C compiler from 211bsd.git commit 98921db
[ccom.git] / c02.c
1 /*
2  * C compiler
3  */
4
5 #include <string.h>
6 #include "c0.h"
7
8 /*
9  * Process a single external definition
10  */
11 void extdef() {
12         register int o;
13         int sclass, scflag;
14         struct nmlist typer;
15         register struct nmlist *ds;
16
17         if(((o=symbol())==EOFC) || o==SEMI)
18                 return;
19         peeksym = o;
20         sclass = 0;
21         blklev = 0;
22         if (getkeywords(&sclass, &typer)==0) {
23                 sclass = EXTERN;
24                 if (peeksym!=NAME)
25                         goto syntax;
26         }
27         scflag = 0;
28         if (sclass==DEFXTRN) {
29                 scflag++;
30                 sclass = EXTERN;
31         }
32         if (sclass!=EXTERN && sclass!=STATIC && sclass!=TYPEDEF)
33                 error("Illegal storage class");
34         do {
35                 defsym = 0;
36                 paraml = NULL;
37                 parame = NULL;
38                 if (sclass==TYPEDEF) {
39                         decl1(TYPEDEF, &typer, 0, (struct nmlist *)NULL);
40                         continue;
41                 }
42                 decl1(EXTERN, &typer, 0, (struct nmlist *)NULL);
43                 if ((ds=defsym)==0)
44                         return;
45                 funcsym = ds;
46                 if ((ds->htype&XTYPE)==FUNC) {
47                         if ((peeksym=symbol())==LBRACE || peeksym==KEYW
48                          || (peeksym==NAME && csym->hclass==TYPEDEF)) {
49                                 funcblk.type = decref(ds->htype);
50                                 funcblk.strp = ds->hstrp;
51                                 setinit(ds);
52                                 outcode("BS", SYMDEF, sclass==EXTERN?ds->name:"");
53                                 cfunc();
54                                 return;
55                         }
56                         if (paraml)
57                                 error("Inappropriate parameters");
58                 } else if ((o=symbol())==COMMA || o==SEMI) {
59                         peeksym = o;
60                         o = (length((union tree *)ds)+ALIGN) & ~ALIGN;
61                         if (sclass==STATIC) {
62                                 setinit(ds);
63                                 outcode("BSBBSBN", SYMDEF, "", BSS, NLABEL, ds->name, SSPACE, o);
64                         } else if (scflag)
65                                 outcode("BSN", CSPACE, ds->name, o);
66                 } else {
67                         if (o!=ASSIGN) {
68                                 error("Declaration syntax");
69                                 peeksym = o;
70                         }
71                         setinit(ds);
72                         if (sclass==EXTERN)
73                                 outcode("BS", SYMDEF, ds->name);
74                         outcode("BBS", DATA, NLABEL, ds->name);
75                         if (cinit(ds, 1, sclass) & ALIGN)
76                                 outcode("B", EVEN);
77                 }
78         } while ((o=symbol())==COMMA);
79         if (o==SEMI)
80                 return;
81 syntax:
82         if (o==RBRACE) {
83                 error("Too many }'s");
84                 peeksym = 0;
85                 return;
86         }
87         error("External definition syntax");
88         errflush(o);
89         statement();
90 }
91
92 /*
93  * Process a function definition.
94  */
95 void cfunc() {
96         register char *cb;
97         register int sloc;
98
99         sloc = isn;
100         isn += 2;
101         outcode("BBS", PROG, RLABEL, funcsym->name);
102         regvar = 5;
103         autolen = STAUTO;
104         maxauto = STAUTO;
105         blklev = 1;
106         cb = locbase;
107         declist(ARG);
108         outcode("B", SAVE);
109         if (proflg)
110                 outcode("BNS", PROFIL, isn++, funcsym->name);
111         funchead();
112         branch(sloc);
113         label(sloc+1);
114         retlab = isn++;
115         blklev = 0;
116         if ((peeksym = symbol()) != LBRACE)
117                 error("Compound statement required");
118         statement();
119         outcode("BNB", LABEL, retlab, RETRN);
120         label(sloc);
121 /* add STAUTO; overlay bug fix, coupled with section in c11.c */
122         outcode("BN", SETSTK, -maxauto+STAUTO);
123         branch(sloc+1);
124  /*fprintf(stderr, "cb=%p\n", cp);*/
125         locbase = cb;
126 }
127
128 /*
129  * Process the initializers for an external definition.
130  */
131 int cinit(anp, flex, sclass) struct nmlist *anp; int flex; int sclass; {
132         struct nmlist np;
133         register int nel, ninit;
134         int width, isarray, o, brace, realtype;
135         union tree *s;
136
137         np = *anp;
138         realtype = np.htype;
139         isarray = 0;
140         if ((realtype&XTYPE) == ARRAY)
141                 isarray++;
142         else
143                 flex = 0;
144         width = length((union tree *)&np);
145         nel = 1;
146         /*
147          * If it's an array, find the number of elements.
148          * temporarily modify to look like kind of thing it's
149          * an array of.
150          */
151         if (sclass==AUTO)
152                 if (isarray || realtype==STRUCT)
153                         error("No auto. aggregate initialization");
154         if (isarray) {
155                 np.htype = decref(realtype);
156                 np.hsubsp++;
157                 if (width==0 && flex==0)
158                         error("0-length row: %s", anp->name);
159                 o = length((union tree *)&np);
160                 nel = (unsigned)width/o;
161                 width = o;
162         }
163         brace = 0;
164         if ((peeksym=symbol())==LBRACE && (isarray || np.htype!=STRUCT)) {
165                 peeksym = -1;
166                 brace++;
167         }
168         ninit = 0;
169         do {
170                 if ((o=symbol())==RBRACE)
171                         break;
172                 peeksym = o;
173                 if (o==STRING && (realtype==ARRAY+CHAR || realtype==ARRAY+UNCHAR)) {
174                         if (sclass==AUTO)
175                                 error("No strings in automatic");
176                         peeksym = -1;
177                         putstr(0, flex?10000:nel);
178                         ninit += nchstr;
179                         o = symbol();
180                         break;
181                 } else if (np.htype==STRUCT) {
182                         strinit(&np, sclass);
183                 } else if ((np.htype&ARRAY)==ARRAY || peeksym==LBRACE)
184                         cinit(&np, 0, sclass);
185                 else {
186                         char *st;
187                         initflg++;
188                         st = starttree();
189                         s = tree(0);
190                         initflg = 0;
191                         if (np.hflag&FFIELD)
192                                 error("No field initialization");
193                         *cp++ = nblock(&np);
194                         *cp++ = s;
195                         build(ASSIGN);
196                         if (sclass==AUTO||sclass==REG)
197                                 rcexpr(*--cp);
198                         else if (sclass==ENUMCON) {
199                                 if (s->t.op!=CON)
200                                         error("Illegal enum constant for %s", anp->name);
201                                 anp->hoffset = s->c.value;
202                         } else
203                                 rcexpr(block(INIT,np.htype,(int *)NULL,
204                                   (union str *)NULL, (*--cp)->t.tr2, TNULL));
205                         endtree(st);
206                 }
207                 ninit++;
208                 if ((ninit&077)==0 && sclass==EXTERN)
209                         outcode("BS", SYMDEF, "");
210         } while ((o=symbol())==COMMA && (ninit<nel || brace || flex));
211         if (brace==0 || o!=RBRACE)
212                 peeksym = o;
213         /*
214          * If there are too few initializers, allocate
215          * more storage.
216          * If there are too many initializers, extend
217          * the declared size for benefit of "sizeof"
218          */
219         if (ninit<nel && sclass!=AUTO)
220                 outcode("BN", SSPACE, (nel-ninit)*width);
221         else if (ninit>nel) {
222                 if (flex && nel==0) {
223                         np.hsubsp[-1] = ninit;
224                 } else
225                         error("Too many initializers: %s", anp->name);
226                 nel = ninit;
227         }
228         return(nel*width);
229 }
230
231 /*
232  * Initialize a structure
233  */
234 void strinit(np, sclass) struct nmlist *np; int sclass; {
235         static struct nmlist junk;
236         register struct nmlist **mlp;
237         static struct nmlist *zerloc = NULL;
238         register int o, brace;
239
240         if ((mlp = np->hstrp->S.memlist)==NULL) {
241                 mlp = &zerloc;
242                 error("Undefined structure initialization");
243         }
244         brace = 0;
245         if ((o = symbol()) == LBRACE)
246                 brace++;
247         else
248                 peeksym = o;
249         do {
250                 if ((o=symbol()) == RBRACE)
251                         break;
252                 peeksym = o;
253                 if (*mlp==0) {
254                         error("Too many structure initializers");
255                         cinit(&junk, 0, sclass);
256                 } else
257                         cinit(*mlp++, 0, sclass);
258                 if (*mlp ==  &structhole) {
259                         outcode("B", EVEN);
260                         mlp++;
261                 }
262                                 /* DAG -- union initialization bug fix */
263                 if (*mlp && mlp[-1]->hoffset == (*mlp)->hoffset) {
264                         werror("union initialization non-portable");
265                         while (*mlp)    /* will NOT be &structhole */
266                                 mlp++;  /* skip other members of union */
267                 }
268         } while ((o=symbol())==COMMA && (*mlp || brace));
269         if (sclass!=AUTO && sclass!=REG) {
270                 if (*mlp)
271                         outcode("BN", SSPACE, np->hstrp->S.ssize - (*mlp)->hoffset);
272                 outcode("B", EVEN);
273         }
274         if (o!=RBRACE || brace==0)
275                 peeksym = o;
276 }
277
278 /*
279  * Mark already initialized
280  */
281 void setinit(np) register struct nmlist *np; {
282
283         if (np->hflag&FINIT)
284                 error("%s multiply defined", np->name);
285         np->hflag |= FINIT;
286 }
287
288 /*
289  * Process one statement in a function.
290  */
291 void statement() {
292         register int o, o1;
293         int sauto, sreg;
294
295 stmt:
296         switch(o=symbol()) {
297
298         case EOFC:
299                 error("Unexpected EOF");
300         case SEMI:
301                 return;
302
303         case LBRACE:
304                 sauto = autolen;
305                 sreg = regvar;
306                 blockhead();
307                 while (!eof) {
308                         if ((o=symbol())==RBRACE) {
309                                 autolen = sauto;
310                                 if (sreg!=regvar)
311                                         outcode("BN", SETREG, sreg);
312                                 regvar = sreg;
313                                 blkend();
314                                 return;
315                         }
316                         peeksym = o;
317                         statement();
318                 }
319                 error("Missing '}'");
320                 return;
321
322         case KEYW:
323                 switch(cval) {
324
325                 case GOTO:
326                         if (o1 = simplegoto())
327                                 branch(o1);
328                         else 
329                                 dogoto();
330                         goto semi;
331
332                 case RETURN:
333                         doret();
334                         goto semi;
335
336                 case ASM:
337                 {
338                         char    tmp[80],        /* tmp for line buffer */
339                                 *p;
340
341                         if (symbol() != LPARN || (o1 = symbol()) != STRING)
342                                 goto syntax;
343                         for (p = tmp; (o1 = mapch('"')) >= 0; )
344                                 *p++ = o1&0177;
345                         *p = '\0';
346                         if (symbol() != RPARN)
347                                 goto syntax;
348                         outcode("BF", ASSEM, tmp);
349                         goto semi;
350                 }
351
352                 case IF: {
353                         register int o2;
354                         register union tree *np;
355
356                         np = pexpr(1);
357                         o2 = 0;
358                         if ((o1=symbol())==KEYW) switch (cval) {
359                         case GOTO:
360                                 if (o2=simplegoto())
361                                         goto simpif;
362                                 cbranch(np, o2=isn++, 0);
363                                 dogoto();
364                                 label(o2);
365                                 goto hardif;
366
367                         case RETURN:
368                                 if (nextchar()==';') {
369                                         o2 = retlab;
370                                         goto simpif;
371                                 }
372                                 cbranch(np, o1=isn++, 0);
373                                 doret();
374                                 label(o1);
375                                 o2++;
376                                 goto hardif;
377
378                         case BREAK:
379                                 o2 = brklab;
380                                 goto simpif;
381
382                         case CONTIN:
383                                 o2 = contlab;
384                         simpif:
385                                 chconbrk(o2);
386                                 cbranch(np, o2, 1);
387                         hardif:
388                                 if ((o=symbol())!=SEMI)
389                                         goto syntax;
390                                 if ((o1=symbol())==KEYW && cval==ELSE) 
391                                         goto stmt;
392                                 peeksym = o1;
393                                 return;
394                         }
395                         peeksym = o1;
396                         cbranch(np, o1=isn++, 0);
397                         statement();
398                         if ((o=symbol())==KEYW && cval==ELSE) {
399                                 o2 = isn++;
400                                 branch(o2);
401                                 label(o1);
402                                 statement();
403                                 label(o2);
404                                 return;
405                         }
406                         peeksym = o;
407                         label(o1);
408                         return;
409                 }
410
411                 case WHILE: {
412                         register int o2;
413                         o1 = contlab;
414                         o2 = brklab;
415                         label(contlab = isn++);
416                         cbranch(pexpr(1), brklab=isn++, 0);
417                         statement();
418                         branch(contlab);
419                         label(brklab);
420                         contlab = o1;
421                         brklab = o2;
422                         return;
423                 }
424
425                 case BREAK:
426                         chconbrk(brklab);
427                         branch(brklab);
428                         goto semi;
429
430                 case CONTIN:
431                         chconbrk(contlab);
432                         branch(contlab);
433                         goto semi;
434
435                 case DO: {
436                         register int o2, o3;
437                         o1 = contlab;
438                         o2 = brklab;
439                         contlab = isn++;
440                         brklab = isn++;
441                         label(o3 = isn++);
442                         statement();
443                         label(contlab);
444                         contlab = o1;
445                         if ((o=symbol())==KEYW && cval==WHILE) {
446                                 cbranch(tree(1), o3, 1);
447                                 label(brklab);
448                                 brklab = o2;
449                                 goto semi;
450                         }
451                         goto syntax;
452                 }
453
454                 case CASE:
455                         o1 = conexp();
456                         if ((o=symbol())!=COLON)
457                                 goto syntax;
458                         if (swp==0) {
459                                 error("Case not in switch");
460                                 goto stmt;
461                         }
462                         if(swp>=swtab+SWSIZ) {
463                                 error("Switch table overflow");
464                         } else {
465                                 swp->swlab = isn;
466                                 (swp++)->swval = o1;
467                                 label(isn++);
468                         }
469                         goto stmt;
470
471                 case SWITCH: {
472                         register union tree *np;
473                         register char *st;
474
475                         o1 = brklab;
476                         brklab = isn++;
477                         st = starttree();
478                         np = pexpr(0);
479                         chkw(np, -1);
480                         rcexpr(block(RFORCE,0,(int *)NULL,(union str *)NULL,np,TNULL));
481                         endtree(st);
482                         pswitch();
483                         brklab = o1;
484                         return;
485                 }
486
487                 case DEFAULT:
488                         if (swp==0)
489                                 error("Default not in switch");
490                         if (deflab)
491                                 error("More than 1 'default'");
492                         if ((o=symbol())!=COLON)
493                                 goto syntax;
494                         label(deflab = isn++);
495                         goto stmt;
496
497                 case FOR: {
498                         register int o2;
499                         o1 = contlab;
500                         o2 = brklab;
501                         contlab = isn++;
502                         brklab = isn++;
503                         if (o=forstmt())
504                                 goto syntax;
505                         contlab = o1;
506                         brklab = o2;
507                         return;
508                 }
509
510                 case ELSE:
511                         error("Inappropriate 'else'");
512                         statement();
513                         return;
514                 }
515                 error("Unknown keyword");
516                 goto syntax;
517
518         case NAME: {
519                 register struct nmlist *np;
520                 if (nextchar()==':') {
521                         peekc = 0;
522                         np = csym;
523                         if (np->hclass>0) {
524                                 if (np->hblklev==0) {
525                                         np = pushdecl(np);
526                                         np->hoffset = 0;
527                                 } else {
528                                         defsym = np;
529                                         redec();
530                                         goto stmt;
531                                 }
532                         }
533                         np->hclass = STATIC;
534                         np->htype = ARRAY;
535                         np->hflag |= FLABL;
536                         if (np->hoffset==0)
537                                 np->hoffset = isn++;
538                         label(np->hoffset);
539                         goto stmt;
540                 }
541         }
542         }
543         peeksym = o;
544         rcexpr(tree(1));
545
546 semi:
547         if ((o=symbol())==SEMI)
548                 return;
549 syntax:
550         error("Statement syntax");
551         errflush(o);
552 }
553
554 /*
555  * Process a for statement.
556  */
557 int forstmt() {
558         register int o;
559         register union tree *st;
560         register int l;
561         char *ss;
562
563         if ((o=symbol()) != LPARN)
564                 return(o);
565         if ((o=symbol()) != SEMI) {             /* init part */
566                 peeksym = o;
567                 rcexpr(tree(1));
568                 if ((o=symbol()) != SEMI)
569                         return(o);
570         }
571         l = isn;
572         isn += 3;
573         branch(l+0);
574         label(l+1);
575         branch(l+2);
576         label(contlab);
577         st = NULL;
578         if ((o=symbol()) != SEMI) {             /* test part */
579                 peeksym = o;
580                 ss = starttree();
581                 st = tree(0);
582                 if ((o=symbol()) != SEMI) {
583                         endtree(ss);
584                         return(o);
585                 }
586         }
587         if ((o=symbol()) != RPARN) {    /* incr part */
588                 peeksym = o;
589                 rcexpr(tree(1));
590                 if ((o=symbol()) != RPARN) {
591                         if (st)
592                                 endtree(ss);
593                         return(o);
594                 }
595         }
596         label(l+0);
597         if (st) {
598                 cbranch(st, l+1, 1);
599                 endtree(ss);
600         } else
601                 branch(l+1);
602         branch(brklab);
603         label(l+2);
604         statement();
605         branch(contlab);
606         label(brklab);
607         return(0);
608 }
609
610 /*
611  * A parenthesized expression,
612  * as after "if".
613  */
614 union tree *pexpr(eflag) int eflag; {
615         register int o;
616         register union tree *t;
617
618         if ((o=symbol())!=LPARN)
619                 goto syntax;
620         t = tree(eflag);
621         if ((o=symbol())!=RPARN)
622                 goto syntax;
623         if (t->t.type==VOID)
624                 error("Illegal use of void");
625         return(t);
626 syntax:
627         error("Statement syntax");
628         errflush(o);
629         return(0);
630 }
631
632 /*
633  * The switch statement, which involves collecting the
634  * constants and labels for the cases.
635  */
636 void pswitch() {
637         register struct swtab *cswp, *sswp;
638         int dl, swlab;
639
640         cswp = sswp = swp;
641         if (swp==0)
642                 cswp = swp = swtab;
643         branch(swlab=isn++);
644         dl = deflab;
645         deflab = 0;
646         statement();
647         branch(brklab);
648         label(swlab);
649         if (deflab==0)
650                 deflab = brklab;
651         outcode("BNN", SWIT, deflab, line);
652         for (; cswp < swp; cswp++)
653                 outcode("NN", cswp->swlab, cswp->swval);
654         outcode("0");
655         label(brklab);
656         deflab = dl;
657         swp = sswp;
658 }
659
660 /*
661  * funchead is called at the start of each function
662  * to process the arguments, which have been linked in a list.
663  * This list is necessary because in
664  * f(a, b) float b; int a; ...
665  * the names are seen before the types.
666  */
667 /*
668  * Structure resembling a block for a register variable.
669  */
670 struct  nmlist  hreg    = { REG, 0, 0, NULL, NULL, 0 };
671 struct  tnode   areg    = { NAME, 0, NULL, NULL, (union tree *)&hreg};
672 void funchead() {
673         register int pl;
674         register struct nmlist *cs;
675         register char *st;
676
677         pl = STARG;
678         while(paraml) {
679                 parame->sparent = NULL;
680                 cs = paraml;
681                 paraml = &paraml->sparent->P;
682                 if (cs->htype==FLOAT)
683                         cs->htype = DOUBLE;
684                 cs->hoffset = pl;
685                 if ((cs->htype&XTYPE) == ARRAY) {
686                         cs->htype -= (ARRAY-PTR);       /* set ptr */
687                         cs->hsubsp++;           /* pop dims */
688                 }
689                 pl += rlength((union tree *)cs);
690                 if (cs->hclass==AREG && (hreg.hoffset=goodreg(cs))>=0) {
691                         st = starttree();
692                         *cp++ = (union tree *)&areg;
693                         *cp++ = nblock(cs);
694                         areg.type = cs->htype;
695                         areg.strp = cs->hstrp;
696                         cs->hclass = AUTO;
697                         build(ASSIGN);
698                         rcexpr(*--cp);
699                         cs->hoffset = hreg.hoffset;
700                         cs->hclass = REG;
701                         endtree(st);
702                 } else
703                         cs->hclass = AUTO;
704                 prste(cs);
705         }
706         for (pl=0; pl<HSHSIZ; pl++) {
707                 for (cs = hshtab[pl]; cs!=NULL; cs = cs->nextnm) {
708                         if (cs->hclass == ARG || cs->hclass==AREG)
709                                 error("Not an argument: %s", cs->name);
710                 }
711         }
712         outcode("BN", SETREG, regvar);
713 }
714
715 void blockhead() {
716         register int r;
717
718         r = regvar;
719         blklev++;
720         declist(0);
721         if (r != regvar)
722                 outcode("BN", SETREG, regvar);
723 }
724
725 /*
726  * After the end of a block, delete local
727  * symbols;
728  * Also complain about undefined labels.
729  */
730 void blkend() {
731         register struct nmlist *cs, **lcs;
732         register int i;
733
734         blklev--;
735         for (i = 0; i < HSHSIZ; i++) {
736                 lcs = &hshtab[i];
737                 cs = *lcs;
738                 while (cs) {
739                         if (cs->hblklev > blklev
740                          && (((cs->hflag&FLABL)==0 && cs->hclass!=EXTERN) || blklev<=0)) {
741                                 if (cs->hclass==0)
742                                         error("%s undefined", cs->name);
743                                 if (cs->hclass==EXTERN)
744                                         nameconflict(hshtab[i], cs);
745                                 *lcs = cs->nextnm;
746                         } else
747                                 lcs = &cs->nextnm;
748                         cs = cs->nextnm;
749                 }
750         }
751 }
752
753 void nameconflict(ocs, cs) register struct nmlist *ocs; register struct nmlist *cs; {
754
755         for (; ocs!=NULL; ocs = ocs->nextnm) 
756                 if (ocs!=cs && ocs->hclass==EXTERN && 
757                     strncmp(cs->name, ocs->name, MAXCPS-1) == 0)
758                         error("names %s and %s conflict", cs->name, ocs->name);
759 }
760
761 /*
762  * write out special definitions of local symbols for
763  * benefit of the debugger.  None of these are used
764  * by the assembler except to save them.
765  */
766 void prste(cs) struct nmlist *cs; {
767         register int nkind;
768
769         switch (cs->hclass) {
770         case REG:
771                 nkind = RNAME;
772                 break;
773
774         case AUTO:
775                 nkind = ANAME;
776                 break;
777
778         case STATIC:
779                 nkind = SNAME;
780                 break;
781
782         default:
783                 return;
784
785         }
786         outcode("BSN", nkind, cs->name, cs->hoffset);
787 }
788
789 /*
790  * In case of error, skip to the next
791  * statement delimiter.
792  */
793 void errflush(ao) int ao; {
794         register int o;
795
796         o = ao;
797         while(o>RBRACE) {       /* ; { } */
798                 if (o==STRING)
799                         putstr(0, 0);
800                 o = symbol();
801         }
802         peeksym  = o;
803 }