updated
[tinycc.git] / tcc.c
blob264e336e0adaee4090e3b8abcfbfc9000e29a455
1 #include <stdio.h>
3 #define TEXT_SIZE 20000
4 #define DATA_SIZE 2000
5 #define SYM_TABLE_SIZE 10000
6 #define VAR_TABLE_SIZE 4096
8 /* vac: offset of variables
9 vat: type of variables
10 loc : local variable index
11 glo : global variable index
12 parm : parameter variable index
13 ind : output code ptr
14 lsym: loop symbol stack
15 rsym: return symbol
16 prog: output code
17 astk: arg position stack
19 int tok, *vac, *vat, *lsym, rsym,
20 prog, ind, loc, glo, file, vt,
21 vc, *macro_stack, *macro_stack_ptr, line_num;
22 char *idtable, *idptr, *idlast, *filename;
24 /* The current value can be: */
25 #define VT_CONST 0x0002 /* constant in vc */
26 #define VT_VAR 0x0004 /* value is in eax */
27 #define VT_LOCAL 0x0008 /* offset on stack */
29 #define VT_LVAL 0x0010 /* const or var is an lvalue */
30 #define VT_CMP 0x0020 /* the value is stored in processor flags (in vc) */
31 #define VT_FORWARD 0x0040 /* value is forward reference (only used for functions) */
32 #define VT_JMP 0x0080 /* value is the consequence of jmp. bit 0 is set if inv */
34 #define VT_LVALN -17 /* ~VT_LVAL */
38 * VT_FUNC indicates a function. The return type is the stored type. A
39 * function pointer is stored as a 'char' pointer.
41 * If VT_PTRMASK is non nul, then it indicates the number of pointer
42 * iterations to reach the basic type.
44 * Basic types:
46 * VT_BYTE indicate a char
49 * otherwise integer type is assumed.
50 * */
52 #define VT_BYTE 0x00001 /* byte pointer. HARDCODED VALUE */
53 #define VT_PTRMASK 0x00f00 /* pointer mask */
54 #define VT_PTRINC 0x00100 /* pointer increment */
55 #define VT_FUNC 0x01000 /* function type */
56 #define VT_TYPE 0x01f01 /* type mask */
58 #define VT_TYPEN 0xffffe0fe /* ~VT_TYPE */
59 #define VT_FUNCN -4097
61 /* Special infos */
62 #define VT_DEFINE 0x02000 /* special value for #defined symbols */
64 /* token values */
65 #define TOK_INT 256
66 #define TOK_VOID 257
67 #define TOK_CHAR 258
68 #define TOK_IF 259
69 #define TOK_ELSE 260
70 #define TOK_WHILE 261
71 #define TOK_BREAK 262
72 #define TOK_RETURN 263
73 #define TOK_DEFINE 264
74 #define TOK_MAIN 265
75 #define TOK_FOR 266
77 #define TOK_EQ 0x94 /* warning: depend on asm code */
78 #define TOK_NE 0x95 /* warning: depend on asm code */
79 #define TOK_LT 0x9c /* warning: depend on asm code */
80 #define TOK_GE 0x9d /* warning: depend on asm code */
81 #define TOK_LE 0x9e /* warning: depend on asm code */
82 #define TOK_GT 0x9f /* warning: depend on asm code */
84 #define TOK_LAND 0xa0
85 #define TOK_LOR 0xa1
87 #define TOK_DEC 0xa2
88 #define TOK_MID 0xa3 /* inc/dec, to void constant */
89 #define TOK_INC 0xa4
91 #define TOK_SHL 0xe0 /* warning: depend on asm code */
92 #define TOK_SHR 0xf8 /* warning: depend on asm code */
94 #ifdef TINY
95 #define expr_eq() expr()
96 #endif
98 int inp()
100 #if 0
101 int c;
102 c = fgetc(file);
103 printf("c=%c\n", c);
104 return c;
105 #else
106 return fgetc(file);
107 #endif
110 int isid(c)
112 return (c >= 'a' & c <= 'z') |
113 (c >= 'A' & c <= 'Z') |
114 c == '_';
117 int isnum(c)
119 return c >= '0' & c <= '9';
122 #ifndef TINY
123 /* XXX: use stderr ? */
124 void error(char *msg)
126 printf("%s:%d: %s\n", filename, line_num, msg);
127 exit(1);
130 void warning(char *msg)
132 printf("%s:%d: warning: %s\n", filename, line_num, msg);
135 void skip(c)
137 if (tok != c) {
138 printf("%s:%d: '%c' expected\n", filename, line_num, c);
139 exit(1);
141 next();
144 void test_lvalue()
146 if (!(vt & VT_LVAL))
147 error("lvalue expected\n");
150 #else
152 #define skip(c) next()
153 #define test_lvalue()
155 #endif
157 void next()
159 int c, v;
160 char *q, *p;
162 while(1) {
163 c = inp();
164 #ifndef TINY
165 if (c == '/') {
166 /* comments */
167 c = inp();
168 if (c == '/') {
169 /* single line comments */
170 while (c != '\n')
171 c = inp();
172 } else if (c == '*') {
173 /* comments */
174 while ((c = inp()) >= 0) {
175 if (c == '*') {
176 c = inp();
177 if (c == '/') {
178 c = ' ';
179 break;
180 } else if (c == '*')
181 ungetc(c, file);
182 } else if (c == '\n')
183 line_num++;
185 } else {
186 ungetc(c, file);
187 c = '/';
188 break;
190 } else
191 #endif
192 if (c == 35) {
193 /* preprocessor: we handle only define */
194 next();
195 if (tok == TOK_DEFINE) {
196 next();
197 /* now tok is the macro symbol */
198 vat[tok] = VT_DEFINE;
199 vac[tok] = ftell(file);
201 /* ignore preprocessor or shell */
202 while (c != '\n')
203 c = inp();
205 if (c == '\n') {
206 /* end of line : check if we are in macro state. if so,
207 pop new file position */
208 if (macro_stack_ptr > macro_stack)
209 fseek(file, *--macro_stack_ptr, 0);
210 else
211 line_num++;
212 } else if (c != ' ' & c != 9)
213 break;
215 if (isid(c)) {
216 q = idptr;
217 idlast = q;
218 while(isid(c) | isnum(c)) {
219 *q++ = c;
220 c = inp();
222 *q++ = '\0';
223 ungetc(c, file);
224 p = idtable;
225 tok = 256;
226 while (p < idptr) {
227 if (strcmp(p, idptr) == 0)
228 break;
229 while (*p++);
230 tok++;
232 /* if not found, add symbol */
233 if (p == idptr)
234 idptr = q;
235 /* eval defines */
236 if (vat[tok] & VT_DEFINE) {
237 *macro_stack_ptr++ = ftell(file);
238 fseek(file, vac[tok], 0);
239 next();
241 } else {
242 #ifdef TINY
243 q = "<=\236>=\235!=\225++\244--\242==\224";
244 #else
245 q = "<=\236>=\235!=\225&&\240||\241++\244--\242==\224<<\340>>\370";
246 #endif
247 /* two chars */
248 v = inp();
249 while (*q) {
250 if (*q == c & q[1] == v) {
251 tok = q[2] & 0xff;
252 return;
254 q = q + 3;
256 ungetc(v, file);
257 /* single char substitutions */
258 if (c == '<')
259 tok = TOK_LT;
260 else if (c == '>')
261 tok = TOK_GT;
262 else
263 tok = c;
267 void g(c)
269 *(char *)ind++ = c;
272 void o(c)
274 while (c) {
275 g(c);
276 c = c / 256;
280 /* output a symbol and patch all calls to it */
281 void gsym(t)
283 int n;
284 while (t) {
285 n = *(int *)t; /* next value */
286 *(int *)t = ind - t - 4;
287 t = n;
291 /* psym is used to put an instruction with a data field which is a
292 reference to a symbol. It is in fact the same as oad ! */
293 #define psym oad
295 /* instruction + 4 bytes data. Return the address of the data */
296 int oad(c, s)
298 o(c);
299 *(int *)ind = s;
300 s = ind;
301 ind = ind + 4;
302 return s;
305 void vset(t, v)
307 vt = t;
308 vc = v;
311 /* generate a value in eax from vt and vc */
312 void gv()
314 #ifndef TINY
315 int t;
316 #endif
317 if (vt & VT_LVAL) {
318 if ((vt & VT_TYPE) == VT_BYTE)
319 o(0xbe0f); /* movsbl x, %eax */
320 else
321 o(0x8b); /* movl x,%eax */
322 if (vt & VT_CONST)
323 oad(0x05, vc);
324 else if (vt & VT_LOCAL)
325 oad(0x85, vc);
326 else
327 g(0x00);
328 } else {
329 if (vt & VT_CONST) {
330 oad(0xb8, vc); /* mov $xx, %eax */
331 } else if (vt & VT_LOCAL) {
332 oad(0x858d, vc); /* lea xxx(%ebp), %eax */
333 } else if (vt & VT_CMP) {
334 oad(0xb8, 0); /* mov $0, %eax */
335 o(0x0f); /* setxx %al */
336 o(vc);
337 o(0xc0);
339 #ifndef TINY
340 else if (vt & VT_JMP) {
341 t = vt & 1;
342 oad(0xb8, t); /* mov $1, %eax */
343 oad(0xe9, 5); /* jmp after */
344 gsym(vc);
345 oad(0xb8, t ^ 1); /* mov $0, %eax */
347 #endif
349 vt = (vt & VT_TYPE) | VT_VAR;
352 /* generate a test. set 'inv' to invert test */
353 /* XXX: handle constant */
354 int gtst(inv, t)
356 if (vt & VT_CMP) {
357 /* fast case : can jump directly since flags are set */
358 g(0x0f);
359 t = psym((vc - 16) ^ inv, t);
360 } else
361 #ifndef TINY
362 if (vt & VT_JMP) {
363 /* && or || optimization */
364 if ((vt & 1) == inv)
365 t = vc;
366 else {
367 t = psym(0xe9, t);
368 gsym(vc);
370 } else
371 if ((vt & (VT_CONST | VT_LVAL)) == VT_CONST) {
372 /* constant jmp optimization */
373 if ((vc != 0) != inv)
374 t = psym(0xe9, t);
375 } else
376 #endif
378 gv();
379 o(0xc085); /* test %eax, %eax */
380 g(0x0f);
381 t = psym(0x85 ^ inv, t);
383 return t;
386 /* return the size in bytes of a given type */
387 int type_size(t)
389 if ((t & VT_PTRMASK) > VT_PTRINC | (t & VT_TYPE) == VT_PTRINC)
390 return 4;
391 else
392 return 1;
395 #define POST_ADD 0x1000
396 #define PRE_ADD 0
398 /* a defines POST/PRE add. c is the token ++ or -- */
399 void inc(a, c)
401 test_lvalue();
402 vt = vt & VT_LVALN;
403 gv();
404 o(0x018bc189); /* movl %eax, %ecx ; mov (%ecx), %eax */
405 o(0x408d | a); /* leal x(%eax), %eax/%edx */
406 g((c - TOK_MID) * type_size(vt));
407 o(0x0189 | a); /* mov %eax/%edx, (%ecx) */
410 /* XXX: handle ptr sub and 'int + ptr' case (only 'ptr + int' handled) */
411 /* XXX: handle constant propagation (need to track live eax) */
412 void gen_op(op, l)
414 int t;
415 gv();
416 t = vt;
417 o(0x50); /* push %eax */
418 next();
419 if (l < 0)
420 expr();
421 else
422 sum(l);
423 gv();
424 o(0x59); /* pop %ecx */
425 if (op == '+' | op == '-') {
426 /* XXX: incorrect for short (futur!) */
427 if (type_size(t) == 4)
428 o(0x02e0c1); /* shl $2, %eax */
429 if (op == '-')
430 o(0xd8f7); /* neg %eax */
431 o(0xc801); /* add %ecx, %eax */
432 vt = t;
433 } else if (op == '&')
434 o(0xc821);
435 else if (op == '^')
436 o(0xc831);
437 else if (op == '|')
438 o(0xc809);
439 else if (op == '*')
440 o(0xc1af0f); /* imul %ecx, %eax */
441 #ifndef TINY
442 else if (op == TOK_SHL | op == TOK_SHR) {
443 o(0xd391); /* xchg %ecx, %eax, shl/sar %cl, %eax */
444 o(op);
446 #endif
447 else if (op == '/' | op == '%') {
448 o(0x91); /* xchg %ecx, %eax */
449 o(0xf9f799); /* cltd, idiv %ecx, %eax */
450 if (op == '%')
451 o(0x92); /* xchg %edx, %eax */
452 } else {
453 o(0xc139); /* cmp %eax,%ecx */
454 vset(VT_CMP, op);
458 /* return 0 if no type declaration. otherwise, return the basic type
459 and skip it.
460 XXX: A '2' is ored to ensure non zero return if int type.
462 int ist()
464 int t;
466 if (tok == TOK_INT | tok == TOK_CHAR | tok == TOK_VOID) {
467 t = tok;
468 next();
469 return (t != TOK_INT) | 2;
470 } else {
471 return 0;
475 /* Read a type declaration (except basic type), and return the
476 type. If v is true, then also put variable name in 'vc' */
477 int typ(v,t)
479 int u, p, n;
481 t = t & -3; /* suppress the ored '2' */
482 while (tok == '*') {
483 next();
484 t = t + VT_PTRINC;
487 /* recursive type */
488 /* XXX: incorrect if abstract type for functions (e.g. 'int ()') */
489 if (tok == '(') {
490 next();
491 u = typ(v, 0);
492 skip(')');
493 } else {
494 u = 0;
495 /* type identifier */
496 if (v) {
497 vc = tok;
498 next();
501 /* function declaration */
502 if (tok == '(') {
503 next();
504 p = 4;
505 n = vc; /* must save vc there */
506 while (tok != ')') {
507 /* read param name and compute offset */
508 if (t = ist())
509 t = typ(1, t); /* XXX: should accept both arg/non arg if v == 0 */
510 else {
511 vc = tok;
512 t = 0;
513 next();
515 p = p + 4;
516 vat[vc] = VT_LOCAL | VT_LVAL | t;
517 vac[vc] = p;
518 if (tok == ',')
519 next();
521 next(); /* skip ')' */
522 vc = n;
523 if (u)
524 t = u + VT_BYTE;
525 else
526 t = t | VT_FUNC;
528 return t;
531 /* read a number in base b */
532 int getn(c, b)
534 int n, t;
535 n = 0;
536 #ifndef TINY
537 while (1) {
538 if (c >= 'a')
539 t = c - 'a' + 10;
540 else if (c >= 'A')
541 t = c - 'A' + 10;
542 else
543 t = c - '0';
544 if (t < 0 | t >= b)
545 break;
546 n = n * b + t;
547 c = inp();
549 #else
550 while (isnum(c)) {
551 n = n * b + c - '0';
552 c = inp();
554 #endif
555 ungetc(c, file);
556 return n;
559 int getq(n)
561 if (n == '\\') {
562 n = inp();
563 if (n == 'n')
564 n = '\n';
565 #ifndef TINY
566 else if (n == 'r')
567 n = '\r';
568 else if (n == 't')
569 n = '\t';
570 #endif
571 else if (isnum(n))
572 n = getn(n, 8);
574 return n;
577 void unary()
579 int n, t, ft, fc, p;
581 if (isnum(tok)) {
582 /* number */
583 #ifndef TINY
584 t = 10;
585 if (tok == '0') {
586 t = 8;
587 tok = inp();
588 if (tok == 'x') {
589 t = 16;
590 tok = inp();
593 vset(VT_CONST, getn(tok, t));
594 #else
595 vset(VT_CONST, getn(tok, 10));
596 #endif
597 next();
598 } else
599 #ifndef TINY
600 if (tok == '\'') {
601 vset(VT_CONST, getq(inp()));
602 next(); /* skip char */
603 skip('\'');
604 } else
605 #endif
606 if (tok == '\"') {
607 vset(VT_CONST | VT_PTRINC | VT_BYTE, glo);
608 while (tok == '\"') {
609 while((n = inp()) != 34) {
610 *(char *)glo = getq(n);
611 glo++;
613 next();
615 *(char *)glo = 0;
616 glo = (glo + 4) & -4; /* align heap */
617 } else {
618 t = tok;
619 next();
620 if (t == '(') {
621 /* cast ? */
622 if (t = ist()) {
623 ft = typ(0, t);
624 skip(')');
625 unary();
626 vt = (vt & VT_TYPEN) | ft;
627 } else {
628 expr();
629 skip(')');
631 } else if (t == '*') {
632 unary();
633 if (vt & VT_LVAL)
634 gv();
635 #ifndef TINY
636 if (!(vt & VT_PTRMASK))
637 error("pointer expected");
638 #endif
639 vt = (vt - VT_PTRINC) | VT_LVAL;
640 } else if (t == '&') {
641 unary();
642 test_lvalue();
643 vt = (vt & VT_LVALN) + VT_PTRINC;
644 } else
645 #ifndef TINY
646 if (t == '!') {
647 unary();
648 if (vt & VT_CMP)
649 vc = vc ^ 1;
650 else
651 vset(VT_JMP, gtst(1, 0));
652 } else
653 if (t == '~') {
654 unary();
655 if ((vt & (VT_CONST | VT_LVAL)) == VT_CONST)
656 vc = ~vc;
657 else {
658 gv();
659 o(0xd0f7);
661 } else
662 if (t == '+') {
663 unary();
664 } else
665 #endif
666 if (t == TOK_INC | t == TOK_DEC) {
667 unary();
668 inc(PRE_ADD, t);
669 } else if (t == '-') {
670 unary();
671 if ((vt & (VT_CONST | VT_LVAL)) == VT_CONST)
672 vc = -vc;
673 else {
674 gv();
675 o(0xd8f7); /* neg %eax */
677 } else
679 vset(vat[t], vac[t]);
680 /* forward reference or external reference ? */
681 if (vt == 0) {
682 n = dlsym(0, idlast);
683 if (n == 0)
684 vset(VT_CONST | VT_FORWARD | VT_LVAL, vac + t);
685 else
686 vset(VT_CONST | VT_LVAL, n);
691 /* post operations */
692 if (tok == TOK_INC | tok == TOK_DEC) {
693 inc(POST_ADD, tok);
694 next();
695 } else
696 if (tok == '[') {
697 #ifndef TINY
698 if (!(vt & VT_PTRMASK))
699 error("pointer expected");
700 #endif
701 gen_op('+', -1);
702 /* dereference pointer */
703 vt = (vt - VT_PTRINC) | VT_LVAL;
704 skip(']');
705 } else
706 if (tok == '(') {
707 /* function call */
708 /* lvalue is implied */
709 vt = vt & VT_LVALN;
710 if ((vt & VT_CONST) == 0) {
711 /* evaluate function address */
712 gv();
713 o(0x50); /* push %eax */
715 ft = vt;
716 fc = vc;
718 next();
719 t = 0;
720 while (tok != ')') {
721 t = t + 4;
722 expr_eq();
723 gv();
724 o(0x50); /* push %eax */
725 if (tok == ',')
726 next();
728 skip(')');
729 /* horrible, but needed : convert to native ordering (could
730 parse parameters in reverse order, but would cost more
731 code) */
732 n = 0;
733 p = t - 4;
734 while (n < p) {
735 oad(0x24848b, p); /* mov x(%esp,1), %eax */
736 oad(0x248487, n); /* xchg x(%esp,1), %eax */
737 oad(0x248489, p); /* mov %eax, x(%esp,1) */
738 n = n + 4;
739 p = p - 4;
741 if (ft & VT_CONST) {
742 /* forward reference */
743 if (ft & VT_FORWARD)
744 *(int *)fc = psym(0xe8, *(int *)fc);
745 else
746 oad(0xe8, fc - ind - 5);
747 } else {
748 oad(0x2494ff, t); /* call *xxx(%esp) */
749 t = t + 4;
751 if (t)
752 oad(0xc481, t);
753 /* return value is variable, int */
754 vt = VT_VAR;
758 void uneq()
760 int ft, fc, b;
762 unary();
763 if (tok == '=') {
764 test_lvalue();
765 next();
766 fc = vc;
767 ft = vt;
768 b = (vt & VT_TYPE) == VT_BYTE;
769 if (ft & VT_VAR)
770 o(0x50); /* push %eax */
771 expr_eq();
772 #ifndef TINY
773 if ((vt & VT_PTRMASK) != (ft & VT_PTRMASK))
774 warning("incompatible type");
775 #endif
776 gv(); /* generate value */
778 if (ft & VT_VAR) {
779 o(0x59); /* pop %ecx */
780 o(0x0189 - b); /* mov %eax/%al, (%ecx) */
781 } else if (ft & VT_LOCAL)
782 oad(0x8589 - b, fc); /* mov %eax/%al,xxx(%ebp) */
783 else
784 oad(0xa3 - b, fc); /* mov %eax/%al,xxx */
788 void sum(l)
790 #ifndef TINY
791 int t;
792 #endif
793 if (l == 0)
794 uneq();
795 else {
796 sum(--l);
797 while ((l == 0 & (tok == '*' | tok == '/' | tok == '%')) |
798 (l == 1 & (tok == '+' | tok == '-')) |
799 #ifndef TINY
800 (l == 2 & (tok == TOK_SHL | tok == TOK_SHR)) |
801 #endif
802 (l == 3 & (tok >= TOK_LT & tok <= TOK_GT)) |
803 (l == 4 & (tok == TOK_EQ | tok == TOK_NE)) |
804 (l == 5 & tok == '&') |
805 (l == 6 & tok == '^') |
806 (l == 7 & tok == '|')) {
807 gen_op(tok, l);
812 #ifdef TINY
813 void expr()
815 sum(8);
817 #else
818 void eand()
820 int t;
822 sum(8);
823 t = 0;
824 while (1) {
825 if (tok != TOK_LAND) {
826 if (t) {
827 t = gtst(1, t);
828 vset(VT_JMP | 1, t);
830 break;
832 t = gtst(1, t);
833 next();
834 sum(8);
838 void eor()
840 int t, u;
842 eand();
843 t = 0;
844 while (1) {
845 if (tok != TOK_LOR) {
846 if (t) {
847 t = gtst(0, t);
848 vset(VT_JMP, t);
850 break;
852 t = gtst(0, t);
853 next();
854 eand();
858 void expr_eq()
860 int t, u;
862 eor();
863 if (tok == '?') {
864 next();
865 t = gtst(1, 0);
866 expr();
867 gv();
868 skip(':');
869 u = psym(0xe9, 0);
870 gsym(t);
871 expr_eq();
872 gv();
873 gsym(u);
877 void expr()
879 while (1) {
880 expr_eq();
881 if (tok != ',')
882 break;
883 next();
887 #endif
889 void block()
891 int a, c, d;
893 if (tok == TOK_IF) {
894 /* if test */
895 next();
896 skip('(');
897 expr();
898 skip(')');
899 a = gtst(1, 0);
900 block();
901 c = tok;
902 if (c == TOK_ELSE) {
903 next();
904 d = psym(0xe9, 0); /* jmp */
905 gsym(a);
906 block();
907 gsym(d); /* patch else jmp */
908 } else
909 gsym(a);
910 } else if (tok == TOK_WHILE) {
911 next();
912 d = ind;
913 skip('(');
914 expr();
915 skip(')');
916 *++lsym = gtst(1, 0);
917 block();
918 oad(0xe9, d - ind - 5); /* jmp */
919 gsym(*lsym--);
920 } else if (tok == '{') {
921 next();
922 /* declarations */
923 decl(VT_LOCAL);
924 while (tok != '}')
925 block();
926 next();
927 } else if (tok == TOK_RETURN) {
928 next();
929 if (tok != ';') {
930 expr();
931 gv();
933 skip(';');
934 rsym = psym(0xe9, rsym); /* jmp */
935 } else if (tok == TOK_BREAK) {
936 /* compute jump */
937 *lsym = psym(0xe9, *lsym);
938 next();
939 skip(';');
940 } else
941 #ifndef TINY
942 if (tok == TOK_FOR) {
943 int e;
944 next();
945 skip('(');
946 if (tok != ';')
947 expr();
948 skip(';');
949 d = ind;
950 c = ind;
951 a = 0;
952 if (tok != ';') {
953 expr();
954 a = gtst(1, 0);
956 *++lsym = a;
957 skip(';');
958 if (tok != ')') {
959 e = psym(0xe9, 0);
960 c = ind;
961 expr();
962 oad(0xe9, d - ind - 5); /* jmp */
963 gsym(e);
965 skip(')');
966 block();
967 oad(0xe9, c - ind - 5); /* jmp */
968 gsym(*lsym--);
969 } else
970 #endif
972 if (tok != ';')
973 expr();
974 skip(';');
978 /* 'l' is true if local declarations */
979 void decl(l)
981 int *a, t, b;
983 while (b = ist()) {
984 while (1) { /* iterate thru each declaration */
985 vt = typ(1, b);
986 if (tok == '{') {
987 /* patch forward references (XXX: does not work for
988 function pointers) */
989 if (vat[vc] == 0)
990 gsym(vac[vc]);
991 /* put function address */
992 vat[vc] = VT_CONST | VT_LVAL | vt;
993 vac[vc] = ind;
994 loc = 0;
995 o(0xe58955); /* push %ebp, mov %esp, %ebp */
996 a = oad(0xec81, 0); /* sub $xxx, %esp */
997 rsym = 0;
998 block();
999 gsym(rsym);
1000 o(0xc3c9); /* leave, ret */
1001 *a = loc; /* save local variables */
1002 break;
1003 } else {
1004 /* variable */
1005 vat[vc] = l | VT_LVAL | vt;
1006 if (l == VT_LOCAL) {
1007 loc = loc + 4;
1008 vac[vc] = -loc;
1009 } else {
1010 vac[vc] = glo;
1011 glo = glo + 4;
1013 if (tok != ',') {
1014 skip(';');
1015 break;
1017 next();
1023 int main(int c, char **v)
1025 int (*t)();
1026 if (c < 2) {
1027 printf("usage: tc src\n");
1028 return 1;
1030 v++;
1031 filename = *v;
1032 file = fopen(filename, "r");
1033 #ifndef TINY
1034 if (!file) {
1035 perror(filename);
1036 exit(1);
1038 #endif
1040 idtable = malloc(SYM_TABLE_SIZE);
1041 #ifdef TINY
1042 memcpy(idtable,
1043 "int\0void\0char\0if\0else\0while\0break\0return\0define\0main", 53);
1044 idptr = idtable + 53;
1045 #else
1046 memcpy(idtable,
1047 "int\0void\0char\0if\0else\0while\0break\0return\0define\0main\0for", 57);
1048 idptr = idtable + 57;
1049 #endif
1050 glo = malloc(DATA_SIZE);
1051 prog = malloc(TEXT_SIZE);
1052 vac = malloc(VAR_TABLE_SIZE);
1053 vat = malloc(VAR_TABLE_SIZE);
1054 lsym = malloc(256);
1055 macro_stack = malloc(256);
1056 macro_stack_ptr = macro_stack;
1057 ind = prog;
1058 line_num = 1;
1059 next();
1060 decl(VT_CONST);
1061 #ifdef TEST
1063 FILE *f;
1064 f = fopen(v[1], "w");
1065 fwrite((void *)prog, 1, ind - prog, f);
1066 fclose(f);
1067 return 0;
1069 #else
1070 t = vac[TOK_MAIN];
1071 if (!t)
1072 error("main() not defined");
1073 return (*t)(c - 1, v);
1074 #endif