Research V7 development
[unix-history] / usr / src / cmd / c / c01.c
CommitLineData
1a3b21a9
DR
1#
2/*
3 * C compiler
4 *
5 *
6 */
7
8#include "c0.h"
9
10/*
11 * Called from tree, this routine takes the top 1, 2, or 3
12 * operands on the expression stack, makes a new node with
13 * the operator op, and puts it on the stack.
14 * Essentially all the work is in inserting
15 * appropriate conversions.
16 */
17build(op)
18{
19 register int t1;
20 int t2, t;
21 register struct tnode *p1, *p2;
22 struct tnode *p3;
23 int dope, leftc, cvn, pcvn;
24
25 /*
26 * a[i] => *(a+i)
27 */
28 if (op==LBRACK) {
29 build(PLUS);
30 op = STAR;
31 }
32 dope = opdope[op];
33 if ((dope&BINARY)!=0) {
34 p2 = chkfun(disarray(*--cp));
35 t2 = p2->type;
36 }
37 p1 = *--cp;
38 /*
39 * sizeof gets turned into a number here.
40 */
41 if (op==SIZEOF) {
42 t1 = cblock(length(p1));
43 t1->type = UNSIGN;
44 *cp++ = t1;
45 return;
46 }
47 if (op!=AMPER) {
48 p1 = disarray(p1);
49 if (op!=CALL)
50 p1 = chkfun(p1);
51 }
52 t1 = p1->type;
53 pcvn = 0;
54 t = INT;
55 switch (op) {
56
57 case CAST:
58 if ((t1&XTYPE)==FUNC || (t1&XTYPE)==ARRAY)
59 error("Disallowed conversion");
60 if (t1==UNSIGN && t2==CHAR) {
61 t2 = INT;
62 p2 = block(AND,INT,NULL,NULL,p2,cblock(0377));
63 }
64 break;
65
66 /* end of expression */
67 case 0:
68 *cp++ = p1;
69 return;
70
71 /* no-conversion operators */
72 case QUEST:
73 if (p2->op!=COLON)
74 error("Illegal conditional");
75 else
76 if (fold(QUEST, p1, p2))
77 return;
78
79 case SEQNC:
80 t = t2;
81
82 case COMMA:
83 case LOGAND:
84 case LOGOR:
85 *cp++ = block(op, t, NULL, NULL, p1, p2);
86 return;
87
88 case EXCLA:
89 t1 = INT;
90 break;
91
92 case CALL:
93 if ((t1&XTYPE) != FUNC)
94 error("Call of non-function");
95 *cp++ = block(CALL,decref(t1),p1->subsp,p1->strp,p1,p2);
96 return;
97
98 case STAR:
99 if ((t1&XTYPE) == FUNC)
100 error("Illegal indirection");
101 *cp++ = block(STAR, decref(t1), p1->subsp, p1->strp, p1);
102 return;
103
104 case AMPER:
105 if (p1->op==NAME || p1->op==STAR) {
106 *cp++ = block(op,incref(t1),p1->subsp,p1->strp,p1);
107 return;
108 }
109 error("Illegal lvalue");
110 break;
111
112 /*
113 * a.b goes to (&a)->b
114 */
115 case DOT:
116 if (p1->op==CALL && t1==STRUCT) {
117 t1 = incref(t1);
118 setype(p1, t1, p1);
119 } else {
120 *cp++ = p1;
121 build(AMPER);
122 p1 = *--cp;
123 }
124
125 /*
126 * In a->b, a is given the type ptr-to-structure element;
127 * then the offset is added in without conversion;
128 * then * is tacked on to access the member.
129 */
130 case ARROW:
131 if (p2->op!=NAME || p2->tr1->hclass!=MOS) {
132 error("Illegal structure ref");
133 *cp++ = p1;
134 return;
135 }
136 if (t2==INT && p2->tr1->hflag&FFIELD)
137 t2 = UNSIGN;
138 t = incref(t2);
139 chkw(p1, -1);
140 setype(p1, t, p2);
141 *cp++ = block(PLUS,t,p2->subsp,p2->strp,p1,cblock(p2->tr1->hoffset));
142 build(STAR);
143 if (p2->tr1->hflag&FFIELD)
144 *cp++ = block(FSEL,UNSIGN,NULL,NULL,*--cp,p2->tr1->hstrp);
145 return;
146 }
147 if ((dope&LVALUE)!=0)
148 chklval(p1);
149 if ((dope&LWORD)!=0)
150 chkw(p1, LONG);
151 if ((dope&RWORD)!=0)
152 chkw(p2, LONG);
153 if ((dope&BINARY)==0) {
154 if (op==ITOF)
155 t1 = DOUBLE;
156 else if (op==FTOI)
157 t1 = INT;
158 if (!fold(op, p1, 0))
159 *cp++ = block(op,t1,p1->subsp,p1->strp,p1);
160 return;
161 }
162 cvn = 0;
163 if (t1==STRUCT || t2==STRUCT) {
164 if (t1!=t2 || p1->strp != p2->strp)
165 error("Incompatible structures");
166 cvn = 0;
167 } else
168 cvn = cvtab[lintyp(t1)][lintyp(t2)];
169 leftc = (cvn>>4)&017;
170 cvn =& 017;
171 t = leftc? t2:t1;
172 if ((t==INT||t==CHAR) && (t1==UNSIGN||t2==UNSIGN))
173 t = UNSIGN;
174 if (dope&ASSGOP || op==CAST) {
175 t = t1;
176 if (op==ASSIGN || op==CAST) {
177 if (cvn==ITP||cvn==PTI)
178 cvn = leftc = 0;
179 else if (cvn==LTP) {
180 if (leftc==0)
181 cvn = LTI;
182 else {
183 cvn = ITL;
184 leftc = 0;
185 }
186 }
187 }
188 if (leftc)
189 cvn = leftc;
190 leftc = 0;
191 } else if (op==COLON || op==MAX || op==MIN) {
192 if (t1>=PTR && t1==t2)
193 cvn = 0;
194 if (op!=COLON && (t1>=PTR || t2>=PTR))
195 op =+ MAXP-MAX;
196 } else if (dope&RELAT) {
197 if (op>=LESSEQ && (t1>=PTR||t2>=PTR||(t1==UNSIGN||t2==UNSIGN)
198 && (t==INT||t==CHAR||t==UNSIGN)))
199 op =+ LESSEQP-LESSEQ;
200 if (cvn==ITP || cvn==PTI)
201 cvn = 0;
202 }
203 if (cvn==PTI) {
204 cvn = 0;
205 if (op==MINUS) {
206 t = INT;
207 pcvn++;
208 } else {
209 if (t1!=t2 || t1!=(PTR+CHAR))
210 cvn = XX;
211 }
212 }
213 if (cvn) {
214 t1 = plength(p1);
215 t2 = plength(p2);
216 if (cvn==XX || (cvn==PTI&&t1!=t2))
217 error("Illegal conversion");
218 else if (leftc)
219 p1 = convert(p1, t, cvn, t2);
220 else
221 p2 = convert(p2, t, cvn, t1);
222 }
223 if (dope&RELAT)
224 t = INT;
225 if (t==FLOAT)
226 t = DOUBLE;
227 if (t==CHAR)
228 t = INT;
229 if (op==CAST) {
230 if (t!=DOUBLE && (t!=INT || p2->type!=CHAR)) {
231 p2->type = t;
232 p2->subsp = p1->subsp;
233 p2->strp = p1->strp;
234 }
235 if (t==INT && p1->type==CHAR)
236 p2 = block(ITOC, INT, NULL, NULL, p2);
237 *cp++ = p2;
238 return;
239 }
240 if (fold(op, p1, p2)==0) {
241 p3 = leftc?p2:p1;
242 *cp++ = block(op, t, p3->subsp, p3->strp, p1, p2);
243 }
244 if (pcvn && t1!=(PTR+CHAR)) {
245 p1 = *--cp;
246 *cp++ = convert(p1, 0, PTI, plength(p1->tr1));
247 }
248}
249
250/*
251 * Generate the appropriate conversion operator.
252 */
253struct tnode *
254convert(p, t, cvn, len)
255struct tnode *p;
256{
257 register int op;
258
259 op = cvntab[cvn];
260 if (opdope[op]&BINARY) {
261 if (len==0)
262 error("Illegal conversion");
263 return(block(op, t, NULL, NULL, p, cblock(len)));
264 }
265 return(block(op, t, NULL, NULL, p));
266}
267
268/*
269 * Traverse an expression tree, adjust things
270 * so the types of things in it are consistent
271 * with the view that its top node has
272 * type at.
273 * Used with structure references.
274 */
275setype(ap, at, anewp)
276struct tnode *ap, *anewp;
277{
278 register struct tnode *p, *newp;
279 register t;
280
281 p = ap;
282 t = at;
283 newp = anewp;
284 for (;; p = p->tr1) {
285 p->subsp = newp->subsp;
286 p->strp = newp->strp;
287 p->type = t;
288 if (p->op==AMPER)
289 t = decref(t);
290 else if (p->op==STAR)
291 t = incref(t);
292 else if (p->op!=PLUS)
293 break;
294 }
295}
296
297/*
298 * A mention of a function name is turned into
299 * a pointer to that function.
300 */
301struct tnode *
302chkfun(ap)
303struct tnode *ap;
304{
305 register struct tnode *p;
306 register int t;
307
308 p = ap;
309 if (((t = p->type)&XTYPE)==FUNC && p->op!=ETYPE)
310 return(block(AMPER,incref(t),p->subsp,p->strp,p));
311 return(p);
312}
313
314/*
315 * A mention of an array is turned into
316 * a pointer to the base of the array.
317 */
318struct tnode *
319disarray(ap)
320struct tnode *ap;
321{
322 register int t;
323 register struct tnode *p;
324
325 p = ap;
326 /* check array & not MOS and not typer */
327 if (((t = p->type)&XTYPE)!=ARRAY || p->op==NAME&&p->tr1->hclass==MOS
328 || p->op==ETYPE)
329 return(p);
330 p->subsp++;
331 *cp++ = p;
332 setype(p, decref(t), p);
333 build(AMPER);
334 return(*--cp);
335}
336
337/*
338 * make sure that p is a ptr to a node
339 * with type int or char or 'okt.'
340 * okt might be nonexistent or 'long'
341 * (e.g. for <<).
342 */
343chkw(p, okt)
344struct tnode *p;
345{
346 register int t;
347
348 if ((t=p->type)!=INT && t<PTR && t!=CHAR && t!=UNSIGN && t!=okt)
349 error("Illegal type of operand");
350 return;
351}
352
353/*
354 *'linearize' a type for looking up in the
355 * conversion table
356 */
357lintyp(t)
358{
359 switch(t) {
360
361 case INT:
362 case CHAR:
363 case UNSIGN:
364 return(0);
365
366 case FLOAT:
367 case DOUBLE:
368 return(1);
369
370 case LONG:
371 return(2);
372
373 default:
374 return(3);
375 }
376}
377
378/*
379 * Report an error.
380 */
381error(s, p1, p2, p3, p4, p5, p6)
382{
383 nerror++;
384 if (filename[0])
385 fprintf(stderr, "%s:", filename);
386 fprintf(stderr, "%d: ", line);
387 fprintf(stderr, s, p1, p2, p3, p4, p5, p6);
388 fprintf(stderr, "\n");
389}
390
391/*
392 * Generate a node in an expression tree,
393 * setting the operator, type, dimen/struct table ptrs,
394 * and the operands.
395 */
396struct tnode *
397block(op, t, subs, str, p1,p2)
398int *subs;
399struct str *str;
400struct tnode *p1, *p2;
401{
402 register struct tnode *p;
403
404 p = gblock(sizeof(*p));
405 p->op = op;
406 p->type = t;
407 p->subsp = subs;
408 p->strp = str;
409 p->tr1 = p1;
410 if (opdope[op]&BINARY)
411 p->tr2 = p2;
412 else
413 p->tr2 = NULL;
414 return(p);
415}
416
417struct tnode *
418nblock(ads)
419struct hshtab *ads;
420{
421 register struct hshtab *ds;
422
423 ds = ads;
424 return(block(NAME, ds->htype, ds->hsubsp, ds->hstrp, ds));
425}
426
427/*
428 * Generate a block for a constant
429 */
430struct cnode *
431cblock(v)
432{
433 register struct cnode *p;
434
435 p = gblock(sizeof(*p));
436 p->op = CON;
437 p->type = INT;
438 p->subsp = NULL;
439 p->strp = NULL;
440 p->value = v;
441 return(p);
442}
443
444/*
445 * A block for a float or long constant
446 */
447struct fnode *
448fblock(t, string)
449char *string;
450{
451 register struct fnode *p;
452
453 p = gblock(sizeof(*p));
454 p->op = FCON;
455 p->type = t;
456 p->subsp = NULL;
457 p->strp = NULL;
458 p->cstr = string;
459 return(p);
460}
461
462/*
463 * Assign a block for use in the
464 * expression tree.
465 */
466char *
467gblock(n)
468{
469 register int *p;
470
471 p = curbase;
472 if ((curbase =+ n) >= coremax) {
473 if (sbrk(1024) == -1) {
474 error("Out of space");
475 exit(1);
476 }
477 coremax =+ 1024;
478 }
479 return(p);
480}
481
482/*
483 * Check that a tree can be used as an lvalue.
484 */
485chklval(ap)
486struct tnode *ap;
487{
488 register struct tnode *p;
489
490 p = ap;
491 if (p->op==FSEL)
492 p = p->tr1;
493 if (p->op!=NAME && p->op!=STAR)
494 error("Lvalue required");
495}
496
497/*
498 * reduce some forms of `constant op constant'
499 * to a constant. More of this is done in the next pass
500 * but this is used to allow constant expressions
501 * to be used in switches and array bounds.
502 */
503fold(op, ap1, ap2)
504struct tnode *ap1, *ap2;
505{
506 register struct tnode *p1;
507 register int v1, v2;
508 int unsignf;
509
510 p1 = ap1;
511 if (p1->op!=CON)
512 return(0);
513 unsignf = p1->type==UNSIGN;
514 if (op==QUEST) {
515 if (ap2->tr1->op==CON && ap2->tr2->op==CON) {
516 p1->value = p1->value? ap2->tr1->value: ap2->tr2->value;
517 *cp++ = p1;
518 return(1);
519 }
520 return(0);
521 }
522 if (ap2) {
523 if (ap2->op!=CON)
524 return(0);
525 v2 = ap2->value;
526 unsignf |= ap2->type==UNSIGN;
527 }
528 v1 = p1->value;
529 switch (op) {
530
531 case PLUS:
532 v1 =+ v2;
533 break;
534
535 case MINUS:
536 v1 =- v2;
537 break;
538
539 case TIMES:
540 v1 =* v2;
541 break;
542
543 case DIVIDE:
544 if (v2==0)
545 goto divchk;
546 if (unsignf) {
547 v1 = (unsigned)v1 / v2;
548 break;
549 }
550 v1 =/ v2;
551 break;
552
553 case MOD:
554 if (v2==0)
555 goto divchk;
556 if (unsignf) {
557 v1 = (unsigned)v1 % v2;
558 break;
559 }
560 v1 =% v2;
561 break;
562
563 case AND:
564 v1 =& v2;
565 break;
566
567 case OR:
568 v1 =| v2;
569 break;
570
571 case EXOR:
572 v1 =^ v2;
573 break;
574
575 case NEG:
576 v1 = - v1;
577 break;
578
579 case COMPL:
580 v1 = ~ v1;
581 break;
582
583 case LSHIFT:
584 v1 =<< v2;
585 break;
586
587 case RSHIFT:
588 if (unsignf) {
589 v1 = (unsigned)v1 >> v2;
590 break;
591 }
592 v1 =>> v2;
593 break;
594
595 case EQUAL:
596 v1 = v1==v2;
597 break;
598
599 case NEQUAL:
600 v1 = v1!=v2;
601 break;
602
603 case LESS:
604 v1 = v1<v2;
605 break;
606
607 case GREAT:
608 v1 = v1>v2;
609 break;
610
611 case LESSEQ:
612 v1 = v1<=v2;
613 break;
614
615 case GREATEQ:
616 v1 = v1>=v2;
617 break;
618
619 divchk:
620 error("Divide check");
621 default:
622 return(0);
623 }
624 p1->value = v1;
625 *cp++ = p1;
626 return(1);
627}
628
629/*
630 * Compile an expression expected to have constant value,
631 * for example an array bound or a case value.
632 */
633conexp()
634{
635 register struct tnode *t;
636
637 initflg++;
638 if (t = tree())
639 if (t->op != CON)
640 error("Constant required");
641 initflg--;
642 curbase = funcbase;
643 return(t->value);
644}