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 'if' statement here */
64 /* Generate a jump label and parse the condition */
68 /* Parse the if body */
69 gotbreak = Statement ();
71 /* Else clause present? */
72 if (curtok != TOK_ELSE) {
74 g_defloclabel (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.
93 /* Mark the label as unused */
96 g_defloclabel (flab1);
97 gotbreak &= Statement ();
99 /* Generate the label for the else clause */
101 g_defloclabel (flab2);
111 static void dowhile (char wtype)
112 /* Handle 'while' statement here */
120 AddLoop (oursp, loop, lab, 0, 0);
121 g_defloclabel (loop);
127 /* If the statement following the while loop is empty, that is, we have
128 * something like "while (1) ;", the test function ommitted the jump as
129 * an optimization. Since we know, the condition codes are set, we can
130 * do another small optimization here, and use a conditional jump
131 * instead an absolute one.
133 if (curtok == TOK_SEMI) {
136 /* Use a conditional jump */
137 g_truejump (CF_NONE, loop);
139 /* There is code inside the while loop */
149 Consume (TOK_WHILE, "`while' expected");
160 static void DoReturn (void)
161 /* Handle 'return' statement here */
166 if (curtok != TOK_SEMI) {
167 if (HasVoidReturn (CurrentFunc)) {
168 Error ("Returning a value in function with return type void");
171 /* Evaluate the return expression. Result will be in primary */
174 /* Convert the return value to the type of the function result */
175 if (!HasVoidReturn (CurrentFunc)) {
176 assignadjust (GetReturnType (CurrentFunc), &lval);
178 } else if (!HasVoidReturn (CurrentFunc)) {
179 Error ("Function `%s' must return a value", GetFuncName (CurrentFunc));
182 /* Cleanup the stack in case we're inside a block with locals */
183 g_space (oursp - GetTopLevelSP (CurrentFunc));
185 /* Output a jump to the function exit code */
186 g_jump (GetRetLab (CurrentFunc));
191 static void dobreak (void)
192 /* Handle 'break' statement here */
199 /* Get the current loop descriptor */
202 /* Check if we are inside a loop */
204 /* Error: No current loop */
205 Error ("`break' statement not within loop or switch");
209 /* Correct the stack pointer if needed */
210 g_space (oursp - L->StackPtr);
212 /* Jump to the exit label of the loop */
218 static void docontinue (void)
219 /* Handle 'continue' statement here */
223 /* Skip the continue */
226 /* Get the current loop descriptor */
229 /* Search for the correct loop */
238 /* Did we find it? */
240 Error ("`continue' statement not within a loop");
244 /* Correct the stackpointer if needed */
245 g_space (oursp - L->StackPtr);
247 /* Output the loop code */
257 static void cascadeswitch (struct expent* eval)
258 /* Handle a switch statement for chars with a cmp cascade for the selector */
260 unsigned ExitLab; /* Exit label */
261 unsigned NextLab; /* Next case label */
262 unsigned CodeLab; /* Label that starts the actual selector code */
263 int HaveBreak; /* Remember if we exited with break */
264 int HaveDefault; /* Remember if we had a default label */
265 int lcount; /* Label count */
266 unsigned Flags; /* Code generator flags */
267 struct expent lval; /* Case label expression */
268 long Val; /* Case label value */
271 /* Create a loop so we may break out, init labels */
272 ExitLab = GetLabel ();
273 AddLoop (oursp, 0, ExitLab, 0, 0);
275 /* Setup some variables needed in the loop below */
276 Flags = TypeOf (eval->e_tptr) | CF_CONST | CF_FORCECHAR;
277 CodeLab = NextLab = 0;
281 /* Parse the labels */
283 while (curtok != TOK_RCURLY) {
285 if (curtok == TOK_CASE || curtok == TOK_DEFAULT) {
287 /* If the code for the previous selector did not end with a
288 * break statement, we must jump over the next selector test.
291 /* Define a label for the code */
293 CodeLab = GetLabel ();
298 /* If we have a cascade label, emit it */
300 g_defloclabel (NextLab);
304 while (curtok == TOK_CASE || curtok == TOK_DEFAULT) {
306 /* Parse the selector */
307 if (curtok == TOK_CASE) {
312 /* Skip the "case" token */
315 /* Read the selector expression */
317 if (!IsClassInt (lval.e_tptr)) {
318 Error ("Switch quantity not an integer");
321 /* Check the range of the expression */
323 switch (*eval->e_tptr) {
327 if (Val < -128 || Val > 127) {
328 Error ("Range error");
333 if (Val < 0 || Val > 255) {
334 Error ("Range error");
339 if (Val < -32768 || Val > 32767) {
340 Error ("Range error");
345 if (Val < 0 || Val > 65535) {
346 Error ("Range error");
351 Internal ("Invalid type: %02X", *eval->e_tptr & 0xFF);
360 /* If another case follows, we will jump to the code if
361 * the condition is true.
363 if (curtok == TOK_CASE) {
364 /* Create a code label if needed */
366 CodeLab = GetLabel ();
368 g_falsejump (CF_NONE, CodeLab);
369 } else if (curtok != TOK_DEFAULT) {
370 /* No case follows, jump to next selector */
372 NextLab = GetLabel ();
374 g_truejump (CF_NONE, NextLab);
385 /* Handle the pathologic case: DEFAULT followed by CASE */
386 if (curtok == TOK_CASE) {
388 CodeLab = GetLabel ();
393 /* Remember that we had a default label */
401 /* Emit a code label if we have one */
403 g_defloclabel (CodeLab);
407 /* Parse statements */
408 if (curtok != TOK_RCURLY) {
409 HaveBreak = Statement ();
413 /* Check if we have any labels */
414 if (lcount == 0 && !HaveDefault) {
415 Warning ("No case labels");
418 /* Eat the closing curly brace */
421 /* Define the exit label and, if there's a next label left, create this
425 g_defloclabel (NextLab);
427 g_defloclabel (ExitLab);
435 static void tableswitch (struct expent* eval)
436 /* Handle a switch statement via table based selector */
438 /* Entry for one case in a switch statement */
440 long sw_const; /* selector value */
441 unsigned sw_lab; /* label for this selector */
444 int dlabel; /* for default */
445 int lab; /* exit label */
446 int label; /* label for case */
447 int lcase; /* label for compares */
448 int lcount; /* Label count */
449 int HaveBreak; /* Last statement has a break */
450 int HaveDefault; /* Remember if we had a default label */
451 unsigned Flags; /* Code generator flags */
452 struct expent lval; /* Case label expression */
456 /* Allocate memory for the switch table */
457 swtab = xmalloc (CASE_MAX * sizeof (struct swent));
459 /* Create a look so we may break out, init labels */
460 HaveBreak = 0; /* Keep gcc silent */
461 HaveDefault = 0; /* No default case until now */
462 dlabel = 0; /* init */
463 lab = GetLabel (); /* get exit */
465 AddLoop (oursp, 0, lab, 0, 0);
467 /* Jump behind the code for the CASE labels */
468 g_jump (lcase = GetLabel ());
470 while (curtok != TOK_RCURLY) {
471 if (curtok == TOK_CASE || curtok == TOK_DEFAULT) {
472 if (lcount >= CASE_MAX) {
473 Fatal ("Too many case labels");
477 if (curtok == TOK_CASE) {
480 if (!IsClassInt (lval.e_tptr)) {
481 Error ("Switch quantity not an integer");
483 p->sw_const = lval.e_const;
493 } while (curtok == TOK_CASE || curtok == TOK_DEFAULT);
494 g_defloclabel (label);
497 if (curtok != TOK_RCURLY) {
498 HaveBreak = Statement ();
502 /* Check if we have any labels */
503 if (lcount == 0 && !HaveDefault) {
504 Warning ("No case labels");
507 /* Eat the closing curly brace */
510 /* If the last statement doesn't have a break or return, add one */
515 /* Actual selector code goes here */
516 g_defloclabel (lcase);
518 /* Create the call to the switch subroutine */
519 Flags = TypeOf (eval->e_tptr);
522 /* First entry is negative of label count */
523 g_defdata (CF_INT | CF_CONST, -((int)lcount)-1, 0);
525 /* Create the case selector table */
526 AddCodeHint ("casetable");
529 g_case (Flags, p->sw_lab, p->sw_const); /* Create one label */
540 /* Free the allocated space for the labels */
546 static void doswitch (void)
547 /* Handle 'switch' statement here */
549 struct expent eval; /* Switch statement expression */
551 /* Eat the "switch" */
554 /* Read the switch expression */
559 /* result of expr is in P */
562 /* Now decide which sort of switch we will create: */
563 if (IsTypeChar (eval.e_tptr) || (CodeSizeFactor >= 200 && IsClassInt (eval.e_tptr))) {
564 cascadeswitch (&eval);
572 static void dofor (void)
573 /* Handle 'for' statement here */
588 AddLoop (oursp, loop, lab, linc, lstat);
590 if (curtok != TOK_SEMI) { /* exp1 */
594 g_defloclabel (loop);
595 if (curtok != TOK_SEMI) { /* exp2 */
597 g_truejump (CF_NONE, lstat);
603 g_defloclabel (linc);
604 if (curtok != TOK_RPAREN) { /* exp3 */
609 g_defloclabel (lstat);
618 static int CompoundStatement (void)
619 /* Compound statement. Allow any number of statements inside braces. */
627 /* Remember the stack at block entry */
630 /* Enter a new lexical level */
633 /* Parse local variable declarations if any */
636 /* Now process statements in this block */
638 while (curtok != TOK_RCURLY) {
639 if (curtok != TOK_CEOF) {
640 isbrk = Statement ();
646 /* Emit references to imports/exports for this block */
649 /* Clean up the stack. */
653 g_space (oursp - oldsp);
657 /* Leave the lexical level */
660 /* Eat closing brace */
669 /* Statement parser. Returns 1 if the statement does a return/break, returns
676 if (curtok == TOK_IDENT && nxttok == TOK_COLON) {
678 /* Special handling for a label */
686 return CompoundStatement ();
737 AddCodeHint ("stmt:start");
739 AddCodeHint ("stmt:end");