Add tests, fixes for tests, reinstate and type-convert stuff marked "bitrot"
[ccom.git] / c04.c
1 /*
2  * C compiler
3  */
4
5 #include <stdlib.h>
6 #ifdef __STDC__
7 #include <stdarg.h>
8 #define _va_start(argp, arg) va_start(argp, arg)
9 #else
10 #include <varargs.h>
11 #define _va_start(argp, arg) va_start(argp)
12 #endif
13 #include "c0.h"
14 #include "c1.h" /* rcexpr0() one-pass version */
15
16 /*
17  * Reduce the degree-of-reference by one.
18  * e.g. turn "ptr-to-int" into "int".
19  */
20 int decref0(t) register int t; {
21         if ((t & ~TYPE) == 0) {
22                 error0("Illegal indirection");
23                 return(t);
24         }
25         return((t>>TYLEN) & ~TYPE | t&TYPE);
26 }
27
28 /*
29  * Increase the degree of reference by
30  * one; e.g. turn "int" to "ptr-to-int".
31  */
32 int incref0(t) register int t; {
33         return(((t&~TYPE)<<TYLEN) | (t&TYPE) | PTR);
34 }
35
36 /*
37  * Make a tree that causes a branch to lbl
38  * if the tree's value is non-zero together with the cond.
39  */
40 void cbranch0(t, lbl, cond) struct node *t; int lbl; int cond; {
41 #if 1 /* one-pass version */
42         long outloc;
43
44         regpanic = 0;
45         if (setjmp(jmpbuf)) {
46  fprintf(stderr, "a seek %ld\n", outloc);
47                 regpanic = 10;
48                 fseek(/*stdout*/temp_fp[temp_fi], outloc, 0);
49         }
50         nstack = 0;
51         panicposs = 0;
52         t = optim(t);
53         if (regpanic==0 && panicposs)
54  {
55                 outloc = ftell(/*stdout*/temp_fp[temp_fi]);
56   fprintf(stderr, "a tell %ld\n", outloc);
57   cbranch1(t, lbl, cond, 0);
58   fprintf(stderr, "a done\n");
59  }
60  else
61         cbranch1(t, lbl, cond, 0);
62 #else
63         treeout(t, 0);
64         outcode("BNNN", CBRANCH, lbl, cond, line);
65 #endif
66 }
67
68 /*
69  * Write out a tree.
70  */
71 void rcexpr0(tp) register struct node *tp; {
72 #if 1 /* one-pass version */
73         long outloc;
74 #endif
75         /*
76          * Special optimization
77          */
78         if (tp->n_op==INIT && ((struct tnode *)tp)->tn_tr1->n_op==CON) {
79 #define ttp ((struct tnode *)tp)
80                 if (ttp->tn_type==CHAR || ttp->tn_type==UNCHAR) {
81                         outcode("B1N0", BDATA, ((struct cnode *)ttp->tn_tr1)->cn_value);
82                         return;
83                 } else if (ttp->tn_type==INT || ttp->tn_type==UNSIGN) {
84                         outcode("BN", SINIT, ((struct cnode *)ttp->tn_tr1)->cn_value);
85                         return;
86                 }
87 #undef ttp
88         }
89 #if 1 /* one-pass version */
90         regpanic = 0;
91         if (setjmp(jmpbuf)) {
92  fprintf(stderr, "b seek %ld\n", outloc);
93                 regpanic = 10;
94                 fseek(/*stdout*/temp_fp[temp_fi], outloc, 0);
95         }
96         nstack = 0;
97         panicposs = 0;
98         tp = optim(tp);
99         if (regpanic==0 && panicposs)
100  {
101                 outloc = ftell(/*stdout*/temp_fp[temp_fi]);
102   fprintf(stderr, "b tell %ld\n", outloc);
103   rcexpr1(tp, efftab, 0);
104   fprintf(stderr, "b done\n");
105  }
106  else
107         rcexpr1(tp, efftab, 0);
108 #else
109         treeout(tp, 0);
110         outcode("BN", EXPR, line);
111 #endif
112 }
113
114 #if 0
115 void treeout(tp, isstruct) register struct node *tp; int isstruct; {
116         register struct nmlist *hp;
117         register int nextisstruct;
118
119         if (tp == NULL || tp->tn_op==NULLOP0) {
120                 outcode("B", NULLOP);
121                 return;
122         }
123         nextisstruct = tp->tn_type==STRUCT;
124         switch(tp->tn_op) {
125
126         case NAME:
127                 hp = (struct nmlist *)tp->tn_tr1;
128                 if (hp->nl_class==TYPEDEF)
129                         error0("Illegal use of type name");
130 #if 1
131  if (hp->nl_class==EXTERN)
132   outcode("BNNS", NAME, EXTERN, tp->tn_type, hp->nl_name);
133  else
134   outcode("BNNN", NAME, hp->nl_class==0?STATIC:hp->nl_class, tp->tn_type, hp->nl_offset);
135 #else
136                 outcode("BNN", NAME, hp->nl_class==0?STATIC:hp->nl_class, tp->tn_type);
137                 if (hp->nl_class==EXTERN)
138                         outcode("S", hp->nl_name);
139                 else
140                         outcode("N", hp->nl_offset);
141 #endif
142                 break;
143
144         case LCON:
145                 outcode("BNNN", tp->ln_op, tp->ln_type, (_UNSIGNED_INT)(tp->ln_lvalue>>16),
146                    (_UNSIGNED_INT)tp->ln_lvalue);
147                 break;
148
149         case CON:
150                 outcode("BNN", tp->cn_op, tp->cn_type, tp->cn_value);
151                 break;
152
153         case FCON:
154                 outcode("BNF", tp->fn_op, tp->fn_type, tp->f.cstr);
155                 break;
156
157         case STRING:
158                 outcode("BNNN", NAME, STATIC, tp->tn_type, tp->tn_tr1);
159                 break;
160
161         case FSEL:
162                 treeout(tp->tn_tr1, nextisstruct);
163                 outcode("BNNN", tp->tn_op, tp->tn_type,
164                    ((struct FS *)tp->tn_tr2)->bitoffs, ((struct FS *)tp->tn_tr2)->flen);
165                 break;
166
167         case ETYPE:
168                 error0("Illegal use of type");
169                 break;
170
171         case AMPER:
172                 treeout(tp->tn_tr1, 1);
173                 outcode("BN", tp->tn_op, tp->tn_type);
174                 break;
175
176
177         case CALL:
178                 treeout(tp->tn_tr1, 1);
179                 treeout(tp->tn_tr2, 0);
180                 outcode("BN", CALL, tp->tn_type);
181                 break;
182
183         default:
184                 treeout(tp->tn_tr1, nextisstruct);
185                 if (opdope0[tp->tn_op]&BINARY)
186                         treeout(tp->tn_tr2, nextisstruct);
187                 outcode("BN", tp->tn_op, tp->tn_type);
188                 break;
189         }
190         if (nextisstruct && isstruct==0)
191                 outcode("BNN", STRASG, STRUCT, tp->tn_strp->S.ssize);
192 }
193 #endif
194
195 /*
196  * Generate a branch
197  */
198 void branch0(lab) int lab; {
199         outcode("BN", BRANCH, lab);
200 }
201
202 /*
203  * Generate a label
204  */
205 void label0(l) int l; {
206         outcode("BN", LABEL, l);
207 }
208
209 /*
210  * ap is a tree node whose type
211  * is some kind of pointer; return the size of the object
212  * to which the pointer points.
213  */
214 int XXXlength(cs) struct node *cs; {
215         register int t, elsz;
216         long n;
217         int nd;
218
219         t = cs->n_type;
220         n = 1;
221         nd = 0;
222         while ((t&XTYPE) == ARRAY) {
223                 t = decref0(t);
224                 n *= cs->n_subsp[nd++];
225         }
226         if ((t&~TYPE)==FUNC)
227                 return(0);
228         if (t>=PTR)
229                 elsz = SZPTR;
230         else switch(t&TYPE) {
231
232         case VOID:
233                 error0("Illegal use of void object");
234                 return(2);
235
236         case INT:
237         case UNSIGN:
238                 elsz = SZINT;
239                 break;
240
241         case CHAR:
242         case UNCHAR:
243                 elsz = 1;
244                 break;
245
246         case FLOAT:
247                 elsz = SZFLOAT;
248                 break;
249
250         case UNLONG:
251         case LONG:
252                 elsz = SZLONG;
253                 break;
254
255         case DOUBLE:
256                 elsz = SZDOUB;
257                 break;
258
259         case STRUCT:
260                 if ((elsz = cs->n_strp->S.ssize) == 0)
261                         error0("Undefined structure");
262                 break;
263         default:
264                 error0("Compiler error0 (length)");
265                 return(0);
266         }
267  /*fprintf(stderr, "%d %d %d\n", (int)n, (int)elsz, (int)(n * elsz));*/
268         n *= elsz;
269         if (n >= (_UNSIGNED_INT)50000)
270                 werror0("very large data structure");
271         return(n);
272 }
273 int plength(p) register struct node *p; {
274         register int t, l;
275
276         if (p==0 || ((t=p->n_type)&~TYPE) == 0)         /* not a reference */
277                 return(1);
278         p->n_type = decref0(t);
279         l = XXXlength(p);
280         p->n_type = t;
281         return(l);
282 }
283
284 /*
285  * return the number of bytes in the object
286  * whose tree node is acs.
287  */
288 int length(cs) struct /*node*/type *cs; {
289         register int /*t,*/ elsz;
290  register struct type *t;
291         long n;
292  /*     int nd;*/
293
294  /*     t = cs->n_type;
295         n = 1;
296         nd = 0;
297         while ((t&XTYPE) == ARRAY) {
298                 t = decref0(t);
299                 n *= cs->n_subsp[nd++];
300         }*/
301  n = 1;
302  for (t = cs; t->t_id == (REF | ARRAY); t = ((struct atype *)t)->at_reftype)
303   n *= ((struct atype *)t)->at_nelt;
304         if (/*(t&~TYPE)==FUNC*/t->t_id==(REF|FUNC))
305                 return(0);
306  /*     if (t>=PTR)
307                 elsz = SZPTR;
308         else*/ switch(/*t&TYPE*/t->t_id) {
309  case REF | PTR:
310   elsz = SZPTR;
311   break;
312
313         case VOID:
314                 error0("Illegal use of void object");
315                 return(2);
316
317         case INT:
318         case UNSIGN:
319                 elsz = SZINT;
320                 break;
321
322         case CHAR:
323         case UNCHAR:
324                 elsz = 1;
325                 break;
326
327         case FLOAT:
328                 elsz = SZFLOAT;
329                 break;
330
331         case UNLONG:
332         case LONG:
333                 elsz = SZLONG;
334                 break;
335
336         case DOUBLE:
337                 elsz = SZDOUB;
338                 break;
339
340         case STRUCT:
341                 if ((elsz = /*cs->n_strp->S.ssize*/((struct stype *)t)->st_ssize) == 0)
342                         error0("Undefined structure");
343                 break;
344         default:
345                 error0("Compiler error (length)");
346                 return(0);
347         }
348  /*fprintf(stderr, "%d %d %d\n", (int)n, (int)elsz, (int)(n * elsz));*/
349         n *= elsz;
350         if (n >= (_UNSIGNED_INT)50000)
351                 werror0("very large data structure");
352         return(n);
353 }
354
355 /*
356  * The number of bytes in an object, rounded up to a word.
357  */
358 int rlength(cs) struct /*node*/type *cs; {
359         return((length(cs)+ALIGN) & ~ALIGN);
360 }
361
362 /*
363  * After an "if (...) goto", look to see if the transfer
364  * is to a simple label.
365  */
366 extern struct type gototype; /* dummy type distinguished by its address */
367 int simplegoto() {
368         register struct nmlist *csp;
369
370         if ((peeksym=symbol())==NAME && nextchar()==';') {
371                 csp = csym;
372                 if (csp->nl_blklev == 0)
373                         csp = pushdecl(csp);
374                 if (csp->nl_class==0 && csp->/*nl_type==0*/nl_dtype==NULL) {
375  /*                     csp->nl_type = ARRAY;*/
376  csp->nl_dtype = &gototype;
377                         csp->nl_flag |= FLABL;
378                         if (csp->nl_offset==0)
379                                 csp->nl_offset = isn0++;
380                 }
381                 if ((csp->nl_class==0||csp->nl_class==STATIC)
382                  &&  /*csp->nl_type==ARRAY*/csp->nl_dtype==&gototype) {
383                         peeksym = -1;
384                         return(csp->nl_offset);
385                 }
386         }
387         return(0);
388 }
389
390 /*
391  * Return the next non-white-space character
392  */
393 int nextchar() {
394         while (spnextchar()==' ')
395                 peekc = 0;
396         return(peekc);
397 }
398
399 /*
400  * Return the next character, translating all white space
401  * to blank and handling line-ends.
402  */
403 int spnextchar() {
404         register int c;
405
406         if ((c = peekc)==0)
407                 c = getchar();
408         if (c=='\t' || c=='\014')       /* FF */
409                 c = ' ';
410         else if (c=='\n') {
411                 c = ' ';
412                 line++;
413         }
414         peekc = c;
415         return(c);
416 }
417
418 /*
419  * is a break or continue legal?
420  */
421 void chconbrk(l) int l; {
422         if (l==0)
423                 error0("Break/continue error");
424 }
425
426 /*
427  * The goto statement.
428  */
429 void dogoto() {
430         register struct node *np;
431         register char *st;
432
433         st = starttree();
434         *cp++ = tree(/*0*/);
435         build(STAR);
436         chkw(np = *--cp, -1);
437         rcexpr0((struct node *)block(JUMP, 0, (int *)NULL, (union str *)NULL, np, (struct node *)NULL));
438         endtree(st);
439 }
440
441 /*
442  * The return statement, which has to convert
443  * the returned object to the function's type.
444  */
445 void doret() {
446         if (nextchar() != ';') {
447                 register char *st;
448
449                 st = starttree();
450                 *cp++ = (struct node *)&funcblk;
451                 *cp++ = tree(/*0*/);
452                 build(ASSIGN);
453                 cp[-1] = ((struct tnode *)cp[-1])->tn_tr2;
454                 build(RFORCE);
455                 rcexpr0(*--cp);
456                 endtree(st);
457         }
458         branch0(retlab);
459 }
460
461 /*
462  * Write a character on the error output.
463  */
464 /*
465  * Coded output:
466  *   B: beginning of line; an operator
467  *   N: a number
468  *   S: a symbol (external)
469  *   1: number 1
470  *   0: number 0
471  */
472 #if 0
473 #ifdef __STDC__
474 void outcode(char *s, ...)
475 #else
476 void outcode(s, va_alist) char *s; va_dcl
477 #endif
478 {
479         va_list ap;
480         register FILE *bufp;
481         register int ni;
482         register char *np;
483         int n;
484
485 #if 1
486         bufp = temp_fp[temp_fi];
487 #else
488         bufp = stdout;
489         if (strflg)
490                 bufp = sbufp;
491 #endif
492         _va_start(argp, s);
493         for (;;) switch(*s++) {
494         case 'B':
495                 ni = va_arg(ap, int);
496                 fputc(ni, bufp);
497                 fputc(0376, bufp);
498                 continue;
499
500         case 'N':
501                 ni = va_arg(ap, int);
502                 fputc(ni, bufp);
503                 fputc(ni>>8, bufp);
504                 continue;
505
506         case 'F':
507                 np = va_arg(ap, char *);
508                 n = 1000;
509                 goto str;
510
511         case 'S':
512                 np = va_arg(ap, char *);
513                 n = MAXCPS-1;
514                 if (*np)
515                         fputc('_', bufp);
516         str:
517                 while(n-- && *np) {
518                         fputc(*np++ & 0177, bufp);
519                 }
520                 fputc(0, bufp);
521                 continue;
522
523         case '1':
524                 fputc(1, bufp);
525                 fputc(0, bufp);
526                 continue;
527
528         case '0':
529                 fputc(0, bufp);
530                 fputc(0, bufp);
531                 continue;
532
533         case '\0':
534                 va_end(argp);
535                 if (ferror(bufp)) {
536                         error0("Write error on temp");
537                         exit(1);
538                 }
539                 return;
540
541         default:
542                 error0("Botch in outcode");
543         }
544 }
545 #endif
546
547 unsigned int hash(sp) register char *sp; {
548         register unsigned int h;
549
550         h = 0;
551         for (; *sp; sp++) {
552                 h += h;
553                 h += *sp;
554         }
555         return(h%HSHSIZ);
556 }