cc: fix getting local variable type
[neatcc/cc.git] / cc.c
blobf196418f2c98334ce233307ff770817b44de3a2f
1 #include <fcntl.h>
2 #include <unistd.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <sys/stat.h>
6 #include <sys/types.h>
7 #include "gen.h"
8 #include "tok.h"
10 #define MAXLOCALS (1 << 10)
11 #define MAXARGS (1 << 5)
12 #define print(s) write(2, (s), strlen(s));
14 #define TYPE_BT(t) ((t)->ptr ? 8 : (t)->bt)
15 #define TYPE_SZ(t) ((t)->ptr ? 8 : (t)->bt & BT_SZMASK)
16 #define TYPE_DEREF_BT(t) ((t)->ptr > 1 ? 8 : (t)->bt)
17 #define TYPE_DEREF_SZ(t) ((t)->ptr > 1 ? 8 : (t)->bt & BT_SZMASK)
19 #define T_ARRAY 0x01
21 struct type {
22 unsigned bt;
23 unsigned flags;
24 int ptr;
27 /* type stack */
28 static struct type ts[MAXTMP];
29 static int nts;
31 static void ts_push_bt(unsigned bt)
33 ts[nts].ptr = 0;
34 ts[nts].flags = 0;
35 ts[nts++].bt = bt;
38 static void ts_push(struct type *type)
40 ts[nts++] = *type;
43 static void ts_pop(struct type *type)
45 nts--;
46 if (type)
47 *type = ts[nts];
50 static struct local {
51 char name[NAMELEN];
52 long addr;
53 struct type type;
54 } locals[MAXLOCALS];
55 static int nlocals;
57 static void local_add(char *name, long addr, struct type type)
59 strcpy(locals[nlocals].name, name);
60 locals[nlocals].addr = addr;
61 locals[nlocals].type = type;
62 nlocals++;
65 static void die(char *s)
67 print(s);
68 exit(1);
71 static int tok_jmp(int tok)
73 if (tok_see() != tok)
74 return 1;
75 tok_get();
76 return 0;
79 static void tok_expect(int tok)
81 if (tok_get() != tok)
82 die("syntax error\n");
85 static void readexpr(void);
87 static int basetype(struct type *type)
89 int sign = 1;
90 int size = 4;
91 int done = 0;
92 int i = 0;
93 while (!done) {
94 switch (tok_see()) {
95 case TOK_VOID:
96 sign = 0;
97 size = 0;
98 done = 1;
99 break;
100 case TOK_INT:
101 done = 1;
102 break;
103 case TOK_CHAR:
104 size = 1;
105 done = 1;
106 break;
107 case TOK_SHORT:
108 size = 2;
109 break;
110 case TOK_LONG:
111 size = 8;
112 break;
113 case TOK_UNSIGNED:
114 sign = 0;
115 break;
116 case TOK_ENUM:
117 case TOK_STRUCT:
118 tok_expect(TOK_NAME);
119 done = 1;
120 break;
121 default:
122 if (!i)
123 return 1;
124 done = 1;
125 continue;
127 i++;
128 tok_get();
130 type->bt = size | (sign ? BT_SIGNED : 0);
131 type->ptr = 0;
132 return 0;
135 static void readptrs(struct type *type)
137 while (!tok_jmp('*'))
138 type->ptr++;
141 static int readtype(struct type *type)
143 if (basetype(type))
144 return 1;
145 readptrs(type);
146 return 0;
149 static void readprimary(void)
151 int i;
152 if (!tok_jmp(TOK_NUM)) {
153 ts_push_bt(4 | BT_SIGNED);
154 o_num(atoi(tok_id()), 4 | BT_SIGNED);
155 return;
157 if (!tok_jmp(TOK_NAME)) {
158 for (i = 0; i < nlocals; i++) {
159 struct type *t = &locals[i].type;
160 if (!strcmp(locals[i].name, tok_id())) {
161 ts_push(t);
162 o_local(locals[i].addr, TYPE_BT(t));
163 if (t->flags & T_ARRAY)
164 o_addr();
165 return;
168 ts_push_bt(8);
169 o_symaddr(tok_id(), 8);
170 return;
172 if (!tok_jmp('(')) {
173 readexpr();
174 tok_expect(')');
175 return;
179 void arrayderef(unsigned bt)
181 if (BT_SZ(bt) > 1) {
182 o_num(BT_SZ(bt), 4);
183 o_mul();
185 o_add();
186 o_deref(bt);
189 static void inc_post(void (*op)(void))
191 struct type *t = &ts[nts - 1];
192 o_tmpcopy();
193 o_load();
194 o_tmpswap();
195 o_tmpcopy();
196 o_num(1, 4);
197 op();
198 o_assign(t->bt);
199 o_tmpdrop(1);
200 return;
203 static void readpost(void)
205 readprimary();
206 if (!tok_jmp('[')) {
207 struct type t1;
208 ts_pop(&t1);
209 readexpr();
210 ts_pop(NULL);
211 tok_expect(']');
212 arrayderef(TYPE_DEREF_BT(&t1));
213 t1.ptr--;
214 ts_push(&t1);
215 return;
217 if (!tok_jmp('(')) {
218 int argc = 0;
219 unsigned bt[MAXARGS];
220 if (tok_see() != ')') {
221 readexpr();
222 bt[argc++] = 4 | BT_SIGNED;
223 ts_pop(NULL);
225 while (!tok_jmp(',')) {
226 readexpr();
227 bt[argc++] = 4 | BT_SIGNED;
228 ts_pop(NULL);
230 tok_expect(')');
231 ts_pop(NULL);
232 o_call(argc, bt, 4 | BT_SIGNED);
233 ts_push_bt(4 | BT_SIGNED);
234 return;
236 if (!tok_jmp(TOK2("++"))) {
237 inc_post(o_add);
238 return;
240 if (!tok_jmp(TOK2("--"))) {
241 inc_post(o_sub);
242 return;
246 static void inc_pre(void (*op)(void))
248 struct type *t = &ts[nts - 1];
249 readpost();
250 o_tmpcopy();
251 o_num(1, 4);
252 op();
253 o_assign(t->bt);
256 static void readpre(void)
258 if (!tok_jmp('&')) {
259 struct type type;
260 readpost();
261 ts_pop(&type);
262 type.ptr++;
263 ts_push(&type);
264 o_addr();
265 return;
267 if (!tok_jmp('*')) {
268 struct type type;
269 readpost();
270 ts_pop(&type);
271 type.ptr--;
272 ts_push(&type);
273 o_deref(TYPE_BT(&type));
274 return;
276 if (!tok_jmp('!')) {
277 struct type type;
278 readpost();
279 ts_pop(&type);
280 o_num(0, TYPE_BT(&type));
281 o_eq();
282 ts_push_bt(4 | BT_SIGNED);
283 return;
285 if (!tok_jmp('-')) {
286 readpost();
287 o_neg();
288 return;
290 if (!tok_jmp('~')) {
291 readpost();
292 o_not();
293 return;
295 if (!tok_jmp(TOK2("++"))) {
296 inc_pre(o_add);
297 return;
299 if (!tok_jmp(TOK2("--"))) {
300 inc_pre(o_sub);
301 return;
303 readpost();
306 static int shifts(int n)
308 int i = -1;
309 while (i++ < 16)
310 if (n == 1 << i)
311 break;
312 return i;
315 static unsigned bt_op(unsigned bt1, unsigned bt2)
317 unsigned s1 = BT_SZ(bt1);
318 unsigned s2 = BT_SZ(bt2);
319 return (bt1 | bt2) & BT_SIGNED | (s1 > s2 ? s1 : s2);
322 static void ts_binop(void (*o_sth)(void))
324 struct type t1, t2;
325 ts_pop(&t1);
326 ts_pop(&t2);
327 o_sth();
328 ts_push_bt(bt_op(TYPE_BT(&t1), TYPE_BT(&t2)));
331 static void ts_binop_add(void (*o_sth)(void))
333 struct type t1, t2;
334 ts_pop(&t1);
335 ts_pop(&t2);
336 if (!t1.ptr && !t2.ptr) {
337 o_sth();
338 ts_push_bt(bt_op(TYPE_BT(&t1), TYPE_BT(&t2)));
339 return;
341 if (t1.ptr && !t2.ptr) {
342 struct type t = t2;
343 t2 = t1;
344 t1 = t;
345 o_tmpswap();
347 if (!t1.ptr && t2.ptr)
348 if (TYPE_DEREF_SZ(&t2) > 1) {
349 o_num(shifts(TYPE_DEREF_SZ(&t2)), 1);
350 o_shl();
352 o_sth();
353 if (t1.ptr && t2.ptr) {
354 o_num(shifts(TYPE_DEREF_SZ(&t1)), 1);
355 o_shr();
356 ts_push_bt(4 | BT_SIGNED);
357 } else {
358 ts_push(&t2);
362 static void readmul(void)
364 readpre();
365 while (1) {
366 if (!tok_jmp('*')) {
367 readpre();
368 ts_binop(o_mul);
369 continue;
371 if (!tok_jmp('/')) {
372 readpre();
373 ts_binop(o_div);
374 continue;
376 if (!tok_jmp('%')) {
377 readpre();
378 ts_binop(o_mod);
379 continue;
381 break;
385 static void readadd(void)
387 readmul();
388 while (1) {
389 if (!tok_jmp('+')) {
390 readmul();
391 ts_binop_add(o_add);
392 continue;
394 if (!tok_jmp('-')) {
395 readmul();
396 ts_binop_add(o_sub);
397 continue;
399 break;
403 static void shift(void (*op)(void))
405 struct type t;
406 readadd();
407 ts_pop(NULL);
408 ts_pop(&t);
409 op();
410 ts_push_bt(TYPE_BT(&t));
413 static void readshift(void)
415 readadd();
416 if (!tok_jmp(TOK2("<<"))) {
417 shift(o_shl);
418 return;
420 if (!tok_jmp(TOK2(">>"))) {
421 shift(o_shr);
422 return;
426 static void cmp(void (*op)(void))
428 readshift();
429 ts_pop(NULL);
430 ts_pop(NULL);
431 op();
432 ts_push_bt(4 | BT_SIGNED);
435 static void readcmp(void)
437 readshift();
438 if (!tok_jmp('<')) {
439 cmp(o_lt);
440 return;
442 if (!tok_jmp('>')) {
443 cmp(o_gt);
444 return;
446 if (!tok_jmp(TOK2("<="))) {
447 cmp(o_le);
448 return;
450 if (!tok_jmp(TOK2(">="))) {
451 cmp(o_ge);
452 return;
456 static void eq(void (*op)(void))
458 readcmp();
459 ts_pop(NULL);
460 ts_pop(NULL);
461 op();
462 ts_push_bt(4 | BT_SIGNED);
465 static void readeq(void)
467 readcmp();
468 if (!tok_jmp(TOK2("=="))) {
469 eq(o_eq);
470 return;
472 if (!tok_jmp(TOK2("!="))) {
473 eq(o_neq);
474 return;
478 static void readbitand(void)
480 readeq();
481 while (!tok_jmp('&')) {
482 readeq();
483 ts_binop(o_and);
487 static void readxor(void)
489 readbitand();
490 while (!tok_jmp('^')) {
491 readbitand();
492 ts_binop(o_xor);
496 static void readbitor(void)
498 readxor();
499 while (!tok_jmp('|')) {
500 readxor();
501 ts_binop(o_or);
505 static void readcexpr(void)
507 readbitor();
508 if (!tok_jmp('?')) {
509 long l1, l2;
510 l1 = o_jz(0);
511 ts_pop(NULL);
512 readbitor();
513 o_tmpfork();
514 l2 = o_jmp(0);
515 ts_pop(NULL);
516 tok_expect(':');
517 o_filljmp(l1);
518 readbitor();
519 o_tmpjoin();
520 o_filljmp(l2);
524 static void opassign(void (*op)(void))
526 unsigned bt = TYPE_BT(&ts[nts - 1]);
527 o_tmpcopy();
528 readexpr();
529 op();
530 o_assign(bt);
533 static void readexpr(void)
535 readcexpr();
536 if (!tok_jmp('=')) {
537 readexpr();
538 o_assign(TYPE_BT(&ts[nts - 1]));
539 return;
541 if (!tok_jmp(TOK2("+="))) {
542 opassign(o_add);
543 return;
545 if (!tok_jmp(TOK2("-="))) {
546 opassign(o_sub);
547 return;
549 if (!tok_jmp(TOK2("*="))) {
550 opassign(o_mul);
551 return;
553 if (!tok_jmp(TOK2("/="))) {
554 opassign(o_div);
555 return;
557 if (!tok_jmp(TOK2("%="))) {
558 opassign(o_mod);
559 return;
561 if (!tok_jmp(TOK3("<<="))) {
562 opassign(o_shl);
563 return;
565 if (!tok_jmp(TOK3(">>="))) {
566 opassign(o_shr);
567 return;
571 static void readestmt(void)
573 do {
574 o_tmpdrop(-1);
575 nts = 0;
576 readexpr();
577 } while (!tok_jmp(','));
580 static void readstmt(void)
582 struct type base = {0};
583 o_tmpdrop(-1);
584 nts = 0;
585 if (!tok_jmp('{')) {
586 while (tok_jmp('}'))
587 readstmt();
588 return;
590 if (!basetype(&base)) {
591 struct type type = base;
592 char name[NAMELEN];
593 int n = 1;
594 readptrs(&type);
595 tok_expect(TOK_NAME);
596 strcpy(name, tok_id());
597 if (!tok_jmp('[')) {
598 tok_expect(TOK_NUM);
599 n = atoi(tok_id());
600 type.ptr++;
601 type.flags = T_ARRAY;
602 tok_expect(']');
604 local_add(name, o_mklocal(TYPE_SZ(&type) * n), type);
605 /* initializer */
606 if (!tok_jmp('=')) {
607 struct type *t = &locals[nlocals - 1].type;
608 o_local(locals[nlocals - 1].addr, TYPE_BT(t));
609 readexpr();
610 ts_pop(NULL);
611 ts_push_bt(TYPE_BT(t));
612 o_assign(TYPE_BT(t));
614 tok_expect(';');
615 return;
617 if (!tok_jmp(TOK_IF)) {
618 long l1, l2;
619 tok_expect('(');
620 readexpr();
621 tok_expect(')');
622 l1 = o_jz(0);
623 readstmt();
624 if (!tok_jmp(TOK_ELSE)) {
625 l2 = o_jmp(0);
626 o_filljmp(l1);
627 readstmt();
628 o_filljmp(l2);
629 } else {
630 o_filljmp(l1);
632 return;
634 if (!tok_jmp(TOK_WHILE)) {
635 long l1, l2;
636 l1 = o_mklabel();
637 tok_expect('(');
638 readexpr();
639 tok_expect(')');
640 l2 = o_jz(0);
641 readstmt();
642 o_jz(l1);
643 o_filljmp(l2);
644 return;
646 if (!tok_jmp(TOK_FOR)) {
647 long check, jump, end, body;
648 tok_expect('(');
649 if (tok_see() != ';')
650 readestmt();
651 tok_expect(';');
652 check = o_mklabel();
653 if (tok_see() != ';')
654 readestmt();
655 tok_expect(';');
656 end = o_jz(0);
657 body = o_jmp(0);
658 jump = o_mklabel();
659 if (tok_see() != ')')
660 readestmt();
661 tok_expect(')');
662 o_jmp(check);
663 o_filljmp(body);
664 readstmt();
665 o_jmp(jump);
666 o_filljmp(end);
667 return;
669 if (!tok_jmp(TOK_RETURN)) {
670 int ret = tok_see() != ';';
671 if (ret)
672 readexpr();
673 tok_expect(';');
674 o_ret(4 | BT_SIGNED);
675 return;
677 readestmt();
678 tok_expect(';');
681 static void readdecl(void)
683 char name[NAMELEN];
684 struct type type;
685 readtype(&type);
686 tok_expect(TOK_NAME);
687 strcpy(name, tok_id());
688 if (!tok_jmp(';'))
689 return;
690 if (!tok_jmp('(')) {
691 /* read args */
692 char args[MAXARGS][NAMELEN];
693 struct type types[MAXARGS];
694 int nargs = 0;
695 int i;
696 while (tok_see() != ')') {
697 readtype(&types[nargs]);
698 if (!tok_jmp(TOK_NAME))
699 strcpy(args[nargs++], tok_id());
700 if (tok_jmp(','))
701 break;
703 tok_expect(')');
704 if (!tok_jmp(';'))
705 return;
706 o_func_beg(name);
707 for (i = 0; i < nargs; i++)
708 local_add(args[i], o_arg(i, TYPE_BT(&types[i])),
709 types[i]);
710 readstmt();
711 o_func_end();
712 return;
714 die("syntax error\n");
717 static void parse(void)
719 while (tok_see() != TOK_EOF)
720 readdecl();
723 int main(int argc, char *argv[])
725 char obj[128];
726 char *src = argv[1];
727 int ifd, ofd;
728 ifd = open(src, O_RDONLY);
729 tok_init(ifd);
730 close(ifd);
731 parse();
733 strcpy(obj, src);
734 obj[strlen(obj) - 1] = 'o';
735 ofd = open(obj, O_WRONLY | O_TRUNC | O_CREAT, 0600);
736 out_write(ofd);
737 close(ofd);
738 return 0;