fix defined() handling
[tinycc.git] / tcc.c
blob04c309a817c5feb8d100ddbe8f69087545f3845f
1 /*
2 * TCC - Tiny C Compiler
3 *
4 * Copyright (c) 2001 Fabrice Bellard
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 #include "tcclib.h"
22 #define INCLUDE_PATH "/usr/include"
24 #define TEXT_SIZE 50000
25 #define DATA_SIZE 50000
26 #define SYM_TABLE_SIZE 10000
27 #define MACRO_STACK_SIZE 32
28 #define INCLUDE_STACK_SIZE 32
29 #define IFDEF_STACK_SIZE 64
31 #define NB_REGS 3
33 /* symbol management */
34 typedef struct Sym {
35 int v; /* symbol token */
36 int t; /* associated type */
37 int c; /* associated number */
38 struct Sym *next; /* next related symbol */
39 struct Sym *prev; /* prev symbol in stack */
40 } Sym;
42 #define SYM_STRUCT 0x40000000 /* struct/union/enum symbol space */
43 #define SYM_FIELD 0x20000000 /* struct/union field symbol space */
45 #define FUNC_NEW 1 /* ansi function prototype */
46 #define FUNC_OLD 2 /* old function prototype */
47 #define FUNC_ELLIPSIS 3 /* ansi function prototype with ... */
49 typedef struct {
50 FILE *file;
51 char *filename;
52 int line_num;
53 } IncludeFile;
55 /* loc : local variable index
56 glo : global variable index
57 ind : output code ptr
58 rsym: return symbol
59 prog: output code
60 anon_sym: anonymous symbol index
62 FILE *file;
63 int tok, tok1, tokc, rsym, anon_sym,
64 prog, ind, loc, glo, vt, *vstack, *vstack_ptr,
65 vc, line_num;
66 char *idtable, *idptr, *filename;
67 Sym *define_stack, *global_stack, *local_stack, *label_stack;
69 char *macro_stack[MACRO_STACK_SIZE], **macro_stack_ptr, *macro_ptr;
70 IncludeFile include_stack[INCLUDE_STACK_SIZE], *include_stack_ptr;
71 int ifdef_stack[IFDEF_STACK_SIZE], *ifdef_stack_ptr;
73 /* The current value can be: */
74 #define VT_VALMASK 0x000f
75 #define VT_CONST 0x000a /* constant in vc
76 (must be first non register value) */
77 #define VT_LLOCAL 0x000b /* lvalue, offset on stack */
78 #define VT_LOCAL 0x000c /* offset on stack */
79 #define VT_CMP 0x000d /* the value is stored in processor flags (in vc) */
80 #define VT_JMP 0x000e /* value is the consequence of jmp true */
81 #define VT_JMPI 0x000f /* value is the consequence of jmp false */
82 #define VT_LVAL 0x0010 /* var is an lvalue */
83 #define VT_LVALN -17 /* ~VT_LVAL */
84 #define VT_FORWARD 0x0020 /* value is forward reference
85 (only used for functions) */
87 #define VT_VOID 0x00040
88 #define VT_BYTE 0x00080 /* byte type */
89 #define VT_PTR 0x00100 /* pointer increment */
90 #define VT_UNSIGNED 0x00200 /* unsigned type */
91 #define VT_ARRAY 0x00400 /* array type (only used in parsing) */
92 #define VT_ENUM 0x00800 /* enum definition */
93 #define VT_FUNC 0x01000 /* function type */
94 #define VT_STRUCT 0x002000 /* struct/union definition */
95 #define VT_TYPEDEF 0x004000 /* typedef definition */
96 #define VT_EXTERN 0x008000 /* extern definition */
97 #define VT_STATIC 0x010000 /* static variable */
98 #define VT_STRUCT_SHIFT 17 /* structure/enum name shift (12 bits lefts) */
100 #define VT_TYPE 0xffffffc0 /* type mask */
101 #define VT_TYPEN 0x0000003f /* ~VT_TYPE */
102 #define VT_FUNCN -4097 /* ~VT_FUNC */
105 /* Special infos */
107 /* token values */
109 /* warning: the following compare tokens depend on i386 asm code */
110 #define TOK_ULT 0x92
111 #define TOK_UGE 0x93
112 #define TOK_EQ 0x94
113 #define TOK_NE 0x95
114 #define TOK_ULE 0x96
115 #define TOK_UGT 0x97
116 #define TOK_LT 0x9c
117 #define TOK_GE 0x9d
118 #define TOK_LE 0x9e
119 #define TOK_GT 0x9f
121 #define TOK_LAND 0xa0
122 #define TOK_LOR 0xa1
124 #define TOK_DEC 0xa2
125 #define TOK_MID 0xa3 /* inc/dec, to void constant */
126 #define TOK_INC 0xa4
127 #define TOK_ARROW 0xa7
128 #define TOK_DOTS 0xa8 /* three dots */
129 #define TOK_SHR 0xa9 /* unsigned shift right */
130 #define TOK_UDIV 0xb0 /* unsigned division */
131 #define TOK_UMOD 0xb1 /* unsigned modulo */
132 #define TOK_PDIV 0xb2 /* fast division with undefined rounding for pointers */
133 #define TOK_NUM 0xb3 /* number in tokc */
135 #define TOK_SHL 0x01 /* shift left */
136 #define TOK_SAR 0x02 /* signed shift right */
138 /* assignement operators : normal operator or 0x80 */
139 #define TOK_A_MOD 0xa5
140 #define TOK_A_AND 0xa6
141 #define TOK_A_MUL 0xaa
142 #define TOK_A_ADD 0xab
143 #define TOK_A_SUB 0xad
144 #define TOK_A_DIV 0xaf
145 #define TOK_A_XOR 0xde
146 #define TOK_A_OR 0xfc
147 #define TOK_A_SHL 0x81
148 #define TOK_A_SAR 0x82
150 enum {
151 TOK_INT = 256,
152 TOK_VOID,
153 TOK_CHAR,
154 TOK_IF,
155 TOK_ELSE,
156 TOK_WHILE,
157 TOK_BREAK,
158 TOK_RETURN,
159 TOK_FOR,
160 TOK_EXTERN,
161 TOK_STATIC,
162 TOK_UNSIGNED,
163 TOK_GOTO,
164 TOK_DO,
165 TOK_CONTINUE,
166 TOK_SWITCH,
167 TOK_CASE,
169 /* ignored types Must have contiguous values */
170 TOK_CONST,
171 TOK_VOLATILE,
172 TOK_LONG,
173 TOK_REGISTER,
174 TOK_SIGNED,
175 TOK_AUTO,
176 TOK_INLINE,
178 /* unsupported type */
179 TOK_FLOAT,
180 TOK_DOUBLE,
182 TOK_STRUCT,
183 TOK_UNION,
184 TOK_TYPEDEF,
185 TOK_DEFAULT,
186 TOK_ENUM,
187 TOK_SIZEOF,
189 /* preprocessor only */
190 TOK_DEFINE,
191 TOK_INCLUDE,
192 TOK_IFDEF,
193 TOK_IFNDEF,
194 TOK_ELIF,
195 TOK_ENDIF,
196 TOK_DEFINED,
198 /* special identifiers */
199 TOK_MAIN,
202 void sum();
203 void next();
204 int expr_const();
205 void expr_eq();
206 void expr();
207 void decl();
208 int gv();
209 void move_reg();
210 void save_reg();
212 int isid(c)
214 return (c >= 'a' & c <= 'z') |
215 (c >= 'A' & c <= 'Z') |
216 c == '_';
219 int isnum(c)
221 return c >= '0' & c <= '9';
224 #ifndef TINY
226 void printline()
228 IncludeFile *f;
229 for(f = include_stack; f < include_stack_ptr; f++)
230 printf("In file included from %s:%d:\n", f->filename, f->line_num);
231 printf("%s:%d: ", filename, line_num);
234 /* XXX: use stderr ? */
235 void error(char *msg)
237 printline();
238 printf("%s\n", msg);
239 exit(1);
242 void expect(char *msg)
244 printline();
245 printf("%s expected\n", msg);
246 exit(1);
249 void warning(char *msg)
251 printline();
252 printf("warning: %s\n", msg);
255 void skip(c)
257 if (tok != c) {
258 printline();
259 printf("'%c' expected\n", c);
260 exit(1);
262 next();
265 void test_lvalue()
267 if (!(vt & VT_LVAL))
268 expect("lvalue");
271 #else
273 #define skip(c) next()
274 #define test_lvalue()
276 #endif
278 char *get_tok_str(int v)
280 int t;
281 char *p;
282 p = idtable;
283 t = 256;
284 while (t != v) {
285 if (p >= idptr)
286 return 0;
287 while (*p++);
288 t++;
290 return p;
293 /* find a symbol and return its associated structure. 's' is the top
294 of the symbol stack */
295 Sym *sym_find1(Sym *s, int v)
297 while (s) {
298 if (s->v == v)
299 return s;
300 s = s->prev;
302 return 0;
305 Sym *sym_push1(Sym **ps, int v, int t, int c)
307 Sym *s;
308 s = malloc(sizeof(Sym));
309 if (!s)
310 error("memory full");
311 s->v = v;
312 s->t = t;
313 s->c = c;
314 s->next = 0;
315 s->prev = *ps;
316 *ps = s;
317 return s;
320 /* find a symbol in the right symbol space */
321 Sym *sym_find(int v)
323 Sym *s;
324 s = sym_find1(local_stack, v);
325 if (!s)
326 s = sym_find1(global_stack, v);
327 return s;
330 /* push a given symbol on the symbol stack */
331 Sym *sym_push(int v, int t, int c)
333 // printf("sym_push: %x %s type=%x\n", v, get_tok_str(v), t);
334 if (local_stack)
335 return sym_push1(&local_stack, v, t, c);
336 else
337 return sym_push1(&global_stack, v, t, c);
340 /* pop symbols until top reaches 'b' */
341 void sym_pop(Sym **ps, Sym *b)
343 Sym *s, *ss;
345 s = *ps;
346 while(s != b) {
347 ss = s->prev;
348 // printf("sym_pop: %x %s type=%x\n", s->v, get_tok_str(s->v), s->t);
349 free(s);
350 s = ss;
352 *ps = b;
355 int ch, ch1;
357 /* read next char from current input file */
358 void inp()
360 int c;
362 redo:
363 ch1 = fgetc(file);
364 if (ch1 == -1) {
365 if (include_stack_ptr == include_stack)
366 return;
367 /* pop include stack */
368 fclose(file);
369 free(filename);
370 include_stack_ptr--;
371 file = include_stack_ptr->file;
372 filename = include_stack_ptr->filename;
373 line_num = include_stack_ptr->line_num;
374 goto redo;
376 if (ch1 == '\n')
377 line_num++;
378 // printf("ch1=%c 0x%x\n", ch1, ch1);
381 /* input with '\\n' handling and macro subtitution if in macro state */
382 void minp()
384 if (macro_ptr != 0) {
385 ch = *macro_ptr++;
386 /* end of macro ? */
387 if (ch == '\0') {
388 macro_ptr = *--macro_stack_ptr;
389 ch = (int)*--macro_stack_ptr;
391 } else {
392 redo:
393 ch = ch1;
394 inp();
395 if (ch == '\\' && ch1 == '\n') {
396 inp();
397 goto redo;
400 // printf("ch=%c 0x%x\n", ch, ch);
403 /* same as minp, but also skip comments */
404 /* XXX: skip strings & chars */
405 void cinp()
407 int c;
409 if (ch1 == '/') {
410 inp();
411 if (ch1 == '/') {
412 /* single line C++ comments */
413 inp();
414 while (ch1 != '\n' && ch1 != -1)
415 inp();
416 inp();
417 ch = ' '; /* return space */
418 } else if (ch1 == '*') {
419 /* C comments */
420 inp();
421 while (ch1 != -1) {
422 c = ch1;
423 inp();
424 if (c == '*' && ch1 == '/') {
425 inp();
426 ch = ' '; /* return space */
427 break;
430 } else {
431 ch = '/';
433 } else {
434 minp();
438 void skip_spaces()
440 while (ch == ' ' || ch == '\t')
441 cinp();
444 /* skip block of text until #else, #elif or #endif. skip also pairs of
445 #if/#endif */
446 void preprocess_skip()
448 int a;
449 a = 0;
450 while (1) {
451 while (ch != '\n') {
452 if (ch == -1)
453 expect("#endif");
454 cinp();
456 cinp();
457 skip_spaces();
458 if (ch == '#') {
459 cinp();
460 next();
461 if (a == 0 &&
462 (tok == TOK_ELSE || tok == TOK_ELIF || tok == TOK_ENDIF))
463 break;
464 if (tok == TOK_IF || tok == TOK_IFDEF || tok == TOK_IFNDEF)
465 a++;
466 else if (tok == TOK_ENDIF)
467 a--;
472 /* parse until eol and add given char */
473 char *get_str(c)
475 char *str;
476 int size, n;
478 str = NULL;
479 size = 0;
480 n = 0;
481 while (1) {
482 if ((n + 1) >= size) {
483 size += 128;
484 str = realloc(str, size);
485 if (!str)
486 error("memory full");
488 if (ch == -1 || ch == '\n') {
489 str[n++] = c;
490 str[n++] = '\0';
491 break;
493 str[n++] = ch;
494 cinp();
496 return str;
499 /* return next token without macro substitution */
500 void next_nomacro()
502 Sym *s;
503 /* hack to avoid replacing id by defined value */
504 s = define_stack;
505 define_stack = 0;
506 next();
507 define_stack = s;
510 /* XXX: not correct yet (need to ensure it is constant) */
511 int expr_preprocess()
513 int c;
515 if ((macro_stack_ptr - macro_stack) >= MACRO_STACK_SIZE)
516 error("too many nested macros");
517 *macro_stack_ptr++ = (char *)'\n';
518 *macro_stack_ptr++ = macro_ptr;
519 macro_ptr = get_str(';');
520 cinp();
521 next();
522 c = expr_const();
523 ch = '\n';
524 return c != 0;
527 void preprocess()
529 char *str;
530 int size, n, c, v;
531 char buf[1024], *q, *p;
532 char buf1[1024];
533 FILE *f;
535 cinp();
536 next_nomacro();
537 redo:
538 if (tok == TOK_DEFINE) {
539 next_nomacro(); /* XXX: should pass parameter to avoid macro subst */
540 skip_spaces();
541 /* now 'tok' is the macro symbol */
542 /* a space is inserted after each macro */
543 str = get_str(' ');
544 printf("define %s '%s'\n", get_tok_str(tok), str);
545 sym_push1(&define_stack, tok, 0, (int)str);
546 } else if (tok == TOK_INCLUDE) {
547 skip_spaces();
548 if (ch == '<') {
549 c = '>';
550 goto read_name;
551 } else if (ch == '\"') {
552 c = ch;
553 read_name:
554 minp();
555 q = buf;
556 while (ch != c && ch != '\n' && ch != -1) {
557 if ((q - buf) < sizeof(buf) - 1)
558 *q++ = ch;
559 minp();
561 *q = '\0';
562 if (include_stack_ptr >= include_stack + INCLUDE_STACK_SIZE)
563 error("memory full");
564 if (c == '\"') {
565 /* first search in current dir if "header.h" */
566 /* XXX: buffer overflow */
567 size = 0;
568 p = strrchr(filename, '/');
569 if (p)
570 size = p + 1 - filename;
571 memcpy(buf1, filename, size);
572 buf1[size] = '\0';
573 strcat(buf1, buf);
574 f = fopen(buf1, "r");
575 if (f)
576 goto found;
578 /* now search in standard include path */
579 strcpy(buf1, INCLUDE_PATH);
580 strcat(buf1, "/");
581 strcat(buf1, buf);
582 f = fopen(buf1, "r");
583 if (!f)
584 error("include file not found");
585 found:
586 /* push current file in stack */
587 /* XXX: fix current line init */
588 include_stack_ptr->file = file;
589 include_stack_ptr->filename = filename;
590 include_stack_ptr->line_num = line_num;
591 include_stack_ptr++;
592 file = f;
593 filename = strdup(buf1);
594 line_num = 1;
596 } else if (tok == TOK_IFNDEF) {
597 c = 1;
598 goto do_ifdef;
599 } else if (tok == TOK_IF) {
600 c = expr_preprocess();
601 goto do_if;
602 } else if (tok == TOK_IFDEF) {
603 c = 0;
604 do_ifdef:
605 next_nomacro();
606 c = (sym_find1(define_stack, tok) != 0) ^ c;
607 do_if:
608 if (ifdef_stack_ptr >= ifdef_stack + IFDEF_STACK_SIZE)
609 error("memory full");
610 *ifdef_stack_ptr++ = c;
611 goto test_skip;
612 } else if (tok == TOK_ELSE) {
613 if (ifdef_stack_ptr == ifdef_stack ||
614 (ifdef_stack_ptr[-1] & 2))
615 error("#else after #else");
616 c = (ifdef_stack_ptr[-1] ^= 3);
617 goto test_skip;
618 } else if (tok == TOK_ELIF) {
619 if (ifdef_stack_ptr == ifdef_stack ||
620 ifdef_stack_ptr[-1] > 1)
621 error("#elif after #else");
622 c = expr_preprocess();
623 ifdef_stack_ptr[-1] = c;
624 test_skip:
625 if (!(c & 1)) {
626 preprocess_skip();
627 goto redo;
629 } else if (tok == TOK_ENDIF) {
630 if (ifdef_stack_ptr == ifdef_stack)
631 expect("#if");
632 ifdef_stack_ptr--;
634 /* ignore other preprocess commands or #! for C scripts */
635 while (ch != '\n' && ch != -1)
636 cinp();
639 /* read a number in base b */
640 int getn(b)
642 int n, t;
643 n = 0;
644 while (1) {
645 if (ch >= 'a' & ch <= 'f')
646 t = ch - 'a' + 10;
647 else if (ch >= 'A' & ch <= 'F')
648 t = ch - 'A' + 10;
649 else if (isnum(ch))
650 t = ch - '0';
651 else
652 break;
653 if (t < 0 | t >= b)
654 break;
655 n = n * b + t;
656 cinp();
658 return n;
661 void next()
663 int v, b;
664 char *q, *p;
665 Sym *s;
667 /* special 'ungettok' case for label parsing */
668 if (tok1) {
669 tok = tok1;
670 tok1 = 0;
671 return;
673 redo:
674 /* skip spaces */
675 while(1) {
676 while (ch == '\n') {
677 cinp();
678 while (ch == ' ' || ch == 9)
679 cinp();
680 if (ch == '#') {
681 /* preprocessor command if # at start of line after
682 spaces */
683 preprocess();
686 if (ch != ' ' && ch != 9)
687 break;
688 cinp();
690 if (isid(ch)) {
691 q = idptr;
692 while(isid(ch) | isnum(ch)) {
693 *q++ = ch;
694 cinp();
696 *q++ = '\0';
697 p = idtable;
698 tok = 256;
699 while (p < idptr) {
700 if (strcmp(p, idptr) == 0)
701 break;
702 while (*p++);
703 tok++;
705 // printf("id=%s\n", idptr);
706 /* if not found, add symbol */
707 if (p == idptr)
708 idptr = q;
709 /* if symbol is a define, prepare substitution */
710 if (s = sym_find1(define_stack, tok)) {
711 if ((macro_stack_ptr - macro_stack) >= MACRO_STACK_SIZE)
712 error("too many nested macros");
713 *macro_stack_ptr++ = (char *)ch;
714 *macro_stack_ptr++ = macro_ptr;
715 macro_ptr = (char *)s->c;
716 cinp();
717 goto redo;
719 } else if (isnum(ch)) {
720 /* number */
721 b = 10;
722 if (ch == '0') {
723 cinp();
724 b = 8;
725 if (ch == 'x') {
726 cinp();
727 b = 16;
730 tokc = getn(b);
731 tok = TOK_NUM;
732 } else {
733 #ifdef TINY
734 q = "<=\236>=\235!=\225++\244--\242==\224";
735 #else
736 q = "<=\236>=\235!=\225&&\240||\241++\244--\242==\224<<\1>>\2+=\253-=\255*=\252/=\257%=\245&=\246^=\336|=\374->\247..\250";
737 #endif
738 /* two chars */
739 tok = ch;
740 cinp();
741 while (*q) {
742 if (*q == tok & q[1] == ch) {
743 cinp();
744 tok = q[2] & 0xff;
745 /* three chars tests */
746 if (tok == TOK_SHL | tok == TOK_SAR) {
747 if (ch == '=') {
748 tok = tok | 0x80;
749 cinp();
751 } else if (tok == TOK_DOTS) {
752 if (ch != '.')
753 error("parse error");
754 cinp();
756 return;
758 q = q + 3;
760 /* single char substitutions */
761 if (tok == '<')
762 tok = TOK_LT;
763 else if (tok == '>')
764 tok = TOK_GT;
766 // printf("tok=%x\n", tok);
769 void swap(int *p, int *q)
771 int t;
772 t = *p;
773 *p = *q;
774 *q = t;
777 void vset(t, v)
779 vt = t;
780 vc = v;
783 /******************************************************/
784 /* X86 code generator */
786 void g(c)
788 *(char *)ind++ = c;
791 void o(c)
793 while (c) {
794 g(c);
795 c = c / 256;
799 /* output a symbol and patch all calls to it */
800 void gsym_addr(t, a)
802 int n;
803 while (t) {
804 n = *(int *)t; /* next value */
805 *(int *)t = a - t - 4;
806 t = n;
810 void gsym(t)
812 gsym_addr(t, ind);
815 /* psym is used to put an instruction with a data field which is a
816 reference to a symbol. It is in fact the same as oad ! */
817 #define psym oad
819 /* instruction + 4 bytes data. Return the address of the data */
820 int oad(c, s)
822 o(c);
823 *(int *)ind = s;
824 s = ind;
825 ind = ind + 4;
826 return s;
829 /* XXX: generate correct pointer for forward references to functions */
830 /* r = (ft, fc) */
831 void load(r, ft, fc)
833 int v, t;
835 v = ft & VT_VALMASK;
836 if (ft & VT_LVAL) {
837 if (v == VT_LLOCAL) {
838 load(r, VT_LOCAL | VT_LVAL, fc);
839 v = r;
841 if ((ft & VT_TYPE) == VT_BYTE)
842 o(0xbe0f); /* movsbl */
843 else
844 o(0x8b); /* movl */
845 if (v == VT_CONST) {
846 oad(0x05 + r * 8, fc); /* 0xXX, r */
847 } else if (v == VT_LOCAL) {
848 oad(0x85 + r * 8, fc); /* xx(%ebp), r */
849 } else {
850 g(0x00 + r * 8 + v); /* (v), r */
852 } else {
853 if (v == VT_CONST) {
854 oad(0xb8 + r, fc); /* mov $xx, r */
855 } else if (v == VT_LOCAL) {
856 o(0x8d);
857 oad(0x85 + r * 8, fc); /* lea xxx(%ebp), r */
858 } else if (v == VT_CMP) {
859 oad(0xb8 + r, 0); /* mov $0, r */
860 o(0x0f); /* setxx %br */
861 o(fc);
862 o(0xc0 + r);
863 } else if (v == VT_JMP || v == VT_JMPI) {
864 t = v & 1;
865 oad(0xb8 + r, t); /* mov $1, r */
866 oad(0xe9, 5); /* jmp after */
867 gsym(fc);
868 oad(0xb8 + r, t ^ 1); /* mov $0, r */
869 } else if (v != r) {
870 o(0x89);
871 o(0xc0 + r + v * 8); /* mov v, r */
876 /* (ft, fc) = r */
877 /* WARNING: r must not be allocated on the stack */
878 void store(r, ft, fc)
880 int fr, b;
882 fr = ft & VT_VALMASK;
883 b = (ft & VT_TYPE) == VT_BYTE;
884 o(0x89 - b);
885 if (fr == VT_CONST) {
886 oad(0x05 + r * 8, fc); /* mov r,xxx */
887 } else if (fr == VT_LOCAL) {
888 oad(0x85 + r * 8, fc); /* mov r,xxx(%ebp) */
889 } else if (ft & VT_LVAL) {
890 g(fr + r * 8); /* mov r, (fr) */
891 } else if (fr != r) {
892 o(0xc0 + fr + r * 8); /* mov r, fr */
896 int gjmp(t)
898 return psym(0xe9, t);
901 /* generate a test. set 'inv' to invert test */
902 int gtst(inv, t)
904 int v, *p;
905 v = vt & VT_VALMASK;
906 if (v == VT_CMP) {
907 /* fast case : can jump directly since flags are set */
908 g(0x0f);
909 t = psym((vc - 16) ^ inv, t);
910 } else if (v == VT_JMP || v == VT_JMPI) {
911 /* && or || optimization */
912 if ((v & 1) == inv) {
913 /* insert vc jump list in t */
914 p = &vc;
915 while (*p != 0)
916 p = (int *)*p;
917 *p = t;
918 t = vc;
919 } else {
920 t = gjmp(t);
921 gsym(vc);
923 } else if ((vt & (VT_VALMASK | VT_LVAL)) == VT_CONST) {
924 /* constant jmp optimization */
925 if ((vc != 0) != inv)
926 t = gjmp(t);
927 } else {
928 v = gv();
929 o(0x85);
930 o(0xc0 + v * 9);
931 g(0x0f);
932 t = psym(0x85 ^ inv, t);
934 return t;
937 /* generate a binary operation 'v = r op fr' instruction and modifies
938 (vt,vc) if needed */
939 void gen_op1(op, r, fr)
941 int t;
942 if (op == '+') {
943 o(0x01);
944 o(0xc0 + r + fr * 8);
945 } else if (op == '-') {
946 o(0x29);
947 o(0xc0 + r + fr * 8);
948 } else if (op == '&') {
949 o(0x21);
950 o(0xc0 + r + fr * 8);
951 } else if (op == '^') {
952 o(0x31);
953 o(0xc0 + r + fr * 8);
954 } else if (op == '|') {
955 o(0x09);
956 o(0xc0 + r + fr * 8);
957 } else if (op == '*') {
958 o(0xaf0f); /* imul fr, r */
959 o(0xc0 + fr + r * 8);
960 } else if (op == TOK_SHL | op == TOK_SHR | op == TOK_SAR) {
961 /* op2 is %ecx */
962 if (fr != 1) {
963 if (r == 1) {
964 r = fr;
965 fr = 1;
966 o(0x87); /* xchg r, %ecx */
967 o(0xc1 + r * 8);
968 } else
969 move_reg(1, fr);
971 o(0xd3); /* shl/shr/sar %cl, r */
972 if (op == TOK_SHL)
973 o(0xe0 + r);
974 else if (op == TOK_SHR)
975 o(0xe8 + r);
976 else
977 o(0xf8 + r);
978 vt = (vt & VT_TYPE) | r;
979 } else if (op == '/' | op == TOK_UDIV | op == TOK_PDIV |
980 op == '%' | op == TOK_UMOD) {
981 save_reg(2); /* save edx */
982 t = save_reg_forced(fr); /* save fr and get op2 location */
983 move_reg(0, r); /* op1 is %eax */
984 if (op == TOK_UDIV | op == TOK_UMOD) {
985 o(0xf7d231); /* xor %edx, %edx, div t(%ebp), %eax */
986 oad(0xb5, t);
987 } else {
988 o(0xf799); /* cltd, idiv t(%ebp), %eax */
989 oad(0xbd, t);
991 if (op == '%' | op == TOK_UMOD)
992 r = 2;
993 else
994 r = 0;
995 vt = (vt & VT_TYPE) | r;
996 } else {
997 o(0x39);
998 o(0xc0 + r + fr * 8); /* cmp fr, r */
999 vset(VT_CMP, op);
1003 /* end of X86 code generator */
1004 /*************************************************************/
1006 int save_reg_forced(r)
1008 int i, l, *p, t;
1009 /* store register */
1010 loc = (loc - 4) & -3;
1011 store(r, VT_LOCAL, loc);
1012 l = loc;
1014 /* modify all stack values */
1015 for(p=vstack;p<vstack_ptr;p+=2) {
1016 i = p[0] & VT_VALMASK;
1017 if (i == r) {
1018 if (p[0] & VT_LVAL)
1019 t = VT_LLOCAL;
1020 else
1021 t = VT_LOCAL;
1022 p[0] = (p[0] & VT_TYPE) | VT_LVAL | t;
1023 p[1] = l;
1026 return l;
1029 /* save r to memory. and mark it as being free */
1030 void save_reg(r)
1032 int i, *p;
1034 /* modify all stack values */
1035 for(p=vstack;p<vstack_ptr;p+=2) {
1036 i = p[0] & VT_VALMASK;
1037 if (i == r) {
1038 save_reg_forced(r);
1039 break;
1044 /* find a free register. If none, save one register */
1045 int get_reg()
1047 int r, i, *p;
1049 /* find a free register */
1050 for(r=0;r<NB_REGS;r++) {
1051 for(p=vstack;p<vstack_ptr;p+=2) {
1052 i = p[0] & VT_VALMASK;
1053 if (i == r)
1054 goto notfound;
1056 return r;
1057 notfound: ;
1060 /* no register left : free the first one on the stack (very
1061 important to start from the bottom to ensure that we don't
1062 spill registers used in gen_op()) */
1063 for(p=vstack;p<vstack_ptr;p+=2) {
1064 r = p[0] & VT_VALMASK;
1065 if (r < VT_CONST) {
1066 save_reg(r);
1067 break;
1070 return r;
1073 void save_regs()
1075 int r, *p;
1076 for(p=vstack;p<vstack_ptr;p+=2) {
1077 r = p[0] & VT_VALMASK;
1078 if (r < VT_CONST) {
1079 save_reg(r);
1084 /* move register 's' to 'r', and flush previous value of r to memory
1085 if needed */
1086 void move_reg(r, s)
1088 if (r != s) {
1089 save_reg(r);
1090 load(r, s, 0);
1094 /* convert a stack entry in register */
1095 int gvp(int *p)
1097 int r;
1098 r = p[0] & VT_VALMASK;
1099 if (r >= VT_CONST || (p[0] & VT_LVAL))
1100 r = get_reg();
1101 load(r, p[0], p[1]);
1102 p[0] = (p[0] & VT_TYPE) | r;
1103 return r;
1106 void vpush()
1108 *vstack_ptr++ = vt;
1109 *vstack_ptr++ = vc;
1110 /* cannot let cpu flags if other instruction are generated */
1111 if ((vt & VT_VALMASK) == VT_CMP)
1112 gvp(vstack_ptr - 2);
1115 void vpop(int *ft, int *fc)
1117 *fc = *--vstack_ptr;
1118 *ft = *--vstack_ptr;
1121 /* generate a value in a register from vt and vc */
1122 int gv()
1124 int r;
1125 vpush();
1126 r = gvp(vstack_ptr - 2);
1127 vpop(&vt, &vc);
1128 return r;
1131 /* handle constant optimizations and various machine independant opt */
1132 void gen_opc(op)
1134 int fr, ft, fc, r, c1, c2, n;
1136 vpop(&ft, &fc);
1137 vpop(&vt, &vc);
1138 c1 = (vt & (VT_VALMASK | VT_LVAL)) == VT_CONST;
1139 c2 = (ft & (VT_VALMASK | VT_LVAL)) == VT_CONST;
1140 if (c1 && c2) {
1141 switch(op) {
1142 case '+': vc += fc; break;
1143 case '-': vc -= fc; break;
1144 case '&': vc &= fc; break;
1145 case '^': vc ^= fc; break;
1146 case '|': vc |= fc; break;
1147 case '*': vc *= fc; break;
1148 case TOK_PDIV:
1149 case '/': vc /= fc; break; /* XXX: zero case ? */
1150 case '%': vc %= fc; break; /* XXX: zero case ? */
1151 case TOK_UDIV: vc = (unsigned)vc / fc; break; /* XXX: zero case ? */
1152 case TOK_UMOD: vc = (unsigned)vc % fc; break; /* XXX: zero case ? */
1153 case TOK_SHL: vc <<= fc; break;
1154 case TOK_SHR: vc = (unsigned)vc >> fc; break;
1155 case TOK_SAR: vc >>= fc; break;
1156 default:
1157 goto general_case;
1159 } else {
1160 /* if commutative ops, put c2 as constant */
1161 if (c1 && (op == '+' || op == '&' || op == '^' ||
1162 op == '|' || op == '*')) {
1163 swap(&vt, &ft);
1164 swap(&vc, &fc);
1165 swap(&c1, &c2);
1167 if (c2 && (((op == '*' || op == '/' || op == TOK_UDIV ||
1168 op == TOK_PDIV) &&
1169 fc == 1) ||
1170 ((op == '+' || op == '-' || op == '|' || op == '^' ||
1171 op == TOK_SHL || op == TOK_SHR || op == TOK_SAR) &&
1172 fc == 0) ||
1173 (op == '&' &&
1174 fc == -1))) {
1175 } else if (c2 && (op == '*' || op == TOK_PDIV || op == TOK_UDIV)) {
1176 /* try to use shifts instead of muls or divs */
1177 if (fc > 0 && (fc & (fc - 1)) == 0) {
1178 n = -1;
1179 while (fc) {
1180 fc >>= 1;
1181 n++;
1183 fc = n;
1184 if (op == '*')
1185 op = TOK_SHL;
1186 else if (op == TOK_PDIV)
1187 op = TOK_SAR;
1188 else
1189 op = TOK_SHR;
1191 goto general_case;
1192 } else {
1193 general_case:
1194 vpush();
1195 vt = ft;
1196 vc = fc;
1197 vpush();
1198 r = gvp(vstack_ptr - 4);
1199 fr = gvp(vstack_ptr - 2);
1200 vpop(&ft, &fc);
1201 vpop(&vt, &vc);
1202 /* call low level op generator */
1203 gen_op1(op, r, fr);
1208 int pointed_size(t)
1210 return type_size(pointed_type(t), &t);
1213 /* generic gen_op: handles types problems */
1214 void gen_op(op)
1216 int u, t1, t2;
1218 vpush();
1219 t1 = vstack_ptr[-4];
1220 t2 = vstack_ptr[-2];
1221 if (op == '+' | op == '-') {
1222 if ((t1 & VT_PTR) && (t2 & VT_PTR)) {
1223 if (op != '-')
1224 error("invalid type");
1225 /* XXX: check that types are compatible */
1226 u = pointed_size(t1);
1227 gen_opc(op);
1228 vpush();
1229 vstack_ptr[-2] &= ~VT_TYPE; /* set to integer */
1230 vset(VT_CONST, u);
1231 gen_op(TOK_PDIV);
1232 } else if ((t1 | t2) & VT_PTR) {
1233 if (t2 & VT_PTR) {
1234 swap(vstack_ptr - 4, vstack_ptr - 2);
1235 swap(vstack_ptr - 3, vstack_ptr - 1);
1236 swap(&t1, &t2);
1238 /* stack-4 contains pointer, stack-2 value to add */
1239 vset(VT_CONST, pointed_size(vstack_ptr[-4]));
1240 gen_op('*');
1241 vpush();
1242 gen_opc(op);
1243 /* put again type if gen_opc() swaped operands */
1244 vt = (vt & VT_TYPEN) | (t1 & VT_TYPE);
1245 } else {
1246 gen_opc(op);
1248 } else {
1249 /* XXX: test types and compute returned value */
1250 if ((t1 | t2) & (VT_UNSIGNED | VT_PTR)) {
1251 if (op == TOK_SAR)
1252 op = TOK_SHR;
1253 else if (op == '/')
1254 op = TOK_UDIV;
1255 else if (op == '%')
1256 op = TOK_UMOD;
1257 else if (op == TOK_LT)
1258 op = TOK_ULT;
1259 else if (op == TOK_GT)
1260 op = TOK_UGT;
1261 else if (op == TOK_LE)
1262 op = TOK_ULE;
1263 else if (op == TOK_GE)
1264 op = TOK_UGE;
1266 gen_opc(op);
1270 /* return type size. Put alignment at 'a' */
1271 int type_size(int t, int *a)
1273 Sym *s;
1275 /* int, enum or pointer */
1276 if (t & VT_STRUCT) {
1277 /* struct/union */
1278 s = sym_find(((unsigned)t >> VT_STRUCT_SHIFT) | SYM_STRUCT);
1279 *a = 4; /* XXX: cannot store it yet. Doing that is safe */
1280 return s->c;
1281 } else if (t & VT_ARRAY) {
1282 s = sym_find(((unsigned)t >> VT_STRUCT_SHIFT));
1283 return type_size(s->t, a) * s->c;
1284 } else if ((t & VT_PTR) |
1285 (t & VT_TYPE) == 0 |
1286 (t & VT_ENUM)) {
1287 *a = 4;
1288 return 4;
1289 } else {
1290 *a = 1;
1291 return 1;
1295 /* return the pointed type of t */
1296 int pointed_type(int t)
1298 Sym *s;
1299 s = sym_find(((unsigned)t >> VT_STRUCT_SHIFT));
1300 return s->t | (t & VT_TYPEN);
1303 int mk_pointer(int t)
1305 int p;
1306 p = anon_sym++;
1307 sym_push(p, t, -1);
1308 return VT_PTR | (p << VT_STRUCT_SHIFT) | (t & VT_TYPEN);
1311 /* store value in lvalue pushed on stack */
1312 void vstore()
1314 int ft, fc, r, t;
1316 r = gv(); /* generate value */
1317 vpush();
1318 ft = vstack_ptr[-4];
1319 fc = vstack_ptr[-3];
1320 if ((ft & VT_VALMASK) == VT_LLOCAL) {
1321 t = get_reg();
1322 load(t, VT_LOCAL | VT_LVAL, fc);
1323 ft = (ft & ~VT_VALMASK) | t;
1325 store(r, ft, fc);
1326 vstack_ptr -= 4;
1329 /* post defines POST/PRE add. c is the token ++ or -- */
1330 void inc(post, c)
1332 int r, r1;
1333 test_lvalue();
1334 if (post)
1335 vpush(); /* room for returned value */
1336 vpush(); /* save lvalue */
1337 r = gv();
1338 vpush(); /* save value */
1339 if (post) {
1340 /* duplicate value */
1341 r1 = get_reg();
1342 load(r1, r, 0); /* move r to r1 */
1343 vstack_ptr[-6] = (vt & VT_TYPE) | r1;
1344 vstack_ptr[-5] = 0;
1346 /* add constant */
1347 vset(VT_CONST, c - TOK_MID);
1348 gen_op('+');
1349 vstore(); /* store value */
1350 if (post)
1351 vpop(&vt, &vc);
1354 int expr_const()
1356 expr_eq();
1357 if ((vt & (VT_CONST | VT_LVAL)) != VT_CONST)
1358 expect("constant");
1359 return vc;
1362 /* enum/struct/union declaration */
1363 int struct_decl(u)
1365 int a, t, b, v, size, align, maxalign, c;
1366 Sym *slast, *s, *ss;
1368 a = tok; /* save decl type */
1369 next();
1370 if (tok != '{') {
1371 v = tok;
1372 next();
1373 /* struct already defined ? return it */
1374 /* XXX: check consistency */
1375 if (s = sym_find(v | SYM_STRUCT)) {
1376 if (s->t != a)
1377 error("invalid type");
1378 u = u | (v << VT_STRUCT_SHIFT);
1379 return u;
1381 } else {
1382 v = anon_sym++;
1384 s = sym_push(v | SYM_STRUCT, a, 0);
1385 /* put struct/union/enum name in type */
1386 u = u | (v << VT_STRUCT_SHIFT);
1388 if (tok == '{') {
1389 next();
1390 /* cannot be empty */
1391 c = 0;
1392 maxalign = 0;
1393 slast = 0;
1394 while (1) {
1395 if (a == TOK_ENUM) {
1396 v = tok;
1397 next();
1398 if (tok == '=') {
1399 next();
1400 c = expr_const();
1402 sym_push(v, VT_CONST, c);
1403 if (tok == ',')
1404 next();
1405 c++;
1406 } else {
1407 b = ist();
1408 while (1) {
1409 t = typ(&v, b);
1410 if (t & (VT_FUNC | VT_TYPEDEF))
1411 error("invalid type");
1412 /* XXX: align & correct type size */
1413 v |= SYM_FIELD;
1414 size = type_size(t, &align);
1415 if (a == TOK_STRUCT) {
1416 c = (c + align - 1) & -align;
1417 ss = sym_push(v, t, c);
1418 c += size;
1419 } else {
1420 ss = sym_push(v, t, 0);
1421 if (size > c)
1422 c = size;
1424 if (align > maxalign)
1425 maxalign = align;
1426 ss->next = slast;
1427 slast = ss;
1428 if (tok == ';' || tok == -1)
1429 break;
1430 skip(',');
1432 skip(';');
1434 if (tok == '}')
1435 break;
1437 skip('}');
1438 s->next = slast;
1439 /* size for struct/union, dummy for enum */
1440 s->c = (c + maxalign - 1) & -maxalign;
1442 return u;
1445 /* return 0 if no type declaration. otherwise, return the basic type
1446 and skip it.
1447 XXX: A '2' is ored to ensure non zero return if int type.
1449 int ist()
1451 int t, n, v;
1452 Sym *s;
1454 t = 0;
1455 while(1) {
1456 #ifndef TINY
1457 if (tok == TOK_ENUM) {
1458 t |= struct_decl(VT_ENUM);
1459 } else if (tok == TOK_STRUCT || tok == TOK_UNION) {
1460 t |= struct_decl(VT_STRUCT);
1461 } else
1462 #endif
1464 if (tok == TOK_CHAR) {
1465 t |= VT_BYTE;
1466 } else if (tok == TOK_VOID) {
1467 t |= VT_VOID;
1468 } else if (tok == TOK_INT |
1469 (tok >= TOK_CONST & tok <= TOK_INLINE)) {
1470 /* ignored types */
1471 } else if (tok == TOK_FLOAT & tok == TOK_DOUBLE) {
1472 error("floats not supported");
1473 } else if (tok == TOK_EXTERN) {
1474 t |= VT_EXTERN;
1475 } else if (tok == TOK_STATIC) {
1476 t |= VT_STATIC;
1477 } else if (tok == TOK_UNSIGNED) {
1478 t |= VT_UNSIGNED;
1479 } else if (tok == TOK_TYPEDEF) {
1480 t |= VT_TYPEDEF;
1481 } else {
1482 s = sym_find(tok);
1483 if (!s || !(s->t & VT_TYPEDEF))
1484 break;
1485 t = s->t & ~VT_TYPEDEF;
1487 next();
1489 t |= 2;
1491 return t;
1494 int post_type(t)
1496 int p, n, pt, l, a;
1497 Sym *last, *s;
1499 if (tok == '(') {
1500 /* function declaration */
1501 next();
1502 a = 4;
1503 l = 0;
1504 last = NULL;
1505 while (tok != ')') {
1506 /* read param name and compute offset */
1507 if (l != FUNC_OLD) {
1508 if (!(pt = ist())) {
1509 if (l) {
1510 error("invalid type");
1511 } else {
1512 l = FUNC_OLD;
1513 goto old_proto;
1516 if (pt & VT_VOID && tok == ')')
1517 break;
1518 l = FUNC_NEW;
1519 pt = typ(&n, pt); /* XXX: should accept
1520 both arg/non arg if v == 0 */
1521 } else {
1522 old_proto:
1523 n = tok;
1524 pt = 0; /* int type */
1525 next();
1527 /* array must be transformed to pointer according to ANSI C */
1528 pt &= ~VT_ARRAY;
1529 /* XXX: size will be different someday */
1530 a = a + 4;
1531 s = sym_push(n | SYM_FIELD, VT_LOCAL | VT_LVAL | pt, a);
1532 s->next = last;
1533 last = s;
1534 if (tok == ',') {
1535 next();
1536 if (l == FUNC_NEW && tok == TOK_DOTS) {
1537 l = FUNC_ELLIPSIS;
1538 next();
1539 break;
1543 skip(')');
1544 t = post_type(t);
1545 /* we push a anonymous symbol which will contain the function prototype */
1546 p = anon_sym++;
1547 s = sym_push(p, t, l);
1548 s->next = last;
1549 t = VT_FUNC | (p << VT_STRUCT_SHIFT);
1550 } else if (tok == '[') {
1551 /* array definition */
1552 next();
1553 n = -1;
1554 if (tok != ']') {
1555 n = expr_const();
1556 if (n < 0)
1557 error("invalid array size");
1559 skip(']');
1560 /* parse next post type */
1561 t = post_type(t);
1563 /* we push a anonymous symbol which will contain the array
1564 element type */
1565 p = anon_sym++;
1566 sym_push(p, t, n);
1567 t = VT_ARRAY | VT_PTR | (p << VT_STRUCT_SHIFT);
1569 return t;
1572 /* Read a type declaration (except basic type), and return the
1573 type. If v is true, then also put variable name in 'vc' */
1574 int typ(int *v, int t)
1576 int u, p;
1577 Sym *s;
1579 t = t & -3; /* suppress the ored '2' */
1580 while (tok == '*') {
1581 next();
1582 t = mk_pointer(t);
1585 /* recursive type */
1586 /* XXX: incorrect if abstract type for functions (e.g. 'int ()') */
1587 if (tok == '(') {
1588 next();
1589 u = typ(v, 0);
1590 skip(')');
1591 } else {
1592 u = 0;
1593 /* type identifier */
1594 if (v) {
1595 *v = tok;
1596 next();
1599 /* append t at the end of u */
1600 t = post_type(t);
1601 if (!u)
1602 return t;
1603 p = u;
1604 while(1) {
1605 s = sym_find((unsigned)p >> VT_STRUCT_SHIFT);
1606 p = s->t;
1607 if (!p) {
1608 s->t = t;
1609 break;
1612 return u;
1615 /* define a new external reference to a function 'v' of type 'u' */
1616 Sym *external_func(v, u)
1618 int t, n, p;
1619 Sym *s;
1620 s = sym_find(v);
1621 if (!s) {
1622 n = dlsym(0, get_tok_str(v));
1623 if (n == 0) {
1624 /* used to generate symbol list */
1625 s = sym_push1(&global_stack,
1626 v, u | VT_CONST | VT_LVAL | VT_FORWARD, 0);
1627 } else {
1628 /* int f() */
1629 s = sym_push1(&global_stack,
1630 v, u | VT_CONST | VT_LVAL, n);
1633 return s;
1636 /* read a character for string or char constant and eval escape codes */
1637 int getq()
1639 int c;
1641 c = ch;
1642 minp();
1643 if (c == '\\') {
1644 if (isnum(ch)) {
1645 return getn(8);
1646 } else {
1647 if (ch == 'n')
1648 c = '\n';
1649 else if (ch == 'r')
1650 c = '\r';
1651 else if (ch == 't')
1652 c = '\t';
1653 else
1654 c = ch;
1655 minp();
1658 return c;
1661 void indir()
1663 if (vt & VT_LVAL)
1664 gv();
1665 if (!(vt & VT_PTR))
1666 expect("pointer");
1667 vt = pointed_type(vt);
1668 if (!(vt & VT_ARRAY)) /* an array is never an lvalue */
1669 vt |= VT_LVAL;
1672 void unary()
1674 int n, t, ft, fc, p, r;
1675 Sym *s;
1677 if (tok == TOK_NUM) {
1678 vset(VT_CONST, tokc);
1679 next();
1680 } else
1681 if (tok == '\'') {
1682 vset(VT_CONST, getq());
1683 next(); /* skip char */
1684 skip('\'');
1685 } else if (tok == '\"') {
1686 /* generate (char *) type */
1687 vset(VT_CONST | mk_pointer(VT_TYPE), glo);
1688 while (tok == '\"') {
1689 while (ch != '\"') {
1690 if (ch == -1)
1691 error("unterminated string");
1692 *(char *)glo++ = getq();
1694 minp();
1695 next();
1697 *(char *)glo++ = 0;
1698 } else if (tok == TOK_DEFINED) {
1699 /* XXX: should only be used in preprocess expr parsing */
1700 next_nomacro();
1701 t = tok;
1702 if (t == '(')
1703 next_nomacro();
1704 vset(VT_CONST, sym_find1(define_stack, tok) != 0);
1705 next();
1706 if (t == '(')
1707 skip(')');
1708 } else {
1709 t = tok;
1710 next();
1711 if (t == '(') {
1712 /* cast ? */
1713 if (t = ist()) {
1714 ft = typ(0, t);
1715 skip(')');
1716 unary();
1717 vt = (vt & VT_TYPEN) | ft;
1718 } else {
1719 expr();
1720 skip(')');
1722 } else if (t == '*') {
1723 unary();
1724 indir();
1725 } else if (t == '&') {
1726 unary();
1727 test_lvalue();
1728 vt = mk_pointer(vt & VT_LVALN);
1729 } else
1730 if (t == '!') {
1731 unary();
1732 if ((vt & VT_VALMASK) == VT_CMP)
1733 vc = vc ^ 1;
1734 else
1735 vset(VT_JMP, gtst(1, 0));
1736 } else
1737 if (t == '~') {
1738 unary();
1739 vpush();
1740 vset(VT_CONST, -1);
1741 gen_op('^');
1742 } else
1743 if (t == '+') {
1744 unary();
1745 } else
1746 if (t == TOK_SIZEOF) {
1747 /* XXX: some code can be generated */
1748 if (tok == '(') {
1749 next();
1750 if (t = ist())
1751 vt = typ(0, t);
1752 else
1753 expr();
1754 skip(')');
1755 } else {
1756 unary();
1758 vset(VT_CONST, type_size(vt, &t));
1759 } else
1760 if (t == TOK_INC | t == TOK_DEC) {
1761 unary();
1762 inc(0, t);
1763 } else if (t == '-') {
1764 vset(VT_CONST, 0);
1765 vpush();
1766 unary();
1767 gen_op('-');
1768 } else
1770 s = sym_find(t);
1771 if (!s) {
1772 if (tok != '(')
1773 error("undefined symbol");
1774 /* for simple function calls, we tolerate undeclared
1775 external reference */
1776 p = anon_sym++;
1777 sym_push1(&global_stack, p, 0, FUNC_OLD);
1778 /* int() function */
1779 s = external_func(t, VT_FUNC | (p << VT_STRUCT_SHIFT));
1781 vset(s->t, s->c);
1782 /* if forward reference, we must point to s->c */
1783 if (vt & VT_FORWARD)
1784 vc = (int)&s->c;
1788 /* post operations */
1789 while (1) {
1790 if (tok == TOK_INC | tok == TOK_DEC) {
1791 inc(1, tok);
1792 next();
1793 } else if (tok == '.' | tok == TOK_ARROW) {
1794 /* field */
1795 if (tok == TOK_ARROW)
1796 indir();
1797 test_lvalue();
1798 vt &= VT_LVALN;
1799 next();
1800 /* expect pointer on structure */
1801 if (!(vt & VT_STRUCT))
1802 expect("struct or union");
1803 s = sym_find(((unsigned)vt >> VT_STRUCT_SHIFT) | SYM_STRUCT);
1804 /* find field */
1805 tok |= SYM_FIELD;
1806 while (s = s->next) {
1807 if (s->v == tok)
1808 break;
1810 if (!s)
1811 error("field not found");
1812 /* add field offset to pointer */
1813 vt = vt & VT_TYPEN; /* change type to int */
1814 vpush();
1815 vset(VT_CONST, s->c);
1816 gen_op('+');
1817 /* change type to field type, and set to lvalue */
1818 vt = (vt & VT_TYPEN) | VT_LVAL | s->t;
1819 next();
1820 } else if (tok == '[') {
1821 next();
1822 vpush();
1823 expr();
1824 gen_op('+');
1825 indir();
1826 skip(']');
1827 } else if (tok == '(') {
1828 /* function call */
1829 save_regs(); /* save used temporary registers */
1830 /* lvalue is implied */
1831 vt = vt & VT_LVALN;
1832 if ((vt & VT_VALMASK) != VT_CONST) {
1833 /* evaluate function address */
1834 r = gv();
1835 o(0x50 + r); /* push r */
1837 ft = vt;
1838 fc = vc;
1839 next();
1840 t = 0;
1841 while (tok != ')') {
1842 t = t + 4;
1843 expr_eq();
1844 r = gv();
1845 o(0x50 + r); /* push r */
1846 if (tok == ',')
1847 next();
1849 skip(')');
1850 /* horrible, but needed : convert to native ordering (could
1851 parse parameters in reverse order, but would cost more
1852 code) */
1853 n = 0;
1854 p = t - 4;
1855 while (n < p) {
1856 oad(0x24848b, p); /* mov x(%esp,1), %eax */
1857 oad(0x248487, n); /* xchg x(%esp,1), %eax */
1858 oad(0x248489, p); /* mov %eax, x(%esp,1) */
1859 n = n + 4;
1860 p = p - 4;
1862 if ((ft & VT_VALMASK) == VT_CONST) {
1863 /* forward reference */
1864 if (ft & VT_FORWARD) {
1865 *(int *)fc = psym(0xe8, *(int *)fc);
1866 } else
1867 oad(0xe8, fc - ind - 5);
1868 } else {
1869 oad(0x2494ff, t); /* call *xxx(%esp) */
1870 t = t + 4;
1872 if (t)
1873 oad(0xc481, t);
1874 /* get return type */
1875 s = sym_find((unsigned)ft >> VT_STRUCT_SHIFT);
1876 vt = s->t | 0; /* return register is eax */
1877 } else {
1878 break;
1883 void uneq()
1885 int t;
1887 unary();
1888 if (tok == '=' |
1889 (tok >= TOK_A_MOD & tok <= TOK_A_DIV) |
1890 tok == TOK_A_XOR | tok == TOK_A_OR |
1891 tok == TOK_A_SHL | tok == TOK_A_SAR) {
1892 test_lvalue();
1893 vpush();
1894 t = tok;
1895 next();
1896 if (t == '=') {
1897 expr_eq();
1898 /* XXX: be more precise */
1899 if ((vt & VT_PTR) != (vstack_ptr[-2] & VT_PTR))
1900 warning("incompatible type");
1901 } else {
1902 vpush();
1903 expr_eq();
1904 gen_op(t & 0x7f);
1906 vstore();
1910 void sum(l)
1912 int ft, fc, t;
1914 if (l == 0)
1915 uneq();
1916 else {
1917 sum(--l);
1918 while ((l == 0 & (tok == '*' | tok == '/' | tok == '%')) |
1919 (l == 1 & (tok == '+' | tok == '-')) |
1920 (l == 2 & (tok == TOK_SHL | tok == TOK_SAR)) |
1921 (l == 3 & ((tok >= TOK_ULE & tok <= TOK_GT) |
1922 tok == TOK_ULT | tok == TOK_UGE)) |
1923 (l == 4 & (tok == TOK_EQ | tok == TOK_NE)) |
1924 (l == 5 & tok == '&') |
1925 (l == 6 & tok == '^') |
1926 (l == 7 & tok == '|')) {
1927 vpush();
1928 t = tok;
1929 next();
1930 sum(l);
1931 gen_op(t);
1936 #ifdef TINY
1937 void expr()
1939 sum(8);
1941 #else
1942 void eand()
1944 int t;
1946 sum(8);
1947 t = 0;
1948 while (1) {
1949 if (tok != TOK_LAND) {
1950 if (t) {
1951 t = gtst(1, t);
1952 vset(VT_JMPI, t);
1954 break;
1956 t = gtst(1, t);
1957 next();
1958 sum(8);
1962 void eor()
1964 int t, u;
1966 eand();
1967 t = 0;
1968 while (1) {
1969 if (tok != TOK_LOR) {
1970 if (t) {
1971 t = gtst(0, t);
1972 vset(VT_JMP, t);
1974 break;
1976 t = gtst(0, t);
1977 next();
1978 eand();
1982 void expr_eq()
1984 int t, u;
1986 eor();
1987 if (tok == '?') {
1988 next();
1989 t = gtst(1, 0);
1990 expr();
1991 gv();
1992 skip(':');
1993 u = gjmp(0);
1994 gsym(t);
1995 expr_eq();
1996 gv();
1997 gsym(u);
2001 void expr()
2003 while (1) {
2004 expr_eq();
2005 if (tok != ',')
2006 break;
2007 next();
2011 #endif
2013 void block(int *bsym, int *csym, int *case_sym, int *def_sym, int case_reg)
2015 int a, b, c, d;
2016 Sym *s;
2018 if (tok == TOK_IF) {
2019 /* if test */
2020 next();
2021 skip('(');
2022 expr();
2023 skip(')');
2024 a = gtst(1, 0);
2025 block(bsym, csym, case_sym, def_sym, case_reg);
2026 c = tok;
2027 if (c == TOK_ELSE) {
2028 next();
2029 d = gjmp(0);
2030 gsym(a);
2031 block(bsym, csym, case_sym, def_sym, case_reg);
2032 gsym(d); /* patch else jmp */
2033 } else
2034 gsym(a);
2035 } else if (tok == TOK_WHILE) {
2036 next();
2037 d = ind;
2038 skip('(');
2039 expr();
2040 skip(')');
2041 a = gtst(1, 0);
2042 b = 0;
2043 block(&a, &b, case_sym, def_sym, case_reg);
2044 oad(0xe9, d - ind - 5); /* jmp */
2045 gsym(a);
2046 gsym_addr(b, d);
2047 } else if (tok == '{') {
2048 next();
2049 /* declarations */
2050 s = local_stack;
2051 decl(VT_LOCAL);
2052 while (tok != '}')
2053 block(bsym, csym, case_sym, def_sym, case_reg);
2054 /* pop locally defined symbols */
2055 sym_pop(&local_stack, s);
2056 next();
2057 } else if (tok == TOK_RETURN) {
2058 next();
2059 if (tok != ';') {
2060 expr();
2061 move_reg(0, gv());
2063 skip(';');
2064 rsym = gjmp(rsym); /* jmp */
2065 } else if (tok == TOK_BREAK) {
2066 /* compute jump */
2067 if (!bsym)
2068 error("cannot break");
2069 *bsym = gjmp(*bsym);
2070 next();
2071 skip(';');
2072 } else if (tok == TOK_CONTINUE) {
2073 /* compute jump */
2074 if (!csym)
2075 error("cannot continue");
2076 *csym = gjmp(*csym);
2077 next();
2078 skip(';');
2079 } else
2080 #ifndef TINY
2081 if (tok == TOK_FOR) {
2082 int e;
2083 next();
2084 skip('(');
2085 if (tok != ';')
2086 expr();
2087 skip(';');
2088 d = ind;
2089 c = ind;
2090 a = 0;
2091 b = 0;
2092 if (tok != ';') {
2093 expr();
2094 a = gtst(1, 0);
2096 skip(';');
2097 if (tok != ')') {
2098 e = gjmp(0);
2099 c = ind;
2100 expr();
2101 oad(0xe9, d - ind - 5); /* jmp */
2102 gsym(e);
2104 skip(')');
2105 block(&a, &b, case_sym, def_sym, case_reg);
2106 oad(0xe9, c - ind - 5); /* jmp */
2107 gsym(a);
2108 gsym_addr(b, c);
2109 } else
2110 if (tok == TOK_DO) {
2111 next();
2112 a = 0;
2113 b = 0;
2114 d = ind;
2115 block(&a, &b, case_sym, def_sym, case_reg);
2116 skip(TOK_WHILE);
2117 skip('(');
2118 gsym(b);
2119 expr();
2120 c = gtst(0, 0);
2121 gsym_addr(c, d);
2122 skip(')');
2123 gsym(a);
2124 } else
2125 if (tok == TOK_SWITCH) {
2126 next();
2127 skip('(');
2128 expr();
2129 case_reg = gv();
2130 skip(')');
2131 a = 0;
2132 b = 0;
2133 c = 0;
2134 block(&a, csym, &b, &c, case_reg);
2135 /* if no default, jmp after switch */
2136 if (c == 0)
2137 c = ind;
2138 /* default label */
2139 gsym_addr(b, c);
2140 /* break label */
2141 gsym(a);
2142 } else
2143 if (tok == TOK_CASE) {
2144 next();
2145 a = expr_const();
2146 if (!case_sym)
2147 expect("switch");
2148 gsym(*case_sym);
2149 vset(case_reg, 0);
2150 vpush();
2151 vset(VT_CONST, a);
2152 gen_op(TOK_EQ);
2153 *case_sym = gtst(1, 0);
2154 skip(':');
2155 block(bsym, csym, case_sym, def_sym, case_reg);
2156 } else
2157 if (tok == TOK_DEFAULT) {
2158 next();
2159 skip(':');
2160 if (!def_sym)
2161 expect("switch");
2162 if (*def_sym)
2163 error("too many 'default'");
2164 *def_sym = ind;
2165 block(bsym, csym, case_sym, def_sym, case_reg);
2166 } else
2167 if (tok == TOK_GOTO) {
2168 next();
2169 s = sym_find1(label_stack, tok);
2170 /* put forward definition if needed */
2171 if (!s)
2172 s = sym_push1(&label_stack, tok, VT_FORWARD, 0);
2173 /* label already defined */
2174 if (s->t & VT_FORWARD)
2175 s->c = gjmp(s->c); /* jmp xxx */
2176 else
2177 oad(0xe9, s->c - ind - 5); /* jmp xxx */
2178 next();
2179 skip(';');
2180 } else
2181 #endif
2183 b = tok;
2184 next();
2185 if (tok == ':') {
2186 next();
2187 /* label case */
2188 s = sym_find1(label_stack, b);
2189 if (s) {
2190 if (!(s->t & VT_FORWARD))
2191 error("multiple defined label");
2192 gsym(s->c);
2193 s->c = ind;
2194 s->t = 0;
2195 } else {
2196 sym_push1(&label_stack, b, 0, ind);
2198 block(bsym, csym, case_sym, def_sym, case_reg);
2199 } else {
2200 /* expression case: go backward of one token */
2201 /* XXX: currently incorrect if number/string/char */
2202 tok1 = tok;
2203 tok = b;
2204 if (tok != ';') {
2205 expr();
2207 skip(';');
2212 /* 'l' is VT_LOCAL or VT_CONST to define default storage type */
2213 void decl(l)
2215 int *a, t, b, size, align, v, u, n;
2216 Sym *sym;
2218 while (b = ist()) {
2219 if ((b & (VT_ENUM | VT_STRUCT)) && tok == ';') {
2220 /* we accept no variable after */
2221 next();
2222 continue;
2224 while (1) { /* iterate thru each declaration */
2225 t = typ(&v, b);
2226 if (tok == '{') {
2227 if (!(t & VT_FUNC))
2228 expect("function defintion");
2229 /* patch forward references */
2230 if ((sym = sym_find(v)) && (sym->t & VT_FORWARD)) {
2231 gsym(sym->c);
2232 sym->c = ind;
2233 sym->t = VT_CONST | VT_LVAL | t;
2234 } else {
2235 /* put function address */
2236 sym_push1(&global_stack, v, VT_CONST | VT_LVAL | t, ind);
2238 /* push a dummy symbol to enable local sym storage */
2239 sym_push1(&local_stack, 0, 0, 0);
2240 /* define parameters */
2241 sym = sym_find((unsigned)t >> VT_STRUCT_SHIFT);
2242 while (sym = sym->next)
2243 sym_push(sym->v & ~SYM_FIELD, sym->t, sym->c);
2244 loc = 0;
2245 o(0xe58955); /* push %ebp, mov %esp, %ebp */
2246 a = (int *)oad(0xec81, 0); /* sub $xxx, %esp */
2247 rsym = 0;
2248 block(0, 0, 0, 0, 0);
2249 gsym(rsym);
2250 o(0xc3c9); /* leave, ret */
2251 *a = (-loc + 3) & -4; /* align local size to word &
2252 save local variables */
2253 sym_pop(&label_stack, 0); /* reset label stack */
2254 sym_pop(&local_stack, 0); /* reset local stack */
2255 break;
2256 } else {
2257 if (b & VT_TYPEDEF) {
2258 /* save typedefed type */
2259 sym_push(v, t | VT_TYPEDEF, 0);
2260 } else if (t & VT_FUNC) {
2261 /* XXX: incorrect to flush, but needed while
2262 waiting for function prototypes */
2263 /* external function definition */
2264 external_func(v, t);
2265 } else {
2266 /* not lvalue if array */
2267 if (!(t & VT_ARRAY))
2268 t |= VT_LVAL;
2269 if (t & VT_EXTERN) {
2270 /* external variable */
2271 /* XXX: factorize with external function def */
2272 n = dlsym(NULL, get_tok_str(v));
2273 if (!n)
2274 error("unknown external variable");
2275 sym_push(v, VT_CONST | t, n);
2276 } else {
2277 u = l;
2278 if (t & VT_STATIC)
2279 u = VT_CONST;
2280 u |= t;
2281 size = type_size(t, &align);
2282 if (size < 0)
2283 error("invalid size");
2284 if ((u & VT_VALMASK) == VT_LOCAL) {
2285 /* allocate space down on the stack */
2286 loc = (loc - size) & -align;
2287 sym_push(v, u, loc);
2288 } else {
2289 /* allocate space up in the data space */
2290 glo = (glo + align - 1) & -align;
2291 sym_push(v, u, glo);
2292 glo += size;
2296 if (tok != ',') {
2297 skip(';');
2298 break;
2300 next();
2306 int main(int c, char **v)
2308 Sym *s;
2309 int (*t)();
2310 if (c < 2) {
2311 printf("usage: tcc source ...\n");
2312 return 1;
2314 v++;
2315 filename = *v;
2316 line_num = 1;
2317 file = fopen(filename, "r");
2318 if (!file) {
2319 perror(filename);
2320 exit(1);
2322 include_stack_ptr = include_stack;
2323 ifdef_stack_ptr = ifdef_stack;
2325 idtable = malloc(SYM_TABLE_SIZE);
2326 memcpy(idtable,
2327 "int\0void\0char\0if\0else\0while\0break\0return\0for\0extern\0static\0unsigned\0goto\0do\0continue\0switch\0case\0const\0volatile\0long\0register\0signed\0auto\0inline\0float\0double\0struct\0union\0typedef\0default\0enum\0sizeof\0define\0include\0ifdef\0ifndef\0elif\0endif\0defined\0main", 251);
2328 idptr = idtable + 251;
2330 glo = malloc(DATA_SIZE);
2331 memset((void *)glo, 0, DATA_SIZE);
2332 prog = malloc(TEXT_SIZE);
2333 vstack = malloc(256);
2334 vstack_ptr = vstack;
2335 macro_stack_ptr = macro_stack;
2336 anon_sym = 1 << (31 - VT_STRUCT_SHIFT);
2337 ind = prog;
2338 inp();
2339 ch = '\n'; /* needed to parse correctly first preprocessor command */
2340 next();
2341 decl(VT_CONST);
2342 if (tok != -1)
2343 expect("declaration");
2344 #ifdef TEST
2346 FILE *f;
2347 f = fopen(v[1], "w");
2348 fwrite((void *)prog, 1, ind - prog, f);
2349 fclose(f);
2350 return 0;
2352 #else
2353 s = sym_find(TOK_MAIN);
2354 if (!s)
2355 error("main() not defined");
2356 t = s->c;
2357 return (*t)(c - 1, v);
2358 #endif