X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=src%2Fcc65%2Fstmt.c;h=67742113cdda5532c7e9540d6d3a48042118702f;hb=57c2e0cc0bcda3d08692abc60f5c85510801801d;hp=51a6009e365dec7a8e33815a3893570226af60d2;hpb=9cc25f13b6aabc4fd299c54c9c38c5825689eb47;p=cc65 diff --git a/src/cc65/stmt.c b/src/cc65/stmt.c index 51a6009e3..67742113c 100644 --- a/src/cc65/stmt.c +++ b/src/cc65/stmt.c @@ -1,16 +1,46 @@ -/* - * stmt.c - * - * Ullrich von Bassewitz, 06.08.1998 - * - * Original by John R. Dunning - see copyleft.jrd - */ +/*****************************************************************************/ +/* */ +/* stmt.c */ +/* */ +/* Parse a statement */ +/* */ +/* */ +/* */ +/* (C) 1998-2004 Ullrich von Bassewitz */ +/* Römerstraße 52 */ +/* D-70794 Filderstadt */ +/* EMail: uz@cc65.org */ +/* */ +/* */ +/* This software is provided 'as-is', without any expressed or implied */ +/* warranty. In no event will the authors be held liable for any damages */ +/* arising from the use of this software. */ +/* */ +/* Permission is granted to anyone to use this software for any purpose, */ +/* including commercial applications, and to alter it and redistribute it */ +/* freely, subject to the following restrictions: */ +/* */ +/* 1. The origin of this software must not be misrepresented; you must not */ +/* claim that you wrote the original software. If you use this software */ +/* in a product, an acknowledgment in the product documentation would be */ +/* appreciated but is not required. */ +/* 2. Altered source versions must be plainly marked as such, and must not */ +/* be misrepresented as being the original software. */ +/* 3. This notice may not be removed or altered from any source */ +/* distribution. */ +/* */ +/*****************************************************************************/ #include #include +/* common */ +#include "coll.h" +#include "xmalloc.h" + +/* cc65 */ #include "asmcode.h" #include "asmlabel.h" #include "codegen.h" @@ -21,59 +51,109 @@ #include "global.h" #include "goto.h" #include "litpool.h" +#include "loadexpr.h" #include "locals.h" #include "loop.h" -#include "mem.h" #include "pragma.h" #include "scanner.h" +#include "stackptr.h" +#include "swstmt.h" #include "symtab.h" #include "stmt.h" +#include "testexpr.h" +#include "typeconv.h" /*****************************************************************************/ -/* Data */ +/* Helper functions */ /*****************************************************************************/ -/* Maximum count of cases */ -#define CASE_MAX 257 +static void CheckTok (token_t Tok, const char* Msg, int* PendingToken) +/* Helper function for Statement. Will check for Tok and print Msg if not + * found. If PendingToken is NULL, it will the skip the token, otherwise + * it will store one to PendingToken. + */ +{ + if (CurTok.Tok != Tok) { + Error (Msg); + } else if (PendingToken) { + *PendingToken = 1; + } else { + NextToken (); + } +} -/*****************************************************************************/ -/* Code */ -/*****************************************************************************/ +static void CheckSemi (int* PendingToken) +/* Helper function for Statement. Will check for a semicolon and print an + * error message if not found (plus some error recovery). If PendingToken is + * NULL, it will the skip the token, otherwise it will store one to + * PendingToken. + * This function is a special version of CheckTok with the addition of the + * error recovery. + */ +{ + int HaveToken = (CurTok.Tok == TOK_SEMI); + if (!HaveToken) { + Error ("`;' expected"); + /* Try to be smart about errors */ + if (CurTok.Tok == TOK_COLON || CurTok.Tok == TOK_COMMA) { + HaveToken = 1; + } + } + if (HaveToken) { + if (PendingToken) { + *PendingToken = 1; + } else { + NextToken (); + } + } +} + + +static void SkipPending (int PendingToken) +/* Skip the pending token if we have one */ +{ + if (PendingToken) { + NextToken (); + } +} -static int statement (void); -/* Forward decl */ +/*****************************************************************************/ +/* Code */ +/*****************************************************************************/ -static int doif (void) -/* Handle 'if' statement here */ + +static int IfStatement (void) +/* Handle an 'if' statement */ { - int flab1; - int flab2; - int gotbreak; + unsigned Label1; + unsigned TestResult; + int GotBreak; /* Skip the if */ NextToken (); /* Generate a jump label and parse the condition */ - flab1 = GetLabel (); - test (flab1, 0); + Label1 = GetLocalLabel (); + TestResult = TestInParens (Label1, 0); /* Parse the if body */ - gotbreak = statement (); + GotBreak = Statement (0); /* Else clause present? */ - if (curtok != TOK_ELSE) { + if (CurTok.Tok != TOK_ELSE) { + + g_defcodelabel (Label1); - g_defloclabel (flab1); /* Since there's no else clause, we're not sure, if the a break * statement is really executed. */ @@ -81,591 +161,457 @@ static int doif (void) } else { - /* Skip the else */ + /* Generate a jump around the else branch */ + unsigned Label2 = GetLocalLabel (); + g_jump (Label2); + + /* Skip the else */ NextToken (); - /* If we had some sort of break statement at the end of the if clause, - * there's no need to generate an additional jump around the else - * clause, since the jump is never reached. - */ - if (!gotbreak) { - flab2 = GetLabel (); - g_jump (flab2); - } else { - /* Mark the label as unused */ - flab2 = 0; - } - g_defloclabel (flab1); - gotbreak &= statement (); + /* If the if expression was always true, the code in the else branch + * is never executed. Output a warning if this is the case. + */ + if (TestResult == TESTEXPR_TRUE) { + Warning ("Unreachable code"); + } + + /* Define the target for the first test */ + g_defcodelabel (Label1); + + /* Total break only if both branches had a break. */ + GotBreak &= Statement (0); /* Generate the label for the else clause */ - if (flab2) { - g_defloclabel (flab2); - } + g_defcodelabel (Label2); /* Done */ - return gotbreak; + return GotBreak; } } -static void dowhile (char wtype) -/* Handle 'while' statement here */ +static void DoStatement (void) +/* Handle the 'do' statement */ { - int loop; - int lab; + /* Get the loop control labels */ + unsigned LoopLabel = GetLocalLabel (); + unsigned BreakLabel = GetLocalLabel (); + unsigned ContinueLabel = GetLocalLabel (); + /* Skip the while token */ NextToken (); - loop = GetLabel (); - lab = GetLabel (); - addloop (oursp, loop, lab, 0, 0); - g_defloclabel (loop); - if (wtype == 'w') { - - /* While loop */ - test (lab, 0); - - /* If the statement following the while loop is empty, that is, we have - * something like "while (1) ;", the test function ommitted the jump as - * an optimization. Since we know, the condition codes are set, we can - * do another small optimization here, and use a conditional jump - * instead an absolute one. - */ - if (curtok == TOK_SEMI) { - /* Shortcut */ - NextToken (); - /* Use a conditional jump */ - g_truejump (CF_NONE, loop); - } else { - /* There is code inside the while loop */ - statement (); - g_jump (loop); - g_defloclabel (lab); - } - } else { + /* Add the loop to the loop stack */ + AddLoop (BreakLabel, ContinueLabel); - /* Do loop */ - statement (); - Consume (TOK_WHILE, ERR_WHILE_EXPECTED); - test (loop, 1); - ConsumeSemi (); - g_defloclabel (lab); + /* Define the loop label */ + g_defcodelabel (LoopLabel); - } - delloop (); + /* Parse the loop body */ + Statement (0); + + /* Output the label for a continue */ + g_defcodelabel (ContinueLabel); + + /* Parse the end condition */ + Consume (TOK_WHILE, "`while' expected"); + TestInParens (LoopLabel, 1); + ConsumeSemi (); + + /* Define the break label */ + g_defcodelabel (BreakLabel); + + /* Remove the loop from the loop stack */ + DelLoop (); } -static void doreturn (void) -/* Handle 'return' statement here */ +static void WhileStatement (void) +/* Handle the 'while' statement */ { - struct expent lval; - unsigned etype = 0; /* Type of return expression */ - int HaveVal = 0; /* Do we have a return value in ax? */ + int PendingToken; + /* Get the loop control labels */ + unsigned LoopLabel = GetLocalLabel (); + unsigned BreakLabel = GetLocalLabel (); + /* Skip the while token */ NextToken (); - if (curtok != TOK_SEMI) { - if (HasVoidReturn (CurrentFunc)) { - Error (ERR_CANNOT_RETURN_VALUE); - } - if (evalexpr (CF_NONE, hie0, &lval) == 0) { - /* Constant value */ - etype = CF_CONST; - } else { - /* Value in the primary register */ - HaveVal = 1; - } - /* Convert the return value to the type of the function result */ - if (!HasVoidReturn (CurrentFunc)) { - etype |= assignadjust (GetReturnType (CurrentFunc), &lval) & ~CF_CONST; - } - } else if (!HasVoidReturn (CurrentFunc)) { - Error (ERR_MUST_RETURN_VALUE); - } - RestoreRegVars (HaveVal); - g_leave (etype, lval.e_const); -} + /* Add the loop to the loop stack. In case of a while loop, the loop head + * label is used for continue statements. + */ + AddLoop (BreakLabel, LoopLabel); + /* Define the head label */ + g_defcodelabel (LoopLabel); + /* Test the loop condition */ + TestInParens (BreakLabel, 0); -static void dobreak (void) -/* Handle 'break' statement here */ -{ - struct loopdesc* l; + /* Loop body */ + Statement (&PendingToken); - NextToken (); - if ((l = currentloop ()) == 0) { - /* Error: No current loop */ - return; - } - g_space (oursp - l->sp); - g_jump (l->label); + /* Jump back to loop top */ + g_jump (LoopLabel); + + /* Exit label */ + g_defcodelabel (BreakLabel); + + /* Eat remaining tokens that were delayed because of line info + * correctness + */ + SkipPending (PendingToken); + + /* Remove the loop from the loop stack */ + DelLoop (); } -static void docontinue (void) -/* Handle 'continue' statement here */ +static void ReturnStatement (void) +/* Handle the 'return' statement */ { - struct loopdesc* l; + ExprDesc Expr; NextToken (); - if ((l = currentloop ()) == 0) { - /* Error: Not in loop */ - return; - } - do { - if (l->loop) { - break; - } - l = l->next; - } while (l); - if (l == 0) { - Error (ERR_UNEXPECTED_CONTINUE); - return; - } - g_space (oursp - l->sp); - if (l->linc) { - g_jump (l->linc); - } else { - g_jump (l->loop); - } -} + if (CurTok.Tok != TOK_SEMI) { + /* Check if the function has a return value declared */ + if (F_HasVoidReturn (CurrentFunc)) { + Error ("Returning a value in function with return type void"); + } + /* Evaluate the return expression */ + hie0 (&Expr); -static void cascadeswitch (struct expent* eval) -/* Handle a switch statement for chars with a cmp cascade for the selector */ -{ - unsigned exitlab; /* Exit label */ - unsigned nextlab; /* Next case label */ - unsigned codelab; /* Label that starts the actual selector code */ - int havebreak; /* Remember if we exited with break */ - int lcount; /* Label count */ - unsigned flags; /* Code generator flags */ - struct expent lval; /* Case label expression */ - long val; /* Case label value */ - - - /* Create a loop so we may break out, init labels */ - exitlab = GetLabel (); - addloop (oursp, 0, exitlab, 0, 0); - - /* Setup some variables needed in the loop below */ - flags = TypeOf (eval->e_tptr) | CF_CONST | CF_FORCECHAR; - codelab = nextlab = 0; - havebreak = 1; - - /* Parse the labels */ - lcount = 0; - while (curtok != TOK_RCURLY) { - - if (curtok == TOK_CASE || curtok == TOK_DEFAULT) { - - /* If the code for the previous selector did not end with a - * break statement, we must jump over the next selector test. - */ - if (!havebreak) { - /* Define a label for the code */ - if (codelab == 0) { - codelab = GetLabel (); - } - g_jump (codelab); - } - - /* If we have a cascade label, emit it */ - if (nextlab) { - g_defloclabel (nextlab); - nextlab = 0; - } - - while (curtok == TOK_CASE || curtok == TOK_DEFAULT) { - - /* Parse the selector */ - if (curtok == TOK_CASE) { - - /* Count labels */ - ++lcount; - - /* Skip the "case" token */ - NextToken (); - - /* Read the selector expression */ - constexpr (&lval); - if (!IsInt (lval.e_tptr)) { - Error (ERR_ILLEGAL_TYPE); - } - - /* Check the range of the expression */ - val = lval.e_const; - switch (*eval->e_tptr) { - - case T_CHAR: - /* Signed char */ - if (val < -128 || val > 127) { - Error (ERR_RANGE); - } - break; - - case T_UCHAR: - if (val < 0 || val > 255) { - Error (ERR_RANGE); - } - break; - - case T_INT: - if (val < -32768 || val > 32767) { - Error (ERR_RANGE); - } - break; - - case T_UINT: - if (val < 0 || val > 65535) { - Error (ERR_RANGE); - } - break; - - default: - Internal ("Invalid type: %02X", *eval->e_tptr & 0xFF); - } - - /* Skip the colon */ - ConsumeColon (); - - /* Emit a compare */ - g_cmp (flags, val); - - /* If another case follows, we will jump to the code if - * the condition is true. - */ - if (curtok == TOK_CASE) { - /* Create a code label if needed */ - if (codelab == 0) { - codelab = GetLabel (); - } - g_falsejump (CF_NONE, codelab); - } else if (curtok != TOK_DEFAULT) { - /* No case follows, jump to next selector */ - if (nextlab == 0) { - nextlab = GetLabel (); - } - g_truejump (CF_NONE, nextlab); - } - - } else { - - /* Default case */ - NextToken (); - - /* Skip the colon */ - ConsumeColon (); - - /* Handle the pathologic case: DEFAULT followed by CASE */ - if (curtok == TOK_CASE) { - if (codelab == 0) { - codelab = GetLabel (); - } - g_jump (codelab); - } - } - - } + /* Ignore the return expression if the function returns void */ + if (!F_HasVoidReturn (CurrentFunc)) { - } + /* Convert the return value to the type of the function result */ + TypeConversion (&Expr, F_GetReturnType (CurrentFunc)); - /* Emit a code label if we have one */ - if (codelab) { - g_defloclabel (codelab); - codelab = 0; - } + /* Load the value into the primary */ + LoadExpr (CF_NONE, &Expr); + } - /* Parse statements */ - if (curtok != TOK_RCURLY) { - havebreak = statement (); - } + } else if (!F_HasVoidReturn (CurrentFunc) && !F_HasOldStyleIntRet (CurrentFunc)) { + Error ("Function `%s' must return a value", F_GetFuncName (CurrentFunc)); } - /* Check if we have any labels */ - if (lcount == 0) { - Warning (WARN_NO_CASE_LABELS); - } + /* Cleanup the stack in case we're inside a block with locals */ + g_space (StackPtr - F_GetTopLevelSP (CurrentFunc)); + + /* Output a jump to the function exit code */ + g_jump (F_GetRetLab (CurrentFunc)); +} - /* Eat the closing curly brace */ + + +static void BreakStatement (void) +/* Handle the 'break' statement */ +{ + LoopDesc* L; + + /* Skip the break */ NextToken (); - /* Define the exit label and, if there's a next label left, create this - * one, too. - */ - if (nextlab) { - g_defloclabel (nextlab); + /* Get the current loop descriptor */ + L = CurrentLoop (); + + /* Check if we are inside a loop */ + if (L == 0) { + /* Error: No current loop */ + Error ("`break' statement not within loop or switch"); + return; } - g_defloclabel (exitlab); - /* End the loop */ - delloop (); + /* Correct the stack pointer if needed */ + g_space (StackPtr - L->StackPtr); + + /* Jump to the exit label of the loop */ + g_jump (L->BreakLabel); } -static void tableswitch (struct expent* eval) -/* Handle a switch statement via table based selector */ +static void ContinueStatement (void) +/* Handle the 'continue' statement */ { - /* Entry for one case in a switch statement */ - struct swent { - long sw_const; /* selector value */ - unsigned sw_lab; /* label for this selector */ - }; - - int dlabel; /* for default */ - int lab; /* exit label */ - int label; /* label for case */ - int lcase; /* label for compares */ - int lcount; /* Label count */ - int havebreak; /* Last statement has a break */ - unsigned flags; /* Code generator flags */ - struct expent lval; /* Case label expression */ - struct swent *p; - struct swent *swtab; - - /* Allocate memory for the switch table */ - swtab = xmalloc (CASE_MAX * sizeof (struct swent)); - - /* Create a look so we may break out, init labels */ - havebreak = 0; /* Keep gcc silent */ - dlabel = 0; /* init */ - lab = GetLabel (); /* get exit */ - p = swtab; - addloop (oursp, 0, lab, 0, 0); - - /* Jump behind the code for the CASE labels */ - g_jump (lcase = GetLabel ()); - lcount = 0; - while (curtok != TOK_RCURLY) { - if (curtok == TOK_CASE || curtok == TOK_DEFAULT) { - if (lcount >= CASE_MAX) { - Fatal (FAT_TOO_MANY_CASE_LABELS); + LoopDesc* L; + + /* Skip the continue */ + NextToken (); + + /* Get the current loop descriptor */ + L = CurrentLoop (); + if (L) { + /* Search for a loop that has a continue label. */ + do { + if (L->ContinueLabel) { + break; } - label = GetLabel (); - do { - if (curtok == TOK_CASE) { - NextToken (); - constexpr (&lval); - if (!IsInt (lval.e_tptr)) { - Error (ERR_ILLEGAL_TYPE); - } - p->sw_const = lval.e_const; - p->sw_lab = label; - ++p; - ++lcount; - } else { - NextToken (); - dlabel = label; - } - ConsumeColon (); - } while (curtok == TOK_CASE || curtok == TOK_DEFAULT); - g_defloclabel (label); - havebreak = 0; - } - if (curtok != TOK_RCURLY) { - havebreak = statement (); - } + L = L->Next; + } while (L); } - /* Check if we have any labels */ - if (lcount == 0) { - Warning (WARN_NO_CASE_LABELS); + /* Did we find it? */ + if (L == 0) { + Error ("`continue' statement not within a loop"); + return; } - /* Eat the closing curly brace */ - NextToken (); + /* Correct the stackpointer if needed */ + g_space (StackPtr - L->StackPtr); - /* If the last statement doesn't have a break or return, add one */ - if (!havebreak) { - g_jump (lab); - } + /* Jump to next loop iteration */ + g_jump (L->ContinueLabel); +} - /* Actual selector code goes here */ - g_defloclabel (lcase); - /* Create the call to the switch subroutine */ - flags = TypeOf (eval->e_tptr); - g_switch (flags); - /* First entry is negative of label count */ - g_defdata (CF_INT | CF_CONST, -((int)lcount)-1, 0); +static void ForStatement (void) +/* Handle a 'for' statement */ +{ + ExprDesc lval1; + ExprDesc lval3; + int HaveIncExpr; + CodeMark IncExprStart; + CodeMark IncExprEnd; + int PendingToken; + + /* Get several local labels needed later */ + unsigned TestLabel = GetLocalLabel (); + unsigned BreakLabel = GetLocalLabel (); + unsigned IncLabel = GetLocalLabel (); + unsigned BodyLabel = GetLocalLabel (); + + /* Skip the FOR token */ + NextToken (); + + /* Add the loop to the loop stack. A continue jumps to the start of the + * the increment condition. + */ + AddLoop (BreakLabel, IncLabel); + + /* Skip the opening paren */ + ConsumeLParen (); - /* Create the case selector table */ - AddCodeHint ("casetable"); - p = swtab; - while (lcount) { - g_case (flags, p->sw_lab, p->sw_const); /* Create one label */ - --lcount; - ++p; + /* Parse the initializer expression */ + if (CurTok.Tok != TOK_SEMI) { + Expression0 (&lval1); } + ConsumeSemi (); + + /* Label for the test expressions */ + g_defcodelabel (TestLabel); - if (dlabel) { - g_jump (dlabel); + /* Parse the test expression */ + if (CurTok.Tok != TOK_SEMI) { + Test (BodyLabel, 1); + g_jump (BreakLabel); + } else { + g_jump (BodyLabel); } - g_defloclabel (lab); - delloop (); + ConsumeSemi (); - /* Free the allocated space for the labels */ - xfree (swtab); -} + /* Remember the start of the increment expression */ + GetCodePos (&IncExprStart); + /* Label for the increment expression */ + g_defcodelabel (IncLabel); + /* Parse the increment expression */ + HaveIncExpr = (CurTok.Tok != TOK_RPAREN); + if (HaveIncExpr) { + Expression0 (&lval3); + } -static void doswitch (void) -/* Handle 'switch' statement here */ -{ - struct expent eval; /* Switch statement expression */ + /* Jump to the test */ + g_jump (TestLabel); - /* Eat the "switch" */ - NextToken (); + /* Remember the end of the increment expression */ + GetCodePos (&IncExprEnd); - /* Read the switch expression */ - ConsumeLParen (); - intexpr (&eval); + /* Skip the closing paren */ ConsumeRParen (); - /* result of expr is in P */ - ConsumeLCurly (); + /* Loop body */ + g_defcodelabel (BodyLabel); + Statement (&PendingToken); - /* Now decide which sort of switch we will create: */ - if (IsChar (eval.e_tptr) || (FavourSize == 0 && IsInt (eval.e_tptr))) { - cascadeswitch (&eval); + /* 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 body. + */ + if (HaveIncExpr) { + CodeMark Here; + GetCodePos (&Here); + MoveCode (&IncExprStart, &IncExprEnd, &Here); } else { - tableswitch (&eval); + /* Jump back to the increment expression */ + g_jump (IncLabel); } + + /* Skip a pending token if we have one */ + SkipPending (PendingToken); + + /* Declare the break label */ + g_defcodelabel (BreakLabel); + + /* Remove the loop from the loop stack */ + DelLoop (); } -static void dofor (void) -/* Handle 'for' statement here */ +static int CompoundStatement (void) +/* Compound statement. Allow any number of statements inside braces. The + * function returns true if the last statement was a break or return. + */ { - int loop; - int lab; - int linc; - int lstat; - struct expent lval1; - struct expent lval2; - struct expent lval3; + int GotBreak; - NextToken (); - loop = GetLabel (); - lab = GetLabel (); - linc = GetLabel (); - lstat = GetLabel (); - addloop (oursp, loop, lab, linc, lstat); - ConsumeLParen (); - if (curtok != TOK_SEMI) { /* exp1 */ - expression (&lval1); - } - ConsumeSemi (); - g_defloclabel (loop); - if (curtok != TOK_SEMI) { /* exp2 */ - boolexpr (&lval2); - g_truejump (CF_NONE, lstat); - g_jump (lab); - } else { - g_jump (lstat); + /* Remember the stack at block entry */ + int OldStack = StackPtr; + + /* Enter a new lexical level */ + EnterBlockLevel (); + + /* Parse local variable declarations if any */ + DeclareLocals (); + + /* Now process statements in this block */ + GotBreak = 0; + while (CurTok.Tok != TOK_RCURLY) { + if (CurTok.Tok != TOK_CEOF) { + GotBreak = Statement (0); + } else { + break; + } } - ConsumeSemi (); - g_defloclabel (linc); - if (curtok != TOK_RPAREN) { /* exp3 */ - expression (&lval3); + + /* Clean up the stack. */ + if (!GotBreak) { + g_space (StackPtr - OldStack); } - ConsumeRParen (); - g_jump (loop); - g_defloclabel (lstat); - statement (); - g_jump (linc); - g_defloclabel (lab); - delloop (); + StackPtr = OldStack; + + /* Emit references to imports/exports for this block */ + EmitExternals (); + + /* Leave the lexical level */ + LeaveBlockLevel (); + + return GotBreak; } -static int statement (void) -/* Statement parser. Called whenever syntax requires a statement. - * This routine performs that statement and returns 1 if it is a branch, - * 0 otherwise +int Statement (int* PendingToken) +/* Statement parser. Returns 1 if the statement does a return/break, returns + * 0 otherwise. If the PendingToken pointer is not NULL, the function will + * not skip the terminating token of the statement (closing brace or + * semicolon), but store true if there is a pending token, and false if there + * is none. The token is always checked, so there is no need for the caller to + * check this token, it must be skipped, however. If the argument pointer is + * NULL, the function will skip the token. */ { - struct expent lval; + ExprDesc Expr; + int GotBreak; + CodeMark Start, End; - /* */ - if (curtok == TOK_IDENT && nxttok == TOK_COLON) { + /* Assume no pending token */ + if (PendingToken) { + *PendingToken = 0; + } + + /* Check for a label */ + if (CurTok.Tok == TOK_IDENT && NextTok.Tok == TOK_COLON) { /* Special handling for a label */ DoLabel (); } else { - switch (curtok) { + switch (CurTok.Tok) { case TOK_LCURLY: - return compound (); + NextToken (); + GotBreak = CompoundStatement (); + CheckTok (TOK_RCURLY, "`{' expected", PendingToken); + return GotBreak; case TOK_IF: - return doif (); + return IfStatement (); case TOK_WHILE: - dowhile ('w'); - break; + WhileStatement (); + break; case TOK_DO: - dowhile ('d'); - break; + DoStatement (); + break; case TOK_SWITCH: - doswitch (); - break; + SwitchStatement (); + break; case TOK_RETURN: - doreturn (); - ConsumeSemi (); - return 1; + ReturnStatement (); + CheckSemi (PendingToken); + return 1; case TOK_BREAK: - dobreak (); - ConsumeSemi (); + BreakStatement (); + CheckSemi (PendingToken); return 1; case TOK_CONTINUE: - docontinue (); - ConsumeSemi (); + ContinueStatement (); + CheckSemi (PendingToken); return 1; case TOK_FOR: - dofor (); + ForStatement (); break; case TOK_GOTO: - DoGoto (); - ConsumeSemi (); + GotoStatement (); + CheckSemi (PendingToken); return 1; case TOK_SEMI: - /* ignore it. */ - NextToken (); + /* Ignore it */ + CheckSemi (PendingToken); break; case TOK_PRAGMA: DoPragma (); - break; + break; default: - AddCodeHint ("stmt:start"); - expression (&lval); - AddCodeHint ("stmt:end"); - ConsumeSemi (); + /* Remember the current code position */ + GetCodePos (&Start); + /* Actual statement */ + ExprWithCheck (hie0, &Expr); + /* Load the result only if it is an lvalue and the type is + * marked as volatile. Otherwise the load is useless. + */ + if (ED_IsLVal (&Expr) && IsQualVolatile (Expr.Type)) { + LoadExpr (CF_NONE, &Expr); + } + /* 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"); + } + CheckSemi (PendingToken); } } return 0; @@ -673,61 +619,4 @@ static int statement (void) -int compound (void) -/* Compound statement. Allow any number of statements, inside braces. */ -{ - static unsigned CurrentLevel = 0; - - int isbrk; - int oldsp; - - /* eat LCURLY */ - NextToken (); - - /* Remember the stack at block entry */ - oldsp = oursp; - - /* If we're not on function level, enter a new lexical level */ - if (CurrentLevel++ > 0) { - /* A nested block */ - EnterBlockLevel (); - } - - /* Parse local variable declarations if any */ - DeclareLocals (); - - /* Now process statements in the function body */ - isbrk = 0; - while (curtok != TOK_RCURLY) { - if (curtok == TOK_CEOF) - break; - else { - isbrk = statement (); - } - } - - /* Emit references to imports/exports for this block */ - EmitExternals (); - - /* If this is not the top level compound statement, clean up the stack. - * For a top level statement this will be done by the function exit code. - */ - if (--CurrentLevel != 0) { - /* Some sort of nested block */ - LeaveBlockLevel (); - if (isbrk) { - oursp = oldsp; - } else { - g_space (oursp - oldsp); - oursp = oldsp; - } - } - - /* Eat closing brace */ - ConsumeRCurly (); - - return isbrk; -} - -