1
0
mirror of https://github.com/cc65/cc65.git synced 2024-06-18 07:29:36 +00:00

Rewrote the switch statement

git-svn-id: svn://svn.cc65.org/cc65/trunk@1021 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
cuz 2001-10-11 08:02:03 +00:00
parent 5e7e3d4b81
commit 41d2cc8f91
9 changed files with 574 additions and 357 deletions

183
src/cc65/casenode.c Normal file
View File

@ -0,0 +1,183 @@
/*****************************************************************************/
/* */
/* 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 = GetLocalLabel ();
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 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;
while (Depth--) {
/* Get the key */
unsigned char Key = (Val >> (Depth * CHAR_BIT)) & 0xFF;
/* Search for the node in the collection */
int Index;
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.
*/
if (Depth > 0) {
N->Nodes = NewCollection ();
}
} 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 N->Label;
}

144
src/cc65/casenode.h Normal file
View File

@ -0,0 +1,144 @@
/*****************************************************************************/
/* */
/* casenode.h */
/* */
/* 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. */
/* */
/*****************************************************************************/
#ifndef CASENODE_H
#define CASENODE_H
/* common */
#include "coll.h"
/*****************************************************************************/
/* Data */
/*****************************************************************************/
typedef struct CaseNode CaseNode;
struct CaseNode {
unsigned char Value;
unsigned Label;
Collection* Nodes;
};
/*****************************************************************************/
/* Code */
/*****************************************************************************/
CaseNode* NewCaseNode (unsigned char Value);
/* Create and initialize a new CaseNode */
void FreeCaseNode (CaseNode* N);
/* Delete a case node plus all sub nodes */
#if defined(HAVE_INLINE)
INLINE unsigned CN_GetSubNodeCount (const CaseNode* N)
/* Return the number of subnodes in N */
{
return N->Nodes? CollCount (N->Nodes) : 0;
}
#else
# define CN_GetSubNodeCount(N) ((N)->Nodes? CollCount (&(N)->Nodes) : 0)
#endif
#if defined(HAVE_INLINE)
INLINE CaseNode* CN_GetSubNode (CaseNode* N, unsigned Index)
/* Get a sub node of the given node */
{
return CollAt (N->Nodes, Index);
}
#else
# define CN_GetSubNode(N, Index) CollAt (&(N)->Nodes, Index)
#endif
#if defined(HAVE_INLINE)
INLINE unsigned char CN_GetValue (const CaseNode* N)
/* Return the value for a case node */
{
return N->Value;
}
#else
# define CN_GetValue(N) ((N)->Value)
#endif
#if defined(HAVE_INLINE)
INLINE unsigned CN_GetLabel (const CaseNode* N)
/* Return the label for a case node */
{
return N->Label;
}
#else
# define CN_GetLabel(N) ((N)->Label)
#endif
#if defined(HAVE_INLINE)
INLINE int CN_IsLeafNode (const CaseNode* N)
/* Return true if this is a leaf node */
{
return (N->Nodes == 0);
}
#else
# define CN_IsLeafNode(N) ((N)->Nodes == 0)
#endif
void FreeCaseNodeColl (Collection* Nodes);
/* Free a collection of case 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 the insertion position of the node and return
* false.
*/
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.
*/
/* End of casenode.h */
#endif

View File

