From 41d2cc8f915bd5513488fde96b652f0a59fba0b8 Mon Sep 17 00:00:00 2001 From: cuz Date: Thu, 11 Oct 2001 08:02:03 +0000 Subject: [PATCH] Rewrote the switch statement git-svn-id: svn://svn.cc65.org/cc65/trunk@1021 b7a2c559-68d2-44c3-8de9-860c34a00d81 --- src/cc65/casenode.c | 183 ++++++++++++++++++ src/cc65/casenode.h | 144 ++++++++++++++ src/cc65/codegen.c | 130 ++++++++----- src/cc65/codegen.h | 20 +- src/cc65/codelab.c | 5 +- src/cc65/make/gcc.mak | 1 + src/cc65/make/watcom.mak | 4 +- src/cc65/stmt.c | 17 +- src/cc65/swstmt.c | 405 +++++++++++++-------------------------- 9 files changed, 563 insertions(+), 346 deletions(-) create mode 100644 src/cc65/casenode.c create mode 100644 src/cc65/casenode.h diff --git a/src/cc65/casenode.c b/src/cc65/casenode.c new file mode 100644 index 000000000..45a61ea65 --- /dev/null +++ b/src/cc65/casenode.c @@ -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 + +/* 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; +} + + + diff --git a/src/cc65/casenode.h b/src/cc65/casenode.h new file mode 100644 index 000000000..19861ce96 --- /dev/null +++ b/src/cc65/casenode.h @@ -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 + + + diff --git a/src/cc65/codegen.c b/src/cc65/codegen.c index b79b53304..fbcc759d5 100644 --- a/src/cc65/codegen.c +++ b/src/cc65/codegen.c @@ -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 */ /*****************************************************************************/ diff --git a/src/cc65/codegen.h b/src/cc65/codegen.h index 704032ea4..538838e42 100644 --- a/src/cc65/codegen.h +++ b/src/cc65/codegen.h @@ -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 */ /*****************************************************************************/ diff --git a/src/cc65/codelab.c b/src/cc65/codelab.c index e4fdef46e..db4341d87 100644 --- a/src/cc65/codelab.c +++ b/src/cc65/codelab.c @@ -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) + diff --git a/src/cc65/make/gcc.mak b/src/cc65/make/gcc.mak index 2a34da998..9fa674dc4 100644 --- a/src/cc65/make/gcc.mak +++ b/src/cc65/make/gcc.mak @@ -26,6 +26,7 @@ OBJS = anonname.o \ asmcode.o \ asmlabel.o \ asmstmt.o \ + casenode.o \ codeent.o \ codegen.o \ codelab.o \ diff --git a/src/cc65/make/watcom.mak b/src/cc65/make/watcom.mak index 4d7cfb370..80527dd40 100644 --- a/src/cc65/make/watcom.mak +++ b/src/cc65/make/watcom.mak @@ -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 diff --git a/src/cc65/stmt.c b/src/cc65/stmt.c index 3863c72e5..16ada99e6 100644 --- a/src/cc65/stmt.c +++ b/src/cc65/stmt.c @@ -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) - + diff --git a/src/cc65/swstmt.c b/src/cc65/swstmt.c index 05abe0747..3c541c93d 100644 --- a/src/cc65/swstmt.c +++ b/src/cc65/swstmt.c @@ -33,12 +33,16 @@ +#include + /* 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,325 +56,178 @@ /*****************************************************************************/ -/* 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]); + + /* Get the number of bytes the selector type has */ + Depth = SizeOf (SwitchExpr.Type); + CHECK (Depth == 1 || Depth == 2 || Depth == 4); + + /* 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 a loop so we may break out, init labels */ - ExitLab = GetLocalLabel (); - AddLoop (oursp, 0, ExitLab, 0, 0); + /* Create the collection for the case node tree */ + Nodes = NewCollection (); - /* Setup some variables needed in the loop below */ - Flags = TypeOf (Expr->Type) | CF_CONST | CF_FORCECHAR; - CodeLab = NextLab = 0; - HaveBreak = 1; - HaveDefault = 0; + /* 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 (); + /* Parse the selector */ + if (CurTok.Tok == TOK_CASE) { + + /* Skip the "case" token */ + NextToken (); + + /* Read the selector expression */ + constexpr (&CaseExpr); + if (!IsClassInt (CaseExpr.Type)) { + Error ("Switch quantity not an integer"); } - g_jump (CodeLab); - } - - /* If we have a cascade label, emit it */ - if (NextLab) { - g_defcodelabel (NextLab); - NextLab = 0; - } - - 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; + + /* 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; + + 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; + + 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); - /* Emit a code label if we have one */ - if (CodeLab) { - g_defcodelabel (CodeLab); - CodeLab = 0; - } + /* Skip the colon */ + ConsumeColon (); - /* Parse statements */ - if (CurTok.Tok != TOK_RCURLY) { - HaveBreak = Statement (0); - } - } + } else { - /* Check if we have any labels */ - if (lcount == 0 && !HaveDefault) { - Warning ("No case labels"); - } + /* Default case */ + NextToken (); - /* Define the exit label and, if there's a next label left, create this - * one, too. - */ - if (NextLab) { - g_defcodelabel (NextLab); - } - g_defcodelabel (ExitLab); + /* Check if we do already have a default branch */ + if (DefaultLabel == 0) { - /* Eat the closing curly brace */ - NextToken (); + /* Generate and emit the default label */ + DefaultLabel = GetLocalLabel (); + g_defcodelabel (DefaultLabel); - /* End the loop */ - DelLoop (); -} + } else { + /* We had the default label already */ + Error ("Duplicate `default' case"); + } + /* Skip the colon */ + ConsumeColon (); + } -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); - } + /* Parse statements */ + if (CurTok.Tok != TOK_RCURLY) { + Statement (0); + } } - /* Check if we have any labels */ - if (CollCount(&SwitchTab) == 0 && DefaultLabel == 0) { - Warning ("No case labels"); - } + /* Check if we had any labels */ + if (CollCount (Nodes) == 0 && DefaultLabel == 0) { - /* Eat the closing curly brace */ - NextToken (); + Warning ("No case labels"); - /* If the last statement doesn't have a break or return, add one */ - if (!HaveBreak) { - g_jump (ExitLabel); - } + } else { - /* Actual selector code goes here */ - g_defcodelabel (lcase); + /* Remember the current position */ + CodeMark SwitchCodeStart = GetCodePos(); - /* Create the call to the switch subroutine */ - Flags = TypeOf (Expr->Type); - g_switch (Flags); + /* Generate code */ + g_switch (Nodes, DefaultLabel? DefaultLabel : ExitLabel, Depth); - /* First entry is negative of label count */ - g_defdata (CF_INT | CF_CONST, -((int)CollCount(&SwitchTab))-1, 0); + /* Move the code to the front */ + MoveCode (SwitchCodeStart, GetCodePos(), CaseCodeStart); - /* 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); - } + /* Define the exit label */ 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" */ + /* Eat the closing curly brace */ 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); - } + /* End the loop */ + DelLoop (); } -- 2.39.5