add support for global variables
[neatcc.git] / cc.c
blob5fd21c58f2d51752d277cab6ac7e6a186af9cef1
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 MAXGLOBALS (1 << 10)
12 #define MAXARGS (1 << 5)
13 #define print(s) write(2, (s), strlen(s));
15 #define TYPE_BT(t) ((t)->ptr ? 8 : (t)->bt)
16 #define TYPE_SZ(t) ((t)->ptr ? 8 : (t)->bt & BT_SZMASK)
17 #define TYPE_DEREF_BT(t) ((t)->ptr > 1 ? 8 : (t)->bt)
18 #define TYPE_DEREF_SZ(t) ((t)->ptr > 1 ? 8 : (t)->bt & BT_SZMASK)
20 #define T_ARRAY 0x01
22 struct type {
23 unsigned bt;
24 unsigned flags;
25 int ptr;
26 int n;
29 /* type stack */
30 static struct type ts[MAXTMP];
31 static int nts;
33 static void ts_push_bt(unsigned bt)
35 ts[nts].ptr = 0;
36 ts[nts].flags = 0;
37 ts[nts++].bt = bt;
40 static void ts_push(struct type *type)
42 ts[nts++] = *type;
45 static void ts_pop(struct type *type)
47 nts--;
48 if (type)
49 *type = ts[nts];
52 static int type_totsz(struct type *t)
54 if (!t->ptr || t->flags & T_ARRAY && (t)->ptr == 1)
55 return BT_SZ(t->bt) * t->n;
56 return 8;
59 struct name {
60 char name[NAMELEN];
61 struct type type;
62 long addr;
65 static struct name locals[MAXLOCALS];
66 static int nlocals;
67 static struct name globals[MAXGLOBALS];
68 static int nglobals;
70 static void local_add(struct name *name)
72 memcpy(&locals[nlocals++], name, sizeof(*name));
75 static void global_add(struct name *name)
77 memcpy(&globals[nglobals++], name, sizeof(*name));
80 static void die(char *s)
82 print(s);
83 exit(1);
86 static int tok_jmp(int tok)
88 if (tok_see() != tok)
89 return 1;
90 tok_get();
91 return 0;
94 static void tok_expect(int tok)
96 if (tok_get() != tok)
97 die("syntax error\n");
100 static void readexpr(void);
102 static int basetype(struct type *type)
104 int sign = 1;
105 int size = 4;
106 int done = 0;
107 int i = 0;
108 while (!done) {
109 switch (tok_see()) {
110 case TOK_VOID:
111 sign = 0;
112 size = 0;
113 done = 1;
114 break;
115 case TOK_INT:
116 done = 1;
117 break;
118 case TOK_CHAR:
119 size = 1;
120 done = 1;
121 break;
122 case TOK_SHORT:
123 size = 2;
124 break;
125 case TOK_LONG:
126 size = 8;
127 break;
128 case TOK_UNSIGNED:
129 sign = 0;
130 break;
131 case TOK_ENUM:
132 case TOK_STRUCT:
133 tok_expect(TOK_NAME);
134 done = 1;
135 break;
136 default:
137 if (!i)
138 return 1;
139 done = 1;
140 continue;
142 i++;
143 tok_get();
145 type->bt = size | (sign ? BT_SIGNED : 0);
146 type->ptr = 0;
147 type->n = 1;
148 return 0;
151 static void readptrs(struct type *type)
153 while (!tok_jmp('*'))
154 type->ptr++;
157 static int readtype(struct type *type)
159 if (basetype(type))
160 return 1;
161 readptrs(type);
162 return 0;
165 static void readprimary(void)
167 struct name name;
168 int i;
169 if (!tok_jmp(TOK_NUM)) {
170 ts_push_bt(4 | BT_SIGNED);
171 o_num(tok_num(), 4 | BT_SIGNED);
172 return;
174 if (!tok_jmp(TOK_NAME)) {
175 for (i = 0; i < nlocals; i++) {
176 struct type *t = &locals[i].type;
177 if (!strcmp(locals[i].name, tok_id())) {
178 ts_push(t);
179 o_local(locals[i].addr, TYPE_BT(t));
180 if (t->flags & T_ARRAY)
181 o_addr();
182 return;
185 for (i = 0; i < nglobals; i++) {
186 struct type *t = &globals[i].type;
187 if (!strcmp(globals[i].name, tok_id())) {
188 ts_push(t);
189 o_symaddr(globals[i].addr, TYPE_BT(t));
190 if (t->flags & T_ARRAY)
191 o_addr();
192 return;
195 strcpy(name.name, tok_id());
196 name.addr = o_mkundef(name.name);
197 global_add(&name);
198 ts_push_bt(8);
199 o_symaddr(name.addr, 8);
200 return;
202 if (!tok_jmp('(')) {
203 readexpr();
204 tok_expect(')');
205 return;
209 void arrayderef(unsigned bt)
211 if (BT_SZ(bt) > 1) {
212 o_num(BT_SZ(bt), 4);
213 o_mul();
215 o_add();
216 o_deref(bt);
219 static void inc_post(void (*op)(void))
221 struct type *t = &ts[nts - 1];
222 o_tmpcopy();
223 o_load();
224 o_tmpswap();
225 o_tmpcopy();
226 o_num(1, 4);
227 op();
228 o_assign(t->bt);
229 o_tmpdrop(1);
230 return;
233 static void readpost(void)
235 readprimary();
236 if (!tok_jmp('[')) {
237 struct type t1;
238 ts_pop(&t1);
239 readexpr();
240 ts_pop(NULL);
241 tok_expect(']');
242 arrayderef(TYPE_DEREF_BT(&t1));
243 t1.ptr--;
244 ts_push(&t1);
245 return;
247 if (!tok_jmp('(')) {
248 int argc = 0;
249 unsigned bt[MAXARGS];
250 if (tok_see() != ')') {
251 readexpr();
252 bt[argc++] = 4 | BT_SIGNED;
253 ts_pop(NULL);
255 while (!tok_jmp(',')) {
256 readexpr();
257 bt[argc++] = 4 | BT_SIGNED;
258 ts_pop(NULL);
260 tok_expect(')');
261 ts_pop(NULL);
262 o_call(argc, bt, 4 | BT_SIGNED);
263 ts_push_bt(4 | BT_SIGNED);
264 return;
266 if (!tok_jmp(TOK2("++"))) {
267 inc_post(o_add);
268 return;
270 if (!tok_jmp(TOK2("--"))) {
271 inc_post(o_sub);
272 return;
276 static void inc_pre(void (*op)(void))
278 struct type *t = &ts[nts - 1];
279 readpost();
280 o_tmpcopy();
281 o_num(1, 4);
282 op();
283 o_assign(t->bt);
286 static void readpre(void)
288 if (!tok_jmp('&')) {
289 struct type type;
290 readpost();
291 ts_pop(&type);
292 type.ptr++;
293 ts_push(&type);
294 o_addr();
295 return;
297 if (!tok_jmp('*')) {
298 struct type type;
299 readpost();
300 ts_pop(&type);
301 type.ptr--;
302 ts_push(&type);
303 o_deref(TYPE_BT(&type));
304 return;
306 if (!tok_jmp('!')) {
307 struct type type;
308 readpost();
309 ts_pop(&type);
310 o_lnot();
311 ts_push_bt(4 | BT_SIGNED);
312 return;
314 if (!tok_jmp('-')) {
315 readpost();
316 o_neg();
317 return;
319 if (!tok_jmp('~')) {
320 readpost();
321 o_not();
322 return;
324 if (!tok_jmp(TOK2("++"))) {
325 inc_pre(o_add);
326 return;
328 if (!tok_jmp(TOK2("--"))) {
329 inc_pre(o_sub);
330 return;
332 readpost();
335 static int shifts(int n)
337 int i = -1;
338 while (i++ < 16)
339 if (n == 1 << i)
340 break;
341 return i;
344 static unsigned bt_op(unsigned bt1, unsigned bt2)
346 unsigned s1 = BT_SZ(bt1);
347 unsigned s2 = BT_SZ(bt2);
348 return (bt1 | bt2) & BT_SIGNED | (s1 > s2 ? s1 : s2);
351 static void ts_binop(void (*o_sth)(void))
353 struct type t1, t2;
354 ts_pop(&t1);
355 ts_pop(&t2);
356 o_sth();
357 ts_push_bt(bt_op(TYPE_BT(&t1), TYPE_BT(&t2)));
360 static void ts_binop_add(void (*o_sth)(void))
362 struct type t1, t2;
363 ts_pop(&t1);
364 ts_pop(&t2);
365 if (!t1.ptr && !t2.ptr) {
366 o_sth();
367 ts_push_bt(bt_op(TYPE_BT(&t1), TYPE_BT(&t2)));
368 return;
370 if (t1.ptr && !t2.ptr) {
371 struct type t = t2;
372 t2 = t1;
373 t1 = t;
374 o_tmpswap();
376 if (!t1.ptr && t2.ptr)
377 if (TYPE_DEREF_SZ(&t2) > 1) {
378 o_num(shifts(TYPE_DEREF_SZ(&t2)), 1);
379 o_shl();
381 o_sth();
382 if (t1.ptr && t2.ptr) {
383 o_num(shifts(TYPE_DEREF_SZ(&t1)), 1);
384 o_shr();
385 ts_push_bt(4 | BT_SIGNED);
386 } else {
387 ts_push(&t2);
391 static void readmul(void)
393 readpre();
394 while (1) {
395 if (!tok_jmp('*')) {
396 readpre();
397 ts_binop(o_mul);
398 continue;
400 if (!tok_jmp('/')) {
401 readpre();
402 ts_binop(o_div);
403 continue;
405 if (!tok_jmp('%')) {
406 readpre();
407 ts_binop(o_mod);
408 continue;
410 break;
414 static void readadd(void)
416 readmul();
417 while (1) {
418 if (!tok_jmp('+')) {
419 readmul();
420 ts_binop_add(o_add);
421 continue;
423 if (!tok_jmp('-')) {
424 readmul();
425 ts_binop_add(o_sub);
426 continue;
428 break;
432 static void shift(void (*op)(void))
434 struct type t;
435 readadd();
436 ts_pop(NULL);
437 ts_pop(&t);
438 op();
439 ts_push_bt(TYPE_BT(&t));
442 static void readshift(void)
444 readadd();
445 if (!tok_jmp(TOK2("<<"))) {
446 shift(o_shl);
447 return;
449 if (!tok_jmp(TOK2(">>"))) {
450 shift(o_shr);
451 return;
455 static void cmp(void (*op)(void))
457 readshift();
458 ts_pop(NULL);
459 ts_pop(NULL);
460 op();
461 ts_push_bt(4 | BT_SIGNED);
464 static void readcmp(void)
466 readshift();
467 if (!tok_jmp('<')) {
468 cmp(o_lt);
469 return;
471 if (!tok_jmp('>')) {
472 cmp(o_gt);
473 return;
475 if (!tok_jmp(TOK2("<="))) {
476 cmp(o_le);
477 return;
479 if (!tok_jmp(TOK2(">="))) {
480 cmp(o_ge);
481 return;
485 static void eq(void (*op)(void))
487 readcmp();
488 ts_pop(NULL);
489 ts_pop(NULL);
490 op();
491 ts_push_bt(4 | BT_SIGNED);
494 static void readeq(void)
496 readcmp();
497 if (!tok_jmp(TOK2("=="))) {
498 eq(o_eq);
499 return;
501 if (!tok_jmp(TOK2("!="))) {
502 eq(o_neq);
503 return;
507 static void readbitand(void)
509 readeq();
510 while (!tok_jmp('&')) {
511 readeq();
512 ts_binop(o_and);
516 static void readxor(void)
518 readbitand();
519 while (!tok_jmp('^')) {
520 readbitand();
521 ts_binop(o_xor);
525 static void readbitor(void)
527 readxor();
528 while (!tok_jmp('|')) {
529 readxor();
530 ts_binop(o_or);
534 #define MAXCOND (1 << 5)
536 static void readand(void)
538 long conds[MAXCOND];
539 int nconds = 0;
540 long passed;
541 int i;
542 readbitor();
543 if (tok_see() != TOK2("&&"))
544 return;
545 conds[nconds++] = o_jz(0);
546 ts_pop(NULL);
547 while (!tok_jmp(TOK2("&&"))) {
548 readbitor();
549 conds[nconds++] = o_jz(0);
550 ts_pop(NULL);
552 o_num(1, 4 | BT_SIGNED);
553 o_tmpfork();
554 passed = o_jmp(0);
555 for (i = 0; i < nconds; i++)
556 o_filljmp(conds[i]);
557 o_num(0, 4 | BT_SIGNED);
558 o_tmpjoin();
559 o_filljmp(passed);
560 ts_push_bt(4 | BT_SIGNED);
563 static void reador(void)
565 long conds[MAXCOND];
566 int nconds = 0;
567 long failed;
568 int i;
569 readand();
570 if (tok_see() != TOK2("||"))
571 return;
572 conds[nconds++] = o_jnz(0);
573 ts_pop(NULL);
574 while (!tok_jmp(TOK2("||"))) {
575 readand();
576 conds[nconds++] = o_jnz(0);
577 ts_pop(NULL);
579 o_num(0, 4 | BT_SIGNED);
580 o_tmpfork();
581 failed = o_jmp(0);
582 for (i = 0; i < nconds; i++)
583 o_filljmp(conds[i]);
584 o_num(1, 4 | BT_SIGNED);
585 o_tmpjoin();
586 o_filljmp(failed);
587 ts_push_bt(4 | BT_SIGNED);
590 static void readcexpr(void)
592 reador();
593 if (!tok_jmp('?')) {
594 long l1, l2;
595 l1 = o_jz(0);
596 ts_pop(NULL);
597 reador();
598 o_tmpfork();
599 l2 = o_jmp(0);
600 ts_pop(NULL);
601 tok_expect(':');
602 o_filljmp(l1);
603 reador();
604 o_tmpjoin();
605 o_filljmp(l2);
609 static void opassign(void (*op)(void))
611 o_tmpcopy();
612 readexpr();
613 op();
614 ts_pop(NULL);
615 o_assign(TYPE_BT(&ts[nts - 1]));
618 static void readexpr(void)
620 readcexpr();
621 if (!tok_jmp('=')) {
622 readexpr();
623 ts_pop(NULL);
624 o_assign(TYPE_BT(&ts[nts - 1]));
625 return;
627 if (!tok_jmp(TOK2("+="))) {
628 opassign(o_add);
629 return;
631 if (!tok_jmp(TOK2("-="))) {
632 opassign(o_sub);
633 return;
635 if (!tok_jmp(TOK2("*="))) {
636 opassign(o_mul);
637 return;
639 if (!tok_jmp(TOK2("/="))) {
640 opassign(o_div);
641 return;
643 if (!tok_jmp(TOK2("%="))) {
644 opassign(o_mod);
645 return;
647 if (!tok_jmp(TOK3("<<="))) {
648 opassign(o_shl);
649 return;
651 if (!tok_jmp(TOK3(">>="))) {
652 opassign(o_shr);
653 return;
655 if (!tok_jmp(TOK3("&="))) {
656 opassign(o_and);
657 return;
659 if (!tok_jmp(TOK3("|="))) {
660 opassign(o_or);
661 return;
663 if (!tok_jmp(TOK3("^="))) {
664 opassign(o_xor);
665 return;
669 static void readestmt(void)
671 do {
672 o_tmpdrop(-1);
673 nts = 0;
674 readexpr();
675 } while (!tok_jmp(','));
678 static void localdef(struct name *name, int init)
680 name->addr = o_mklocal(type_totsz(&name->type));
681 local_add(name);
682 if (init) {
683 struct type *t = &name->type;
684 o_local(locals[nlocals - 1].addr, TYPE_BT(t));
685 readexpr();
686 o_assign(TYPE_BT(t));
690 static void funcdef(struct name *name, struct name *args, int nargs)
692 int i;
693 name->addr = o_func_beg(name->name);
694 global_add(name);
695 for (i = 0; i < nargs; i++) {
696 args[i].addr = o_arg(i, type_totsz(&args[i].type));
697 local_add(&args[i]);
701 static int readdefs(void (*def)(struct name *name, int init))
703 struct type base;
704 if (basetype(&base))
705 return 1;
706 while (tok_see() != ';' && tok_see() != '{') {
707 struct name name;
708 struct type *type = &name.type;
709 memcpy(type, &base, sizeof(base));
710 readptrs(type);
711 tok_expect(TOK_NAME);
712 strcpy(name.name, tok_id());
713 if (!tok_jmp('[')) {
714 tok_expect(TOK_NUM);
715 type->n = tok_num();
716 type->ptr++;
717 type->flags = T_ARRAY;
718 tok_expect(']');
720 if (!tok_jmp('(')) {
721 struct name args[MAXARGS];
722 int nargs = 0;
723 while (tok_see() != ')') {
724 readtype(&args[nargs].type);
725 if (!tok_jmp(TOK_NAME))
726 strcpy(args[nargs++].name, tok_id());
727 if (tok_jmp(','))
728 break;
730 tok_expect(')');
731 if (tok_see() != '{')
732 continue;
733 funcdef(&name, args, nargs);
734 return 0;
736 def(&name, !tok_jmp('='));
738 return 0;
741 static void readstmt(void)
743 o_tmpdrop(-1);
744 nts = 0;
745 if (!tok_jmp('{')) {
746 while (tok_jmp('}'))
747 readstmt();
748 return;
750 if (!readdefs(localdef)) {
751 tok_expect(';');
752 return;
754 if (!tok_jmp(TOK_IF)) {
755 long l1, l2;
756 tok_expect('(');
757 readexpr();
758 tok_expect(')');
759 l1 = o_jz(0);
760 readstmt();
761 if (!tok_jmp(TOK_ELSE)) {
762 l2 = o_jmp(0);
763 o_filljmp(l1);
764 readstmt();
765 o_filljmp(l2);
766 } else {
767 o_filljmp(l1);
769 return;
771 if (!tok_jmp(TOK_WHILE)) {
772 long l1, l2;
773 l1 = o_mklabel();
774 tok_expect('(');
775 readexpr();
776 tok_expect(')');
777 l2 = o_jz(0);
778 readstmt();
779 o_jz(l1);
780 o_filljmp(l2);
781 return;
783 if (!tok_jmp(TOK_FOR)) {
784 long check, jump, end, body;
785 tok_expect('(');
786 if (tok_see() != ';')
787 readestmt();
788 tok_expect(';');
789 check = o_mklabel();
790 if (tok_see() != ';')
791 readestmt();
792 tok_expect(';');
793 end = o_jz(0);
794 body = o_jmp(0);
795 jump = o_mklabel();
796 if (tok_see() != ')')
797 readestmt();
798 tok_expect(')');
799 o_jmp(check);
800 o_filljmp(body);
801 readstmt();
802 o_jmp(jump);
803 o_filljmp(end);
804 return;
806 if (!tok_jmp(TOK_RETURN)) {
807 int ret = tok_see() != ';';
808 if (ret)
809 readexpr();
810 tok_expect(';');
811 o_ret(4 | BT_SIGNED);
812 return;
814 readestmt();
815 tok_expect(';');
818 static void globaldef(struct name *name, int init)
820 name->addr = o_mkvar(name->name, type_totsz(&name->type));
821 global_add(name);
824 static void readdecl(void)
826 readdefs(globaldef);
827 if (tok_see() == '{') {
828 readstmt();
829 o_func_end();
830 nlocals = 0;
831 return;
833 tok_expect(';');
836 static void parse(void)
838 while (tok_see() != TOK_EOF)
839 readdecl();
842 int main(int argc, char *argv[])
844 char obj[128];
845 char *src = argv[1];
846 int ifd, ofd;
847 ifd = open(src, O_RDONLY);
848 tok_init(ifd);
849 close(ifd);
850 parse();
852 strcpy(obj, src);
853 obj[strlen(obj) - 1] = 'o';
854 ofd = open(obj, O_WRONLY | O_TRUNC | O_CREAT, 0600);
855 out_write(ofd);
856 close(ofd);
857 return 0;