]> git.sur5r.net Git - cc65/blob - src/cc65/stmt.c
Changed TgtTranslateBuf
[cc65] / src / cc65 / stmt.c
1 /*
2  * stmt.c
3  *
4  * Ullrich von Bassewitz, 06.08.1998
5  *
6  * Original by John R. Dunning - see copyleft.jrd
7  */
8
9
10
11 #include <stdio.h>
12 #include <string.h>
13
14 /* common */
15 #include "xmalloc.h"
16
17 /* cc65 */
18 #include "asmcode.h"
19 #include "asmlabel.h"
20 #include "codegen.h"
21 #include "datatype.h"
22 #include "error.h"
23 #include "expr.h"
24 #include "function.h"
25 #include "global.h"
26 #include "goto.h"
27 #include "litpool.h"
28 #include "locals.h"
29 #include "loop.h"
30 #include "pragma.h"
31 #include "scanner.h"
32 #include "symtab.h"
33 #include "stmt.h"
34
35
36
37 /*****************************************************************************/
38 /*                                   Data                                    */
39 /*****************************************************************************/
40
41
42
43 /* Maximum count of cases */
44 #define CASE_MAX        257
45
46
47
48 /*****************************************************************************/
49 /*                                   Code                                    */
50 /*****************************************************************************/
51
52
53
54 static int statement (void);
55 /* Forward decl */
56
57
58
59 static int doif (void)
60 /* Handle 'if' statement here */
61 {
62     int flab1;
63     int flab2;
64     int gotbreak;
65
66     /* Skip the if */
67     NextToken ();
68
69     /* Generate a jump label and parse the condition */
70     flab1 = GetLabel ();
71     test (flab1, 0);
72
73     /* Parse the if body */
74     gotbreak = statement ();
75
76     /* Else clause present? */
77     if (curtok != TOK_ELSE) {
78
79         g_defloclabel (flab1);
80         /* Since there's no else clause, we're not sure, if the a break
81          * statement is really executed.
82          */
83         return 0;
84
85     } else {
86
87         /* Skip the else */
88         NextToken ();
89
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.
93          */
94         if (!gotbreak) {
95             flab2 = GetLabel ();
96             g_jump (flab2);
97         } else {
98             /* Mark the label as unused */
99             flab2 = 0;
100         }
101         g_defloclabel (flab1);
102         gotbreak &= statement ();
103
104         /* Generate the label for the else clause */
105         if (flab2) {
106             g_defloclabel (flab2);
107         }
108
109         /* Done */
110         return gotbreak;
111     }
112 }
113
114
115
116 static void dowhile (char wtype)
117 /* Handle 'while' statement here */
118 {
119     int loop;
120     int lab;
121
122     NextToken ();
123     loop = GetLabel ();
124     lab = GetLabel ();
125     AddLoop (oursp, loop, lab, 0, 0);
126     g_defloclabel (loop);
127     if (wtype == 'w') {
128
129         /* While loop */
130         test (lab, 0);
131
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.
137          */
138         if (curtok == TOK_SEMI) {
139             /* Shortcut */
140             NextToken ();
141             /* Use a conditional jump */
142             g_truejump (CF_NONE, loop);
143         } else {
144             /* There is code inside the while loop */
145             statement ();
146             g_jump (loop);
147             g_defloclabel (lab);
148         }
149
150     } else {
151
152         /* Do loop */
153         statement ();
154         Consume (TOK_WHILE, "`while' expected");
155         test (loop, 1);
156         ConsumeSemi ();
157         g_defloclabel (lab);
158
159     }
160     DelLoop ();
161 }
162
163
164
165 static void doreturn (void)
166 /* Handle 'return' statement here */
167 {
168     struct expent lval;
169     unsigned Flags = 0;         /* Code generator flags */
170     int HaveVal = 0;            /* Do we have a return value in ax? */
171
172
173     NextToken ();
174     if (curtok != TOK_SEMI) {
175         if (HasVoidReturn (CurrentFunc)) {
176             Error ("Returning a value in function with return type void");
177         }
178         if (evalexpr (CF_NONE, hie0, &lval) == 0) {
179             /* Constant value */
180             Flags = CF_CONST;
181         } else {
182             /* Value in the primary register */
183             HaveVal = 1;
184         }
185
186         /* Convert the return value to the type of the function result */
187         if (!HasVoidReturn (CurrentFunc)) {
188             Flags |= (assignadjust (GetReturnType (CurrentFunc), &lval) & ~CF_CONST) | CF_REG;
189         }
190     } else if (!HasVoidReturn (CurrentFunc)) {
191         Error ("Function `%s' must return a value", GetFuncName (CurrentFunc));
192     }
193     RestoreRegVars (HaveVal);
194     g_leave (Flags, lval.e_const);
195 }
196
197
198
199 static void dobreak (void)
200 /* Handle 'break' statement here */
201 {
202     LoopDesc* L;
203
204     /* Skip the break */
205     NextToken ();
206
207     /* Get the current loop descriptor */
208     L = CurrentLoop ();
209
210     /* Check if we are inside a loop */
211     if (L == 0) {
212         /* Error: No current loop */
213         Error ("`break' statement not within loop or switch");
214         return;
215     }
216
217     /* Correct the stack pointer if needed */
218     g_space (oursp - L->StackPtr);
219
220     /* Jump to the exit label of the loop */
221     g_jump (L->Label);
222 }
223
224
225
226 static void docontinue (void)
227 /* Handle 'continue' statement here */
228 {
229     LoopDesc* L;
230
231     /* Skip the continue */
232     NextToken ();
233
234     /* Get the current loop descriptor */
235     L = CurrentLoop ();
236     if (L) {
237         /* Search for the correct loop */
238         do {
239             if (L->Loop) {
240                 break;
241             }
242             L = L->Next;
243         } while (L);
244     }
245
246     /* Did we find it? */
247     if (L == 0) {
248         Error ("`continue' statement not within a loop");
249         return;
250     }
251
252     /* Correct the stackpointer if needed */
253     g_space (oursp - L->StackPtr);
254
255     /* Output the loop code */
256     if (L->linc) {
257         g_jump (L->linc);
258     } else {
259         g_jump (L->Loop);
260     }
261 }
262
263
264
265 static void cascadeswitch (struct expent* eval)
266 /* Handle a switch statement for chars with a cmp cascade for the selector */
267 {
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 */
277
278
279     /* Create a loop so we may break out, init labels */
280     ExitLab = GetLabel ();
281     AddLoop (oursp, 0, ExitLab, 0, 0);
282
283     /* Setup some variables needed in the loop  below */
284     Flags = TypeOf (eval->e_tptr) | CF_CONST | CF_FORCECHAR;
285     CodeLab = NextLab = 0;
286     HaveBreak = 1;
287     HaveDefault = 0;
288
289     /* Parse the labels */
290     lcount = 0;
291     while (curtok != TOK_RCURLY) {
292
293         if (curtok == TOK_CASE || curtok == TOK_DEFAULT) {
294
295             /* If the code for the previous selector did not end with a
296              * break statement, we must jump over the next selector test.
297              */
298             if (!HaveBreak) {
299                 /* Define a label for the code */
300                 if (CodeLab == 0) {
301                     CodeLab = GetLabel ();
302                 }
303                 g_jump (CodeLab);
304             }
305
306             /* If we have a cascade label, emit it */
307             if (NextLab) {
308                 g_defloclabel (NextLab);
309                 NextLab = 0;
310             }
311
312             while (curtok == TOK_CASE || curtok == TOK_DEFAULT) {
313
314                 /* Parse the selector */
315                 if (curtok == TOK_CASE) {
316
317                     /* Count labels */
318                     ++lcount;
319
320                     /* Skip the "case" token */
321                     NextToken ();
322
323                     /* Read the selector expression */
324                     constexpr (&lval);
325                     if (!IsClassInt (lval.e_tptr)) {
326                         Error ("Switch quantity not an integer");
327                     }
328
329                     /* Check the range of the expression */
330                     Val = lval.e_const;
331                     switch (*eval->e_tptr) {
332
333                         case T_SCHAR:
334                             /* Signed char */
335                             if (Val < -128 || Val > 127) {
336                                 Error ("Range error");
337                             }
338                             break;
339
340                         case T_UCHAR:
341                             if (Val < 0 || Val > 255) {
342                                 Error ("Range error");
343                             }
344                             break;
345
346                         case T_INT:
347                             if (Val < -32768 || Val > 32767) {
348                                 Error ("Range error");
349                             }
350                             break;
351
352                         case T_UINT:
353                             if (Val < 0 || Val > 65535) {
354                                 Error ("Range error");
355                             }
356                             break;
357
358                         default:
359                             Internal ("Invalid type: %02X", *eval->e_tptr & 0xFF);
360                     }
361
362                     /* Skip the colon */
363                     ConsumeColon ();
364
365                     /* Emit a compare */
366                     g_cmp (Flags, Val);
367
368                     /* If another case follows, we will jump to the code if
369                      * the condition is true.
370                      */
371                     if (curtok == TOK_CASE) {
372                         /* Create a code label if needed */
373                         if (CodeLab == 0) {
374                             CodeLab = GetLabel ();
375                         }
376                         g_falsejump (CF_NONE, CodeLab);
377                     } else if (curtok != TOK_DEFAULT) {
378                         /* No case follows, jump to next selector */
379                         if (NextLab == 0) {
380                             NextLab = GetLabel ();
381                         }
382                         g_truejump (CF_NONE, NextLab);
383                     }
384
385                 } else {
386
387                     /* Default case */
388                     NextToken ();
389
390                     /* Skip the colon */
391                     ConsumeColon ();
392
393                     /* Handle the pathologic case: DEFAULT followed by CASE */
394                     if (curtok == TOK_CASE) {
395                         if (CodeLab == 0) {
396                             CodeLab = GetLabel ();
397                         }
398                         g_jump (CodeLab);
399                     }
400
401                     /* Remember that we had a default label */
402                     HaveDefault = 1;
403                 }
404
405             }
406
407         }
408
409         /* Emit a code label if we have one */
410         if (CodeLab) {
411             g_defloclabel (CodeLab);
412             CodeLab = 0;
413         }
414
415         /* Parse statements */
416         if (curtok != TOK_RCURLY) {
417             HaveBreak = statement ();
418         }
419     }
420
421     /* Check if we have any labels */
422     if (lcount == 0 && !HaveDefault) {
423         Warning ("No case labels");
424     }
425
426     /* Eat the closing curly brace */
427     NextToken ();
428
429     /* Define the exit label and, if there's a next label left, create this
430      * one, too.
431      */
432     if (NextLab) {
433         g_defloclabel (NextLab);
434     }
435     g_defloclabel (ExitLab);
436
437     /* End the loop */
438     DelLoop ();
439 }
440
441
442
443 static void tableswitch (struct expent* eval)
444 /* Handle a switch statement via table based selector */
445 {
446     /* Entry for one case in a switch statement */
447     struct swent {
448         long     sw_const;      /* selector value */
449         unsigned sw_lab;        /* label for this selector */
450     };
451
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 */
461     struct swent *p;
462     struct swent *swtab;
463
464     /* Allocate memory for the switch table */
465     swtab = xmalloc (CASE_MAX * sizeof (struct swent));
466
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 */
472     p = swtab;
473     AddLoop (oursp, 0, lab, 0, 0);
474
475     /* Jump behind the code for the CASE labels */
476     g_jump (lcase = GetLabel ());
477     lcount = 0;
478     while (curtok != TOK_RCURLY) {
479         if (curtok == TOK_CASE || curtok == TOK_DEFAULT) {
480             if (lcount >= CASE_MAX) {
481                 Fatal ("Too many case labels");
482             }
483             label = GetLabel ();
484             do {
485                 if (curtok == TOK_CASE) {
486                     NextToken ();
487                     constexpr (&lval);
488                     if (!IsClassInt (lval.e_tptr)) {
489                         Error ("Switch quantity not an integer");
490                     }
491                     p->sw_const = lval.e_const;
492                     p->sw_lab = label;
493                     ++p;
494                     ++lcount;
495                 } else {
496                     NextToken ();
497                     dlabel = label;
498                     HaveDefault = 1;
499                 }
500                 ConsumeColon ();
501             } while (curtok == TOK_CASE || curtok == TOK_DEFAULT);
502             g_defloclabel (label);
503             HaveBreak = 0;
504         }
505         if (curtok != TOK_RCURLY) {
506             HaveBreak = statement ();
507         }
508     }
509
510     /* Check if we have any labels */
511     if (lcount == 0 && !HaveDefault) {
512         Warning ("No case labels");
513     }
514
515     /* Eat the closing curly brace */
516     NextToken ();
517
518     /* If the last statement doesn't have a break or return, add one */
519     if (!HaveBreak) {
520         g_jump (lab);
521     }
522
523     /* Actual selector code goes here */
524     g_defloclabel (lcase);
525
526     /* Create the call to the switch subroutine */
527     Flags = TypeOf (eval->e_tptr);
528     g_switch (Flags);
529
530     /* First entry is negative of label count */
531     g_defdata (CF_INT | CF_CONST, -((int)lcount)-1, 0);
532
533     /* Create the case selector table */
534     AddCodeHint ("casetable");
535     p = swtab;
536     while (lcount) {
537         g_case (Flags, p->sw_lab, p->sw_const); /* Create one label */
538         --lcount;
539         ++p;
540     }
541
542     if (dlabel) {
543         g_jump (dlabel);
544     }
545     g_defloclabel (lab);
546     DelLoop ();
547
548     /* Free the allocated space for the labels */
549     xfree (swtab);
550 }
551
552
553
554 static void doswitch (void)
555 /* Handle 'switch' statement here */
556 {
557     struct expent eval;         /* Switch statement expression */
558
559     /* Eat the "switch" */
560     NextToken ();
561
562     /* Read the switch expression */
563     ConsumeLParen ();
564     intexpr (&eval);
565     ConsumeRParen ();
566
567     /* result of expr is in P */
568     ConsumeLCurly ();
569
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);
573     } else {
574         tableswitch (&eval);
575     }
576 }
577
578
579
580 static void dofor (void)
581 /* Handle 'for' statement here */
582 {
583     int loop;
584     int lab;
585     int linc;
586     int lstat;
587     struct expent lval1;
588     struct expent lval2;
589     struct expent lval3;
590
591     NextToken ();
592     loop = GetLabel ();
593     lab = GetLabel ();
594     linc = GetLabel ();
595     lstat = GetLabel ();
596     AddLoop (oursp, loop, lab, linc, lstat);
597     ConsumeLParen ();
598     if (curtok != TOK_SEMI) {   /* exp1 */
599         expression (&lval1);
600     }
601     ConsumeSemi ();
602     g_defloclabel (loop);
603     if (curtok != TOK_SEMI) {   /* exp2 */
604         boolexpr (&lval2);
605         g_truejump (CF_NONE, lstat);
606         g_jump (lab);
607     } else {
608         g_jump (lstat);
609     }
610     ConsumeSemi ();
611     g_defloclabel (linc);
612     if (curtok != TOK_RPAREN) { /* exp3 */
613         expression (&lval3);
614     }
615     ConsumeRParen ();
616     g_jump (loop);
617     g_defloclabel (lstat);
618     statement ();
619     g_jump (linc);
620     g_defloclabel (lab);
621     DelLoop ();
622 }
623
624
625
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,
629  * 0 otherwise
630  */
631 {
632     struct expent lval;
633
634     /* */
635     if (curtok == TOK_IDENT && nxttok == TOK_COLON) {
636
637         /* Special handling for a label */
638         DoLabel ();
639
640     } else {
641
642         switch (curtok) {
643
644             case TOK_LCURLY:
645                 return compound ();
646
647             case TOK_IF:
648                 return doif ();
649
650             case TOK_WHILE:
651                 dowhile ('w');
652                 break;
653
654             case TOK_DO:
655                 dowhile ('d');
656                 break;
657
658             case TOK_SWITCH:
659                 doswitch ();
660                 break;
661
662             case TOK_RETURN:
663                 doreturn ();
664                 ConsumeSemi ();
665                 return 1;
666
667             case TOK_BREAK:
668                 dobreak ();
669                 ConsumeSemi ();
670                 return 1;
671
672             case TOK_CONTINUE:
673                 docontinue ();
674                 ConsumeSemi ();
675                 return 1;
676
677             case TOK_FOR:
678                 dofor ();
679                 break;
680
681             case TOK_GOTO:
682                 DoGoto ();
683                 ConsumeSemi ();
684                 return 1;
685
686             case TOK_SEMI:
687                 /* ignore it. */
688                 NextToken ();
689                 break;
690
691             case TOK_PRAGMA:
692                 DoPragma ();
693                 break;
694
695             default:
696                 AddCodeHint ("stmt:start");
697                 expression (&lval);
698                 AddCodeHint ("stmt:end");
699                 ConsumeSemi ();
700         }
701     }
702     return 0;
703 }
704
705
706
707 int compound (void)
708 /* Compound statement.  Allow any number of statements, inside braces. */
709 {
710     static unsigned CurrentLevel = 0;
711
712     int isbrk;
713     int oldsp;
714
715     /* eat LCURLY */
716     NextToken ();
717
718     /* Remember the stack at block entry */
719     oldsp = oursp;
720
721     /* If we're not on function level, enter a new lexical level */
722     if (CurrentLevel++ > 0) {
723         /* A nested block */
724         EnterBlockLevel ();
725     }
726
727     /* Parse local variable declarations if any */
728     DeclareLocals ();
729
730     /* Now process statements in the function body */
731     isbrk = 0;
732     while (curtok != TOK_RCURLY) {
733         if (curtok == TOK_CEOF)
734             break;
735         else {
736             isbrk = statement ();
737         }
738     }
739
740     /* Emit references to imports/exports for this block */
741     EmitExternals ();
742
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.
745      */
746     if (--CurrentLevel != 0) {
747         /* Some sort of nested block */
748         LeaveBlockLevel ();
749         if (isbrk) {
750             oursp = oldsp;
751         } else {
752             g_space (oursp - oldsp);
753             oursp = oldsp;
754         }
755     }
756
757     /* Eat closing brace */
758     ConsumeRCurly ();
759
760     return isbrk;
761 }
762
763
764