added 'x'= operators
[tinycc.git] / tcc.c
blob6bc1e586d2231e5403dc6e4251d99f88ffeaeac6
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 0x01
92 #define TOK_SHR 0x02
94 /* assignement operators : normal operator or 0x80 */
95 #define TOK_A_MOD 0xa5
96 #define TOK_A_AND 0xa6
97 #define TOK_A_MUL 0xaa
98 #define TOK_A_ADD 0xab
99 #define TOK_A_SUB 0xad
100 #define TOK_A_DIV 0xaf
101 #define TOK_A_XOR 0xde
102 #define TOK_A_OR 0xfc
103 #define TOK_A_SHL 0x81
104 #define TOK_A_SHR 0x82
106 #ifdef TINY
107 #define expr_eq() expr()
108 #endif
110 int inp()
112 #if 0
113 int c;
114 c = fgetc(file);
115 printf("c=%c\n", c);
116 return c;
117 #else
118 return fgetc(file);
119 #endif
122 int isid(c)
124 return (c >= 'a' & c <= 'z') |
125 (c >= 'A' & c <= 'Z') |
126 c == '_';
129 int isnum(c)
131 return c >= '0' & c <= '9';
134 #ifndef TINY
135 /* XXX: use stderr ? */
136 void error(char *msg)
138 printf("%s:%d: %s\n", filename, line_num, msg);
139 exit(1);
142 void warning(char *msg)
144 printf("%s:%d: warning: %s\n", filename, line_num, msg);
147 void skip(c)
149 if (tok != c) {
150 printf("%s:%d: '%c' expected\n", filename, line_num, c);
151 exit(1);
153 next();
156 void test_lvalue()
158 if (!(vt & VT_LVAL))
159 error("lvalue expected\n");
162 #else
164 #define skip(c) next()
165 #define test_lvalue()
167 #endif
169 void next()
171 int c, v;
172 char *q, *p;
174 while(1) {
175 c = inp();
176 #ifndef TINY
177 if (c == '/') {
178 /* comments */
179 c = inp();
180 if (c == '/') {
181 /* single line comments */
182 while (c != '\n')
183 c = inp();
184 } else if (c == '*') {
185 /* comments */
186 while ((c = inp()) >= 0) {
187 if (c == '*') {
188 c = inp();
189 if (c == '/') {
190 c = ' ';
191 break;
192 } else if (c == '*')
193 ungetc(c, file);
194 } else if (c == '\n')
195 line_num++;
197 } else {
198 ungetc(c, file);
199 c = '/';
200 break;
202 } else
203 #endif
204 if (c == 35) {
205 /* preprocessor: we handle only define */
206 next();
207 if (tok == TOK_DEFINE) {
208 next();
209 /* now tok is the macro symbol */
210 vat[tok] = VT_DEFINE;
211 vac[tok] = ftell(file);
213 /* ignore preprocessor or shell */
214 while (c != '\n')
215 c = inp();
217 if (c == '\n') {
218 /* end of line : check if we are in macro state. if so,
219 pop new file position */
220 if (macro_stack_ptr > macro_stack)
221 fseek(file, *--macro_stack_ptr, 0);
222 else
223 line_num++;
224 } else if (c != ' ' & c != 9)
225 break;
227 if (isid(c)) {
228 q = idptr;
229 idlast = q;
230 while(isid(c) | isnum(c)) {
231 *q++ = c;
232 c = inp();
234 *q++ = '\0';
235 ungetc(c, file);
236 p = idtable;
237 tok = 256;
238 while (p < idptr) {
239 if (strcmp(p, idptr) == 0)
240 break;
241 while (*p++);
242 tok++;
244 /* if not found, add symbol */
245 if (p == idptr)
246 idptr = q;
247 /* eval defines */
248 if (vat[tok] & VT_DEFINE) {
249 *macro_stack_ptr++ = ftell(file);
250 fseek(file, vac[tok], 0);
251 next();
253 } else {
254 #ifdef TINY
255 q = "<=\236>=\235!=\225++\244--\242==\224";
256 #else
257 q = "<=\236>=\235!=\225&&\240||\241++\244--\242==\224<<\1>>\2+=\253-=\255*=\252/=\257%=\245&=\246^=\336|=\374";
258 #endif
259 /* two chars */
260 v = inp();
261 while (*q) {
262 if (*q == c & q[1] == v) {
263 tok = q[2] & 0xff;
264 if (tok == TOK_SHL | tok == TOK_SHR) {
265 v = inp();
266 if (v == '=')
267 tok = tok | 0x80;
268 else
269 ungetc(v, file);
271 return;
273 q = q + 3;
275 ungetc(v, file);
276 /* single char substitutions */
277 if (c == '<')
278 tok = TOK_LT;
279 else if (c == '>')
280 tok = TOK_GT;
281 else
282 tok = c;
286 void g(c)
288 *(char *)ind++ = c;
291 void o(c)
293 while (c) {
294 g(c);
295 c = c / 256;
299 /* output a symbol and patch all calls to it */
300 void gsym(t)
302 int n;
303 while (t) {
304 n = *(int *)t; /* next value */
305 *(int *)t = ind - t - 4;
306 t = n;
310 /* psym is used to put an instruction with a data field which is a
311 reference to a symbol. It is in fact the same as oad ! */
312 #define psym oad
314 /* instruction + 4 bytes data. Return the address of the data */
315 int oad(c, s)
317 o(c);
318 *(int *)ind = s;
319 s = ind;
320 ind = ind + 4;
321 return s;
324 void vset(t, v)
326 vt = t;
327 vc = v;
330 /* generate a value in eax from vt and vc */
331 void gv()
333 #ifndef TINY
334 int t;
335 #endif
336 if (vt & VT_LVAL) {
337 if ((vt & VT_TYPE) == VT_BYTE)
338 o(0xbe0f); /* movsbl x, %eax */
339 else
340 o(0x8b); /* movl x,%eax */
341 if (vt & VT_CONST)
342 oad(0x05, vc);
343 else if (vt & VT_LOCAL)
344 oad(0x85, vc);
345 else
346 g(0x00);
347 } else {
348 if (vt & VT_CONST) {
349 oad(0xb8, vc); /* mov $xx, %eax */
350 } else if (vt & VT_LOCAL) {
351 oad(0x858d, vc); /* lea xxx(%ebp), %eax */
352 } else if (vt & VT_CMP) {
353 oad(0xb8, 0); /* mov $0, %eax */
354 o(0x0f); /* setxx %al */
355 o(vc);
356 o(0xc0);
358 #ifndef TINY
359 else if (vt & VT_JMP) {
360 t = vt & 1;
361 oad(0xb8, t); /* mov $1, %eax */
362 oad(0xe9, 5); /* jmp after */
363 gsym(vc);
364 oad(0xb8, t ^ 1); /* mov $0, %eax */
366 #endif
368 vt = (vt & VT_TYPE) | VT_VAR;
371 /* generate a test. set 'inv' to invert test */
372 /* XXX: handle constant */
373 int gtst(inv, t)
375 if (vt & VT_CMP) {
376 /* fast case : can jump directly since flags are set */
377 g(0x0f);
378 t = psym((vc - 16) ^ inv, t);
379 } else
380 #ifndef TINY
381 if (vt & VT_JMP) {
382 /* && or || optimization */
383 if ((vt & 1) == inv)
384 t = vc;
385 else {
386 t = psym(0xe9, t);
387 gsym(vc);
389 } else
390 if ((vt & (VT_CONST | VT_LVAL)) == VT_CONST) {
391 /* constant jmp optimization */
392 if ((vc != 0) != inv)
393 t = psym(0xe9, t);
394 } else
395 #endif
397 gv();
398 o(0xc085); /* test %eax, %eax */
399 g(0x0f);
400 t = psym(0x85 ^ inv, t);
402 return t;
405 /* return the size in bytes of a given type */
406 int type_size(t)
408 if ((t & VT_PTRMASK) > VT_PTRINC | (t & VT_TYPE) == VT_PTRINC)
409 return 4;
410 else
411 return 1;
414 #define POST_ADD 0x1000
415 #define PRE_ADD 0
417 /* a defines POST/PRE add. c is the token ++ or -- */
418 void inc(a, c)
420 test_lvalue();
421 vt = vt & VT_LVALN;
422 gv();
423 o(0x018bc189); /* movl %eax, %ecx ; mov (%ecx), %eax */
424 o(0x408d | a); /* leal x(%eax), %eax/%edx */
425 g((c - TOK_MID) * type_size(vt));
426 o(0x0189 | a); /* mov %eax/%edx, (%ecx) */
429 /* XXX: handle ptr sub and 'int + ptr' case (only 'ptr + int' handled) */
430 /* XXX: handle constant propagation (need to track live eax) */
431 void gen_op(op, l)
433 int t;
434 gv();
435 t = vt;
436 o(0x50); /* push %eax */
437 next();
438 if (l == -1)
439 expr();
440 else if (l == -2)
441 expr_eq();
442 else
443 sum(l);
444 gv();
445 o(0x59); /* pop %ecx */
446 if (op == '+' | op == '-') {
447 /* XXX: incorrect for short (futur!) */
448 if (type_size(t) == 4)
449 o(0x02e0c1); /* shl $2, %eax */
450 if (op == '-')
451 o(0xd8f7); /* neg %eax */
452 o(0xc801); /* add %ecx, %eax */
453 vt = t;
454 } else if (op == '&')
455 o(0xc821);
456 else if (op == '^')
457 o(0xc831);
458 else if (op == '|')
459 o(0xc809);
460 else if (op == '*')
461 o(0xc1af0f); /* imul %ecx, %eax */
462 #ifndef TINY
463 else if (op == TOK_SHL | op == TOK_SHR) {
464 o(0xd391); /* xchg %ecx, %eax, shl/sar %cl, %eax */
465 if (op == TOK_SHL)
466 o(0xe0);
467 else
468 o(0xf8);
470 #endif
471 else if (op == '/' | op == '%') {
472 o(0x91); /* xchg %ecx, %eax */
473 o(0xf9f799); /* cltd, idiv %ecx, %eax */
474 if (op == '%')
475 o(0x92); /* xchg %edx, %eax */
476 } else {
477 o(0xc139); /* cmp %eax,%ecx */
478 vset(VT_CMP, op);
482 /* return 0 if no type declaration. otherwise, return the basic type
483 and skip it.
484 XXX: A '2' is ored to ensure non zero return if int type.
486 int ist()
488 int t;
490 if (tok == TOK_INT | tok == TOK_CHAR | tok == TOK_VOID) {
491 t = tok;
492 next();
493 return (t != TOK_INT) | 2;
494 } else {
495 return 0;
499 /* Read a type declaration (except basic type), and return the
500 type. If v is true, then also put variable name in 'vc' */
501 int typ(v,t)
503 int u, p, n;
505 t = t & -3; /* suppress the ored '2' */
506 while (tok == '*') {
507 next();
508 t = t + VT_PTRINC;
511 /* recursive type */
512 /* XXX: incorrect if abstract type for functions (e.g. 'int ()') */
513 if (tok == '(') {
514 next();
515 u = typ(v, 0);
516 skip(')');
517 } else {
518 u = 0;
519 /* type identifier */
520 if (v) {
521 vc = tok;
522 next();
525 /* function declaration */
526 if (tok == '(') {
527 next();
528 p = 4;
529 n = vc; /* must save vc there */
530 while (tok != ')') {
531 /* read param name and compute offset */
532 if (t = ist())
533 t = typ(1, t); /* XXX: should accept both arg/non arg if v == 0 */
534 else {
535 vc = tok;
536 t = 0;
537 next();
539 p = p + 4;
540 vat[vc] = VT_LOCAL | VT_LVAL | t;
541 vac[vc] = p;
542 if (tok == ',')
543 next();
545 next(); /* skip ')' */
546 vc = n;
547 if (u)
548 t = u + VT_BYTE;
549 else
550 t = t | VT_FUNC;
552 return t;
555 /* read a number in base b */
556 int getn(c, b)
558 int n, t;
559 n = 0;
560 #ifndef TINY
561 while (1) {
562 if (c >= 'a')
563 t = c - 'a' + 10;
564 else if (c >= 'A')
565 t = c - 'A' + 10;
566 else
567 t = c - '0';
568 if (t < 0 | t >= b)
569 break;
570 n = n * b + t;
571 c = inp();
573 #else
574 while (isnum(c)) {
575 n = n * b + c - '0';
576 c = inp();
578 #endif
579 ungetc(c, file);
580 return n;
583 int getq(n)
585 if (n == '\\') {
586 n = inp();
587 if (n == 'n')
588 n = '\n';
589 #ifndef TINY
590 else if (n == 'r')
591 n = '\r';
592 else if (n == 't')
593 n = '\t';
594 #endif
595 else if (isnum(n))
596 n = getn(n, 8);
598 return n;
601 void unary()
603 int n, t, ft, fc, p;
605 if (isnum(tok)) {
606 /* number */
607 #ifndef TINY
608 t = 10;
609 if (tok == '0') {
610 t = 8;
611 tok = inp();
612 if (tok == 'x') {
613 t = 16;
614 tok = inp();
617 vset(VT_CONST, getn(tok, t));
618 #else
619 vset(VT_CONST, getn(tok, 10));
620 #endif
621 next();
622 } else
623 #ifndef TINY
624 if (tok == '\'') {
625 vset(VT_CONST, getq(inp()));
626 next(); /* skip char */
627 skip('\'');
628 } else
629 #endif
630 if (tok == '\"') {
631 vset(VT_CONST | VT_PTRINC | VT_BYTE, glo);
632 while (tok == '\"') {
633 while((n = inp()) != 34) {
634 *(char *)glo = getq(n);
635 glo++;
637 next();
639 *(char *)glo = 0;
640 glo = (glo + 4) & -4; /* align heap */
641 } else {
642 t = tok;
643 next();
644 if (t == '(') {
645 /* cast ? */
646 if (t = ist()) {
647 ft = typ(0, t);
648 skip(')');
649 unary();
650 vt = (vt & VT_TYPEN) | ft;
651 } else {
652 expr();
653 skip(')');
655 } else if (t == '*') {
656 unary();
657 if (vt & VT_LVAL)
658 gv();
659 #ifndef TINY
660 if (!(vt & VT_PTRMASK))
661 error("pointer expected");
662 #endif
663 vt = (vt - VT_PTRINC) | VT_LVAL;
664 } else if (t == '&') {
665 unary();
666 test_lvalue();
667 vt = (vt & VT_LVALN) + VT_PTRINC;
668 } else
669 #ifndef TINY
670 if (t == '!') {
671 unary();
672 if (vt & VT_CMP)
673 vc = vc ^ 1;
674 else
675 vset(VT_JMP, gtst(1, 0));
676 } else
677 if (t == '~') {
678 unary();
679 if ((vt & (VT_CONST | VT_LVAL)) == VT_CONST)
680 vc = ~vc;
681 else {
682 gv();
683 o(0xd0f7);
685 } else
686 if (t == '+') {
687 unary();
688 } else
689 #endif
690 if (t == TOK_INC | t == TOK_DEC) {
691 unary();
692 inc(PRE_ADD, t);
693 } else if (t == '-') {
694 unary();
695 if ((vt & (VT_CONST | VT_LVAL)) == VT_CONST)
696 vc = -vc;
697 else {
698 gv();
699 o(0xd8f7); /* neg %eax */
701 } else
703 vset(vat[t], vac[t]);
704 /* forward reference or external reference ? */
705 if (vt == 0) {
706 n = dlsym(0, idlast);
707 if (n == 0)
708 vset(VT_CONST | VT_FORWARD | VT_LVAL, vac + t);
709 else
710 vset(VT_CONST | VT_LVAL, n);
715 /* post operations */
716 if (tok == TOK_INC | tok == TOK_DEC) {
717 inc(POST_ADD, tok);
718 next();
719 } else
720 if (tok == '[') {
721 #ifndef TINY
722 if (!(vt & VT_PTRMASK))
723 error("pointer expected");
724 #endif
725 gen_op('+', -1);
726 /* dereference pointer */
727 vt = (vt - VT_PTRINC) | VT_LVAL;
728 skip(']');
729 } else
730 if (tok == '(') {
731 /* function call */
732 /* lvalue is implied */
733 vt = vt & VT_LVALN;
734 if ((vt & VT_CONST) == 0) {
735 /* evaluate function address */
736 gv();
737 o(0x50); /* push %eax */
739 ft = vt;
740 fc = vc;
742 next();
743 t = 0;
744 while (tok != ')') {
745 t = t + 4;
746 expr_eq();
747 gv();
748 o(0x50); /* push %eax */
749 if (tok == ',')
750 next();
752 skip(')');
753 /* horrible, but needed : convert to native ordering (could
754 parse parameters in reverse order, but would cost more
755 code) */
756 n = 0;
757 p = t - 4;
758 while (n < p) {
759 oad(0x24848b, p); /* mov x(%esp,1), %eax */
760 oad(0x248487, n); /* xchg x(%esp,1), %eax */
761 oad(0x248489, p); /* mov %eax, x(%esp,1) */
762 n = n + 4;
763 p = p - 4;
765 if (ft & VT_CONST) {
766 /* forward reference */
767 if (ft & VT_FORWARD)
768 *(int *)fc = psym(0xe8, *(int *)fc);
769 else
770 oad(0xe8, fc - ind - 5);
771 } else {
772 oad(0x2494ff, t); /* call *xxx(%esp) */
773 t = t + 4;
775 if (t)
776 oad(0xc481, t);
777 /* return value is variable, int */
778 vt = VT_VAR;
782 void uneq()
784 int ft, fc, b;
786 unary();
787 if (tok == '=' |
788 (tok >= TOK_A_MOD & TOK_A_DIV) |
789 tok == TOK_A_XOR | tok == TOK_A_OR |
790 tok == TOK_A_SHL | tok == TOK_A_SHR) {
791 test_lvalue();
792 fc = vc;
793 ft = vt;
794 b = (vt & VT_TYPE) == VT_BYTE;
795 if (ft & VT_VAR)
796 o(0x50); /* push %eax */
797 if (tok == '=') {
798 next();
799 expr_eq();
800 #ifndef TINY
801 if ((vt & VT_PTRMASK) != (ft & VT_PTRMASK))
802 warning("incompatible type");
803 #endif
804 gv(); /* generate value */
805 } else
806 gen_op(tok & 0x7f, -2); /* XXX: incorrect, must call expr_eq */
808 if (ft & VT_VAR) {
809 o(0x59); /* pop %ecx */
810 o(0x0189 - b); /* mov %eax/%al, (%ecx) */
811 } else if (ft & VT_LOCAL)
812 oad(0x8589 - b, fc); /* mov %eax/%al,xxx(%ebp) */
813 else
814 oad(0xa3 - b, fc); /* mov %eax/%al,xxx */
818 void sum(l)
820 #ifndef TINY
821 int t;
822 #endif
823 if (l == 0)
824 uneq();
825 else {
826 sum(--l);
827 while ((l == 0 & (tok == '*' | tok == '/' | tok == '%')) |
828 (l == 1 & (tok == '+' | tok == '-')) |
829 #ifndef TINY
830 (l == 2 & (tok == TOK_SHL | tok == TOK_SHR)) |
831 #endif
832 (l == 3 & (tok >= TOK_LT & tok <= TOK_GT)) |
833 (l == 4 & (tok == TOK_EQ | tok == TOK_NE)) |
834 (l == 5 & tok == '&') |
835 (l == 6 & tok == '^') |
836 (l == 7 & tok == '|')) {
837 gen_op(tok, l);
842 #ifdef TINY
843 void expr()
845 sum(8);
847 #else
848 void eand()
850 int t;
852 sum(8);
853 t = 0;
854 while (1) {
855 if (tok != TOK_LAND) {
856 if (t) {
857 t = gtst(1, t);
858 vset(VT_JMP | 1, t);
860 break;
862 t = gtst(1, t);
863 next();
864 sum(8);
868 void eor()
870 int t, u;
872 eand();
873 t = 0;
874 while (1) {
875 if (tok != TOK_LOR) {
876 if (t) {
877 t = gtst(0, t);
878 vset(VT_JMP, t);
880 break;
882 t = gtst(0, t);
883 next();
884 eand();
888 void expr_eq()
890 int t, u;
892 eor();
893 if (tok == '?') {
894 next();
895 t = gtst(1, 0);
896 expr();
897 gv();
898 skip(':');
899 u = psym(0xe9, 0);
900 gsym(t);
901 expr_eq();
902 gv();
903 gsym(u);
907 void expr()
909 while (1) {
910 expr_eq();
911 if (tok != ',')
912 break;
913 next();
917 #endif
919 void block()
921 int a, c, d;
923 if (tok == TOK_IF) {
924 /* if test */
925 next();
926 skip('(');
927 expr();
928 skip(')');
929 a = gtst(1, 0);
930 block();
931 c = tok;
932 if (c == TOK_ELSE) {
933 next();
934 d = psym(0xe9, 0); /* jmp */
935 gsym(a);
936 block();
937 gsym(d); /* patch else jmp */
938 } else
939 gsym(a);
940 } else if (tok == TOK_WHILE) {
941 next();
942 d = ind;
943 skip('(');
944 expr();
945 skip(')');
946 *++lsym = gtst(1, 0);
947 block();
948 oad(0xe9, d - ind - 5); /* jmp */
949 gsym(*lsym--);
950 } else if (tok == '{') {
951 next();
952 /* declarations */
953 decl(VT_LOCAL);
954 while (tok != '}')
955 block();
956 next();
957 } else if (tok == TOK_RETURN) {
958 next();
959 if (tok != ';') {
960 expr();
961 gv();
963 skip(';');
964 rsym = psym(0xe9, rsym); /* jmp */
965 } else if (tok == TOK_BREAK) {
966 /* compute jump */
967 *lsym = psym(0xe9, *lsym);
968 next();
969 skip(';');
970 } else
971 #ifndef TINY
972 if (tok == TOK_FOR) {
973 int e;
974 next();
975 skip('(');
976 if (tok != ';')
977 expr();
978 skip(';');
979 d = ind;
980 c = ind;
981 a = 0;
982 if (tok != ';') {
983 expr();
984 a = gtst(1, 0);
986 *++lsym = a;
987 skip(';');
988 if (tok != ')') {
989 e = psym(0xe9, 0);
990 c = ind;
991 expr();
992 oad(0xe9, d - ind - 5); /* jmp */
993 gsym(e);
995 skip(')');
996 block();
997 oad(0xe9, c - ind - 5); /* jmp */
998 gsym(*lsym--);
999 } else
1000 #endif
1002 if (tok != ';')
1003 expr();
1004 skip(';');
1008 /* 'l' is true if local declarations */
1009 void decl(l)
1011 int *a, t, b;
1013 while (b = ist()) {
1014 while (1) { /* iterate thru each declaration */
1015 vt = typ(1, b);
1016 if (tok == '{') {
1017 /* patch forward references (XXX: does not work for
1018 function pointers) */
1019 if (vat[vc] == 0)
1020 gsym(vac[vc]);
1021 /* put function address */
1022 vat[vc] = VT_CONST | VT_LVAL | vt;
1023 vac[vc] = ind;
1024 loc = 0;
1025 o(0xe58955); /* push %ebp, mov %esp, %ebp */
1026 a = oad(0xec81, 0); /* sub $xxx, %esp */
1027 rsym = 0;
1028 block();
1029 gsym(rsym);
1030 o(0xc3c9); /* leave, ret */
1031 *a = loc; /* save local variables */
1032 break;
1033 } else {
1034 /* variable */
1035 vat[vc] = l | VT_LVAL | vt;
1036 if (l == VT_LOCAL) {
1037 loc = loc + 4;
1038 vac[vc] = -loc;
1039 } else {
1040 vac[vc] = glo;
1041 glo = glo + 4;
1043 if (tok != ',') {
1044 skip(';');
1045 break;
1047 next();
1053 int main(int c, char **v)
1055 int (*t)();
1056 if (c < 2) {
1057 printf("usage: tc src\n");
1058 return 1;
1060 v++;
1061 filename = *v;
1062 file = fopen(filename, "r");
1063 #ifndef TINY
1064 if (!file) {
1065 perror(filename);
1066 exit(1);
1068 #endif
1070 idtable = malloc(SYM_TABLE_SIZE);
1071 #ifdef TINY
1072 memcpy(idtable,
1073 "int\0void\0char\0if\0else\0while\0break\0return\0define\0main", 53);
1074 idptr = idtable + 53;
1075 #else
1076 memcpy(idtable,
1077 "int\0void\0char\0if\0else\0while\0break\0return\0define\0main\0for", 57);
1078 idptr = idtable + 57;
1079 #endif
1080 glo = malloc(DATA_SIZE);
1081 prog = malloc(TEXT_SIZE);
1082 vac = malloc(VAR_TABLE_SIZE);
1083 vat = malloc(VAR_TABLE_SIZE);
1084 lsym = malloc(256);
1085 macro_stack = malloc(256);
1086 macro_stack_ptr = macro_stack;
1087 ind = prog;
1088 line_num = 1;
1089 next();
1090 decl(VT_CONST);
1091 #ifdef TEST
1093 FILE *f;
1094 f = fopen(v[1], "w");
1095 fwrite((void *)prog, 1, ind - prog, f);
1096 fclose(f);
1097 return 0;
1099 #else
1100 t = vac[TOK_MAIN];
1101 #ifndef TINY
1102 if (!t)
1103 error("main() not defined");
1104 #endif
1105 return (*t)(c - 1, v);
1106 #endif