1 /*****************************************************************************/
5 /* Parse a statement */
9 /* (C) 1998-2010, Ullrich von Bassewitz */
10 /* Roemerstrasse 52 */
11 /* D-70794 Filderstadt */
12 /* EMail: uz@cc65.org */
15 /* This software is provided 'as-is', without any expressed or implied */
16 /* warranty. In no event will the authors be held liable for any damages */
17 /* arising from the use of this software. */
19 /* Permission is granted to anyone to use this software for any purpose, */
20 /* including commercial applications, and to alter it and redistribute it */
21 /* freely, subject to the following restrictions: */
23 /* 1. The origin of this software must not be misrepresented; you must not */
24 /* claim that you wrote the original software. If you use this software */
25 /* in a product, an acknowledgment in the product documentation would be */
26 /* appreciated but is not required. */
27 /* 2. Altered source versions must be plainly marked as such, and must not */
28 /* be misrepresented as being the original software. */
29 /* 3. This notice may not be removed or altered from any source */
32 /*****************************************************************************/
68 /*****************************************************************************/
69 /* Helper functions */
70 /*****************************************************************************/
74 static int CheckLabelWithoutStatement (void)
75 /* Called from Statement() after a label definition. Will check for a
76 * following closing curly brace. This means that a label is not followed
77 * by a statement which is required by the standard. Output an error if so.
80 if (CurTok.Tok == TOK_RCURLY) {
81 Error ("Label at end of compound statement");
90 static void CheckTok (token_t Tok, const char* Msg, int* PendingToken)
91 /* Helper function for Statement. Will check for Tok and print Msg if not
92 * found. If PendingToken is NULL, it will the skip the token, otherwise
93 * it will store one to PendingToken.
96 if (CurTok.Tok != Tok) {
98 } else if (PendingToken) {
107 static void CheckSemi (int* PendingToken)
108 /* Helper function for Statement. Will check for a semicolon and print an
109 * error message if not found (plus some error recovery). If PendingToken is
110 * NULL, it will the skip the token, otherwise it will store one to
112 * This function is a special version of CheckTok with the addition of the
116 int HaveToken = (CurTok.Tok == TOK_SEMI);
118 Error ("`;' expected");
119 /* Try to be smart about errors */
120 if (CurTok.Tok == TOK_COLON || CurTok.Tok == TOK_COMMA) {
135 static void SkipPending (int PendingToken)
136 /* Skip the pending token if we have one */
145 /*****************************************************************************/
147 /*****************************************************************************/
151 static int IfStatement (void)
152 /* Handle an 'if' statement */
161 /* Generate a jump label and parse the condition */
162 Label1 = GetLocalLabel ();
163 TestResult = TestInParens (Label1, 0);
165 /* Parse the if body */
166 GotBreak = Statement (0);
168 /* Else clause present? */
169 if (CurTok.Tok != TOK_ELSE) {
171 g_defcodelabel (Label1);
173 /* Since there's no else clause, we're not sure, if the a break
174 * statement is really executed.
180 /* Generate a jump around the else branch */
181 unsigned Label2 = GetLocalLabel ();
187 /* If the if expression was always true, the code in the else branch
188 * is never executed. Output a warning if this is the case.
190 if (TestResult == TESTEXPR_TRUE) {
191 Warning ("Unreachable code");
194 /* Define the target for the first test */
195 g_defcodelabel (Label1);
197 /* Total break only if both branches had a break. */
198 GotBreak &= Statement (0);
200 /* Generate the label for the else clause */
201 g_defcodelabel (Label2);
210 static void DoStatement (void)
211 /* Handle the 'do' statement */
213 /* Get the loop control labels */
214 unsigned LoopLabel = GetLocalLabel ();
215 unsigned BreakLabel = GetLocalLabel ();
216 unsigned ContinueLabel = GetLocalLabel ();
218 /* Skip the while token */
221 /* Add the loop to the loop stack */
222 AddLoop (BreakLabel, ContinueLabel);
224 /* Define the loop label */
225 g_defcodelabel (LoopLabel);
227 /* Parse the loop body */
230 /* Output the label for a continue */
231 g_defcodelabel (ContinueLabel);
233 /* Parse the end condition */
234 Consume (TOK_WHILE, "`while' expected");
235 TestInParens (LoopLabel, 1);
238 /* Define the break label */
239 g_defcodelabel (BreakLabel);
241 /* Remove the loop from the loop stack */
247 static void WhileStatement (void)
248 /* Handle the 'while' statement */
251 CodeMark CondCodeStart; /* Start of condition evaluation code */
252 CodeMark CondCodeEnd; /* End of condition evaluation code */
253 CodeMark Here; /* "Here" location of code */
255 /* Get the loop control labels */
256 unsigned LoopLabel = GetLocalLabel ();
257 unsigned BreakLabel = GetLocalLabel ();
258 unsigned CondLabel = GetLocalLabel ();
260 /* Skip the while token */
263 /* Add the loop to the loop stack. In case of a while loop, the condition
264 * label is used for continue statements.
266 AddLoop (BreakLabel, CondLabel);
268 /* We will move the code that evaluates the while condition to the end of
269 * the loop, so generate a jump here.
273 /* Remember the current position */
274 GetCodePos (&CondCodeStart);
276 /* Emit the code position label */
277 g_defcodelabel (CondLabel);
279 /* Test the loop condition */
280 TestInParens (LoopLabel, 1);
282 /* Remember the end of the condition evaluation code */
283 GetCodePos (&CondCodeEnd);
285 /* Define the head label */
286 g_defcodelabel (LoopLabel);
289 Statement (&PendingToken);
291 /* Move the test code here */
293 MoveCode (&CondCodeStart, &CondCodeEnd, &Here);
296 g_defcodelabel (BreakLabel);
298 /* Eat remaining tokens that were delayed because of line info
301 SkipPending (PendingToken);
303 /* Remove the loop from the loop stack */
309 static void ReturnStatement (void)
310 /* Handle the 'return' statement */
315 if (CurTok.Tok != TOK_SEMI) {
317 /* Evaluate the return expression */
320 /* If we return something in a void function, print an error and
321 * ignore the value. Otherwise convert the value to the type of the
324 if (F_HasVoidReturn (CurrentFunc)) {
325 Error ("Returning a value in function with return type void");
327 /* Convert the return value to the type of the function result */
328 TypeConversion (&Expr, F_GetReturnType (CurrentFunc));
330 /* Load the value into the primary */
331 LoadExpr (CF_NONE, &Expr);
334 } else if (!F_HasVoidReturn (CurrentFunc) && !F_HasOldStyleIntRet (CurrentFunc)) {
335 Error ("Function `%s' must return a value", F_GetFuncName (CurrentFunc));
338 /* Mark the function as having a return statement */
339 F_ReturnFound (CurrentFunc);
341 /* Cleanup the stack in case we're inside a block with locals */
342 g_space (StackPtr - F_GetTopLevelSP (CurrentFunc));
344 /* Output a jump to the function exit code */
345 g_jump (F_GetRetLab (CurrentFunc));
350 static void BreakStatement (void)
351 /* Handle the 'break' statement */
358 /* Get the current loop descriptor */
361 /* Check if we are inside a loop */
363 /* Error: No current loop */
364 Error ("`break' statement not within loop or switch");
368 /* Correct the stack pointer if needed */
369 g_space (StackPtr - L->StackPtr);
371 /* Jump to the exit label of the loop */
372 g_jump (L->BreakLabel);
377 static void ContinueStatement (void)
378 /* Handle the 'continue' statement */
382 /* Skip the continue */
385 /* Get the current loop descriptor */
388 /* Search for a loop that has a continue label. */
390 if (L->ContinueLabel) {
397 /* Did we find it? */
399 Error ("`continue' statement not within a loop");
403 /* Correct the stackpointer if needed */
404 g_space (StackPtr - L->StackPtr);
406 /* Jump to next loop iteration */
407 g_jump (L->ContinueLabel);
412 static void ForStatement (void)
413 /* Handle a 'for' statement */
418 CodeMark IncExprStart;
422 /* Get several local labels needed later */
423 unsigned TestLabel = GetLocalLabel ();
424 unsigned BreakLabel = GetLocalLabel ();
425 unsigned IncLabel = GetLocalLabel ();
426 unsigned BodyLabel = GetLocalLabel ();
428 /* Skip the FOR token */
431 /* Add the loop to the loop stack. A continue jumps to the start of the
432 * the increment condition.
434 AddLoop (BreakLabel, IncLabel);
436 /* Skip the opening paren */
439 /* Parse the initializer expression */
440 if (CurTok.Tok != TOK_SEMI) {
441 Expression0 (&lval1);
445 /* Label for the test expressions */
446 g_defcodelabel (TestLabel);
448 /* Parse the test expression */
449 if (CurTok.Tok != TOK_SEMI) {
457 /* Remember the start of the increment expression */
458 GetCodePos (&IncExprStart);
460 /* Label for the increment expression */
461 g_defcodelabel (IncLabel);
463 /* Parse the increment expression */
464 HaveIncExpr = (CurTok.Tok != TOK_RPAREN);
466 Expression0 (&lval3);
469 /* Jump to the test */
472 /* Remember the end of the increment expression */
473 GetCodePos (&IncExprEnd);
475 /* Skip the closing paren */
479 g_defcodelabel (BodyLabel);
480 Statement (&PendingToken);
482 /* If we had an increment expression, move the code to the bottom of
483 * the loop. In this case we don't need to jump there at the end of
489 MoveCode (&IncExprStart, &IncExprEnd, &Here);
491 /* Jump back to the increment expression */
495 /* Skip a pending token if we have one */
496 SkipPending (PendingToken);
498 /* Declare the break label */
499 g_defcodelabel (BreakLabel);
501 /* Remove the loop from the loop stack */
507 static int CompoundStatement (void)
508 /* Compound statement. Allow any number of statements inside braces. The
509 * function returns true if the last statement was a break or return.
514 /* Remember the stack at block entry */
515 int OldStack = StackPtr;
517 /* Enter a new lexical level */
520 /* Parse local variable declarations if any */
523 /* Now process statements in this block */
525 while (CurTok.Tok != TOK_RCURLY) {
526 if (CurTok.Tok != TOK_CEOF) {
527 GotBreak = Statement (0);
533 /* Clean up the stack. */
535 g_space (StackPtr - OldStack);
539 /* Emit references to imports/exports for this block */
542 /* Leave the lexical level */
550 int Statement (int* PendingToken)
551 /* Statement parser. Returns 1 if the statement does a return/break, returns
552 * 0 otherwise. If the PendingToken pointer is not NULL, the function will
553 * not skip the terminating token of the statement (closing brace or
554 * semicolon), but store true if there is a pending token, and false if there
555 * is none. The token is always checked, so there is no need for the caller to
556 * check this token, it must be skipped, however. If the argument pointer is
557 * NULL, the function will skip the token.
564 /* Assume no pending token */
569 /* Check for a label. A label is always part of a statement, it does not
572 while (CurTok.Tok == TOK_IDENT && NextTok.Tok == TOK_COLON) {
573 /* Handle the label */
575 if (CheckLabelWithoutStatement ()) {
580 switch (CurTok.Tok) {
584 GotBreak = CompoundStatement ();
585 CheckTok (TOK_RCURLY, "`{' expected", PendingToken);
589 return IfStatement ();
605 CheckSemi (PendingToken);
610 CheckSemi (PendingToken);
614 ContinueStatement ();
615 CheckSemi (PendingToken);
624 CheckSemi (PendingToken);
629 CheckSemi (PendingToken);
638 CheckLabelWithoutStatement ();
643 CheckLabelWithoutStatement ();
647 /* Remember the current code position */
649 /* Actual statement */
650 ExprWithCheck (hie0, &Expr);
651 /* Load the result only if it is an lvalue and the type is
652 * marked as volatile. Otherwise the load is useless.
654 if (ED_IsLVal (&Expr) && IsQualVolatile (Expr.Type)) {
655 LoadExpr (CF_NONE, &Expr);
657 /* If the statement didn't generate code, and is not of type
658 * void, emit a warning.
661 if (CodeRangeIsEmpty (&Start, &End) &&
662 !IsTypeVoid (Expr.Type) &&
663 IS_Get (&WarnNoEffect)) {
664 Warning ("Statement has no effect");
666 CheckSemi (PendingToken);