added do while continue - simplify break/continue handling
[tinycc.git] / tcc.c
blobd95257ed1cf6212717abaee7d7e80737ad4c96a2
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 rsym: return symbol
15 prog: output code
16 astk: arg position stack
18 int tok, *vac, *vat, rsym,
19 prog, ind, loc, glo, file, vt,
20 vc, *macro_stack, *macro_stack_ptr, line_num;
21 char *idtable, *idptr, *filename;
23 /* The current value can be: */
24 #define VT_CONST 0x0002 /* constant in vc */
25 #define VT_VAR 0x0004 /* value is in eax */
26 #define VT_LOCAL 0x0008 /* offset on stack */
28 #define VT_LVAL 0x0010 /* const or var is an lvalue */
29 #define VT_CMP 0x0020 /* the value is stored in processor flags (in vc) */
30 #define VT_FORWARD 0x0040 /* value is forward reference (only used for functions) */
31 #define VT_JMP 0x0080 /* value is the consequence of jmp. bit 0 is set if inv */
33 #define VT_LVALN -17 /* ~VT_LVAL */
37 * VT_FUNC indicates a function. The return type is the stored type. A
38 * function pointer is stored as a 'char' pointer.
40 * If VT_PTRMASK is non nul, then it indicates the number of pointer
41 * iterations to reach the basic type.
43 * Basic types:
45 * VT_BYTE indicate a char
48 * otherwise integer type is assumed.
49 * */
51 #define VT_BYTE 0x00001 /* byte pointer. HARDCODED VALUE */
52 #define VT_PTRMASK 0x00f00 /* pointer mask */
53 #define VT_PTRINC 0x00100 /* pointer increment */
54 #define VT_FUNC 0x01000 /* function type */
55 #define VT_UNSIGNED 0x02000 /* unsigned type */
56 #define VT_ARRAY 0x04000 /* array type (only used in parsing) */
57 #define VT_TYPE 0x07f01 /* type mask */
58 #define VT_TYPEN 0xffff80fe /* ~VT_TYPE */
59 #define VT_FUNCN -4097
61 #define VT_EXTERN 0x08000 /* extern definition */
62 #define VT_STATIC 0x10000 /* static variable */
64 /* Special infos */
65 #define VT_DEFINE 0x80000 /* special value for #defined symbols */
67 /* token values */
68 #define TOK_INT 256
69 #define TOK_VOID 257
70 #define TOK_CHAR 258
71 #define TOK_IF 259
72 #define TOK_ELSE 260
73 #define TOK_WHILE 261
74 #define TOK_BREAK 262
75 #define TOK_RETURN 263
76 #define TOK_DEFINE 264
77 #define TOK_MAIN 265
78 #define TOK_FOR 266
79 #define TOK_EXTERN 267
80 #define TOK_STATIC 268
81 #define TOK_UNSIGNED 269
82 #define TOK_GOTO 270
83 #define TOK_DO 271
84 #define TOK_CONTINUE 272
85 #define TOK_SWITCH 273
86 #define TOK_CASE 274
88 /* ignored types Must have contiguous values */
89 #define TOK_CONST 275
90 #define TOK_VOLATILE 276
91 #define TOK_LONG 277
92 #define TOK_REGISTER 278
93 #define TOK_SIGNED 279
95 /* unsupported types. Must have contiguous values */
96 #define TOK_FLOAT 280
97 #define TOK_DOUBLE 281
98 #define TOK_STRUCT 282
99 #define TOK_UNION 283
100 #define TOK_TYPEDEF 284
102 #define TOK_DEFAULT 285
103 #define TOK_ENUM 286
105 #define TOK_EQ 0x94 /* warning: depend on asm code */
106 #define TOK_NE 0x95 /* warning: depend on asm code */
107 #define TOK_LT 0x9c /* warning: depend on asm code */
108 #define TOK_GE 0x9d /* warning: depend on asm code */
109 #define TOK_LE 0x9e /* warning: depend on asm code */
110 #define TOK_GT 0x9f /* warning: depend on asm code */
112 #define TOK_LAND 0xa0
113 #define TOK_LOR 0xa1
115 #define TOK_DEC 0xa2
116 #define TOK_MID 0xa3 /* inc/dec, to void constant */
117 #define TOK_INC 0xa4
119 #define TOK_SHL 0x01
120 #define TOK_SHR 0x02
122 /* assignement operators : normal operator or 0x80 */
123 #define TOK_A_MOD 0xa5
124 #define TOK_A_AND 0xa6
125 #define TOK_A_MUL 0xaa
126 #define TOK_A_ADD 0xab
127 #define TOK_A_SUB 0xad
128 #define TOK_A_DIV 0xaf
129 #define TOK_A_XOR 0xde
130 #define TOK_A_OR 0xfc
131 #define TOK_A_SHL 0x81
132 #define TOK_A_SHR 0x82
134 #ifdef TINY
135 #define expr_eq() expr()
136 #endif
138 int inp()
140 #if 0
141 int c;
142 c = fgetc(file);
143 printf("c=%c\n", c);
144 return c;
145 #else
146 return fgetc(file);
147 #endif
150 int isid(c)
152 return (c >= 'a' & c <= 'z') |
153 (c >= 'A' & c <= 'Z') |
154 c == '_';
157 int isnum(c)
159 return c >= '0' & c <= '9';
162 #ifndef TINY
163 /* XXX: use stderr ? */
164 void error(char *msg)
166 printf("%s:%d: %s\n", filename, line_num, msg);
167 exit(1);
170 void warning(char *msg)
172 printf("%s:%d: warning: %s\n", filename, line_num, msg);
175 void skip(c)
177 if (tok != c) {
178 printf("%s:%d: '%c' expected\n", filename, line_num, c);
179 exit(1);
181 next();
184 void test_lvalue()
186 if (!(vt & VT_LVAL))
187 error("lvalue expected\n");
190 #else
192 #define skip(c) next()
193 #define test_lvalue()
195 #endif
197 char *get_tok_str(int v)
199 int t;
200 char *p;
201 p = idtable;
202 t = 256;
203 while (t != v) {
204 if (p >= idptr)
205 return 0;
206 while (*p++);
207 t++;
209 return p;
212 void next()
214 int c, v;
215 char *q, *p;
217 while(1) {
218 c = inp();
219 #ifndef TINY
220 if (c == '/') {
221 /* comments */
222 c = inp();
223 if (c == '/') {
224 /* single line comments */
225 while (c != '\n')
226 c = inp();
227 } else if (c == '*') {
228 /* comments */
229 while ((c = inp()) >= 0) {
230 if (c == '*') {
231 c = inp();
232 if (c == '/') {
233 c = ' ';
234 break;
235 } else if (c == '*')
236 ungetc(c, file);
237 } else if (c == '\n')
238 line_num++;
240 } else {
241 ungetc(c, file);
242 c = '/';
243 break;
245 } else
246 #endif
247 if (c == 35) {
248 /* preprocessor: we handle only define */
249 next();
250 if (tok == TOK_DEFINE) {
251 next();
252 /* now tok is the macro symbol */
253 vat[tok] = VT_DEFINE;
254 vac[tok] = ftell(file);
256 /* ignore preprocessor or shell */
257 while (c != '\n')
258 c = inp();
260 if (c == '\n') {
261 /* end of line : check if we are in macro state. if so,
262 pop new file position */
263 if (macro_stack_ptr > macro_stack)
264 fseek(file, *--macro_stack_ptr, 0);
265 else
266 line_num++;
267 } else if (c != ' ' & c != 9)
268 break;
270 if (isid(c)) {
271 q = idptr;
272 while(isid(c) | isnum(c)) {
273 *q++ = c;
274 c = inp();
276 *q++ = '\0';
277 ungetc(c, file);
278 p = idtable;
279 tok = 256;
280 while (p < idptr) {
281 if (strcmp(p, idptr) == 0)
282 break;
283 while (*p++);
284 tok++;
286 /* if not found, add symbol */
287 if (p == idptr)
288 idptr = q;
289 /* eval defines */
290 if (vat[tok] & VT_DEFINE) {
291 *macro_stack_ptr++ = ftell(file);
292 fseek(file, vac[tok], 0);
293 next();
295 } else {
296 #ifdef TINY
297 q = "<=\236>=\235!=\225++\244--\242==\224";
298 #else
299 q = "<=\236>=\235!=\225&&\240||\241++\244--\242==\224<<\1>>\2+=\253-=\255*=\252/=\257%=\245&=\246^=\336|=\374";
300 #endif
301 /* two chars */
302 v = inp();
303 while (*q) {
304 if (*q == c & q[1] == v) {
305 tok = q[2] & 0xff;
306 if (tok == TOK_SHL | tok == TOK_SHR) {
307 v = inp();
308 if (v == '=')
309 tok = tok | 0x80;
310 else
311 ungetc(v, file);
313 return;
315 q = q + 3;
317 ungetc(v, file);
318 /* single char substitutions */
319 if (c == '<')
320 tok = TOK_LT;
321 else if (c == '>')
322 tok = TOK_GT;
323 else
324 tok = c;
328 void g(c)
330 *(char *)ind++ = c;
333 void o(c)
335 while (c) {
336 g(c);
337 c = c / 256;
341 /* output a symbol and patch all calls to it */
342 void gsym_addr(t, a)
344 int n;
345 while (t) {
346 n = *(int *)t; /* next value */
347 *(int *)t = a - t - 4;
348 t = n;
352 void gsym(t)
354 gsym_addr(t, ind);
357 /* psym is used to put an instruction with a data field which is a
358 reference to a symbol. It is in fact the same as oad ! */
359 #define psym oad
361 /* instruction + 4 bytes data. Return the address of the data */
362 int oad(c, s)
364 o(c);
365 *(int *)ind = s;
366 s = ind;
367 ind = ind + 4;
368 return s;
371 void vset(t, v)
373 vt = t;
374 vc = v;
377 /* generate a value in eax from vt and vc */
378 /* XXX: generate correct pointer for forward references to functions */
379 void gv()
381 #ifndef TINY
382 int t;
383 #endif
384 if (vt & VT_LVAL) {
385 if ((vt & VT_TYPE) == VT_BYTE)
386 o(0xbe0f); /* movsbl x, %eax */
387 else
388 o(0x8b); /* movl x,%eax */
389 if (vt & VT_CONST)
390 oad(0x05, vc);
391 else if (vt & VT_LOCAL)
392 oad(0x85, vc);
393 else
394 g(0x00);
395 } else {
396 if (vt & VT_CONST) {
397 oad(0xb8, vc); /* mov $xx, %eax */
398 } else if (vt & VT_LOCAL) {
399 oad(0x858d, vc); /* lea xxx(%ebp), %eax */
400 } else if (vt & VT_CMP) {
401 oad(0xb8, 0); /* mov $0, %eax */
402 o(0x0f); /* setxx %al */
403 o(vc);
404 o(0xc0);
406 #ifndef TINY
407 else if (vt & VT_JMP) {
408 t = vt & 1;
409 oad(0xb8, t); /* mov $1, %eax */
410 oad(0xe9, 5); /* jmp after */
411 gsym(vc);
412 oad(0xb8, t ^ 1); /* mov $0, %eax */
414 #endif
416 vt = (vt & VT_TYPE) | VT_VAR;
419 /* generate a test. set 'inv' to invert test */
420 /* XXX: handle constant */
421 int gtst(inv, t)
423 if (vt & VT_CMP) {
424 /* fast case : can jump directly since flags are set */
425 g(0x0f);
426 t = psym((vc - 16) ^ inv, t);
427 } else
428 #ifndef TINY
429 if (vt & VT_JMP) {
430 /* && or || optimization */
431 if ((vt & 1) == inv)
432 t = vc;
433 else {
434 t = psym(0xe9, t);
435 gsym(vc);
437 } else
438 if ((vt & (VT_CONST | VT_LVAL)) == VT_CONST) {
439 /* constant jmp optimization */
440 if ((vc != 0) != inv)
441 t = psym(0xe9, t);
442 } else
443 #endif
445 gv();
446 o(0xc085); /* test %eax, %eax */
447 g(0x0f);
448 t = psym(0x85 ^ inv, t);
450 return t;
453 int type_size(t)
455 if ((t & VT_PTRMASK) >= VT_PTRINC | (t & VT_TYPE) == 0)
456 return 4;
457 else
458 return 1;
461 /* return the number size in bytes of a given type */
462 int incr_value(t)
464 if ((t & VT_PTRMASK) >= VT_PTRINC)
465 return type_size(t - VT_PTRINC);
466 else
467 return 1;
470 #define POST_ADD 0x1000
471 #define PRE_ADD 0
473 /* a defines POST/PRE add. c is the token ++ or -- */
474 void inc(a, c)
476 test_lvalue();
477 vt = vt & VT_LVALN;
478 gv();
479 o(0x018bc189); /* movl %eax, %ecx ; mov (%ecx), %eax */
480 o(0x408d | a); /* leal x(%eax), %eax/%edx */
481 g((c - TOK_MID) * incr_value(vt));
482 o(0x0189 | a); /* mov %eax/%edx, (%ecx) */
485 /* XXX: handle ptr sub and 'int + ptr' case (only 'ptr + int' handled) */
486 /* XXX: handle constant propagation (need to track live eax) */
487 /* XXX: handle unsigned propagation */
488 void gen_op(op, l)
490 int t;
491 gv();
492 t = vt;
493 o(0x50); /* push %eax */
494 next();
495 if (l == -1)
496 expr();
497 else if (l == -2)
498 expr_eq();
499 else
500 sum(l);
501 gv();
502 o(0x59); /* pop %ecx */
503 if (op == '+' | op == '-') {
504 /* XXX: incorrect for short (futur!) */
505 if (incr_value(t) == 4)
506 o(0x02e0c1); /* shl $2, %eax */
507 if (op == '-')
508 o(0xd8f7); /* neg %eax */
509 o(0xc801); /* add %ecx, %eax */
510 vt = t;
511 } else if (op == '&')
512 o(0xc821);
513 else if (op == '^')
514 o(0xc831);
515 else if (op == '|')
516 o(0xc809);
517 else if (op == '*')
518 o(0xc1af0f); /* imul %ecx, %eax */
519 #ifndef TINY
520 else if (op == TOK_SHL | op == TOK_SHR) {
521 o(0xd391); /* xchg %ecx, %eax, shl/shr/sar %cl, %eax */
522 if (op == TOK_SHL)
523 o(0xe0);
524 else if (t & VT_UNSIGNED)
525 o(0xe8);
526 else
527 o(0xf8);
529 #endif
530 else if (op == '/' | op == '%') {
531 o(0x91); /* xchg %ecx, %eax */
532 if (t & VT_UNSIGNED) {
533 o(0xd231); /* xor %edx, %edx */
534 o(0xf1f7); /* div %ecx, %eax */
535 } else {
536 o(0xf9f799); /* cltd, idiv %ecx, %eax */
538 if (op == '%')
539 o(0x92); /* xchg %edx, %eax */
540 } else {
541 o(0xc139); /* cmp %eax,%ecx */
542 vset(VT_CMP, op);
546 /* return 0 if no type declaration. otherwise, return the basic type
547 and skip it.
548 XXX: A '2' is ored to ensure non zero return if int type.
550 int ist()
552 int t;
553 t = 0;
554 while(1) {
555 if (tok == TOK_CHAR | tok == TOK_VOID) {
556 t |= VT_BYTE;
557 } else if (tok == TOK_INT |
558 (tok >= TOK_CONST & tok <= TOK_SIGNED)) {
559 /* ignored types */
560 } else if (tok >= TOK_FLOAT & tok <= TOK_TYPEDEF) {
561 error("unsupported type");
562 } else if (tok == TOK_EXTERN) {
563 t |= VT_EXTERN;
564 } else if (tok == TOK_STATIC) {
565 t |= VT_STATIC;
566 } else if (tok == TOK_UNSIGNED) {
567 t |= VT_UNSIGNED;
568 } else {
569 break;
571 next();
572 t |= 2;
574 return t;
577 /* Read a type declaration (except basic type), and return the
578 type. If v is true, then also put variable name in 'vc' */
579 int typ(int *v, int t, int *array_size_ptr)
581 int u, p, n;
583 t = t & -3; /* suppress the ored '2' */
584 while (tok == '*') {
585 next();
586 t = t + VT_PTRINC;
589 /* recursive type */
590 /* XXX: incorrect if abstract type for functions (e.g. 'int ()') */
591 if (tok == '(') {
592 next();
593 u = typ(v, 0, 0);
594 skip(')');
595 } else {
596 u = 0;
597 /* type identifier */
598 if (v) {
599 *v = tok;
600 next();
603 while(1) {
604 if (tok == '(') {
605 /* function declaration */
606 next();
607 p = 4;
608 while (tok != ')') {
609 /* read param name and compute offset */
610 if (t = ist())
611 t = typ(&n, t, 0); /* XXX: should accept both arg/non arg if v == 0 */
612 else {
613 n = tok;
614 t = 0;
615 next();
617 p = p + 4;
618 vat[n] = VT_LOCAL | VT_LVAL | t;
619 vac[n] = p;
620 if (tok == ',')
621 next();
623 next(); /* skip ')' */
624 if (u)
625 t = u + VT_BYTE;
626 else
627 t = t | VT_FUNC;
628 } else if (tok == '[') {
629 /* array definition */
630 if (t & VT_ARRAY)
631 error("multi dimension arrays not supported");
632 next();
633 vc = 0;
634 if (tok != ']') {
635 expr();
636 if (array_size_ptr)
637 *array_size_ptr = vc;
639 if ((vt & (VT_CONST | VT_LVAL)) != VT_CONST |
640 (vc <= 0 & array_size_ptr != 0))
641 error("invalid array size");
642 skip(']');
643 t = (t + VT_PTRINC) | VT_ARRAY;
644 } else
645 break;
647 return t;
650 /* define a new external reference to a function 'v' of type 'u' */
651 void external_func(v, u)
653 int t, n;
654 t = vat[v];
655 if (t == 0) {
656 n = dlsym(0, get_tok_str(v));
657 if (n == 0) {
658 vat[v] = u | VT_CONST | VT_LVAL | VT_FORWARD;
659 vac[v] = 0; /* used to generate symbol list */
660 } else {
661 vat[v] = u | VT_CONST | VT_LVAL; /* int f() */
662 vac[v] = n;
667 /* read a number in base b */
668 int getn(c, b)
670 int n, t;
671 n = 0;
672 #ifndef TINY
673 while (1) {
674 if (c >= 'a')
675 t = c - 'a' + 10;
676 else if (c >= 'A')
677 t = c - 'A' + 10;
678 else
679 t = c - '0';
680 if (t < 0 | t >= b)
681 break;
682 n = n * b + t;
683 c = inp();
685 #else
686 while (isnum(c)) {
687 n = n * b + c - '0';
688 c = inp();
690 #endif
691 ungetc(c, file);
692 return n;
695 int getq(n)
697 if (n == '\\') {
698 n = inp();
699 if (n == 'n')
700 n = '\n';
701 #ifndef TINY
702 else if (n == 'r')
703 n = '\r';
704 else if (n == 't')
705 n = '\t';
706 #endif
707 else if (isnum(n))
708 n = getn(n, 8);
710 return n;
713 void unary()
715 int n, t, ft, fc, p;
717 if (isnum(tok)) {
718 /* number */
719 #ifndef TINY
720 t = 10;
721 if (tok == '0') {
722 t = 8;
723 tok = inp();
724 if (tok == 'x') {
725 t = 16;
726 tok = inp();
729 vset(VT_CONST, getn(tok, t));
730 #else
731 vset(VT_CONST, getn(tok, 10));
732 #endif
733 next();
734 } else
735 #ifndef TINY
736 if (tok == '\'') {
737 vset(VT_CONST, getq(inp()));
738 next(); /* skip char */
739 skip('\'');
740 } else
741 #endif
742 if (tok == '\"') {
743 vset(VT_CONST | VT_PTRINC | VT_BYTE, glo);
744 while (tok == '\"') {
745 while((n = inp()) != 34) {
746 *(char *)glo++ = getq(n);
748 next();
750 *(char *)glo++ = 0;
751 } else {
752 t = tok;
753 next();
754 if (t == '(') {
755 /* cast ? */
756 if (t = ist()) {
757 ft = typ(0, t, 0);
758 skip(')');
759 unary();
760 vt = (vt & VT_TYPEN) | ft;
761 } else {
762 expr();
763 skip(')');
765 } else if (t == '*') {
766 unary();
767 if (vt & VT_LVAL)
768 gv();
769 #ifndef TINY
770 if (!(vt & VT_PTRMASK))
771 error("pointer expected");
772 #endif
773 vt = (vt - VT_PTRINC) | VT_LVAL;
774 } else if (t == '&') {
775 unary();
776 test_lvalue();
777 vt = (vt & VT_LVALN) + VT_PTRINC;
778 } else
779 #ifndef TINY
780 if (t == '!') {
781 unary();
782 if (vt & VT_CMP)
783 vc = vc ^ 1;
784 else
785 vset(VT_JMP, gtst(1, 0));
786 } else
787 if (t == '~') {
788 unary();
789 if ((vt & (VT_CONST | VT_LVAL)) == VT_CONST)
790 vc = ~vc;
791 else {
792 gv();
793 o(0xd0f7);
795 } else
796 if (t == '+') {
797 unary();
798 } else
799 #endif
800 if (t == TOK_INC | t == TOK_DEC) {
801 unary();
802 inc(PRE_ADD, t);
803 } else if (t == '-') {
804 unary();
805 if ((vt & (VT_CONST | VT_LVAL)) == VT_CONST)
806 vc = -vc;
807 else {
808 gv();
809 o(0xd8f7); /* neg %eax */
811 } else
813 if (vat[t] == 0) {
814 if (tok != '(')
815 error("undefined symbol");
816 /* for simple function calls, we tolerate undeclared
817 external reference */
818 external_func(t, VT_FUNC); /* int() function */
820 vset(vat[t], vac[t]);
821 /* if forward reference, we must point to vac[t] */
822 if (vt & VT_FORWARD)
823 vc = t;
827 /* post operations */
828 if (tok == TOK_INC | tok == TOK_DEC) {
829 inc(POST_ADD, tok);
830 next();
831 } else
832 if (tok == '[') {
833 #ifndef TINY
834 if (!(vt & VT_PTRMASK))
835 error("pointer expected");
836 #endif
837 gen_op('+', -1);
838 /* dereference pointer */
839 vt = (vt - VT_PTRINC) | VT_LVAL;
840 skip(']');
841 } else
842 if (tok == '(') {
843 /* function call */
844 /* lvalue is implied */
845 vt = vt & VT_LVALN;
846 if ((vt & VT_CONST) == 0) {
847 /* evaluate function address */
848 gv();
849 o(0x50); /* push %eax */
851 ft = vt;
852 fc = vc;
854 next();
855 t = 0;
856 while (tok != ')') {
857 t = t + 4;
858 expr_eq();
859 gv();
860 o(0x50); /* push %eax */
861 if (tok == ',')
862 next();
864 skip(')');
865 /* horrible, but needed : convert to native ordering (could
866 parse parameters in reverse order, but would cost more
867 code) */
868 n = 0;
869 p = t - 4;
870 while (n < p) {
871 oad(0x24848b, p); /* mov x(%esp,1), %eax */
872 oad(0x248487, n); /* xchg x(%esp,1), %eax */
873 oad(0x248489, p); /* mov %eax, x(%esp,1) */
874 n = n + 4;
875 p = p - 4;
877 if (ft & VT_CONST) {
878 /* forward reference */
879 if (ft & VT_FORWARD) {
880 vac[fc] = psym(0xe8, vac[fc]);
881 } else
882 oad(0xe8, fc - ind - 5);
883 /* return value is variable, and take type from function proto */
884 vt = VT_VAR | (ft & VT_TYPE & VT_FUNCN);
885 } else {
886 oad(0x2494ff, t); /* call *xxx(%esp) */
887 t = t + 4;
888 /* return value is variable, int */
889 vt = VT_VAR;
891 if (t)
892 oad(0xc481, t);
896 void uneq()
898 int ft, fc, b;
900 unary();
901 if (tok == '=' |
902 (tok >= TOK_A_MOD & TOK_A_DIV) |
903 tok == TOK_A_XOR | tok == TOK_A_OR |
904 tok == TOK_A_SHL | tok == TOK_A_SHR) {
905 test_lvalue();
906 fc = vc;
907 ft = vt;
908 b = (vt & VT_TYPE) == VT_BYTE;
909 if (ft & VT_VAR)
910 o(0x50); /* push %eax */
911 if (tok == '=') {
912 next();
913 expr_eq();
914 #ifndef TINY
915 if ((vt & VT_PTRMASK) != (ft & VT_PTRMASK))
916 warning("incompatible type");
917 #endif
918 gv(); /* generate value */
919 } else
920 gen_op(tok & 0x7f, -2); /* XXX: incorrect, must call expr_eq */
922 if (ft & VT_VAR) {
923 o(0x59); /* pop %ecx */
924 o(0x0189 - b); /* mov %eax/%al, (%ecx) */
925 } else if (ft & VT_LOCAL)
926 oad(0x8589 - b, fc); /* mov %eax/%al,xxx(%ebp) */
927 else
928 oad(0xa3 - b, fc); /* mov %eax/%al,xxx */
932 void sum(l)
934 #ifndef TINY
935 int t;
936 #endif
937 if (l == 0)
938 uneq();
939 else {
940 sum(--l);
941 while ((l == 0 & (tok == '*' | tok == '/' | tok == '%')) |
942 (l == 1 & (tok == '+' | tok == '-')) |
943 #ifndef TINY
944 (l == 2 & (tok == TOK_SHL | tok == TOK_SHR)) |
945 #endif
946 (l == 3 & (tok >= TOK_LT & tok <= TOK_GT)) |
947 (l == 4 & (tok == TOK_EQ | tok == TOK_NE)) |
948 (l == 5 & tok == '&') |
949 (l == 6 & tok == '^') |
950 (l == 7 & tok == '|')) {
951 gen_op(tok, l);
956 #ifdef TINY
957 void expr()
959 sum(8);
961 #else
962 void eand()
964 int t;
966 sum(8);
967 t = 0;
968 while (1) {
969 if (tok != TOK_LAND) {
970 if (t) {
971 t = gtst(1, t);
972 vset(VT_JMP | 1, t);
974 break;
976 t = gtst(1, t);
977 next();
978 sum(8);
982 void eor()
984 int t, u;
986 eand();
987 t = 0;
988 while (1) {
989 if (tok != TOK_LOR) {
990 if (t) {
991 t = gtst(0, t);
992 vset(VT_JMP, t);
994 break;
996 t = gtst(0, t);
997 next();
998 eand();
1002 void expr_eq()
1004 int t, u;
1006 eor();
1007 if (tok == '?') {
1008 next();
1009 t = gtst(1, 0);
1010 expr();
1011 gv();
1012 skip(':');
1013 u = psym(0xe9, 0);
1014 gsym(t);
1015 expr_eq();
1016 gv();
1017 gsym(u);
1021 void expr()
1023 while (1) {
1024 expr_eq();
1025 if (tok != ',')
1026 break;
1027 next();
1031 #endif
1033 void block(int *bsym, int *csym)
1035 int a, b, c, d;
1037 if (tok == TOK_IF) {
1038 /* if test */
1039 next();
1040 skip('(');
1041 expr();
1042 skip(')');
1043 a = gtst(1, 0);
1044 block(bsym, csym);
1045 c = tok;
1046 if (c == TOK_ELSE) {
1047 next();
1048 d = psym(0xe9, 0); /* jmp */
1049 gsym(a);
1050 block(bsym, csym);
1051 gsym(d); /* patch else jmp */
1052 } else
1053 gsym(a);
1054 } else if (tok == TOK_WHILE) {
1055 next();
1056 d = ind;
1057 skip('(');
1058 expr();
1059 skip(')');
1060 a = gtst(1, 0);
1061 b = 0;
1062 block(&a, &b);
1063 oad(0xe9, d - ind - 5); /* jmp */
1064 gsym(a);
1065 gsym_addr(b, d);
1066 } else if (tok == '{') {
1067 next();
1068 /* declarations */
1069 decl(VT_LOCAL);
1070 while (tok != '}')
1071 block(bsym, csym);
1072 next();
1073 } else if (tok == TOK_RETURN) {
1074 next();
1075 if (tok != ';') {
1076 expr();
1077 gv();
1079 skip(';');
1080 rsym = psym(0xe9, rsym); /* jmp */
1081 } else if (tok == TOK_BREAK) {
1082 /* compute jump */
1083 if (!bsym)
1084 error("cannot break");
1085 *bsym = psym(0xe9, *bsym);
1086 next();
1087 skip(';');
1088 } else if (tok == TOK_CONTINUE) {
1089 /* compute jump */
1090 if (!csym)
1091 error("cannot continue");
1092 *csym = psym(0xe9, *csym);
1093 next();
1094 skip(';');
1095 } else
1096 #ifndef TINY
1097 if (tok == TOK_FOR) {
1098 int e;
1099 next();
1100 skip('(');
1101 if (tok != ';')
1102 expr();
1103 skip(';');
1104 d = ind;
1105 c = ind;
1106 a = 0;
1107 b = 0;
1108 if (tok != ';') {
1109 expr();
1110 a = gtst(1, 0);
1112 skip(';');
1113 if (tok != ')') {
1114 e = psym(0xe9, 0);
1115 c = ind;
1116 expr();
1117 oad(0xe9, d - ind - 5); /* jmp */
1118 gsym(e);
1120 skip(')');
1121 block(&a, &b);
1122 oad(0xe9, c - ind - 5); /* jmp */
1123 gsym(a);
1124 gsym_addr(b, c);
1125 } else
1126 if (tok == TOK_DO) {
1127 next();
1128 a = 0;
1129 b = 0;
1130 d = ind;
1131 block(&a, &b);
1132 skip(TOK_WHILE);
1133 skip('(');
1134 gsym(b);
1135 expr();
1136 c = gtst(0, 0);
1137 gsym_addr(c, d);
1138 skip(')');
1139 gsym(a);
1140 } else
1141 #endif
1143 if (tok != ';')
1144 expr();
1145 skip(';');
1149 /* 'l' is VT_LOCAL or VT_CONST to define default storage type */
1150 void decl(l)
1152 int *a, t, b, s, align, v, u, n;
1154 while (b = ist()) {
1155 while (1) { /* iterate thru each declaration */
1156 s = 1;
1157 t = typ(&v, b, &s);
1158 if (tok == '{') {
1159 /* patch forward references */
1160 if (vat[v] & VT_FORWARD)
1161 gsym(vac[v]);
1162 /* put function address */
1163 vat[v] = VT_CONST | VT_LVAL | t;
1164 vac[v] = ind;
1165 loc = 0;
1166 o(0xe58955); /* push %ebp, mov %esp, %ebp */
1167 a = oad(0xec81, 0); /* sub $xxx, %esp */
1168 rsym = 0;
1169 block(0, 0);
1170 gsym(rsym);
1171 o(0xc3c9); /* leave, ret */
1172 *a = (-loc + 3) & -4; /* align local size to word &
1173 save local variables */
1174 break;
1175 } else {
1176 if (t & VT_FUNC) {
1177 /* external function definition */
1178 external_func(v, t);
1179 } else {
1180 /* not lvalue if array */
1181 if (!(t & VT_ARRAY))
1182 t |= VT_LVAL;
1183 if (t & VT_EXTERN) {
1184 /* external variable */
1185 n = dlsym(NULL, get_tok_str(v));
1186 if (!n)
1187 error("unknown external variable");
1188 vat[v] = VT_CONST | t;
1189 vac[v] = n;
1190 } else {
1191 u = l;
1192 if (t & VT_STATIC)
1193 u = VT_CONST;
1194 vat[v] = u | t;
1195 if (t & VT_ARRAY)
1196 t -= VT_PTRINC;
1197 align = type_size(t);
1198 s *= align;
1199 if (u == VT_LOCAL) {
1200 /* allocate space down on the stack */
1201 loc = (loc - s) & -align;
1202 vac[v] = loc;
1203 } else {
1204 /* allocate space up in the data space */
1205 glo = (glo + align - 1) & -align;
1206 vac[v] = glo;
1207 glo += s;
1211 if (tok != ',') {
1212 skip(';');
1213 break;
1215 next();
1221 int main(int c, char **v)
1223 int (*t)();
1224 if (c < 2) {
1225 printf("usage: tc src\n");
1226 return 1;
1228 v++;
1229 filename = *v;
1230 file = fopen(filename, "r");
1231 #ifndef TINY
1232 if (!file) {
1233 perror(filename);
1234 exit(1);
1236 #endif
1238 idtable = malloc(SYM_TABLE_SIZE);
1239 #ifdef TINY
1240 memcpy(idtable,
1241 "int\0void\0char\0if\0else\0while\0break\0return\0define\0main", 53);
1242 idptr = idtable + 53;
1243 #else
1244 memcpy(idtable,
1245 "int\0void\0char\0if\0else\0while\0break\0return\0define\0main\0for\0extern\0static\0unsigned\0goto\0do\0continue\0switch\0case\0const\0volatile\0long\0register\0signed\0float\0double\0struct\0union\0typedef\0default\0enum", 192);
1246 idptr = idtable + 192;
1247 #endif
1248 glo = malloc(DATA_SIZE);
1249 prog = malloc(TEXT_SIZE);
1250 vac = malloc(VAR_TABLE_SIZE);
1251 vat = malloc(VAR_TABLE_SIZE);
1252 macro_stack = malloc(256);
1253 macro_stack_ptr = macro_stack;
1254 ind = prog;
1255 line_num = 1;
1256 next();
1257 decl(VT_CONST);
1258 #ifdef TEST
1260 FILE *f;
1261 f = fopen(v[1], "w");
1262 fwrite((void *)prog, 1, ind - prog, f);
1263 fclose(f);
1264 return 0;
1266 #else
1267 t = vac[TOK_MAIN];
1268 #ifndef TINY
1269 if (!t)
1270 error("main() not defined");
1271 #endif
1272 return (*t)(c - 1, v);
1273 #endif