Fixed 'case'/'default' labels in non-compound 'switch' body statement.
This commit is contained in:
@@ -644,7 +644,7 @@ void NewFunc (SymEntry* Func, FuncDesc* D)
|
|||||||
|
|
||||||
/* Now process statements in this block */
|
/* Now process statements in this block */
|
||||||
while (CurTok.Tok != TOK_RCURLY && CurTok.Tok != TOK_CEOF) {
|
while (CurTok.Tok != TOK_RCURLY && CurTok.Tok != TOK_CEOF) {
|
||||||
Statement (0);
|
AnyStatement (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If this is not a void function, and not the main function in a C99
|
/* If this is not a void function, and not the main function in a C99
|
||||||
|
|||||||
177
src/cc65/stmt.c
177
src/cc65/stmt.c
@@ -163,7 +163,7 @@ static int IfStatement (void)
|
|||||||
TestResult = TestInParens (Label1, 0);
|
TestResult = TestInParens (Label1, 0);
|
||||||
|
|
||||||
/* Parse the if body */
|
/* Parse the if body */
|
||||||
GotBreak = Statement (0);
|
GotBreak = AnyStatement (0);
|
||||||
|
|
||||||
/* Else clause present? */
|
/* Else clause present? */
|
||||||
if (CurTok.Tok != TOK_ELSE) {
|
if (CurTok.Tok != TOK_ELSE) {
|
||||||
@@ -195,7 +195,7 @@ static int IfStatement (void)
|
|||||||
g_defcodelabel (Label1);
|
g_defcodelabel (Label1);
|
||||||
|
|
||||||
/* Total break only if both branches had a break. */
|
/* Total break only if both branches had a break. */
|
||||||
GotBreak &= Statement (0);
|
GotBreak &= AnyStatement (0);
|
||||||
|
|
||||||
/* Generate the label for the else clause */
|
/* Generate the label for the else clause */
|
||||||
g_defcodelabel (Label2);
|
g_defcodelabel (Label2);
|
||||||
@@ -225,7 +225,7 @@ static void DoStatement (void)
|
|||||||
g_defcodelabel (LoopLabel);
|
g_defcodelabel (LoopLabel);
|
||||||
|
|
||||||
/* Parse the loop body */
|
/* Parse the loop body */
|
||||||
Statement (0);
|
AnyStatement (0);
|
||||||
|
|
||||||
/* Output the label for a continue */
|
/* Output the label for a continue */
|
||||||
g_defcodelabel (ContinueLabel);
|
g_defcodelabel (ContinueLabel);
|
||||||
@@ -283,7 +283,7 @@ static void WhileStatement (void)
|
|||||||
g_defcodelabel (LoopLabel);
|
g_defcodelabel (LoopLabel);
|
||||||
|
|
||||||
/* Loop body */
|
/* Loop body */
|
||||||
Statement (&PendingToken);
|
AnyStatement (&PendingToken);
|
||||||
|
|
||||||
/* Emit the while condition label */
|
/* Emit the while condition label */
|
||||||
g_defcodelabel (CondLabel);
|
g_defcodelabel (CondLabel);
|
||||||
@@ -509,7 +509,7 @@ static void ForStatement (void)
|
|||||||
|
|
||||||
/* Loop body */
|
/* Loop body */
|
||||||
g_defcodelabel (BodyLabel);
|
g_defcodelabel (BodyLabel);
|
||||||
Statement (&PendingToken);
|
AnyStatement (&PendingToken);
|
||||||
|
|
||||||
/* If we had an increment expression, move the code to the bottom of
|
/* If we had an increment expression, move the code to the bottom of
|
||||||
** the loop. In this case we don't need to jump there at the end of
|
** the loop. In this case we don't need to jump there at the end of
|
||||||
@@ -536,17 +536,20 @@ static void ForStatement (void)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
static int CompoundStatement (void)
|
static int CompoundStatement (int* PendingToken)
|
||||||
/* Compound statement. Allow any number of statements inside braces. The
|
/* Compound statement. Allow any number of statements inside braces. The
|
||||||
** function returns true if the last statement was a break or return.
|
** function returns true if the last statement was a break or return.
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
int GotBreak;
|
int GotBreak = 0;
|
||||||
|
|
||||||
/* Remember the stack at block entry */
|
/* Remember the stack at block entry */
|
||||||
int OldStack = StackPtr;
|
int OldStack = StackPtr;
|
||||||
unsigned OldBlockStackSize = CollCount (&CurrentFunc->LocalsBlockStack);
|
unsigned OldBlockStackSize = CollCount (&CurrentFunc->LocalsBlockStack);
|
||||||
|
|
||||||
|
/* Skip '{' */
|
||||||
|
NextToken ();
|
||||||
|
|
||||||
/* Enter a new lexical level */
|
/* Enter a new lexical level */
|
||||||
EnterBlockLevel ();
|
EnterBlockLevel ();
|
||||||
|
|
||||||
@@ -554,16 +557,15 @@ static int CompoundStatement (void)
|
|||||||
DeclareLocals ();
|
DeclareLocals ();
|
||||||
|
|
||||||
/* Now process statements in this block */
|
/* Now process statements in this block */
|
||||||
GotBreak = 0;
|
|
||||||
while (CurTok.Tok != TOK_RCURLY) {
|
while (CurTok.Tok != TOK_RCURLY) {
|
||||||
if (CurTok.Tok != TOK_CEOF) {
|
if (CurTok.Tok != TOK_CEOF) {
|
||||||
GotBreak = Statement (0);
|
GotBreak = AnyStatement (0);
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Clean up the stack. */
|
/* Clean up the stack if the codeflow may reach the end */
|
||||||
if (!GotBreak) {
|
if (!GotBreak) {
|
||||||
g_space (StackPtr - OldStack);
|
g_space (StackPtr - OldStack);
|
||||||
}
|
}
|
||||||
@@ -583,12 +585,80 @@ static int CompoundStatement (void)
|
|||||||
/* Leave the lexical level */
|
/* Leave the lexical level */
|
||||||
LeaveBlockLevel ();
|
LeaveBlockLevel ();
|
||||||
|
|
||||||
|
/* Skip '}' */
|
||||||
|
CheckTok (TOK_RCURLY, "'}' expected", PendingToken);
|
||||||
|
|
||||||
return GotBreak;
|
return GotBreak;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int Statement (int* PendingToken)
|
static void Statement (int* PendingToken)
|
||||||
|
/* Single-line statement */
|
||||||
|
{
|
||||||
|
ExprDesc Expr;
|
||||||
|
unsigned PrevErrorCount;
|
||||||
|
CodeMark Start, End;
|
||||||
|
|
||||||
|
/* Remember the current error count and code position */
|
||||||
|
PrevErrorCount = ErrorCount;
|
||||||
|
GetCodePos (&Start);
|
||||||
|
|
||||||
|
/* Actual statement */
|
||||||
|
ED_Init (&Expr);
|
||||||
|
Expr.Flags |= E_NEED_NONE;
|
||||||
|
Expression0 (&Expr);
|
||||||
|
|
||||||
|
/* If the statement didn't generate code, and is not of type
|
||||||
|
** void, emit a warning.
|
||||||
|
*/
|
||||||
|
GetCodePos (&End);
|
||||||
|
if (!ED_YetToLoad (&Expr) &&
|
||||||
|
!ED_MayHaveNoEffect (&Expr) &&
|
||||||
|
CodeRangeIsEmpty (&Start, &End) &&
|
||||||
|
IS_Get (&WarnNoEffect) &&
|
||||||
|
PrevErrorCount == ErrorCount) {
|
||||||
|
Warning ("Expression result unused");
|
||||||
|
}
|
||||||
|
CheckSemi (PendingToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static int ParseAnyLabels (void)
|
||||||
|
/* Return -1 if there are any labels with a statement */
|
||||||
|
{
|
||||||
|
unsigned PrevErrorCount = ErrorCount;
|
||||||
|
int HasLabels = 0;
|
||||||
|
for (;;) {
|
||||||
|
if (CurTok.Tok == TOK_IDENT && NextTok.Tok == TOK_COLON) {
|
||||||
|
/* C 'goto' label */
|
||||||
|
DoLabel ();
|
||||||
|
} else if (CurTok.Tok == TOK_CASE) {
|
||||||
|
/* C 'case' label */
|
||||||
|
CaseLabel ();
|
||||||
|
} else if (CurTok.Tok == TOK_DEFAULT) {
|
||||||
|
/* C 'default' label */
|
||||||
|
DefaultLabel ();
|
||||||
|
} else {
|
||||||
|
/* No labels */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
HasLabels = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (HasLabels) {
|
||||||
|
if (PrevErrorCount != ErrorCount || CheckLabelWithoutStatement ()) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int AnyStatement (int* PendingToken)
|
||||||
/* Statement parser. Returns 1 if the statement does a return/break, returns
|
/* Statement parser. Returns 1 if the statement does a return/break, returns
|
||||||
** 0 otherwise. If the PendingToken pointer is not NULL, the function will
|
** 0 otherwise. If the PendingToken pointer is not NULL, the function will
|
||||||
** not skip the terminating token of the statement (closing brace or
|
** not skip the terminating token of the statement (closing brace or
|
||||||
@@ -598,40 +668,27 @@ int Statement (int* PendingToken)
|
|||||||
** NULL, the function will skip the token.
|
** NULL, the function will skip the token.
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
ExprDesc Expr;
|
|
||||||
int GotBreak;
|
|
||||||
unsigned PrevErrorCount;
|
|
||||||
CodeMark Start, End;
|
|
||||||
|
|
||||||
ED_Init (&Expr);
|
|
||||||
|
|
||||||
/* Assume no pending token */
|
/* Assume no pending token */
|
||||||
if (PendingToken) {
|
if (PendingToken) {
|
||||||
*PendingToken = 0;
|
*PendingToken = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check for a label. A label is always part of a statement, it does not
|
/* Handle any labels. A label is always part of a statement, it does not
|
||||||
** replace one.
|
** replace one.
|
||||||
*/
|
*/
|
||||||
while (CurTok.Tok == TOK_IDENT && NextTok.Tok == TOK_COLON) {
|
if (ParseAnyLabels ()) {
|
||||||
/* Handle the label */
|
return 0;
|
||||||
DoLabel ();
|
|
||||||
if (CheckLabelWithoutStatement ()) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (CurTok.Tok) {
|
switch (CurTok.Tok) {
|
||||||
|
|
||||||
case TOK_LCURLY:
|
|
||||||
NextToken ();
|
|
||||||
GotBreak = CompoundStatement ();
|
|
||||||
CheckTok (TOK_RCURLY, "'{' expected", PendingToken);
|
|
||||||
return GotBreak;
|
|
||||||
|
|
||||||
case TOK_IF:
|
case TOK_IF:
|
||||||
return IfStatement ();
|
return IfStatement ();
|
||||||
|
|
||||||
|
case TOK_SWITCH:
|
||||||
|
SwitchStatement ();
|
||||||
|
break;
|
||||||
|
|
||||||
case TOK_WHILE:
|
case TOK_WHILE:
|
||||||
WhileStatement ();
|
WhileStatement ();
|
||||||
break;
|
break;
|
||||||
@@ -640,10 +697,15 @@ int Statement (int* PendingToken)
|
|||||||
DoStatement ();
|
DoStatement ();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TOK_SWITCH:
|
case TOK_FOR:
|
||||||
SwitchStatement ();
|
ForStatement ();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case TOK_GOTO:
|
||||||
|
GotoStatement ();
|
||||||
|
CheckSemi (PendingToken);
|
||||||
|
return 1;
|
||||||
|
|
||||||
case TOK_RETURN:
|
case TOK_RETURN:
|
||||||
ReturnStatement ();
|
ReturnStatement ();
|
||||||
CheckSemi (PendingToken);
|
CheckSemi (PendingToken);
|
||||||
@@ -659,55 +721,22 @@ int Statement (int* PendingToken)
|
|||||||
CheckSemi (PendingToken);
|
CheckSemi (PendingToken);
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
case TOK_FOR:
|
|
||||||
ForStatement ();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TOK_GOTO:
|
|
||||||
GotoStatement ();
|
|
||||||
CheckSemi (PendingToken);
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
case TOK_SEMI:
|
|
||||||
/* Ignore it */
|
|
||||||
CheckSemi (PendingToken);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TOK_PRAGMA:
|
case TOK_PRAGMA:
|
||||||
DoPragma ();
|
DoPragma ();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TOK_CASE:
|
case TOK_SEMI:
|
||||||
CaseLabel ();
|
/* Empty statement. Ignore it */
|
||||||
CheckLabelWithoutStatement ();
|
CheckSemi (PendingToken);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TOK_DEFAULT:
|
case TOK_LCURLY:
|
||||||
DefaultLabel ();
|
return CompoundStatement (PendingToken);
|
||||||
CheckLabelWithoutStatement ();
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
/* Remember the current error count and code position */
|
/* Simple statement */
|
||||||
PrevErrorCount = ErrorCount;
|
Statement (PendingToken);
|
||||||
GetCodePos (&Start);
|
break;
|
||||||
|
|
||||||
/* Actual statement */
|
|
||||||
Expr.Flags |= E_NEED_NONE;
|
|
||||||
Expression0 (&Expr);
|
|
||||||
|
|
||||||
/* If the statement didn't generate code, and is not of type
|
|
||||||
** void, emit a warning.
|
|
||||||
*/
|
|
||||||
GetCodePos (&End);
|
|
||||||
if (!ED_YetToLoad (&Expr) &&
|
|
||||||
!ED_MayHaveNoEffect (&Expr) &&
|
|
||||||
CodeRangeIsEmpty (&Start, &End) &&
|
|
||||||
IS_Get (&WarnNoEffect) &&
|
|
||||||
PrevErrorCount == ErrorCount) {
|
|
||||||
Warning ("Expression result unused");
|
|
||||||
}
|
|
||||||
CheckSemi (PendingToken);
|
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,7 +44,7 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
int Statement (int* PendingToken);
|
int AnyStatement (int* PendingToken);
|
||||||
/* Statement parser. Returns 1 if the statement does a return/break, returns
|
/* Statement parser. Returns 1 if the statement does a return/break, returns
|
||||||
** 0 otherwise. If the PendingToken pointer is not NULL, the function will
|
** 0 otherwise. If the PendingToken pointer is not NULL, the function will
|
||||||
** not skip the terminating token of the statement (closing brace or
|
** not skip the terminating token of the statement (closing brace or
|
||||||
|
|||||||
@@ -148,7 +148,7 @@ void SwitchStatement (void)
|
|||||||
/* Parse the following statement, which may actually be a compound
|
/* Parse the following statement, which may actually be a compound
|
||||||
** statement if there is a curly brace at the current input position
|
** statement if there is a curly brace at the current input position
|
||||||
*/
|
*/
|
||||||
HaveBreak = Statement (&RCurlyBrace);
|
HaveBreak = AnyStatement (&RCurlyBrace);
|
||||||
|
|
||||||
/* Check if we had any labels */
|
/* Check if we had any labels */
|
||||||
if (CollCount (SwitchData.Nodes) == 0 && SwitchData.DefaultLabel == 0) {
|
if (CollCount (SwitchData.Nodes) == 0 && SwitchData.DefaultLabel == 0) {
|
||||||
|
|||||||
Reference in New Issue
Block a user