mirror of https://github.com/cc65/cc65.git
185 lines
6.0 KiB
C
185 lines
6.0 KiB
C
/*****************************************************************************/
|
|
/* */
|
|
/* casenode.c */
|
|
/* */
|
|
/* Node for the tree that is generated for a switch statement */
|
|
/* */
|
|
/* */
|
|
/* */
|
|
/* (C) 2001 Ullrich von Bassewitz */
|
|
/* Wacholderweg 14 */
|
|
/* D-70597 Stuttgart */
|
|
/* EMail: uz@cc65.org */
|
|
/* */
|
|
/* */
|
|
/* This software is provided 'as-is', without any expressed or implied */
|
|
/* warranty. In no event will the authors be held liable for any damages */
|
|
/* arising from the use of this software. */
|
|
/* */
|
|
/* Permission is granted to anyone to use this software for any purpose, */
|
|
/* including commercial applications, and to alter it and redistribute it */
|
|
/* freely, subject to the following restrictions: */
|
|
/* */
|
|
/* 1. The origin of this software must not be misrepresented; you must not */
|
|
/* claim that you wrote the original software. If you use this software */
|
|
/* in a product, an acknowledgment in the product documentation would be */
|
|
/* appreciated but is not required. */
|
|
/* 2. Altered source versions must be plainly marked as such, and must not */
|
|
/* be misrepresented as being the original software. */
|
|
/* 3. This notice may not be removed or altered from any source */
|
|
/* distribution. */
|
|
/* */
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
#include <limits.h>
|
|
|
|
/* common */
|
|
#include "coll.h"
|
|
#include "xmalloc.h"
|
|
|
|
/* cc65 */
|
|
#include "asmlabel.h"
|
|
#include "error.h"
|
|
#include "casenode.h"
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
/* Code */
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
CaseNode* NewCaseNode (unsigned char Value)
|
|
/* Create and initialize a new CaseNode */
|
|
{
|
|
/* Allocate memory */
|
|
CaseNode* N = xmalloc (sizeof (CaseNode));
|
|
|
|
/* Initialize the fields */
|
|
N->Value = Value;
|
|
N->Label = 0;
|
|
N->Nodes = 0;
|
|
|
|
/* Return the new node */
|
|
return N;
|
|
}
|
|
|
|
|
|
|
|
void FreeCaseNode (CaseNode* N)
|
|
/* Delete a case node plus all sub nodes */
|
|
{
|
|
if (N->Nodes) {
|
|
FreeCaseNodeColl (N->Nodes);
|
|
}
|
|
xfree (N);
|
|
}
|
|
|
|
|
|
|
|
void FreeCaseNodeColl (Collection* Nodes)
|
|
/* Free a collection of case nodes */
|
|
{
|
|
unsigned I;
|
|
for (I = 0; I < CollCount (Nodes); ++I) {
|
|
FreeCaseNode (CollAtUnchecked (Nodes, I));
|
|
}
|
|
FreeCollection (Nodes);
|
|
}
|
|
|
|
|
|
|
|
int SearchCaseNode (const Collection* Nodes, unsigned char Key, int* Index)
|
|
/* Search for a node in the given collection. If the node has been found,
|
|
** set Index to the index of the node and return true. If the node was not
|
|
** found, set Index the insertion position of the node and return
|
|
** false.
|
|
*/
|
|
{
|
|
/* Do a binary search */
|
|
int First = 0;
|
|
int Last = CollCount (Nodes) - 1;
|
|
int S = 0;
|
|
|
|
while (First <= Last) {
|
|
|
|
/* Set current to mid of range */
|
|
int Current = (Last + First) / 2;
|
|
|
|
/* Get the entry from this position */
|
|
const CaseNode* N = CollConstAt (Nodes, Current);
|
|
|
|
/* Compare the values */
|
|
if (N->Value < Key) {
|
|
First = Current + 1;
|
|
} else {
|
|
Last = Current - 1;
|
|
if (N->Value == Key) {
|
|
/* Found. We cannot have duplicates, so end the search here. */
|
|
S = 1;
|
|
First = Current;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
*Index = First;
|
|
return S;
|
|
}
|
|
|
|
|
|
|
|
unsigned InsertCaseValue (Collection* Nodes, unsigned long Val, unsigned Depth)
|
|
/* Insert a new case value into a CaseNode tree with the given depth. Return
|
|
** the code label for the value.
|
|
*/
|
|
{
|
|
CaseNode* N = 0;
|
|
unsigned CaseLabel = GetLocalLabel (); /* Code label */
|
|
|
|
while (Depth--) {
|
|
|
|
int Index;
|
|
|
|
/* Get the key */
|
|
unsigned char Key = (Val >> (Depth * CHAR_BIT)) & 0xFF;
|
|
|
|
/* Search for the node in the collection */
|
|
if (SearchCaseNode (Nodes, Key, &Index) == 0) {
|
|
|
|
/* Node not found - insert one */
|
|
N = NewCaseNode (Key);
|
|
CollInsert (Nodes, N, Index);
|
|
|
|
/* If this is not the last round, create the collection for
|
|
** the subnodes, otherwise get a label for the code.
|
|
*/
|
|
if (Depth > 0) {
|
|
N->Nodes = NewCollection ();
|
|
} else {
|
|
N->Label = CaseLabel;
|
|
}
|
|
|
|
} else {
|
|
/* Node found, get it */
|
|
N = CollAt (Nodes, Index);
|
|
|
|
/* If this is the last round and we found a node, we have a
|
|
** duplicate case label in a switch.
|
|
*/
|
|
if (Depth == 0) {
|
|
Error ("Duplicate case label");
|
|
}
|
|
}
|
|
|
|
/* Get the collection from the node for the next round. */
|
|
Nodes = N->Nodes;
|
|
}
|
|
|
|
/* Return the label of the node we found/created */
|
|
return CaseLabel;
|
|
}
|