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 /* number of available temporary registers */
39 /* defined if function parameters must be evaluated in revert order */
40 #define INVERT_FUNC_PARAMS
42 /* token symbol management */
43 typedef struct TokenSym
{
44 struct TokenSym
*next
;
45 int tok
; /* token number */
50 /* symbol management */
52 int v
; /* symbol token */
53 int t
; /* associated type */
54 int c
; /* associated number */
55 struct Sym
*next
; /* next related symbol */
56 struct Sym
*prev
; /* prev symbol in stack */
59 #define SYM_STRUCT 0x40000000 /* struct/union/enum symbol space */
60 #define SYM_FIELD 0x20000000 /* struct/union field symbol space */
62 #define FUNC_NEW 1 /* ansi function prototype */
63 #define FUNC_OLD 2 /* old function prototype */
64 #define FUNC_ELLIPSIS 3 /* ansi function prototype with ... */
66 /* field 'Sym.t' for macros */
67 #define MACRO_OBJ 0 /* object like macro */
68 #define MACRO_FUNC 1 /* function like macro */
70 /* type_decl() types */
71 #define TYPE_ABSTRACT 1 /* type without variable */
72 #define TYPE_DIRECT 2 /* type with variable */
80 /* loc : local variable index
81 glo : global variable index
85 anon_sym: anonymous symbol index
88 int tok
, tok1
, tokc
, rsym
, anon_sym
,
89 prog
, ind
, loc
, glo
, vt
, vc
, const_wanted
, line_num
;
90 TokenSym
*first_ident
;
91 char token_buf
[STRING_MAX_SIZE
+ 1];
93 Sym
*define_stack
, *global_stack
, *local_stack
, *label_stack
;
95 int vstack
[VSTACK_SIZE
], *vstack_ptr
;
96 int *macro_ptr
, *macro_ptr_allocated
;
97 IncludeFile include_stack
[INCLUDE_STACK_SIZE
], *include_stack_ptr
;
98 int ifdef_stack
[IFDEF_STACK_SIZE
], *ifdef_stack_ptr
;
99 char *include_paths
[INCLUDE_PATHS_MAX
];
100 int nb_include_paths
;
102 /* The current value can be: */
103 #define VT_VALMASK 0x000f
104 #define VT_CONST 0x000a /* constant in vc
105 (must be first non register value) */
106 #define VT_LLOCAL 0x000b /* lvalue, offset on stack */
107 #define VT_LOCAL 0x000c /* offset on stack */
108 #define VT_CMP 0x000d /* the value is stored in processor flags (in vc) */
109 #define VT_JMP 0x000e /* value is the consequence of jmp true */
110 #define VT_JMPI 0x000f /* value is the consequence of jmp false */
111 #define VT_LVAL 0x0010 /* var is an lvalue */
112 #define VT_LVALN -17 /* ~VT_LVAL */
113 #define VT_FORWARD 0x0020 /* value is forward reference
114 (only used for functions) */
117 #define VT_VOID 0x00040
118 #define VT_BYTE 0x00080 /* signed byte type */
119 #define VT_PTR 0x00100 /* pointer increment */
120 #define VT_UNSIGNED 0x00200 /* unsigned type */
121 #define VT_ARRAY 0x00400 /* array type (only used in parsing) */
122 #define VT_ENUM 0x00800 /* enum definition */
123 #define VT_FUNC 0x01000 /* function type */
124 #define VT_STRUCT 0x002000 /* struct/union definition */
125 #define VT_TYPEDEF 0x004000 /* typedef definition */
126 #define VT_EXTERN 0x008000 /* extern definition */
127 #define VT_STATIC 0x010000 /* static variable */
128 #define VT_SHORT 0x020000 /* short type */
129 #define VT_STRUCT_SHIFT 18 /* structure/enum name shift (14 bits left) */
131 #define VT_TYPE 0xffffffc0 /* type mask */
132 #define VT_TYPEN 0x0000003f /* ~VT_TYPE */
133 #define VT_FUNCN -4097 /* ~VT_FUNC */
137 /* warning: the following compare tokens depend on i386 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 */
162 #define TOK_CCHAR 0xb4 /* char constant in tokc */
163 #define TOK_STR 0xb5 /* pointer to string in tokc */
165 #define TOK_TWOSHARPS 0xb6 /* ## preprocessing token */
167 #define TOK_SHL 0x01 /* shift left */
168 #define TOK_SAR 0x02 /* signed shift right */
170 /* assignement operators : normal operator or 0x80 */
171 #define TOK_A_MOD 0xa5
172 #define TOK_A_AND 0xa6
173 #define TOK_A_MUL 0xaa
174 #define TOK_A_ADD 0xab
175 #define TOK_A_SUB 0xad
176 #define TOK_A_DIV 0xaf
177 #define TOK_A_XOR 0xde
178 #define TOK_A_OR 0xfc
179 #define TOK_A_SHL 0x81
180 #define TOK_A_SAR 0x82
182 /* all identificators and strings have token above that */
183 #define TOK_IDENT 256
204 /* ignored types Must have contiguous values */
213 /* unsupported type */
225 /* preprocessor only */
235 /* special identifiers */
249 void macro_subst(int **tok_str
, int *tok_len
,
250 Sym
**nested_list
, int *macro_str
);
251 int save_reg_forced(int r
);
252 int type_size(int t
, int *a
);
253 int pointed_type(int t
);
254 int pointed_size(int t
);
256 int type_decl(int *v
, int t
, int td
);
259 /* dummy function for profiling */
260 void *dlopen(const char *filename
, int flag
)
264 const char *dlerror(void)
269 void *dlsym(void *handle
, char *symbol
)
278 return (c
>= 'a' & c
<= 'z') |
279 (c
>= 'A' & c
<= 'Z') |
285 return c
>= '0' & c
<= '9';
291 for(f
= include_stack
; f
< include_stack_ptr
; f
++)
292 fprintf(stderr
, "In file included from %s:%d:\n",
293 f
->filename
, f
->line_num
);
294 fprintf(stderr
, "%s:%d: ", filename
, line_num
);
297 void error(const char *fmt
, ...)
302 vfprintf(stderr
, fmt
, ap
);
303 fprintf(stderr
, "\n");
308 void expect(const char *msg
)
310 error("%s expected", msg
);
313 void warning(const char *msg
)
316 fprintf(stderr
, "warning: %s\n", msg
);
322 error("'%c' expected", c
);
332 TokenSym
*tok_alloc(char *str
, int len
)
343 if (ts
->len
== len
&& !memcmp(ts
->str
, str
, len
))
348 ts
= malloc(sizeof(TokenSym
) + len
);
350 error("memory full");
354 memcpy(ts
->str
, str
, len
+ 1);
360 void add_char(char **pp
, int c
)
364 if (c
== '\'' || c
== '\"' || c
== '\\') {
365 /* XXX: could be more precise if char or string */
368 if (c
>= 32 && c
<= 126) {
375 *p
++ = '0' + ((c
>> 6) & 7);
376 *p
++ = '0' + ((c
>> 3) & 7);
377 *p
++ = '0' + (c
& 7);
383 /* XXX: buffer overflow */
384 char *get_tok_str(int v
, int c
)
386 static char buf
[STRING_MAX_SIZE
+ 1];
392 sprintf(buf
, "%d", c
);
394 } else if (v
== TOK_CCHAR
) {
401 } else if (v
== TOK_STR
) {
405 for(i
=0;i
<ts
->len
;i
++)
406 add_char(&p
, ts
->str
[i
]);
410 } else if (v
< TOK_IDENT
) {
426 /* find a symbol and return its associated structure. 's' is the top
427 of the symbol stack */
428 Sym
*sym_find1(Sym
*s
, int v
)
438 Sym
*sym_push1(Sym
**ps
, int v
, int t
, int c
)
441 s
= malloc(sizeof(Sym
));
443 error("memory full");
453 /* find a symbol in the right symbol space */
457 s
= sym_find1(local_stack
, v
);
459 s
= sym_find1(global_stack
, v
);
463 /* push a given symbol on the symbol stack */
464 Sym
*sym_push(int v
, int t
, int c
)
467 return sym_push1(&local_stack
, v
, t
, c
);
469 return sym_push1(&global_stack
, v
, t
, c
);
472 /* pop symbols until top reaches 'b' */
473 void sym_pop(Sym
**ps
, Sym
*b
)
488 /* read next char from current input file */
494 if (include_stack_ptr
== include_stack
)
496 /* pop include stack */
500 file
= include_stack_ptr
->file
;
501 filename
= include_stack_ptr
->filename
;
502 line_num
= include_stack_ptr
->line_num
;
507 // printf("ch1=%c 0x%x\n", ch1, ch1);
510 /* input with '\\n' handling */
516 if (ch
== '\\' && ch1
== '\n') {
520 //printf("ch=%c 0x%x\n", ch, ch);
523 /* same as minp, but also skip comments */
531 /* single line C++ comments */
533 while (ch1
!= '\n' && ch1
!= -1)
536 ch
= ' '; /* return space */
537 } else if (ch1
== '*') {
543 if (c
== '*' && ch1
== '/') {
545 ch
= ' '; /* return space */
559 while (ch
== ' ' || ch
== '\t')
563 /* skip block of text until #else, #elif or #endif. skip also pairs of
565 void preprocess_skip()
581 (tok
== TOK_ELSE
|| tok
== TOK_ELIF
|| tok
== TOK_ENDIF
))
583 if (tok
== TOK_IF
|| tok
== TOK_IFDEF
|| tok
== TOK_IFNDEF
)
585 else if (tok
== TOK_ENDIF
)
591 void tok_add(int **tok_str
, int *tok_len
, int t
)
596 if ((len
& 63) == 0) {
597 str
= realloc(str
, (len
+ 64) * sizeof(int));
606 void tok_add2(int **tok_str
, int *tok_len
, int t
, int c
)
608 tok_add(tok_str
, tok_len
, t
);
609 if (t
== TOK_NUM
|| t
== TOK_CCHAR
|| t
== TOK_STR
)
610 tok_add(tok_str
, tok_len
, c
);
613 /* eval an expression for #if/#elif */
614 int expr_preprocess()
624 next(); /* do macro subst */
625 if (tok
== TOK_DEFINED
) {
630 c
= sym_find1(define_stack
, tok
) != 0;
635 } else if (tok
>= TOK_IDENT
) {
636 /* if undefined macro */
640 tok_add2(&str
, &len
, tok
, tokc
);
642 tok_add(&str
, &len
, -1); /* simulate end of file */
643 tok_add(&str
, &len
, 0);
644 /* now evaluate C constant expression */
654 void tok_print(int *str
)
663 if (t
== TOK_NUM
|| t
== TOK_CCHAR
|| t
== TOK_STR
)
665 printf(" %s", get_tok_str(t
, c
));
671 /* XXX: should be more factorized */
672 void define_symbol(char *sym
)
677 ts
= tok_alloc(sym
, strlen(sym
));
680 tok_add2(&str
, &len
, TOK_NUM
, 1);
681 tok_add(&str
, &len
, 0);
682 sym_push1(&define_stack
, ts
->tok
, MACRO_OBJ
, (int)str
);
687 int size
, i
, c
, v
, t
, *str
, len
;
688 char buf
[1024], *q
, *p
;
691 Sym
**ps
, *first
, *s
;
696 if (tok
== TOK_DEFINE
) {
699 /* XXX: should check if same macro (ANSI) */
702 /* '(' must be just after macro definition for MACRO_FUNC */
708 s
= sym_push1(&define_stack
, tok
| SYM_FIELD
, 0, 0);
722 if (ch
== '\n' || ch
== -1)
725 tok_add2(&str
, &len
, tok
, tokc
);
727 tok_add(&str
, &len
, 0);
729 printf("define %s %d: ", get_tok_str(v
, 0), t
);
732 s
= sym_push1(&define_stack
, v
, t
, (int)str
);
734 } else if (tok
== TOK_UNDEF
) {
736 s
= sym_find1(define_stack
, tok
);
737 /* undefine symbol by putting an invalid name */
740 } else if (tok
== TOK_INCLUDE
) {
745 } else if (ch
== '\"') {
750 while (ch
!= c
&& ch
!= '\n' && ch
!= -1) {
751 if ((q
- buf
) < sizeof(buf
) - 1)
756 if (include_stack_ptr
>= include_stack
+ INCLUDE_STACK_SIZE
)
757 error("memory full");
759 /* first search in current dir if "header.h" */
760 /* XXX: buffer overflow */
762 p
= strrchr(filename
, '/');
764 size
= p
+ 1 - filename
;
765 memcpy(buf1
, filename
, size
);
768 f
= fopen(buf1
, "r");
772 /* now search in standard include path */
773 for(i
=nb_include_paths
- 1;i
>=0;i
--) {
774 strcpy(buf1
, include_paths
[i
]);
777 f
= fopen(buf1
, "r");
781 error("include file not found");
784 /* push current file in stack */
785 /* XXX: fix current line init */
786 include_stack_ptr
->file
= file
;
787 include_stack_ptr
->filename
= filename
;
788 include_stack_ptr
->line_num
= line_num
;
791 filename
= strdup(buf1
);
794 } else if (tok
== TOK_IFNDEF
) {
797 } else if (tok
== TOK_IF
) {
798 c
= expr_preprocess();
800 } else if (tok
== TOK_IFDEF
) {
804 c
= (sym_find1(define_stack
, tok
) != 0) ^ c
;
806 if (ifdef_stack_ptr
>= ifdef_stack
+ IFDEF_STACK_SIZE
)
807 error("memory full");
808 *ifdef_stack_ptr
++ = c
;
810 } else if (tok
== TOK_ELSE
) {
811 if (ifdef_stack_ptr
== ifdef_stack
||
812 (ifdef_stack_ptr
[-1] & 2))
813 error("#else after #else");
814 c
= (ifdef_stack_ptr
[-1] ^= 3);
816 } else if (tok
== TOK_ELIF
) {
817 if (ifdef_stack_ptr
== ifdef_stack
||
818 ifdef_stack_ptr
[-1] > 1)
819 error("#elif after #else");
820 c
= expr_preprocess();
821 ifdef_stack_ptr
[-1] = c
;
827 } else if (tok
== TOK_ENDIF
) {
828 if (ifdef_stack_ptr
== ifdef_stack
)
832 /* ignore other preprocess commands or #! for C scripts */
833 while (ch
!= '\n' && ch
!= -1)
837 /* read a number in base b */
843 if (ch
>= 'a' & ch
<= 'f')
845 else if (ch
>= 'A' & ch
<= 'F')
859 /* read a character for string or char constant and eval escape codes */
892 /* return next token without macro substitution */
903 while (ch
== ' ' || ch
== 9)
906 /* preprocessor command if # at start of line after
911 if (ch
!= ' ' && ch
!= '\t' && ch
!= '\f')
917 while (isid(ch
) | isnum(ch
)) {
918 if (q
>= token_buf
+ STRING_MAX_SIZE
)
919 error("ident too long");
924 ts
= tok_alloc(token_buf
, q
- token_buf
);
926 } else if (isnum(ch
)) {
932 if (ch
== 'x' || ch
== 'X') {
938 /* XXX: add unsigned constant support (ANSI) */
939 while (ch
== 'L' || ch
== 'l' || ch
== 'U' || ch
== 'u')
942 } else if (ch
== '\'') {
949 } else if (ch
== '\"') {
955 error("unterminated string");
956 if (q
>= token_buf
+ STRING_MAX_SIZE
)
957 error("string too long");
961 tokc
= (int)tok_alloc(token_buf
, q
- token_buf
);
965 q
= "<=\236>=\235!=\225&&\240||\241++\244--\242==\224<<\1>>\2+=\253-=\255*=\252/=\257%=\245&=\246^=\336|=\374->\247..\250##\266";
970 if (*q
== tok
& q
[1] == ch
) {
973 /* three chars tests */
974 if (tok
== TOK_SHL
| tok
== TOK_SAR
) {
979 } else if (tok
== TOK_DOTS
) {
981 error("parse error");
988 /* single char substitutions */
996 /* return next token without macro substitution. Can read input from
1004 if (tok
== TOK_NUM
|| tok
== TOK_CCHAR
|| tok
== TOK_STR
)
1005 tokc
= *macro_ptr
++;
1012 /* substitute args in macro_str and return allocated string */
1013 int *macro_arg_subst(Sym
**nested_list
, int *macro_str
, Sym
*args
)
1015 int *st
, last_tok
, t
, c
, notfirst
, *str
, len
;
1031 s
= sym_find1(args
, t
);
1033 token_buf
[0] = '\0';
1035 /* XXX: buffer overflow */
1039 strcat(token_buf
, " ");
1042 if (t
== TOK_NUM
|| t
== TOK_CCHAR
|| t
== TOK_STR
)
1044 strcat(token_buf
, get_tok_str(t
, c
));
1048 printf("stringize: %s\n", token_buf
);
1051 ts
= tok_alloc(token_buf
, strlen(token_buf
));
1052 tok_add2(&str
, &len
, TOK_STR
, (int)ts
);
1054 tok_add(&str
, &len
, t
);
1056 } else if (t
== TOK_NUM
|| t
== TOK_CCHAR
|| t
== TOK_STR
) {
1057 tok_add2(&str
, &len
, t
, *macro_ptr
++);
1059 s
= sym_find1(args
, t
);
1062 /* if '##' is present before or after , no arg substitution */
1063 if (*macro_str
== TOK_TWOSHARPS
|| last_tok
== TOK_TWOSHARPS
) {
1065 tok_add(&str
, &len
, *st
++);
1067 macro_subst(&str
, &len
, nested_list
, st
);
1070 tok_add(&str
, &len
, t
);
1075 tok_add(&str
, &len
, 0);
1079 /* handle the '##' operator */
1080 int *macro_twosharps(int *macro_str
)
1083 int *macro_str1
, macro_str1_len
, *macro_ptr1
;
1094 if (*macro_ptr
== TOK_TWOSHARPS
) {
1096 macro_ptr1
= macro_ptr
;
1101 if (t
== TOK_NUM
|| t
== TOK_CCHAR
|| t
== TOK_STR
)
1103 /* XXX: we handle only most common cases:
1104 ident + ident or ident + number */
1105 if (tok
>= TOK_IDENT
&&
1106 (t
>= TOK_IDENT
|| t
== TOK_NUM
)) {
1107 /* XXX: buffer overflow */
1108 p
= get_tok_str(tok
, tokc
);
1109 strcpy(token_buf
, p
);
1110 p
= get_tok_str(t
, c
);
1111 strcat(token_buf
, p
);
1112 ts
= tok_alloc(token_buf
, strlen(token_buf
));
1113 tok_add2(¯o_str1
, ¯o_str1_len
, ts
->tok
, 0);
1115 /* cannot merge tokens: skip '##' */
1116 macro_ptr
= macro_ptr1
;
1120 tok_add2(¯o_str1
, ¯o_str1_len
, tok
, tokc
);
1123 tok_add(¯o_str1
, ¯o_str1_len
, 0);
1129 /* do macro substitution of macro_str and add result to
1130 (tok_str,tok_len). If macro_str is NULL, then input stream token is
1131 substituted. 'nested_list' is the list of all macros we got inside
1132 to avoid recursing. */
1133 void macro_subst(int **tok_str
, int *tok_len
,
1134 Sym
**nested_list
, int *macro_str
)
1137 int *str
, parlevel
, len
, *mstr
, t
, *saved_macro_ptr
;
1138 int mstr_allocated
, *macro_str1
;
1140 saved_macro_ptr
= macro_ptr
;
1141 macro_ptr
= macro_str
;
1144 /* first scan for '##' operator handling */
1145 macro_str1
= macro_twosharps(macro_str
);
1146 macro_ptr
= macro_str1
;
1153 /* if symbol is a macro, prepare substitution */
1154 s
= sym_find1(define_stack
, tok
);
1156 /* if nested substitution, do nothing */
1157 if (sym_find1(*nested_list
, tok
))
1161 if (s
->t
== MACRO_FUNC
) {
1162 /* NOTE: we do not use next_nomacro to avoid eating the
1163 next token. XXX: find better solution */
1167 while (ch
== ' ' || ch
== '\t' || ch
== '\n')
1171 if (t
!= '(') /* no macro subst */
1174 /* argument macro */
1179 while (tok
!= ')' && sa
) {
1183 while ((parlevel
> 0 || (tok
!= ')' && tok
!= ',')) &&
1187 else if (tok
== ')')
1189 tok_add2(&str
, &len
, tok
, tokc
);
1192 tok_add(&str
, &len
, 0);
1193 sym_push1(&args
, sa
->v
& ~SYM_FIELD
, 0, (int)str
);
1201 /* now subst each arg */
1202 mstr
= macro_arg_subst(nested_list
, mstr
, args
);
1209 sym_pop(&args
, NULL
);
1212 sym_push1(nested_list
, s
->v
, 0, 0);
1213 macro_subst(tok_str
, tok_len
, nested_list
, mstr
);
1214 sym_pop(nested_list
, (*nested_list
)->prev
);
1217 /* only replace one macro while parsing input stream */
1222 /* no need to add if reading input stream */
1225 tok_add2(tok_str
, tok_len
, tok
, tokc
);
1228 macro_ptr
= saved_macro_ptr
;
1233 /* return next token with macro substitution */
1239 /* special 'ungettok' case for label parsing */
1246 /* if not reading from macro substuted string, then try to substitute */
1250 macro_subst(&ptr
, &len
, &nested_list
, NULL
);
1252 tok_add(&ptr
, &len
, 0);
1254 macro_ptr_allocated
= ptr
;
1262 /* end of macro string: free it */
1263 free(macro_ptr_allocated
);
1270 printf("token = %s\n", get_tok_str(tok
, tokc
));
1274 void swap(int *p
, int *q
)
1288 /******************************************************/
1289 /* X86 code generator */
1304 /* output a symbol and patch all calls to it */
1305 void gsym_addr(t
, a
)
1309 n
= *(int *)t
; /* next value */
1310 *(int *)t
= a
- t
- 4;
1320 /* psym is used to put an instruction with a data field which is a
1321 reference to a symbol. It is in fact the same as oad ! */
1324 /* instruction + 4 bytes data. Return the address of the data */
1334 /* XXX: generate correct pointer for forward references to functions */
1336 void load(r
, ft
, fc
)
1340 v
= ft
& VT_VALMASK
;
1342 if (v
== VT_LLOCAL
) {
1343 load(r
, VT_LOCAL
| VT_LVAL
, fc
);
1346 if ((ft
& VT_TYPE
) == VT_BYTE
)
1347 o(0xbe0f); /* movsbl */
1348 else if ((ft
& VT_TYPE
) == (VT_BYTE
| VT_UNSIGNED
))
1349 o(0xb60f); /* movzbl */
1350 else if ((ft
& VT_TYPE
) == VT_SHORT
)
1351 o(0xbf0f); /* movswl */
1352 else if ((ft
& VT_TYPE
) == (VT_SHORT
| VT_UNSIGNED
))
1353 o(0xb70f); /* movzwl */
1356 if (v
== VT_CONST
) {
1357 oad(0x05 + r
* 8, fc
); /* 0xXX, r */
1358 } else if (v
== VT_LOCAL
) {
1359 oad(0x85 + r
* 8, fc
); /* xx(%ebp), r */
1361 g(0x00 + r
* 8 + v
); /* (v), r */
1364 if (v
== VT_CONST
) {
1365 oad(0xb8 + r
, fc
); /* mov $xx, r */
1366 } else if (v
== VT_LOCAL
) {
1368 oad(0x85 + r
* 8, fc
); /* lea xxx(%ebp), r */
1369 } else if (v
== VT_CMP
) {
1370 oad(0xb8 + r
, 0); /* mov $0, r */
1371 o(0x0f); /* setxx %br */
1374 } else if (v
== VT_JMP
|| v
== VT_JMPI
) {
1376 oad(0xb8 + r
, t
); /* mov $1, r */
1377 oad(0xe9, 5); /* jmp after */
1379 oad(0xb8 + r
, t
^ 1); /* mov $0, r */
1380 } else if (v
!= r
) {
1382 o(0xc0 + r
+ v
* 8); /* mov v, r */
1388 /* WARNING: r must not be allocated on the stack */
1389 void store(r
, ft
, fc
)
1393 fr
= ft
& VT_VALMASK
;
1394 b
= (ft
& VT_TYPE
) == VT_BYTE
;
1395 /* XXX: incorrect if reg to reg */
1399 if (fr
== VT_CONST
) {
1400 oad(0x05 + r
* 8, fc
); /* mov r,xxx */
1401 } else if (fr
== VT_LOCAL
) {
1402 oad(0x85 + r
* 8, fc
); /* mov r,xxx(%ebp) */
1403 } else if (ft
& VT_LVAL
) {
1404 g(fr
+ r
* 8); /* mov r, (fr) */
1405 } else if (fr
!= r
) {
1406 o(0xc0 + fr
+ r
* 8); /* mov r, fr */
1410 void gfunc_param(void)
1412 o(0x50 + gv()); /* push r */
1417 return psym(0xe9, t
);
1420 /* generate a test. set 'inv' to invert test */
1424 v
= vt
& VT_VALMASK
;
1426 /* fast case : can jump directly since flags are set */
1428 t
= psym((vc
- 16) ^ inv
, t
);
1429 } else if (v
== VT_JMP
|| v
== VT_JMPI
) {
1430 /* && or || optimization */
1431 if ((v
& 1) == inv
) {
1432 /* insert vc jump list in t */
1442 } else if ((vt
& (VT_VALMASK
| VT_LVAL
)) == VT_CONST
) {
1443 /* constant jmp optimization */
1444 if ((vc
!= 0) != inv
)
1451 t
= psym(0x85 ^ inv
, t
);
1456 /* generate a binary operation 'v = r op fr' instruction and modifies
1457 (vt,vc) if needed */
1458 void gen_op1(op
, r
, fr
)
1463 o(0xc0 + r
+ fr
* 8);
1464 } else if (op
== '-') {
1466 o(0xc0 + r
+ fr
* 8);
1467 } else if (op
== '&') {
1469 o(0xc0 + r
+ fr
* 8);
1470 } else if (op
== '^') {
1472 o(0xc0 + r
+ fr
* 8);
1473 } else if (op
== '|') {
1475 o(0xc0 + r
+ fr
* 8);
1476 } else if (op
== '*') {
1477 o(0xaf0f); /* imul fr, r */
1478 o(0xc0 + fr
+ r
* 8);
1479 } else if (op
== TOK_SHL
| op
== TOK_SHR
| op
== TOK_SAR
) {
1485 o(0x87); /* xchg r, %ecx */
1490 o(0xd3); /* shl/shr/sar %cl, r */
1493 else if (op
== TOK_SHR
)
1497 vt
= (vt
& VT_TYPE
) | r
;
1498 } else if (op
== '/' | op
== TOK_UDIV
| op
== TOK_PDIV
|
1499 op
== '%' | op
== TOK_UMOD
) {
1500 save_reg(2); /* save edx */
1501 t
= save_reg_forced(fr
); /* save fr and get op2 location */
1502 move_reg(0, r
); /* op1 is %eax */
1503 if (op
== TOK_UDIV
| op
== TOK_UMOD
) {
1504 o(0xf7d231); /* xor %edx, %edx, div t(%ebp), %eax */
1507 o(0xf799); /* cltd, idiv t(%ebp), %eax */
1510 if (op
== '%' | op
== TOK_UMOD
)
1514 vt
= (vt
& VT_TYPE
) | r
;
1517 o(0xc0 + r
+ fr
* 8); /* cmp fr, r */
1522 /* end of X86 code generator */
1523 /*************************************************************/
1525 int save_reg_forced(int r
)
1528 /* store register */
1529 loc
= (loc
- 4) & -3;
1530 store(r
, VT_LOCAL
, loc
);
1533 /* modify all stack values */
1534 for(p
=vstack
;p
<vstack_ptr
;p
+=2) {
1535 i
= p
[0] & VT_VALMASK
;
1541 p
[0] = (p
[0] & VT_TYPE
) | VT_LVAL
| t
;
1548 /* save r to memory. and mark it as being free */
1553 /* modify all stack values */
1554 for(p
=vstack
;p
<vstack_ptr
;p
+=2) {
1555 i
= p
[0] & VT_VALMASK
;
1563 /* find a free register. If none, save one register */
1568 /* find a free register */
1569 for(r
=0;r
<NB_REGS
;r
++) {
1570 for(p
=vstack
;p
<vstack_ptr
;p
+=2) {
1571 i
= p
[0] & VT_VALMASK
;
1579 /* no register left : free the first one on the stack (very
1580 important to start from the bottom to ensure that we don't
1581 spill registers used in gen_op()) */
1582 for(p
=vstack
;p
<vstack_ptr
;p
+=2) {
1583 r
= p
[0] & VT_VALMASK
;
1595 for(p
=vstack
;p
<vstack_ptr
;p
+=2) {
1596 r
= p
[0] & VT_VALMASK
;
1603 /* move register 's' to 'r', and flush previous value of r to memory
1613 /* convert a stack entry in register */
1617 r
= p
[0] & VT_VALMASK
;
1618 if (r
>= VT_CONST
|| (p
[0] & VT_LVAL
))
1620 load(r
, p
[0], p
[1]);
1621 p
[0] = (p
[0] & VT_TYPE
) | r
;
1627 if (vstack_ptr
>= vstack
+ VSTACK_SIZE
)
1628 error("memory full");
1631 /* cannot let cpu flags if other instruction are generated */
1632 if ((vt
& VT_VALMASK
) == VT_CMP
)
1633 gvp(vstack_ptr
- 2);
1636 void vpop(int *ft
, int *fc
)
1638 *fc
= *--vstack_ptr
;
1639 *ft
= *--vstack_ptr
;
1642 /* generate a value in a register from vt and vc */
1647 r
= gvp(vstack_ptr
- 2);
1652 /* handle constant optimizations and various machine independant opt */
1655 int fr
, ft
, fc
, r
, c1
, c2
, n
;
1659 c1
= (vt
& (VT_VALMASK
| VT_LVAL
)) == VT_CONST
;
1660 c2
= (ft
& (VT_VALMASK
| VT_LVAL
)) == VT_CONST
;
1663 case '+': vc
+= fc
; break;
1664 case '-': vc
-= fc
; break;
1665 case '&': vc
&= fc
; break;
1666 case '^': vc
^= fc
; break;
1667 case '|': vc
|= fc
; break;
1668 case '*': vc
*= fc
; break;
1670 case '/': vc
/= fc
; break; /* XXX: zero case ? */
1671 case '%': vc
%= fc
; break; /* XXX: zero case ? */
1672 case TOK_UDIV
: vc
= (unsigned)vc
/ fc
; break; /* XXX: zero case ? */
1673 case TOK_UMOD
: vc
= (unsigned)vc
% fc
; break; /* XXX: zero case ? */
1674 case TOK_SHL
: vc
<<= fc
; break;
1675 case TOK_SHR
: vc
= (unsigned)vc
>> fc
; break;
1676 case TOK_SAR
: vc
>>= fc
; break;
1678 case TOK_ULT
: vc
= (unsigned)vc
< (unsigned)fc
; break;
1679 case TOK_UGE
: vc
= (unsigned)vc
>= (unsigned)fc
; break;
1680 case TOK_EQ
: vc
= vc
== fc
; break;
1681 case TOK_NE
: vc
= vc
!= fc
; break;
1682 case TOK_ULE
: vc
= (unsigned)vc
<= (unsigned)fc
; break;
1683 case TOK_UGT
: vc
= (unsigned)vc
> (unsigned)fc
; break;
1684 case TOK_LT
: vc
= vc
< fc
; break;
1685 case TOK_GE
: vc
= vc
>= fc
; break;
1686 case TOK_LE
: vc
= vc
<= fc
; break;
1687 case TOK_GT
: vc
= vc
> fc
; break;
1689 case TOK_LAND
: vc
= vc
&& fc
; break;
1690 case TOK_LOR
: vc
= vc
|| fc
; break;
1695 /* if commutative ops, put c2 as constant */
1696 if (c1
&& (op
== '+' || op
== '&' || op
== '^' ||
1697 op
== '|' || op
== '*')) {
1702 if (c2
&& (((op
== '*' || op
== '/' || op
== TOK_UDIV
||
1705 ((op
== '+' || op
== '-' || op
== '|' || op
== '^' ||
1706 op
== TOK_SHL
|| op
== TOK_SHR
|| op
== TOK_SAR
) &&
1710 } else if (c2
&& (op
== '*' || op
== TOK_PDIV
|| op
== TOK_UDIV
)) {
1711 /* try to use shifts instead of muls or divs */
1712 if (fc
> 0 && (fc
& (fc
- 1)) == 0) {
1721 else if (op
== TOK_PDIV
)
1733 r
= gvp(vstack_ptr
- 4);
1734 fr
= gvp(vstack_ptr
- 2);
1737 /* call low level op generator */
1743 int pointed_size(int t
)
1745 return type_size(pointed_type(t
), &t
);
1748 /* generic gen_op: handles types problems */
1754 t1
= vstack_ptr
[-4];
1755 t2
= vstack_ptr
[-2];
1756 if (op
== '+' | op
== '-') {
1757 if ((t1
& VT_PTR
) && (t2
& VT_PTR
)) {
1759 error("invalid type");
1760 /* XXX: check that types are compatible */
1761 u
= pointed_size(t1
);
1764 vstack_ptr
[-2] &= ~VT_TYPE
; /* set to integer */
1767 } else if ((t1
| t2
) & VT_PTR
) {
1769 swap(vstack_ptr
- 4, vstack_ptr
- 2);
1770 swap(vstack_ptr
- 3, vstack_ptr
- 1);
1773 /* stack-4 contains pointer, stack-2 value to add */
1774 vset(VT_CONST
, pointed_size(vstack_ptr
[-4]));
1778 /* put again type if gen_opc() swaped operands */
1779 vt
= (vt
& VT_TYPEN
) | (t1
& VT_TYPE
);
1784 /* XXX: test types and compute returned value */
1785 if ((t1
| t2
) & (VT_UNSIGNED
| VT_PTR
)) {
1792 else if (op
== TOK_LT
)
1794 else if (op
== TOK_GT
)
1796 else if (op
== TOK_LE
)
1798 else if (op
== TOK_GE
)
1805 /* return type size. Put alignment at 'a' */
1806 int type_size(int t
, int *a
)
1810 /* int, enum or pointer */
1811 if (t
& VT_STRUCT
) {
1813 s
= sym_find(((unsigned)t
>> VT_STRUCT_SHIFT
) | SYM_STRUCT
);
1814 *a
= 4; /* XXX: cannot store it yet. Doing that is safe */
1816 } else if (t
& VT_ARRAY
) {
1817 s
= sym_find(((unsigned)t
>> VT_STRUCT_SHIFT
));
1818 return type_size(s
->t
, a
) * s
->c
;
1819 } else if ((t
& VT_PTR
) |
1820 (t
& VT_TYPE
) == 0 |
1824 } else if (t
& VT_SHORT
) {
1833 /* return the pointed type of t */
1834 int pointed_type(int t
)
1837 s
= sym_find(((unsigned)t
>> VT_STRUCT_SHIFT
));
1838 return s
->t
| (t
& VT_TYPEN
);
1841 int mk_pointer(int t
)
1846 return VT_PTR
| (p
<< VT_STRUCT_SHIFT
) | (t
& VT_TYPEN
);
1849 /* store value in lvalue pushed on stack */
1854 r
= gv(); /* generate value */
1856 ft
= vstack_ptr
[-4];
1857 fc
= vstack_ptr
[-3];
1858 if ((ft
& VT_VALMASK
) == VT_LLOCAL
) {
1860 load(t
, VT_LOCAL
| VT_LVAL
, fc
);
1861 ft
= (ft
& ~VT_VALMASK
) | t
;
1867 /* post defines POST/PRE add. c is the token ++ or -- */
1873 vpush(); /* room for returned value */
1874 vpush(); /* save lvalue */
1876 vpush(); /* save value */
1878 /* duplicate value */
1880 load(r1
, r
, 0); /* move r to r1 */
1881 vstack_ptr
[-6] = (vt
& VT_TYPE
) | r1
;
1885 vset(VT_CONST
, c
- TOK_MID
);
1887 vstore(); /* store value */
1892 /* enum/struct/union declaration */
1895 int a
, t
, b
, v
, size
, align
, maxalign
, c
;
1896 Sym
*slast
, *s
, *ss
;
1898 a
= tok
; /* save decl type */
1903 /* struct already defined ? return it */
1904 /* XXX: check consistency */
1905 if (s
= sym_find(v
| SYM_STRUCT
)) {
1907 error("invalid type");
1913 s
= sym_push(v
| SYM_STRUCT
, a
, 0);
1914 /* put struct/union/enum name in type */
1916 u
= u
| (v
<< VT_STRUCT_SHIFT
);
1921 error("struct/union/enum already defined");
1922 /* cannot be empty */
1927 if (a
== TOK_ENUM
) {
1934 sym_push(v
, VT_CONST
, c
);
1941 t
= type_decl(&v
, b
, TYPE_DIRECT
);
1942 if (t
& (VT_FUNC
| VT_TYPEDEF
))
1943 error("invalid type");
1944 /* XXX: align & correct type size */
1946 size
= type_size(t
, &align
);
1947 if (a
== TOK_STRUCT
) {
1948 c
= (c
+ align
- 1) & -align
;
1949 ss
= sym_push(v
, t
, c
);
1952 ss
= sym_push(v
, t
, 0);
1956 if (align
> maxalign
)
1960 if (tok
== ';' || tok
== -1)
1971 /* size for struct/union, dummy for enum */
1972 s
->c
= (c
+ maxalign
- 1) & -maxalign
;
1977 /* return 0 if no type declaration. otherwise, return the basic type
1979 XXX: A '2' is ored to ensure non zero return if int type.
1988 if (tok
== TOK_ENUM
) {
1989 t
|= struct_decl(VT_ENUM
);
1990 } else if (tok
== TOK_STRUCT
|| tok
== TOK_UNION
) {
1991 t
|= struct_decl(VT_STRUCT
);
1993 if (tok
== TOK_CHAR
) {
1995 } else if (tok
== TOK_VOID
) {
1997 } else if (tok
== TOK_SHORT
) {
1999 } else if (tok
== TOK_INT
|
2000 (tok
>= TOK_CONST
& tok
<= TOK_INLINE
)) {
2002 } else if (tok
== TOK_FLOAT
|| tok
== TOK_DOUBLE
) {
2003 /* We allow that to compile standard headers */
2004 // warning("floats not supported");
2005 } else if (tok
== TOK_EXTERN
) {
2007 } else if (tok
== TOK_STATIC
) {
2009 } else if (tok
== TOK_UNSIGNED
) {
2011 } else if (tok
== TOK_TYPEDEF
) {
2015 if (!s
|| !(s
->t
& VT_TYPEDEF
))
2017 t
|= (s
->t
& ~VT_TYPEDEF
);
2032 /* function declaration */
2037 while (tok
!= ')') {
2038 /* read param name and compute offset */
2039 if (l
!= FUNC_OLD
) {
2040 if (!(pt
= ist())) {
2042 error("invalid type");
2048 if (pt
& VT_VOID
&& tok
== ')')
2051 pt
= type_decl(&n
, pt
, TYPE_DIRECT
| TYPE_ABSTRACT
);
2055 pt
= 0; /* int type */
2058 /* array must be transformed to pointer according to ANSI C */
2060 /* XXX: size will be different someday */
2062 s
= sym_push(n
| SYM_FIELD
, VT_LOCAL
| VT_LVAL
| pt
, a
);
2067 if (l
== FUNC_NEW
&& tok
== TOK_DOTS
) {
2076 /* we push a anonymous symbol which will contain the function prototype */
2078 s
= sym_push(p
, t
, l
);
2080 t
= VT_FUNC
| (p
<< VT_STRUCT_SHIFT
);
2081 } else if (tok
== '[') {
2082 /* array definition */
2088 error("invalid array size");
2091 /* parse next post type */
2094 /* we push a anonymous symbol which will contain the array
2098 t
= VT_ARRAY
| VT_PTR
| (p
<< VT_STRUCT_SHIFT
);
2103 /* Read a type declaration (except basic type), and return the
2104 type. If v is true, then also put variable name in 'vc' */
2105 int type_decl(int *v
, int t
, int td
)
2110 t
= t
& -3; /* suppress the ored '2' */
2111 while (tok
== '*') {
2113 while (tok
== TOK_CONST
|| tok
== TOK_VOLATILE
)
2118 /* recursive type */
2119 /* XXX: incorrect if abstract type for functions (e.g. 'int ()') */
2122 u
= type_decl(v
, 0, td
);
2126 /* type identifier */
2127 if (tok
>= TOK_IDENT
&& (td
& TYPE_DIRECT
)) {
2131 if (!(td
& TYPE_ABSTRACT
))
2132 expect("identifier");
2136 /* append t at the end of u */
2142 s
= sym_find((unsigned)p
>> VT_STRUCT_SHIFT
);
2152 /* define a new external reference to a function 'v' of type 'u' */
2153 Sym
*external_func(v
, u
)
2159 n
= (int)dlsym(0, get_tok_str(v
, 0));
2161 /* used to generate symbol list */
2162 s
= sym_push1(&global_stack
,
2163 v
, u
| VT_CONST
| VT_LVAL
| VT_FORWARD
, 0);
2166 s
= sym_push1(&global_stack
,
2167 v
, u
| VT_CONST
| VT_LVAL
, n
);
2179 vt
= pointed_type(vt
);
2180 if (!(vt
& VT_ARRAY
)) /* an array is never an lvalue */
2186 int n
, t
, ft
, fc
, p
, r
;
2189 if (tok
== TOK_NUM
|| tok
== TOK_CCHAR
) {
2190 vset(VT_CONST
, tokc
);
2192 } else if (tok
== TOK_STR
) {
2194 /* generate (char *) type */
2195 vset(VT_CONST
| mk_pointer(VT_TYPE
), glo
);
2196 while (tok
== TOK_STR
) {
2197 ts
= (TokenSym
*)tokc
;
2198 memcpy((void *)glo
, ts
->str
, ts
->len
);
2209 ft
= type_decl(&n
, t
, TYPE_ABSTRACT
);
2212 vt
= (vt
& VT_TYPEN
) | ft
;
2217 } else if (t
== '*') {
2220 } else if (t
== '&') {
2223 vt
= mk_pointer(vt
& VT_LVALN
);
2227 if ((vt
& (VT_CONST
| VT_LVAL
)) == VT_CONST
)
2229 else if ((vt
& VT_VALMASK
) == VT_CMP
)
2232 vset(VT_JMP
, gtst(1, 0));
2243 if (t
== TOK_SIZEOF
) {
2244 /* XXX: some code can be generated */
2248 vt
= type_decl(&n
, t
, TYPE_ABSTRACT
);
2255 vset(VT_CONST
, type_size(vt
, &t
));
2257 if (t
== TOK_INC
| t
== TOK_DEC
) {
2260 } else if (t
== '-') {
2270 error("undefined symbol");
2271 /* for simple function calls, we tolerate undeclared
2272 external reference */
2274 sym_push1(&global_stack
, p
, 0, FUNC_OLD
);
2275 /* int() function */
2276 s
= external_func(t
, VT_FUNC
| (p
<< VT_STRUCT_SHIFT
));
2279 /* if forward reference, we must point to s->c */
2280 if (vt
& VT_FORWARD
)
2285 /* post operations */
2287 if (tok
== TOK_INC
| tok
== TOK_DEC
) {
2290 } else if (tok
== '.' | tok
== TOK_ARROW
) {
2292 if (tok
== TOK_ARROW
)
2297 /* expect pointer on structure */
2298 if (!(vt
& VT_STRUCT
))
2299 expect("struct or union");
2300 s
= sym_find(((unsigned)vt
>> VT_STRUCT_SHIFT
) | SYM_STRUCT
);
2303 while (s
= s
->next
) {
2308 error("field not found");
2309 /* add field offset to pointer */
2310 vt
= vt
& VT_TYPEN
; /* change type to int */
2312 vset(VT_CONST
, s
->c
);
2314 /* change type to field type, and set to lvalue */
2315 vt
= (vt
& VT_TYPEN
) | s
->t
;
2316 /* an array is never an lvalue */
2317 if (!(vt
& VT_ARRAY
))
2320 } else if (tok
== '[') {
2327 } else if (tok
== '(') {
2329 save_regs(); /* save used temporary registers */
2330 /* lvalue is implied */
2332 if ((vt
& VT_VALMASK
) != VT_CONST
) {
2333 /* evaluate function address */
2335 o(0x50 + r
); /* push r */
2340 #ifdef INVERT_FUNC_PARAMS
2342 int *str
, len
, parlevel
, *saved_macro_ptr
;
2345 /* read each argument and store it on a stack */
2346 /* XXX: merge it with macro args ? */
2348 while (tok
!= ')') {
2352 while ((parlevel
> 0 || (tok
!= ')' && tok
!= ',')) &&
2356 else if (tok
== ')')
2358 tok_add2(&str
, &len
, tok
, tokc
);
2361 tok_add(&str
, &len
, -1); /* end of file added */
2362 tok_add(&str
, &len
, 0);
2363 sym_push1(&args
, 0, 0, (int)str
);
2371 /* now generate code in reverse order by reading the stack */
2372 saved_macro_ptr
= macro_ptr
;
2376 macro_ptr
= (int *)args
->c
;
2380 free((int *)args
->c
);
2381 sym_pop(&args
, args
->prev
);
2383 macro_ptr
= saved_macro_ptr
;
2389 while (tok
!= ')') {
2398 if ((ft
& VT_VALMASK
) == VT_CONST
) {
2399 /* forward reference */
2400 if (ft
& VT_FORWARD
) {
2401 *(int *)fc
= psym(0xe8, *(int *)fc
);
2403 oad(0xe8, fc
- ind
- 5);
2405 oad(0x2494ff, t
); /* call *xxx(%esp) */
2410 /* get return type */
2411 s
= sym_find((unsigned)ft
>> VT_STRUCT_SHIFT
);
2412 vt
= s
->t
| 0; /* return register is eax */
2425 (tok
>= TOK_A_MOD
& tok
<= TOK_A_DIV
) |
2426 tok
== TOK_A_XOR
| tok
== TOK_A_OR
|
2427 tok
== TOK_A_SHL
| tok
== TOK_A_SAR
) {
2434 /* XXX: be more precise */
2435 if ((vt
& VT_PTR
) != (vstack_ptr
[-2] & VT_PTR
))
2436 warning("incompatible type");
2454 while ((l
== 0 & (tok
== '*' | tok
== '/' | tok
== '%')) |
2455 (l
== 1 & (tok
== '+' | tok
== '-')) |
2456 (l
== 2 & (tok
== TOK_SHL
| tok
== TOK_SAR
)) |
2457 (l
== 3 & ((tok
>= TOK_ULE
& tok
<= TOK_GT
) |
2458 tok
== TOK_ULT
| tok
== TOK_UGE
)) |
2459 (l
== 4 & (tok
== TOK_EQ
| tok
== TOK_NE
)) |
2460 (l
== 5 & tok
== '&') |
2461 (l
== 6 & tok
== '^') |
2462 (l
== 7 & tok
== '|') |
2463 (l
== 8 & tok
== TOK_LAND
) |
2464 (l
== 9 & tok
== TOK_LOR
)) {
2474 /* only used if non constant */
2482 if (tok
!= TOK_LAND
) {
2502 if (tok
!= TOK_LOR
) {
2515 /* XXX: better constant handling */
2518 int t
, u
, c
, r1
, r2
;
2545 vt
= (vt
& VT_TYPE
) | r1
;
2567 if ((vt
& (VT_CONST
| VT_LVAL
)) != VT_CONST
)
2573 void block(int *bsym
, int *csym
, int *case_sym
, int *def_sym
, int case_reg
)
2578 if (tok
== TOK_IF
) {
2585 block(bsym
, csym
, case_sym
, def_sym
, case_reg
);
2587 if (c
== TOK_ELSE
) {
2591 block(bsym
, csym
, case_sym
, def_sym
, case_reg
);
2592 gsym(d
); /* patch else jmp */
2595 } else if (tok
== TOK_WHILE
) {
2603 block(&a
, &b
, case_sym
, def_sym
, case_reg
);
2604 oad(0xe9, d
- ind
- 5); /* jmp */
2607 } else if (tok
== '{') {
2613 block(bsym
, csym
, case_sym
, def_sym
, case_reg
);
2614 /* pop locally defined symbols */
2615 sym_pop(&local_stack
, s
);
2617 } else if (tok
== TOK_RETURN
) {
2624 rsym
= gjmp(rsym
); /* jmp */
2625 } else if (tok
== TOK_BREAK
) {
2628 error("cannot break");
2629 *bsym
= gjmp(*bsym
);
2632 } else if (tok
== TOK_CONTINUE
) {
2635 error("cannot continue");
2636 *csym
= gjmp(*csym
);
2639 } else if (tok
== TOK_FOR
) {
2659 oad(0xe9, d
- ind
- 5); /* jmp */
2663 block(&a
, &b
, case_sym
, def_sym
, case_reg
);
2664 oad(0xe9, c
- ind
- 5); /* jmp */
2668 if (tok
== TOK_DO
) {
2673 block(&a
, &b
, case_sym
, def_sym
, case_reg
);
2683 if (tok
== TOK_SWITCH
) {
2692 block(&a
, csym
, &b
, &c
, case_reg
);
2693 /* if no default, jmp after switch */
2701 if (tok
== TOK_CASE
) {
2711 *case_sym
= gtst(1, 0);
2713 block(bsym
, csym
, case_sym
, def_sym
, case_reg
);
2715 if (tok
== TOK_DEFAULT
) {
2721 error("too many 'default'");
2723 block(bsym
, csym
, case_sym
, def_sym
, case_reg
);
2725 if (tok
== TOK_GOTO
) {
2727 s
= sym_find1(label_stack
, tok
);
2728 /* put forward definition if needed */
2730 s
= sym_push1(&label_stack
, tok
, VT_FORWARD
, 0);
2731 /* label already defined */
2732 if (s
->t
& VT_FORWARD
)
2733 s
->c
= gjmp(s
->c
); /* jmp xxx */
2735 oad(0xe9, s
->c
- ind
- 5); /* jmp xxx */
2744 s
= sym_find1(label_stack
, b
);
2746 if (!(s
->t
& VT_FORWARD
))
2747 error("multiple defined label");
2752 sym_push1(&label_stack
, b
, 0, ind
);
2754 block(bsym
, csym
, case_sym
, def_sym
, case_reg
);
2756 /* expression case: go backward of one token */
2757 /* XXX: currently incorrect if number/string/char */
2768 /* 'l' is VT_LOCAL or VT_CONST to define default storage type */
2771 int *a
, t
, b
, size
, align
, v
, u
, n
;
2775 if ((b
& (VT_ENUM
| VT_STRUCT
)) && tok
== ';') {
2776 /* we accept no variable after */
2780 while (1) { /* iterate thru each declaration */
2781 t
= type_decl(&v
, b
, TYPE_DIRECT
);
2784 expect("function defintion");
2785 /* patch forward references */
2786 if ((sym
= sym_find(v
)) && (sym
->t
& VT_FORWARD
)) {
2789 sym
->t
= VT_CONST
| VT_LVAL
| t
;
2791 /* put function address */
2792 sym_push1(&global_stack
, v
, VT_CONST
| VT_LVAL
| t
, ind
);
2794 /* push a dummy symbol to enable local sym storage */
2795 sym_push1(&local_stack
, 0, 0, 0);
2796 /* define parameters */
2797 sym
= sym_find((unsigned)t
>> VT_STRUCT_SHIFT
);
2798 while (sym
= sym
->next
)
2799 sym_push(sym
->v
& ~SYM_FIELD
, sym
->t
, sym
->c
);
2801 o(0xe58955); /* push %ebp, mov %esp, %ebp */
2802 a
= (int *)oad(0xec81, 0); /* sub $xxx, %esp */
2804 block(0, 0, 0, 0, 0);
2806 o(0xc3c9); /* leave, ret */
2807 *a
= (-loc
+ 3) & -4; /* align local size to word &
2808 save local variables */
2809 sym_pop(&label_stack
, 0); /* reset label stack */
2810 sym_pop(&local_stack
, 0); /* reset local stack */
2813 if (b
& VT_TYPEDEF
) {
2814 /* save typedefed type */
2815 sym_push(v
, t
| VT_TYPEDEF
, 0);
2816 } else if (t
& VT_FUNC
) {
2817 /* XXX: incorrect to flush, but needed while
2818 waiting for function prototypes */
2819 /* external function definition */
2820 external_func(v
, t
);
2822 /* not lvalue if array */
2823 if (!(t
& VT_ARRAY
))
2825 if (b
& VT_EXTERN
) {
2826 /* external variable */
2827 /* XXX: factorize with external function def */
2828 n
= (int)dlsym(NULL
, get_tok_str(v
, 0));
2830 error("unknown external variable");
2831 sym_push(v
, VT_CONST
| t
, n
);
2837 size
= type_size(t
, &align
);
2839 error("invalid size");
2840 if ((u
& VT_VALMASK
) == VT_LOCAL
) {
2841 /* allocate space down on the stack */
2842 loc
= (loc
- size
) & -align
;
2843 sym_push(v
, u
, loc
);
2845 /* allocate space up in the data space */
2846 glo
= (glo
+ align
- 1) & -align
;
2847 sym_push(v
, u
, glo
);
2862 /* open a dynamic library so that its symbol are available for
2863 compiled programs */
2864 void open_dll(char *libname
)
2869 snprintf(buf
, sizeof(buf
), "lib%s.so", libname
);
2870 h
= dlopen(buf
, RTLD_GLOBAL
| RTLD_LAZY
);
2872 error((char *)dlerror());
2875 int main(int argc
, char **argv
)
2882 include_paths
[0] = "/usr/include";
2883 include_paths
[1] = "/usr/lib/tcc";
2884 include_paths
[2] = "/usr/local/lib/tcc";
2885 nb_include_paths
= 3;
2887 /* add all tokens */
2888 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\0float\0double\0short\0struct\0union\0typedef\0default\0enum\0sizeof\0define\0include\0ifdef\0ifndef\0elif\0endif\0defined\0undef\0main\0";
2892 tok_alloc(p
, r
- p
- 1);
2896 /* standard defines */
2897 define_symbol("__STDC__");
2899 define_symbol("__i386__");
2904 if (optind
>= argc
) {
2905 printf("tcc version 0.9 - Tiny C Compiler - Copyright (C) 2001 Fabrice Bellard\n"
2906 "usage: tcc [-Idir] [-Dsym] [-llib] infile [infile_arg...]\n");
2913 if (nb_include_paths
>= INCLUDE_PATHS_MAX
)
2914 error("too many include paths");
2915 include_paths
[nb_include_paths
++] = r
+ 2;
2916 } else if (r
[1] == 'D') {
2917 define_symbol(r
+ 2);
2918 } else if (r
[1] == 'l') {
2921 fprintf(stderr
, "invalid option -- '%s'\n", r
);
2927 filename
= argv
[optind
];
2929 file
= fopen(filename
, "r");
2934 include_stack_ptr
= include_stack
;
2935 ifdef_stack_ptr
= ifdef_stack
;
2937 glo
= (int)malloc(DATA_SIZE
);
2938 memset((void *)glo
, 0, DATA_SIZE
);
2939 prog
= (int)malloc(TEXT_SIZE
);
2940 vstack_ptr
= vstack
;
2941 anon_sym
= 1 << (31 - VT_STRUCT_SHIFT
);
2944 ch
= '\n'; /* needed to parse correctly first preprocessor command */
2948 expect("declaration");
2952 f
= fopen(argv
[optind
+ 1], "w");
2953 fwrite((void *)prog
, 1, ind
- prog
, f
);
2958 s
= sym_find(TOK_MAIN
);
2960 error("main() not defined");
2961 t
= (int (*)())s
->c
;
2965 return (*t
)(argc
- optind
, argv
+ optind
);