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.
23 /* preprocessor debug */
26 /* these sizes are dummy for unix, because malloc() does not use
27 memory when the pages are not used */
28 #define TEXT_SIZE (4*1024*1024)
29 #define DATA_SIZE (4*1024*1024)
31 #define INCLUDE_STACK_SIZE 32
32 #define IFDEF_STACK_SIZE 64
33 #define VSTACK_SIZE 64
34 #define STRING_MAX_SIZE 1024
35 #define INCLUDE_PATHS_MAX 32
37 #define TOK_HASH_SIZE 521
38 #define TOK_ALLOC_INCR 256 /* must be a power of two */
39 #define SYM_HASH_SIZE 263
41 /* number of available temporary registers */
43 /* defined if function parameters must be evaluated in reverse order */
44 #define INVERT_FUNC_PARAMS
46 /* token symbol management */
47 typedef struct TokenSym
{
48 struct TokenSym
*hash_next
;
49 int tok
; /* token number */
54 /* symbol management */
56 int v
; /* symbol token */
57 int t
; /* associated type */
58 int c
; /* associated number */
59 struct Sym
*next
; /* next related symbol */
60 struct Sym
*prev
; /* prev symbol in stack */
61 struct Sym
*hash_next
; /* next symbol in hash table */
64 typedef struct SymStack
{
66 struct Sym
*hash
[SYM_HASH_SIZE
];
69 #define SYM_STRUCT 0x40000000 /* struct/union/enum symbol space */
70 #define SYM_FIELD 0x20000000 /* struct/union field symbol space */
72 #define FUNC_NEW 1 /* ansi function prototype */
73 #define FUNC_OLD 2 /* old function prototype */
74 #define FUNC_ELLIPSIS 3 /* ansi function prototype with ... */
76 /* field 'Sym.t' for macros */
77 #define MACRO_OBJ 0 /* object like macro */
78 #define MACRO_FUNC 1 /* function like macro */
80 /* type_decl() types */
81 #define TYPE_ABSTRACT 1 /* type without variable */
82 #define TYPE_DIRECT 2 /* type with variable */
90 /* loc : local variable index
91 glo : global variable index
95 anon_sym: anonymous symbol index
98 int tok
, tok1
, tokc
, rsym
, anon_sym
,
99 prog
, ind
, loc
, glo
, vt
, vc
, const_wanted
, line_num
;
100 int global_expr
; /* true if compound literals must be allocated
101 globally (used during initializers parsing */
103 TokenSym
**table_ident
;
104 TokenSym
*hash_ident
[521];
105 char token_buf
[STRING_MAX_SIZE
+ 1];
106 char *filename
, *funcname
;
107 SymStack define_stack
, global_stack
, local_stack
, label_stack
;
109 int vstack
[VSTACK_SIZE
], *vstack_ptr
;
110 int *macro_ptr
, *macro_ptr_allocated
;
111 IncludeFile include_stack
[INCLUDE_STACK_SIZE
], *include_stack_ptr
;
112 int ifdef_stack
[IFDEF_STACK_SIZE
], *ifdef_stack_ptr
;
113 char *include_paths
[INCLUDE_PATHS_MAX
];
114 int nb_include_paths
;
116 /* The current value can be: */
117 #define VT_VALMASK 0x000f
118 #define VT_CONST 0x000a /* constant in vc
119 (must be first non register value) */
120 #define VT_LLOCAL 0x000b /* lvalue, offset on stack */
121 #define VT_LOCAL 0x000c /* offset on stack */
122 #define VT_CMP 0x000d /* the value is stored in processor flags (in vc) */
123 #define VT_JMP 0x000e /* value is the consequence of jmp true */
124 #define VT_JMPI 0x000f /* value is the consequence of jmp false */
125 #define VT_LVAL 0x0010 /* var is an lvalue */
126 #define VT_LVALN -17 /* ~VT_LVAL */
127 #define VT_FORWARD 0x0020 /* value is forward reference
128 (only used for functions) */
132 #define VT_VOID 0x00040
133 #define VT_BYTE 0x00080 /* signed byte type */
134 #define VT_PTR 0x00100 /* pointer increment */
135 #define VT_UNSIGNED 0x00200 /* unsigned type */
136 #define VT_ARRAY 0x00400 /* array type (only used in parsing) */
137 #define VT_ENUM 0x00800 /* enum definition */
138 #define VT_FUNC 0x01000 /* function type */
139 #define VT_STRUCT 0x002000 /* struct/union definition */
140 #define VT_TYPEDEF 0x004000 /* typedef definition */
141 #define VT_EXTERN 0x008000 /* extern definition */
142 #define VT_STATIC 0x010000 /* static variable */
143 #define VT_SHORT 0x020000 /* short type */
144 #define VT_STRUCT_SHIFT 18 /* structure/enum name shift (14 bits left) */
146 #define VT_TYPE 0xffffffc0 /* type mask */
147 #define VT_TYPEN 0x0000003f /* ~VT_TYPE */
148 #define VT_FUNCN -4097 /* ~VT_FUNC */
152 /* warning: the following compare tokens depend on i386 asm code */
164 #define TOK_LAND 0xa0
168 #define TOK_MID 0xa3 /* inc/dec, to void constant */
170 #define TOK_ARROW 0xa7
171 #define TOK_DOTS 0xa8 /* three dots */
172 #define TOK_SHR 0xa9 /* unsigned shift right */
173 #define TOK_UDIV 0xb0 /* unsigned division */
174 #define TOK_UMOD 0xb1 /* unsigned modulo */
175 #define TOK_PDIV 0xb2 /* fast division with undefined rounding for pointers */
176 #define TOK_NUM 0xb3 /* number in tokc */
177 #define TOK_CCHAR 0xb4 /* char constant in tokc */
178 #define TOK_STR 0xb5 /* pointer to string in tokc */
179 #define TOK_TWOSHARPS 0xb6 /* ## preprocessing token */
180 #define TOK_LCHAR 0xb7
181 #define TOK_LSTR 0xb8
183 #define TOK_SHL 0x01 /* shift left */
184 #define TOK_SAR 0x02 /* signed shift right */
186 /* assignement operators : normal operator or 0x80 */
187 #define TOK_A_MOD 0xa5
188 #define TOK_A_AND 0xa6
189 #define TOK_A_MUL 0xaa
190 #define TOK_A_ADD 0xab
191 #define TOK_A_SUB 0xad
192 #define TOK_A_DIV 0xaf
193 #define TOK_A_XOR 0xde
194 #define TOK_A_OR 0xfc
195 #define TOK_A_SHL 0x81
196 #define TOK_A_SAR 0x82
198 /* all identificators and strings have token above that */
199 #define TOK_IDENT 256
220 /* ignored types Must have contiguous values */
230 /* unsupported type */
242 /* preprocessor only */
259 /* special identifiers */
271 void decl_initializer(int t
, int c
, int first
, int size_only
);
272 int decl_initializer_alloc(int t
, int has_init
);
276 void macro_subst(int **tok_str
, int *tok_len
,
277 Sym
**nested_list
, int *macro_str
);
278 int save_reg_forced(int r
);
279 int type_size(int t
, int *a
);
280 int pointed_type(int t
);
281 int pointed_size(int t
);
283 int type_decl(int *v
, int t
, int td
);
286 /* dummy function for profiling */
287 void *dlopen(const char *filename
, int flag
)
291 const char *dlerror(void)
296 void *dlsym(void *handle
, char *symbol
)
305 return (c
>= 'a' && c
<= 'z') ||
306 (c
>= 'A' && c
<= 'Z') ||
312 return c
>= '0' & c
<= '9';
318 for(f
= include_stack
; f
< include_stack_ptr
; f
++)
319 fprintf(stderr
, "In file included from %s:%d:\n",
320 f
->filename
, f
->line_num
);
321 fprintf(stderr
, "%s:%d: ", filename
, line_num
);
324 void error(const char *fmt
, ...)
329 vfprintf(stderr
, fmt
, ap
);
330 fprintf(stderr
, "\n");
335 void expect(const char *msg
)
337 error("%s expected", msg
);
340 void warning(const char *msg
)
343 fprintf(stderr
, "warning: %s\n", msg
);
349 error("'%c' expected", c
);
359 TokenSym
*tok_alloc(char *str
, int len
)
361 TokenSym
*ts
, **pts
, **ptable
;
368 h
= ((h
<< 8) | (str
[i
] & 0xff)) % TOK_HASH_SIZE
;
370 pts
= &hash_ident
[h
];
375 if (ts
->len
== len
&& !memcmp(ts
->str
, str
, len
))
377 pts
= &(ts
->hash_next
);
379 /* expand token table if needed */
380 i
= tok_ident
- TOK_IDENT
;
381 if ((i
% TOK_ALLOC_INCR
) == 0) {
382 ptable
= realloc(table_ident
, (i
+ TOK_ALLOC_INCR
) * sizeof(TokenSym
*));
384 error("memory full");
385 table_ident
= ptable
;
387 ts
= malloc(sizeof(TokenSym
) + len
);
389 error("memory full");
391 ts
->tok
= tok_ident
++;
393 ts
->hash_next
= NULL
;
394 memcpy(ts
->str
, str
, len
+ 1);
399 void add_char(char **pp
, int c
)
403 if (c
== '\'' || c
== '\"' || c
== '\\') {
404 /* XXX: could be more precise if char or string */
407 if (c
>= 32 && c
<= 126) {
414 *p
++ = '0' + ((c
>> 6) & 7);
415 *p
++ = '0' + ((c
>> 3) & 7);
416 *p
++ = '0' + (c
& 7);
422 /* XXX: buffer overflow */
423 char *get_tok_str(int v
, int c
)
425 static char buf
[STRING_MAX_SIZE
+ 1];
431 sprintf(buf
, "%d", c
);
433 } else if (v
== TOK_CCHAR
|| v
== TOK_LCHAR
) {
440 } else if (v
== TOK_STR
|| v
== TOK_LSTR
) {
444 for(i
=0;i
<ts
->len
;i
++)
445 add_char(&p
, ts
->str
[i
]);
449 } else if (v
< TOK_IDENT
) {
454 } else if (v
< tok_ident
) {
455 return table_ident
[v
- TOK_IDENT
]->str
;
457 /* should never happen */
462 /* push, without hashing */
463 Sym
*sym_push2(Sym
**ps
, int v
, int t
, int c
)
466 s
= malloc(sizeof(Sym
));
468 error("memory full");
479 /* find a symbol and return its associated structure. 's' is the top
480 of the symbol stack */
481 Sym
*sym_find2(Sym
*s
, int v
)
491 /* find a symbol and return its associated structure. 'st' is the
493 Sym
*sym_find1(SymStack
*st
, int v
)
497 s
= st
->hash
[v
% SYM_HASH_SIZE
];
506 Sym
*sym_push1(SymStack
*st
, int v
, int t
, int c
)
509 s
= sym_push2(&st
->top
, v
, t
, c
);
510 /* add in hash table */
511 ps
= &st
->hash
[s
->v
% SYM_HASH_SIZE
];
517 /* find a symbol in the right symbol space */
521 s
= sym_find1(&local_stack
, v
);
523 s
= sym_find1(&global_stack
, v
);
527 /* push a given symbol on the symbol stack */
528 Sym
*sym_push(int v
, int t
, int c
)
531 return sym_push1(&local_stack
, v
, t
, c
);
533 return sym_push1(&global_stack
, v
, t
, c
);
536 /* pop symbols until top reaches 'b' */
537 void sym_pop(SymStack
*st
, Sym
*b
)
544 /* free hash table entry */
545 st
->hash
[s
->v
% SYM_HASH_SIZE
] = s
->hash_next
;
554 /* read next char from current input file */
560 if (include_stack_ptr
== include_stack
)
562 /* pop include stack */
566 file
= include_stack_ptr
->file
;
567 filename
= include_stack_ptr
->filename
;
568 line_num
= include_stack_ptr
->line_num
;
573 // printf("ch1=%c 0x%x\n", ch1, ch1);
576 /* input with '\\n' handling */
582 if (ch
== '\\' && ch1
== '\n') {
586 //printf("ch=%c 0x%x\n", ch, ch);
589 /* same as minp, but also skip comments */
597 /* single line C++ comments */
599 while (ch1
!= '\n' && ch1
!= -1)
602 ch
= ' '; /* return space */
603 } else if (ch1
== '*') {
609 if (c
== '*' && ch1
== '/') {
611 ch
= ' '; /* return space */
625 while (ch
== ' ' || ch
== '\t')
629 /* skip block of text until #else, #elif or #endif. skip also pairs of
631 void preprocess_skip()
647 (tok
== TOK_ELSE
|| tok
== TOK_ELIF
|| tok
== TOK_ENDIF
))
649 if (tok
== TOK_IF
|| tok
== TOK_IFDEF
|| tok
== TOK_IFNDEF
)
651 else if (tok
== TOK_ENDIF
)
657 inline int is_long_tok(int t
)
659 return (t
== TOK_NUM
||
660 t
== TOK_CCHAR
|| t
== TOK_LCHAR
||
661 t
== TOK_STR
|| t
== TOK_LSTR
);
664 void tok_add(int **tok_str
, int *tok_len
, int t
)
669 if ((len
& 63) == 0) {
670 str
= realloc(str
, (len
+ 64) * sizeof(int));
679 void tok_add2(int **tok_str
, int *tok_len
, int t
, int c
)
681 tok_add(tok_str
, tok_len
, t
);
683 tok_add(tok_str
, tok_len
, c
);
686 /* eval an expression for #if/#elif */
687 int expr_preprocess()
697 next(); /* do macro subst */
698 if (tok
== TOK_DEFINED
) {
703 c
= sym_find1(&define_stack
, tok
) != 0;
708 } else if (tok
>= TOK_IDENT
) {
709 /* if undefined macro */
713 tok_add2(&str
, &len
, tok
, tokc
);
715 tok_add(&str
, &len
, -1); /* simulate end of file */
716 tok_add(&str
, &len
, 0);
717 /* now evaluate C constant expression */
727 void tok_print(int *str
)
738 printf(" %s", get_tok_str(t
, c
));
744 /* XXX: should be more factorized */
745 void define_symbol(char *sym
)
750 ts
= tok_alloc(sym
, 0);
753 tok_add2(&str
, &len
, TOK_NUM
, 1);
754 tok_add(&str
, &len
, 0);
755 sym_push1(&define_stack
, ts
->tok
, MACRO_OBJ
, (int)str
);
760 int size
, i
, c
, v
, t
, *str
, len
;
761 char buf
[1024], *q
, *p
;
764 Sym
**ps
, *first
, *s
;
769 if (tok
== TOK_DEFINE
) {
772 /* XXX: should check if same macro (ANSI) */
775 /* '(' must be just after macro definition for MACRO_FUNC */
782 tok
= TOK___VA_ARGS__
;
783 s
= sym_push1(&define_stack
, tok
| SYM_FIELD
, 0, 0);
797 if (ch
== '\n' || ch
== -1)
800 tok_add2(&str
, &len
, tok
, tokc
);
802 tok_add(&str
, &len
, 0);
804 printf("define %s %d: ", get_tok_str(v
, 0), t
);
807 s
= sym_push1(&define_stack
, v
, t
, (int)str
);
809 } else if (tok
== TOK_UNDEF
) {
811 s
= sym_find1(&define_stack
, tok
);
812 /* undefine symbol by putting an invalid name */
815 } else if (tok
== TOK_INCLUDE
) {
820 } else if (ch
== '\"') {
825 while (ch
!= c
&& ch
!= '\n' && ch
!= -1) {
826 if ((q
- buf
) < sizeof(buf
) - 1)
834 error("#include syntax error");
835 /* XXX: buffer overflow */
836 strcpy(buf
, get_tok_str(tok
, tokc
));
839 if (include_stack_ptr
>= include_stack
+ INCLUDE_STACK_SIZE
)
840 error("memory full");
842 /* first search in current dir if "header.h" */
843 /* XXX: buffer overflow */
845 p
= strrchr(filename
, '/');
847 size
= p
+ 1 - filename
;
848 memcpy(buf1
, filename
, size
);
851 f
= fopen(buf1
, "r");
855 /* now search in standard include path */
856 for(i
=nb_include_paths
- 1;i
>=0;i
--) {
857 strcpy(buf1
, include_paths
[i
]);
860 f
= fopen(buf1
, "r");
864 error("include file not found");
867 /* push current file in stack */
868 /* XXX: fix current line init */
869 include_stack_ptr
->file
= file
;
870 include_stack_ptr
->filename
= filename
;
871 include_stack_ptr
->line_num
= line_num
;
874 filename
= strdup(buf1
);
876 } else if (tok
== TOK_IFNDEF
) {
879 } else if (tok
== TOK_IF
) {
880 c
= expr_preprocess();
882 } else if (tok
== TOK_IFDEF
) {
886 c
= (sym_find1(&define_stack
, tok
) != 0) ^ c
;
888 if (ifdef_stack_ptr
>= ifdef_stack
+ IFDEF_STACK_SIZE
)
889 error("memory full");
890 *ifdef_stack_ptr
++ = c
;
892 } else if (tok
== TOK_ELSE
) {
893 if (ifdef_stack_ptr
== ifdef_stack
||
894 (ifdef_stack_ptr
[-1] & 2))
895 error("#else after #else");
896 c
= (ifdef_stack_ptr
[-1] ^= 3);
898 } else if (tok
== TOK_ELIF
) {
899 if (ifdef_stack_ptr
== ifdef_stack
||
900 ifdef_stack_ptr
[-1] > 1)
901 error("#elif after #else");
902 c
= expr_preprocess();
903 ifdef_stack_ptr
[-1] = c
;
909 } else if (tok
== TOK_ENDIF
) {
910 if (ifdef_stack_ptr
== ifdef_stack
)
913 } else if (tok
== TOK_LINE
) {
923 /* XXX: potential memory leak */
924 filename
= strdup(get_tok_str(tok
, tokc
));
926 } else if (tok
== TOK_ERROR
) {
929 /* ignore other preprocess commands or #! for C scripts */
930 while (ch
!= '\n' && ch
!= -1)
934 /* read a number in base b */
940 if (ch
>= 'a' & ch
<= 'f')
942 else if (ch
>= 'A' & ch
<= 'F')
956 /* read a character for string or char constant and eval escape codes */
965 /* at most three octal digits */
969 c
= c
* 8 + ch
- '0';
972 c
= c
* 8 + ch
- '0';
977 } else if (ch
== 'x') {
1003 /* return next token without macro substitution */
1004 void next_nomacro1()
1012 while (ch
== '\n') {
1014 while (ch
== ' ' || ch
== 9)
1017 /* preprocessor command if # at start of line after
1022 if (ch
!= ' ' && ch
!= '\t' && ch
!= '\f')
1031 /* XXX: not supported entirely (needs different
1032 preprocessor architecture) */
1042 while (isid(ch
) | isnum(ch
)) {
1043 if (q
>= token_buf
+ STRING_MAX_SIZE
)
1044 error("ident too long");
1049 ts
= tok_alloc(token_buf
, q
- token_buf
);
1051 } else if (isnum(ch
)) {
1057 if (ch
== 'x' || ch
== 'X') {
1060 } else if (ch
== 'b' || ch
== 'B') {
1066 /* XXX: add unsigned constant support (ANSI) */
1067 while (ch
== 'L' || ch
== 'l' || ch
== 'U' || ch
== 'u')
1070 } else if (ch
== '\'') {
1078 } else if (ch
== '\"') {
1083 while (ch
!= '\"') {
1086 error("unterminated string");
1087 if (q
>= token_buf
+ STRING_MAX_SIZE
)
1088 error("string too long");
1092 tokc
= (int)tok_alloc(token_buf
, q
- token_buf
);
1095 q
= "<=\236>=\235!=\225&&\240||\241++\244--\242==\224<<\1>>\2+=\253-=\255*=\252/=\257%=\245&=\246^=\336|=\374->\247..\250##\266";
1100 if (*q
== tok
& q
[1] == ch
) {
1103 /* three chars tests */
1104 if (tok
== TOK_SHL
| tok
== TOK_SAR
) {
1109 } else if (tok
== TOK_DOTS
) {
1111 error("parse error");
1118 /* single char substitutions */
1121 else if (tok
== '>')
1126 /* return next token without macro substitution. Can read input from
1134 if (is_long_tok(tok
))
1135 tokc
= *macro_ptr
++;
1142 /* substitute args in macro_str and return allocated string */
1143 int *macro_arg_subst(Sym
**nested_list
, int *macro_str
, Sym
*args
)
1145 int *st
, last_tok
, t
, c
, notfirst
, *str
, len
;
1161 s
= sym_find2(args
, t
);
1163 token_buf
[0] = '\0';
1165 /* XXX: buffer overflow */
1169 strcat(token_buf
, " ");
1174 strcat(token_buf
, get_tok_str(t
, c
));
1178 printf("stringize: %s\n", token_buf
);
1181 ts
= tok_alloc(token_buf
, 0);
1182 tok_add2(&str
, &len
, TOK_STR
, (int)ts
);
1184 tok_add(&str
, &len
, t
);
1186 } else if (is_long_tok(t
)) {
1187 tok_add2(&str
, &len
, t
, *macro_str
++);
1189 s
= sym_find2(args
, t
);
1192 /* if '##' is present before or after , no arg substitution */
1193 if (*macro_str
== TOK_TWOSHARPS
|| last_tok
== TOK_TWOSHARPS
) {
1195 tok_add(&str
, &len
, *st
++);
1197 macro_subst(&str
, &len
, nested_list
, st
);
1200 tok_add(&str
, &len
, t
);
1205 tok_add(&str
, &len
, 0);
1209 /* handle the '##' operator */
1210 int *macro_twosharps(int *macro_str
)
1213 int *macro_str1
, macro_str1_len
, *macro_ptr1
;
1224 if (*macro_ptr
== TOK_TWOSHARPS
) {
1226 macro_ptr1
= macro_ptr
;
1233 /* XXX: we handle only most common cases:
1234 ident + ident or ident + number */
1235 if (tok
>= TOK_IDENT
&&
1236 (t
>= TOK_IDENT
|| t
== TOK_NUM
)) {
1237 /* XXX: buffer overflow */
1238 p
= get_tok_str(tok
, tokc
);
1239 strcpy(token_buf
, p
);
1240 p
= get_tok_str(t
, c
);
1241 strcat(token_buf
, p
);
1242 ts
= tok_alloc(token_buf
, 0);
1243 tok_add2(¯o_str1
, ¯o_str1_len
, ts
->tok
, 0);
1245 /* cannot merge tokens: skip '##' */
1246 macro_ptr
= macro_ptr1
;
1250 tok_add2(¯o_str1
, ¯o_str1_len
, tok
, tokc
);
1253 tok_add(¯o_str1
, ¯o_str1_len
, 0);
1259 /* do macro substitution of macro_str and add result to
1260 (tok_str,tok_len). If macro_str is NULL, then input stream token is
1261 substituted. 'nested_list' is the list of all macros we got inside
1262 to avoid recursing. */
1263 void macro_subst(int **tok_str
, int *tok_len
,
1264 Sym
**nested_list
, int *macro_str
)
1266 Sym
*s
, *args
, *sa
, *sa1
;
1267 int *str
, parlevel
, len
, *mstr
, t
, *saved_macro_ptr
;
1268 int mstr_allocated
, *macro_str1
;
1270 saved_macro_ptr
= macro_ptr
;
1271 macro_ptr
= macro_str
;
1274 /* first scan for '##' operator handling */
1275 macro_str1
= macro_twosharps(macro_str
);
1276 macro_ptr
= macro_str1
;
1283 /* special macros */
1284 if (tok
== TOK___LINE__
) {
1285 tok_add2(tok_str
, tok_len
, TOK_NUM
, line_num
);
1286 } else if (tok
== TOK___FILE__
) {
1287 tok_add2(tok_str
, tok_len
, TOK_STR
,
1288 (int)tok_alloc(filename
, 0));
1289 } else if (tok
== TOK___DATE__
) {
1290 tok_add2(tok_str
, tok_len
, TOK_STR
,
1291 (int)tok_alloc("Jan 1 1970", 0));
1292 } else if (tok
== TOK___TIME__
) {
1293 tok_add2(tok_str
, tok_len
, TOK_STR
,
1294 (int)tok_alloc("00:00:00", 0));
1295 } else if ((s
= sym_find1(&define_stack
, tok
)) != NULL
) {
1296 /* if symbol is a macro, prepare substitution */
1297 /* if nested substitution, do nothing */
1298 if (sym_find2(*nested_list
, tok
))
1302 if (s
->t
== MACRO_FUNC
) {
1303 /* NOTE: we do not use next_nomacro to avoid eating the
1304 next token. XXX: find better solution */
1308 while (ch
== ' ' || ch
== '\t' || ch
== '\n')
1312 if (t
!= '(') /* no macro subst */
1315 /* argument macro */
1320 while (tok
!= ')' && sa
) {
1324 while ((parlevel
> 0 ||
1327 sa
->v
== (TOK___VA_ARGS__
| SYM_FIELD
)))) &&
1331 else if (tok
== ')')
1333 tok_add2(&str
, &len
, tok
, tokc
);
1336 tok_add(&str
, &len
, 0);
1337 sym_push2(&args
, sa
->v
& ~SYM_FIELD
, 0, (int)str
);
1345 /* now subst each arg */
1346 mstr
= macro_arg_subst(nested_list
, mstr
, args
);
1357 sym_push2(nested_list
, s
->v
, 0, 0);
1358 macro_subst(tok_str
, tok_len
, nested_list
, mstr
);
1359 /* pop nested defined symbol */
1361 *nested_list
= sa1
->prev
;
1367 /* no need to add if reading input stream */
1370 tok_add2(tok_str
, tok_len
, tok
, tokc
);
1372 /* only replace one macro while parsing input stream */
1376 macro_ptr
= saved_macro_ptr
;
1381 /* return next token with macro substitution */
1387 /* special 'ungettok' case for label parsing */
1394 /* if not reading from macro substuted string, then try to substitute */
1398 macro_subst(&ptr
, &len
, &nested_list
, NULL
);
1400 tok_add(&ptr
, &len
, 0);
1402 macro_ptr_allocated
= ptr
;
1410 /* end of macro string: free it */
1411 free(macro_ptr_allocated
);
1418 printf("token = %s\n", get_tok_str(tok
, tokc
));
1422 void swap(int *p
, int *q
)
1436 /******************************************************/
1437 /* X86 code generator */
1452 /* output a symbol and patch all calls to it */
1453 void gsym_addr(t
, a
)
1457 n
= *(int *)t
; /* next value */
1458 *(int *)t
= a
- t
- 4;
1468 /* psym is used to put an instruction with a data field which is a
1469 reference to a symbol. It is in fact the same as oad ! */
1472 /* instruction + 4 bytes data. Return the address of the data */
1482 /* XXX: generate correct pointer for forward references to functions */
1484 void load(r
, ft
, fc
)
1488 v
= ft
& VT_VALMASK
;
1490 if (v
== VT_LLOCAL
) {
1491 load(r
, VT_LOCAL
| VT_LVAL
, fc
);
1494 if ((ft
& VT_TYPE
) == VT_BYTE
)
1495 o(0xbe0f); /* movsbl */
1496 else if ((ft
& VT_TYPE
) == (VT_BYTE
| VT_UNSIGNED
))
1497 o(0xb60f); /* movzbl */
1498 else if ((ft
& VT_TYPE
) == VT_SHORT
)
1499 o(0xbf0f); /* movswl */
1500 else if ((ft
& VT_TYPE
) == (VT_SHORT
| VT_UNSIGNED
))
1501 o(0xb70f); /* movzwl */
1504 if (v
== VT_CONST
) {
1505 oad(0x05 + r
* 8, fc
); /* 0xXX, r */
1506 } else if (v
== VT_LOCAL
) {
1507 oad(0x85 + r
* 8, fc
); /* xx(%ebp), r */
1509 g(0x00 + r
* 8 + v
); /* (v), r */
1512 if (v
== VT_CONST
) {
1513 oad(0xb8 + r
, fc
); /* mov $xx, r */
1514 } else if (v
== VT_LOCAL
) {
1516 oad(0x85 + r
* 8, fc
); /* lea xxx(%ebp), r */
1517 } else if (v
== VT_CMP
) {
1518 oad(0xb8 + r
, 0); /* mov $0, r */
1519 o(0x0f); /* setxx %br */
1522 } else if (v
== VT_JMP
|| v
== VT_JMPI
) {
1524 oad(0xb8 + r
, t
); /* mov $1, r */
1525 oad(0xe9, 5); /* jmp after */
1527 oad(0xb8 + r
, t
^ 1); /* mov $0, r */
1528 } else if (v
!= r
) {
1530 o(0xc0 + r
+ v
* 8); /* mov v, r */
1536 /* WARNING: r must not be allocated on the stack */
1537 void store(r
, ft
, fc
)
1541 fr
= ft
& VT_VALMASK
;
1542 b
= (ft
& VT_TYPE
) == VT_BYTE
;
1543 /* XXX: incorrect if reg to reg */
1547 if (fr
== VT_CONST
) {
1548 oad(0x05 + r
* 8, fc
); /* mov r,xxx */
1549 } else if (fr
== VT_LOCAL
) {
1550 oad(0x85 + r
* 8, fc
); /* mov r,xxx(%ebp) */
1551 } else if (ft
& VT_LVAL
) {
1552 g(fr
+ r
* 8); /* mov r, (fr) */
1553 } else if (fr
!= r
) {
1554 o(0xc0 + fr
+ r
* 8); /* mov r, fr */
1558 void gfunc_param(void)
1560 o(0x50 + gv()); /* push r */
1565 return psym(0xe9, t
);
1568 /* generate a test. set 'inv' to invert test */
1572 v
= vt
& VT_VALMASK
;
1574 /* fast case : can jump directly since flags are set */
1576 t
= psym((vc
- 16) ^ inv
, t
);
1577 } else if (v
== VT_JMP
|| v
== VT_JMPI
) {
1578 /* && or || optimization */
1579 if ((v
& 1) == inv
) {
1580 /* insert vc jump list in t */
1590 } else if ((vt
& (VT_VALMASK
| VT_LVAL
)) == VT_CONST
) {
1591 /* constant jmp optimization */
1592 if ((vc
!= 0) != inv
)
1599 t
= psym(0x85 ^ inv
, t
);
1604 /* generate a binary operation 'v = r op fr' instruction and modifies
1605 (vt,vc) if needed */
1606 void gen_op1(op
, r
, fr
)
1611 o(0xc0 + r
+ fr
* 8);
1612 } else if (op
== '-') {
1614 o(0xc0 + r
+ fr
* 8);
1615 } else if (op
== '&') {
1617 o(0xc0 + r
+ fr
* 8);
1618 } else if (op
== '^') {
1620 o(0xc0 + r
+ fr
* 8);
1621 } else if (op
== '|') {
1623 o(0xc0 + r
+ fr
* 8);
1624 } else if (op
== '*') {
1625 o(0xaf0f); /* imul fr, r */
1626 o(0xc0 + fr
+ r
* 8);
1627 } else if (op
== TOK_SHL
| op
== TOK_SHR
| op
== TOK_SAR
) {
1633 o(0x87); /* xchg r, %ecx */
1638 o(0xd3); /* shl/shr/sar %cl, r */
1641 else if (op
== TOK_SHR
)
1645 vt
= (vt
& VT_TYPE
) | r
;
1646 } else if (op
== '/' | op
== TOK_UDIV
| op
== TOK_PDIV
|
1647 op
== '%' | op
== TOK_UMOD
) {
1648 save_reg(2); /* save edx */
1649 t
= save_reg_forced(fr
); /* save fr and get op2 location */
1650 move_reg(0, r
); /* op1 is %eax */
1651 if (op
== TOK_UDIV
| op
== TOK_UMOD
) {
1652 o(0xf7d231); /* xor %edx, %edx, div t(%ebp), %eax */
1655 o(0xf799); /* cltd, idiv t(%ebp), %eax */
1658 if (op
== '%' | op
== TOK_UMOD
)
1662 vt
= (vt
& VT_TYPE
) | r
;
1665 o(0xc0 + r
+ fr
* 8); /* cmp fr, r */
1670 /* end of X86 code generator */
1671 /*************************************************************/
1673 int save_reg_forced(int r
)
1676 /* store register */
1677 loc
= (loc
- 4) & -3;
1678 store(r
, VT_LOCAL
, loc
);
1681 /* modify all stack values */
1682 for(p
=vstack
;p
<vstack_ptr
;p
+=2) {
1683 i
= p
[0] & VT_VALMASK
;
1689 p
[0] = (p
[0] & VT_TYPE
) | VT_LVAL
| t
;
1696 /* save r to memory. and mark it as being free */
1701 /* modify all stack values */
1702 for(p
=vstack
;p
<vstack_ptr
;p
+=2) {
1703 i
= p
[0] & VT_VALMASK
;
1711 /* find a free register. If none, save one register */
1716 /* find a free register */
1717 for(r
=0;r
<NB_REGS
;r
++) {
1718 for(p
=vstack
;p
<vstack_ptr
;p
+=2) {
1719 i
= p
[0] & VT_VALMASK
;
1727 /* no register left : free the first one on the stack (very
1728 important to start from the bottom to ensure that we don't
1729 spill registers used in gen_op()) */
1730 for(p
=vstack
;p
<vstack_ptr
;p
+=2) {
1731 r
= p
[0] & VT_VALMASK
;
1743 for(p
=vstack
;p
<vstack_ptr
;p
+=2) {
1744 r
= p
[0] & VT_VALMASK
;
1751 /* move register 's' to 'r', and flush previous value of r to memory
1761 /* convert a stack entry in register */
1765 r
= p
[0] & VT_VALMASK
;
1766 if (r
>= VT_CONST
|| (p
[0] & VT_LVAL
))
1768 load(r
, p
[0], p
[1]);
1769 p
[0] = (p
[0] & VT_TYPE
) | r
;
1775 if (vstack_ptr
>= vstack
+ VSTACK_SIZE
)
1776 error("memory full");
1779 /* cannot let cpu flags if other instruction are generated */
1780 if ((vt
& VT_VALMASK
) == VT_CMP
)
1781 gvp(vstack_ptr
- 2);
1784 void vpop(int *ft
, int *fc
)
1786 *fc
= *--vstack_ptr
;
1787 *ft
= *--vstack_ptr
;
1790 /* generate a value in a register from vt and vc */
1795 r
= gvp(vstack_ptr
- 2);
1800 /* handle constant optimizations and various machine independant opt */
1803 int fr
, ft
, fc
, r
, c1
, c2
, n
;
1807 c1
= (vt
& (VT_VALMASK
| VT_LVAL
)) == VT_CONST
;
1808 c2
= (ft
& (VT_VALMASK
| VT_LVAL
)) == VT_CONST
;
1811 case '+': vc
+= fc
; break;
1812 case '-': vc
-= fc
; break;
1813 case '&': vc
&= fc
; break;
1814 case '^': vc
^= fc
; break;
1815 case '|': vc
|= fc
; break;
1816 case '*': vc
*= fc
; break;
1818 case '/': vc
/= fc
; break; /* XXX: zero case ? */
1819 case '%': vc
%= fc
; break; /* XXX: zero case ? */
1820 case TOK_UDIV
: vc
= (unsigned)vc
/ fc
; break; /* XXX: zero case ? */
1821 case TOK_UMOD
: vc
= (unsigned)vc
% fc
; break; /* XXX: zero case ? */
1822 case TOK_SHL
: vc
<<= fc
; break;
1823 case TOK_SHR
: vc
= (unsigned)vc
>> fc
; break;
1824 case TOK_SAR
: vc
>>= fc
; break;
1826 case TOK_ULT
: vc
= (unsigned)vc
< (unsigned)fc
; break;
1827 case TOK_UGE
: vc
= (unsigned)vc
>= (unsigned)fc
; break;
1828 case TOK_EQ
: vc
= vc
== fc
; break;
1829 case TOK_NE
: vc
= vc
!= fc
; break;
1830 case TOK_ULE
: vc
= (unsigned)vc
<= (unsigned)fc
; break;
1831 case TOK_UGT
: vc
= (unsigned)vc
> (unsigned)fc
; break;
1832 case TOK_LT
: vc
= vc
< fc
; break;
1833 case TOK_GE
: vc
= vc
>= fc
; break;
1834 case TOK_LE
: vc
= vc
<= fc
; break;
1835 case TOK_GT
: vc
= vc
> fc
; break;
1837 case TOK_LAND
: vc
= vc
&& fc
; break;
1838 case TOK_LOR
: vc
= vc
|| fc
; break;
1843 /* if commutative ops, put c2 as constant */
1844 if (c1
&& (op
== '+' || op
== '&' || op
== '^' ||
1845 op
== '|' || op
== '*')) {
1850 if (c2
&& (((op
== '*' || op
== '/' || op
== TOK_UDIV
||
1853 ((op
== '+' || op
== '-' || op
== '|' || op
== '^' ||
1854 op
== TOK_SHL
|| op
== TOK_SHR
|| op
== TOK_SAR
) &&
1858 } else if (c2
&& (op
== '*' || op
== TOK_PDIV
|| op
== TOK_UDIV
)) {
1859 /* try to use shifts instead of muls or divs */
1860 if (fc
> 0 && (fc
& (fc
- 1)) == 0) {
1869 else if (op
== TOK_PDIV
)
1881 r
= gvp(vstack_ptr
- 4);
1882 fr
= gvp(vstack_ptr
- 2);
1885 /* call low level op generator */
1891 int pointed_size(int t
)
1893 return type_size(pointed_type(t
), &t
);
1896 /* generic gen_op: handles types problems */
1902 t1
= vstack_ptr
[-4];
1903 t2
= vstack_ptr
[-2];
1904 if (op
== '+' | op
== '-') {
1905 if ((t1
& VT_PTR
) && (t2
& VT_PTR
)) {
1907 error("invalid type");
1908 /* XXX: check that types are compatible */
1909 u
= pointed_size(t1
);
1912 vstack_ptr
[-2] &= ~VT_TYPE
; /* set to integer */
1915 } else if ((t1
| t2
) & VT_PTR
) {
1917 swap(vstack_ptr
- 4, vstack_ptr
- 2);
1918 swap(vstack_ptr
- 3, vstack_ptr
- 1);
1921 /* stack-4 contains pointer, stack-2 value to add */
1922 vset(VT_CONST
, pointed_size(vstack_ptr
[-4]));
1926 /* put again type if gen_opc() swaped operands */
1927 vt
= (vt
& VT_TYPEN
) | (t1
& VT_TYPE
);
1932 /* XXX: test types and compute returned value */
1933 if ((t1
| t2
) & (VT_UNSIGNED
| VT_PTR
)) {
1940 else if (op
== TOK_LT
)
1942 else if (op
== TOK_GT
)
1944 else if (op
== TOK_LE
)
1946 else if (op
== TOK_GE
)
1953 /* return type size. Put alignment at 'a' */
1954 int type_size(int t
, int *a
)
1958 /* int, enum or pointer */
1959 if (t
& VT_STRUCT
) {
1961 s
= sym_find(((unsigned)t
>> VT_STRUCT_SHIFT
) | SYM_STRUCT
);
1962 *a
= 4; /* XXX: cannot store it yet. Doing that is safe */
1964 } else if (t
& VT_ARRAY
) {
1965 s
= sym_find(((unsigned)t
>> VT_STRUCT_SHIFT
));
1966 return type_size(s
->t
, a
) * s
->c
;
1967 } else if ((t
& VT_PTR
) |
1968 (t
& VT_TYPE
) == 0 |
1972 } else if (t
& VT_SHORT
) {
1981 /* return the pointed type of t */
1982 int pointed_type(int t
)
1985 s
= sym_find(((unsigned)t
>> VT_STRUCT_SHIFT
));
1986 return s
->t
| (t
& VT_TYPEN
);
1989 int mk_pointer(int t
)
1994 return VT_PTR
| (p
<< VT_STRUCT_SHIFT
) | (t
& VT_TYPEN
);
1997 /* store value in lvalue pushed on stack */
2002 r
= gv(); /* generate value */
2004 ft
= vstack_ptr
[-4];
2005 fc
= vstack_ptr
[-3];
2006 if ((ft
& VT_VALMASK
) == VT_LLOCAL
) {
2008 load(t
, VT_LOCAL
| VT_LVAL
, fc
);
2009 ft
= (ft
& ~VT_VALMASK
) | t
;
2015 /* post defines POST/PRE add. c is the token ++ or -- */
2021 vpush(); /* room for returned value */
2022 vpush(); /* save lvalue */
2024 vpush(); /* save value */
2026 /* duplicate value */
2028 load(r1
, r
, 0); /* move r to r1 */
2029 vstack_ptr
[-6] = (vt
& VT_TYPE
) | r1
;
2033 vset(VT_CONST
, c
- TOK_MID
);
2035 vstore(); /* store value */
2040 /* enum/struct/union declaration */
2043 int a
, t
, b
, v
, size
, align
, maxalign
, c
;
2046 a
= tok
; /* save decl type */
2051 /* struct already defined ? return it */
2052 /* XXX: check consistency */
2053 if (s
= sym_find(v
| SYM_STRUCT
)) {
2055 error("invalid type");
2061 s
= sym_push(v
| SYM_STRUCT
, a
, 0);
2062 /* put struct/union/enum name in type */
2064 u
= u
| (v
<< VT_STRUCT_SHIFT
);
2069 error("struct/union/enum already defined");
2070 /* cannot be empty */
2075 if (a
== TOK_ENUM
) {
2082 sym_push(v
, VT_CONST
, c
);
2089 t
= type_decl(&v
, b
, TYPE_DIRECT
);
2090 if (t
& (VT_FUNC
| VT_TYPEDEF
))
2091 error("invalid type");
2092 /* XXX: align & correct type size */
2094 size
= type_size(t
, &align
);
2095 if (a
== TOK_STRUCT
) {
2096 c
= (c
+ align
- 1) & -align
;
2097 ss
= sym_push(v
, t
, c
);
2100 ss
= sym_push(v
, t
, 0);
2104 if (align
> maxalign
)
2108 if (tok
== ';' || tok
== -1)
2118 /* size for struct/union, dummy for enum */
2119 s
->c
= (c
+ maxalign
- 1) & -maxalign
;
2124 /* return 0 if no type declaration. otherwise, return the basic type
2126 XXX: A '2' is ored to ensure non zero return if int type.
2135 if (tok
== TOK_ENUM
) {
2136 t
|= struct_decl(VT_ENUM
);
2137 } else if (tok
== TOK_STRUCT
|| tok
== TOK_UNION
) {
2138 t
|= struct_decl(VT_STRUCT
);
2140 if (tok
== TOK_CHAR
) {
2142 } else if (tok
== TOK_VOID
) {
2144 } else if (tok
== TOK_SHORT
) {
2146 } else if (tok
== TOK_INT
|
2147 (tok
>= TOK_CONST
& tok
<= TOK_INLINE
)) {
2149 } else if (tok
== TOK_FLOAT
|| tok
== TOK_DOUBLE
) {
2150 /* We allow that to compile standard headers */
2151 // warning("floats not supported");
2152 } else if (tok
== TOK_EXTERN
) {
2154 } else if (tok
== TOK_STATIC
) {
2156 } else if (tok
== TOK_UNSIGNED
) {
2158 } else if (tok
== TOK_TYPEDEF
) {
2162 if (!s
|| !(s
->t
& VT_TYPEDEF
))
2164 t
|= (s
->t
& ~VT_TYPEDEF
);
2179 /* function declaration */
2184 while (tok
!= ')') {
2185 /* read param name and compute offset */
2186 if (l
!= FUNC_OLD
) {
2187 if (!(pt
= ist())) {
2189 error("invalid type");
2195 if (pt
& VT_VOID
&& tok
== ')')
2198 pt
= type_decl(&n
, pt
, TYPE_DIRECT
| TYPE_ABSTRACT
);
2202 pt
= 0; /* int type */
2205 /* array must be transformed to pointer according to ANSI C */
2207 /* XXX: size will be different someday */
2209 s
= sym_push(n
| SYM_FIELD
, VT_LOCAL
| VT_LVAL
| pt
, a
);
2214 if (l
== FUNC_NEW
&& tok
== TOK_DOTS
) {
2223 /* we push a anonymous symbol which will contain the function prototype */
2225 s
= sym_push(p
, t
, l
);
2227 t
= VT_FUNC
| (p
<< VT_STRUCT_SHIFT
);
2228 } else if (tok
== '[') {
2229 /* array definition */
2235 error("invalid array size");
2238 /* parse next post type */
2241 /* we push a anonymous symbol which will contain the array
2245 t
= VT_ARRAY
| VT_PTR
| (p
<< VT_STRUCT_SHIFT
);
2250 /* Read a type declaration (except basic type), and return the
2251 type. If v is true, then also put variable name in 'vc' */
2252 int type_decl(int *v
, int t
, int td
)
2257 t
= t
& -3; /* suppress the ored '2' */
2258 while (tok
== '*') {
2260 while (tok
== TOK_CONST
|| tok
== TOK_VOLATILE
|| tok
== TOK_RESTRICT
)
2265 /* recursive type */
2266 /* XXX: incorrect if abstract type for functions (e.g. 'int ()') */
2269 u
= type_decl(v
, 0, td
);
2273 /* type identifier */
2274 if (tok
>= TOK_IDENT
&& (td
& TYPE_DIRECT
)) {
2278 if (!(td
& TYPE_ABSTRACT
))
2279 expect("identifier");
2283 /* append t at the end of u */
2289 s
= sym_find((unsigned)p
>> VT_STRUCT_SHIFT
);
2299 /* define a new external reference to a function 'v' of type 'u' */
2300 Sym
*external_func(v
, u
)
2306 n
= (int)dlsym(0, get_tok_str(v
, 0));
2308 /* used to generate symbol list */
2309 s
= sym_push1(&global_stack
,
2310 v
, u
| VT_CONST
| VT_LVAL
| VT_FORWARD
, 0);
2313 s
= sym_push1(&global_stack
,
2314 v
, u
| VT_CONST
| VT_LVAL
, n
);
2326 vt
= pointed_type(vt
);
2327 if (!(vt
& VT_ARRAY
)) /* an array is never an lvalue */
2333 int n
, t
, ft
, fc
, p
, r
, align
;
2336 if (tok
== TOK_NUM
|| tok
== TOK_CCHAR
|| tok
== TOK_LCHAR
) {
2337 vset(VT_CONST
, tokc
);
2339 } else if (tok
== TOK___FUNC__
) {
2340 /* special function name identifier */
2341 /* generate (char *) type */
2342 vset(VT_CONST
| mk_pointer(VT_BYTE
), glo
);
2343 strcpy((void *)glo
, funcname
);
2344 glo
+= strlen(funcname
) + 1;
2345 } else if (tok
== TOK_LSTR
) {
2348 } else if (tok
== TOK_STR
) {
2349 /* string parsing */
2352 type_size(t
, &align
);
2353 glo
= (glo
+ align
- 1) & -align
;
2355 /* we must declare it as an array first to use initializer parser */
2356 t
= VT_CONST
| VT_ARRAY
| mk_pointer(t
);
2357 decl_initializer(t
, glo
, 1, 0);
2358 glo
+= type_size(t
, &align
);
2359 /* put it as pointer */
2360 vset(t
& ~VT_ARRAY
, fc
);
2367 ft
= type_decl(&n
, t
, TYPE_ABSTRACT
);
2369 /* check ISOC99 compound literal */
2371 /* data is allocated locally by default */
2376 /* all except arrays are lvalues */
2377 if (!(ft
& VT_ARRAY
))
2379 fc
= decl_initializer_alloc(ft
, 1);
2383 vt
= (vt
& VT_TYPEN
) | ft
;
2389 } else if (t
== '*') {
2392 } else if (t
== '&') {
2395 vt
= mk_pointer(vt
& VT_LVALN
);
2399 if ((vt
& (VT_CONST
| VT_LVAL
)) == VT_CONST
)
2401 else if ((vt
& VT_VALMASK
) == VT_CMP
)
2404 vset(VT_JMP
, gtst(1, 0));
2415 if (t
== TOK_SIZEOF
) {
2416 /* XXX: some code can be generated */
2420 vt
= type_decl(&n
, t
, TYPE_ABSTRACT
);
2427 vset(VT_CONST
, type_size(vt
, &t
));
2429 if (t
== TOK_INC
| t
== TOK_DEC
) {
2432 } else if (t
== '-') {
2442 error("'%s' undeclared", get_tok_str(t
, 0));
2443 /* for simple function calls, we tolerate undeclared
2444 external reference */
2446 sym_push1(&global_stack
, p
, 0, FUNC_OLD
);
2447 /* int() function */
2448 s
= external_func(t
, VT_FUNC
| (p
<< VT_STRUCT_SHIFT
));
2451 /* if forward reference, we must point to s->c */
2452 if (vt
& VT_FORWARD
)
2457 /* post operations */
2459 if (tok
== TOK_INC
| tok
== TOK_DEC
) {
2462 } else if (tok
== '.' | tok
== TOK_ARROW
) {
2464 if (tok
== TOK_ARROW
)
2469 /* expect pointer on structure */
2470 if (!(vt
& VT_STRUCT
))
2471 expect("struct or union");
2472 s
= sym_find(((unsigned)vt
>> VT_STRUCT_SHIFT
) | SYM_STRUCT
);
2475 while (s
= s
->next
) {
2480 error("field not found");
2481 /* add field offset to pointer */
2482 vt
= vt
& VT_TYPEN
; /* change type to int */
2484 vset(VT_CONST
, s
->c
);
2486 /* change type to field type, and set to lvalue */
2487 vt
= (vt
& VT_TYPEN
) | s
->t
;
2488 /* an array is never an lvalue */
2489 if (!(vt
& VT_ARRAY
))
2492 } else if (tok
== '[') {
2499 } else if (tok
== '(') {
2501 save_regs(); /* save used temporary registers */
2502 /* lvalue is implied */
2504 if ((vt
& VT_VALMASK
) != VT_CONST
) {
2505 /* evaluate function address */
2507 o(0x50 + r
); /* push r */
2512 #ifdef INVERT_FUNC_PARAMS
2514 int *str
, len
, parlevel
, *saved_macro_ptr
;
2517 /* read each argument and store it on a stack */
2518 /* XXX: merge it with macro args ? */
2520 while (tok
!= ')') {
2524 while ((parlevel
> 0 || (tok
!= ')' && tok
!= ',')) &&
2528 else if (tok
== ')')
2530 tok_add2(&str
, &len
, tok
, tokc
);
2533 tok_add(&str
, &len
, -1); /* end of file added */
2534 tok_add(&str
, &len
, 0);
2535 sym_push2(&args
, 0, 0, (int)str
);
2543 /* now generate code in reverse order by reading the stack */
2544 saved_macro_ptr
= macro_ptr
;
2548 macro_ptr
= (int *)args
->c
;
2553 free((int *)args
->c
);
2557 macro_ptr
= saved_macro_ptr
;
2563 while (tok
!= ')') {
2572 if ((ft
& VT_VALMASK
) == VT_CONST
) {
2573 /* forward reference */
2574 if (ft
& VT_FORWARD
) {
2575 *(int *)fc
= psym(0xe8, *(int *)fc
);
2577 oad(0xe8, fc
- ind
- 5);
2579 oad(0x2494ff, t
); /* call *xxx(%esp) */
2584 /* get return type */
2585 s
= sym_find((unsigned)ft
>> VT_STRUCT_SHIFT
);
2586 vt
= s
->t
| 0; /* return register is eax */
2599 (tok
>= TOK_A_MOD
& tok
<= TOK_A_DIV
) |
2600 tok
== TOK_A_XOR
| tok
== TOK_A_OR
|
2601 tok
== TOK_A_SHL
| tok
== TOK_A_SAR
) {
2608 /* XXX: be more precise */
2609 if ((vt
& VT_PTR
) != (vstack_ptr
[-2] & VT_PTR
))
2610 warning("incompatible type");
2628 while ((l
== 0 & (tok
== '*' | tok
== '/' | tok
== '%')) |
2629 (l
== 1 & (tok
== '+' | tok
== '-')) |
2630 (l
== 2 & (tok
== TOK_SHL
| tok
== TOK_SAR
)) |
2631 (l
== 3 & ((tok
>= TOK_ULE
& tok
<= TOK_GT
) |
2632 tok
== TOK_ULT
| tok
== TOK_UGE
)) |
2633 (l
== 4 & (tok
== TOK_EQ
| tok
== TOK_NE
)) |
2634 (l
== 5 & tok
== '&') |
2635 (l
== 6 & tok
== '^') |
2636 (l
== 7 & tok
== '|') |
2637 (l
== 8 & tok
== TOK_LAND
) |
2638 (l
== 9 & tok
== TOK_LOR
)) {
2648 /* only used if non constant */
2656 if (tok
!= TOK_LAND
) {
2676 if (tok
!= TOK_LOR
) {
2689 /* XXX: better constant handling */
2692 int t
, u
, c
, r1
, r2
;
2719 vt
= (vt
& VT_TYPE
) | r1
;
2741 if ((vt
& (VT_CONST
| VT_LVAL
)) != VT_CONST
)
2747 void block(int *bsym
, int *csym
, int *case_sym
, int *def_sym
, int case_reg
)
2752 if (tok
== TOK_IF
) {
2759 block(bsym
, csym
, case_sym
, def_sym
, case_reg
);
2761 if (c
== TOK_ELSE
) {
2765 block(bsym
, csym
, case_sym
, def_sym
, case_reg
);
2766 gsym(d
); /* patch else jmp */
2769 } else if (tok
== TOK_WHILE
) {
2777 block(&a
, &b
, case_sym
, def_sym
, case_reg
);
2778 oad(0xe9, d
- ind
- 5); /* jmp */
2781 } else if (tok
== '{') {
2784 s
= local_stack
.top
;
2785 while (tok
!= '}') {
2787 block(bsym
, csym
, case_sym
, def_sym
, case_reg
);
2789 /* pop locally defined symbols */
2790 sym_pop(&local_stack
, s
);
2792 } else if (tok
== TOK_RETURN
) {
2799 rsym
= gjmp(rsym
); /* jmp */
2800 } else if (tok
== TOK_BREAK
) {
2803 error("cannot break");
2804 *bsym
= gjmp(*bsym
);
2807 } else if (tok
== TOK_CONTINUE
) {
2810 error("cannot continue");
2811 *csym
= gjmp(*csym
);
2814 } else if (tok
== TOK_FOR
) {
2834 oad(0xe9, d
- ind
- 5); /* jmp */
2838 block(&a
, &b
, case_sym
, def_sym
, case_reg
);
2839 oad(0xe9, c
- ind
- 5); /* jmp */
2843 if (tok
== TOK_DO
) {
2848 block(&a
, &b
, case_sym
, def_sym
, case_reg
);
2858 if (tok
== TOK_SWITCH
) {
2867 block(&a
, csym
, &b
, &c
, case_reg
);
2868 /* if no default, jmp after switch */
2876 if (tok
== TOK_CASE
) {
2886 *case_sym
= gtst(1, 0);
2888 block(bsym
, csym
, case_sym
, def_sym
, case_reg
);
2890 if (tok
== TOK_DEFAULT
) {
2896 error("too many 'default'");
2898 block(bsym
, csym
, case_sym
, def_sym
, case_reg
);
2900 if (tok
== TOK_GOTO
) {
2902 s
= sym_find1(&label_stack
, tok
);
2903 /* put forward definition if needed */
2905 s
= sym_push1(&label_stack
, tok
, VT_FORWARD
, 0);
2906 /* label already defined */
2907 if (s
->t
& VT_FORWARD
)
2908 s
->c
= gjmp(s
->c
); /* jmp xxx */
2910 oad(0xe9, s
->c
- ind
- 5); /* jmp xxx */
2919 s
= sym_find1(&label_stack
, b
);
2921 if (!(s
->t
& VT_FORWARD
))
2922 error("multiple defined label");
2927 sym_push1(&label_stack
, b
, 0, ind
);
2929 block(bsym
, csym
, case_sym
, def_sym
, case_reg
);
2931 /* expression case: go backward of one token */
2932 /* XXX: currently incorrect if number/string/char */
2943 /* t is the array or struct type. c is the array or struct
2944 address. cur_index/cur_field is the pointer to the current
2945 value. 'size_only' is true if only size info is needed (only used
2947 void decl_designator(int t
, int c
,
2948 int *cur_index
, Sym
**cur_field
,
2952 int notfirst
, index
, align
;
2955 while (tok
== '[' || tok
== '.') {
2957 if (!(t
& VT_ARRAY
))
2958 expect("array type");
2959 s
= sym_find(((unsigned)t
>> VT_STRUCT_SHIFT
));
2961 index
= expr_const();
2962 if (index
< 0 || (s
->c
>= 0 && index
>= s
->c
))
2963 expect("invalid index");
2967 t
= pointed_type(t
);
2968 c
+= index
* type_size(t
, &align
);
2970 if (!(t
& VT_STRUCT
))
2971 expect("struct/union type");
2973 s
= sym_find(((unsigned)t
>> VT_STRUCT_SHIFT
) | SYM_STRUCT
);
2986 t
= f
->t
| (t
& VT_TYPEN
);
2996 t
= pointed_type(t
);
2997 c
+= index
* type_size(t
, &align
);
3001 error("too many field init");
3002 t
= f
->t
| (t
& VT_TYPEN
);
3006 decl_initializer(t
, c
, 0, size_only
);
3009 /* store a value or an expression directly in global data or in local array */
3011 void init_putv(int t
, int c
, int v
, int is_expr
)
3013 int saved_global_expr
;
3015 if ((t
& VT_VALMASK
) == VT_CONST
) {
3017 /* compound literals must be allocated globally in this case */
3018 saved_global_expr
= global_expr
;
3021 global_expr
= saved_global_expr
;
3025 else if (t
& VT_SHORT
)
3041 /* put zeros for variable based init */
3042 void init_putz(int t
, int c
, int size
)
3046 if ((t
& VT_VALMASK
) == VT_CONST
) {
3047 /* nothing to do because global are already set to zero */
3049 vset(VT_CONST
, size
);
3058 memset_addr
= (int)&memset
;
3059 oad(0xe8, memset_addr
- ind
- 5);
3064 /* 't' contains the type and storage info. c is the address of the
3065 object. 'first' is true if array '{' must be read (multi dimension
3066 implicit array init handling). 'size_only' is true if size only
3067 evaluation is wanted (only for arrays). */
3068 void decl_initializer(int t
, int c
, int first
, int size_only
)
3070 int index
, array_length
, n
, no_oblock
, nb
, parlevel
, i
;
3071 int t1
, size1
, align1
;
3076 s
= sym_find(((unsigned)t
>> VT_STRUCT_SHIFT
));
3079 t1
= pointed_type(t
);
3080 size1
= type_size(t1
, &align1
);
3083 if ((first
&& tok
!= TOK_LSTR
&& tok
!= TOK_STR
) ||
3089 /* only parse strings here if correct type (otherwise: handle
3090 them as ((w)char *) expressions */
3091 if ((tok
== TOK_LSTR
&&
3092 (t1
& VT_TYPE
& ~VT_UNSIGNED
) == VT_INT
) ||
3094 (t1
& VT_TYPE
& ~VT_UNSIGNED
) == VT_BYTE
)) {
3095 /* XXX: move multiple string parsing in parser ? */
3096 while (tok
== TOK_STR
|| tok
== TOK_LSTR
) {
3097 ts
= (TokenSym
*)tokc
;
3098 /* compute maximum number of chars wanted */
3100 if (n
>= 0 && nb
> (n
- array_length
))
3101 nb
= n
- array_length
;
3104 warning("initializer-string for array is too long");
3106 init_putv(t1
, c
+ (array_length
+ i
) * size1
,
3113 /* only add trailing zero if enough storage (no
3114 warning in this case since it is standard) */
3115 if (n
< 0 || array_length
< n
) {
3117 init_putv(t1
, c
+ (array_length
* size1
), 0, 0);
3123 while (tok
!= '}') {
3124 decl_designator(t
, c
, &index
, NULL
, size_only
);
3125 if (n
>= 0 && index
>= n
)
3126 error("index too large");
3127 /* must put zero in holes (note that doing it that way
3128 ensures that it even works with designators) */
3129 if (!size_only
&& array_length
< index
) {
3130 init_putz(t1
, c
+ array_length
* size1
,
3131 (index
- array_length
) * size1
);
3134 if (index
> array_length
)
3135 array_length
= index
;
3136 /* special test for multi dimensional arrays (may not
3137 be strictly correct if designators are used at the
3139 if (index
>= n
&& no_oblock
)
3148 /* put zeros at the end */
3149 if (!size_only
&& n
>= 0 && array_length
< n
) {
3150 init_putz(t1
, c
+ array_length
* size1
,
3151 (n
- array_length
) * size1
);
3153 /* patch type size if needed */
3155 s
->c
= array_length
;
3156 } else if (t
& VT_STRUCT
) {
3157 /* XXX: union needs only one init */
3159 s
= sym_find(((unsigned)t
>> VT_STRUCT_SHIFT
) | SYM_STRUCT
);
3164 while (tok
!= '}') {
3165 decl_designator(t
, c
, NULL
, &f
, size_only
);
3166 /* fill with zero between fields */
3168 if (!size_only
&& array_length
< index
) {
3169 init_putz(t
, c
+ array_length
,
3170 index
- array_length
);
3172 index
= index
+ type_size(f
->t
, &align1
);
3173 if (index
> array_length
)
3174 array_length
= index
;
3180 /* put zeros at the end */
3181 if (!size_only
&& array_length
< n
) {
3182 init_putz(t
, c
+ array_length
,
3186 } else if (tok
== '{') {
3188 decl_initializer(t
, c
, first
, size_only
);
3190 } else if (size_only
) {
3191 /* just skip expression */
3193 while ((parlevel
> 0 || (tok
!= '}' && tok
!= ',')) &&
3197 else if (tok
== ')')
3202 init_putv(t
, c
, 0, 1);
3206 /* parse an initializer for type 't' if 'has_init' is true, and
3207 allocate space in local or global data space. The allocated address
3209 int decl_initializer_alloc(int t
, int has_init
)
3211 int size
, align
, addr
, tok1
;
3212 int *init_str
, init_len
, level
, *saved_macro_ptr
;
3214 size
= type_size(t
, &align
);
3215 /* If unknown size, we must evaluate it before
3216 evaluating initializers because
3217 initializers can generate global data too
3218 (e.g. string pointers or ISOC99 compound
3219 literals). It also simplifies local
3220 initializers handling */
3223 saved_macro_ptr
= NULL
; /* avoid warning */
3227 error("unknown type size");
3228 /* get all init string */
3230 while (level
> 0 || (tok
!= ',' && tok
!= ';')) {
3232 error("unexpect end of file in initializer");
3233 tok_add2(&init_str
, &init_len
, tok
, tokc
);
3236 else if (tok
== '}') {
3244 tok_add(&init_str
, &init_len
, -1);
3245 tok_add(&init_str
, &init_len
, 0);
3248 saved_macro_ptr
= macro_ptr
;
3249 macro_ptr
= init_str
;
3251 decl_initializer(t
, 0, 1, 1);
3252 /* prepare second initializer parsing */
3253 macro_ptr
= init_str
;
3256 /* if still unknown size, error */
3257 size
= type_size(t
, &align
);
3259 error("unknown type size");
3261 if ((t
& VT_VALMASK
) == VT_LOCAL
) {
3262 loc
= (loc
- size
) & -align
;
3265 glo
= (glo
+ align
- 1) & -align
;
3267 /* very important to increment global
3268 pointer at this time because
3269 initializers themselves can create new
3274 decl_initializer(t
, addr
, 1, 0);
3275 /* restore parse state if needed */
3278 macro_ptr
= saved_macro_ptr
;
3286 /* 'l' is VT_LOCAL or VT_CONST to define default storage type */
3289 int *a
, t
, b
, v
, u
, n
, addr
, has_init
;
3295 /* special test for old K&R protos without explicit int
3296 type. Only accepted when defining global data */
3297 if (l
== VT_LOCAL
|| tok
< TOK_DEFINE
)
3301 if ((b
& (VT_ENUM
| VT_STRUCT
)) && tok
== ';') {
3302 /* we accept no variable after */
3306 while (1) { /* iterate thru each declaration */
3307 t
= type_decl(&v
, b
, TYPE_DIRECT
);
3310 expect("function definition");
3311 /* patch forward references */
3312 if ((sym
= sym_find(v
)) && (sym
->t
& VT_FORWARD
)) {
3315 sym
->t
= VT_CONST
| VT_LVAL
| t
;
3317 /* put function address */
3318 sym_push1(&global_stack
, v
, VT_CONST
| VT_LVAL
| t
, ind
);
3320 funcname
= get_tok_str(v
, 0);
3321 /* push a dummy symbol to enable local sym storage */
3322 sym_push1(&local_stack
, 0, 0, 0);
3323 /* define parameters */
3324 sym
= sym_find((unsigned)t
>> VT_STRUCT_SHIFT
);
3325 while (sym
= sym
->next
)
3326 sym_push(sym
->v
& ~SYM_FIELD
, sym
->t
, sym
->c
);
3328 o(0xe58955); /* push %ebp, mov %esp, %ebp */
3329 a
= (int *)oad(0xec81, 0); /* sub $xxx, %esp */
3331 block(0, 0, 0, 0, 0);
3333 o(0xc3c9); /* leave, ret */
3334 *a
= (-loc
+ 3) & -4; /* align local size to word &
3335 save local variables */
3336 sym_pop(&label_stack
, 0); /* reset label stack */
3337 sym_pop(&local_stack
, 0); /* reset local stack */
3341 if (b
& VT_TYPEDEF
) {
3342 /* save typedefed type */
3343 sym_push(v
, t
| VT_TYPEDEF
, 0);
3344 } else if (t
& VT_FUNC
) {
3345 /* XXX: incorrect to flush, but needed while
3346 waiting for function prototypes */
3347 /* external function definition */
3348 external_func(v
, t
);
3350 /* not lvalue if array */
3351 if (!(t
& VT_ARRAY
))
3353 if (b
& VT_EXTERN
) {
3354 /* external variable */
3355 /* XXX: factorize with external function def */
3356 n
= (int)dlsym(NULL
, get_tok_str(v
, 0));
3358 error("unknown external variable");
3359 sym_push(v
, VT_CONST
| t
, n
);
3365 has_init
= (tok
== '=');
3368 addr
= decl_initializer_alloc(u
, has_init
);
3369 sym_push(v
, u
, addr
);
3382 /* open a dynamic library so that its symbol are available for
3383 compiled programs */
3384 void open_dll(char *libname
)
3389 snprintf(buf
, sizeof(buf
), "lib%s.so", libname
);
3390 h
= dlopen(buf
, RTLD_GLOBAL
| RTLD_LAZY
);
3392 error((char *)dlerror());
3395 /* output a binary file (for testing) */
3396 void build_exe(char *filename
)
3399 f
= fopen(filename
, "w");
3400 fwrite((void *)prog
, 1, ind
- prog
, f
);
3404 int main(int argc
, char **argv
)
3408 char *p
, *r
, *outfile
;
3411 include_paths
[0] = "/usr/include";
3412 include_paths
[1] = "/usr/lib/tcc";
3413 include_paths
[2] = "/usr/local/lib/tcc";
3414 nb_include_paths
= 3;
3416 /* add all tokens */
3417 tok_ident
= TOK_IDENT
;
3418 p
= "int\0void\0char\0if\0else\0while\0break\0return\0for\0extern\0static\0unsigned\0goto\0do\0continue\0switch\0case\0const\0volatile\0long\0register\0signed\0auto\0inline\0restrict\0float\0double\0short\0struct\0union\0typedef\0default\0enum\0sizeof\0define\0include\0ifdef\0ifndef\0elif\0endif\0defined\0undef\0error\0line\0__LINE__\0__FILE__\0__DATE__\0__TIME__\0__VA_ARGS__\0__func__\0main\0";
3422 tok_alloc(p
, r
- p
- 1);
3426 /* standard defines */
3427 define_symbol("__STDC__");
3429 define_symbol("__i386__");
3435 if (optind
>= argc
) {
3437 printf("tcc version 0.9 - Tiny C Compiler - Copyright (C) 2001 Fabrice Bellard\n"
3438 "usage: tcc [-Idir] [-Dsym] [-llib] infile [infile_arg...]\n");
3446 if (nb_include_paths
>= INCLUDE_PATHS_MAX
)
3447 error("too many include paths");
3448 include_paths
[nb_include_paths
++] = r
+ 2;
3449 } else if (r
[1] == 'D') {
3450 define_symbol(r
+ 2);
3451 } else if (r
[1] == 'l') {
3453 } else if (r
[1] == 'o') {
3454 /* currently, only for testing, so not documented */
3457 outfile
= argv
[optind
++];
3459 fprintf(stderr
, "invalid option -- '%s'\n", r
);
3464 filename
= argv
[optind
];
3467 file
= fopen(filename
, "r");
3472 include_stack_ptr
= include_stack
;
3473 ifdef_stack_ptr
= ifdef_stack
;
3475 glo
= (int)malloc(DATA_SIZE
);
3476 memset((void *)glo
, 0, DATA_SIZE
);
3477 prog
= (int)malloc(TEXT_SIZE
);
3478 vstack_ptr
= vstack
;
3479 anon_sym
= 1 << (31 - VT_STRUCT_SHIFT
);
3482 ch
= '\n'; /* needed to parse correctly first preprocessor command */
3486 expect("declaration");
3491 s
= sym_find(TOK_MAIN
);
3493 error("main() not defined");
3494 t
= (int (*)())s
->c
;
3498 return (*t
)(argc
- optind
, argv
+ optind
);