@ -47,6 +47,7 @@
/* cc65 */
#include "asmcode.h"
#include "asmlabel.h"
#include "casenode.h"
#include "codeseg.h"
#include "cpu.h"
#include "dataseg.h"
@ -2354,53 +2355,6 @@ void g_jump (unsigned Label)
void g_switch (unsigned Flags)
/* Output switch statement preamble */
{
switch (Flags & CF_TYPE) {
case CF_CHAR:
case CF_INT:
AddCodeLine ("jsr switch");
break;
case CF_LONG:
AddCodeLine ("jsr lswitch");
break;
default:
typeerror (Flags);
}
}
void g_case (unsigned flags, unsigned label, unsigned long val)
/* Create table code for one case selector */
{
switch (flags & CF_TYPE) {
case CF_CHAR:
case CF_INT:
AddCodeLine (".word $%04X, %s",
(unsigned)(val & 0xFFFF),
LocalLabelName (label));
break;
case CF_LONG:
AddCodeLine (".dword $%08lX", val);
AddCodeLine (".word %s", LocalLabelName (label));
break;
default:
typeerror (flags);
}
}
void g_truejump (unsigned flags attribute ((unused)), unsigned label)
/* Jump to label if zero flag clear */
{
@ -3798,7 +3752,7 @@ void g_defdata (unsigned flags, unsigned long val, unsigned offs)
const char* Label = GetLabelName (flags, val, offs);
/* Labels are always 16 bit */
AddDataLine ("\t.word\t%s", Label);
AddDataLine ("\t.addr\t%s", Label);
}
}
@ -3849,6 +3803,84 @@ void g_zerobytes (unsigned n)
/*****************************************************************************/
/* Switch statement */
/*****************************************************************************/
void g_switch (Collection* Nodes, unsigned DefaultLabel, unsigned Depth)
/* Generate code for a switch statement */
{
unsigned NextLabel = 0;
unsigned I;
/* Setup registers and determine which compare insn to use */
const char* Compare;
switch (Depth) {
case 1:
Compare = "cmp #$%02X";
break;
case 2:
Compare = "cpx #$%02X";
break;
case 3:
AddCodeLine ("ldy sreg");
Compare = "cpy #$%02X";
break;
case 4:
AddCodeLine ("ldy sreg+1");
Compare = "cpy #$%02X";
break;
default:
Internal ("Invalid depth in g_switch: %u", Depth);
}
/* Walk over all nodes */
for (I = 0; I < CollCount (Nodes); ++I) {
/* Get the next case node */
CaseNode* N = CollAtUnchecked (Nodes, I);
/* If we have a next label, define it */
if (NextLabel) {
g_defcodelabel (NextLabel);
NextLabel = 0;
}
/* Do the compare */
AddCodeLine (Compare, CN_GetValue (N));
/* If this is the last level, jump directly to the case code if found */
if (Depth == 1) {
/* Branch if equal */
g_falsejump (0, CN_GetLabel (N));
} else {
/* Determine the next label */
if (I == CollCount (Nodes) - 1) {
/* Last node means not found */
g_truejump (0, DefaultLabel);
} else {
/* Jump to the next check */
NextLabel = GetLocalLabel ();
g_truejump (0, NextLabel);
}
/* Check the next level */
g_switch (N->Nodes, DefaultLabel, Depth-1);
}
}
/* If we go here, we haven't found the label */
g_jump (DefaultLabel);
}
/*****************************************************************************/
/* User supplied assembler code */
/*****************************************************************************/
@ -3864,7 +3896,7 @@ void g_asmcode (struct StrBuf* B)
/*****************************************************************************/
/* Inlined known functions */
/* Inlined known functions */
/*****************************************************************************/

View File

@ -38,6 +38,9 @@
/* common */
#include "coll.h"
/* cc65 */
#include "segments.h"
@ -376,12 +379,6 @@ void g_callind (unsigned Flags, unsigned ArgSize, int Offs);
void g_jump (unsigned Label);
/* Jump to specified internal label number */
void g_switch (unsigned Flags);
/* Output switch statement preamble */
void g_case (unsigned flags, unsigned label, unsigned long val);
/* Create table code for one case selector */
void g_truejump (unsigned flags, unsigned label);
/* Jump to label if zero flag clear */
@ -434,6 +431,17 @@ void g_zerobytes (unsigned n);
/*****************************************************************************/
/* Switch statement */
/*****************************************************************************/
void g_switch (Collection* Nodes, unsigned DefaultLabel, unsigned Depth);
/* Generate code for a switch statement */
/*****************************************************************************/
/* User supplied assembler code */
/*****************************************************************************/

View File

