X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=src%2Fcc65%2Fstmt.c;h=5078bfa11a1d32c4076e304247fd1b2d1bcde8cb;hb=112ae0e3db511ddd92e769c11328646ebe2a6240;hp=cd4c53dc30b7b617a1aca84c2e462cbf8ebea85b;hpb=8d8162eb23e1f275e38662f9c7e54c875ec5d63e;p=cc65 diff --git a/src/cc65/stmt.c b/src/cc65/stmt.c index cd4c53dc3..5078bfa11 100644 --- a/src/cc65/stmt.c +++ b/src/cc65/stmt.c @@ -6,10 +6,10 @@ /* */ /* */ /* */ -/* (C) 1998-2004 Ullrich von Bassewitz */ -/* Römerstraße 52 */ -/* D-70794 Filderstadt */ -/* 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,15 @@ #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" @@ -69,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 @@ -76,7 +91,7 @@ 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; } else { @@ -201,7 +216,7 @@ static void DoStatement (void) NextToken (); /* Add the loop to the loop stack */ - AddLoop (StackPtr, BreakLabel, ContinueLabel); + AddLoop (BreakLabel, ContinueLabel); /* Define the loop label */ g_defcodelabel (LoopLabel); @@ -229,31 +244,50 @@ 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 LoopLabel = GetLocalLabel (); unsigned BreakLabel = GetLocalLabel (); + unsigned CondLabel = GetLocalLabel (); /* Skip the while token */ NextToken (); - /* Add the loop to the loop stack. In case of a while loop, the loop head + /* Add the loop to the loop stack. In case of a while loop, the condition * label is used for continue statements. */ - AddLoop (StackPtr, BreakLabel, LoopLabel); + AddLoop (BreakLabel, CondLabel); - /* Define the head label */ - g_defcodelabel (LoopLabel); + /* 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 */ - TestInParens (BreakLabel, 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 (LoopLabel); + /* Move the test code here */ + GetCodePos (&Here); + MoveCode (&CondCodeStart, &CondCodeEnd, &Here); /* Exit label */ g_defcodelabel (BreakLabel); @@ -277,28 +311,30 @@ static void ReturnStatement (void) NextToken (); 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); - /* Ignore the return expression if the function returns void */ - if (!F_HasVoidReturn (CurrentFunc)) { - + /* 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)); /* Load the value into the primary */ - ExprLoad (CF_NONE, &Expr); + LoadExpr (CF_NONE, &Expr); } } 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 (StackPtr - F_GetTopLevelSP (CurrentFunc)); @@ -392,7 +428,7 @@ static void ForStatement (void) /* Add the loop to the loop stack. A continue jumps to the start of the * the increment condition. */ - AddLoop (StackPtr, BreakLabel, IncLabel); + AddLoop (BreakLabel, IncLabel); /* Skip the opening paren */ ConsumeLParen (); @@ -416,7 +452,7 @@ static void ForStatement (void) ConsumeSemi (); /* Remember the start of the increment expression */ - IncExprStart = GetCodePos(); + GetCodePos (&IncExprStart); /* Label for the increment expression */ g_defcodelabel (IncLabel); @@ -431,7 +467,7 @@ static void ForStatement (void) g_jump (TestLabel); /* Remember the end of the increment expression */ - IncExprEnd = GetCodePos(); + GetCodePos (&IncExprEnd); /* Skip the closing paren */ ConsumeRParen (); @@ -445,7 +481,9 @@ 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); @@ -516,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) { - 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 */ - Expression0 (&lval); - CheckSemi (PendingToken); - } + 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; }