4 * Ullrich von Bassewitz, 06.08.1998
6 * Original by John R. Dunning - see copyleft.jrd
37 /*****************************************************************************/
39 /*****************************************************************************/
43 /* Maximum count of cases */
48 /*****************************************************************************/
50 /*****************************************************************************/
54 /*****************************************************************************/
56 /*****************************************************************************/
60 static int IfStatement (void)
61 /* Handle an 'if' statement */
69 /* Generate a jump label and parse the condition */
70 Label1 = GetLocalLabel ();
73 /* Parse the if body */
74 GotBreak = Statement ();
76 /* Else clause present? */
77 if (CurTok.Tok != TOK_ELSE) {
79 g_defcodelabel (Label1);
80 /* Since there's no else clause, we're not sure, if the a break
81 * statement is really executed.
87 /* Generate a jump around the else branch */
88 unsigned Label2 = GetLocalLabel ();
94 /* Define the target for the first test */
95 g_defcodelabel (Label1);
97 /* Total break only if both branches had a break. */
98 GotBreak &= Statement ();
100 /* Generate the label for the else clause */
101 g_defcodelabel (Label2);
110 static void DoStatement (void)
111 /* Handle the 'do' statement */
113 /* Get the loop control labels */
114 unsigned loop = GetLocalLabel ();
115 unsigned lab = GetLocalLabel ();
117 /* Skip the while token */
120 /* Add the loop to the loop stack */
121 AddLoop (oursp, loop, lab, 0, 0);
123 /* Define the head label */
124 g_defcodelabel (loop);
126 /* Parse the loop body */
129 /* Parse the end condition */
130 Consume (TOK_WHILE, "`while' expected");
134 /* Define the break label */
135 g_defcodelabel (lab);
137 /* Remove the loop from the loop stack */
143 static void WhileStatement (void)
144 /* Handle the 'while' statement */
146 /* Get the loop control labels */
147 unsigned loop = GetLocalLabel ();
148 unsigned lab = GetLocalLabel ();
150 /* Skip the while token */
153 /* Add the loop to the loop stack */
154 AddLoop (oursp, loop, lab, 0, 0);
156 /* Define the head label */
157 g_defcodelabel (loop);
159 /* Test the loop condition */
162 /* If the statement following the while loop is empty, that is, we have
163 * something like "while (1) ;", the test function ommitted the jump as
164 * an optimization. Since we know, the condition codes are set, we can
165 * do another small optimization here, and use a conditional jump
166 * instead an absolute one.
168 if (CurTok.Tok == TOK_SEMI) {
169 /* Use a conditional jump */
170 g_truejump (CF_NONE, loop);
174 /* There is code inside the while loop, parse the body */
177 g_defcodelabel (lab);
180 /* Remove the loop from the loop stack */
186 static void ReturnStatement (void)
187 /* Handle the 'return' statement */
192 if (CurTok.Tok != TOK_SEMI) {
193 if (HasVoidReturn (CurrentFunc)) {
194 Error ("Returning a value in function with return type void");
197 /* Evaluate the return expression. Result will be in primary */
200 /* Convert the return value to the type of the function result */
201 if (!HasVoidReturn (CurrentFunc)) {
202 assignadjust (GetReturnType (CurrentFunc), &lval);
204 } else if (!HasVoidReturn (CurrentFunc)) {
205 Error ("Function `%s' must return a value", GetFuncName (CurrentFunc));
208 /* Cleanup the stack in case we're inside a block with locals */
209 g_space (oursp - GetTopLevelSP (CurrentFunc));
211 /* Output a jump to the function exit code */
212 g_jump (GetRetLab (CurrentFunc));
217 static void BreakStatement (void)
218 /* Handle the 'break' statement */
225 /* Get the current loop descriptor */
228 /* Check if we are inside a loop */
230 /* Error: No current loop */
231 Error ("`break' statement not within loop or switch");
235 /* Correct the stack pointer if needed */
236 g_space (oursp - L->StackPtr);
238 /* Jump to the exit label of the loop */
244 static void ContinueStatement (void)
245 /* Handle the 'continue' statement */
249 /* Skip the continue */
252 /* Get the current loop descriptor */
255 /* Search for the correct loop */
264 /* Did we find it? */
266 Error ("`continue' statement not within a loop");
270 /* Correct the stackpointer if needed */
271 g_space (oursp - L->StackPtr);
273 /* Output the loop code */
283 static void CascadeSwitch (struct expent* eval)
284 /* Handle a switch statement for chars with a cmp cascade for the selector */
286 unsigned ExitLab; /* Exit label */
287 unsigned NextLab; /* Next case label */
288 unsigned CodeLab; /* Label that starts the actual selector code */
289 int HaveBreak; /* Remember if we exited with break */
290 int HaveDefault; /* Remember if we had a default label */
291 int lcount; /* Label count */
292 unsigned Flags; /* Code generator flags */
293 struct expent lval; /* Case label expression */
294 long Val; /* Case label value */
297 /* Create a loop so we may break out, init labels */
298 ExitLab = GetLocalLabel ();
299 AddLoop (oursp, 0, ExitLab, 0, 0);
301 /* Setup some variables needed in the loop below */
302 Flags = TypeOf (eval->e_tptr) | CF_CONST | CF_FORCECHAR;
303 CodeLab = NextLab = 0;
307 /* Parse the labels */
309 while (CurTok.Tok != TOK_RCURLY) {
311 if (CurTok.Tok == TOK_CASE || CurTok.Tok == TOK_DEFAULT) {
313 /* If the code for the previous selector did not end with a
314 * break statement, we must jump over the next selector test.
317 /* Define a label for the code */
319 CodeLab = GetLocalLabel ();
324 /* If we have a cascade label, emit it */
326 g_defcodelabel (NextLab);
330 while (CurTok.Tok == TOK_CASE || CurTok.Tok == TOK_DEFAULT) {
332 /* Parse the selector */
333 if (CurTok.Tok == TOK_CASE) {
338 /* Skip the "case" token */
341 /* Read the selector expression */
343 if (!IsClassInt (lval.e_tptr)) {
344 Error ("Switch quantity not an integer");
347 /* Check the range of the expression */
349 switch (*eval->e_tptr) {
353 if (Val < -128 || Val > 127) {
354 Error ("Range error");
359 if (Val < 0 || Val > 255) {
360 Error ("Range error");
365 if (Val < -32768 || Val > 32767) {
366 Error ("Range error");
371 if (Val < 0 || Val > 65535) {
372 Error ("Range error");
377 Internal ("Invalid type: %02X", *eval->e_tptr & 0xFF);
383 /* If another case follows, we will jump to the code if
384 * the condition is true.
386 if (CurTok.Tok == TOK_CASE) {
387 /* Create a code label if needed */
389 CodeLab = GetLocalLabel ();
391 g_falsejump (CF_NONE, CodeLab);
392 } else if (CurTok.Tok != TOK_DEFAULT) {
393 /* No case follows, jump to next selector */
395 NextLab = GetLocalLabel ();
397 g_truejump (CF_NONE, NextLab);
408 /* Handle the pathologic case: DEFAULT followed by CASE */
409 if (CurTok.Tok == TOK_CASE) {
411 CodeLab = GetLocalLabel ();
419 /* Remember that we had a default label */
427 /* Emit a code label if we have one */
429 g_defcodelabel (CodeLab);
433 /* Parse statements */
434 if (CurTok.Tok != TOK_RCURLY) {
435 HaveBreak = Statement ();
439 /* Check if we have any labels */
440 if (lcount == 0 && !HaveDefault) {
441 Warning ("No case labels");
444 /* Define the exit label and, if there's a next label left, create this
448 g_defcodelabel (NextLab);
450 g_defcodelabel (ExitLab);
452 /* Eat the closing curly brace */
461 static void TableSwitch (struct expent* eval)
462 /* Handle a switch statement via table based selector */
464 /* Entry for one case in a switch statement */
466 long sw_const; /* selector value */
467 unsigned sw_lab; /* label for this selector */
470 int dlabel; /* for default */
471 int lab; /* exit label */
472 int label; /* label for case */
473 int lcase; /* label for compares */
474 int lcount; /* Label count */
475 int HaveBreak; /* Last statement has a break */
476 int HaveDefault; /* Remember if we had a default label */
477 unsigned Flags; /* Code generator flags */
478 struct expent lval; /* Case label expression */
482 /* Allocate memory for the switch table */
483 swtab = xmalloc (CASE_MAX * sizeof (struct swent));
485 /* Create a look so we may break out, init labels */
486 HaveBreak = 0; /* Keep gcc silent */
487 HaveDefault = 0; /* No default case until now */
488 dlabel = 0; /* init */
489 lab = GetLocalLabel (); /* get exit */
491 AddLoop (oursp, 0, lab, 0, 0);
493 /* Jump behind the code for the CASE labels */
494 g_jump (lcase = GetLocalLabel ());
496 while (CurTok.Tok != TOK_RCURLY) {
497 if (CurTok.Tok == TOK_CASE || CurTok.Tok == TOK_DEFAULT) {
498 if (lcount >= CASE_MAX) {
499 Fatal ("Too many case labels");
501 label = GetLocalLabel ();
503 if (CurTok.Tok == TOK_CASE) {
506 if (!IsClassInt (lval.e_tptr)) {
507 Error ("Switch quantity not an integer");
509 p->sw_const = lval.e_const;
519 } while (CurTok.Tok == TOK_CASE || CurTok.Tok == TOK_DEFAULT);
520 g_defcodelabel (label);
523 if (CurTok.Tok != TOK_RCURLY) {
524 HaveBreak = Statement ();
528 /* Check if we have any labels */
529 if (lcount == 0 && !HaveDefault) {
530 Warning ("No case labels");
533 /* Eat the closing curly brace */
536 /* If the last statement doesn't have a break or return, add one */
541 /* Actual selector code goes here */
542 g_defcodelabel (lcase);
544 /* Create the call to the switch subroutine */
545 Flags = TypeOf (eval->e_tptr);
548 /* First entry is negative of label count */
549 g_defdata (CF_INT | CF_CONST, -((int)lcount)-1, 0);
551 /* Create the case selector table */
554 g_case (Flags, p->sw_lab, p->sw_const); /* Create one label */
562 g_defcodelabel (lab);
565 /* Free the allocated space for the labels */
571 static void SwitchStatement (void)
572 /* Handle a 'switch' statement */
574 struct expent eval; /* Switch statement expression */
576 /* Eat the "switch" */
579 /* Read the switch expression */
584 /* result of expr is in P */
587 /* Now decide which sort of switch we will create: */
588 if (IsTypeChar (eval.e_tptr) || (CodeSizeFactor >= 200 && IsClassInt (eval.e_tptr))) {
589 CascadeSwitch (&eval);
597 static void ForStatement (void)
598 /* Handle a 'for' statement */
604 /* Get several local labels needed later */
605 unsigned TestLabel = GetLocalLabel ();
606 unsigned lab = GetLocalLabel ();
607 unsigned IncLabel = GetLocalLabel ();
608 unsigned lstat = GetLocalLabel ();
610 /* Skip the FOR token */
613 /* Add the loop to the loop stack */
614 AddLoop (oursp, TestLabel, lab, IncLabel, lstat);
616 /* Skip the opening paren */
619 /* Parse the initializer expression */
620 if (CurTok.Tok != TOK_SEMI) {
625 /* Label for the test expressions */
626 g_defcodelabel (TestLabel);
628 /* Parse the test expression */
629 if (CurTok.Tok != TOK_SEMI) {
631 g_truejump (CF_NONE, lstat);
638 /* Label for the increment expression */
639 g_defcodelabel (IncLabel);
641 /* Parse the increment expression */
642 if (CurTok.Tok != TOK_RPAREN) {
646 /* Jump to the test */
649 /* Skip the closing paren */
653 g_defcodelabel (lstat);
656 /* Jump back to the increment expression */
659 /* Declare the break label */
660 g_defcodelabel (lab);
662 /* Remove the loop from the loop stack */
668 static int CompoundStatement (void)
669 /* Compound statement. Allow any number of statements inside braces. The
670 * function returns true if the last statement was a break or return.
675 /* Remember the stack at block entry */
676 int OldStack = oursp;
678 /* Enter a new lexical level */
681 /* Skip the rcurly */
684 /* Parse local variable declarations if any */
687 /* Now process statements in this block */
689 while (CurTok.Tok != TOK_RCURLY) {
690 if (CurTok.Tok != TOK_CEOF) {
691 GotBreak = Statement ();
697 /* Clean up the stack. */
699 g_space (oursp - OldStack);
703 /* Skip the closing brace */
706 /* Emit references to imports/exports for this block */
709 /* Leave the lexical level */
718 /* Statement parser. Returns 1 if the statement does a return/break, returns
724 /* Check for a label */
725 if (CurTok.Tok == TOK_IDENT && NextTok.Tok == TOK_COLON) {
727 /* Special handling for a label */
732 switch (CurTok.Tok) {
735 return CompoundStatement ();
738 return IfStatement ();
763 ContinueStatement ();
786 /* Actual statement */