X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=src%2Fcc65%2Fstmt.c;h=5078bfa11a1d32c4076e304247fd1b2d1bcde8cb;hb=112ae0e3db511ddd92e769c11328646ebe2a6240;hp=55478e84fc862e7181c793427a65b77358364be9;hpb=1483fa741a8c1c3565e1fb84a885ebf382b08f46;p=cc65 diff --git a/src/cc65/stmt.c b/src/cc65/stmt.c index 55478e84f..5078bfa11 100644 --- a/src/cc65/stmt.c +++ b/src/cc65/stmt.c @@ -6,10 +6,10 @@ /* */ /* */ /* */ -/* (C) 1998-2001 Ullrich von Bassewitz */ -/* Wacholderweg 14 */ -/* D-70597 Stuttgart */ -/* EMail: uz@cc65.org */ +/* (C) 1998-2009, Ullrich von Bassewitz */ +/* Roemerstrasse 52 */ +/* D-70794 Filderstadt */ +/* EMail: uz@cc65.org */ /* */ /* */ /* This software is provided 'as-is', without any expressed or implied */ @@ -51,13 +51,17 @@ #include "global.h" #include "goto.h" #include "litpool.h" +#include "loadexpr.h" #include "locals.h" #include "loop.h" #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" @@ -67,6 +71,19 @@ +static void CheckLabelWithoutStatement (void) +/* Called from Statement() after a label definition. Will check for a + * following closing curly brace. This means that a label is not followed + * by a statement which is required by the standard. Output an error if so. + */ +{ + if (CurTok.Tok == TOK_RCURLY) { + Error ("Label at end of compound statement"); + } +} + + + 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 @@ -74,22 +91,40 @@ static void CheckTok (token_t Tok, const char* Msg, int* PendingToken) */ { if (CurTok.Tok != Tok) { - Error (Msg); + Error ("%s", Msg); } else if (PendingToken) { - *PendingToken = 1; + *PendingToken = 1; } else { - NextToken (); + NextToken (); } } static void CheckSemi (int* PendingToken) -/* Helper function for Statement. Will call CheckTok with the parameters - * for a semicolon. +/* 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. */ { - CheckTok (TOK_SEMI, "`;' expected", PendingToken); + 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 (); + } + } } @@ -114,6 +149,7 @@ static int IfStatement (void) /* Handle an 'if' statement */ { unsigned Label1; + unsigned TestResult; int GotBreak; /* Skip the if */ @@ -121,7 +157,7 @@ static int IfStatement (void) /* Generate a jump label and parse the condition */ Label1 = GetLocalLabel (); - test (Label1, 0); + TestResult = TestInParens (Label1, 0); /* Parse the if body */ GotBreak = Statement (0); @@ -138,21 +174,28 @@ static int IfStatement (void) } else { - /* Generate a jump around the else branch */ + /* Generate a jump around the else branch */ unsigned Label2 = GetLocalLabel (); - g_jump (Label2); + g_jump (Label2); - /* Skip the else */ + /* Skip the else */ NextToken (); - /* Define the target for the first test */ - g_defcodelabel (Label1); + /* 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. */ + /* Total break only if both branches had a break. */ GotBreak &= Statement (0); /* Generate the label for the else clause */ - g_defcodelabel (Label2); + g_defcodelabel (Label2); /* Done */ return GotBreak; @@ -165,28 +208,32 @@ static void DoStatement (void) /* Handle the 'do' statement */ { /* Get the loop control labels */ - unsigned loop = GetLocalLabel (); - unsigned lab = GetLocalLabel (); + unsigned LoopLabel = GetLocalLabel (); + unsigned BreakLabel = GetLocalLabel (); + unsigned ContinueLabel = GetLocalLabel (); /* Skip the while token */ NextToken (); /* Add the loop to the loop stack */ - AddLoop (oursp, loop, lab, 0, 0); + AddLoop (BreakLabel, ContinueLabel); - /* Define the head label */ - g_defcodelabel (loop); + /* Define the loop label */ + g_defcodelabel (LoopLabel); /* Parse the loop body */ Statement (0); + /* Output the label for a continue */ + g_defcodelabel (ContinueLabel); + /* Parse the end condition */ Consume (TOK_WHILE, "`while' expected"); - test (loop, 1); + TestInParens (LoopLabel, 1); ConsumeSemi (); /* Define the break label */ - g_defcodelabel (lab); + g_defcodelabel (BreakLabel); /* Remove the loop from the loop stack */ DelLoop (); @@ -197,32 +244,53 @@ static void DoStatement (void) static void WhileStatement (void) /* Handle the 'while' statement */ { - int PendingToken; + int PendingToken; + CodeMark CondCodeStart; /* Start of condition evaluation code */ + CodeMark CondCodeEnd; /* End of condition evaluation code */ + CodeMark Here; /* "Here" location of code */ /* Get the loop control labels */ - unsigned loop = GetLocalLabel (); - unsigned lab = GetLocalLabel (); + unsigned LoopLabel = GetLocalLabel (); + unsigned BreakLabel = GetLocalLabel (); + unsigned CondLabel = GetLocalLabel (); /* Skip the while token */ NextToken (); - /* Add the loop to the loop stack */ - AddLoop (oursp, loop, lab, 0, 0); + /* Add the loop to the loop stack. In case of a while loop, the condition + * label is used for continue statements. + */ + AddLoop (BreakLabel, CondLabel); - /* Define the head label */ - g_defcodelabel (loop); + /* We will move the code that evaluates the while condition to the end of + * the loop, so generate a jump here. + */ + g_jump (CondLabel); + + /* Remember the current position */ + GetCodePos (&CondCodeStart); + + /* Emit the code position label */ + g_defcodelabel (CondLabel); /* Test the loop condition */ - test (lab, 0); + TestInParens (LoopLabel, 1); + + /* Remember the end of the condition evaluation code */ + GetCodePos (&CondCodeEnd); + + /* Define the head label */ + g_defcodelabel (LoopLabel); /* Loop body */ Statement (&PendingToken); - /* Jump back to loop top */ - g_jump (loop); + /* Move the test code here */ + GetCodePos (&Here); + MoveCode (&CondCodeStart, &CondCodeEnd, &Here); /* Exit label */ - g_defcodelabel (lab); + g_defcodelabel (BreakLabel); /* Eat remaining tokens that were delayed because of line info * correctness @@ -238,30 +306,40 @@ static void WhileStatement (void) static void ReturnStatement (void) /* Handle the 'return' statement */ { - ExprDesc lval; + ExprDesc Expr; NextToken (); if (CurTok.Tok != TOK_SEMI) { - if (HasVoidReturn (CurrentFunc)) { - Error ("Returning a value in function with return type void"); - } - /* Evaluate the return expression. Result will be in primary */ - expression (&lval); + /* Evaluate the return expression */ + hie0 (&Expr); + + /* If we return something in a void function, print an error and + * ignore the value. Otherwise convert the value to the type of the + * return. + */ + if (F_HasVoidReturn (CurrentFunc)) { + Error ("Returning a value in function with return type void"); + } else { + /* Convert the return value to the type of the function result */ + TypeConversion (&Expr, F_GetReturnType (CurrentFunc)); - /* Convert the return value to the type of the function result */ - if (!HasVoidReturn (CurrentFunc)) { - assignadjust (GetReturnType (CurrentFunc), &lval); + /* Load the value into the primary */ + LoadExpr (CF_NONE, &Expr); } - } else if (!HasVoidReturn (CurrentFunc)) { - Error ("Function `%s' must return a value", GetFuncName (CurrentFunc)); + + } else if (!F_HasVoidReturn (CurrentFunc) && !F_HasOldStyleIntRet (CurrentFunc)) { + Error ("Function `%s' must return a value", F_GetFuncName (CurrentFunc)); } + /* Mark the function as having a return statement */ + F_ReturnFound (CurrentFunc); + /* Cleanup the stack in case we're inside a block with locals */ - g_space (oursp - GetTopLevelSP (CurrentFunc)); + g_space (StackPtr - F_GetTopLevelSP (CurrentFunc)); /* Output a jump to the function exit code */ - g_jump (GetRetLab (CurrentFunc)); + g_jump (F_GetRetLab (CurrentFunc)); } @@ -285,10 +363,10 @@ static void BreakStatement (void) } /* Correct the stack pointer if needed */ - g_space (oursp - L->StackPtr); + g_space (StackPtr - L->StackPtr); /* Jump to the exit label of the loop */ - g_jump (L->Label); + g_jump (L->BreakLabel); } @@ -304,10 +382,10 @@ static void ContinueStatement (void) /* Get the current loop descriptor */ L = CurrentLoop (); if (L) { - /* Search for the correct loop */ + /* Search for a loop that has a continue label. */ do { - if (L->Loop) { - break; + if (L->ContinueLabel) { + break; } L = L->Next; } while (L); @@ -320,14 +398,10 @@ static void ContinueStatement (void) } /* Correct the stackpointer if needed */ - g_space (oursp - L->StackPtr); + g_space (StackPtr - L->StackPtr); - /* Output the loop code */ - if (L->linc) { - g_jump (L->linc); - } else { - g_jump (L->Loop); - } + /* Jump to next loop iteration */ + g_jump (L->ContinueLabel); } @@ -336,7 +410,6 @@ static void ForStatement (void) /* Handle a 'for' statement */ { ExprDesc lval1; - ExprDesc lval2; ExprDesc lval3; int HaveIncExpr; CodeMark IncExprStart; @@ -344,23 +417,25 @@ static void ForStatement (void) int PendingToken; /* Get several local labels needed later */ - unsigned TestLabel = GetLocalLabel (); - unsigned lab = GetLocalLabel (); - unsigned IncLabel = GetLocalLabel (); - unsigned lstat = GetLocalLabel (); + unsigned TestLabel = GetLocalLabel (); + unsigned BreakLabel = GetLocalLabel (); + unsigned IncLabel = GetLocalLabel (); + unsigned BodyLabel = GetLocalLabel (); /* Skip the FOR token */ NextToken (); - /* Add the loop to the loop stack */ - AddLoop (oursp, TestLabel, lab, IncLabel, lstat); + /* 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 (); /* Parse the initializer expression */ if (CurTok.Tok != TOK_SEMI) { - expression (&lval1); + Expression0 (&lval1); } ConsumeSemi (); @@ -369,16 +444,15 @@ static void ForStatement (void) /* Parse the test expression */ if (CurTok.Tok != TOK_SEMI) { - boolexpr (&lval2); - g_truejump (CF_NONE, lstat); - g_jump (lab); + Test (BodyLabel, 1); + g_jump (BreakLabel); } else { - g_jump (lstat); + g_jump (BodyLabel); } ConsumeSemi (); /* Remember the start of the increment expression */ - IncExprStart = GetCodePos(); + GetCodePos (&IncExprStart); /* Label for the increment expression */ g_defcodelabel (IncLabel); @@ -386,20 +460,20 @@ static void ForStatement (void) /* Parse the increment expression */ HaveIncExpr = (CurTok.Tok != TOK_RPAREN); if (HaveIncExpr) { - expression (&lval3); + Expression0 (&lval3); } /* Jump to the test */ g_jump (TestLabel); /* Remember the end of the increment expression */ - IncExprEnd = GetCodePos(); + GetCodePos (&IncExprEnd); /* Skip the closing paren */ ConsumeRParen (); /* Loop body */ - g_defcodelabel (lstat); + g_defcodelabel (BodyLabel); Statement (&PendingToken); /* If we had an increment expression, move the code to the bottom of @@ -407,17 +481,19 @@ static void ForStatement (void) * the loop body. */ if (HaveIncExpr) { - MoveCode (IncExprStart, IncExprEnd, GetCodePos()); + CodeMark Here; + GetCodePos (&Here); + MoveCode (&IncExprStart, &IncExprEnd, &Here); } else { - /* Jump back to the increment expression */ - g_jump (IncLabel); + /* 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 (lab); + g_defcodelabel (BreakLabel); /* Remove the loop from the loop stack */ DelLoop (); @@ -433,7 +509,7 @@ static int CompoundStatement (void) int GotBreak; /* Remember the stack at block entry */ - int OldStack = oursp; + int OldStack = StackPtr; /* Enter a new lexical level */ EnterBlockLevel (); @@ -453,9 +529,9 @@ static int CompoundStatement (void) /* Clean up the stack. */ if (!GotBreak) { - g_space (oursp - OldStack); + g_space (StackPtr - OldStack); } - oursp = OldStack; + StackPtr = OldStack; /* Emit references to imports/exports for this block */ EmitExternals (); @@ -478,83 +554,109 @@ int Statement (int* PendingToken) * NULL, the function will skip the token. */ { - ExprDesc lval; + ExprDesc Expr; int GotBreak; + CodeMark Start, End; /* 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 */ + /* Check for a label. A label is always part of a statement, it does not + * replace one. + */ + while (CurTok.Tok == TOK_IDENT && NextTok.Tok == TOK_COLON) { + /* Handle the label */ DoLabel (); + CheckLabelWithoutStatement (); + } - } else { - - switch (CurTok.Tok) { - - case TOK_LCURLY: - NextToken (); - GotBreak = CompoundStatement (); - CheckTok (TOK_RCURLY, "`{' expected", PendingToken); - return GotBreak; - - case TOK_IF: - return IfStatement (); - - case TOK_WHILE: - WhileStatement (); - break; - - case TOK_DO: - DoStatement (); - break; - - case TOK_SWITCH: - SwitchStatement (); - break; - - case TOK_RETURN: - ReturnStatement (); - CheckSemi (PendingToken); - return 1; - - case TOK_BREAK: - BreakStatement (); - CheckSemi (PendingToken); - return 1; - - case TOK_CONTINUE: - ContinueStatement (); - CheckSemi (PendingToken); - 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: - DoPragma (); - break; - - default: - /* Actual statement */ - expression (&lval); - CheckSemi (PendingToken); - } + switch (CurTok.Tok) { + + case TOK_LCURLY: + NextToken (); + GotBreak = CompoundStatement (); + CheckTok (TOK_RCURLY, "`{' expected", PendingToken); + return GotBreak; + + case TOK_IF: + return IfStatement (); + + case TOK_WHILE: + WhileStatement (); + break; + + case TOK_DO: + DoStatement (); + break; + + case TOK_SWITCH: + SwitchStatement (); + break; + + case TOK_RETURN: + ReturnStatement (); + CheckSemi (PendingToken); + return 1; + + case TOK_BREAK: + BreakStatement (); + CheckSemi (PendingToken); + return 1; + + case TOK_CONTINUE: + ContinueStatement (); + CheckSemi (PendingToken); + 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: + DoPragma (); + break; + + case TOK_CASE: + CaseLabel (); + CheckLabelWithoutStatement (); + break; + + case TOK_DEFAULT: + DefaultLabel (); + CheckLabelWithoutStatement (); + break; + + default: + /* 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; }