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:
@@ -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");
|
||||||
|
@@ -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 */
|
||||||
/* */
|
/* */
|
||||||
/* */
|
/* */
|
||||||
|
@@ -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 ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -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 */
|
||||||
|
Reference in New Issue
Block a user