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 statement (void);
59 static int doif (void)
60 /* Handle 'if' statement here */
69 /* Generate a jump label and parse the condition */
73 /* Parse the if body */
74 gotbreak = statement ();
76 /* Else clause present? */
77 if (curtok != TOK_ELSE) {
79 g_defloclabel (flab1);
80 /* Since there's no else clause, we're not sure, if the a break
81 * statement is really executed.
90 /* If we had some sort of break statement at the end of the if clause,
91 * there's no need to generate an additional jump around the else
92 * clause, since the jump is never reached.
98 /* Mark the label as unused */
101 g_defloclabel (flab1);
102 gotbreak &= statement ();
104 /* Generate the label for the else clause */
106 g_defloclabel (flab2);
116 static void dowhile (char wtype)
117 /* Handle 'while' statement here */
125 addloop (oursp, loop, lab, 0, 0);
126 g_defloclabel (loop);
132 /* If the statement following the while loop is empty, that is, we have
133 * something like "while (1) ;", the test function ommitted the jump as
134 * an optimization. Since we know, the condition codes are set, we can
135 * do another small optimization here, and use a conditional jump
136 * instead an absolute one.
138 if (curtok == TOK_SEMI) {
141 /* Use a conditional jump */
142 g_truejump (CF_NONE, loop);
144 /* There is code inside the while loop */
154 Consume (TOK_WHILE, ERR_WHILE_EXPECTED);
165 static void doreturn (void)
166 /* Handle 'return' statement here */
169 unsigned etype = 0; /* Type of return expression */
170 int HaveVal = 0; /* Do we have a return value in ax? */
174 if (curtok != TOK_SEMI) {
175 if (HasVoidReturn (CurrentFunc)) {
176 Error (ERR_CANNOT_RETURN_VALUE);
178 if (evalexpr (CF_NONE, hie0, &lval) == 0) {
182 /* Value in the primary register */
186 /* Convert the return value to the type of the function result */
187 if (!HasVoidReturn (CurrentFunc)) {
188 etype |= assignadjust (GetReturnType (CurrentFunc), &lval) & ~CF_CONST;
190 } else if (!HasVoidReturn (CurrentFunc)) {
191 Error (ERR_MUST_RETURN_VALUE);
193 RestoreRegVars (HaveVal);
194 g_leave (etype, lval.e_const);
199 static void dobreak (void)
200 /* Handle 'break' statement here */
205 if ((l = currentloop ()) == 0) {
206 /* Error: No current loop */
209 g_space (oursp - l->sp);
215 static void docontinue (void)
216 /* Handle 'continue' statement here */
221 if ((l = currentloop ()) == 0) {
222 /* Error: Not in loop */
232 Error (ERR_UNEXPECTED_CONTINUE);
235 g_space (oursp - l->sp);
245 static void cascadeswitch (struct expent* eval)
246 /* Handle a switch statement for chars with a cmp cascade for the selector */
248 unsigned exitlab; /* Exit label */
249 unsigned nextlab; /* Next case label */
250 unsigned codelab; /* Label that starts the actual selector code */
251 int havebreak; /* Remember if we exited with break */
252 int lcount; /* Label count */
253 unsigned flags; /* Code generator flags */
254 struct expent lval; /* Case label expression */
255 long val; /* Case label value */
258 /* Create a loop so we may break out, init labels */
259 exitlab = GetLabel ();
260 addloop (oursp, 0, exitlab, 0, 0);
262 /* Setup some variables needed in the loop below */
263 flags = TypeOf (eval->e_tptr) | CF_CONST | CF_FORCECHAR;
264 codelab = nextlab = 0;
267 /* Parse the labels */
269 while (curtok != TOK_RCURLY) {
271 if (curtok == TOK_CASE || curtok == TOK_DEFAULT) {
273 /* If the code for the previous selector did not end with a
274 * break statement, we must jump over the next selector test.
277 /* Define a label for the code */
279 codelab = GetLabel ();
284 /* If we have a cascade label, emit it */
286 g_defloclabel (nextlab);
290 while (curtok == TOK_CASE || curtok == TOK_DEFAULT) {
292 /* Parse the selector */
293 if (curtok == TOK_CASE) {
298 /* Skip the "case" token */
301 /* Read the selector expression */
303 if (!IsClassInt (lval.e_tptr)) {
304 Error (ERR_ILLEGAL_TYPE);
307 /* Check the range of the expression */
309 switch (*eval->e_tptr) {
313 if (val < -128 || val > 127) {
319 if (val < 0 || val > 255) {
325 if (val < -32768 || val > 32767) {
331 if (val < 0 || val > 65535) {
337 Internal ("Invalid type: %02X", *eval->e_tptr & 0xFF);
346 /* If another case follows, we will jump to the code if
347 * the condition is true.
349 if (curtok == TOK_CASE) {
350 /* Create a code label if needed */
352 codelab = GetLabel ();
354 g_falsejump (CF_NONE, codelab);
355 } else if (curtok != TOK_DEFAULT) {
356 /* No case follows, jump to next selector */
358 nextlab = GetLabel ();
360 g_truejump (CF_NONE, nextlab);
371 /* Handle the pathologic case: DEFAULT followed by CASE */
372 if (curtok == TOK_CASE) {
374 codelab = GetLabel ();
384 /* Emit a code label if we have one */
386 g_defloclabel (codelab);
390 /* Parse statements */
391 if (curtok != TOK_RCURLY) {
392 havebreak = statement ();
396 /* Check if we have any labels */
398 Warning (WARN_NO_CASE_LABELS);
401 /* Eat the closing curly brace */
404 /* Define the exit label and, if there's a next label left, create this
408 g_defloclabel (nextlab);
410 g_defloclabel (exitlab);
418 static void tableswitch (struct expent* eval)
419 /* Handle a switch statement via table based selector */
421 /* Entry for one case in a switch statement */
423 long sw_const; /* selector value */
424 unsigned sw_lab; /* label for this selector */
427 int dlabel; /* for default */
428 int lab; /* exit label */
429 int label; /* label for case */
430 int lcase; /* label for compares */
431 int lcount; /* Label count */
432 int havebreak; /* Last statement has a break */
433 unsigned flags; /* Code generator flags */
434 struct expent lval; /* Case label expression */
438 /* Allocate memory for the switch table */
439 swtab = xmalloc (CASE_MAX * sizeof (struct swent));
441 /* Create a look so we may break out, init labels */
442 havebreak = 0; /* Keep gcc silent */
443 dlabel = 0; /* init */
444 lab = GetLabel (); /* get exit */
446 addloop (oursp, 0, lab, 0, 0);
448 /* Jump behind the code for the CASE labels */
449 g_jump (lcase = GetLabel ());
451 while (curtok != TOK_RCURLY) {
452 if (curtok == TOK_CASE || curtok == TOK_DEFAULT) {
453 if (lcount >= CASE_MAX) {
454 Fatal (FAT_TOO_MANY_CASE_LABELS);
458 if (curtok == TOK_CASE) {
461 if (!IsClassInt (lval.e_tptr)) {
462 Error (ERR_ILLEGAL_TYPE);
464 p->sw_const = lval.e_const;
473 } while (curtok == TOK_CASE || curtok == TOK_DEFAULT);
474 g_defloclabel (label);
477 if (curtok != TOK_RCURLY) {
478 havebreak = statement ();
482 /* Check if we have any labels */
484 Warning (WARN_NO_CASE_LABELS);
487 /* Eat the closing curly brace */
490 /* If the last statement doesn't have a break or return, add one */
495 /* Actual selector code goes here */
496 g_defloclabel (lcase);
498 /* Create the call to the switch subroutine */
499 flags = TypeOf (eval->e_tptr);
502 /* First entry is negative of label count */
503 g_defdata (CF_INT | CF_CONST, -((int)lcount)-1, 0);
505 /* Create the case selector table */
506 AddCodeHint ("casetable");
509 g_case (flags, p->sw_lab, p->sw_const); /* Create one label */
520 /* Free the allocated space for the labels */
526 static void doswitch (void)
527 /* Handle 'switch' statement here */
529 struct expent eval; /* Switch statement expression */
531 /* Eat the "switch" */
534 /* Read the switch expression */
539 /* result of expr is in P */
542 /* Now decide which sort of switch we will create: */
543 if (IsTypeChar (eval.e_tptr) || (FavourSize == 0 && IsClassInt (eval.e_tptr))) {
544 cascadeswitch (&eval);
552 static void dofor (void)
553 /* Handle 'for' statement here */
568 addloop (oursp, loop, lab, linc, lstat);
570 if (curtok != TOK_SEMI) { /* exp1 */
574 g_defloclabel (loop);
575 if (curtok != TOK_SEMI) { /* exp2 */
577 g_truejump (CF_NONE, lstat);
583 g_defloclabel (linc);
584 if (curtok != TOK_RPAREN) { /* exp3 */
589 g_defloclabel (lstat);
598 static int statement (void)
599 /* Statement parser. Called whenever syntax requires a statement.
600 * This routine performs that statement and returns 1 if it is a branch,
607 if (curtok == TOK_IDENT && nxttok == TOK_COLON) {
609 /* Special handling for a label */
668 AddCodeHint ("stmt:start");
670 AddCodeHint ("stmt:end");
680 /* Compound statement. Allow any number of statements, inside braces. */
682 static unsigned CurrentLevel = 0;
690 /* Remember the stack at block entry */
693 /* If we're not on function level, enter a new lexical level */
694 if (CurrentLevel++ > 0) {
699 /* Parse local variable declarations if any */
702 /* Now process statements in the function body */
704 while (curtok != TOK_RCURLY) {
705 if (curtok == TOK_CEOF)
708 isbrk = statement ();
712 /* Emit references to imports/exports for this block */
715 /* If this is not the top level compound statement, clean up the stack.
716 * For a top level statement this will be done by the function exit code.
718 if (--CurrentLevel != 0) {
719 /* Some sort of nested block */
724 g_space (oursp - oldsp);
729 /* Eat closing brace */