Fixed 'case'/'default' labels in non-compound 'switch' body statement.

This commit is contained in:
acqn
2021-05-16 16:06:52 +08:00
committed by Oliver Schmidt
parent a9af6aa743
commit 43ca887263
4 changed files with 106 additions and 77 deletions

View File

@@ -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

View File

@@ -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;
} }

View File

@@ -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

View File

@@ -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) {