2 * TCC - Tiny C Compiler
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.
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
33 /* symbol management */
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 */
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 ... */
55 /* loc : local variable index
56 glo : global variable index
60 anon_sym: anonymous symbol index
63 int tok
, tok1
, tokc
, rsym
, anon_sym
,
64 prog
, ind
, loc
, glo
, vt
, *vstack
, *vstack_ptr
,
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 */
109 /* warning: the following compare tokens depend on i386 asm code */
121 #define TOK_LAND 0xa0
125 #define TOK_MID 0xa3 /* inc/dec, to void constant */
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
169 /* ignored types Must have contiguous values */
178 /* unsupported type */
189 /* preprocessor only */
198 /* special identifiers */
214 return (c
>= 'a' & c
<= 'z') |
215 (c
>= 'A' & c
<= 'Z') |
221 return c
>= '0' & c
<= '9';
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
)
242 void expect(char *msg
)
245 printf("%s expected\n", msg
);
249 void warning(char *msg
)
252 printf("warning: %s\n", msg
);
259 printf("'%c' expected\n", c
);
273 #define skip(c) next()
274 #define test_lvalue()
278 char *get_tok_str(int v
)
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
)
305 Sym
*sym_push1(Sym
**ps
, int v
, int t
, int c
)
308 s
= malloc(sizeof(Sym
));
310 error("memory full");
320 /* find a symbol in the right symbol space */
324 s
= sym_find1(local_stack
, v
);
326 s
= sym_find1(global_stack
, v
);
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);
335 return sym_push1(&local_stack
, v
, t
, c
);
337 return sym_push1(&global_stack
, v
, t
, c
);
340 /* pop symbols until top reaches 'b' */
341 void sym_pop(Sym
**ps
, Sym
*b
)
348 // printf("sym_pop: %x %s type=%x\n", s->v, get_tok_str(s->v), s->t);
357 /* read next char from current input file */
365 if (include_stack_ptr
== include_stack
)
367 /* pop include stack */
371 file
= include_stack_ptr
->file
;
372 filename
= include_stack_ptr
->filename
;
373 line_num
= include_stack_ptr
->line_num
;
378 // printf("ch1=%c 0x%x\n", ch1, ch1);
381 /* input with '\\n' handling and macro subtitution if in macro state */
384 if (macro_ptr
!= 0) {
388 macro_ptr
= *--macro_stack_ptr
;
389 ch
= (int)*--macro_stack_ptr
;
395 if (ch
== '\\' && ch1
== '\n') {
400 // printf("ch=%c 0x%x\n", ch, ch);
403 /* same as minp, but also skip comments */
404 /* XXX: skip strings & chars */
412 /* single line C++ comments */
414 while (ch1
!= '\n' && ch1
!= -1)
417 ch
= ' '; /* return space */
418 } else if (ch1
== '*') {
424 if (c
== '*' && ch1
== '/') {
426 ch
= ' '; /* return space */
440 while (ch
== ' ' || ch
== '\t')
444 /* skip block of text until #else, #elif or #endif. skip also pairs of
446 void preprocess_skip()
462 (tok
== TOK_ELSE
|| tok
== TOK_ELIF
|| tok
== TOK_ENDIF
))
464 if (tok
== TOK_IF
|| tok
== TOK_IFDEF
|| tok
== TOK_IFNDEF
)
466 else if (tok
== TOK_ENDIF
)
472 /* parse until eol and add given char */
482 if ((n
+ 1) >= size
) {
484 str
= realloc(str
, size
);
486 error("memory full");
488 if (ch
== -1 || ch
== '\n') {
499 /* return next token without macro substitution */
503 /* hack to avoid replacing id by defined value */
510 /* XXX: not correct yet (need to ensure it is constant) */
511 int expr_preprocess()
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(';');
531 char buf
[1024], *q
, *p
;
538 if (tok
== TOK_DEFINE
) {
539 next_nomacro(); /* XXX: should pass parameter to avoid macro subst */
541 /* now 'tok' is the macro symbol */
542 /* a space is inserted after each macro */
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
) {
551 } else if (ch
== '\"') {
556 while (ch
!= c
&& ch
!= '\n' && ch
!= -1) {
557 if ((q
- buf
) < sizeof(buf
) - 1)
562 if (include_stack_ptr
>= include_stack
+ INCLUDE_STACK_SIZE
)
563 error("memory full");
565 /* first search in current dir if "header.h" */
566 /* XXX: buffer overflow */
568 p
= strrchr(filename
, '/');
570 size
= p
+ 1 - filename
;
571 memcpy(buf1
, filename
, size
);
574 f
= fopen(buf1
, "r");
578 /* now search in standard include path */
579 strcpy(buf1
, INCLUDE_PATH
);
582 f
= fopen(buf1
, "r");
584 error("include file not 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
;
593 filename
= strdup(buf1
);
596 } else if (tok
== TOK_IFNDEF
) {
599 } else if (tok
== TOK_IF
) {
600 c
= expr_preprocess();
602 } else if (tok
== TOK_IFDEF
) {
606 c
= (sym_find1(define_stack
, tok
) != 0) ^ c
;
608 if (ifdef_stack_ptr
>= ifdef_stack
+ IFDEF_STACK_SIZE
)
609 error("memory full");
610 *ifdef_stack_ptr
++ = c
;
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);
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
;
629 } else if (tok
== TOK_ENDIF
) {
630 if (ifdef_stack_ptr
== ifdef_stack
)
634 /* ignore other preprocess commands or #! for C scripts */
635 while (ch
!= '\n' && ch
!= -1)
639 /* read a number in base b */
645 if (ch
>= 'a' & ch
<= 'f')
647 else if (ch
>= 'A' & ch
<= 'F')
667 /* special 'ungettok' case for label parsing */
678 while (ch
== ' ' || ch
== 9)
681 /* preprocessor command if # at start of line after
686 if (ch
!= ' ' && ch
!= 9)
692 while(isid(ch
) | isnum(ch
)) {
700 if (strcmp(p
, idptr
) == 0)
705 // printf("id=%s\n", idptr);
706 /* if not found, add symbol */
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
;
719 } else if (isnum(ch
)) {
734 q
= "<=\236>=\235!=\225++\244--\242==\224";
736 q
= "<=\236>=\235!=\225&&\240||\241++\244--\242==\224<<\1>>\2+=\253-=\255*=\252/=\257%=\245&=\246^=\336|=\374->\247..\250";
742 if (*q
== tok
& q
[1] == ch
) {
745 /* three chars tests */
746 if (tok
== TOK_SHL
| tok
== TOK_SAR
) {
751 } else if (tok
== TOK_DOTS
) {
753 error("parse error");
760 /* single char substitutions */
766 // printf("tok=%x\n", tok);
769 void swap(int *p
, int *q
)
783 /******************************************************/
784 /* X86 code generator */
799 /* output a symbol and patch all calls to it */
804 n
= *(int *)t
; /* next value */
805 *(int *)t
= a
- t
- 4;
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 ! */
819 /* instruction + 4 bytes data. Return the address of the data */
829 /* XXX: generate correct pointer for forward references to functions */
837 if (v
== VT_LLOCAL
) {
838 load(r
, VT_LOCAL
| VT_LVAL
, fc
);
841 if ((ft
& VT_TYPE
) == VT_BYTE
)
842 o(0xbe0f); /* movsbl */
846 oad(0x05 + r
* 8, fc
); /* 0xXX, r */
847 } else if (v
== VT_LOCAL
) {
848 oad(0x85 + r
* 8, fc
); /* xx(%ebp), r */
850 g(0x00 + r
* 8 + v
); /* (v), r */
854 oad(0xb8 + r
, fc
); /* mov $xx, r */
855 } else if (v
== VT_LOCAL
) {
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 */
863 } else if (v
== VT_JMP
|| v
== VT_JMPI
) {
865 oad(0xb8 + r
, t
); /* mov $1, r */
866 oad(0xe9, 5); /* jmp after */
868 oad(0xb8 + r
, t
^ 1); /* mov $0, r */
871 o(0xc0 + r
+ v
* 8); /* mov v, r */
877 /* WARNING: r must not be allocated on the stack */
878 void store(r
, ft
, fc
)
882 fr
= ft
& VT_VALMASK
;
883 b
= (ft
& VT_TYPE
) == VT_BYTE
;
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 */
898 return psym(0xe9, t
);
901 /* generate a test. set 'inv' to invert test */
907 /* fast case : can jump directly since flags are set */
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 */
923 } else if ((vt
& (VT_VALMASK
| VT_LVAL
)) == VT_CONST
) {
924 /* constant jmp optimization */
925 if ((vc
!= 0) != inv
)
932 t
= psym(0x85 ^ inv
, t
);
937 /* generate a binary operation 'v = r op fr' instruction and modifies
939 void gen_op1(op
, r
, fr
)
944 o(0xc0 + r
+ fr
* 8);
945 } else if (op
== '-') {
947 o(0xc0 + r
+ fr
* 8);
948 } else if (op
== '&') {
950 o(0xc0 + r
+ fr
* 8);
951 } else if (op
== '^') {
953 o(0xc0 + r
+ fr
* 8);
954 } else if (op
== '|') {
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
) {
966 o(0x87); /* xchg r, %ecx */
971 o(0xd3); /* shl/shr/sar %cl, r */
974 else if (op
== TOK_SHR
)
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 */
988 o(0xf799); /* cltd, idiv t(%ebp), %eax */
991 if (op
== '%' | op
== TOK_UMOD
)
995 vt
= (vt
& VT_TYPE
) | r
;
998 o(0xc0 + r
+ fr
* 8); /* cmp fr, r */
1003 /* end of X86 code generator */
1004 /*************************************************************/
1006 int save_reg_forced(r
)
1009 /* store register */
1010 loc
= (loc
- 4) & -3;
1011 store(r
, VT_LOCAL
, loc
);
1014 /* modify all stack values */
1015 for(p
=vstack
;p
<vstack_ptr
;p
+=2) {
1016 i
= p
[0] & VT_VALMASK
;
1022 p
[0] = (p
[0] & VT_TYPE
) | VT_LVAL
| t
;
1029 /* save r to memory. and mark it as being free */
1034 /* modify all stack values */
1035 for(p
=vstack
;p
<vstack_ptr
;p
+=2) {
1036 i
= p
[0] & VT_VALMASK
;
1044 /* find a free register. If none, save one register */
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
;
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
;
1076 for(p
=vstack
;p
<vstack_ptr
;p
+=2) {
1077 r
= p
[0] & VT_VALMASK
;
1084 /* move register 's' to 'r', and flush previous value of r to memory
1094 /* convert a stack entry in register */
1098 r
= p
[0] & VT_VALMASK
;
1099 if (r
>= VT_CONST
|| (p
[0] & VT_LVAL
))
1101 load(r
, p
[0], p
[1]);
1102 p
[0] = (p
[0] & VT_TYPE
) | r
;
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 */
1126 r
= gvp(vstack_ptr
- 2);
1131 /* handle constant optimizations and various machine independant opt */
1134 int fr
, ft
, fc
, r
, c1
, c2
, n
;
1138 c1
= (vt
& (VT_VALMASK
| VT_LVAL
)) == VT_CONST
;
1139 c2
= (ft
& (VT_VALMASK
| VT_LVAL
)) == VT_CONST
;
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;
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;
1160 /* if commutative ops, put c2 as constant */
1161 if (c1
&& (op
== '+' || op
== '&' || op
== '^' ||
1162 op
== '|' || op
== '*')) {
1167 if (c2
&& (((op
== '*' || op
== '/' || op
== TOK_UDIV
||
1170 ((op
== '+' || op
== '-' || op
== '|' || op
== '^' ||
1171 op
== TOK_SHL
|| op
== TOK_SHR
|| op
== TOK_SAR
) &&
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) {
1186 else if (op
== TOK_PDIV
)
1198 r
= gvp(vstack_ptr
- 4);
1199 fr
= gvp(vstack_ptr
- 2);
1202 /* call low level op generator */
1210 return type_size(pointed_type(t
), &t
);
1213 /* generic gen_op: handles types problems */
1219 t1
= vstack_ptr
[-4];
1220 t2
= vstack_ptr
[-2];
1221 if (op
== '+' | op
== '-') {
1222 if ((t1
& VT_PTR
) && (t2
& VT_PTR
)) {
1224 error("invalid type");
1225 /* XXX: check that types are compatible */
1226 u
= pointed_size(t1
);
1229 vstack_ptr
[-2] &= ~VT_TYPE
; /* set to integer */
1232 } else if ((t1
| t2
) & VT_PTR
) {
1234 swap(vstack_ptr
- 4, vstack_ptr
- 2);
1235 swap(vstack_ptr
- 3, vstack_ptr
- 1);
1238 /* stack-4 contains pointer, stack-2 value to add */
1239 vset(VT_CONST
, pointed_size(vstack_ptr
[-4]));
1243 /* put again type if gen_opc() swaped operands */
1244 vt
= (vt
& VT_TYPEN
) | (t1
& VT_TYPE
);
1249 /* XXX: test types and compute returned value */
1250 if ((t1
| t2
) & (VT_UNSIGNED
| VT_PTR
)) {
1257 else if (op
== TOK_LT
)
1259 else if (op
== TOK_GT
)
1261 else if (op
== TOK_LE
)
1263 else if (op
== TOK_GE
)
1270 /* return type size. Put alignment at 'a' */
1271 int type_size(int t
, int *a
)
1275 /* int, enum or pointer */
1276 if (t
& VT_STRUCT
) {
1278 s
= sym_find(((unsigned)t
>> VT_STRUCT_SHIFT
) | SYM_STRUCT
);
1279 *a
= 4; /* XXX: cannot store it yet. Doing that is safe */
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 |
1295 /* return the pointed type of t */
1296 int pointed_type(int t
)
1299 s
= sym_find(((unsigned)t
>> VT_STRUCT_SHIFT
));
1300 return s
->t
| (t
& VT_TYPEN
);
1303 int mk_pointer(int t
)
1308 return VT_PTR
| (p
<< VT_STRUCT_SHIFT
) | (t
& VT_TYPEN
);
1311 /* store value in lvalue pushed on stack */
1316 r
= gv(); /* generate value */
1318 ft
= vstack_ptr
[-4];
1319 fc
= vstack_ptr
[-3];
1320 if ((ft
& VT_VALMASK
) == VT_LLOCAL
) {
1322 load(t
, VT_LOCAL
| VT_LVAL
, fc
);
1323 ft
= (ft
& ~VT_VALMASK
) | t
;
1329 /* post defines POST/PRE add. c is the token ++ or -- */
1335 vpush(); /* room for returned value */
1336 vpush(); /* save lvalue */
1338 vpush(); /* save value */
1340 /* duplicate value */
1342 load(r1
, r
, 0); /* move r to r1 */
1343 vstack_ptr
[-6] = (vt
& VT_TYPE
) | r1
;
1347 vset(VT_CONST
, c
- TOK_MID
);
1349 vstore(); /* store value */
1357 if ((vt
& (VT_CONST
| VT_LVAL
)) != VT_CONST
)
1362 /* enum/struct/union declaration */
1365 int a
, t
, b
, v
, size
, align
, maxalign
, c
;
1366 Sym
*slast
, *s
, *ss
;
1368 a
= tok
; /* save decl type */
1373 /* struct already defined ? return it */
1374 /* XXX: check consistency */
1375 if (s
= sym_find(v
| SYM_STRUCT
)) {
1377 error("invalid type");
1378 u
= u
| (v
<< VT_STRUCT_SHIFT
);
1384 s
= sym_push(v
| SYM_STRUCT
, a
, 0);
1385 /* put struct/union/enum name in type */
1386 u
= u
| (v
<< VT_STRUCT_SHIFT
);
1390 /* cannot be empty */
1395 if (a
== TOK_ENUM
) {
1402 sym_push(v
, VT_CONST
, c
);
1410 if (t
& (VT_FUNC
| VT_TYPEDEF
))
1411 error("invalid type");
1412 /* XXX: align & correct type size */
1414 size
= type_size(t
, &align
);
1415 if (a
== TOK_STRUCT
) {
1416 c
= (c
+ align
- 1) & -align
;
1417 ss
= sym_push(v
, t
, c
);
1420 ss
= sym_push(v
, t
, 0);
1424 if (align
> maxalign
)
1428 if (tok
== ';' || tok
== -1)
1439 /* size for struct/union, dummy for enum */
1440 s
->c
= (c
+ maxalign
- 1) & -maxalign
;
1445 /* return 0 if no type declaration. otherwise, return the basic type
1447 XXX: A '2' is ored to ensure non zero return if int type.
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
);
1464 if (tok
== TOK_CHAR
) {
1466 } else if (tok
== TOK_VOID
) {
1468 } else if (tok
== TOK_INT
|
1469 (tok
>= TOK_CONST
& tok
<= TOK_INLINE
)) {
1471 } else if (tok
== TOK_FLOAT
& tok
== TOK_DOUBLE
) {
1472 error("floats not supported");
1473 } else if (tok
== TOK_EXTERN
) {
1475 } else if (tok
== TOK_STATIC
) {
1477 } else if (tok
== TOK_UNSIGNED
) {
1479 } else if (tok
== TOK_TYPEDEF
) {
1483 if (!s
|| !(s
->t
& VT_TYPEDEF
))
1485 t
= s
->t
& ~VT_TYPEDEF
;
1500 /* function declaration */
1505 while (tok
!= ')') {
1506 /* read param name and compute offset */
1507 if (l
!= FUNC_OLD
) {
1508 if (!(pt
= ist())) {
1510 error("invalid type");
1516 if (pt
& VT_VOID
&& tok
== ')')
1519 pt
= typ(&n
, pt
); /* XXX: should accept
1520 both arg/non arg if v == 0 */
1524 pt
= 0; /* int type */
1527 /* array must be transformed to pointer according to ANSI C */
1529 /* XXX: size will be different someday */
1531 s
= sym_push(n
| SYM_FIELD
, VT_LOCAL
| VT_LVAL
| pt
, a
);
1536 if (l
== FUNC_NEW
&& tok
== TOK_DOTS
) {
1545 /* we push a anonymous symbol which will contain the function prototype */
1547 s
= sym_push(p
, t
, l
);
1549 t
= VT_FUNC
| (p
<< VT_STRUCT_SHIFT
);
1550 } else if (tok
== '[') {
1551 /* array definition */
1557 error("invalid array size");
1560 /* parse next post type */
1563 /* we push a anonymous symbol which will contain the array
1567 t
= VT_ARRAY
| VT_PTR
| (p
<< VT_STRUCT_SHIFT
);
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
)
1579 t
= t
& -3; /* suppress the ored '2' */
1580 while (tok
== '*') {
1585 /* recursive type */
1586 /* XXX: incorrect if abstract type for functions (e.g. 'int ()') */
1593 /* type identifier */
1599 /* append t at the end of u */
1605 s
= sym_find((unsigned)p
>> VT_STRUCT_SHIFT
);
1615 /* define a new external reference to a function 'v' of type 'u' */
1616 Sym
*external_func(v
, u
)
1622 n
= dlsym(0, get_tok_str(v
));
1624 /* used to generate symbol list */
1625 s
= sym_push1(&global_stack
,
1626 v
, u
| VT_CONST
| VT_LVAL
| VT_FORWARD
, 0);
1629 s
= sym_push1(&global_stack
,
1630 v
, u
| VT_CONST
| VT_LVAL
, n
);
1636 /* read a character for string or char constant and eval escape codes */
1667 vt
= pointed_type(vt
);
1668 if (!(vt
& VT_ARRAY
)) /* an array is never an lvalue */
1674 int n
, t
, ft
, fc
, p
, r
;
1677 if (tok
== TOK_NUM
) {
1678 vset(VT_CONST
, tokc
);
1682 vset(VT_CONST
, getq());
1683 next(); /* skip char */
1685 } else if (tok
== '\"') {
1686 /* generate (char *) type */
1687 vset(VT_CONST
| mk_pointer(VT_TYPE
), glo
);
1688 while (tok
== '\"') {
1689 while (ch
!= '\"') {
1691 error("unterminated string");
1692 *(char *)glo
++ = getq();
1698 } else if (tok
== TOK_DEFINED
) {
1699 /* XXX: should only be used in preprocess expr parsing */
1704 vset(VT_CONST
, sym_find1(define_stack
, tok
) != 0);
1717 vt
= (vt
& VT_TYPEN
) | ft
;
1722 } else if (t
== '*') {
1725 } else if (t
== '&') {
1728 vt
= mk_pointer(vt
& VT_LVALN
);
1732 if ((vt
& VT_VALMASK
) == VT_CMP
)
1735 vset(VT_JMP
, gtst(1, 0));
1746 if (t
== TOK_SIZEOF
) {
1747 /* XXX: some code can be generated */
1758 vset(VT_CONST
, type_size(vt
, &t
));
1760 if (t
== TOK_INC
| t
== TOK_DEC
) {
1763 } else if (t
== '-') {
1773 error("undefined symbol");
1774 /* for simple function calls, we tolerate undeclared
1775 external reference */
1777 sym_push1(&global_stack
, p
, 0, FUNC_OLD
);
1778 /* int() function */
1779 s
= external_func(t
, VT_FUNC
| (p
<< VT_STRUCT_SHIFT
));
1782 /* if forward reference, we must point to s->c */
1783 if (vt
& VT_FORWARD
)
1788 /* post operations */
1790 if (tok
== TOK_INC
| tok
== TOK_DEC
) {
1793 } else if (tok
== '.' | tok
== TOK_ARROW
) {
1795 if (tok
== TOK_ARROW
)
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
);
1806 while (s
= s
->next
) {
1811 error("field not found");
1812 /* add field offset to pointer */
1813 vt
= vt
& VT_TYPEN
; /* change type to int */
1815 vset(VT_CONST
, s
->c
);
1817 /* change type to field type, and set to lvalue */
1818 vt
= (vt
& VT_TYPEN
) | VT_LVAL
| s
->t
;
1820 } else if (tok
== '[') {
1827 } else if (tok
== '(') {
1829 save_regs(); /* save used temporary registers */
1830 /* lvalue is implied */
1832 if ((vt
& VT_VALMASK
) != VT_CONST
) {
1833 /* evaluate function address */
1835 o(0x50 + r
); /* push r */
1841 while (tok
!= ')') {
1845 o(0x50 + r
); /* push r */
1850 /* horrible, but needed : convert to native ordering (could
1851 parse parameters in reverse order, but would cost more
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) */
1862 if ((ft
& VT_VALMASK
) == VT_CONST
) {
1863 /* forward reference */
1864 if (ft
& VT_FORWARD
) {
1865 *(int *)fc
= psym(0xe8, *(int *)fc
);
1867 oad(0xe8, fc
- ind
- 5);
1869 oad(0x2494ff, t
); /* call *xxx(%esp) */
1874 /* get return type */
1875 s
= sym_find((unsigned)ft
>> VT_STRUCT_SHIFT
);
1876 vt
= s
->t
| 0; /* return register is eax */
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
) {
1898 /* XXX: be more precise */
1899 if ((vt
& VT_PTR
) != (vstack_ptr
[-2] & VT_PTR
))
1900 warning("incompatible type");
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
== '|')) {
1949 if (tok
!= TOK_LAND
) {
1969 if (tok
!= TOK_LOR
) {
2013 void block(int *bsym
, int *csym
, int *case_sym
, int *def_sym
, int case_reg
)
2018 if (tok
== TOK_IF
) {
2025 block(bsym
, csym
, case_sym
, def_sym
, case_reg
);
2027 if (c
== TOK_ELSE
) {
2031 block(bsym
, csym
, case_sym
, def_sym
, case_reg
);
2032 gsym(d
); /* patch else jmp */
2035 } else if (tok
== TOK_WHILE
) {
2043 block(&a
, &b
, case_sym
, def_sym
, case_reg
);
2044 oad(0xe9, d
- ind
- 5); /* jmp */
2047 } else if (tok
== '{') {
2053 block(bsym
, csym
, case_sym
, def_sym
, case_reg
);
2054 /* pop locally defined symbols */
2055 sym_pop(&local_stack
, s
);
2057 } else if (tok
== TOK_RETURN
) {
2064 rsym
= gjmp(rsym
); /* jmp */
2065 } else if (tok
== TOK_BREAK
) {
2068 error("cannot break");
2069 *bsym
= gjmp(*bsym
);
2072 } else if (tok
== TOK_CONTINUE
) {
2075 error("cannot continue");
2076 *csym
= gjmp(*csym
);
2081 if (tok
== TOK_FOR
) {
2101 oad(0xe9, d
- ind
- 5); /* jmp */
2105 block(&a
, &b
, case_sym
, def_sym
, case_reg
);
2106 oad(0xe9, c
- ind
- 5); /* jmp */
2110 if (tok
== TOK_DO
) {
2115 block(&a
, &b
, case_sym
, def_sym
, case_reg
);
2125 if (tok
== TOK_SWITCH
) {
2134 block(&a
, csym
, &b
, &c
, case_reg
);
2135 /* if no default, jmp after switch */
2143 if (tok
== TOK_CASE
) {
2153 *case_sym
= gtst(1, 0);
2155 block(bsym
, csym
, case_sym
, def_sym
, case_reg
);
2157 if (tok
== TOK_DEFAULT
) {
2163 error("too many 'default'");
2165 block(bsym
, csym
, case_sym
, def_sym
, case_reg
);
2167 if (tok
== TOK_GOTO
) {
2169 s
= sym_find1(label_stack
, tok
);
2170 /* put forward definition if needed */
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 */
2177 oad(0xe9, s
->c
- ind
- 5); /* jmp xxx */
2188 s
= sym_find1(label_stack
, b
);
2190 if (!(s
->t
& VT_FORWARD
))
2191 error("multiple defined label");
2196 sym_push1(&label_stack
, b
, 0, ind
);
2198 block(bsym
, csym
, case_sym
, def_sym
, case_reg
);
2200 /* expression case: go backward of one token */
2201 /* XXX: currently incorrect if number/string/char */
2212 /* 'l' is VT_LOCAL or VT_CONST to define default storage type */
2215 int *a
, t
, b
, size
, align
, v
, u
, n
;
2219 if ((b
& (VT_ENUM
| VT_STRUCT
)) && tok
== ';') {
2220 /* we accept no variable after */
2224 while (1) { /* iterate thru each declaration */
2228 expect("function defintion");
2229 /* patch forward references */
2230 if ((sym
= sym_find(v
)) && (sym
->t
& VT_FORWARD
)) {
2233 sym
->t
= VT_CONST
| VT_LVAL
| t
;
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
);
2245 o(0xe58955); /* push %ebp, mov %esp, %ebp */
2246 a
= (int *)oad(0xec81, 0); /* sub $xxx, %esp */
2248 block(0, 0, 0, 0, 0);
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 */
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
);
2266 /* not lvalue if array */
2267 if (!(t
& VT_ARRAY
))
2269 if (t
& VT_EXTERN
) {
2270 /* external variable */
2271 /* XXX: factorize with external function def */
2272 n
= dlsym(NULL
, get_tok_str(v
));
2274 error("unknown external variable");
2275 sym_push(v
, VT_CONST
| t
, n
);
2281 size
= type_size(t
, &align
);
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
);
2289 /* allocate space up in the data space */
2290 glo
= (glo
+ align
- 1) & -align
;
2291 sym_push(v
, u
, glo
);
2306 int main(int c
, char **v
)
2311 printf("usage: tcc source ...\n");
2317 file
= fopen(filename
, "r");
2322 include_stack_ptr
= include_stack
;
2323 ifdef_stack_ptr
= ifdef_stack
;
2325 idtable
= malloc(SYM_TABLE_SIZE
);
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
);
2339 ch
= '\n'; /* needed to parse correctly first preprocessor command */
2343 expect("declaration");
2347 f
= fopen(v
[1], "w");
2348 fwrite((void *)prog
, 1, ind
- prog
, f
);
2353 s
= sym_find(TOK_MAIN
);
2355 error("main() not defined");
2357 return (*t
)(c
- 1, v
);