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, "`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 ("Returning a value in function with return type void");
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 ("Function `%s' must return a value", GetFuncName (CurrentFunc));
193 RestoreRegVars (HaveVal);
194 g_leave (etype, lval.e_const);
199 static void dobreak (void)
200 /* Handle 'break' statement here */
207 /* Get the current loop descriptor */
210 /* Check if we are inside a loop */
212 /* Error: No current loop */
213 Error ("`break' statement not within loop or switch");
217 /* Correct the stack pointer if needed */
218 g_space (oursp - L->StackPtr);
220 /* Jump to the exit label of the loop */
226 static void docontinue (void)
227 /* Handle 'continue' statement here */
231 /* Skip the continue */
234 /* Get the current loop descriptor */
237 /* Search for the correct loop */
246 /* Did we find it? */
248 Error ("`continue' statement not within a loop");
252 /* Correct the stackpointer if needed */
253 g_space (oursp - L->StackPtr);
255 /* Output the loop code */
265 static void cascadeswitch (struct expent* eval)
266 /* Handle a switch statement for chars with a cmp cascade for the selector */
268 unsigned ExitLab; /* Exit label */
269 unsigned NextLab; /* Next case label */
270 unsigned CodeLab; /* Label that starts the actual selector code */
271 int HaveBreak; /* Remember if we exited with break */
272 int HaveDefault; /* Remember if we had a default label */
273 int lcount; /* Label count */
274 unsigned Flags; /* Code generator flags */
275 struct expent lval; /* Case label expression */
276 long Val; /* Case label value */
279 /* Create a loop so we may break out, init labels */
280 ExitLab = GetLabel ();
281 AddLoop (oursp, 0, ExitLab, 0, 0);
283 /* Setup some variables needed in the loop below */
284 Flags = TypeOf (eval->e_tptr) | CF_CONST | CF_FORCECHAR;
285 CodeLab = NextLab = 0;
289 /* Parse the labels */
291 while (curtok != TOK_RCURLY) {
293 if (curtok == TOK_CASE || curtok == TOK_DEFAULT) {
295 /* If the code for the previous selector did not end with a
296 * break statement, we must jump over the next selector test.
299 /* Define a label for the code */
301 CodeLab = GetLabel ();
306 /* If we have a cascade label, emit it */
308 g_defloclabel (NextLab);
312 while (curtok == TOK_CASE || curtok == TOK_DEFAULT) {
314 /* Parse the selector */
315 if (curtok == TOK_CASE) {
320 /* Skip the "case" token */
323 /* Read the selector expression */
325 if (!IsClassInt (lval.e_tptr)) {
326 Error ("Switch quantity not an integer");
329 /* Check the range of the expression */
331 switch (*eval->e_tptr) {
335 if (Val < -128 || Val > 127) {
336 Error ("Range error");
341 if (Val < 0 || Val > 255) {
342 Error ("Range error");
347 if (Val < -32768 || Val > 32767) {
348 Error ("Range error");
353 if (Val < 0 || Val > 65535) {
354 Error ("Range error");
359 Internal ("Invalid type: %02X", *eval->e_tptr & 0xFF);
368 /* If another case follows, we will jump to the code if
369 * the condition is true.
371 if (curtok == TOK_CASE) {
372 /* Create a code label if needed */
374 CodeLab = GetLabel ();
376 g_falsejump (CF_NONE, CodeLab);
377 } else if (curtok != TOK_DEFAULT) {
378 /* No case follows, jump to next selector */
380 NextLab = GetLabel ();
382 g_truejump (CF_NONE, NextLab);
393 /* Handle the pathologic case: DEFAULT followed by CASE */
394 if (curtok == TOK_CASE) {
396 CodeLab = GetLabel ();
401 /* Remember that we had a default label */
409 /* Emit a code label if we have one */
411 g_defloclabel (CodeLab);
415 /* Parse statements */
416 if (curtok != TOK_RCURLY) {
417 HaveBreak = statement ();
421 /* Check if we have any labels */
422 if (lcount == 0 && !HaveDefault) {
423 Warning ("No case labels");
426 /* Eat the closing curly brace */
429 /* Define the exit label and, if there's a next label left, create this
433 g_defloclabel (NextLab);
435 g_defloclabel (ExitLab);
443 static void tableswitch (struct expent* eval)
444 /* Handle a switch statement via table based selector */
446 /* Entry for one case in a switch statement */
448 long sw_const; /* selector value */
449 unsigned sw_lab; /* label for this selector */
452 int dlabel; /* for default */
453 int lab; /* exit label */
454 int label; /* label for case */
455 int lcase; /* label for compares */
456 int lcount; /* Label count */
457 int HaveBreak; /* Last statement has a break */
458 int HaveDefault; /* Remember if we had a default label */
459 unsigned Flags; /* Code generator flags */
460 struct expent lval; /* Case label expression */
464 /* Allocate memory for the switch table */
465 swtab = xmalloc (CASE_MAX * sizeof (struct swent));
467 /* Create a look so we may break out, init labels */
468 HaveBreak = 0; /* Keep gcc silent */
469 HaveDefault = 0; /* No default case until now */
470 dlabel = 0; /* init */
471 lab = GetLabel (); /* get exit */
473 AddLoop (oursp, 0, lab, 0, 0);
475 /* Jump behind the code for the CASE labels */
476 g_jump (lcase = GetLabel ());
478 while (curtok != TOK_RCURLY) {
479 if (curtok == TOK_CASE || curtok == TOK_DEFAULT) {
480 if (lcount >= CASE_MAX) {
481 Fatal ("Too many case labels");
485 if (curtok == TOK_CASE) {
488 if (!IsClassInt (lval.e_tptr)) {
489 Error ("Switch quantity not an integer");
491 p->sw_const = lval.e_const;
501 } while (curtok == TOK_CASE || curtok == TOK_DEFAULT);
502 g_defloclabel (label);
505 if (curtok != TOK_RCURLY) {
506 HaveBreak = statement ();
510 /* Check if we have any labels */
511 if (lcount == 0 && !HaveDefault) {
512 Warning ("No case labels");
515 /* Eat the closing curly brace */
518 /* If the last statement doesn't have a break or return, add one */
523 /* Actual selector code goes here */
524 g_defloclabel (lcase);
526 /* Create the call to the switch subroutine */
527 Flags = TypeOf (eval->e_tptr);
530 /* First entry is negative of label count */
531 g_defdata (CF_INT | CF_CONST, -((int)lcount)-1, 0);
533 /* Create the case selector table */
534 AddCodeHint ("casetable");
537 g_case (Flags, p->sw_lab, p->sw_const); /* Create one label */
548 /* Free the allocated space for the labels */
554 static void doswitch (void)
555 /* Handle 'switch' statement here */
557 struct expent eval; /* Switch statement expression */
559 /* Eat the "switch" */
562 /* Read the switch expression */
567 /* result of expr is in P */
570 /* Now decide which sort of switch we will create: */
571 if (IsTypeChar (eval.e_tptr) || (FavourSize == 0 && IsClassInt (eval.e_tptr))) {
572 cascadeswitch (&eval);
580 static void dofor (void)
581 /* Handle 'for' statement here */
596 AddLoop (oursp, loop, lab, linc, lstat);
598 if (curtok != TOK_SEMI) { /* exp1 */
602 g_defloclabel (loop);
603 if (curtok != TOK_SEMI) { /* exp2 */
605 g_truejump (CF_NONE, lstat);
611 g_defloclabel (linc);
612 if (curtok != TOK_RPAREN) { /* exp3 */
617 g_defloclabel (lstat);
626 static int statement (void)
627 /* Statement parser. Called whenever syntax requires a statement.
628 * This routine performs that statement and returns 1 if it is a branch,
635 if (curtok == TOK_IDENT && nxttok == TOK_COLON) {
637 /* Special handling for a label */
696 AddCodeHint ("stmt:start");
698 AddCodeHint ("stmt:end");
708 /* Compound statement. Allow any number of statements, inside braces. */
710 static unsigned CurrentLevel = 0;
718 /* Remember the stack at block entry */
721 /* If we're not on function level, enter a new lexical level */
722 if (CurrentLevel++ > 0) {
727 /* Parse local variable declarations if any */
730 /* Now process statements in the function body */
732 while (curtok != TOK_RCURLY) {
733 if (curtok == TOK_CEOF)
736 isbrk = statement ();
740 /* Emit references to imports/exports for this block */
743 /* If this is not the top level compound statement, clean up the stack.
744 * For a top level statement this will be done by the function exit code.
746 if (--CurrentLevel != 0) {
747 /* Some sort of nested block */
752 g_space (oursp - oldsp);
757 /* Eat closing brace */