4 * Ullrich von Bassewitz, 06.08.1998
6 * Original by John R. Dunning - see copyleft.jrd
14 #include "../common/xmalloc.h"
35 /*****************************************************************************/
37 /*****************************************************************************/
41 /* Maximum count of cases */
46 /*****************************************************************************/
48 /*****************************************************************************/
52 static int statement (void);
57 static int doif (void)
58 /* Handle 'if' statement here */
67 /* Generate a jump label and parse the condition */
71 /* Parse the if body */
72 gotbreak = statement ();
74 /* Else clause present? */
75 if (curtok != TOK_ELSE) {
77 g_defloclabel (flab1);
78 /* Since there's no else clause, we're not sure, if the a break
79 * statement is really executed.
88 /* If we had some sort of break statement at the end of the if clause,
89 * there's no need to generate an additional jump around the else
90 * clause, since the jump is never reached.
96 /* Mark the label as unused */
99 g_defloclabel (flab1);
100 gotbreak &= statement ();
102 /* Generate the label for the else clause */
104 g_defloclabel (flab2);
114 static void dowhile (char wtype)
115 /* Handle 'while' statement here */
123 addloop (oursp, loop, lab, 0, 0);
124 g_defloclabel (loop);
130 /* If the statement following the while loop is empty, that is, we have
131 * something like "while (1) ;", the test function ommitted the jump as
132 * an optimization. Since we know, the condition codes are set, we can
133 * do another small optimization here, and use a conditional jump
134 * instead an absolute one.
136 if (curtok == TOK_SEMI) {
139 /* Use a conditional jump */
140 g_truejump (CF_NONE, loop);
142 /* There is code inside the while loop */
152 Consume (TOK_WHILE, ERR_WHILE_EXPECTED);
163 static void doreturn (void)
164 /* Handle 'return' statement here */
167 unsigned etype = 0; /* Type of return expression */
168 int HaveVal = 0; /* Do we have a return value in ax? */
172 if (curtok != TOK_SEMI) {
173 if (HasVoidReturn (CurrentFunc)) {
174 Error (ERR_CANNOT_RETURN_VALUE);
176 if (evalexpr (CF_NONE, hie0, &lval) == 0) {
180 /* Value in the primary register */
184 /* Convert the return value to the type of the function result */
185 if (!HasVoidReturn (CurrentFunc)) {
186 etype |= assignadjust (GetReturnType (CurrentFunc), &lval) & ~CF_CONST;
188 } else if (!HasVoidReturn (CurrentFunc)) {
189 Error (ERR_MUST_RETURN_VALUE);
191 RestoreRegVars (HaveVal);
192 g_leave (etype, lval.e_const);
197 static void dobreak (void)
198 /* Handle 'break' statement here */
203 if ((l = currentloop ()) == 0) {
204 /* Error: No current loop */
207 g_space (oursp - l->sp);
213 static void docontinue (void)
214 /* Handle 'continue' statement here */
219 if ((l = currentloop ()) == 0) {
220 /* Error: Not in loop */
230 Error (ERR_UNEXPECTED_CONTINUE);
233 g_space (oursp - l->sp);
243 static void cascadeswitch (struct expent* eval)
244 /* Handle a switch statement for chars with a cmp cascade for the selector */
246 unsigned exitlab; /* Exit label */
247 unsigned nextlab; /* Next case label */
248 unsigned codelab; /* Label that starts the actual selector code */
249 int havebreak; /* Remember if we exited with break */
250 int lcount; /* Label count */
251 unsigned flags; /* Code generator flags */
252 struct expent lval; /* Case label expression */
253 long val; /* Case label value */
256 /* Create a loop so we may break out, init labels */
257 exitlab = GetLabel ();
258 addloop (oursp, 0, exitlab, 0, 0);
260 /* Setup some variables needed in the loop below */
261 flags = TypeOf (eval->e_tptr) | CF_CONST | CF_FORCECHAR;
262 codelab = nextlab = 0;
265 /* Parse the labels */
267 while (curtok != TOK_RCURLY) {
269 if (curtok == TOK_CASE || curtok == TOK_DEFAULT) {
271 /* If the code for the previous selector did not end with a
272 * break statement, we must jump over the next selector test.
275 /* Define a label for the code */
277 codelab = GetLabel ();
282 /* If we have a cascade label, emit it */
284 g_defloclabel (nextlab);
288 while (curtok == TOK_CASE || curtok == TOK_DEFAULT) {
290 /* Parse the selector */
291 if (curtok == TOK_CASE) {
296 /* Skip the "case" token */
299 /* Read the selector expression */
301 if (!IsInt (lval.e_tptr)) {
302 Error (ERR_ILLEGAL_TYPE);
305 /* Check the range of the expression */
307 switch (*eval->e_tptr) {
311 if (val < -128 || val > 127) {
317 if (val < 0 || val > 255) {
323 if (val < -32768 || val > 32767) {
329 if (val < 0 || val > 65535) {
335 Internal ("Invalid type: %02X", *eval->e_tptr & 0xFF);
344 /* If another case follows, we will jump to the code if
345 * the condition is true.
347 if (curtok == TOK_CASE) {
348 /* Create a code label if needed */
350 codelab = GetLabel ();
352 g_falsejump (CF_NONE, codelab);
353 } else if (curtok != TOK_DEFAULT) {
354 /* No case follows, jump to next selector */
356 nextlab = GetLabel ();
358 g_truejump (CF_NONE, nextlab);
369 /* Handle the pathologic case: DEFAULT followed by CASE */
370 if (curtok == TOK_CASE) {
372 codelab = GetLabel ();
382 /* Emit a code label if we have one */
384 g_defloclabel (codelab);
388 /* Parse statements */
389 if (curtok != TOK_RCURLY) {
390 havebreak = statement ();
394 /* Check if we have any labels */
396 Warning (WARN_NO_CASE_LABELS);
399 /* Eat the closing curly brace */
402 /* Define the exit label and, if there's a next label left, create this
406 g_defloclabel (nextlab);
408 g_defloclabel (exitlab);
416 static void tableswitch (struct expent* eval)
417 /* Handle a switch statement via table based selector */
419 /* Entry for one case in a switch statement */
421 long sw_const; /* selector value */
422 unsigned sw_lab; /* label for this selector */
425 int dlabel; /* for default */
426 int lab; /* exit label */
427 int label; /* label for case */
428 int lcase; /* label for compares */
429 int lcount; /* Label count */
430 int havebreak; /* Last statement has a break */
431 unsigned flags; /* Code generator flags */
432 struct expent lval; /* Case label expression */
436 /* Allocate memory for the switch table */
437 swtab = xmalloc (CASE_MAX * sizeof (struct swent));
439 /* Create a look so we may break out, init labels */
440 havebreak = 0; /* Keep gcc silent */
441 dlabel = 0; /* init */
442 lab = GetLabel (); /* get exit */
444 addloop (oursp, 0, lab, 0, 0);
446 /* Jump behind the code for the CASE labels */
447 g_jump (lcase = GetLabel ());
449 while (curtok != TOK_RCURLY) {
450 if (curtok == TOK_CASE || curtok == TOK_DEFAULT) {
451 if (lcount >= CASE_MAX) {
452 Fatal (FAT_TOO_MANY_CASE_LABELS);
456 if (curtok == TOK_CASE) {
459 if (!IsInt (lval.e_tptr)) {
460 Error (ERR_ILLEGAL_TYPE);
462 p->sw_const = lval.e_const;
471 } while (curtok == TOK_CASE || curtok == TOK_DEFAULT);
472 g_defloclabel (label);
475 if (curtok != TOK_RCURLY) {
476 havebreak = statement ();
480 /* Check if we have any labels */
482 Warning (WARN_NO_CASE_LABELS);
485 /* Eat the closing curly brace */
488 /* If the last statement doesn't have a break or return, add one */
493 /* Actual selector code goes here */
494 g_defloclabel (lcase);
496 /* Create the call to the switch subroutine */
497 flags = TypeOf (eval->e_tptr);
500 /* First entry is negative of label count */
501 g_defdata (CF_INT | CF_CONST, -((int)lcount)-1, 0);
503 /* Create the case selector table */
504 AddCodeHint ("casetable");
507 g_case (flags, p->sw_lab, p->sw_const); /* Create one label */
518 /* Free the allocated space for the labels */
524 static void doswitch (void)
525 /* Handle 'switch' statement here */
527 struct expent eval; /* Switch statement expression */
529 /* Eat the "switch" */
532 /* Read the switch expression */
537 /* result of expr is in P */
540 /* Now decide which sort of switch we will create: */
541 if (IsChar (eval.e_tptr) || (FavourSize == 0 && IsInt (eval.e_tptr))) {
542 cascadeswitch (&eval);
550 static void dofor (void)
551 /* Handle 'for' statement here */
566 addloop (oursp, loop, lab, linc, lstat);
568 if (curtok != TOK_SEMI) { /* exp1 */
572 g_defloclabel (loop);
573 if (curtok != TOK_SEMI) { /* exp2 */
575 g_truejump (CF_NONE, lstat);
581 g_defloclabel (linc);
582 if (curtok != TOK_RPAREN) { /* exp3 */
587 g_defloclabel (lstat);
596 static int statement (void)
597 /* Statement parser. Called whenever syntax requires a statement.
598 * This routine performs that statement and returns 1 if it is a branch,
605 if (curtok == TOK_IDENT && nxttok == TOK_COLON) {
607 /* Special handling for a label */
666 AddCodeHint ("stmt:start");
668 AddCodeHint ("stmt:end");
678 /* Compound statement. Allow any number of statements, inside braces. */
680 static unsigned CurrentLevel = 0;
688 /* Remember the stack at block entry */
691 /* If we're not on function level, enter a new lexical level */
692 if (CurrentLevel++ > 0) {
697 /* Parse local variable declarations if any */
700 /* Now process statements in the function body */
702 while (curtok != TOK_RCURLY) {
703 if (curtok == TOK_CEOF)
706 isbrk = statement ();
710 /* Emit references to imports/exports for this block */
713 /* If this is not the top level compound statement, clean up the stack.
714 * For a top level statement this will be done by the function exit code.
716 if (--CurrentLevel != 0) {
717 /* Some sort of nested block */
722 g_space (oursp - oldsp);
727 /* Eat closing brace */