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

View File

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

View File

@ -6,8 +6,8 @@
/* */
/* */
/* */
/* (C) 1998-2006 Ullrich von Bassewitz */
/* Römerstraße 52 */
/* (C) 1998-2008 Ullrich von Bassewitz */
/* Roemerstrasse 52 */
/* D-70794 Filderstadt */
/* 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)
/* Handle a switch statement for chars with a cmp cascade for the selector */
{
Collection* Nodes; /* CaseNode tree */
ExprDesc SwitchExpr; /* Switch statement expression */
ExprDesc CaseExpr; /* Case label expression */
TypeCode SwitchExprType; /* Basic switch expression type */
CodeMark CaseCodeStart; /* Start of code marker */
CodeMark SwitchCodeStart; /* Start of switch code */
CodeMark SwitchCodeEnd; /* End of switch code */
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 */
unsigned SwitchCodeLabel; /* Label for the switch code */
long Val; /* Case label value */
int HaveBreak = 0; /* True if the last statement had a break */
ExprDesc SwitchExpr; /* Switch statement expression */
CodeMark CaseCodeStart; /* Start of code marker */
CodeMark SwitchCodeStart;/* Start of switch code */
CodeMark SwitchCodeEnd; /* End of switch code */
unsigned ExitLabel; /* Exit label */
unsigned SwitchCodeLabel;/* Label for the switch code */
int HaveBreak = 0; /* True if the last statement had a break */
SwitchCtrl* OldSwitch; /* Pointer to old switch control data */
SwitchCtrl SwitchData; /* New switch data */
/* Eat the "switch" token */
@ -112,15 +129,13 @@ void SwitchStatement (void)
*/
GetCodePos (&CaseCodeStart);
/* Opening curly brace */
ConsumeLCurly ();
/* Get the unqualified type of the switch expression */
SwitchExprType = UnqualifiedType (SwitchExpr.Type[0].C);
/* Get the number of bytes the selector type has */
Depth = SizeOf (SwitchExpr.Type);
CHECK (Depth == SIZEOF_CHAR || Depth == SIZEOF_INT || Depth == SIZEOF_LONG);
/* Setup the control structure, save the old and activate the new one */
SwitchData.Nodes = NewCollection ();
SwitchData.ExprType = UnqualifiedType (SwitchExpr.Type[0].C);
SwitchData.Depth = SizeOf (SwitchExpr.Type);
SwitchData.DefaultLabel = 0;
OldSwitch = Switch;
Switch = &SwitchData;
/* Get the exit label for the switch statement */
ExitLabel = GetLocalLabel ();
@ -128,109 +143,19 @@ void SwitchStatement (void)
/* Create a loop so we may use break. */
AddLoop (ExitLabel, 0);
/* Create the collection for the case node tree */
Nodes = NewCollection ();
/* 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);
}
/* Make sure a curly brace follows */
if (CurTok.Tok != TOK_LCURLY) {
Error ("`{' expected");
}
/* 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 */
if (CollCount (Nodes) == 0 && DefaultLabel == 0) {
if (CollCount (SwitchData.Nodes) == 0 && SwitchData.DefaultLabel == 0) {
Warning ("No case labels");
}
/* If the last statement did not have a break, we may have an open
@ -251,7 +176,11 @@ void SwitchStatement (void)
g_defcodelabel (SwitchCodeLabel);
/* 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 */
GetCodePos (&SwitchCodeEnd);
@ -259,15 +188,124 @@ void SwitchStatement (void)
/* Define the exit label */
g_defcodelabel (ExitLabel);
/* Exit the loop */
DelLoop ();
/* Eat the closing curly brace */
NextToken ();
/* Switch back to the enclosing switch statement if any */
Switch = OldSwitch;
/* Free the case value tree */
FreeCaseNodeColl (Nodes);
/* End the loop */
DelLoop ();
FreeCaseNodeColl (SwitchData.Nodes);
}
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 */
/* Wacholderweg 14 */
/* D-70597 Stuttgart */
/* (C) 1998-2008 Ullrich von Bassewitz */
/* Roemerstrasse 52 */
/* D-70794 Filderstadt */
/* EMail: uz@cc65.org */
/* */
/* */
@ -47,6 +47,12 @@
void SwitchStatement (void);
/* Handle a 'switch' statement */
void CaseLabel (void);
/* Handle a case label */
void DefaultLabel (void);
/* Handle a default label */
/* End of swstmt.h */