4 * Ullrich von Bassewitz, 06.08.1998
6 * Original by John R. Dunning - see copyleft.jrd
34 /*****************************************************************************/
36 /*****************************************************************************/
40 /* Maximum count of cases */
45 /*****************************************************************************/
47 /*****************************************************************************/
51 static int statement (void);
56 static int doif (void)
57 /* Handle 'if' statement here */
66 /* Generate a jump label and parse the condition */
70 /* Parse the if body */
71 gotbreak = statement ();
73 /* Else clause present? */
76 g_defloclabel (flab1);
77 /* Since there's no else clause, we're not sure, if the a break
78 * statement is really executed.
87 /* If we had some sort of break statement at the end of the if clause,
88 * there's no need to generate an additional jump around the else
89 * clause, since the jump is never reached.
95 /* Mark the label as unused */
98 g_defloclabel (flab1);
99 gotbreak &= statement ();
101 /* Generate the label for the else clause */
103 g_defloclabel (flab2);
113 static void dowhile (char wtype)
114 /* Handle 'while' statement here */
122 addloop (oursp, loop, lab, 0, 0);
123 g_defloclabel (loop);
129 /* If the statement following the while loop is empty, that is, we have
130 * something like "while (1) ;", the test function ommitted the jump as
131 * an optimization. Since we know, the condition codes are set, we can
132 * do another small optimization here, and use a conditional jump
133 * instead an absolute one.
135 if (curtok == SEMI) {
138 /* Use a conditional jump */
139 g_truejump (CF_NONE, loop);
141 /* There is code inside the while loop */
151 Consume (WHILE, ERR_WHILE_EXPECTED);
162 static void doreturn (void)
163 /* Handle 'return' statement here */
166 unsigned etype = 0; /* Type of return expression */
167 int HaveVal = 0; /* Do we have a return value in ax? */
171 if (curtok != SEMI) {
172 if (HasVoidReturn (CurrentFunc)) {
173 Error (ERR_CANNOT_RETURN_VALUE);
175 if (evalexpr (CF_NONE, hie0, &lval) == 0) {
179 /* Value in the primary register */
183 /* Convert the return value to the type of the function result */
184 if (!HasVoidReturn (CurrentFunc)) {
185 etype |= assignadjust (GetReturnType (CurrentFunc), &lval) & ~CF_CONST;
187 } else if (!HasVoidReturn (CurrentFunc)) {
188 Error (ERR_MUST_RETURN_VALUE);
190 RestoreRegVars (HaveVal);
191 g_leave (etype, lval.e_const);
196 static void dobreak (void)
197 /* Handle 'break' statement here */
202 if ((l = currentloop ()) == 0) {
203 /* Error: No current loop */
206 g_space (oursp - l->sp);
212 static void docontinue (void)
213 /* Handle 'continue' statement here */
218 if ((l = currentloop ()) == 0) {
219 /* Error: Not in loop */
229 Error (ERR_UNEXPECTED_CONTINUE);
232 g_space (oursp - l->sp);
242 static void cascadeswitch (struct expent* eval)
243 /* Handle a switch statement for chars with a cmp cascade for the selector */
245 unsigned exitlab; /* Exit label */
246 unsigned nextlab; /* Next case label */
247 unsigned codelab; /* Label that starts the actual selector code */
248 int havebreak; /* Remember if we exited with break */
249 int lcount; /* Label count */
250 unsigned flags; /* Code generator flags */
251 struct expent lval; /* Case label expression */
252 long val; /* Case label value */
255 /* Create a loop so we may break out, init labels */
256 exitlab = GetLabel ();
257 addloop (oursp, 0, exitlab, 0, 0);
259 /* Setup some variables needed in the loop below */
260 flags = TypeOf (eval->e_tptr) | CF_CONST | CF_FORCECHAR;
261 codelab = nextlab = 0;
264 /* Parse the labels */
266 while (curtok != RCURLY) {
268 if (curtok == CASE || curtok == DEFAULT) {
270 /* If the code for the previous selector did not end with a
271 * break statement, we must jump over the next selector test.
274 /* Define a label for the code */
276 codelab = GetLabel ();
281 /* If we have a cascade label, emit it */
283 g_defloclabel (nextlab);
287 while (curtok == CASE || curtok == DEFAULT) {
289 /* Parse the selector */
290 if (curtok == CASE) {
295 /* Skip the "case" token */
298 /* Read the selector expression */
300 if (!IsInt (lval.e_tptr)) {
301 Error (ERR_ILLEGAL_TYPE);
304 /* Check the range of the expression */
306 switch (*eval->e_tptr) {
310 if (val < -128 || val > 127) {
316 if (val < 0 || val > 255) {
322 if (val < -32768 || val > 32767) {
328 if (val < 0 || val > 65535) {
334 Internal ("Invalid type: %02X", *eval->e_tptr & 0xFF);
343 /* If another case follows, we will jump to the code if
344 * the condition is true.
346 if (curtok == CASE) {
347 /* Create a code label if needed */
349 codelab = GetLabel ();
351 g_falsejump (CF_NONE, codelab);
352 } else if (curtok != DEFAULT) {
353 /* No case follows, jump to next selector */
355 nextlab = GetLabel ();
357 g_truejump (CF_NONE, nextlab);
368 /* Handle the pathologic case: DEFAULT followed by CASE */
369 if (curtok == CASE) {
371 codelab = GetLabel ();
381 /* Emit a code label if we have one */
383 g_defloclabel (codelab);
387 /* Parse statements */
388 if (curtok != RCURLY) {
389 havebreak = statement ();
393 /* Check if we have any labels */
395 Warning (WARN_NO_CASE_LABELS);
398 /* Eat the closing curly brace */
401 /* Define the exit label and, if there's a next label left, create this
405 g_defloclabel (nextlab);
407 g_defloclabel (exitlab);
415 static void tableswitch (struct expent* eval)
416 /* Handle a switch statement via table based selector */
418 /* Entry for one case in a switch statement */
420 long sw_const; /* selector value */
421 unsigned sw_lab; /* label for this selector */
424 int dlabel; /* for default */
425 int lab; /* exit label */
426 int label; /* label for case */
427 int lcase; /* label for compares */
428 int lcount; /* Label count */
429 int havebreak; /* Last statement has a break */
430 unsigned flags; /* Code generator flags */
431 struct expent lval; /* Case label expression */
435 /* Allocate memory for the switch table */
436 swtab = xmalloc (CASE_MAX * sizeof (struct swent));
438 /* Create a look so we may break out, init labels */
439 havebreak = 0; /* Keep gcc silent */
440 dlabel = 0; /* init */
441 lab = GetLabel (); /* get exit */
443 addloop (oursp, 0, lab, 0, 0);
445 /* Jump behind the code for the CASE labels */
446 g_jump (lcase = GetLabel ());
448 while (curtok != RCURLY) {
449 if (curtok == CASE || curtok == DEFAULT) {
450 if (lcount >= CASE_MAX) {
451 Fatal (FAT_TOO_MANY_CASE_LABELS);
455 if (curtok == CASE) {
458 if (!IsInt (lval.e_tptr)) {
459 Error (ERR_ILLEGAL_TYPE);
461 p->sw_const = lval.e_const;
470 } while (curtok == CASE || curtok == DEFAULT);
471 g_defloclabel (label);
474 if (curtok != RCURLY) {
475 havebreak = statement ();
479 /* Check if we have any labels */
481 Warning (WARN_NO_CASE_LABELS);
484 /* Eat the closing curly brace */
487 /* If the last statement doesn't have a break or return, add one */
492 /* Actual selector code goes here */
493 g_defloclabel (lcase);
495 /* Create the call to the switch subroutine */
496 flags = TypeOf (eval->e_tptr);
499 /* First entry is negative of label count */
500 g_defdata (CF_INT, -((int)lcount)-1, 0);
502 /* Create the case selector table */
503 AddCodeHint ("casetable");
506 g_case (flags, p->sw_lab, p->sw_const); /* Create one label */
517 /* Free the allocated space for the labels */
523 static void doswitch (void)
524 /* Handle 'switch' statement here */
526 struct expent eval; /* Switch statement expression */
528 /* Eat the "switch" */
531 /* Read the switch expression */
536 /* result of expr is in P */
539 /* Now decide which sort of switch we will create: */
540 if (IsChar (eval.e_tptr) || (FavourSize == 0 && IsInt (eval.e_tptr))) {
541 cascadeswitch (&eval);
549 static void dofor (void)
550 /* Handle 'for' statement here */
565 addloop (oursp, loop, lab, linc, lstat);
567 if (curtok != SEMI) { /* exp1 */
571 g_defloclabel (loop);
572 if (curtok != SEMI) { /* exp2 */
574 g_truejump (CF_NONE, lstat);
580 g_defloclabel (linc);
581 if (curtok != RPAREN) { /* exp3 */
586 g_defloclabel (lstat);
595 static int statement (void)
596 /* Statement parser. Called whenever syntax requires a statement.
597 * This routine performs that statement and returns 1 if it is a branch,
604 if (curtok == IDENT && nxttok == COLON) {
606 /* Special handling for a label */
665 AddCodeHint ("stmt:start");
667 AddCodeHint ("stmt:end");
677 /* Compound statement. Allow any number of statements, inside braces. */
679 static unsigned CurrentLevel = 0;
687 /* Remember the stack at block entry */
690 /* If we're not on function level, enter a new lexical level */
691 if (CurrentLevel++ > 0) {
696 /* Parse local variable declarations if any */
699 /* Now process statements in the function body */
701 while (curtok != RCURLY) {
705 isbrk = statement ();
709 /* Emit references to imports/exports for this block */
712 /* If this is not the top level compound statement, clean up the stack.
713 * For a top level statement this will be done by the function exit code.
715 if (--CurrentLevel != 0) {
716 /* Some sort of nested block */
721 g_space (oursp - oldsp);
726 /* Eat closing brace */