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 static int DoIf (void)
55 /* Handle an 'if' statement */
64 /* Generate a jump label and parse the condition */
65 flab1 = GetLocalLabel ();
68 /* Parse the if body */
69 gotbreak = Statement ();
71 /* Else clause present? */
72 if (CurTok.Tok != TOK_ELSE) {
74 g_defcodelabel (flab1);
75 /* Since there's no else clause, we're not sure, if the a break
76 * statement is really executed.
85 /* If we had some sort of break statement at the end of the if clause,
86 * there's no need to generate an additional jump around the else
87 * clause, since the jump is never reached.
90 flab2 = GetLocalLabel ();
93 /* Mark the label as unused */
96 g_defcodelabel (flab1);
97 gotbreak &= Statement ();
99 /* Generate the label for the else clause */
101 g_defcodelabel (flab2);
111 static void DoDo (void)
112 /* Handle the 'do' statement */
114 /* Get the loop control labels */
115 unsigned loop = GetLocalLabel ();
116 unsigned lab = GetLocalLabel ();
118 /* Skip the while token */
121 /* Add the loop to the loop stack */
122 AddLoop (oursp, loop, lab, 0, 0);
124 /* Define the head label */
125 g_defcodelabel (loop);
127 /* Parse the loop body */
130 /* Parse the end condition */
131 Consume (TOK_WHILE, "`while' expected");
135 /* Define the break label */
136 g_defcodelabel (lab);
138 /* Remove the loop from the loop stack */
144 static void DoWhile (void)
145 /* Handle the 'while' statement */
147 /* Get the loop control labels */
148 unsigned loop = GetLocalLabel ();
149 unsigned lab = GetLocalLabel ();
151 /* Skip the while token */
154 /* Add the loop to the loop stack */
155 AddLoop (oursp, loop, lab, 0, 0);
157 /* Define the head label */
158 g_defcodelabel (loop);
160 /* Test the loop condition */
163 /* If the statement following the while loop is empty, that is, we have
164 * something like "while (1) ;", the test function ommitted the jump as
165 * an optimization. Since we know, the condition codes are set, we can
166 * do another small optimization here, and use a conditional jump
167 * instead an absolute one.
169 if (CurTok.Tok == TOK_SEMI) {
170 /* Use a conditional jump */
171 g_truejump (CF_NONE, loop);
175 /* There is code inside the while loop, parse the body */
178 g_defcodelabel (lab);
181 /* Remove the loop from the loop stack */
187 static void DoReturn (void)
188 /* Handle the 'return' statement */
193 if (CurTok.Tok != TOK_SEMI) {
194 if (HasVoidReturn (CurrentFunc)) {
195 Error ("Returning a value in function with return type void");
198 /* Evaluate the return expression. Result will be in primary */
201 /* Convert the return value to the type of the function result */
202 if (!HasVoidReturn (CurrentFunc)) {
203 assignadjust (GetReturnType (CurrentFunc), &lval);
205 } else if (!HasVoidReturn (CurrentFunc)) {
206 Error ("Function `%s' must return a value", GetFuncName (CurrentFunc));
209 /* Cleanup the stack in case we're inside a block with locals */
210 g_space (oursp - GetTopLevelSP (CurrentFunc));
212 /* Output a jump to the function exit code */
213 g_jump (GetRetLab (CurrentFunc));
218 static void DoBreak (void)
219 /* Handle the 'break' statement */
226 /* Get the current loop descriptor */
229 /* Check if we are inside a loop */
231 /* Error: No current loop */
232 Error ("`break' statement not within loop or switch");
236 /* Correct the stack pointer if needed */
237 g_space (oursp - L->StackPtr);
239 /* Jump to the exit label of the loop */
245 static void DoContinue (void)
246 /* Handle the 'continue' statement */
250 /* Skip the continue */
253 /* Get the current loop descriptor */
256 /* Search for the correct loop */
265 /* Did we find it? */
267 Error ("`continue' statement not within a loop");
271 /* Correct the stackpointer if needed */
272 g_space (oursp - L->StackPtr);
274 /* Output the loop code */
284 static void CascadeSwitch (struct expent* eval)
285 /* Handle a switch statement for chars with a cmp cascade for the selector */
287 unsigned ExitLab; /* Exit label */
288 unsigned NextLab; /* Next case label */
289 unsigned CodeLab; /* Label that starts the actual selector code */
290 int HaveBreak; /* Remember if we exited with break */
291 int HaveDefault; /* Remember if we had a default label */
292 int lcount; /* Label count */
293 unsigned Flags; /* Code generator flags */
294 struct expent lval; /* Case label expression */
295 long Val; /* Case label value */
298 /* Create a loop so we may break out, init labels */
299 ExitLab = GetLocalLabel ();
300 AddLoop (oursp, 0, ExitLab, 0, 0);
302 /* Setup some variables needed in the loop below */
303 Flags = TypeOf (eval->e_tptr) | CF_CONST | CF_FORCECHAR;
304 CodeLab = NextLab = 0;
308 /* Parse the labels */
310 while (CurTok.Tok != TOK_RCURLY) {
312 if (CurTok.Tok == TOK_CASE || CurTok.Tok == TOK_DEFAULT) {
314 /* If the code for the previous selector did not end with a
315 * break statement, we must jump over the next selector test.
318 /* Define a label for the code */
320 CodeLab = GetLocalLabel ();
325 /* If we have a cascade label, emit it */
327 g_defcodelabel (NextLab);
331 while (CurTok.Tok == TOK_CASE || CurTok.Tok == TOK_DEFAULT) {
333 /* Parse the selector */
334 if (CurTok.Tok == TOK_CASE) {
339 /* Skip the "case" token */
342 /* Read the selector expression */
344 if (!IsClassInt (lval.e_tptr)) {
345 Error ("Switch quantity not an integer");
348 /* Check the range of the expression */
350 switch (*eval->e_tptr) {
354 if (Val < -128 || Val > 127) {
355 Error ("Range error");
360 if (Val < 0 || Val > 255) {
361 Error ("Range error");
366 if (Val < -32768 || Val > 32767) {
367 Error ("Range error");
372 if (Val < 0 || Val > 65535) {
373 Error ("Range error");
378 Internal ("Invalid type: %02X", *eval->e_tptr & 0xFF);
384 /* If another case follows, we will jump to the code if
385 * the condition is true.
387 if (CurTok.Tok == TOK_CASE) {
388 /* Create a code label if needed */
390 CodeLab = GetLocalLabel ();
392 g_falsejump (CF_NONE, CodeLab);
393 } else if (CurTok.Tok != TOK_DEFAULT) {
394 /* No case follows, jump to next selector */
396 NextLab = GetLocalLabel ();
398 g_truejump (CF_NONE, NextLab);
409 /* Handle the pathologic case: DEFAULT followed by CASE */
410 if (CurTok.Tok == TOK_CASE) {
412 CodeLab = GetLocalLabel ();
420 /* Remember that we had a default label */
428 /* Emit a code label if we have one */
430 g_defcodelabel (CodeLab);
434 /* Parse statements */
435 if (CurTok.Tok != TOK_RCURLY) {
436 HaveBreak = Statement ();
440 /* Check if we have any labels */
441 if (lcount == 0 && !HaveDefault) {
442 Warning ("No case labels");
445 /* Define the exit label and, if there's a next label left, create this
449 g_defcodelabel (NextLab);
451 g_defcodelabel (ExitLab);
453 /* Eat the closing curly brace */
462 static void TableSwitch (struct expent* eval)
463 /* Handle a switch statement via table based selector */
465 /* Entry for one case in a switch statement */
467 long sw_const; /* selector value */
468 unsigned sw_lab; /* label for this selector */
471 int dlabel; /* for default */
472 int lab; /* exit label */
473 int label; /* label for case */
474 int lcase; /* label for compares */
475 int lcount; /* Label count */
476 int HaveBreak; /* Last statement has a break */
477 int HaveDefault; /* Remember if we had a default label */
478 unsigned Flags; /* Code generator flags */
479 struct expent lval; /* Case label expression */
483 /* Allocate memory for the switch table */
484 swtab = xmalloc (CASE_MAX * sizeof (struct swent));
486 /* Create a look so we may break out, init labels */
487 HaveBreak = 0; /* Keep gcc silent */
488 HaveDefault = 0; /* No default case until now */
489 dlabel = 0; /* init */
490 lab = GetLocalLabel (); /* get exit */
492 AddLoop (oursp, 0, lab, 0, 0);
494 /* Jump behind the code for the CASE labels */
495 g_jump (lcase = GetLocalLabel ());
497 while (CurTok.Tok != TOK_RCURLY) {
498 if (CurTok.Tok == TOK_CASE || CurTok.Tok == TOK_DEFAULT) {
499 if (lcount >= CASE_MAX) {
500 Fatal ("Too many case labels");
502 label = GetLocalLabel ();
504 if (CurTok.Tok == TOK_CASE) {
507 if (!IsClassInt (lval.e_tptr)) {
508 Error ("Switch quantity not an integer");
510 p->sw_const = lval.e_const;
520 } while (CurTok.Tok == TOK_CASE || CurTok.Tok == TOK_DEFAULT);
521 g_defcodelabel (label);
524 if (CurTok.Tok != TOK_RCURLY) {
525 HaveBreak = Statement ();
529 /* Check if we have any labels */
530 if (lcount == 0 && !HaveDefault) {
531 Warning ("No case labels");
534 /* Eat the closing curly brace */
537 /* If the last statement doesn't have a break or return, add one */
542 /* Actual selector code goes here */
543 g_defcodelabel (lcase);
545 /* Create the call to the switch subroutine */
546 Flags = TypeOf (eval->e_tptr);
549 /* First entry is negative of label count */
550 g_defdata (CF_INT | CF_CONST, -((int)lcount)-1, 0);
552 /* Create the case selector table */
555 g_case (Flags, p->sw_lab, p->sw_const); /* Create one label */
563 g_defcodelabel (lab);
566 /* Free the allocated space for the labels */
572 static void DoSwitch (void)
573 /* Handle a 'switch' statement */
575 struct expent eval; /* Switch statement expression */
577 /* Eat the "switch" */
580 /* Read the switch expression */
585 /* result of expr is in P */
588 /* Now decide which sort of switch we will create: */
589 if (IsTypeChar (eval.e_tptr) || (CodeSizeFactor >= 200 && IsClassInt (eval.e_tptr))) {
590 CascadeSwitch (&eval);
598 static void DoFor (void)
599 /* Handle a 'for' statement */
610 loop = GetLocalLabel ();
611 lab = GetLocalLabel ();
612 linc = GetLocalLabel ();
613 lstat = GetLocalLabel ();
614 AddLoop (oursp, loop, lab, linc, lstat);
616 if (CurTok.Tok != TOK_SEMI) { /* exp1 */
620 g_defcodelabel (loop);
621 if (CurTok.Tok != TOK_SEMI) { /* exp2 */
623 g_truejump (CF_NONE, lstat);
629 g_defcodelabel (linc);
630 if (CurTok.Tok != TOK_RPAREN) { /* exp3 */
635 g_defcodelabel (lstat);
638 g_defcodelabel (lab);
644 static int CompoundStatement (void)
645 /* Compound statement. Allow any number of statements inside braces. */
653 /* Remember the stack at block entry */
656 /* Enter a new lexical level */
659 /* Parse local variable declarations if any */
662 /* Now process statements in this block */
664 while (CurTok.Tok != TOK_RCURLY) {
665 if (CurTok.Tok != TOK_CEOF) {
666 isbrk = Statement ();
672 /* Emit references to imports/exports for this block */
675 /* Clean up the stack. */
679 g_space (oursp - oldsp);
683 /* Leave the lexical level */
686 /* Eat closing brace */
695 /* Statement parser. Returns 1 if the statement does a return/break, returns
702 if (CurTok.Tok == TOK_IDENT && NextTok.Tok == TOK_COLON) {
704 /* Special handling for a label */
709 switch (CurTok.Tok) {
712 return CompoundStatement ();
763 /* Actual statement */