unsigned Test (unsigned Label, int Invert) /* Evaluate a boolean test expression and jump depending on the result of ** the test and on Invert. The function returns one of the TESTEXPR_xx codes ** defined above. If the jump is always true, a warning is output. */ { ExprDesc Expr; unsigned Result; /* Read a boolean expression */ BoolExpr (hie0, &Expr); /* Check for a constant expression */ if (ED_IsConstAbs (&Expr)) { /* Result is constant, so we know the outcome */ Result = (Expr.IVal != 0); /* Constant rvalue */ if (!Invert && Expr.IVal == 0) { g_jump (Label); Warning ("Unreachable code"); } else if (Invert && Expr.IVal != 0) { g_jump (Label); } } else { /* Result is unknown */ Result = TESTEXPR_UNKNOWN; /* If the expr hasn't set condition codes, set the force-test flag */ if (!ED_IsTested (&Expr)) { ED_MarkForTest (&Expr); } /* Load the value into the primary register */ LoadExpr (CF_FORCECHAR, &Expr); /* Generate the jump */ if (Invert) { g_truejump (CF_NONE, Label); } else { g_falsejump (CF_NONE, Label); } } /* Return the result */ return Result; }
static void ContinueStatement (void) /* Handle the 'continue' statement */ { 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; } L = L->Next; } while (L); } /* Did we find it? */ if (L == 0) { Error ("`continue' statement not within a loop"); return; } /* Correct the stackpointer if needed */ g_space (StackPtr - L->StackPtr); /* Jump to next loop iteration */ g_jump (L->ContinueLabel); }
static void WhileStatement (void) /* Handle the 'while' statement */ { 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 condition ** label is used for continue statements. */ AddLoop (BreakLabel, CondLabel); /* 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 (LoopLabel, 1); /* Remember the end of the condition evaluation code */ GetCodePos (&CondCodeEnd); /* Define the head label */ g_defcodelabel (LoopLabel); /* Loop body */ Statement (&PendingToken); /* Move the test code here */ GetCodePos (&Here); MoveCode (&CondCodeStart, &CondCodeEnd, &Here); /* 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 int IfStatement (void) /* Handle an 'if' statement */ { unsigned Label1; unsigned TestResult; int GotBreak; /* Skip the if */ NextToken (); /* Generate a jump label and parse the condition */ Label1 = GetLocalLabel (); TestResult = TestInParens (Label1, 0); /* Parse the if body */ GotBreak = Statement (0); /* Else clause present? */ if (CurTok.Tok != TOK_ELSE) { g_defcodelabel (Label1); /* Since there's no else clause, we're not sure, if the a break ** statement is really executed. */ return 0; } else { /* Generate a jump around the else branch */ unsigned Label2 = GetLocalLabel (); g_jump (Label2); /* Skip the else */ NextToken (); /* 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 */ g_defcodelabel (Label2); /* Done */ return GotBreak; } }
static void WhileStatement (void) /* Handle the 'while' statement */ { int PendingToken; /* Get the loop control labels */ unsigned LoopLabel = GetLocalLabel (); unsigned BreakLabel = GetLocalLabel (); /* Skip the while token */ NextToken (); /* 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); /* Loop body */ Statement (&PendingToken); /* 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 ReturnStatement (void) /* Handle the 'return' statement */ { ExprDesc Expr; NextToken (); if (CurTok.Tok != TOK_SEMI) { /* 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)); /* Load the value into the primary */ 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)); /* Output a jump to the function exit code */ g_jump (F_GetRetLab (CurrentFunc)); }
static void BreakStatement (void) /* Handle the 'break' statement */ { LoopDesc* L; /* Skip the break */ NextToken (); /* 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; } /* Correct the stack pointer if needed */ g_space (StackPtr - L->StackPtr); /* Jump to the exit label of the loop */ g_jump (L->BreakLabel); }
void SwitchStatement (void) /* Handle a switch statement for chars with a cmp cascade for the selector */ { ExprDesc SwitchExpr; /* Switch statement expression */ CodeMark CaseCodeStart; /* Start of code marker */ CodeMark SwitchCodeStart;/* Start of switch code */ CodeMark SwitchCodeEnd; /* End of switch code */ unsigned ExitLabel; /* Exit label */ unsigned SwitchCodeLabel;/* Label for the switch code */ int HaveBreak = 0; /* True if the last statement had a break */ int RCurlyBrace; /* True if last token is right curly brace */ SwitchCtrl* OldSwitch; /* Pointer to old switch control data */ SwitchCtrl SwitchData; /* New switch data */ /* Eat the "switch" token */ NextToken (); /* Read the switch expression and load it into the primary. It must have * integer type. */ ConsumeLParen (); Expression0 (&SwitchExpr); if (!IsClassInt (SwitchExpr.Type)) { Error ("Switch quantity is not an integer"); /* To avoid any compiler errors, make the expression a valid int */ ED_MakeConstAbsInt (&SwitchExpr, 1); } ConsumeRParen (); /* Add a jump to the switch code. This jump is usually unnecessary, * because the switch code will moved up just behind the switch * expression. However, in rare cases, there's a label at the end of * the switch expression. This label will not get moved, so the code * jumps around the switch code, and after moving the switch code, * things look really weird. If we add a jump here, we will never have * a label attached to the current code position, and the jump itself * will get removed by the optimizer if it is unnecessary. */ SwitchCodeLabel = GetLocalLabel (); g_jump (SwitchCodeLabel); /* Remember the current code position. We will move the switch code * to this position later. */ GetCodePos (&CaseCodeStart); /* Setup the control structure, save the old and activate the new one */ SwitchData.Nodes = NewCollection (); SwitchData.ExprType = UnqualifiedType (SwitchExpr.Type[0].C); SwitchData.Depth = SizeOf (SwitchExpr.Type); SwitchData.DefaultLabel = 0; OldSwitch = Switch; Switch = &SwitchData; /* Get the exit label for the switch statement */ ExitLabel = GetLocalLabel (); /* Create a loop so we may use break. */ AddLoop (ExitLabel, 0); /* Make sure a curly brace follows */ if (CurTok.Tok != TOK_LCURLY) { Error ("`{' expected"); } /* Parse the following statement, which will actually be a compound * statement because of the curly brace at the current input position */ HaveBreak = Statement (&RCurlyBrace); /* Check if we had any labels */ if (CollCount (SwitchData.Nodes) == 0 && SwitchData.DefaultLabel == 0) { Warning ("No case labels"); } /* If the last statement did not have a break, we may have an open * label (maybe from an if or similar). Emitting code and then moving * this code to the top will also move the label to the top which is * wrong. So if the last statement did not have a break (which would * carry the label), add a jump to the exit. If it is useless, the * optimizer will remove it later. */ if (!HaveBreak) { g_jump (ExitLabel); } /* Remember the current position */ GetCodePos (&SwitchCodeStart); /* Output the switch code label */ g_defcodelabel (SwitchCodeLabel); /* Generate code */ if (SwitchData.DefaultLabel == 0) { /* No default label, use switch exit */ SwitchData.DefaultLabel = ExitLabel; } g_switch (SwitchData.Nodes, SwitchData.DefaultLabel, SwitchData.Depth); /* Move the code to the front */ GetCodePos (&SwitchCodeEnd); MoveCode (&SwitchCodeStart, &SwitchCodeEnd, &CaseCodeStart); /* Define the exit label */ g_defcodelabel (ExitLabel); /* Exit the loop */ DelLoop (); /* Switch back to the enclosing switch statement if any */ Switch = OldSwitch; /* Free the case value tree */ FreeCaseNodeColl (SwitchData.Nodes); /* If the case statement was (correctly) terminated by a closing curly * brace, skip it now. */ if (RCurlyBrace) { NextToken (); } }
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 (); /* Parse the initializer expression */ if (CurTok.Tok != TOK_SEMI) { Expression0 (&lval1); } ConsumeSemi (); /* Label for the test expressions */ g_defcodelabel (TestLabel); /* Parse the test expression */ if (CurTok.Tok != TOK_SEMI) { Test (BodyLabel, 1); g_jump (BreakLabel); } else { g_jump (BodyLabel); } ConsumeSemi (); /* 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); } /* Jump to the test */ g_jump (TestLabel); /* Remember the end of the increment expression */ GetCodePos (&IncExprEnd); /* Skip the closing paren */ ConsumeRParen (); /* Loop body */ g_defcodelabel (BodyLabel); Statement (&PendingToken); /* 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 { /* 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 (); }