4 * Ullrich von Bassewitz, 06.08.1998
6 * Original by John R. Dunning - see copyleft.jrd
37 /*****************************************************************************/
39 /*****************************************************************************/
43 /* Maximum count of cases */
48 /*****************************************************************************/
49 /* Helper functions */
50 /*****************************************************************************/
54 static void CheckTok (token_t Tok, const char* Msg, int* PendingToken)
55 /* Helper function for Statement. Will check for Tok and print Msg if not
56 * found. If PendingToken is NULL, it will the skip the token, otherwise
57 * it will store one to PendingToken.
60 if (CurTok.Tok != Tok) {
62 } else if (PendingToken) {
71 static void CheckSemi (int* PendingToken)
72 /* Helper function for Statement. Will call CheckTok with the parameters
76 CheckTok (TOK_SEMI, "`;' expected", PendingToken);
81 static void SkipPending (int PendingToken)
82 /* Skip the pending token if we have one */
91 /*****************************************************************************/
93 /*****************************************************************************/
97 static int IfStatement (void)
98 /* Handle an 'if' statement */
106 /* Generate a jump label and parse the condition */
107 Label1 = GetLocalLabel ();
110 /* Parse the if body */
111 GotBreak = Statement (0);
113 /* Else clause present? */
114 if (CurTok.Tok != TOK_ELSE) {
116 g_defcodelabel (Label1);
118 /* Since there's no else clause, we're not sure, if the a break
119 * statement is really executed.
125 /* Generate a jump around the else branch */
126 unsigned Label2 = GetLocalLabel ();
132 /* Define the target for the first test */
133 g_defcodelabel (Label1);
135 /* Total break only if both branches had a break. */
136 GotBreak &= Statement (0);
138 /* Generate the label for the else clause */
139 g_defcodelabel (Label2);
148 static void DoStatement (void)
149 /* Handle the 'do' statement */
151 /* Get the loop control labels */
152 unsigned loop = GetLocalLabel ();
153 unsigned lab = GetLocalLabel ();
155 /* Skip the while token */
158 /* Add the loop to the loop stack */
159 AddLoop (oursp, loop, lab, 0, 0);
161 /* Define the head label */
162 g_defcodelabel (loop);
164 /* Parse the loop body */
167 /* Parse the end condition */
168 Consume (TOK_WHILE, "`while' expected");
172 /* Define the break label */
173 g_defcodelabel (lab);
175 /* Remove the loop from the loop stack */
181 static void WhileStatement (void)
182 /* Handle the 'while' statement */
186 /* Get the loop control labels */
187 unsigned loop = GetLocalLabel ();
188 unsigned lab = GetLocalLabel ();
190 /* Skip the while token */
193 /* Add the loop to the loop stack */
194 AddLoop (oursp, loop, lab, 0, 0);
196 /* Define the head label */
197 g_defcodelabel (loop);
199 /* Test the loop condition */
202 /* If the statement following the while loop is empty, that is, we have
203 * something like "while (1) ;", the test function ommitted the jump as
204 * an optimization. Since we know, the condition codes are set, we can
205 * do another small optimization here, and use a conditional jump
206 * instead an absolute one.
208 if (CurTok.Tok == TOK_SEMI) {
209 /* Use a conditional jump */
210 g_truejump (CF_NONE, loop);
214 /* There is code inside the while loop, parse the body */
215 Statement (&PendingToken);
217 g_defcodelabel (lab);
218 SkipPending (PendingToken);
221 /* Remove the loop from the loop stack */
227 static void ReturnStatement (void)
228 /* Handle the 'return' statement */
233 if (CurTok.Tok != TOK_SEMI) {
234 if (HasVoidReturn (CurrentFunc)) {
235 Error ("Returning a value in function with return type void");
238 /* Evaluate the return expression. Result will be in primary */
241 /* Convert the return value to the type of the function result */
242 if (!HasVoidReturn (CurrentFunc)) {
243 assignadjust (GetReturnType (CurrentFunc), &lval);
245 } else if (!HasVoidReturn (CurrentFunc)) {
246 Error ("Function `%s' must return a value", GetFuncName (CurrentFunc));
249 /* Cleanup the stack in case we're inside a block with locals */
250 g_space (oursp - GetTopLevelSP (CurrentFunc));
252 /* Output a jump to the function exit code */
253 g_jump (GetRetLab (CurrentFunc));
258 static void BreakStatement (void)
259 /* Handle the 'break' statement */
266 /* Get the current loop descriptor */
269 /* Check if we are inside a loop */
271 /* Error: No current loop */
272 Error ("`break' statement not within loop or switch");
276 /* Correct the stack pointer if needed */
277 g_space (oursp - L->StackPtr);
279 /* Jump to the exit label of the loop */
285 static void ContinueStatement (void)
286 /* Handle the 'continue' statement */
290 /* Skip the continue */
293 /* Get the current loop descriptor */
296 /* Search for the correct loop */
305 /* Did we find it? */
307 Error ("`continue' statement not within a loop");
311 /* Correct the stackpointer if needed */
312 g_space (oursp - L->StackPtr);
314 /* Output the loop code */
324 static void CascadeSwitch (struct expent* eval)
325 /* Handle a switch statement for chars with a cmp cascade for the selector */
327 unsigned ExitLab; /* Exit label */
328 unsigned NextLab; /* Next case label */
329 unsigned CodeLab; /* Label that starts the actual selector code */
330 int HaveBreak; /* Remember if we exited with break */
331 int HaveDefault; /* Remember if we had a default label */
332 int lcount; /* Label count */
333 unsigned Flags; /* Code generator flags */
334 struct expent lval; /* Case label expression */
335 long Val; /* Case label value */
338 /* Create a loop so we may break out, init labels */
339 ExitLab = GetLocalLabel ();
340 AddLoop (oursp, 0, ExitLab, 0, 0);
342 /* Setup some variables needed in the loop below */
343 Flags = TypeOf (eval->e_tptr) | CF_CONST | CF_FORCECHAR;
344 CodeLab = NextLab = 0;
348 /* Parse the labels */
350 while (CurTok.Tok != TOK_RCURLY) {
352 if (CurTok.Tok == TOK_CASE || CurTok.Tok == TOK_DEFAULT) {
354 /* If the code for the previous selector did not end with a
355 * break statement, we must jump over the next selector test.
358 /* Define a label for the code */
360 CodeLab = GetLocalLabel ();
365 /* If we have a cascade label, emit it */
367 g_defcodelabel (NextLab);
371 while (CurTok.Tok == TOK_CASE || CurTok.Tok == TOK_DEFAULT) {
373 /* Parse the selector */
374 if (CurTok.Tok == TOK_CASE) {
379 /* Skip the "case" token */
382 /* Read the selector expression */
384 if (!IsClassInt (lval.e_tptr)) {
385 Error ("Switch quantity not an integer");
388 /* Check the range of the expression */
390 switch (*eval->e_tptr) {
394 if (Val < -128 || Val > 127) {
395 Error ("Range error");
400 if (Val < 0 || Val > 255) {
401 Error ("Range error");
406 if (Val < -32768 || Val > 32767) {
407 Error ("Range error");
412 if (Val < 0 || Val > 65535) {
413 Error ("Range error");
418 Internal ("Invalid type: %02X", *eval->e_tptr & 0xFF);
424 /* If another case follows, we will jump to the code if
425 * the condition is true.
427 if (CurTok.Tok == TOK_CASE) {
428 /* Create a code label if needed */
430 CodeLab = GetLocalLabel ();
432 g_falsejump (CF_NONE, CodeLab);
433 } else if (CurTok.Tok != TOK_DEFAULT) {
434 /* No case follows, jump to next selector */
436 NextLab = GetLocalLabel ();
438 g_truejump (CF_NONE, NextLab);
449 /* Handle the pathologic case: DEFAULT followed by CASE */
450 if (CurTok.Tok == TOK_CASE) {
452 CodeLab = GetLocalLabel ();
460 /* Remember that we had a default label */
468 /* Emit a code label if we have one */
470 g_defcodelabel (CodeLab);
474 /* Parse statements */
475 if (CurTok.Tok != TOK_RCURLY) {
476 HaveBreak = Statement (0);
480 /* Check if we have any labels */
481 if (lcount == 0 && !HaveDefault) {
482 Warning ("No case labels");
485 /* Define the exit label and, if there's a next label left, create this
489 g_defcodelabel (NextLab);
491 g_defcodelabel (ExitLab);
493 /* Eat the closing curly brace */
502 static void TableSwitch (struct expent* eval)
503 /* Handle a switch statement via table based selector */
505 /* Entry for one case in a switch statement */
507 long sw_const; /* selector value */
508 unsigned sw_lab; /* label for this selector */
511 int dlabel; /* for default */
512 int lab; /* exit label */
513 int label; /* label for case */
514 int lcase; /* label for compares */
515 int lcount; /* Label count */
516 int HaveBreak; /* Last statement has a break */
517 int HaveDefault; /* Remember if we had a default label */
518 unsigned Flags; /* Code generator flags */
519 struct expent lval; /* Case label expression */
523 /* Allocate memory for the switch table */
524 swtab = xmalloc (CASE_MAX * sizeof (struct swent));
526 /* Create a look so we may break out, init labels */
527 HaveBreak = 0; /* Keep gcc silent */
528 HaveDefault = 0; /* No default case until now */
529 dlabel = 0; /* init */
530 lab = GetLocalLabel (); /* get exit */
532 AddLoop (oursp, 0, lab, 0, 0);
534 /* Jump behind the code for the CASE labels */
535 g_jump (lcase = GetLocalLabel ());
537 while (CurTok.Tok != TOK_RCURLY) {
538 if (CurTok.Tok == TOK_CASE || CurTok.Tok == TOK_DEFAULT) {
539 if (lcount >= CASE_MAX) {
540 Fatal ("Too many case labels");
542 label = GetLocalLabel ();
544 if (CurTok.Tok == TOK_CASE) {
547 if (!IsClassInt (lval.e_tptr)) {
548 Error ("Switch quantity not an integer");
550 p->sw_const = lval.e_const;
560 } while (CurTok.Tok == TOK_CASE || CurTok.Tok == TOK_DEFAULT);
561 g_defcodelabel (label);
564 if (CurTok.Tok != TOK_RCURLY) {
565 HaveBreak = Statement (0);
569 /* Check if we have any labels */
570 if (lcount == 0 && !HaveDefault) {
571 Warning ("No case labels");
574 /* Eat the closing curly brace */
577 /* If the last statement doesn't have a break or return, add one */
582 /* Actual selector code goes here */
583 g_defcodelabel (lcase);
585 /* Create the call to the switch subroutine */
586 Flags = TypeOf (eval->e_tptr);
589 /* First entry is negative of label count */
590 g_defdata (CF_INT | CF_CONST, -((int)lcount)-1, 0);
592 /* Create the case selector table */
595 g_case (Flags, p->sw_lab, p->sw_const); /* Create one label */
603 g_defcodelabel (lab);
606 /* Free the allocated space for the labels */
612 static void SwitchStatement (void)
613 /* Handle a 'switch' statement */
615 struct expent eval; /* Switch statement expression */
617 /* Eat the "switch" */
620 /* Read the switch expression */
625 /* result of expr is in P */
628 /* Now decide which sort of switch we will create: */
629 if (IsTypeChar (eval.e_tptr) || (CodeSizeFactor >= 200 && IsClassInt (eval.e_tptr))) {
630 CascadeSwitch (&eval);
638 static void ForStatement (void)
639 /* Handle a 'for' statement */
646 /* Get several local labels needed later */
647 unsigned TestLabel = GetLocalLabel ();
648 unsigned lab = GetLocalLabel ();
649 unsigned IncLabel = GetLocalLabel ();
650 unsigned lstat = GetLocalLabel ();
652 /* Skip the FOR token */
655 /* Add the loop to the loop stack */
656 AddLoop (oursp, TestLabel, lab, IncLabel, lstat);
658 /* Skip the opening paren */
661 /* Parse the initializer expression */
662 if (CurTok.Tok != TOK_SEMI) {
667 /* Label for the test expressions */
668 g_defcodelabel (TestLabel);
670 /* Parse the test expression */
671 if (CurTok.Tok != TOK_SEMI) {
673 g_truejump (CF_NONE, lstat);
680 /* Label for the increment expression */
681 g_defcodelabel (IncLabel);
683 /* Parse the increment expression */
684 if (CurTok.Tok != TOK_RPAREN) {
688 /* Jump to the test */
691 /* Skip the closing paren */
695 g_defcodelabel (lstat);
696 Statement (&PendingToken);
698 /* Jump back to the increment expression */
701 /* Skip a pending token if we have one */
702 SkipPending (PendingToken);
704 /* Declare the break label */
705 g_defcodelabel (lab);
707 /* Remove the loop from the loop stack */
713 static int CompoundStatement (void)
714 /* Compound statement. Allow any number of statements inside braces. The
715 * function returns true if the last statement was a break or return.
720 /* Remember the stack at block entry */
721 int OldStack = oursp;
723 /* Enter a new lexical level */
726 /* Parse local variable declarations if any */
729 /* Now process statements in this block */
731 while (CurTok.Tok != TOK_RCURLY) {
732 if (CurTok.Tok != TOK_CEOF) {
733 GotBreak = Statement (0);
739 /* Clean up the stack. */
741 g_space (oursp - OldStack);
745 /* Emit references to imports/exports for this block */
748 /* Leave the lexical level */
756 int Statement (int* PendingToken)
757 /* Statement parser. Returns 1 if the statement does a return/break, returns
758 * 0 otherwise. If the PendingToken pointer is not NULL, the function will
759 * not skip the terminating token of the statement (closing brace or
760 * semicolon), but store true if there is a pending token, and false if there
761 * is none. The token is always checked, so there is no need for the caller to
762 * check this token, it must be skipped, however. If the argument pointer is
763 * NULL, the function will skip the token.
769 /* Assume no pending token */
774 /* Check for a label */
775 if (CurTok.Tok == TOK_IDENT && NextTok.Tok == TOK_COLON) {
777 /* Special handling for a label */
782 switch (CurTok.Tok) {
786 GotBreak = CompoundStatement ();
787 CheckTok (TOK_RCURLY, "`{' expected", PendingToken);
791 return IfStatement ();
807 CheckSemi (PendingToken);
812 CheckSemi (PendingToken);
816 ContinueStatement ();
817 CheckSemi (PendingToken);
826 CheckSemi (PendingToken);
839 /* Actual statement */
841 CheckSemi (PendingToken);