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
32 /* symbol management */
34 int v
; /* symbol token */
35 int t
; /* associated type */
36 int c
; /* associated number */
37 struct Sym
*next
; /* next related symbol */
38 struct Sym
*prev
; /* prev symbol in stack */
41 #define SYM_STRUCT 0x40000000 /* struct/union/enum symbol space */
42 #define SYM_FIELD 0x20000000 /* struct/union field symbol space */
44 #define FUNC_NEW 1 /* ansi function prototype */
45 #define FUNC_OLD 2 /* old function prototype */
46 #define FUNC_ELLIPSIS 3 /* ansi function prototype with ... */
54 /* loc : local variable index
55 glo : global variable index
59 anon_sym: anonymous symbol index
62 int tok
, tok1
, tokc
, rsym
, anon_sym
,
63 prog
, ind
, loc
, glo
, vt
, *vstack
, *vstack_ptr
,
65 char *idtable
, *idptr
, *filename
;
66 Sym
*define_stack
, *global_stack
, *local_stack
, *label_stack
;
68 char *macro_stack
[MACRO_STACK_SIZE
], **macro_stack_ptr
, *macro_ptr
;
69 IncludeFile include_stack
[INCLUDE_STACK_SIZE
], *include_stack_ptr
;
71 /* The current value can be: */
72 #define VT_VALMASK 0x000f
73 #define VT_CONST 0x000a /* constant in vc
74 (must be first non register value) */
75 #define VT_LLOCAL 0x000b /* lvalue, offset on stack */
76 #define VT_LOCAL 0x000c /* offset on stack */
77 #define VT_CMP 0x000d /* the value is stored in processor flags (in vc) */
78 #define VT_JMP 0x000e /* value is the consequence of jmp true */
79 #define VT_JMPI 0x000f /* value is the consequence of jmp false */
80 #define VT_LVAL 0x0010 /* var is an lvalue */
81 #define VT_LVALN -17 /* ~VT_LVAL */
82 #define VT_FORWARD 0x0020 /* value is forward reference
83 (only used for functions) */
85 #define VT_VOID 0x00040
86 #define VT_BYTE 0x00080 /* byte type */
87 #define VT_PTR 0x00100 /* pointer increment */
88 #define VT_UNSIGNED 0x00200 /* unsigned type */
89 #define VT_ARRAY 0x00400 /* array type (only used in parsing) */
90 #define VT_ENUM 0x00800 /* enum definition */
91 #define VT_FUNC 0x01000 /* function type */
92 #define VT_STRUCT 0x002000 /* struct/union definition */
93 #define VT_TYPEDEF 0x004000 /* typedef definition */
94 #define VT_EXTERN 0x008000 /* extern definition */
95 #define VT_STATIC 0x010000 /* static variable */
96 #define VT_STRUCT_SHIFT 17 /* structure/enum name shift (12 bits lefts) */
98 #define VT_TYPE 0xffffffc0 /* type mask */
99 #define VT_TYPEN 0x0000003f /* ~VT_TYPE */
100 #define VT_FUNCN -4097 /* ~VT_FUNC */
111 #define TOK_WHILE 261
112 #define TOK_BREAK 262
113 #define TOK_RETURN 263
114 #define TOK_DEFINE 264
117 #define TOK_EXTERN 267
118 #define TOK_STATIC 268
119 #define TOK_UNSIGNED 269
122 #define TOK_CONTINUE 272
123 #define TOK_SWITCH 273
126 /* ignored types Must have contiguous values */
127 #define TOK_CONST 275
128 #define TOK_VOLATILE 276
130 #define TOK_REGISTER 278
131 #define TOK_SIGNED 279
133 #define TOK_INLINE 281
135 #define TOK_FLOAT 282 /* unsupported */
136 #define TOK_DOUBLE 283 /* unsupported */
138 #define TOK_STRUCT 284
139 #define TOK_UNION 285
140 #define TOK_TYPEDEF 286
141 #define TOK_DEFAULT 287
143 #define TOK_SIZEOF 289
144 #define TOK_INCLUDE 290
146 /* warning: the following compare tokens depend on i386 asm code */
158 #define TOK_LAND 0xa0
162 #define TOK_MID 0xa3 /* inc/dec, to void constant */
164 #define TOK_ARROW 0xa7
165 #define TOK_DOTS 0xa8 /* three dots */
166 #define TOK_SHR 0xa9 /* unsigned shift right */
167 #define TOK_UDIV 0xb0 /* unsigned division */
168 #define TOK_UMOD 0xb1 /* unsigned modulo */
169 #define TOK_PDIV 0xb2 /* fast division with undefined rounding for pointers */
170 #define TOK_NUM 0xb3 /* number in tokc */
172 #define TOK_SHL 0x01 /* shift left */
173 #define TOK_SAR 0x02 /* signed shift right */
175 /* assignement operators : normal operator or 0x80 */
176 #define TOK_A_MOD 0xa5
177 #define TOK_A_AND 0xa6
178 #define TOK_A_MUL 0xaa
179 #define TOK_A_ADD 0xab
180 #define TOK_A_SUB 0xad
181 #define TOK_A_DIV 0xaf
182 #define TOK_A_XOR 0xde
183 #define TOK_A_OR 0xfc
184 #define TOK_A_SHL 0x81
185 #define TOK_A_SAR 0x82
198 return (c
>= 'a' & c
<= 'z') |
199 (c
>= 'A' & c
<= 'Z') |
205 return c
>= '0' & c
<= '9';
213 for(f
= include_stack
; f
< include_stack_ptr
; f
++)
214 printf("In file included from %s:%d:\n", f
->filename
, f
->line_num
);
215 printf("%s:%d: ", filename
, line_num
);
218 /* XXX: use stderr ? */
219 void error(char *msg
)
226 void expect(char *msg
)
229 printf("%s expected\n", msg
);
233 void warning(char *msg
)
236 printf("warning: %s\n", msg
);
243 printf("'%c' expected\n", c
);
257 #define skip(c) next()
258 #define test_lvalue()
262 char *get_tok_str(int v
)
277 /* find a symbol and return its associated structure. 's' is the top
278 of the symbol stack */
279 Sym
*sym_find1(Sym
*s
, int v
)
289 Sym
*sym_push1(Sym
**ps
, int v
, int t
, int c
)
292 s
= malloc(sizeof(Sym
));
294 error("memory full");
304 /* find a symbol in the right symbol space */
308 s
= sym_find1(local_stack
, v
);
310 s
= sym_find1(global_stack
, v
);
314 /* push a given symbol on the symbol stack */
315 Sym
*sym_push(int v
, int t
, int c
)
317 // printf("sym_push: %x %s type=%x\n", v, get_tok_str(v), t);
319 return sym_push1(&local_stack
, v
, t
, c
);
321 return sym_push1(&global_stack
, v
, t
, c
);
324 /* pop symbols until top reaches 'b' */
325 void sym_pop(Sym
**ps
, Sym
*b
)
332 // printf("sym_pop: %x %s type=%x\n", s->v, get_tok_str(s->v), s->t);
341 /* read next char from current input file */
349 if (include_stack_ptr
== include_stack
)
351 /* pop include stack */
355 file
= include_stack_ptr
->file
;
356 filename
= include_stack_ptr
->filename
;
357 line_num
= include_stack_ptr
->line_num
;
362 // printf("ch1=%c\n", ch1);
365 /* input with '\\n' handling and macro subtitution if in macro state */
368 if (macro_ptr
!= 0) {
372 macro_ptr
= *--macro_stack_ptr
;
373 ch
= (int)*--macro_stack_ptr
;
379 if (ch
== '\\' && ch1
== '\n') {
386 /* same as minp, but also skip comments */
394 /* single line C++ comments */
396 while (ch1
!= '\n' && ch1
!= -1)
399 ch
= ' '; /* return space */
400 } else if (ch1
== '*') {
406 if (c
== '*' && ch1
== '/') {
408 ch
= ' '; /* return space */
422 while (ch
== ' ' || ch
== '\t')
430 char buf
[1024], *q
, *p
;
435 next(); /* XXX: should pass parameter to avoid macro subst */
436 if (tok
== TOK_DEFINE
) {
437 next(); /* XXX: should pass parameter to avoid macro subst */
439 /* now 'tok' is the macro symbol */
444 if ((n
+ 1) >= size
) {
446 str
= realloc(str
, size
);
448 error("memory full");
450 if (ch
== -1 || ch
== '\n') {
451 str
[n
++] = ' '; /* a space is inserted after each macro */
458 sym_push1(&define_stack
, tok
, 0, (int)str
);
459 } else if (tok
== TOK_INCLUDE
) {
464 } else if (ch
== '\"') {
469 while (ch
!= c
&& ch
!= '\n' && ch
!= -1) {
470 if ((q
- buf
) < sizeof(buf
) - 1)
475 if (include_stack_ptr
>= include_stack
+ INCLUDE_STACK_SIZE
)
476 error("memory full");
478 /* first search in current dir if "header.h" */
479 /* XXX: buffer overflow */
481 p
= strrchr(filename
, '/');
483 size
= p
+ 1 - filename
;
484 memcpy(buf1
, filename
, size
);
487 f
= fopen(buf1
, "r");
491 /* now search in standard include path */
492 strcpy(buf1
, INCLUDE_PATH
);
495 f
= fopen(buf1
, "r");
497 error("include file not found");
499 /* push current file in stack */
500 include_stack_ptr
->file
= file
;
501 include_stack_ptr
->filename
= filename
;
502 include_stack_ptr
->line_num
= line_num
;
505 filename
= strdup(buf1
);
510 /* ignore other preprocess commands or #! for C scripts */
511 while (ch
!= '\n' && ch
!= -1)
515 /* read a number in base b */
521 if (ch
>= 'a' & ch
<= 'f')
523 else if (ch
>= 'A' & ch
<= 'F')
543 /* special 'ungettok' case for label parsing */
554 while (ch
== ' ' || ch
== 9)
557 /* preprocessor command if # at start of line after
562 if (ch
!= ' ' && ch
!= 9)
568 while(isid(ch
) | isnum(ch
)) {
576 if (strcmp(p
, idptr
) == 0)
581 // printf("id=%s\n", idptr);
582 /* if not found, add symbol */
585 /* if symbol is a define, prepare substitution */
586 if (s
= sym_find1(define_stack
, tok
)) {
587 if ((macro_stack_ptr
- macro_stack
) >= MACRO_STACK_SIZE
)
588 error("too many nested macros");
589 *macro_stack_ptr
++ = (char *)ch
;
590 *macro_stack_ptr
++ = macro_ptr
;
591 macro_ptr
= (char *)s
->c
;
595 } else if (isnum(ch
)) {
610 q
= "<=\236>=\235!=\225++\244--\242==\224";
612 q
= "<=\236>=\235!=\225&&\240||\241++\244--\242==\224<<\1>>\2+=\253-=\255*=\252/=\257%=\245&=\246^=\336|=\374->\247..\250";
618 if (*q
== tok
& q
[1] == ch
) {
621 /* three chars tests */
622 if (tok
== TOK_SHL
| tok
== TOK_SAR
) {
627 } else if (tok
== TOK_DOTS
) {
629 error("parse error");
636 /* single char substitutions */
644 void swap(int *p
, int *q
)
658 /******************************************************/
659 /* X86 code generator */
674 /* output a symbol and patch all calls to it */
679 n
= *(int *)t
; /* next value */
680 *(int *)t
= a
- t
- 4;
690 /* psym is used to put an instruction with a data field which is a
691 reference to a symbol. It is in fact the same as oad ! */
694 /* instruction + 4 bytes data. Return the address of the data */
704 /* XXX: generate correct pointer for forward references to functions */
712 if (v
== VT_LLOCAL
) {
713 load(r
, VT_LOCAL
| VT_LVAL
, fc
);
716 if ((ft
& VT_TYPE
) == VT_BYTE
)
717 o(0xbe0f); /* movsbl */
721 oad(0x05 + r
* 8, fc
); /* 0xXX, r */
722 } else if (v
== VT_LOCAL
) {
723 oad(0x85 + r
* 8, fc
); /* xx(%ebp), r */
725 g(0x00 + r
* 8 + v
); /* (v), r */
729 oad(0xb8 + r
, fc
); /* mov $xx, r */
730 } else if (v
== VT_LOCAL
) {
732 oad(0x85 + r
* 8, fc
); /* lea xxx(%ebp), r */
733 } else if (v
== VT_CMP
) {
734 oad(0xb8 + r
, 0); /* mov $0, r */
735 o(0x0f); /* setxx %br */
738 } else if (v
== VT_JMP
|| v
== VT_JMPI
) {
740 oad(0xb8 + r
, t
); /* mov $1, r */
741 oad(0xe9, 5); /* jmp after */
743 oad(0xb8 + r
, t
^ 1); /* mov $0, r */
746 o(0xc0 + r
+ v
* 8); /* mov v, r */
752 /* WARNING: r must not be allocated on the stack */
753 void store(r
, ft
, fc
)
757 fr
= ft
& VT_VALMASK
;
758 b
= (ft
& VT_TYPE
) == VT_BYTE
;
760 if (fr
== VT_CONST
) {
761 oad(0x05 + r
* 8, fc
); /* mov r,xxx */
762 } else if (fr
== VT_LOCAL
) {
763 oad(0x85 + r
* 8, fc
); /* mov r,xxx(%ebp) */
764 } else if (ft
& VT_LVAL
) {
765 g(fr
+ r
* 8); /* mov r, (fr) */
766 } else if (fr
!= r
) {
767 o(0xc0 + fr
+ r
* 8); /* mov r, fr */
773 return psym(0xe9, t
);
776 /* generate a test. set 'inv' to invert test */
782 /* fast case : can jump directly since flags are set */
784 t
= psym((vc
- 16) ^ inv
, t
);
785 } else if (v
== VT_JMP
|| v
== VT_JMPI
) {
786 /* && or || optimization */
787 if ((v
& 1) == inv
) {
788 /* insert vc jump list in t */
798 } else if ((vt
& (VT_VALMASK
| VT_LVAL
)) == VT_CONST
) {
799 /* constant jmp optimization */
800 if ((vc
!= 0) != inv
)
807 t
= psym(0x85 ^ inv
, t
);
812 /* generate a binary operation 'v = r op fr' instruction and modifies
814 void gen_op1(op
, r
, fr
)
819 o(0xc0 + r
+ fr
* 8);
820 } else if (op
== '-') {
822 o(0xc0 + r
+ fr
* 8);
823 } else if (op
== '&') {
825 o(0xc0 + r
+ fr
* 8);
826 } else if (op
== '^') {
828 o(0xc0 + r
+ fr
* 8);
829 } else if (op
== '|') {
831 o(0xc0 + r
+ fr
* 8);
832 } else if (op
== '*') {
833 o(0xaf0f); /* imul fr, r */
834 o(0xc0 + fr
+ r
* 8);
835 } else if (op
== TOK_SHL
| op
== TOK_SHR
| op
== TOK_SAR
) {
841 o(0x87); /* xchg r, %ecx */
846 o(0xd3); /* shl/shr/sar %cl, r */
849 else if (op
== TOK_SHR
)
853 vt
= (vt
& VT_TYPE
) | r
;
854 } else if (op
== '/' | op
== TOK_UDIV
| op
== TOK_PDIV
|
855 op
== '%' | op
== TOK_UMOD
) {
856 save_reg(2); /* save edx */
857 t
= save_reg_forced(fr
); /* save fr and get op2 location */
858 move_reg(0, r
); /* op1 is %eax */
859 if (op
== TOK_UDIV
| op
== TOK_UMOD
) {
860 o(0xf7d231); /* xor %edx, %edx, div t(%ebp), %eax */
863 o(0xf799); /* cltd, idiv t(%ebp), %eax */
866 if (op
== '%' | op
== TOK_UMOD
)
870 vt
= (vt
& VT_TYPE
) | r
;
873 o(0xc0 + r
+ fr
* 8); /* cmp fr, r */
878 /* end of X86 code generator */
879 /*************************************************************/
881 int save_reg_forced(r
)
885 loc
= (loc
- 4) & -3;
886 store(r
, VT_LOCAL
, loc
);
889 /* modify all stack values */
890 for(p
=vstack
;p
<vstack_ptr
;p
+=2) {
891 i
= p
[0] & VT_VALMASK
;
897 p
[0] = (p
[0] & VT_TYPE
) | VT_LVAL
| t
;
904 /* save r to memory. and mark it as being free */
909 /* modify all stack values */
910 for(p
=vstack
;p
<vstack_ptr
;p
+=2) {
911 i
= p
[0] & VT_VALMASK
;
919 /* find a free register. If none, save one register */
924 /* find a free register */
925 for(r
=0;r
<NB_REGS
;r
++) {
926 for(p
=vstack
;p
<vstack_ptr
;p
+=2) {
927 i
= p
[0] & VT_VALMASK
;
935 /* no register left : free the first one on the stack (very
936 important to start from the bottom to ensure that we don't
937 spill registers used in gen_op()) */
938 for(p
=vstack
;p
<vstack_ptr
;p
+=2) {
939 r
= p
[0] & VT_VALMASK
;
951 for(p
=vstack
;p
<vstack_ptr
;p
+=2) {
952 r
= p
[0] & VT_VALMASK
;
959 /* move register 's' to 'r', and flush previous value of r to memory
969 /* convert a stack entry in register */
973 r
= p
[0] & VT_VALMASK
;
974 if (r
>= VT_CONST
|| (p
[0] & VT_LVAL
))
977 p
[0] = (p
[0] & VT_TYPE
) | r
;
985 /* cannot let cpu flags if other instruction are generated */
986 if ((vt
& VT_VALMASK
) == VT_CMP
)
990 void vpop(int *ft
, int *fc
)
996 /* generate a value in a register from vt and vc */
1001 r
= gvp(vstack_ptr
- 2);
1006 /* handle constant optimizations and various machine independant opt */
1009 int fr
, ft
, fc
, r
, c1
, c2
, n
;
1013 c1
= (vt
& (VT_VALMASK
| VT_LVAL
)) == VT_CONST
;
1014 c2
= (ft
& (VT_VALMASK
| VT_LVAL
)) == VT_CONST
;
1017 case '+': vc
+= fc
; break;
1018 case '-': vc
-= fc
; break;
1019 case '&': vc
&= fc
; break;
1020 case '^': vc
^= fc
; break;
1021 case '|': vc
|= fc
; break;
1022 case '*': vc
*= fc
; break;
1024 case '/': vc
/= fc
; break; /* XXX: zero case ? */
1025 case '%': vc
%= fc
; break; /* XXX: zero case ? */
1026 case TOK_UDIV
: vc
= (unsigned)vc
/ fc
; break; /* XXX: zero case ? */
1027 case TOK_UMOD
: vc
= (unsigned)vc
% fc
; break; /* XXX: zero case ? */
1028 case TOK_SHL
: vc
<<= fc
; break;
1029 case TOK_SHR
: vc
= (unsigned)vc
>> fc
; break;
1030 case TOK_SAR
: vc
>>= fc
; break;
1035 /* if commutative ops, put c2 as constant */
1036 if (c1
&& (op
== '+' || op
== '&' || op
== '^' ||
1037 op
== '|' || op
== '*')) {
1042 if (c2
&& (((op
== '*' || op
== '/' || op
== TOK_UDIV
||
1045 ((op
== '+' || op
== '-' || op
== '|' || op
== '^' ||
1046 op
== TOK_SHL
|| op
== TOK_SHR
|| op
== TOK_SAR
) &&
1050 } else if (c2
&& (op
== '*' || op
== TOK_PDIV
|| op
== TOK_UDIV
)) {
1051 /* try to use shifts instead of muls or divs */
1052 if (fc
> 0 && (fc
& (fc
- 1)) == 0) {
1061 else if (op
== TOK_PDIV
)
1073 r
= gvp(vstack_ptr
- 4);
1074 fr
= gvp(vstack_ptr
- 2);
1077 /* call low level op generator */
1085 return type_size(pointed_type(t
), &t
);
1088 /* generic gen_op: handles types problems */
1094 t1
= vstack_ptr
[-4];
1095 t2
= vstack_ptr
[-2];
1096 if (op
== '+' | op
== '-') {
1097 if ((t1
& VT_PTR
) && (t2
& VT_PTR
)) {
1099 error("invalid type");
1100 /* XXX: check that types are compatible */
1101 u
= pointed_size(t1
);
1104 vstack_ptr
[-2] &= ~VT_TYPE
; /* set to integer */
1107 } else if ((t1
| t2
) & VT_PTR
) {
1109 swap(vstack_ptr
- 4, vstack_ptr
- 2);
1110 swap(vstack_ptr
- 3, vstack_ptr
- 1);
1113 /* stack-4 contains pointer, stack-2 value to add */
1114 vset(VT_CONST
, pointed_size(vstack_ptr
[-4]));
1118 /* put again type if gen_opc() swaped operands */
1119 vt
= (vt
& VT_TYPEN
) | (t1
& VT_TYPE
);
1124 if ((t1
| t2
) & VT_UNSIGNED
) {
1131 else if (op
== TOK_LT
)
1133 else if (op
== TOK_GT
)
1135 else if (op
== TOK_LE
)
1137 else if (op
== TOK_GE
)
1144 /* return type size. Put alignment at 'a' */
1145 int type_size(int t
, int *a
)
1149 /* int, enum or pointer */
1150 if (t
& VT_STRUCT
) {
1152 s
= sym_find(((unsigned)t
>> VT_STRUCT_SHIFT
) | SYM_STRUCT
);
1153 *a
= 4; /* XXX: cannot store it yet. Doing that is safe */
1155 } else if (t
& VT_ARRAY
) {
1156 s
= sym_find(((unsigned)t
>> VT_STRUCT_SHIFT
));
1157 return type_size(s
->t
, a
) * s
->c
;
1158 } else if ((t
& VT_PTR
) |
1159 (t
& VT_TYPE
) == 0 |
1169 /* return the pointed type of t */
1170 int pointed_type(int t
)
1173 s
= sym_find(((unsigned)t
>> VT_STRUCT_SHIFT
));
1174 return s
->t
| (t
& VT_TYPEN
);
1177 int mk_pointer(int t
)
1182 return VT_PTR
| (p
<< VT_STRUCT_SHIFT
) | (t
& VT_TYPEN
);
1185 /* store value in lvalue pushed on stack */
1190 r
= gv(); /* generate value */
1192 ft
= vstack_ptr
[-4];
1193 fc
= vstack_ptr
[-3];
1194 if ((ft
& VT_VALMASK
) == VT_LLOCAL
) {
1196 load(t
, VT_LOCAL
| VT_LVAL
, fc
);
1197 ft
= (ft
& ~VT_VALMASK
) | t
;
1203 /* post defines POST/PRE add. c is the token ++ or -- */
1209 vpush(); /* room for returned value */
1210 vpush(); /* save lvalue */
1212 vpush(); /* save value */
1214 /* duplicate value */
1216 load(r1
, r
, 0); /* move r to r1 */
1217 vstack_ptr
[-6] = (vt
& VT_TYPE
) | r1
;
1221 vset(VT_CONST
, c
- TOK_MID
);
1223 vstore(); /* store value */
1231 if ((vt
& (VT_CONST
| VT_LVAL
)) != VT_CONST
)
1236 /* enum/struct/union declaration */
1239 int a
, t
, b
, v
, size
, align
, maxalign
, c
;
1240 Sym
*slast
, *s
, *ss
;
1242 a
= tok
; /* save decl type */
1247 /* struct already defined ? return it */
1248 /* XXX: check consistency */
1249 if (s
= sym_find(v
| SYM_STRUCT
)) {
1251 error("invalid type");
1252 u
= u
| (v
<< VT_STRUCT_SHIFT
);
1258 s
= sym_push(v
| SYM_STRUCT
, a
, 0);
1259 /* put struct/union/enum name in type */
1260 u
= u
| (v
<< VT_STRUCT_SHIFT
);
1264 /* cannot be empty */
1269 if (a
== TOK_ENUM
) {
1276 sym_push(v
, VT_CONST
, c
);
1284 if (t
& (VT_FUNC
| VT_TYPEDEF
))
1285 error("invalid type");
1286 /* XXX: align & correct type size */
1288 size
= type_size(t
, &align
);
1289 if (a
== TOK_STRUCT
) {
1290 c
= (c
+ align
- 1) & -align
;
1291 ss
= sym_push(v
, t
, c
);
1294 ss
= sym_push(v
, t
, 0);
1298 if (align
> maxalign
)
1302 if (tok
== ';' || tok
== -1)
1313 /* size for struct/union, dummy for enum */
1314 s
->c
= (c
+ maxalign
- 1) & -maxalign
;
1319 /* return 0 if no type declaration. otherwise, return the basic type
1321 XXX: A '2' is ored to ensure non zero return if int type.
1331 if (tok
== TOK_ENUM
) {
1332 t
|= struct_decl(VT_ENUM
);
1333 } else if (tok
== TOK_STRUCT
|| tok
== TOK_UNION
) {
1334 t
|= struct_decl(VT_STRUCT
);
1338 if (tok
== TOK_CHAR
) {
1340 } else if (tok
== TOK_VOID
) {
1342 } else if (tok
== TOK_INT
|
1343 (tok
>= TOK_CONST
& tok
<= TOK_INLINE
)) {
1345 } else if (tok
== TOK_FLOAT
& tok
== TOK_DOUBLE
) {
1346 error("floats not supported");
1347 } else if (tok
== TOK_EXTERN
) {
1349 } else if (tok
== TOK_STATIC
) {
1351 } else if (tok
== TOK_UNSIGNED
) {
1353 } else if (tok
== TOK_TYPEDEF
) {
1357 if (!s
|| !(s
->t
& VT_TYPEDEF
))
1359 t
= s
->t
& ~VT_TYPEDEF
;
1374 /* function declaration */
1379 while (tok
!= ')') {
1380 /* read param name and compute offset */
1381 if (l
!= FUNC_OLD
) {
1382 if (!(pt
= ist())) {
1384 error("invalid type");
1390 if (pt
& VT_VOID
&& tok
== ')')
1393 pt
= typ(&n
, pt
); /* XXX: should accept
1394 both arg/non arg if v == 0 */
1398 pt
= 0; /* int type */
1401 /* array must be transformed to pointer according to ANSI C */
1403 /* XXX: size will be different someday */
1405 s
= sym_push(n
| SYM_FIELD
, VT_LOCAL
| VT_LVAL
| pt
, a
);
1410 if (l
== FUNC_NEW
&& tok
== TOK_DOTS
) {
1419 /* we push a anonymous symbol which will contain the function prototype */
1421 s
= sym_push(p
, t
, l
);
1423 t
= VT_FUNC
| (p
<< VT_STRUCT_SHIFT
);
1424 } else if (tok
== '[') {
1425 /* array definition */
1431 error("invalid array size");
1434 /* parse next post type */
1437 /* we push a anonymous symbol which will contain the array
1441 t
= VT_ARRAY
| VT_PTR
| (p
<< VT_STRUCT_SHIFT
);
1446 /* Read a type declaration (except basic type), and return the
1447 type. If v is true, then also put variable name in 'vc' */
1448 int typ(int *v
, int t
)
1453 t
= t
& -3; /* suppress the ored '2' */
1454 while (tok
== '*') {
1459 /* recursive type */
1460 /* XXX: incorrect if abstract type for functions (e.g. 'int ()') */
1467 /* type identifier */
1473 /* append t at the end of u */
1479 s
= sym_find((unsigned)p
>> VT_STRUCT_SHIFT
);
1489 /* define a new external reference to a function 'v' of type 'u' */
1490 Sym
*external_func(v
, u
)
1496 n
= dlsym(0, get_tok_str(v
));
1498 /* used to generate symbol list */
1499 s
= sym_push1(&global_stack
,
1500 v
, u
| VT_CONST
| VT_LVAL
| VT_FORWARD
, 0);
1503 s
= sym_push1(&global_stack
,
1504 v
, u
| VT_CONST
| VT_LVAL
, n
);
1510 /* read a character for string or char constant and eval escape codes */
1541 vt
= pointed_type(vt
);
1542 if (!(vt
& VT_ARRAY
)) /* an array is never an lvalue */
1548 int n
, t
, ft
, fc
, p
, r
;
1551 if (tok
== TOK_NUM
) {
1552 vset(VT_CONST
, tokc
);
1556 vset(VT_CONST
, getq());
1557 next(); /* skip char */
1559 } else if (tok
== '\"') {
1560 /* generate (char *) type */
1561 vset(VT_CONST
| mk_pointer(VT_TYPE
), glo
);
1562 while (tok
== '\"') {
1563 while (ch
!= '\"') {
1565 error("unterminated string");
1566 *(char *)glo
++ = getq();
1581 vt
= (vt
& VT_TYPEN
) | ft
;
1586 } else if (t
== '*') {
1589 } else if (t
== '&') {
1592 vt
= mk_pointer(vt
& VT_LVALN
);
1596 if ((vt
& VT_VALMASK
) == VT_CMP
)
1599 vset(VT_JMP
, gtst(1, 0));
1610 if (t
== TOK_SIZEOF
) {
1611 /* XXX: some code can be generated */
1622 vset(VT_CONST
, type_size(vt
, &t
));
1624 if (t
== TOK_INC
| t
== TOK_DEC
) {
1627 } else if (t
== '-') {
1637 error("undefined symbol");
1638 /* for simple function calls, we tolerate undeclared
1639 external reference */
1641 sym_push1(&global_stack
, p
, 0, FUNC_OLD
);
1642 /* int() function */
1643 s
= external_func(t
, VT_FUNC
| (p
<< VT_STRUCT_SHIFT
));
1646 /* if forward reference, we must point to s->c */
1647 if (vt
& VT_FORWARD
)
1652 /* post operations */
1654 if (tok
== TOK_INC
| tok
== TOK_DEC
) {
1657 } else if (tok
== '.' | tok
== TOK_ARROW
) {
1659 if (tok
== TOK_ARROW
)
1664 /* expect pointer on structure */
1665 if (!(vt
& VT_STRUCT
))
1666 expect("struct or union");
1667 s
= sym_find(((unsigned)vt
>> VT_STRUCT_SHIFT
) | SYM_STRUCT
);
1670 while (s
= s
->next
) {
1675 error("field not found");
1676 /* add field offset to pointer */
1677 vt
= vt
& VT_TYPEN
; /* change type to int */
1679 vset(VT_CONST
, s
->c
);
1681 /* change type to field type, and set to lvalue */
1682 vt
= (vt
& VT_TYPEN
) | VT_LVAL
| s
->t
;
1684 } else if (tok
== '[') {
1691 } else if (tok
== '(') {
1693 save_regs(); /* save used temporary registers */
1694 /* lvalue is implied */
1696 if ((vt
& VT_VALMASK
) != VT_CONST
) {
1697 /* evaluate function address */
1699 o(0x50 + r
); /* push r */
1705 while (tok
!= ')') {
1709 o(0x50 + r
); /* push r */
1714 /* horrible, but needed : convert to native ordering (could
1715 parse parameters in reverse order, but would cost more
1720 oad(0x24848b, p
); /* mov x(%esp,1), %eax */
1721 oad(0x248487, n
); /* xchg x(%esp,1), %eax */
1722 oad(0x248489, p
); /* mov %eax, x(%esp,1) */
1726 if ((ft
& VT_VALMASK
) == VT_CONST
) {
1727 /* forward reference */
1728 if (ft
& VT_FORWARD
) {
1729 *(int *)fc
= psym(0xe8, *(int *)fc
);
1731 oad(0xe8, fc
- ind
- 5);
1733 oad(0x2494ff, t
); /* call *xxx(%esp) */
1738 /* get return type */
1739 s
= sym_find((unsigned)ft
>> VT_STRUCT_SHIFT
);
1740 vt
= s
->t
| 0; /* return register is eax */
1753 (tok
>= TOK_A_MOD
& tok
<= TOK_A_DIV
) |
1754 tok
== TOK_A_XOR
| tok
== TOK_A_OR
|
1755 tok
== TOK_A_SHL
| tok
== TOK_A_SAR
) {
1762 /* XXX: be more precise */
1763 if ((vt
& VT_PTR
) != (vstack_ptr
[-2] & VT_PTR
))
1764 warning("incompatible type");
1782 while ((l
== 0 & (tok
== '*' | tok
== '/' | tok
== '%')) |
1783 (l
== 1 & (tok
== '+' | tok
== '-')) |
1784 (l
== 2 & (tok
== TOK_SHL
| tok
== TOK_SAR
)) |
1785 (l
== 3 & ((tok
>= TOK_ULE
& tok
<= TOK_GT
) |
1786 tok
== TOK_ULT
| tok
== TOK_UGE
)) |
1787 (l
== 4 & (tok
== TOK_EQ
| tok
== TOK_NE
)) |
1788 (l
== 5 & tok
== '&') |
1789 (l
== 6 & tok
== '^') |
1790 (l
== 7 & tok
== '|')) {
1813 if (tok
!= TOK_LAND
) {
1833 if (tok
!= TOK_LOR
) {
1877 void block(int *bsym
, int *csym
, int *case_sym
, int *def_sym
, int case_reg
)
1882 if (tok
== TOK_IF
) {
1889 block(bsym
, csym
, case_sym
, def_sym
, case_reg
);
1891 if (c
== TOK_ELSE
) {
1895 block(bsym
, csym
, case_sym
, def_sym
, case_reg
);
1896 gsym(d
); /* patch else jmp */
1899 } else if (tok
== TOK_WHILE
) {
1907 block(&a
, &b
, case_sym
, def_sym
, case_reg
);
1908 oad(0xe9, d
- ind
- 5); /* jmp */
1911 } else if (tok
== '{') {
1917 block(bsym
, csym
, case_sym
, def_sym
, case_reg
);
1918 /* pop locally defined symbols */
1919 sym_pop(&local_stack
, s
);
1921 } else if (tok
== TOK_RETURN
) {
1928 rsym
= gjmp(rsym
); /* jmp */
1929 } else if (tok
== TOK_BREAK
) {
1932 error("cannot break");
1933 *bsym
= gjmp(*bsym
);
1936 } else if (tok
== TOK_CONTINUE
) {
1939 error("cannot continue");
1940 *csym
= gjmp(*csym
);
1945 if (tok
== TOK_FOR
) {
1965 oad(0xe9, d
- ind
- 5); /* jmp */
1969 block(&a
, &b
, case_sym
, def_sym
, case_reg
);
1970 oad(0xe9, c
- ind
- 5); /* jmp */
1974 if (tok
== TOK_DO
) {
1979 block(&a
, &b
, case_sym
, def_sym
, case_reg
);
1989 if (tok
== TOK_SWITCH
) {
1998 block(&a
, csym
, &b
, &c
, case_reg
);
1999 /* if no default, jmp after switch */
2007 if (tok
== TOK_CASE
) {
2017 *case_sym
= gtst(1, 0);
2019 block(bsym
, csym
, case_sym
, def_sym
, case_reg
);
2021 if (tok
== TOK_DEFAULT
) {
2027 error("too many 'default'");
2029 block(bsym
, csym
, case_sym
, def_sym
, case_reg
);
2031 if (tok
== TOK_GOTO
) {
2033 s
= sym_find1(label_stack
, tok
);
2034 /* put forward definition if needed */
2036 s
= sym_push1(&label_stack
, tok
, VT_FORWARD
, 0);
2037 /* label already defined */
2038 if (s
->t
& VT_FORWARD
)
2039 s
->c
= gjmp(s
->c
); /* jmp xxx */
2041 oad(0xe9, s
->c
- ind
- 5); /* jmp xxx */
2052 s
= sym_find1(label_stack
, b
);
2054 if (!(s
->t
& VT_FORWARD
))
2055 error("multiple defined label");
2060 sym_push1(&label_stack
, b
, 0, ind
);
2062 block(bsym
, csym
, case_sym
, def_sym
, case_reg
);
2064 /* expression case: go backward of one token */
2065 /* XXX: currently incorrect if number/string/char */
2076 /* 'l' is VT_LOCAL or VT_CONST to define default storage type */
2079 int *a
, t
, b
, size
, align
, v
, u
, n
;
2083 if ((b
& (VT_ENUM
| VT_STRUCT
)) && tok
== ';') {
2084 /* we accept no variable after */
2088 while (1) { /* iterate thru each declaration */
2092 expect("function defintion");
2093 /* patch forward references */
2094 if ((sym
= sym_find(v
)) && (sym
->t
& VT_FORWARD
)) {
2097 sym
->t
= VT_CONST
| VT_LVAL
| t
;
2099 /* put function address */
2100 sym_push1(&global_stack
, v
, VT_CONST
| VT_LVAL
| t
, ind
);
2102 /* push a dummy symbol to enable local sym storage */
2103 sym_push1(&local_stack
, 0, 0, 0);
2104 /* define parameters */
2105 sym
= sym_find((unsigned)t
>> VT_STRUCT_SHIFT
);
2106 while (sym
= sym
->next
) {
2107 sym_push(sym
->v
& ~SYM_FIELD
, sym
->t
, sym
->c
);
2110 o(0xe58955); /* push %ebp, mov %esp, %ebp */
2111 a
= (int *)oad(0xec81, 0); /* sub $xxx, %esp */
2113 block(0, 0, 0, 0, 0);
2115 o(0xc3c9); /* leave, ret */
2116 *a
= (-loc
+ 3) & -4; /* align local size to word &
2117 save local variables */
2118 sym_pop(&label_stack
, 0); /* reset label stack */
2119 sym_pop(&local_stack
, 0); /* reset local stack */
2122 if (b
& VT_TYPEDEF
) {
2123 /* save typedefed type */
2124 sym_push(v
, t
| VT_TYPEDEF
, 0);
2125 } else if (t
& VT_FUNC
) {
2126 /* XXX: incorrect to flush, but needed while
2127 waiting for function prototypes */
2128 /* external function definition */
2129 external_func(v
, t
);
2131 /* not lvalue if array */
2132 if (!(t
& VT_ARRAY
))
2134 if (t
& VT_EXTERN
) {
2135 /* external variable */
2136 /* XXX: factorize with external function def */
2137 n
= dlsym(NULL
, get_tok_str(v
));
2139 error("unknown external variable");
2140 sym_push(v
, VT_CONST
| t
, n
);
2146 size
= type_size(t
, &align
);
2148 error("invalid size");
2149 if ((u
& VT_VALMASK
) == VT_LOCAL
) {
2150 /* allocate space down on the stack */
2151 loc
= (loc
- size
) & -align
;
2152 sym_push(v
, u
, loc
);
2154 /* allocate space up in the data space */
2155 glo
= (glo
+ align
- 1) & -align
;
2156 sym_push(v
, u
, glo
);
2171 int main(int c
, char **v
)
2176 printf("usage: tcc source ...\n");
2182 file
= fopen(filename
, "r");
2187 include_stack_ptr
= include_stack
;
2189 idtable
= malloc(SYM_TABLE_SIZE
);
2191 "int\0void\0char\0if\0else\0while\0break\0return\0define\0main\0for\0extern\0static\0unsigned\0goto\0do\0continue\0switch\0case\0const\0volatile\0long\0register\0signed\0auto\0inline\0float\0double\0struct\0union\0typedef\0default\0enum\0sizeof\0include", 219);
2192 idptr
= idtable
+ 219;
2194 glo
= malloc(DATA_SIZE
);
2195 memset((void *)glo
, 0, DATA_SIZE
);
2196 prog
= malloc(TEXT_SIZE
);
2197 vstack
= malloc(256);
2198 vstack_ptr
= vstack
;
2199 macro_stack_ptr
= macro_stack
;
2200 anon_sym
= 1 << (31 - VT_STRUCT_SHIFT
);
2203 ch
= '\n'; /* needed to parse correctly first preprocessor command */
2209 f
= fopen(v
[1], "w");
2210 fwrite((void *)prog
, 1, ind
- prog
, f
);
2215 s
= sym_find(TOK_MAIN
);
2217 error("main() not defined");
2219 return (*t
)(c
- 1, v
);