1
0
mirror of https://github.com/cc65/cc65.git synced 2025-08-10 04:25:21 +00:00

Switch statement may now contain arbitrary code as the standard requires. The

compiler will now accept stuff like Duffs device.


git-svn-id: svn://svn.cc65.org/cc65/trunk@3859 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
cuz
2008-08-01 19:44:01 +00:00
parent 22d89f558e
commit 64ec376140
4 changed files with 196 additions and 144 deletions

View File

@@ -6,8 +6,8 @@
/* */ /* */
/* */ /* */
/* */ /* */
/* (C) 1998-2004 Ullrich von Bassewitz */ /* (C) 1998-2008 Ullrich von Bassewitz */
/* R<EFBFBD>merstra<EFBFBD>e 52 */ /* Roemerstrasse 52 */
/* D-70794 Filderstadt */ /* D-70794 Filderstadt */
/* EMail: uz@cc65.org */ /* EMail: uz@cc65.org */
/* */ /* */
@@ -57,9 +57,9 @@
#include "pragma.h" #include "pragma.h"
#include "scanner.h" #include "scanner.h"
#include "stackptr.h" #include "stackptr.h"
#include "stmt.h"
#include "swstmt.h" #include "swstmt.h"
#include "symtab.h" #include "symtab.h"
#include "stmt.h"
#include "testexpr.h" #include "testexpr.h"
#include "typeconv.h" #include "typeconv.h"
@@ -542,7 +542,7 @@ int Statement (int* PendingToken)
case TOK_LCURLY: case TOK_LCURLY:
NextToken (); NextToken ();
GotBreak = CompoundStatement (); GotBreak = CompoundStatement ();
CheckTok (TOK_RCURLY, "`{' expected", PendingToken); CheckTok (TOK_RCURLY, "`{' expected", PendingToken);
return GotBreak; return GotBreak;
case TOK_IF: case TOK_IF:
@@ -567,7 +567,7 @@ int Statement (int* PendingToken)
case TOK_BREAK: case TOK_BREAK:
BreakStatement (); BreakStatement ();
CheckSemi (PendingToken); CheckSemi (PendingToken);
return 1; return 1;
case TOK_CONTINUE: case TOK_CONTINUE:
@@ -593,6 +593,14 @@ int Statement (int* PendingToken)
DoPragma (); DoPragma ();
break; break;
case TOK_CASE:
CaseLabel ();
break;
case TOK_DEFAULT:
DefaultLabel ();
break;
default: default:
/* Remember the current code position */ /* Remember the current code position */
GetCodePos (&Start); GetCodePos (&Start);
@@ -606,7 +614,7 @@ int Statement (int* PendingToken)
} }
/* If the statement didn't generate code, and is not of type /* If the statement didn't generate code, and is not of type
* void, emit a warning. * void, emit a warning.
*/ */
GetCodePos (&End); GetCodePos (&End);
if (CodeRangeIsEmpty (&Start, &End) && !IsTypeVoid (Expr.Type)) { if (CodeRangeIsEmpty (&Start, &End) && !IsTypeVoid (Expr.Type)) {
Warning ("Statement has no effect"); Warning ("Statement has no effect");

View File

@@ -6,9 +6,9 @@
/* */ /* */
/* */ /* */
/* */ /* */
/* (C) 1998-2001 Ullrich von Bassewitz */ /* (C) 1998-2008 Ullrich von Bassewitz */
/* Wacholderweg 14 */ /* Roemerstrasse 52 */
/* D-70597 Stuttgart */ /* D-70794 Filderstadt */
/* EMail: uz@cc65.org */ /* EMail: uz@cc65.org */
/* */ /* */
/* */ /* */

View File

@@ -6,8 +6,8 @@
/* */ /* */
/* */ /* */
/* */ /* */
/* (C) 1998-2006 Ullrich von Bassewitz */ /* (C) 1998-2008 Ullrich von Bassewitz */
/* R<EFBFBD>merstra<EFBFBD>e 52 */ /* Roemerstrasse 52 */
/* D-70794 Filderstadt */ /* D-70794 Filderstadt */
/* EMail: uz@cc65.org */ /* EMail: uz@cc65.org */
/* */ /* */
@@ -56,7 +56,29 @@
/*****************************************************************************/ /*****************************************************************************/
/* Code */ /* Data */
/*****************************************************************************/
typedef struct SwitchCtrl SwitchCtrl;
struct SwitchCtrl {
Collection* Nodes; /* CaseNode tree */
TypeCode ExprType; /* Basic switch expression type */
unsigned Depth; /* Number of bytes the selector type has */
unsigned DefaultLabel; /* Label for the default branch */
};
/* Pointer to current switch control struct */
static SwitchCtrl* Switch = 0;
/*****************************************************************************/
/* Code */
/*****************************************************************************/ /*****************************************************************************/
@@ -64,20 +86,15 @@
void SwitchStatement (void) void SwitchStatement (void)
/* Handle a switch statement for chars with a cmp cascade for the selector */ /* Handle a switch statement for chars with a cmp cascade for the selector */
{ {
Collection* Nodes; /* CaseNode tree */ ExprDesc SwitchExpr; /* Switch statement expression */
ExprDesc SwitchExpr; /* Switch statement expression */ CodeMark CaseCodeStart; /* Start of code marker */
ExprDesc CaseExpr; /* Case label expression */ CodeMark SwitchCodeStart;/* Start of switch code */
TypeCode SwitchExprType; /* Basic switch expression type */ CodeMark SwitchCodeEnd; /* End of switch code */
CodeMark CaseCodeStart; /* Start of code marker */ unsigned ExitLabel; /* Exit label */
CodeMark SwitchCodeStart; /* Start of switch code */ unsigned SwitchCodeLabel;/* Label for the switch code */
CodeMark SwitchCodeEnd; /* End of switch code */ int HaveBreak = 0; /* True if the last statement had a break */
unsigned Depth; /* Number of bytes the selector type has */ SwitchCtrl* OldSwitch; /* Pointer to old switch control data */
unsigned ExitLabel; /* Exit label */ SwitchCtrl SwitchData; /* New switch data */
unsigned CaseLabel; /* Label for case */
unsigned DefaultLabel; /* Label for the default branch */
unsigned SwitchCodeLabel; /* Label for the switch code */
long Val; /* Case label value */
int HaveBreak = 0; /* True if the last statement had a break */
/* Eat the "switch" token */ /* Eat the "switch" token */
@@ -112,15 +129,13 @@ void SwitchStatement (void)
*/ */
GetCodePos (&CaseCodeStart); GetCodePos (&CaseCodeStart);
/* Opening curly brace */ /* Setup the control structure, save the old and activate the new one */
ConsumeLCurly (); SwitchData.Nodes = NewCollection ();
SwitchData.ExprType = UnqualifiedType (SwitchExpr.Type[0].C);
/* Get the unqualified type of the switch expression */ SwitchData.Depth = SizeOf (SwitchExpr.Type);
SwitchExprType = UnqualifiedType (SwitchExpr.Type[0].C); SwitchData.DefaultLabel = 0;
OldSwitch = Switch;
/* Get the number of bytes the selector type has */ Switch = &SwitchData;
Depth = SizeOf (SwitchExpr.Type);
CHECK (Depth == SIZEOF_CHAR || Depth == SIZEOF_INT || Depth == SIZEOF_LONG);
/* Get the exit label for the switch statement */ /* Get the exit label for the switch statement */
ExitLabel = GetLocalLabel (); ExitLabel = GetLocalLabel ();
@@ -128,109 +143,19 @@ void SwitchStatement (void)
/* Create a loop so we may use break. */ /* Create a loop so we may use break. */
AddLoop (ExitLabel, 0); AddLoop (ExitLabel, 0);
/* Create the collection for the case node tree */ /* Make sure a curly brace follows */
Nodes = NewCollection (); if (CurTok.Tok != TOK_LCURLY) {
Error ("`{' expected");
/* Clear the label for the default branch */
DefaultLabel = 0;
/* Parse the labels */
while (CurTok.Tok != TOK_RCURLY) {
while (CurTok.Tok == TOK_CASE || CurTok.Tok == TOK_DEFAULT) {
/* Parse the selector */
if (CurTok.Tok == TOK_CASE) {
/* Skip the "case" token */
NextToken ();
/* Read the selector expression */
ConstAbsIntExpr (hie1, &CaseExpr);
/* Check the range of the expression */
Val = CaseExpr.IVal;
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_SHORT:
case T_INT:
if (Val < -32768 || Val > 32767) {
Error ("Range error");
}
break;
case T_USHORT:
case T_UINT:
if (Val < 0 || Val > 65535) {
Error ("Range error");
}
break;
case T_LONG:
case T_ULONG:
break;
default:
Internal ("Invalid type: %06lX", 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) {
HaveBreak = Statement (0);
}
} }
/* Parse the following statement, which will actually be a compound
* statement because of the curly brace at the current input position
*/
HaveBreak = Statement (0);
/* Check if we had any labels */ /* Check if we had any labels */
if (CollCount (Nodes) == 0 && DefaultLabel == 0) { if (CollCount (SwitchData.Nodes) == 0 && SwitchData.DefaultLabel == 0) {
Warning ("No case labels"); Warning ("No case labels");
} }
/* If the last statement did not have a break, we may have an open /* If the last statement did not have a break, we may have an open
@@ -251,7 +176,11 @@ void SwitchStatement (void)
g_defcodelabel (SwitchCodeLabel); g_defcodelabel (SwitchCodeLabel);
/* Generate code */ /* Generate code */
g_switch (Nodes, DefaultLabel? DefaultLabel : ExitLabel, Depth); if (SwitchData.DefaultLabel == 0) {
/* No default label, use switch exit */
SwitchData.DefaultLabel = ExitLabel;
}
g_switch (SwitchData.Nodes, SwitchData.DefaultLabel, SwitchData.Depth);
/* Move the code to the front */ /* Move the code to the front */
GetCodePos (&SwitchCodeEnd); GetCodePos (&SwitchCodeEnd);
@@ -259,15 +188,124 @@ void SwitchStatement (void)
/* Define the exit label */ /* Define the exit label */
g_defcodelabel (ExitLabel); g_defcodelabel (ExitLabel);
/* Exit the loop */
DelLoop ();
/* Eat the closing curly brace */ /* Switch back to the enclosing switch statement if any */
NextToken (); Switch = OldSwitch;
/* Free the case value tree */ /* Free the case value tree */
FreeCaseNodeColl (Nodes); FreeCaseNodeColl (SwitchData.Nodes);
}
/* End the loop */
DelLoop ();
void CaseLabel (void)
/* Handle a case sabel */
{
ExprDesc CaseExpr; /* Case label expression */
long Val; /* Case label value */
unsigned CodeLabel; /* Code label for this case */
/* Skip the "case" token */
NextToken ();
/* Read the selector expression */
ConstAbsIntExpr (hie1, &CaseExpr);
Val = CaseExpr.IVal;
/* Now check if we're inside a switch statement */
if (Switch != 0) {
/* Check the range of the expression */
switch (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_SHORT:
case T_INT:
if (Val < -32768 || Val > 32767) {
Error ("Range error");
}
break;
case T_USHORT:
case T_UINT:
if (Val < 0 || Val > 65535) {
Error ("Range error");
}
break;
case T_LONG:
case T_ULONG:
break;
default:
Internal ("Invalid type: %06lX", Switch->ExprType);
}
/* Insert the case selector into the selector table */
CodeLabel = InsertCaseValue (Switch->Nodes, Val, Switch->Depth);
/* Define this label */
g_defcodelabel (CodeLabel);
} else {
/* case keyword outside a switch statement */
Error ("Case label not within a switch statement");
}
/* Skip the colon */
ConsumeColon ();
}
void DefaultLabel (void)
/* Handle a default label */
{
/* Default case */
NextToken ();
/* Now check if we're inside a switch statement */
if (Switch != 0) {
/* Check if we do already have a default branch */
if (Switch->DefaultLabel == 0) {
/* Generate and emit the default label */
Switch->DefaultLabel = GetLocalLabel ();
g_defcodelabel (Switch->DefaultLabel);
} else {
/* We had the default label already */
Error ("Multiple default labels in one switch");
}
} else {
/* case keyword outside a switch statement */
Error ("`default' label not within a switch statement");
}
/* Skip the colon */
ConsumeColon ();
} }

View File

@@ -6,9 +6,9 @@
/* */ /* */
/* */ /* */
/* */ /* */
/* (C) 1998-2001 Ullrich von Bassewitz */ /* (C) 1998-2008 Ullrich von Bassewitz */
/* Wacholderweg 14 */ /* Roemerstrasse 52 */
/* D-70597 Stuttgart */ /* D-70794 Filderstadt */
/* EMail: uz@cc65.org */ /* EMail: uz@cc65.org */
/* */ /* */
/* */ /* */
@@ -47,6 +47,12 @@
void SwitchStatement (void); void SwitchStatement (void);
/* Handle a 'switch' statement */ /* Handle a 'switch' statement */
void CaseLabel (void);
/* Handle a case label */
void DefaultLabel (void);
/* Handle a default label */
/* End of swstmt.h */ /* End of swstmt.h */