]> git.sur5r.net Git - cc65/blob - src/cc65/stmt.c
Bugfix
[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 /*                                 Forwards                                  */
50 /*****************************************************************************/
51
52
53
54 /*****************************************************************************/
55 /*                                   Code                                    */
56 /*****************************************************************************/
57
58
59
60 static int IfStatement (void)
61 /* Handle an 'if' statement */
62 {
63     unsigned Label1;
64     int GotBreak;
65
66     /* Skip the if */
67     NextToken ();
68
69     /* Generate a jump label and parse the condition */
70     Label1 = GetLocalLabel ();
71     test (Label1, 0);
72
73     /* Parse the if body */
74     GotBreak = Statement ();
75
76     /* Else clause present? */
77     if (CurTok.Tok != TOK_ELSE) {
78
79         g_defcodelabel (Label1);
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         /* Generate a jump around the else branch */
88         unsigned Label2 = GetLocalLabel ();
89         g_jump (Label2);
90
91         /* Skip the else */
92         NextToken ();
93
94         /* Define the target for the first test */
95         g_defcodelabel (Label1);
96
97         /* Total break only if both branches had a break. */
98         GotBreak &= Statement ();
99
100         /* Generate the label for the else clause */
101         g_defcodelabel (Label2);
102
103         /* Done */
104         return GotBreak;
105     }
106 }
107
108
109
110 static void DoStatement (void)
111 /* Handle the 'do' statement */
112 {
113     /* Get the loop control labels */
114     unsigned loop = GetLocalLabel ();
115     unsigned lab = GetLocalLabel ();
116
117     /* Skip the while token */
118     NextToken ();
119
120     /* Add the loop to the loop stack */
121     AddLoop (oursp, loop, lab, 0, 0);
122
123     /* Define the head label */
124     g_defcodelabel (loop);
125
126     /* Parse the loop body */
127     Statement ();
128
129     /* Parse the end condition */
130     Consume (TOK_WHILE, "`while' expected");
131     test (loop, 1);
132     ConsumeSemi ();
133
134     /* Define the break label */
135     g_defcodelabel (lab);
136
137     /* Remove the loop from the loop stack */
138     DelLoop ();
139 }
140
141
142
143 static void WhileStatement (void)
144 /* Handle the 'while' statement */
145 {
146     /* Get the loop control labels */
147     unsigned loop = GetLocalLabel ();
148     unsigned lab = GetLocalLabel ();
149
150     /* Skip the while token */
151     NextToken ();
152
153     /* Add the loop to the loop stack */
154     AddLoop (oursp, loop, lab, 0, 0);
155
156     /* Define the head label */
157     g_defcodelabel (loop);
158
159     /* Test the loop condition */
160     test (lab, 0);
161
162     /* If the statement following the while loop is empty, that is, we have
163      * something like "while (1) ;", the test function ommitted the jump as
164      * an optimization. Since we know, the condition codes are set, we can
165      * do another small optimization here, and use a conditional jump
166      * instead an absolute one.
167      */
168     if (CurTok.Tok == TOK_SEMI) {
169         /* Use a conditional jump */
170         g_truejump (CF_NONE, loop);
171         /* Shortcut */
172         NextToken ();
173     } else {
174         /* There is code inside the while loop, parse the body */
175         Statement ();
176         g_jump (loop);
177         g_defcodelabel (lab);
178     }
179
180     /* Remove the loop from the loop stack */
181     DelLoop ();
182 }
183
184
185
186 static void ReturnStatement (void)
187 /* Handle the 'return' statement */
188 {
189     struct expent lval;
190
191     NextToken ();
192     if (CurTok.Tok != TOK_SEMI) {
193         if (HasVoidReturn (CurrentFunc)) {
194             Error ("Returning a value in function with return type void");
195         }
196
197         /* Evaluate the return expression. Result will be in primary */
198         expression (&lval);
199
200         /* Convert the return value to the type of the function result */
201         if (!HasVoidReturn (CurrentFunc)) {
202             assignadjust (GetReturnType (CurrentFunc), &lval);
203         }
204     } else if (!HasVoidReturn (CurrentFunc)) {
205         Error ("Function `%s' must return a value", GetFuncName (CurrentFunc));
206     }
207
208     /* Cleanup the stack in case we're inside a block with locals */
209     g_space (oursp - GetTopLevelSP (CurrentFunc));
210
211     /* Output a jump to the function exit code */
212     g_jump (GetRetLab (CurrentFunc));
213 }
214
215
216
217 static void BreakStatement (void)
218 /* Handle the 'break' statement */
219 {
220     LoopDesc* L;
221
222     /* Skip the break */
223     NextToken ();
224
225     /* Get the current loop descriptor */
226     L = CurrentLoop ();
227
228     /* Check if we are inside a loop */
229     if (L == 0) {
230         /* Error: No current loop */
231         Error ("`break' statement not within loop or switch");
232         return;
233     }
234
235     /* Correct the stack pointer if needed */
236     g_space (oursp - L->StackPtr);
237
238     /* Jump to the exit label of the loop */
239     g_jump (L->Label);
240 }
241
242
243
244 static void ContinueStatement (void)
245 /* Handle the 'continue' statement */
246 {
247     LoopDesc* L;
248
249     /* Skip the continue */
250     NextToken ();
251
252     /* Get the current loop descriptor */
253     L = CurrentLoop ();
254     if (L) {
255         /* Search for the correct loop */
256         do {
257             if (L->Loop) {
258                 break;
259             }
260             L = L->Next;
261         } while (L);
262     }
263
264     /* Did we find it? */
265     if (L == 0) {
266         Error ("`continue' statement not within a loop");
267         return;
268     }
269
270     /* Correct the stackpointer if needed */
271     g_space (oursp - L->StackPtr);
272
273     /* Output the loop code */
274     if (L->linc) {
275         g_jump (L->linc);
276     } else {
277         g_jump (L->Loop);
278     }
279 }
280
281
282
283 static void CascadeSwitch (struct expent* eval)
284 /* Handle a switch statement for chars with a cmp cascade for the selector */
285 {
286     unsigned ExitLab;           /* Exit label */
287     unsigned NextLab;           /* Next case label */
288     unsigned CodeLab;           /* Label that starts the actual selector code */
289     int HaveBreak;              /* Remember if we exited with break */
290     int HaveDefault;            /* Remember if we had a default label */
291     int lcount;                 /* Label count */
292     unsigned Flags;             /* Code generator flags */
293     struct expent lval;         /* Case label expression */
294     long Val;                   /* Case label value */
295
296
297     /* Create a loop so we may break out, init labels */
298     ExitLab = GetLocalLabel ();
299     AddLoop (oursp, 0, ExitLab, 0, 0);
300
301     /* Setup some variables needed in the loop  below */
302     Flags = TypeOf (eval->e_tptr) | CF_CONST | CF_FORCECHAR;
303     CodeLab = NextLab = 0;
304     HaveBreak = 1;
305     HaveDefault = 0;
306
307     /* Parse the labels */
308     lcount = 0;
309     while (CurTok.Tok != TOK_RCURLY) {
310
311         if (CurTok.Tok == TOK_CASE || CurTok.Tok == TOK_DEFAULT) {
312
313             /* If the code for the previous selector did not end with a
314              * break statement, we must jump over the next selector test.
315              */
316             if (!HaveBreak) {
317                 /* Define a label for the code */
318                 if (CodeLab == 0) {
319                     CodeLab = GetLocalLabel ();
320                 }
321                 g_jump (CodeLab);
322             }
323
324             /* If we have a cascade label, emit it */
325             if (NextLab) {
326                 g_defcodelabel (NextLab);
327                 NextLab = 0;
328             }
329
330             while (CurTok.Tok == TOK_CASE || CurTok.Tok == TOK_DEFAULT) {
331
332                 /* Parse the selector */
333                 if (CurTok.Tok == TOK_CASE) {
334
335                     /* Count labels */
336                     ++lcount;
337
338                     /* Skip the "case" token */
339                     NextToken ();
340
341                     /* Read the selector expression */
342                     constexpr (&lval);
343                     if (!IsClassInt (lval.e_tptr)) {
344                         Error ("Switch quantity not an integer");
345                     }
346
347                     /* Check the range of the expression */
348                     Val = lval.e_const;
349                     switch (*eval->e_tptr) {
350
351                         case T_SCHAR:
352                             /* Signed char */
353                             if (Val < -128 || Val > 127) {
354                                 Error ("Range error");
355                             }
356                             break;
357
358                         case T_UCHAR:
359                             if (Val < 0 || Val > 255) {
360                                 Error ("Range error");
361                             }
362                             break;
363
364                         case T_INT:
365                             if (Val < -32768 || Val > 32767) {
366                                 Error ("Range error");
367                             }
368                             break;
369
370                         case T_UINT:
371                             if (Val < 0 || Val > 65535) {
372                                 Error ("Range error");
373                             }
374                             break;
375
376                         default:
377                             Internal ("Invalid type: %02X", *eval->e_tptr & 0xFF);
378                     }
379
380                     /* Emit a compare */
381                     g_cmp (Flags, Val);
382
383                     /* If another case follows, we will jump to the code if
384                      * the condition is true.
385                      */
386                     if (CurTok.Tok == TOK_CASE) {
387                         /* Create a code label if needed */
388                         if (CodeLab == 0) {
389                             CodeLab = GetLocalLabel ();
390                         }
391                         g_falsejump (CF_NONE, CodeLab);
392                     } else if (CurTok.Tok != TOK_DEFAULT) {
393                         /* No case follows, jump to next selector */
394                         if (NextLab == 0) {
395                             NextLab = GetLocalLabel ();
396                         }
397                         g_truejump (CF_NONE, NextLab);
398                     }
399
400                     /* Skip the colon */
401                     ConsumeColon ();
402
403                 } else {
404
405                     /* Default case */
406                     NextToken ();
407
408                     /* Handle the pathologic case: DEFAULT followed by CASE */
409                     if (CurTok.Tok == TOK_CASE) {
410                         if (CodeLab == 0) {
411                             CodeLab = GetLocalLabel ();
412                         }
413                         g_jump (CodeLab);
414                     }
415
416                     /* Skip the colon */
417                     ConsumeColon ();
418
419                     /* Remember that we had a default label */
420                     HaveDefault = 1;
421                 }
422
423             }
424
425         }
426
427         /* Emit a code label if we have one */
428         if (CodeLab) {
429             g_defcodelabel (CodeLab);
430             CodeLab = 0;
431         }
432
433         /* Parse statements */
434         if (CurTok.Tok != TOK_RCURLY) {
435             HaveBreak = Statement ();
436         }
437     }
438
439     /* Check if we have any labels */
440     if (lcount == 0 && !HaveDefault) {
441         Warning ("No case labels");
442     }
443
444     /* Define the exit label and, if there's a next label left, create this
445      * one, too.
446      */
447     if (NextLab) {
448         g_defcodelabel (NextLab);
449     }
450     g_defcodelabel (ExitLab);
451
452     /* Eat the closing curly brace */
453     NextToken ();
454
455     /* End the loop */
456     DelLoop ();
457 }
458
459
460
461 static void TableSwitch (struct expent* eval)
462 /* Handle a switch statement via table based selector */
463 {
464     /* Entry for one case in a switch statement */
465     struct swent {
466         long     sw_const;      /* selector value */
467         unsigned sw_lab;        /* label for this selector */
468     };
469
470     int dlabel;                 /* for default */
471     int lab;                    /* exit label */
472     int label;                  /* label for case */
473     int lcase;                  /* label for compares */
474     int lcount;                 /* Label count */
475     int HaveBreak;              /* Last statement has a break */
476     int HaveDefault;            /* Remember if we had a default label */
477     unsigned Flags;             /* Code generator flags */
478     struct expent lval;         /* Case label expression */
479     struct swent *p;
480     struct swent *swtab;
481
482     /* Allocate memory for the switch table */
483     swtab = xmalloc (CASE_MAX * sizeof (struct swent));
484
485     /* Create a look so we may break out, init labels */
486     HaveBreak = 0;              /* Keep gcc silent */
487     HaveDefault = 0;            /* No default case until now */
488     dlabel = 0;                 /* init */
489     lab = GetLocalLabel ();     /* get exit */
490     p = swtab;
491     AddLoop (oursp, 0, lab, 0, 0);
492
493     /* Jump behind the code for the CASE labels */
494     g_jump (lcase = GetLocalLabel ());
495     lcount = 0;
496     while (CurTok.Tok != TOK_RCURLY) {
497         if (CurTok.Tok == TOK_CASE || CurTok.Tok == TOK_DEFAULT) {
498             if (lcount >= CASE_MAX) {
499                 Fatal ("Too many case labels");
500             }
501             label = GetLocalLabel ();
502             do {
503                 if (CurTok.Tok == TOK_CASE) {
504                     NextToken ();
505                     constexpr (&lval);
506                     if (!IsClassInt (lval.e_tptr)) {
507                         Error ("Switch quantity not an integer");
508                     }
509                     p->sw_const = lval.e_const;
510                     p->sw_lab = label;
511                     ++p;
512                     ++lcount;
513                 } else {
514                     NextToken ();
515                     dlabel = label;
516                     HaveDefault = 1;
517                 }
518                 ConsumeColon ();
519             } while (CurTok.Tok == TOK_CASE || CurTok.Tok == TOK_DEFAULT);
520             g_defcodelabel (label);
521             HaveBreak = 0;
522         }
523         if (CurTok.Tok != TOK_RCURLY) {
524             HaveBreak = Statement ();
525         }
526     }
527
528     /* Check if we have any labels */
529     if (lcount == 0 && !HaveDefault) {
530         Warning ("No case labels");
531     }
532
533     /* Eat the closing curly brace */
534     NextToken ();
535
536     /* If the last statement doesn't have a break or return, add one */
537     if (!HaveBreak) {
538         g_jump (lab);
539     }
540
541     /* Actual selector code goes here */
542     g_defcodelabel (lcase);
543
544     /* Create the call to the switch subroutine */
545     Flags = TypeOf (eval->e_tptr);
546     g_switch (Flags);
547
548     /* First entry is negative of label count */
549     g_defdata (CF_INT | CF_CONST, -((int)lcount)-1, 0);
550
551     /* Create the case selector table */
552     p = swtab;
553     while (lcount) {
554         g_case (Flags, p->sw_lab, p->sw_const); /* Create one label */
555         --lcount;
556         ++p;
557     }
558
559     if (dlabel) {
560         g_jump (dlabel);
561     }
562     g_defcodelabel (lab);
563     DelLoop ();
564
565     /* Free the allocated space for the labels */
566     xfree (swtab);
567 }
568
569
570
571 static void SwitchStatement (void)
572 /* Handle a 'switch' statement */
573 {
574     struct expent eval;         /* Switch statement expression */
575
576     /* Eat the "switch" */
577     NextToken ();
578
579     /* Read the switch expression */
580     ConsumeLParen ();
581     intexpr (&eval);
582     ConsumeRParen ();
583
584     /* result of expr is in P */
585     ConsumeLCurly ();
586
587     /* Now decide which sort of switch we will create: */
588     if (IsTypeChar (eval.e_tptr) || (CodeSizeFactor >= 200 && IsClassInt (eval.e_tptr))) {
589         CascadeSwitch (&eval);
590     } else {
591         TableSwitch (&eval);
592     }
593 }
594
595
596
597 static void ForStatement (void)
598 /* Handle a 'for' statement */
599 {
600     struct expent lval1;
601     struct expent lval2;
602     struct expent lval3;
603
604     /* Get several local labels needed later */
605     unsigned TestLabel = GetLocalLabel ();
606     unsigned lab       = GetLocalLabel ();
607     unsigned IncLabel  = GetLocalLabel ();
608     unsigned lstat     = GetLocalLabel ();
609
610     /* Skip the FOR token */
611     NextToken ();
612
613     /* Add the loop to the loop stack */
614     AddLoop (oursp, TestLabel, lab, IncLabel, lstat);
615
616     /* Skip the opening paren */
617     ConsumeLParen ();
618
619     /* Parse the initializer expression */
620     if (CurTok.Tok != TOK_SEMI) {
621         expression (&lval1);
622     }
623     ConsumeSemi ();
624
625     /* Label for the test expressions */
626     g_defcodelabel (TestLabel);
627
628     /* Parse the text expression */
629     if (CurTok.Tok != TOK_SEMI) {
630         boolexpr (&lval2);
631         g_truejump (CF_NONE, lstat);
632         g_jump (lab);
633     } else {
634         g_jump (lstat);
635     }
636     ConsumeSemi ();
637
638     /* Label for the increment expression */
639     g_defcodelabel (IncLabel);
640
641     /* Parse the increment expression */
642     if (CurTok.Tok != TOK_RPAREN) {
643         expression (&lval3);
644     }
645
646     /* Jump to the test */
647     g_jump (TestLabel);
648
649     /* Skip the closing paren */
650     ConsumeRParen ();
651
652     /* Loop body */
653     g_defcodelabel (lstat);
654     Statement ();
655
656     /* Jump back to the increment expression */
657     g_jump (IncLabel);
658
659     /* Declare the break label */
660     g_defcodelabel (lab);
661
662     /* Remove the loop from the loop stack */
663     DelLoop ();
664 }
665
666
667
668 static int CompoundStatement (void)
669 /* Compound statement. Allow any number of statements inside braces. The
670  * function returns true if the last statement was a break or return.
671  */
672 {
673     int GotBreak;
674
675     /* Remember the stack at block entry */
676     int OldStack = oursp;
677
678     /* Enter a new lexical level */
679     EnterBlockLevel ();
680
681     /* Skip the rcurly */
682     NextToken ();
683
684     /* Parse local variable declarations if any */
685     DeclareLocals ();
686
687     /* Now process statements in this block */
688     GotBreak = 0;
689     while (CurTok.Tok != TOK_RCURLY) {
690         if (CurTok.Tok != TOK_CEOF) {
691             GotBreak = Statement ();
692         } else {
693             break;
694         }
695     }
696
697     /* Clean up the stack. */
698     if (!GotBreak) {
699         g_space (oursp - OldStack);
700     }
701     oursp = OldStack;
702
703     /* Skip the closing brace */
704     ConsumeRCurly ();
705
706     /* Emit references to imports/exports for this block */
707     EmitExternals ();
708
709     /* Leave the lexical level */
710     LeaveBlockLevel ();
711
712     return GotBreak;
713 }
714
715
716
717 int Statement (void)
718 /* Statement parser. Returns 1 if the statement does a return/break, returns
719  * 0 otherwise
720  */
721 {
722     struct expent lval;
723
724     /* Check for a label */
725     if (CurTok.Tok == TOK_IDENT && NextTok.Tok == TOK_COLON) {
726
727         /* Special handling for a label */
728         DoLabel ();
729
730     } else {
731
732         switch (CurTok.Tok) {
733
734             case TOK_LCURLY:
735                 return CompoundStatement ();
736
737             case TOK_IF:
738                 return IfStatement ();
739
740             case TOK_WHILE:
741                 WhileStatement ();
742                 break;
743
744             case TOK_DO:
745                 DoStatement ();
746                 break;
747
748             case TOK_SWITCH:
749                 SwitchStatement ();
750                 break;
751
752             case TOK_RETURN:
753                 ReturnStatement ();
754                 ConsumeSemi ();
755                 return 1;
756
757             case TOK_BREAK:
758                 BreakStatement ();
759                 ConsumeSemi ();
760                 return 1;
761
762             case TOK_CONTINUE:
763                 ContinueStatement ();
764                 ConsumeSemi ();
765                 return 1;
766
767             case TOK_FOR:
768                 ForStatement ();
769                 break;
770
771             case TOK_GOTO:
772                 GotoStatement ();
773                 ConsumeSemi ();
774                 return 1;
775
776             case TOK_SEMI:
777                 /* Ignore it */
778                 NextToken ();
779                 break;
780
781             case TOK_PRAGMA:
782                 DoPragma ();
783                 break;
784
785             default:
786                 /* Actual statement */
787                 expression (&lval);
788                 ConsumeSemi ();
789         }
790     }
791     return 0;
792 }
793
794
795