@ -101,11 +101,11 @@ void CL_MoveRefs (CodeLabel* OldLabel, CodeLabel* NewLabel)
*/
{
/* Walk through all instructions referencing the old label */
unsigned Count = CollCount (&OldLabel->JumpFrom);
unsigned Count = CL_GetRefCount (OldLabel);
while (Count--) {
/* Get the instruction that references the old label */
CodeEntry* E = CollAt (&OldLabel->JumpFrom, Count);
CodeEntry* E = CL_GetRef (OldLabel, Count);
/* Change the reference to the new label */
CHECK (E->JumpTo == OldLabel);
@ -127,3 +127,4 @@ void CL_Output (const CodeLabel* L, FILE* F)

View File

@ -26,6 +26,7 @@ OBJS = anonname.o \
asmcode.o \
asmlabel.o \
asmstmt.o \
casenode.o \
codeent.o \
codegen.o \
codelab.o \

View File

@ -71,6 +71,7 @@ OBJS = anonname.obj \
asmcode.obj \
asmlabel.obj \
asmstmt.obj \
casenode.obj \
codeent.obj \
codegen.obj \
codelab.obj \
@ -104,7 +105,7 @@ OBJS = anonname.obj \
lineinfo.obj \
litpool.obj \
locals.obj \
loop.obj \
loop.obj \
macrotab.obj \
main.obj \
opcodes.obj \
@ -147,6 +148,7 @@ FILE anonname.obj
FILE asmcode.obj
FILE asmlabel.obj
FILE asmstmt.obj
FILE casenode.obj
FILE codeent.obj
FILE codegen.obj
FILE codelab.obj

View File

@ -61,17 +61,6 @@
/*****************************************************************************/
/* Data */
/*****************************************************************************/
/* Maximum count of cases */
#define CASE_MAX 257
/*****************************************************************************/
/* Helper functions */
/*****************************************************************************/
@ -235,8 +224,8 @@ static void WhileStatement (void)
/* Exit label */
g_defcodelabel (lab);
/* Eat remaining tokens that were delayed because of line info
* correctness
/* Eat remaining tokens that were delayed because of line info
* correctness
*/
SkipPending (PendingToken);
@ -572,4 +561,4 @@ int Statement (int* PendingToken)

View File

@ -33,12 +33,16 @@
#include <limits.h>
/* common */
#include "coll.h"
#include "xmalloc.h"
/* cc65 */
#include "asmcode.h"
#include "asmlabel.h"
#include "casenode.h"
#include "codegen.h"
#include "datatype.h"
#include "error.h"
@ -52,184 +56,172 @@
/*****************************************************************************/
/* Code */
/* Code */
/*****************************************************************************/
static void CascadeSwitch (ExprDesc* Expr)
void SwitchStatement (void)
/* Handle a switch statement for chars with a cmp cascade for the selector */
{
unsigned ExitLab; /* Exit label */
unsigned NextLab; /* Next case label */
unsigned CodeLab; /* Label that starts the actual selector code */
int HaveBreak; /* Remember if we exited with break */
int HaveDefault; /* Remember if we had a default label */
int lcount; /* Label count */
unsigned Flags; /* Code generator flags */
ExprDesc lval; /* Case label expression */
Collection* Nodes; /* CaseNode tree */
ExprDesc SwitchExpr; /* Switch statement expression */
ExprDesc CaseExpr; /* Case label expression */
type SwitchExprType; /* Basic switch expression type */
CodeMark CaseCodeStart; /* Start of code marker */
unsigned Depth; /* Number of bytes the selector type has */
unsigned ExitLabel; /* Exit label */
unsigned CaseLabel; /* Label for case */
unsigned DefaultLabel; /* Label for the default branch */
long Val; /* Case label value */
/* Eat the "switch" token */
NextToken ();
/* Read the switch expression */
ConsumeLParen ();
intexpr (&SwitchExpr);
ConsumeRParen ();
/* Opening curly brace */
ConsumeLCurly ();
/* Remember the current code position */
CaseCodeStart = GetCodePos();
/* Get the unqualified type of the switch expression */
type ExprType = UnqualifiedType (Expr->Type[0]);
SwitchExprType = UnqualifiedType (SwitchExpr.Type[0]);
/* Create a loop so we may break out, init labels */
ExitLab = GetLocalLabel ();
AddLoop (oursp, 0, ExitLab, 0, 0);
/* Get the number of bytes the selector type has */
Depth = SizeOf (SwitchExpr.Type);
CHECK (Depth == 1 || Depth == 2 || Depth == 4);
/* Setup some variables needed in the loop below */
Flags = TypeOf (Expr->Type) | CF_CONST | CF_FORCECHAR;
CodeLab = NextLab = 0;
HaveBreak = 1;
HaveDefault = 0;
/* Get the exit label for the switch statement */
ExitLabel = GetLocalLabel ();
/* Create a loop so we may use break. */
AddLoop (oursp, 0, ExitLabel, 0, 0);
/* Create the collection for the case node tree */
Nodes = NewCollection ();
/* Clear the label for the default branch */
DefaultLabel = 0;
/* Parse the labels */
lcount = 0;
while (CurTok.Tok != TOK_RCURLY) {
if (CurTok.Tok == TOK_CASE || CurTok.Tok == TOK_DEFAULT) {
while (CurTok.Tok == TOK_CASE || CurTok.Tok == TOK_DEFAULT) {
/* If the code for the previous selector did not end with a
* break statement, we must jump over the next selector test.
*/
if (!HaveBreak) {
/* Define a label for the code */
if (CodeLab == 0) {
CodeLab = GetLocalLabel ();
}
g_jump (CodeLab);
}
/* Parse the selector */
if (CurTok.Tok == TOK_CASE) {
/* If we have a cascade label, emit it */
if (NextLab) {
g_defcodelabel (NextLab);
NextLab = 0;
}
/* Skip the "case" token */
NextToken ();
while (CurTok.Tok == TOK_CASE || CurTok.Tok == TOK_DEFAULT) {
/* Parse the selector */
if (CurTok.Tok == TOK_CASE) {
/* Count labels */
++lcount;
/* Skip the "case" token */
NextToken ();
/* Read the selector expression */
constexpr (&lval);
if (!IsClassInt (lval.Type)) {
Error ("Switch quantity not an integer");
}
/* Check the range of the expression */
Val = lval.ConstVal;
switch (ExprType) {
case T_SCHAR:
/* Signed char */
if (Val < -128 || Val > 127) {
Error ("Range error");
}
break;
case T_UCHAR:
if (Val < 0 || Val > 255) {
Error ("Range error");
}
break;
case T_INT:
if (Val < -32768 || Val > 32767) {
Error ("Range error");
}
break;
case T_UINT:
if (Val < 0 || Val > 65535) {
Error ("Range error");
}
break;
default:
Internal ("Invalid type: %04X", ExprType);
}
/* Emit a compare */
g_cmp (Flags, Val);
/* If another case follows after the colon (which is
* currently pending and cannot be skipped since otherwise
* the debug infos will get wrong), we will jump to the
* code if the condition is true.
*/
if (NextTok.Tok == TOK_CASE) {
/* Create a code label if needed */
if (CodeLab == 0) {
CodeLab = GetLocalLabel ();
}
g_falsejump (CF_NONE, CodeLab);
} else if (NextTok.Tok != TOK_DEFAULT) {
/* No case follows, jump to next selector */
if (NextLab == 0) {
NextLab = GetLocalLabel ();
}
g_truejump (CF_NONE, NextLab);
}
/* Skip the colon */
ConsumeColon ();
} else {
/* Default case */
NextToken ();
/* Handle the pathologic case: DEFAULT followed by CASE */
if (NextTok.Tok == TOK_CASE) {
if (CodeLab == 0) {
CodeLab = GetLocalLabel ();
}
g_jump (CodeLab);
}
/* Skip the colon */
ConsumeColon ();
/* Remember that we had a default label */
HaveDefault = 1;
/* Read the selector expression */
constexpr (&CaseExpr);
if (!IsClassInt (CaseExpr.Type)) {
Error ("Switch quantity not an integer");
}
}
/* Check the range of the expression */
Val = CaseExpr.ConstVal;
switch (SwitchExprType) {
}
case T_SCHAR:
/* Signed char */
if (Val < -128 || Val > 127) {
Error ("Range error");
}
break;
/* Emit a code label if we have one */
if (CodeLab) {
g_defcodelabel (CodeLab);
CodeLab = 0;
}
case T_UCHAR:
if (Val < 0 || Val > 255) {
Error ("Range error");
}
break;
/* Parse statements */
if (CurTok.Tok != TOK_RCURLY) {
HaveBreak = Statement (0);
}
case T_INT:
if (Val < -32768 || Val > 32767) {
Error ("Range error");
}
break;
case T_UINT:
if (Val < 0 || Val > 65535) {
Error ("Range error");
}
break;
case T_LONG:
case T_ULONG:
break;
default:
Internal ("Invalid type: %04X", SwitchExprType);
}
/* Insert the case selector into the selector table */
CaseLabel = InsertCaseValue (Nodes, Val, Depth);
/* Define this label */
g_defcodelabel (CaseLabel);
/* Skip the colon */
ConsumeColon ();
} else {
/* Default case */
NextToken ();
/* Check if we do already have a default branch */
if (DefaultLabel == 0) {
/* Generate and emit the default label */
DefaultLabel = GetLocalLabel ();
g_defcodelabel (DefaultLabel);
} else {
/* We had the default label already */
Error ("Duplicate `default' case");
}
/* Skip the colon */
ConsumeColon ();
}
}
/* Parse statements */
if (CurTok.Tok != TOK_RCURLY) {
Statement (0);
}
}
/* Check if we have any labels */
if (lcount == 0 && !HaveDefault) {
Warning ("No case labels");
/* Check if we had any labels */
if (CollCount (Nodes) == 0 && DefaultLabel == 0) {
Warning ("No case labels");
} else {
/* Remember the current position */
CodeMark SwitchCodeStart = GetCodePos();
/* Generate code */
g_switch (Nodes, DefaultLabel? DefaultLabel : ExitLabel, Depth);
/* Move the code to the front */
MoveCode (SwitchCodeStart, GetCodePos(), CaseCodeStart);
}
/* Define the exit label and, if there's a next label left, create this
* one, too.
*/
if (NextLab) {
g_defcodelabel (NextLab);
}
g_defcodelabel (ExitLab);
/* Define the exit label */
g_defcodelabel (ExitLabel);
/* Eat the closing curly brace */
NextToken ();
@ -240,138 +232,3 @@ static void CascadeSwitch (ExprDesc* Expr)
static void TableSwitch (ExprDesc* Expr)
/* Handle a switch statement via table based selector */
{
/* Entry for one case in a switch statement */
typedef struct {
long Value; /* selector value */
unsigned Label; /* label for this selector */
} SwitchEntry;
unsigned DefaultLabel; /* Label for default case */
unsigned ExitLabel; /* exit label */
int lcase; /* label for compares */
int HaveBreak; /* Last statement has a break */
unsigned Flags; /* Code generator flags */
ExprDesc lval; /* Case label expression */
unsigned I;
SwitchEntry* P;
Collection SwitchTab;
/* Initialize the collection for the switch entries */
InitCollection (&SwitchTab);
/* Create a look so we may break out, init labels */
HaveBreak = 0; /* Keep gcc silent */
DefaultLabel = 0; /* No default case until now */
ExitLabel = GetLocalLabel (); /* get exit */
AddLoop (oursp, 0, ExitLabel, 0, 0);
/* Jump behind the code for the CASE labels */
g_jump (lcase = GetLocalLabel ());
while (CurTok.Tok != TOK_RCURLY) {
if (CurTok.Tok == TOK_CASE || CurTok.Tok == TOK_DEFAULT) {
do {
if (CurTok.Tok == TOK_CASE) {
NextToken ();
constexpr (&lval);
if (!IsClassInt (lval.Type)) {
Error ("Switch quantity not an integer");
}
P = xmalloc (sizeof (SwitchEntry));
P->Value = lval.ConstVal;
P->Label = GetLocalLabel ();
CollAppend (&SwitchTab, P);
g_defcodelabel (P->Label);
} else if (DefaultLabel == 0) {
NextToken ();
DefaultLabel = GetLocalLabel ();
g_defcodelabel (DefaultLabel);
} else {
/* We already had a default label */
Error ("Multiple default labels in one switch");
/* Try to recover */
NextToken ();
}
ConsumeColon ();
} while (CurTok.Tok == TOK_CASE || CurTok.Tok == TOK_DEFAULT);
HaveBreak = 0;
}
if (CurTok.Tok != TOK_RCURLY) {
HaveBreak = Statement (0);
}
}
/* Check if we have any labels */
if (CollCount(&SwitchTab) == 0 && DefaultLabel == 0) {
Warning ("No case labels");
}
/* Eat the closing curly brace */
NextToken ();
/* If the last statement doesn't have a break or return, add one */
if (!HaveBreak) {
g_jump (ExitLabel);
}
/* Actual selector code goes here */
g_defcodelabel (lcase);
/* Create the call to the switch subroutine */
Flags = TypeOf (Expr->Type);
g_switch (Flags);
/* First entry is negative of label count */
g_defdata (CF_INT | CF_CONST, -((int)CollCount(&SwitchTab))-1, 0);
/* Create the case selector table */
for (I = 0; I < CollCount (&SwitchTab); ++I) {
P = CollAt (&SwitchTab, I);
g_case (Flags, P->Label, P->Value); /* Create one label */
}
if (DefaultLabel != 0) {
g_jump (DefaultLabel);
}
g_defcodelabel (ExitLabel);
DelLoop ();
/* Free the allocated space for the labels */
for (I = 0; I < CollCount (&SwitchTab); ++I) {
xfree (CollAt (&SwitchTab, I));
}
/* Free the collection itself */
DoneCollection (&SwitchTab);
}
void SwitchStatement (void)
/* Handle a 'switch' statement */
{
ExprDesc Expr; /* Switch statement expression */
/* Eat the "switch" */
NextToken ();
/* Read the switch expression */
ConsumeLParen ();
intexpr (&Expr);
ConsumeRParen ();
/* result of expr is in P */
ConsumeLCurly ();
/* Now decide which sort of switch we will create: */
if (IsTypeChar (Expr.Type) || (CodeSizeFactor >= 200 && IsClassInt (Expr.Type))) {
CascadeSwitch (&Expr);
} else {
TableSwitch (&Expr);
}
}