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 */
45 FILE *file
; /* stdio file */
50 /* loc : local variable index
51 glo : global variable index
55 anon_sym: anonymous symbol index
58 int tok
, tok1
, tokc
, rsym
, anon_sym
,
59 prog
, ind
, loc
, glo
, vt
, *vstack
, *vstack_ptr
,
61 char *idtable
, *idptr
, *filename
;
62 Sym
*define_stack
, *global_stack
, *local_stack
, *label_stack
;
64 char *macro_stack
[MACRO_STACK_SIZE
], **macro_stack_ptr
, *macro_ptr
;
65 IncludeFile include_stack
[INCLUDE_STACK_SIZE
], *include_stack_ptr
;
67 /* The current value can be: */
68 #define VT_VALMASK 0x000f
69 #define VT_CONST 0x000a /* constant in vc
70 (must be first non register value) */
71 #define VT_LLOCAL 0x000b /* lvalue, offset on stack */
72 #define VT_LOCAL 0x000c /* offset on stack */
73 #define VT_CMP 0x000d /* the value is stored in processor flags (in vc) */
74 #define VT_JMP 0x000e /* value is the consequence of jmp true */
75 #define VT_JMPI 0x000f /* value is the consequence of jmp false */
76 #define VT_LVAL 0x0010 /* var is an lvalue */
77 #define VT_LVALN -17 /* ~VT_LVAL */
78 #define VT_FORWARD 0x0020 /* value is forward reference
79 (only used for functions) */
81 #define VT_VOID 0x00040
82 #define VT_BYTE 0x00080 /* byte type */
83 #define VT_PTR 0x00100 /* pointer increment */
84 #define VT_UNSIGNED 0x00200 /* unsigned type */
85 #define VT_ARRAY 0x00400 /* array type (only used in parsing) */
86 #define VT_ENUM 0x00800 /* enum definition */
87 #define VT_FUNC 0x01000 /* function type */
88 #define VT_STRUCT 0x002000 /* struct/union definition */
89 #define VT_TYPEDEF 0x004000 /* typedef definition */
90 #define VT_EXTERN 0x008000 /* extern definition */
91 #define VT_STATIC 0x010000 /* static variable */
92 #define VT_STRUCT_SHIFT 17 /* structure/enum name shift (12 bits lefts) */
94 #define VT_TYPE 0xffffffc0 /* type mask */
95 #define VT_TYPEN 0x0000003f /* ~VT_TYPE */
96 #define VT_FUNCN -4097 /* ~VT_FUNC */
107 #define TOK_WHILE 261
108 #define TOK_BREAK 262
109 #define TOK_RETURN 263
110 #define TOK_DEFINE 264
113 #define TOK_EXTERN 267
114 #define TOK_STATIC 268
115 #define TOK_UNSIGNED 269
118 #define TOK_CONTINUE 272
119 #define TOK_SWITCH 273
122 /* ignored types Must have contiguous values */
123 #define TOK_CONST 275
124 #define TOK_VOLATILE 276
126 #define TOK_REGISTER 278
127 #define TOK_SIGNED 279
129 #define TOK_INLINE 281
131 #define TOK_FLOAT 282 /* unsupported */
132 #define TOK_DOUBLE 283 /* unsupported */
134 #define TOK_STRUCT 284
135 #define TOK_UNION 285
136 #define TOK_TYPEDEF 286
137 #define TOK_DEFAULT 287
139 #define TOK_SIZEOF 289
140 #define TOK_INCLUDE 290
142 #define TOK_EQ 0x94 /* warning: depend on asm code */
143 #define TOK_NE 0x95 /* warning: depend on asm code */
144 #define TOK_LT 0x9c /* warning: depend on asm code */
145 #define TOK_GE 0x9d /* warning: depend on asm code */
146 #define TOK_LE 0x9e /* warning: depend on asm code */
147 #define TOK_GT 0x9f /* warning: depend on asm code */
149 #define TOK_LAND 0xa0
153 #define TOK_MID 0xa3 /* inc/dec, to void constant */
155 #define TOK_ARROW 0xa7
156 #define TOK_DOTS 0xa8 /* three dots */
157 #define TOK_SHR 0xa9 /* unsigned shift right */
158 #define TOK_UDIV 0xb0 /* unsigned division */
159 #define TOK_UMOD 0xb1 /* unsigned modulo */
160 #define TOK_PDIV 0xb2 /* fast division with undefined rounding for pointers */
161 #define TOK_NUM 0xb3 /* number in tokc */
163 #define TOK_SHL 0x01 /* shift left */
164 #define TOK_SAR 0x02 /* signed shift right */
166 /* assignement operators : normal operator or 0x80 */
167 #define TOK_A_MOD 0xa5
168 #define TOK_A_AND 0xa6
169 #define TOK_A_MUL 0xaa
170 #define TOK_A_ADD 0xab
171 #define TOK_A_SUB 0xad
172 #define TOK_A_DIV 0xaf
173 #define TOK_A_XOR 0xde
174 #define TOK_A_OR 0xfc
175 #define TOK_A_SHL 0x81
176 #define TOK_A_SAR 0x82
189 return (c
>= 'a' & c
<= 'z') |
190 (c
>= 'A' & c
<= 'Z') |
196 return c
>= '0' & c
<= '9';
200 /* XXX: use stderr ? */
201 void error(char *msg
)
203 printf("%s:%d: %s\n", filename
, line_num
, msg
);
207 void expect(char *msg
)
209 printf("%s:%d: %s expected\n", filename
, line_num
, msg
);
213 void warning(char *msg
)
215 printf("%s:%d: warning: %s\n", filename
, line_num
, msg
);
221 printf("%s:%d: '%c' expected\n", filename
, line_num
, c
);
235 #define skip(c) next()
236 #define test_lvalue()
240 char *get_tok_str(int v
)
255 /* find a symbol and return its associated structure. 's' is the top
256 of the symbol stack */
257 Sym
*sym_find1(Sym
*s
, int v
)
267 Sym
*sym_push1(Sym
**ps
, int v
, int t
, int c
)
270 s
= malloc(sizeof(Sym
));
272 error("memory full");
282 /* find a symbol in the right symbol space */
286 s
= sym_find1(local_stack
, v
);
288 s
= sym_find1(global_stack
, v
);
292 /* push a given symbol on the symbol stack */
293 Sym
*sym_push(int v
, int t
, int c
)
295 // printf("sym_push: %x %s type=%x\n", v, get_tok_str(v), t);
297 return sym_push1(&local_stack
, v
, t
, c
);
299 return sym_push1(&global_stack
, v
, t
, c
);
302 /* pop symbols until top reaches 'b' */
303 void sym_pop(Sym
**ps
, Sym
*b
)
310 // printf("sym_pop: %x %s type=%x\n", s->v, get_tok_str(s->v), s->t);
319 /* read next char from current input file */
327 if (include_stack_ptr
== include_stack
)
329 /* pop include stack */
333 file
= include_stack_ptr
->file
;
334 filename
= include_stack_ptr
->filename
;
335 line_num
= include_stack_ptr
->line_num
;
340 // printf("ch1=%c\n", ch1);
343 /* input with '\\n' handling and macro subtitution if in macro state */
346 if (macro_ptr
!= 0) {
350 macro_ptr
= *--macro_stack_ptr
;
351 ch
= (int)*--macro_stack_ptr
;
357 if (ch
== '\\' && ch1
== '\n') {
364 /* same as minp, but also skip comments */
372 /* single line C++ comments */
374 while (ch1
!= '\n' && ch1
!= -1)
377 ch
= ' '; /* return space */
378 } else if (ch1
== '*') {
384 if (c
== '*' && ch1
== '/') {
386 ch
= ' '; /* return space */
400 while (ch
== ' ' || ch
== '\t')
408 char buf
[1024], *q
, *p
;
413 next(); /* XXX: should pass parameter to avoid macro subst */
414 if (tok
== TOK_DEFINE
) {
415 next(); /* XXX: should pass parameter to avoid macro subst */
417 /* now 'tok' is the macro symbol */
422 if ((n
+ 1) >= size
) {
424 str
= realloc(str
, size
);
426 error("memory full");
428 if (ch
== -1 || ch
== '\n') {
429 str
[n
++] = ' '; /* a space is inserted after each macro */
436 sym_push1(&define_stack
, tok
, 0, (int)str
);
437 } else if (tok
== TOK_INCLUDE
) {
442 } else if (ch
== '\"') {
447 while (ch
!= c
&& ch
!= '\n' && ch
!= -1) {
448 if ((q
- buf
) < sizeof(buf
) - 1)
453 if (include_stack_ptr
>= include_stack
+ INCLUDE_STACK_SIZE
)
454 error("memory full");
456 /* first search in current dir if "header.h" */
457 /* XXX: buffer overflow */
459 p
= strrchr(filename
, '/');
461 size
= p
+ 1 - filename
;
462 memcpy(buf1
, filename
, size
);
465 f
= fopen(buf1
, "r");
469 /* now search in standard include path */
470 strcpy(buf1
, INCLUDE_PATH
);
473 f
= fopen(buf1
, "r");
475 error("include file not found");
477 /* push current file in stack */
478 include_stack_ptr
->file
= file
;
479 include_stack_ptr
->filename
= filename
;
480 include_stack_ptr
->line_num
= line_num
;
483 filename
= strdup(buf1
);
488 /* ignore other preprocess commands or #! for C scripts */
489 while (ch
!= '\n' && ch
!= -1)
493 /* read a number in base b */
499 if (ch
>= 'a' & ch
<= 'f')
501 else if (ch
>= 'A' & ch
<= 'F')
521 /* special 'ungettok' case for label parsing */
532 while (ch
== ' ' || ch
== 9)
535 /* preprocessor command if # at start of line after
540 if (ch
!= ' ' && ch
!= 9)
546 while(isid(ch
) | isnum(ch
)) {
554 if (strcmp(p
, idptr
) == 0)
559 // printf("id=%s\n", idptr);
560 /* if not found, add symbol */
563 /* if symbol is a define, prepare substitution */
564 if (s
= sym_find1(define_stack
, tok
)) {
565 if ((macro_stack_ptr
- macro_stack
) >= MACRO_STACK_SIZE
)
566 error("too many nested macros");
567 *macro_stack_ptr
++ = (char *)ch
;
568 *macro_stack_ptr
++ = macro_ptr
;
569 macro_ptr
= (char *)s
->c
;
573 } else if (isnum(ch
)) {
588 q
= "<=\236>=\235!=\225++\244--\242==\224";
590 q
= "<=\236>=\235!=\225&&\240||\241++\244--\242==\224<<\1>>\2+=\253-=\255*=\252/=\257%=\245&=\246^=\336|=\374->\247..\250";
596 if (*q
== tok
& q
[1] == ch
) {
599 /* three chars tests */
600 if (tok
== TOK_SHL
| tok
== TOK_SAR
) {
605 } else if (tok
== TOK_DOTS
) {
607 error("parse error");
614 /* single char substitutions */
622 void swap(int *p
, int *q
)
636 /******************************************************/
637 /* X86 code generator */
652 /* output a symbol and patch all calls to it */
657 n
= *(int *)t
; /* next value */
658 *(int *)t
= a
- t
- 4;
668 /* psym is used to put an instruction with a data field which is a
669 reference to a symbol. It is in fact the same as oad ! */
672 /* instruction + 4 bytes data. Return the address of the data */
682 /* XXX: generate correct pointer for forward references to functions */
690 if (v
== VT_LLOCAL
) {
691 load(r
, VT_LOCAL
| VT_LVAL
, fc
);
694 if ((ft
& VT_TYPE
) == VT_BYTE
)
695 o(0xbe0f); /* movsbl */
699 oad(0x05 + r
* 8, fc
); /* 0xXX, r */
700 } else if (v
== VT_LOCAL
) {
701 oad(0x85 + r
* 8, fc
); /* xx(%ebp), r */
703 g(0x00 + r
* 8 + v
); /* (v), r */
707 oad(0xb8 + r
, fc
); /* mov $xx, r */
708 } else if (v
== VT_LOCAL
) {
710 oad(0x85 + r
* 8, fc
); /* lea xxx(%ebp), r */
711 } else if (v
== VT_CMP
) {
712 oad(0xb8 + r
, 0); /* mov $0, r */
713 o(0x0f); /* setxx %br */
716 } else if (v
== VT_JMP
|| v
== VT_JMPI
) {
718 oad(0xb8 + r
, t
); /* mov $1, r */
719 oad(0xe9, 5); /* jmp after */
721 oad(0xb8 + r
, t
^ 1); /* mov $0, r */
724 o(0xc0 + r
+ v
* 8); /* mov v, r */
730 /* WARNING: r must not be allocated on the stack */
731 void store(r
, ft
, fc
)
735 fr
= ft
& VT_VALMASK
;
736 b
= (ft
& VT_TYPE
) == VT_BYTE
;
738 if (fr
== VT_CONST
) {
739 oad(0x05 + r
* 8, fc
); /* mov r,xxx */
740 } else if (fr
== VT_LOCAL
) {
741 oad(0x85 + r
* 8, fc
); /* mov r,xxx(%ebp) */
742 } else if (ft
& VT_LVAL
) {
743 g(fr
+ r
* 8); /* mov r, (fr) */
744 } else if (fr
!= r
) {
745 o(0xc0 + fr
+ r
* 8); /* mov r, fr */
751 return psym(0xe9, t
);
754 /* generate a test. set 'inv' to invert test */
760 /* fast case : can jump directly since flags are set */
762 t
= psym((vc
- 16) ^ inv
, t
);
763 } else if (v
== VT_JMP
|| v
== VT_JMPI
) {
764 /* && or || optimization */
765 if ((v
& 1) == inv
) {
766 /* insert vc jump list in t */
776 } else if ((vt
& (VT_VALMASK
| VT_LVAL
)) == VT_CONST
) {
777 /* constant jmp optimization */
778 if ((vc
!= 0) != inv
)
785 t
= psym(0x85 ^ inv
, t
);
790 /* generate a binary operation 'v = r op fr' instruction and modifies
792 void gen_op1(op
, r
, fr
)
797 o(0xc0 + r
+ fr
* 8);
798 } else if (op
== '-') {
800 o(0xc0 + r
+ fr
* 8);
801 } else if (op
== '&') {
803 o(0xc0 + r
+ fr
* 8);
804 } else if (op
== '^') {
806 o(0xc0 + r
+ fr
* 8);
807 } else if (op
== '|') {
809 o(0xc0 + r
+ fr
* 8);
810 } else if (op
== '*') {
811 o(0xaf0f); /* imul fr, r */
812 o(0xc0 + fr
+ r
* 8);
813 } else if (op
== TOK_SHL
| op
== TOK_SHR
| op
== TOK_SAR
) {
819 o(0x87); /* xchg r, %ecx */
824 o(0xd3); /* shl/shr/sar %cl, r */
827 else if (op
== TOK_SHR
)
831 vt
= (vt
& VT_TYPE
) | r
;
832 } else if (op
== '/' | op
== TOK_UDIV
| op
== TOK_PDIV
|
833 op
== '%' | op
== TOK_UMOD
) {
834 save_reg(2); /* save edx */
835 t
= save_reg_forced(fr
); /* save fr and get op2 location */
836 move_reg(0, r
); /* op1 is %eax */
837 if (op
== TOK_UDIV
| op
== TOK_UMOD
) {
838 o(0xf7d231); /* xor %edx, %edx, div t(%ebp), %eax */
841 o(0xf799); /* cltd, idiv t(%ebp), %eax */
844 if (op
== '%' | op
== TOK_UMOD
)
848 vt
= (vt
& VT_TYPE
) | r
;
851 o(0xc0 + r
+ fr
* 8); /* cmp fr, r */
856 /* end of X86 code generator */
857 /*************************************************************/
859 int save_reg_forced(r
)
863 loc
= (loc
- 4) & -3;
864 store(r
, VT_LOCAL
, loc
);
867 /* modify all stack values */
868 for(p
=vstack
;p
<vstack_ptr
;p
+=2) {
869 i
= p
[0] & VT_VALMASK
;
875 p
[0] = (p
[0] & VT_TYPE
) | VT_LVAL
| t
;
882 /* save r to memory. and mark it as being free */
887 /* modify all stack values */
888 for(p
=vstack
;p
<vstack_ptr
;p
+=2) {
889 i
= p
[0] & VT_VALMASK
;
897 /* find a free register. If none, save one register */
902 /* find a free register */
903 for(r
=0;r
<NB_REGS
;r
++) {
904 for(p
=vstack
;p
<vstack_ptr
;p
+=2) {
905 i
= p
[0] & VT_VALMASK
;
913 /* no register left : free the first one on the stack (very
914 important to start from the bottom to ensure that we don't
915 spill registers used in gen_op()) */
916 for(p
=vstack
;p
<vstack_ptr
;p
+=2) {
917 r
= p
[0] & VT_VALMASK
;
929 for(p
=vstack
;p
<vstack_ptr
;p
+=2) {
930 r
= p
[0] & VT_VALMASK
;
937 /* move register 's' to 'r', and flush previous value of r to memory
947 /* convert a stack entry in register */
951 r
= p
[0] & VT_VALMASK
;
952 if (r
>= VT_CONST
|| (p
[0] & VT_LVAL
))
955 p
[0] = (p
[0] & VT_TYPE
) | r
;
963 /* cannot let cpu flags if other instruction are generated */
964 if ((vt
& VT_VALMASK
) == VT_CMP
)
968 void vpop(int *ft
, int *fc
)
974 /* generate a value in a register from vt and vc */
979 r
= gvp(vstack_ptr
- 2);
984 /* handle constant optimizations and various machine independant opt */
987 int fr
, ft
, fc
, r
, c1
, c2
, n
;
991 c1
= (vt
& (VT_VALMASK
| VT_LVAL
)) == VT_CONST
;
992 c2
= (ft
& (VT_VALMASK
| VT_LVAL
)) == VT_CONST
;
995 case '+': vc
+= fc
; break;
996 case '-': vc
-= fc
; break;
997 case '&': vc
&= fc
; break;
998 case '^': vc
^= fc
; break;
999 case '|': vc
|= fc
; break;
1000 case '*': vc
*= fc
; break;
1002 case '/': vc
/= fc
; break; /* XXX: zero case ? */
1003 case '%': vc
%= fc
; break; /* XXX: zero case ? */
1004 case TOK_UDIV
: vc
= (unsigned)vc
/ fc
; break; /* XXX: zero case ? */
1005 case TOK_UMOD
: vc
= (unsigned)vc
% fc
; break; /* XXX: zero case ? */
1006 case TOK_SHL
: vc
<<= fc
; break;
1007 case TOK_SHR
: vc
= (unsigned)vc
>> fc
; break;
1008 case TOK_SAR
: vc
>>= fc
; break;
1013 /* if commutative ops, put c2 as constant */
1014 if (c1
&& (op
== '+' || op
== '&' || op
== '^' ||
1015 op
== '|' || op
== '*')) {
1020 if (c2
&& (((op
== '*' || op
== '/' || op
== TOK_UDIV
||
1023 ((op
== '+' || op
== '-' || op
== '|' || op
== '^' ||
1024 op
== TOK_SHL
|| op
== TOK_SHR
|| op
== TOK_SAR
) &&
1028 } else if (c2
&& (op
== '*' || op
== TOK_PDIV
|| op
== TOK_UDIV
)) {
1029 /* try to use shifts instead of muls or divs */
1030 if (fc
> 0 && (fc
& (fc
- 1)) == 0) {
1039 else if (op
== TOK_PDIV
)
1051 r
= gvp(vstack_ptr
- 4);
1052 fr
= gvp(vstack_ptr
- 2);
1055 /* call low level op generator */
1063 return type_size(pointed_type(t
), &t
);
1066 /* generic gen_op: handles types problems */
1072 t1
= vstack_ptr
[-4];
1073 t2
= vstack_ptr
[-2];
1074 if (op
== '+' | op
== '-') {
1075 if ((t1
& VT_PTR
) && (t2
& VT_PTR
)) {
1077 error("invalid type");
1078 /* XXX: check that types are compatible */
1079 u
= pointed_size(t1
);
1082 vstack_ptr
[-2] &= ~VT_TYPE
; /* set to integer */
1085 } else if ((t1
| t2
) & VT_PTR
) {
1087 swap(vstack_ptr
- 4, vstack_ptr
- 2);
1088 swap(vstack_ptr
- 3, vstack_ptr
- 1);
1091 /* stack-4 contains pointer, stack-2 value to add */
1092 vset(VT_CONST
, pointed_size(vstack_ptr
[-4]));
1096 /* put again type if gen_opc() swaped operands */
1097 vt
= (vt
& VT_TYPEN
) | (t1
& VT_TYPE
);
1102 if ((t1
| t2
) & VT_UNSIGNED
) {
1114 /* return type size. Put alignment at 'a' */
1115 int type_size(int t
, int *a
)
1119 /* int, enum or pointer */
1120 if (t
& VT_STRUCT
) {
1122 s
= sym_find(((unsigned)t
>> VT_STRUCT_SHIFT
) | SYM_STRUCT
);
1123 *a
= 4; /* XXX: cannot store it yet. Doing that is safe */
1125 } else if (t
& VT_ARRAY
) {
1126 s
= sym_find(((unsigned)t
>> VT_STRUCT_SHIFT
));
1127 return type_size(s
->t
, a
) * s
->c
;
1128 } else if ((t
& VT_PTR
) |
1129 (t
& VT_TYPE
) == 0 |
1139 /* return the pointed type of t */
1140 int pointed_type(int t
)
1143 s
= sym_find(((unsigned)t
>> VT_STRUCT_SHIFT
));
1144 return s
->t
| (t
& VT_TYPEN
);
1147 int mk_pointer(int t
)
1152 return VT_PTR
| (p
<< VT_STRUCT_SHIFT
) | (t
& VT_TYPEN
);
1155 /* store value in lvalue pushed on stack */
1160 r
= gv(); /* generate value */
1162 ft
= vstack_ptr
[-4];
1163 fc
= vstack_ptr
[-3];
1164 if ((ft
& VT_VALMASK
) == VT_LLOCAL
) {
1166 load(t
, VT_LOCAL
| VT_LVAL
, fc
);
1167 ft
= (ft
& ~VT_VALMASK
) | t
;
1173 /* post defines POST/PRE add. c is the token ++ or -- */
1179 vpush(); /* room for returned value */
1180 vpush(); /* save lvalue */
1182 vpush(); /* save value */
1184 /* duplicate value */
1186 load(r1
, r
, 0); /* move r to r1 */
1187 vstack_ptr
[-6] = (vt
& VT_TYPE
) | r1
;
1191 vset(VT_CONST
, c
- TOK_MID
);
1193 vstore(); /* store value */
1201 if ((vt
& (VT_CONST
| VT_LVAL
)) != VT_CONST
)
1206 /* enum/struct/union declaration */
1209 int a
, t
, b
, v
, size
, align
, maxalign
, c
;
1210 Sym
*slast
, *s
, *ss
;
1212 a
= tok
; /* save decl type */
1217 /* struct already defined ? return it */
1218 /* XXX: check consistency */
1219 if (s
= sym_find(v
| SYM_STRUCT
)) {
1221 error("invalid type");
1222 u
= u
| (v
<< VT_STRUCT_SHIFT
);
1228 s
= sym_push(v
| SYM_STRUCT
, a
, 0);
1229 /* put struct/union/enum name in type */
1230 u
= u
| (v
<< VT_STRUCT_SHIFT
);
1234 /* cannot be empty */
1239 if (a
== TOK_ENUM
) {
1246 sym_push(v
, VT_CONST
, c
);
1254 if (t
& (VT_FUNC
| VT_TYPEDEF
))
1255 error("invalid type");
1256 /* XXX: align & correct type size */
1258 size
= type_size(t
, &align
);
1259 if (a
== TOK_STRUCT
) {
1260 c
= (c
+ align
- 1) & -align
;
1261 ss
= sym_push(v
, t
, c
);
1264 ss
= sym_push(v
, t
, 0);
1268 if (align
> maxalign
)
1272 if (tok
== ';' || tok
== -1)
1283 /* size for struct/union, dummy for enum */
1284 s
->c
= (c
+ maxalign
- 1) & -maxalign
;
1289 /* return 0 if no type declaration. otherwise, return the basic type
1291 XXX: A '2' is ored to ensure non zero return if int type.
1301 if (tok
== TOK_ENUM
) {
1302 t
|= struct_decl(VT_ENUM
);
1303 } else if (tok
== TOK_STRUCT
|| tok
== TOK_UNION
) {
1304 t
|= struct_decl(VT_STRUCT
);
1308 if (tok
== TOK_CHAR
) {
1310 } else if (tok
== TOK_VOID
) {
1312 } else if (tok
== TOK_INT
|
1313 (tok
>= TOK_CONST
& tok
<= TOK_INLINE
)) {
1315 } else if (tok
== TOK_FLOAT
& tok
== TOK_DOUBLE
) {
1316 error("floats not supported");
1317 } else if (tok
== TOK_EXTERN
) {
1319 } else if (tok
== TOK_STATIC
) {
1321 } else if (tok
== TOK_UNSIGNED
) {
1323 } else if (tok
== TOK_TYPEDEF
) {
1327 if (!s
|| !(s
->t
& VT_TYPEDEF
))
1329 t
= s
->t
& ~VT_TYPEDEF
;
1343 /* function declaration */
1345 /* push a dummy symbol to force local symbol stack usage */
1346 sym_push1(&local_stack
, 0, 0, 0);
1349 while (tok
!= ')') {
1350 /* read param name and compute offset */
1352 if (!(pt
= ist())) {
1354 error("invalid type");
1360 if (pt
& VT_VOID
&& tok
== ')')
1363 pt
= typ(&n
, pt
); /* XXX: should accept
1364 both arg/non arg if v == 0 */
1368 pt
= 0; /* int type */
1371 /* array must be transformed to pointer according to ANSI C */
1374 sym_push(n
, VT_LOCAL
| VT_LVAL
| pt
, p
);
1377 if (l
== 1 && tok
== TOK_DOTS
) {
1384 t
= post_type(0, t
); /* XXX: may be incorrect */
1385 /* transform function pointer to 'char *' */
1390 } else if (tok
== '[') {
1391 /* array definition */
1397 error("invalid array size");
1400 /* parse next post type */
1401 t
= post_type(u
, t
);
1403 /* we push a anonymous symbol which will contain the array
1407 t
= VT_ARRAY
| VT_PTR
| (p
<< VT_STRUCT_SHIFT
);
1412 /* Read a type declaration (except basic type), and return the
1413 type. If v is true, then also put variable name in 'vc' */
1414 int typ(int *v
, int t
)
1418 t
= t
& -3; /* suppress the ored '2' */
1419 while (tok
== '*') {
1424 /* recursive type */
1425 /* XXX: incorrect if abstract type for functions (e.g. 'int ()') */
1432 /* type identifier */
1438 return post_type(u
, t
);
1441 /* define a new external reference to a function 'v' of type 'u' */
1442 Sym
*external_func(v
, u
)
1448 n
= dlsym(0, get_tok_str(v
));
1450 /* used to generate symbol list */
1451 s
= sym_push1(&global_stack
,
1452 v
, u
| VT_CONST
| VT_LVAL
| VT_FORWARD
, 0);
1455 s
= sym_push1(&global_stack
,
1456 v
, u
| VT_CONST
| VT_LVAL
, n
);
1462 /* read a character for string or char constant and eval escape codes */
1493 vt
= pointed_type(vt
);
1494 if (!(vt
& VT_ARRAY
)) /* an array is never an lvalue */
1500 int n
, t
, ft
, fc
, p
, r
;
1503 if (tok
== TOK_NUM
) {
1504 vset(VT_CONST
, tokc
);
1508 vset(VT_CONST
, getq());
1509 next(); /* skip char */
1511 } else if (tok
== '\"') {
1512 /* generate (char *) type */
1513 vset(VT_CONST
| mk_pointer(VT_TYPE
), glo
);
1514 while (tok
== '\"') {
1515 while (ch
!= '\"') {
1517 error("unterminated string");
1518 *(char *)glo
++ = getq();
1533 vt
= (vt
& VT_TYPEN
) | ft
;
1538 } else if (t
== '*') {
1541 } else if (t
== '&') {
1544 vt
= mk_pointer(vt
& VT_LVALN
);
1548 if ((vt
& VT_VALMASK
) == VT_CMP
)
1551 vset(VT_JMP
, gtst(1, 0));
1562 if (t
== TOK_SIZEOF
) {
1563 /* XXX: some code can be generated */
1574 vset(VT_CONST
, type_size(vt
, &t
));
1576 if (t
== TOK_INC
| t
== TOK_DEC
) {
1579 } else if (t
== '-') {
1589 error("undefined symbol");
1590 /* for simple function calls, we tolerate undeclared
1591 external reference */
1592 s
= external_func(t
, VT_FUNC
); /* int() function */
1595 /* if forward reference, we must point to s->c */
1596 if (vt
& VT_FORWARD
)
1601 /* post operations */
1603 if (tok
== TOK_INC
| tok
== TOK_DEC
) {
1606 } else if (tok
== '.' | tok
== TOK_ARROW
) {
1608 if (tok
== TOK_ARROW
)
1613 /* expect pointer on structure */
1614 if (!(vt
& VT_STRUCT
))
1615 expect("struct or union");
1616 s
= sym_find(((unsigned)vt
>> VT_STRUCT_SHIFT
) | SYM_STRUCT
);
1619 while (s
= s
->next
) {
1624 error("field not found");
1625 /* add field offset to pointer */
1626 vt
= vt
& VT_TYPEN
; /* change type to int */
1628 vset(VT_CONST
, s
->c
);
1630 /* change type to field type, and set to lvalue */
1631 vt
= (vt
& VT_TYPEN
) | VT_LVAL
| s
->t
;
1633 } else if (tok
== '[') {
1640 } else if (tok
== '(') {
1642 save_regs(); /* save used temporary registers */
1643 /* lvalue is implied */
1645 if ((vt
& VT_VALMASK
) != VT_CONST
) {
1646 /* evaluate function address */
1648 o(0x50 + r
); /* push r */
1654 while (tok
!= ')') {
1658 o(0x50 + r
); /* push r */
1663 /* horrible, but needed : convert to native ordering (could
1664 parse parameters in reverse order, but would cost more
1669 oad(0x24848b, p
); /* mov x(%esp,1), %eax */
1670 oad(0x248487, n
); /* xchg x(%esp,1), %eax */
1671 oad(0x248489, p
); /* mov %eax, x(%esp,1) */
1675 if ((ft
& VT_VALMASK
) == VT_CONST
) {
1676 /* forward reference */
1677 if (ft
& VT_FORWARD
) {
1678 *(int *)fc
= psym(0xe8, *(int *)fc
);
1680 oad(0xe8, fc
- ind
- 5);
1681 /* return value is %eax, and take type from function proto */
1682 vt
= 0 | (ft
& VT_TYPE
& VT_FUNCN
);
1684 oad(0x2494ff, t
); /* call *xxx(%esp) */
1686 /* return value is %eax, integer */
1703 (tok
>= TOK_A_MOD
& tok
<= TOK_A_DIV
) |
1704 tok
== TOK_A_XOR
| tok
== TOK_A_OR
|
1705 tok
== TOK_A_SHL
| tok
== TOK_A_SAR
) {
1712 /* XXX: be more precise */
1713 if ((vt
& VT_PTR
) != (vstack_ptr
[-2] & VT_PTR
))
1714 warning("incompatible type");
1732 while ((l
== 0 & (tok
== '*' | tok
== '/' | tok
== '%')) |
1733 (l
== 1 & (tok
== '+' | tok
== '-')) |
1734 (l
== 2 & (tok
== TOK_SHL
| tok
== TOK_SAR
)) |
1735 (l
== 3 & (tok
>= TOK_LT
& tok
<= TOK_GT
)) |
1736 (l
== 4 & (tok
== TOK_EQ
| tok
== TOK_NE
)) |
1737 (l
== 5 & tok
== '&') |
1738 (l
== 6 & tok
== '^') |
1739 (l
== 7 & tok
== '|')) {
1762 if (tok
!= TOK_LAND
) {
1782 if (tok
!= TOK_LOR
) {
1826 void block(int *bsym
, int *csym
, int *case_sym
, int *def_sym
, int case_reg
)
1831 if (tok
== TOK_IF
) {
1838 block(bsym
, csym
, case_sym
, def_sym
, case_reg
);
1840 if (c
== TOK_ELSE
) {
1844 block(bsym
, csym
, case_sym
, def_sym
, case_reg
);
1845 gsym(d
); /* patch else jmp */
1848 } else if (tok
== TOK_WHILE
) {
1856 block(&a
, &b
, case_sym
, def_sym
, case_reg
);
1857 oad(0xe9, d
- ind
- 5); /* jmp */
1860 } else if (tok
== '{') {
1866 block(bsym
, csym
, case_sym
, def_sym
, case_reg
);
1867 /* pop locally defined symbols */
1868 sym_pop(&local_stack
, s
);
1870 } else if (tok
== TOK_RETURN
) {
1877 rsym
= gjmp(rsym
); /* jmp */
1878 } else if (tok
== TOK_BREAK
) {
1881 error("cannot break");
1882 *bsym
= gjmp(*bsym
);
1885 } else if (tok
== TOK_CONTINUE
) {
1888 error("cannot continue");
1889 *csym
= gjmp(*csym
);
1894 if (tok
== TOK_FOR
) {
1914 oad(0xe9, d
- ind
- 5); /* jmp */
1918 block(&a
, &b
, case_sym
, def_sym
, case_reg
);
1919 oad(0xe9, c
- ind
- 5); /* jmp */
1923 if (tok
== TOK_DO
) {
1928 block(&a
, &b
, case_sym
, def_sym
, case_reg
);
1938 if (tok
== TOK_SWITCH
) {
1947 block(&a
, csym
, &b
, &c
, case_reg
);
1948 /* if no default, jmp after switch */
1956 if (tok
== TOK_CASE
) {
1966 *case_sym
= gtst(1, 0);
1968 block(bsym
, csym
, case_sym
, def_sym
, case_reg
);
1970 if (tok
== TOK_DEFAULT
) {
1976 error("too many 'default'");
1978 block(bsym
, csym
, case_sym
, def_sym
, case_reg
);
1980 if (tok
== TOK_GOTO
) {
1982 s
= sym_find1(label_stack
, tok
);
1983 /* put forward definition if needed */
1985 s
= sym_push1(&label_stack
, tok
, VT_FORWARD
, 0);
1986 /* label already defined */
1987 if (s
->t
& VT_FORWARD
)
1988 s
->c
= gjmp(s
->c
); /* jmp xxx */
1990 oad(0xe9, s
->c
- ind
- 5); /* jmp xxx */
2001 s
= sym_find1(label_stack
, b
);
2003 if (!(s
->t
& VT_FORWARD
))
2004 error("multiple defined label");
2009 sym_push1(&label_stack
, b
, 0, ind
);
2011 block(bsym
, csym
, case_sym
, def_sym
, case_reg
);
2013 /* expression case: go backward of one token */
2014 /* XXX: currently incorrect if number/string/char */
2025 /* 'l' is VT_LOCAL or VT_CONST to define default storage type */
2028 int *a
, t
, b
, size
, align
, v
, u
, n
;
2032 if ((b
& (VT_ENUM
| VT_STRUCT
)) && tok
== ';') {
2033 /* we accept no variable after */
2037 while (1) { /* iterate thru each declaration */
2040 /* patch forward references */
2041 if ((sym
= sym_find(v
)) && (sym
->t
& VT_FORWARD
)) {
2044 sym
->t
= VT_CONST
| VT_LVAL
| t
;
2046 /* put function address */
2047 sym_push1(&global_stack
, v
, VT_CONST
| VT_LVAL
| t
, ind
);
2050 o(0xe58955); /* push %ebp, mov %esp, %ebp */
2051 a
= (int *)oad(0xec81, 0); /* sub $xxx, %esp */
2053 block(0, 0, 0, 0, 0);
2055 o(0xc3c9); /* leave, ret */
2056 *a
= (-loc
+ 3) & -4; /* align local size to word &
2057 save local variables */
2058 sym_pop(&label_stack
, 0); /* reset label stack */
2059 sym_pop(&local_stack
, 0); /* reset local stack */
2062 if (b
& VT_TYPEDEF
) {
2063 /* save typedefed type */
2064 sym_push(v
, t
| VT_TYPEDEF
, 0);
2065 } else if (t
& VT_FUNC
) {
2066 /* XXX: incorrect to flush, but needed while
2067 waiting for function prototypes */
2068 /* external function definition */
2069 external_func(v
, t
);
2071 /* not lvalue if array */
2072 if (!(t
& VT_ARRAY
))
2074 if (t
& VT_EXTERN
) {
2075 /* external variable */
2076 /* XXX: factorize with external function def */
2077 n
= dlsym(NULL
, get_tok_str(v
));
2079 error("unknown external variable");
2080 sym_push(v
, VT_CONST
| t
, n
);
2086 size
= type_size(t
, &align
);
2088 error("invalid size");
2089 if ((u
& VT_VALMASK
) == VT_LOCAL
) {
2090 /* allocate space down on the stack */
2091 loc
= (loc
- size
) & -align
;
2092 sym_push(v
, u
, loc
);
2094 /* allocate space up in the data space */
2095 glo
= (glo
+ align
- 1) & -align
;
2096 sym_push(v
, u
, glo
);
2111 int main(int c
, char **v
)
2116 printf("usage: tcc source ...\n");
2122 file
= fopen(filename
, "r");
2127 include_stack_ptr
= include_stack
;
2129 idtable
= malloc(SYM_TABLE_SIZE
);
2131 "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);
2132 idptr
= idtable
+ 219;
2134 glo
= malloc(DATA_SIZE
);
2135 memset((void *)glo
, 0, DATA_SIZE
);
2136 prog
= malloc(TEXT_SIZE
);
2137 vstack
= malloc(256);
2138 vstack_ptr
= vstack
;
2139 macro_stack_ptr
= macro_stack
;
2140 anon_sym
= 1 << (31 - VT_STRUCT_SHIFT
);
2143 ch
= '\n'; /* needed to parse correctly first preprocessor command */
2149 f
= fopen(v
[1], "w");
2150 fwrite((void *)prog
, 1, ind
- prog
, f
);
2155 s
= sym_find(TOK_MAIN
);
2157 error("main() not defined");
2159 return (*t
)(c
- 1, v
);