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 #define TEXT_SIZE 50000
27 #define DATA_SIZE 50000
28 #define INCLUDE_STACK_SIZE 32
29 #define IFDEF_STACK_SIZE 64
30 #define VSTACK_SIZE 64
31 #define STRING_MAX_SIZE 1024
32 #define INCLUDE_PATHS_MAX 32
36 /* token symbol management */
37 typedef struct TokenSym
{
38 struct TokenSym
*next
;
39 int tok
; /* token number */
44 /* symbol management */
46 int v
; /* symbol token */
47 int t
; /* associated type */
48 int c
; /* associated number */
49 struct Sym
*next
; /* next related symbol */
50 struct Sym
*prev
; /* prev symbol in stack */
53 #define SYM_STRUCT 0x40000000 /* struct/union/enum symbol space */
54 #define SYM_FIELD 0x20000000 /* struct/union field symbol space */
56 #define FUNC_NEW 1 /* ansi function prototype */
57 #define FUNC_OLD 2 /* old function prototype */
58 #define FUNC_ELLIPSIS 3 /* ansi function prototype with ... */
60 /* field t for macros */
61 #define MACRO_OBJ 0 /* object like macro */
62 #define MACRO_FUNC 1 /* function like macro */
70 /* loc : local variable index
71 glo : global variable index
75 anon_sym: anonymous symbol index
78 int tok
, tok1
, tokc
, rsym
, anon_sym
,
79 prog
, ind
, loc
, glo
, vt
, vc
, const_wanted
, line_num
;
80 TokenSym
*first_ident
;
81 char token_buf
[STRING_MAX_SIZE
+ 1];
83 Sym
*define_stack
, *global_stack
, *local_stack
, *label_stack
;
85 int vstack
[VSTACK_SIZE
], *vstack_ptr
;
86 int *macro_ptr
, *macro_ptr_allocated
;
87 IncludeFile include_stack
[INCLUDE_STACK_SIZE
], *include_stack_ptr
;
88 int ifdef_stack
[IFDEF_STACK_SIZE
], *ifdef_stack_ptr
;
89 char *include_paths
[INCLUDE_PATHS_MAX
];
92 /* The current value can be: */
93 #define VT_VALMASK 0x000f
94 #define VT_CONST 0x000a /* constant in vc
95 (must be first non register value) */
96 #define VT_LLOCAL 0x000b /* lvalue, offset on stack */
97 #define VT_LOCAL 0x000c /* offset on stack */
98 #define VT_CMP 0x000d /* the value is stored in processor flags (in vc) */
99 #define VT_JMP 0x000e /* value is the consequence of jmp true */
100 #define VT_JMPI 0x000f /* value is the consequence of jmp false */
101 #define VT_LVAL 0x0010 /* var is an lvalue */
102 #define VT_LVALN -17 /* ~VT_LVAL */
103 #define VT_FORWARD 0x0020 /* value is forward reference
104 (only used for functions) */
106 #define VT_VOID 0x00040
107 #define VT_BYTE 0x00080 /* byte type */
108 #define VT_PTR 0x00100 /* pointer increment */
109 #define VT_UNSIGNED 0x00200 /* unsigned type */
110 #define VT_ARRAY 0x00400 /* array type (only used in parsing) */
111 #define VT_ENUM 0x00800 /* enum definition */
112 #define VT_FUNC 0x01000 /* function type */
113 #define VT_STRUCT 0x002000 /* struct/union definition */
114 #define VT_TYPEDEF 0x004000 /* typedef definition */
115 #define VT_EXTERN 0x008000 /* extern definition */
116 #define VT_STATIC 0x010000 /* static variable */
117 #define VT_STRUCT_SHIFT 17 /* structure/enum name shift (12 bits lefts) */
119 #define VT_TYPE 0xffffffc0 /* type mask */
120 #define VT_TYPEN 0x0000003f /* ~VT_TYPE */
121 #define VT_FUNCN -4097 /* ~VT_FUNC */
128 /* warning: the following compare tokens depend on i386 asm code */
140 #define TOK_LAND 0xa0
144 #define TOK_MID 0xa3 /* inc/dec, to void constant */
146 #define TOK_ARROW 0xa7
147 #define TOK_DOTS 0xa8 /* three dots */
148 #define TOK_SHR 0xa9 /* unsigned shift right */
149 #define TOK_UDIV 0xb0 /* unsigned division */
150 #define TOK_UMOD 0xb1 /* unsigned modulo */
151 #define TOK_PDIV 0xb2 /* fast division with undefined rounding for pointers */
152 #define TOK_NUM 0xb3 /* number in tokc */
153 #define TOK_CCHAR 0xb4 /* char constant in tokc */
154 #define TOK_STR 0xb5 /* pointer to string in tokc */
156 #define TOK_TWOSHARPS 0xb6 /* ## preprocessing token */
158 #define TOK_SHL 0x01 /* shift left */
159 #define TOK_SAR 0x02 /* signed shift right */
161 /* assignement operators : normal operator or 0x80 */
162 #define TOK_A_MOD 0xa5
163 #define TOK_A_AND 0xa6
164 #define TOK_A_MUL 0xaa
165 #define TOK_A_ADD 0xab
166 #define TOK_A_SUB 0xad
167 #define TOK_A_DIV 0xaf
168 #define TOK_A_XOR 0xde
169 #define TOK_A_OR 0xfc
170 #define TOK_A_SHL 0x81
171 #define TOK_A_SAR 0x82
173 /* all identificators and strings have token above that */
174 #define TOK_IDENT 256
195 /* ignored types Must have contiguous values */
204 /* unsupported type */
216 /* preprocessor only */
226 /* special identifiers */
240 void macro_subst(int **tok_str
, int *tok_len
,
241 Sym
**nested_list
, int *macro_str
);
242 int save_reg_forced(int r
);
243 int type_size(int t
, int *a
);
244 int pointed_type(int t
);
245 int pointed_size(int t
);
247 int typ(int *v
, int t
);
251 return (c
>= 'a' & c
<= 'z') |
252 (c
>= 'A' & c
<= 'Z') |
258 return c
>= '0' & c
<= '9';
264 for(f
= include_stack
; f
< include_stack_ptr
; f
++)
265 printf("In file included from %s:%d:\n", f
->filename
, f
->line_num
);
266 printf("%s:%d: ", filename
, line_num
);
269 /* XXX: use stderr ? */
270 void error(char *msg
)
277 void expect(char *msg
)
280 printf("%s expected\n", msg
);
284 void warning(char *msg
)
287 printf("warning: %s\n", msg
);
294 printf("'%c' expected\n", c
);
306 TokenSym
*tok_alloc(char *str
, int len
)
317 if (ts
->len
== len
&& !memcmp(ts
->str
, str
, len
))
322 ts
= malloc(sizeof(TokenSym
) + len
);
324 error("memory full");
328 memcpy(ts
->str
, str
, len
+ 1);
334 void add_char(char **pp
, int c
)
338 if (c
== '\'' || c
== '\"' || c
== '\\') {
339 /* XXX: could be more precise if char or string */
342 if (c
>= 32 && c
<= 126) {
349 *p
++ = '0' + ((c
>> 6) & 7);
350 *p
++ = '0' + ((c
>> 3) & 7);
351 *p
++ = '0' + (c
& 7);
357 /* XXX: buffer overflow */
358 char *get_tok_str(int v
, int c
)
360 static char buf
[STRING_MAX_SIZE
+ 1];
366 sprintf(buf
, "%d", c
);
368 } else if (v
== TOK_CCHAR
) {
375 } else if (v
== TOK_STR
) {
379 for(i
=0;i
<ts
->len
;i
++)
380 add_char(&p
, ts
->str
[i
]);
384 } else if (v
< TOK_IDENT
) {
400 /* find a symbol and return its associated structure. 's' is the top
401 of the symbol stack */
402 Sym
*sym_find1(Sym
*s
, int v
)
412 Sym
*sym_push1(Sym
**ps
, int v
, int t
, int c
)
415 s
= malloc(sizeof(Sym
));
417 error("memory full");
427 /* find a symbol in the right symbol space */
431 s
= sym_find1(local_stack
, v
);
433 s
= sym_find1(global_stack
, v
);
437 /* push a given symbol on the symbol stack */
438 Sym
*sym_push(int v
, int t
, int c
)
441 return sym_push1(&local_stack
, v
, t
, c
);
443 return sym_push1(&global_stack
, v
, t
, c
);
446 /* pop symbols until top reaches 'b' */
447 void sym_pop(Sym
**ps
, Sym
*b
)
462 /* read next char from current input file */
468 if (include_stack_ptr
== include_stack
)
470 /* pop include stack */
474 file
= include_stack_ptr
->file
;
475 filename
= include_stack_ptr
->filename
;
476 line_num
= include_stack_ptr
->line_num
;
481 // printf("ch1=%c 0x%x\n", ch1, ch1);
484 /* input with '\\n' handling */
490 if (ch
== '\\' && ch1
== '\n') {
494 //printf("ch=%c 0x%x\n", ch, ch);
497 /* same as minp, but also skip comments */
498 /* XXX: skip strings & chars */
506 /* single line C++ comments */
508 while (ch1
!= '\n' && ch1
!= -1)
511 ch
= ' '; /* return space */
512 } else if (ch1
== '*') {
518 if (c
== '*' && ch1
== '/') {
520 ch
= ' '; /* return space */
534 while (ch
== ' ' || ch
== '\t')
538 /* skip block of text until #else, #elif or #endif. skip also pairs of
540 void preprocess_skip()
556 (tok
== TOK_ELSE
|| tok
== TOK_ELIF
|| tok
== TOK_ENDIF
))
558 if (tok
== TOK_IF
|| tok
== TOK_IFDEF
|| tok
== TOK_IFNDEF
)
560 else if (tok
== TOK_ENDIF
)
566 /* parse until eol and add given char */
576 if ((n
+ 1) >= size
) {
578 str
= realloc(str
, size
);
580 error("memory full");
582 if (ch
== -1 || ch
== '\n') {
593 void tok_add(int **tok_str
, int *tok_len
, int t
)
598 if ((len
& 63) == 0) {
599 str
= realloc(str
, (len
+ 64) * sizeof(int));
608 void tok_add2(int **tok_str
, int *tok_len
, int t
, int c
)
610 tok_add(tok_str
, tok_len
, t
);
611 if (t
== TOK_NUM
|| t
== TOK_CCHAR
|| t
== TOK_STR
)
612 tok_add(tok_str
, tok_len
, c
);
615 /* eval an expression for #if/#elif */
616 int expr_preprocess()
619 int *saved_macro_ptr
;
627 next(); /* do macro subst */
628 if (tok
== TOK_DEFINED
) {
633 c
= sym_find1(define_stack
, tok
) != 0;
638 } else if (tok
>= TOK_IDENT
) {
639 /* if undefined macro */
643 tok_add2(&str
, &len
, tok
, tokc
);
645 tok_add(&str
, &len
, -1); /* simulate end of file */
646 tok_add(&str
, &len
, 0);
647 /* now evaluate C constant expression */
648 saved_macro_ptr
= macro_ptr
;
652 macro_ptr
= saved_macro_ptr
;
658 void tok_print(int *str
)
667 if (t
== TOK_NUM
|| t
== TOK_CCHAR
|| t
== TOK_STR
)
669 printf(" %s", get_tok_str(t
, c
));
677 int size
, i
, c
, v
, t
, *str
, len
;
678 char buf
[1024], *q
, *p
;
681 Sym
**ps
, *first
, *s
;
686 if (tok
== TOK_DEFINE
) {
689 /* XXX: should check if same macro (ANSI) */
690 if (sym_find1(define_stack
, v
))
691 warning("macro redefinition");
694 /* '(' must be just after macro definition for MACRO_FUNC */
700 s
= sym_push1(&define_stack
, tok
| SYM_FIELD
, 0, 0);
714 if (ch
== '\n' || ch
== -1)
717 tok_add2(&str
, &len
, tok
, tokc
);
719 tok_add(&str
, &len
, 0);
721 printf("define %s %d: ", get_tok_str(v
, 0), t
);
724 s
= sym_push1(&define_stack
, v
, t
, (int)str
);
726 } else if (tok
== TOK_UNDEF
) {
728 s
= sym_find1(define_stack
, tok
);
729 /* undefine symbol by putting an invalid name */
732 } else if (tok
== TOK_INCLUDE
) {
737 } else if (ch
== '\"') {
742 while (ch
!= c
&& ch
!= '\n' && ch
!= -1) {
743 if ((q
- buf
) < sizeof(buf
) - 1)
748 if (include_stack_ptr
>= include_stack
+ INCLUDE_STACK_SIZE
)
749 error("memory full");
751 /* first search in current dir if "header.h" */
752 /* XXX: buffer overflow */
754 p
= strrchr(filename
, '/');
756 size
= p
+ 1 - filename
;
757 memcpy(buf1
, filename
, size
);
760 f
= fopen(buf1
, "r");
764 /* now search in standard include path */
765 for(i
=nb_include_paths
- 1;i
>=0;i
--) {
766 strcpy(buf1
, include_paths
[i
]);
769 f
= fopen(buf1
, "r");
773 error("include file not found");
776 /* push current file in stack */
777 /* XXX: fix current line init */
778 include_stack_ptr
->file
= file
;
779 include_stack_ptr
->filename
= filename
;
780 include_stack_ptr
->line_num
= line_num
;
783 filename
= strdup(buf1
);
786 } else if (tok
== TOK_IFNDEF
) {
789 } else if (tok
== TOK_IF
) {
790 c
= expr_preprocess();
792 } else if (tok
== TOK_IFDEF
) {
796 c
= (sym_find1(define_stack
, tok
) != 0) ^ c
;
798 if (ifdef_stack_ptr
>= ifdef_stack
+ IFDEF_STACK_SIZE
)
799 error("memory full");
800 *ifdef_stack_ptr
++ = c
;
802 } else if (tok
== TOK_ELSE
) {
803 if (ifdef_stack_ptr
== ifdef_stack
||
804 (ifdef_stack_ptr
[-1] & 2))
805 error("#else after #else");
806 c
= (ifdef_stack_ptr
[-1] ^= 3);
808 } else if (tok
== TOK_ELIF
) {
809 if (ifdef_stack_ptr
== ifdef_stack
||
810 ifdef_stack_ptr
[-1] > 1)
811 error("#elif after #else");
812 c
= expr_preprocess();
813 ifdef_stack_ptr
[-1] = c
;
819 } else if (tok
== TOK_ENDIF
) {
820 if (ifdef_stack_ptr
== ifdef_stack
)
824 /* ignore other preprocess commands or #! for C scripts */
825 while (ch
!= '\n' && ch
!= -1)
829 /* read a number in base b */
835 if (ch
>= 'a' & ch
<= 'f')
837 else if (ch
>= 'A' & ch
<= 'F')
851 /* read a character for string or char constant and eval escape codes */
884 /* return next token without macro substitution */
895 while (ch
== ' ' || ch
== 9)
898 /* preprocessor command if # at start of line after
903 if (ch
!= ' ' && ch
!= '\t' && ch
!= '\f')
909 while (isid(ch
) | isnum(ch
)) {
910 if (q
>= token_buf
+ STRING_MAX_SIZE
)
911 error("ident too long");
916 ts
= tok_alloc(token_buf
, q
- token_buf
);
918 } else if (isnum(ch
)) {
924 if (ch
== 'x' || ch
== 'X') {
930 /* XXX: add unsigned constant support (ANSI) */
931 while (ch
== 'L' || ch
== 'l' || ch
== 'U' || ch
== 'u')
934 } else if (ch
== '\'') {
941 } else if (ch
== '\"') {
947 error("unterminated string");
948 if (q
>= token_buf
+ STRING_MAX_SIZE
)
949 error("string too long");
953 tokc
= (int)tok_alloc(token_buf
, q
- token_buf
);
957 q
= "<=\236>=\235!=\225&&\240||\241++\244--\242==\224<<\1>>\2+=\253-=\255*=\252/=\257%=\245&=\246^=\336|=\374->\247..\250##\266";
962 if (*q
== tok
& q
[1] == ch
) {
965 /* three chars tests */
966 if (tok
== TOK_SHL
| tok
== TOK_SAR
) {
971 } else if (tok
== TOK_DOTS
) {
973 error("parse error");
980 /* single char substitutions */
988 /* return next token without macro substitution. Can read input from
996 if (tok
== TOK_NUM
|| tok
== TOK_CCHAR
|| tok
== TOK_STR
)
1004 /* substitute args in macro_str and return allocated string */
1005 int *macro_arg_subst(Sym
**nested_list
, int *macro_str
, Sym
*args
)
1007 int *st
, last_tok
, t
, c
, notfirst
, *str
, len
;
1023 s
= sym_find1(args
, t
);
1025 token_buf
[0] = '\0';
1027 /* XXX: buffer overflow */
1031 strcat(token_buf
, " ");
1034 if (t
== TOK_NUM
|| t
== TOK_CCHAR
|| t
== TOK_STR
)
1036 strcat(token_buf
, get_tok_str(t
, c
));
1040 printf("stringize: %s\n", token_buf
);
1043 ts
= tok_alloc(token_buf
, strlen(token_buf
));
1044 tok_add2(&str
, &len
, TOK_STR
, (int)ts
);
1046 tok_add(&str
, &len
, t
);
1048 } else if (t
== TOK_NUM
|| t
== TOK_CCHAR
|| t
== TOK_STR
) {
1049 tok_add2(&str
, &len
, t
, *macro_ptr
++);
1051 s
= sym_find1(args
, t
);
1054 /* if '##' is present before or after , no arg substitution */
1055 if (*macro_str
== TOK_TWOSHARPS
|| last_tok
== TOK_TWOSHARPS
) {
1057 tok_add(&str
, &len
, *st
++);
1059 macro_subst(&str
, &len
, nested_list
, st
);
1062 tok_add(&str
, &len
, t
);
1067 tok_add(&str
, &len
, 0);
1071 /* handle the '##' operator */
1072 int *macro_twosharps(int *macro_str
)
1075 int *macro_str1
, macro_str1_len
, *macro_ptr1
;
1086 if (*macro_ptr
== TOK_TWOSHARPS
) {
1088 macro_ptr1
= macro_ptr
;
1093 if (t
== TOK_NUM
|| t
== TOK_CCHAR
|| t
== TOK_STR
)
1095 /* XXX: we handle only most common cases:
1096 ident + ident or ident + number */
1097 if (tok
>= TOK_IDENT
&&
1098 (t
>= TOK_IDENT
|| t
== TOK_NUM
)) {
1099 /* XXX: buffer overflow */
1100 p
= get_tok_str(tok
, tokc
);
1101 strcpy(token_buf
, p
);
1102 p
= get_tok_str(t
, c
);
1103 strcat(token_buf
, p
);
1104 ts
= tok_alloc(token_buf
, strlen(token_buf
));
1105 tok_add2(¯o_str1
, ¯o_str1_len
, ts
->tok
, 0);
1107 /* cannot merge tokens: skip '##' */
1108 macro_ptr
= macro_ptr1
;
1112 tok_add2(¯o_str1
, ¯o_str1_len
, tok
, tokc
);
1115 tok_add(¯o_str1
, ¯o_str1_len
, 0);
1121 /* do macro substitution of macro_str and add result to
1122 (tok_str,tok_len). If macro_str is NULL, then input stream token is
1123 substituted. 'nested_list' is the list of all macros we got inside
1124 to avoid recursing. */
1125 void macro_subst(int **tok_str
, int *tok_len
,
1126 Sym
**nested_list
, int *macro_str
)
1129 int *str
, parlevel
, len
, *mstr
, t
, *saved_macro_ptr
;
1130 int mstr_allocated
, *macro_str1
;
1132 saved_macro_ptr
= macro_ptr
;
1133 macro_ptr
= macro_str
;
1136 /* first scan for '##' operator handling */
1137 macro_str1
= macro_twosharps(macro_str
);
1138 macro_ptr
= macro_str1
;
1145 /* if symbol is a macro, prepare substitution */
1146 s
= sym_find1(define_stack
, tok
);
1148 /* if nested substitution, do nothing */
1149 if (sym_find1(*nested_list
, tok
))
1153 if (s
->t
== MACRO_FUNC
) {
1154 /* NOTE: we do not use next_nomacro to avoid eating the
1155 next token. XXX: find better solution */
1159 while (ch
== ' ' || ch
== '\t' || ch
== '\n')
1163 if (t
!= '(') /* no macro subst */
1166 /* argument macro */
1171 while (tok
!= ')' && sa
) {
1175 while ((parlevel
> 0 || (tok
!= ')' && tok
!= ',')) &&
1179 else if (tok
== ')')
1181 tok_add2(&str
, &len
, tok
, tokc
);
1184 tok_add(&str
, &len
, 0);
1185 sym_push1(&args
, sa
->v
& ~SYM_FIELD
, 0, (int)str
);
1193 /* now subst each arg */
1194 mstr
= macro_arg_subst(nested_list
, mstr
, args
);
1195 sym_pop(&args
, NULL
);
1198 sym_push1(nested_list
, s
->v
, 0, 0);
1199 macro_subst(tok_str
, tok_len
, nested_list
, mstr
);
1200 sym_pop(nested_list
, (*nested_list
)->prev
);
1203 /* only replace one macro while parsing input stream */
1208 /* no need to add if reading input stream */
1211 tok_add2(tok_str
, tok_len
, tok
, tokc
);
1214 macro_ptr
= saved_macro_ptr
;
1219 /* return next token with macro substitution */
1225 /* special 'ungettok' case for label parsing */
1232 /* if not reading from macro substuted string, then try to substitute */
1236 macro_subst(&ptr
, &len
, &nested_list
, NULL
);
1238 tok_add(&ptr
, &len
, 0);
1240 macro_ptr_allocated
= ptr
;
1248 /* end of macro string: free it */
1249 free(macro_ptr_allocated
);
1256 printf("token = %s\n", get_tok_str(tok
, tokc
));
1260 void swap(int *p
, int *q
)
1274 /******************************************************/
1275 /* X86 code generator */
1290 /* output a symbol and patch all calls to it */
1291 void gsym_addr(t
, a
)
1295 n
= *(int *)t
; /* next value */
1296 *(int *)t
= a
- t
- 4;
1306 /* psym is used to put an instruction with a data field which is a
1307 reference to a symbol. It is in fact the same as oad ! */
1310 /* instruction + 4 bytes data. Return the address of the data */
1320 /* XXX: generate correct pointer for forward references to functions */
1322 void load(r
, ft
, fc
)
1326 v
= ft
& VT_VALMASK
;
1328 if (v
== VT_LLOCAL
) {
1329 load(r
, VT_LOCAL
| VT_LVAL
, fc
);
1332 if ((ft
& VT_TYPE
) == VT_BYTE
)
1333 o(0xbe0f); /* movsbl */
1336 if (v
== VT_CONST
) {
1337 oad(0x05 + r
* 8, fc
); /* 0xXX, r */
1338 } else if (v
== VT_LOCAL
) {
1339 oad(0x85 + r
* 8, fc
); /* xx(%ebp), r */
1341 g(0x00 + r
* 8 + v
); /* (v), r */
1344 if (v
== VT_CONST
) {
1345 oad(0xb8 + r
, fc
); /* mov $xx, r */
1346 } else if (v
== VT_LOCAL
) {
1348 oad(0x85 + r
* 8, fc
); /* lea xxx(%ebp), r */
1349 } else if (v
== VT_CMP
) {
1350 oad(0xb8 + r
, 0); /* mov $0, r */
1351 o(0x0f); /* setxx %br */
1354 } else if (v
== VT_JMP
|| v
== VT_JMPI
) {
1356 oad(0xb8 + r
, t
); /* mov $1, r */
1357 oad(0xe9, 5); /* jmp after */
1359 oad(0xb8 + r
, t
^ 1); /* mov $0, r */
1360 } else if (v
!= r
) {
1362 o(0xc0 + r
+ v
* 8); /* mov v, r */
1368 /* WARNING: r must not be allocated on the stack */
1369 void store(r
, ft
, fc
)
1373 fr
= ft
& VT_VALMASK
;
1374 b
= (ft
& VT_TYPE
) == VT_BYTE
;
1376 if (fr
== VT_CONST
) {
1377 oad(0x05 + r
* 8, fc
); /* mov r,xxx */
1378 } else if (fr
== VT_LOCAL
) {
1379 oad(0x85 + r
* 8, fc
); /* mov r,xxx(%ebp) */
1380 } else if (ft
& VT_LVAL
) {
1381 g(fr
+ r
* 8); /* mov r, (fr) */
1382 } else if (fr
!= r
) {
1383 o(0xc0 + fr
+ r
* 8); /* mov r, fr */
1389 return psym(0xe9, t
);
1392 /* generate a test. set 'inv' to invert test */
1396 v
= vt
& VT_VALMASK
;
1398 /* fast case : can jump directly since flags are set */
1400 t
= psym((vc
- 16) ^ inv
, t
);
1401 } else if (v
== VT_JMP
|| v
== VT_JMPI
) {
1402 /* && or || optimization */
1403 if ((v
& 1) == inv
) {
1404 /* insert vc jump list in t */
1414 } else if ((vt
& (VT_VALMASK
| VT_LVAL
)) == VT_CONST
) {
1415 /* constant jmp optimization */
1416 if ((vc
!= 0) != inv
)
1423 t
= psym(0x85 ^ inv
, t
);
1428 /* generate a binary operation 'v = r op fr' instruction and modifies
1429 (vt,vc) if needed */
1430 void gen_op1(op
, r
, fr
)
1435 o(0xc0 + r
+ fr
* 8);
1436 } else if (op
== '-') {
1438 o(0xc0 + r
+ fr
* 8);
1439 } else if (op
== '&') {
1441 o(0xc0 + r
+ fr
* 8);
1442 } else if (op
== '^') {
1444 o(0xc0 + r
+ fr
* 8);
1445 } else if (op
== '|') {
1447 o(0xc0 + r
+ fr
* 8);
1448 } else if (op
== '*') {
1449 o(0xaf0f); /* imul fr, r */
1450 o(0xc0 + fr
+ r
* 8);
1451 } else if (op
== TOK_SHL
| op
== TOK_SHR
| op
== TOK_SAR
) {
1457 o(0x87); /* xchg r, %ecx */
1462 o(0xd3); /* shl/shr/sar %cl, r */
1465 else if (op
== TOK_SHR
)
1469 vt
= (vt
& VT_TYPE
) | r
;
1470 } else if (op
== '/' | op
== TOK_UDIV
| op
== TOK_PDIV
|
1471 op
== '%' | op
== TOK_UMOD
) {
1472 save_reg(2); /* save edx */
1473 t
= save_reg_forced(fr
); /* save fr and get op2 location */
1474 move_reg(0, r
); /* op1 is %eax */
1475 if (op
== TOK_UDIV
| op
== TOK_UMOD
) {
1476 o(0xf7d231); /* xor %edx, %edx, div t(%ebp), %eax */
1479 o(0xf799); /* cltd, idiv t(%ebp), %eax */
1482 if (op
== '%' | op
== TOK_UMOD
)
1486 vt
= (vt
& VT_TYPE
) | r
;
1489 o(0xc0 + r
+ fr
* 8); /* cmp fr, r */
1494 /* end of X86 code generator */
1495 /*************************************************************/
1497 int save_reg_forced(int r
)
1500 /* store register */
1501 loc
= (loc
- 4) & -3;
1502 store(r
, VT_LOCAL
, loc
);
1505 /* modify all stack values */
1506 for(p
=vstack
;p
<vstack_ptr
;p
+=2) {
1507 i
= p
[0] & VT_VALMASK
;
1513 p
[0] = (p
[0] & VT_TYPE
) | VT_LVAL
| t
;
1520 /* save r to memory. and mark it as being free */
1525 /* modify all stack values */
1526 for(p
=vstack
;p
<vstack_ptr
;p
+=2) {
1527 i
= p
[0] & VT_VALMASK
;
1535 /* find a free register. If none, save one register */
1540 /* find a free register */
1541 for(r
=0;r
<NB_REGS
;r
++) {
1542 for(p
=vstack
;p
<vstack_ptr
;p
+=2) {
1543 i
= p
[0] & VT_VALMASK
;
1551 /* no register left : free the first one on the stack (very
1552 important to start from the bottom to ensure that we don't
1553 spill registers used in gen_op()) */
1554 for(p
=vstack
;p
<vstack_ptr
;p
+=2) {
1555 r
= p
[0] & VT_VALMASK
;
1567 for(p
=vstack
;p
<vstack_ptr
;p
+=2) {
1568 r
= p
[0] & VT_VALMASK
;
1575 /* move register 's' to 'r', and flush previous value of r to memory
1585 /* convert a stack entry in register */
1589 r
= p
[0] & VT_VALMASK
;
1590 if (r
>= VT_CONST
|| (p
[0] & VT_LVAL
))
1592 load(r
, p
[0], p
[1]);
1593 p
[0] = (p
[0] & VT_TYPE
) | r
;
1599 if (vstack_ptr
>= vstack
+ VSTACK_SIZE
)
1600 error("memory full");
1603 /* cannot let cpu flags if other instruction are generated */
1604 if ((vt
& VT_VALMASK
) == VT_CMP
)
1605 gvp(vstack_ptr
- 2);
1608 void vpop(int *ft
, int *fc
)
1610 *fc
= *--vstack_ptr
;
1611 *ft
= *--vstack_ptr
;
1614 /* generate a value in a register from vt and vc */
1619 r
= gvp(vstack_ptr
- 2);
1624 /* handle constant optimizations and various machine independant opt */
1627 int fr
, ft
, fc
, r
, c1
, c2
, n
;
1631 c1
= (vt
& (VT_VALMASK
| VT_LVAL
)) == VT_CONST
;
1632 c2
= (ft
& (VT_VALMASK
| VT_LVAL
)) == VT_CONST
;
1635 case '+': vc
+= fc
; break;
1636 case '-': vc
-= fc
; break;
1637 case '&': vc
&= fc
; break;
1638 case '^': vc
^= fc
; break;
1639 case '|': vc
|= fc
; break;
1640 case '*': vc
*= fc
; break;
1642 case '/': vc
/= fc
; break; /* XXX: zero case ? */
1643 case '%': vc
%= fc
; break; /* XXX: zero case ? */
1644 case TOK_UDIV
: vc
= (unsigned)vc
/ fc
; break; /* XXX: zero case ? */
1645 case TOK_UMOD
: vc
= (unsigned)vc
% fc
; break; /* XXX: zero case ? */
1646 case TOK_SHL
: vc
<<= fc
; break;
1647 case TOK_SHR
: vc
= (unsigned)vc
>> fc
; break;
1648 case TOK_SAR
: vc
>>= fc
; break;
1650 case TOK_ULT
: vc
= (unsigned)vc
< (unsigned)fc
; break;
1651 case TOK_UGE
: vc
= (unsigned)vc
>= (unsigned)fc
; break;
1652 case TOK_EQ
: vc
= vc
== fc
; break;
1653 case TOK_NE
: vc
= vc
!= fc
; break;
1654 case TOK_ULE
: vc
= (unsigned)vc
<= (unsigned)fc
; break;
1655 case TOK_UGT
: vc
= (unsigned)vc
> (unsigned)fc
; break;
1656 case TOK_LT
: vc
= vc
< fc
; break;
1657 case TOK_GE
: vc
= vc
>= fc
; break;
1658 case TOK_LE
: vc
= vc
<= fc
; break;
1659 case TOK_GT
: vc
= vc
> fc
; break;
1661 case TOK_LAND
: vc
= vc
&& fc
; break;
1662 case TOK_LOR
: vc
= vc
|| fc
; break;
1667 /* if commutative ops, put c2 as constant */
1668 if (c1
&& (op
== '+' || op
== '&' || op
== '^' ||
1669 op
== '|' || op
== '*')) {
1674 if (c2
&& (((op
== '*' || op
== '/' || op
== TOK_UDIV
||
1677 ((op
== '+' || op
== '-' || op
== '|' || op
== '^' ||
1678 op
== TOK_SHL
|| op
== TOK_SHR
|| op
== TOK_SAR
) &&
1682 } else if (c2
&& (op
== '*' || op
== TOK_PDIV
|| op
== TOK_UDIV
)) {
1683 /* try to use shifts instead of muls or divs */
1684 if (fc
> 0 && (fc
& (fc
- 1)) == 0) {
1693 else if (op
== TOK_PDIV
)
1705 r
= gvp(vstack_ptr
- 4);
1706 fr
= gvp(vstack_ptr
- 2);
1709 /* call low level op generator */
1715 int pointed_size(int t
)
1717 return type_size(pointed_type(t
), &t
);
1720 /* generic gen_op: handles types problems */
1726 t1
= vstack_ptr
[-4];
1727 t2
= vstack_ptr
[-2];
1728 if (op
== '+' | op
== '-') {
1729 if ((t1
& VT_PTR
) && (t2
& VT_PTR
)) {
1731 error("invalid type");
1732 /* XXX: check that types are compatible */
1733 u
= pointed_size(t1
);
1736 vstack_ptr
[-2] &= ~VT_TYPE
; /* set to integer */
1739 } else if ((t1
| t2
) & VT_PTR
) {
1741 swap(vstack_ptr
- 4, vstack_ptr
- 2);
1742 swap(vstack_ptr
- 3, vstack_ptr
- 1);
1745 /* stack-4 contains pointer, stack-2 value to add */
1746 vset(VT_CONST
, pointed_size(vstack_ptr
[-4]));
1750 /* put again type if gen_opc() swaped operands */
1751 vt
= (vt
& VT_TYPEN
) | (t1
& VT_TYPE
);
1756 /* XXX: test types and compute returned value */
1757 if ((t1
| t2
) & (VT_UNSIGNED
| VT_PTR
)) {
1764 else if (op
== TOK_LT
)
1766 else if (op
== TOK_GT
)
1768 else if (op
== TOK_LE
)
1770 else if (op
== TOK_GE
)
1777 /* return type size. Put alignment at 'a' */
1778 int type_size(int t
, int *a
)
1782 /* int, enum or pointer */
1783 if (t
& VT_STRUCT
) {
1785 s
= sym_find(((unsigned)t
>> VT_STRUCT_SHIFT
) | SYM_STRUCT
);
1786 *a
= 4; /* XXX: cannot store it yet. Doing that is safe */
1788 } else if (t
& VT_ARRAY
) {
1789 s
= sym_find(((unsigned)t
>> VT_STRUCT_SHIFT
));
1790 return type_size(s
->t
, a
) * s
->c
;
1791 } else if ((t
& VT_PTR
) |
1792 (t
& VT_TYPE
) == 0 |
1802 /* return the pointed type of t */
1803 int pointed_type(int t
)
1806 s
= sym_find(((unsigned)t
>> VT_STRUCT_SHIFT
));
1807 return s
->t
| (t
& VT_TYPEN
);
1810 int mk_pointer(int t
)
1815 return VT_PTR
| (p
<< VT_STRUCT_SHIFT
) | (t
& VT_TYPEN
);
1818 /* store value in lvalue pushed on stack */
1823 r
= gv(); /* generate value */
1825 ft
= vstack_ptr
[-4];
1826 fc
= vstack_ptr
[-3];
1827 if ((ft
& VT_VALMASK
) == VT_LLOCAL
) {
1829 load(t
, VT_LOCAL
| VT_LVAL
, fc
);
1830 ft
= (ft
& ~VT_VALMASK
) | t
;
1836 /* post defines POST/PRE add. c is the token ++ or -- */
1842 vpush(); /* room for returned value */
1843 vpush(); /* save lvalue */
1845 vpush(); /* save value */
1847 /* duplicate value */
1849 load(r1
, r
, 0); /* move r to r1 */
1850 vstack_ptr
[-6] = (vt
& VT_TYPE
) | r1
;
1854 vset(VT_CONST
, c
- TOK_MID
);
1856 vstore(); /* store value */
1861 /* enum/struct/union declaration */
1864 int a
, t
, b
, v
, size
, align
, maxalign
, c
;
1865 Sym
*slast
, *s
, *ss
;
1867 a
= tok
; /* save decl type */
1872 /* struct already defined ? return it */
1873 /* XXX: check consistency */
1874 if (s
= sym_find(v
| SYM_STRUCT
)) {
1876 error("invalid type");
1877 u
= u
| (v
<< VT_STRUCT_SHIFT
);
1883 s
= sym_push(v
| SYM_STRUCT
, a
, 0);
1884 /* put struct/union/enum name in type */
1885 u
= u
| (v
<< VT_STRUCT_SHIFT
);
1889 /* cannot be empty */
1894 if (a
== TOK_ENUM
) {
1901 sym_push(v
, VT_CONST
, c
);
1909 if (t
& (VT_FUNC
| VT_TYPEDEF
))
1910 error("invalid type");
1911 /* XXX: align & correct type size */
1913 size
= type_size(t
, &align
);
1914 if (a
== TOK_STRUCT
) {
1915 c
= (c
+ align
- 1) & -align
;
1916 ss
= sym_push(v
, t
, c
);
1919 ss
= sym_push(v
, t
, 0);
1923 if (align
> maxalign
)
1927 if (tok
== ';' || tok
== -1)
1938 /* size for struct/union, dummy for enum */
1939 s
->c
= (c
+ maxalign
- 1) & -maxalign
;
1944 /* return 0 if no type declaration. otherwise, return the basic type
1946 XXX: A '2' is ored to ensure non zero return if int type.
1955 if (tok
== TOK_ENUM
) {
1956 t
|= struct_decl(VT_ENUM
);
1957 } else if (tok
== TOK_STRUCT
|| tok
== TOK_UNION
) {
1958 t
|= struct_decl(VT_STRUCT
);
1960 if (tok
== TOK_CHAR
) {
1962 } else if (tok
== TOK_VOID
) {
1964 } else if (tok
== TOK_INT
| tok
== TOK_SHORT
|
1965 (tok
>= TOK_CONST
& tok
<= TOK_INLINE
)) {
1967 } else if (tok
== TOK_FLOAT
|| tok
== TOK_DOUBLE
) {
1968 warning("floats not supported");
1969 } else if (tok
== TOK_EXTERN
) {
1971 } else if (tok
== TOK_STATIC
) {
1973 } else if (tok
== TOK_UNSIGNED
) {
1975 } else if (tok
== TOK_TYPEDEF
) {
1979 if (!s
|| !(s
->t
& VT_TYPEDEF
))
1981 t
= s
->t
& ~VT_TYPEDEF
;
1996 /* function declaration */
2001 while (tok
!= ')') {
2002 /* read param name and compute offset */
2003 if (l
!= FUNC_OLD
) {
2004 if (!(pt
= ist())) {
2006 error("invalid type");
2012 if (pt
& VT_VOID
&& tok
== ')')
2015 pt
= typ(&n
, pt
); /* XXX: should accept
2016 both arg/non arg if v == 0 */
2020 pt
= 0; /* int type */
2023 /* array must be transformed to pointer according to ANSI C */
2025 /* XXX: size will be different someday */
2027 s
= sym_push(n
| SYM_FIELD
, VT_LOCAL
| VT_LVAL
| pt
, a
);
2032 if (l
== FUNC_NEW
&& tok
== TOK_DOTS
) {
2041 /* we push a anonymous symbol which will contain the function prototype */
2043 s
= sym_push(p
, t
, l
);
2045 t
= VT_FUNC
| (p
<< VT_STRUCT_SHIFT
);
2046 } else if (tok
== '[') {
2047 /* array definition */
2053 error("invalid array size");
2056 /* parse next post type */
2059 /* we push a anonymous symbol which will contain the array
2063 t
= VT_ARRAY
| VT_PTR
| (p
<< VT_STRUCT_SHIFT
);
2068 /* Read a type declaration (except basic type), and return the
2069 type. If v is true, then also put variable name in 'vc' */
2070 int typ(int *v
, int t
)
2075 t
= t
& -3; /* suppress the ored '2' */
2076 while (tok
== '*') {
2081 /* recursive type */
2082 /* XXX: incorrect if abstract type for functions (e.g. 'int ()') */
2089 /* type identifier */
2095 /* append t at the end of u */
2101 s
= sym_find((unsigned)p
>> VT_STRUCT_SHIFT
);
2111 /* define a new external reference to a function 'v' of type 'u' */
2112 Sym
*external_func(v
, u
)
2118 n
= (int)dlsym(0, get_tok_str(v
, 0));
2120 /* used to generate symbol list */
2121 s
= sym_push1(&global_stack
,
2122 v
, u
| VT_CONST
| VT_LVAL
| VT_FORWARD
, 0);
2125 s
= sym_push1(&global_stack
,
2126 v
, u
| VT_CONST
| VT_LVAL
, n
);
2138 vt
= pointed_type(vt
);
2139 if (!(vt
& VT_ARRAY
)) /* an array is never an lvalue */
2145 int n
, t
, ft
, fc
, p
, r
;
2148 if (tok
== TOK_NUM
|| tok
== TOK_CCHAR
) {
2149 vset(VT_CONST
, tokc
);
2151 } else if (tok
== TOK_STR
) {
2153 /* generate (char *) type */
2154 vset(VT_CONST
| mk_pointer(VT_TYPE
), glo
);
2155 while (tok
== TOK_STR
) {
2156 ts
= (TokenSym
*)tokc
;
2157 memcpy((void *)glo
, ts
->str
, ts
->len
);
2171 vt
= (vt
& VT_TYPEN
) | ft
;
2176 } else if (t
== '*') {
2179 } else if (t
== '&') {
2182 vt
= mk_pointer(vt
& VT_LVALN
);
2186 if ((vt
& (VT_CONST
| VT_LVAL
)) == VT_CONST
)
2188 else if ((vt
& VT_VALMASK
) == VT_CMP
)
2191 vset(VT_JMP
, gtst(1, 0));
2202 if (t
== TOK_SIZEOF
) {
2203 /* XXX: some code can be generated */
2214 vset(VT_CONST
, type_size(vt
, &t
));
2216 if (t
== TOK_INC
| t
== TOK_DEC
) {
2219 } else if (t
== '-') {
2229 error("undefined symbol");
2230 /* for simple function calls, we tolerate undeclared
2231 external reference */
2233 sym_push1(&global_stack
, p
, 0, FUNC_OLD
);
2234 /* int() function */
2235 s
= external_func(t
, VT_FUNC
| (p
<< VT_STRUCT_SHIFT
));
2238 /* if forward reference, we must point to s->c */
2239 if (vt
& VT_FORWARD
)
2244 /* post operations */
2246 if (tok
== TOK_INC
| tok
== TOK_DEC
) {
2249 } else if (tok
== '.' | tok
== TOK_ARROW
) {
2251 if (tok
== TOK_ARROW
)
2256 /* expect pointer on structure */
2257 if (!(vt
& VT_STRUCT
))
2258 expect("struct or union");
2259 s
= sym_find(((unsigned)vt
>> VT_STRUCT_SHIFT
) | SYM_STRUCT
);
2262 while (s
= s
->next
) {
2267 error("field not found");
2268 /* add field offset to pointer */
2269 vt
= vt
& VT_TYPEN
; /* change type to int */
2271 vset(VT_CONST
, s
->c
);
2273 /* change type to field type, and set to lvalue */
2274 vt
= (vt
& VT_TYPEN
) | s
->t
;
2275 /* an array is never an lvalue */
2276 if (!(vt
& VT_ARRAY
))
2279 } else if (tok
== '[') {
2286 } else if (tok
== '(') {
2288 save_regs(); /* save used temporary registers */
2289 /* lvalue is implied */
2291 if ((vt
& VT_VALMASK
) != VT_CONST
) {
2292 /* evaluate function address */
2294 o(0x50 + r
); /* push r */
2300 while (tok
!= ')') {
2304 o(0x50 + r
); /* push r */
2309 /* horrible, but needed : convert to native ordering (could
2310 parse parameters in reverse order, but would cost more
2315 oad(0x24848b, p
); /* mov x(%esp,1), %eax */
2316 oad(0x248487, n
); /* xchg x(%esp,1), %eax */
2317 oad(0x248489, p
); /* mov %eax, x(%esp,1) */
2321 if ((ft
& VT_VALMASK
) == VT_CONST
) {
2322 /* forward reference */
2323 if (ft
& VT_FORWARD
) {
2324 *(int *)fc
= psym(0xe8, *(int *)fc
);
2326 oad(0xe8, fc
- ind
- 5);
2328 oad(0x2494ff, t
); /* call *xxx(%esp) */
2333 /* get return type */
2334 s
= sym_find((unsigned)ft
>> VT_STRUCT_SHIFT
);
2335 vt
= s
->t
| 0; /* return register is eax */
2348 (tok
>= TOK_A_MOD
& tok
<= TOK_A_DIV
) |
2349 tok
== TOK_A_XOR
| tok
== TOK_A_OR
|
2350 tok
== TOK_A_SHL
| tok
== TOK_A_SAR
) {
2357 /* XXX: be more precise */
2358 if ((vt
& VT_PTR
) != (vstack_ptr
[-2] & VT_PTR
))
2359 warning("incompatible type");
2377 while ((l
== 0 & (tok
== '*' | tok
== '/' | tok
== '%')) |
2378 (l
== 1 & (tok
== '+' | tok
== '-')) |
2379 (l
== 2 & (tok
== TOK_SHL
| tok
== TOK_SAR
)) |
2380 (l
== 3 & ((tok
>= TOK_ULE
& tok
<= TOK_GT
) |
2381 tok
== TOK_ULT
| tok
== TOK_UGE
)) |
2382 (l
== 4 & (tok
== TOK_EQ
| tok
== TOK_NE
)) |
2383 (l
== 5 & tok
== '&') |
2384 (l
== 6 & tok
== '^') |
2385 (l
== 7 & tok
== '|') |
2386 (l
== 8 & tok
== TOK_LAND
) |
2387 (l
== 9 & tok
== TOK_LOR
)) {
2397 /* only used if non constant */
2405 if (tok
!= TOK_LAND
) {
2425 if (tok
!= TOK_LOR
) {
2438 /* XXX: better constant handling */
2488 if ((vt
& (VT_CONST
| VT_LVAL
)) != VT_CONST
)
2494 void block(int *bsym
, int *csym
, int *case_sym
, int *def_sym
, int case_reg
)
2499 if (tok
== TOK_IF
) {
2506 block(bsym
, csym
, case_sym
, def_sym
, case_reg
);
2508 if (c
== TOK_ELSE
) {
2512 block(bsym
, csym
, case_sym
, def_sym
, case_reg
);
2513 gsym(d
); /* patch else jmp */
2516 } else if (tok
== TOK_WHILE
) {
2524 block(&a
, &b
, case_sym
, def_sym
, case_reg
);
2525 oad(0xe9, d
- ind
- 5); /* jmp */
2528 } else if (tok
== '{') {
2534 block(bsym
, csym
, case_sym
, def_sym
, case_reg
);
2535 /* pop locally defined symbols */
2536 sym_pop(&local_stack
, s
);
2538 } else if (tok
== TOK_RETURN
) {
2545 rsym
= gjmp(rsym
); /* jmp */
2546 } else if (tok
== TOK_BREAK
) {
2549 error("cannot break");
2550 *bsym
= gjmp(*bsym
);
2553 } else if (tok
== TOK_CONTINUE
) {
2556 error("cannot continue");
2557 *csym
= gjmp(*csym
);
2560 } else if (tok
== TOK_FOR
) {
2580 oad(0xe9, d
- ind
- 5); /* jmp */
2584 block(&a
, &b
, case_sym
, def_sym
, case_reg
);
2585 oad(0xe9, c
- ind
- 5); /* jmp */
2589 if (tok
== TOK_DO
) {
2594 block(&a
, &b
, case_sym
, def_sym
, case_reg
);
2604 if (tok
== TOK_SWITCH
) {
2613 block(&a
, csym
, &b
, &c
, case_reg
);
2614 /* if no default, jmp after switch */
2622 if (tok
== TOK_CASE
) {
2632 *case_sym
= gtst(1, 0);
2634 block(bsym
, csym
, case_sym
, def_sym
, case_reg
);
2636 if (tok
== TOK_DEFAULT
) {
2642 error("too many 'default'");
2644 block(bsym
, csym
, case_sym
, def_sym
, case_reg
);
2646 if (tok
== TOK_GOTO
) {
2648 s
= sym_find1(label_stack
, tok
);
2649 /* put forward definition if needed */
2651 s
= sym_push1(&label_stack
, tok
, VT_FORWARD
, 0);
2652 /* label already defined */
2653 if (s
->t
& VT_FORWARD
)
2654 s
->c
= gjmp(s
->c
); /* jmp xxx */
2656 oad(0xe9, s
->c
- ind
- 5); /* jmp xxx */
2665 s
= sym_find1(label_stack
, b
);
2667 if (!(s
->t
& VT_FORWARD
))
2668 error("multiple defined label");
2673 sym_push1(&label_stack
, b
, 0, ind
);
2675 block(bsym
, csym
, case_sym
, def_sym
, case_reg
);
2677 /* expression case: go backward of one token */
2678 /* XXX: currently incorrect if number/string/char */
2689 /* 'l' is VT_LOCAL or VT_CONST to define default storage type */
2692 int *a
, t
, b
, size
, align
, v
, u
, n
;
2696 if ((b
& (VT_ENUM
| VT_STRUCT
)) && tok
== ';') {
2697 /* we accept no variable after */
2701 while (1) { /* iterate thru each declaration */
2705 expect("function defintion");
2706 /* patch forward references */
2707 if ((sym
= sym_find(v
)) && (sym
->t
& VT_FORWARD
)) {
2710 sym
->t
= VT_CONST
| VT_LVAL
| t
;
2712 /* put function address */
2713 sym_push1(&global_stack
, v
, VT_CONST
| VT_LVAL
| t
, ind
);
2715 /* push a dummy symbol to enable local sym storage */
2716 sym_push1(&local_stack
, 0, 0, 0);
2717 /* define parameters */
2718 sym
= sym_find((unsigned)t
>> VT_STRUCT_SHIFT
);
2719 while (sym
= sym
->next
)
2720 sym_push(sym
->v
& ~SYM_FIELD
, sym
->t
, sym
->c
);
2722 o(0xe58955); /* push %ebp, mov %esp, %ebp */
2723 a
= (int *)oad(0xec81, 0); /* sub $xxx, %esp */
2725 block(0, 0, 0, 0, 0);
2727 o(0xc3c9); /* leave, ret */
2728 *a
= (-loc
+ 3) & -4; /* align local size to word &
2729 save local variables */
2730 sym_pop(&label_stack
, 0); /* reset label stack */
2731 sym_pop(&local_stack
, 0); /* reset local stack */
2734 if (b
& VT_TYPEDEF
) {
2735 /* save typedefed type */
2736 sym_push(v
, t
| VT_TYPEDEF
, 0);
2737 } else if (t
& VT_FUNC
) {
2738 /* XXX: incorrect to flush, but needed while
2739 waiting for function prototypes */
2740 /* external function definition */
2741 external_func(v
, t
);
2743 /* not lvalue if array */
2744 if (!(t
& VT_ARRAY
))
2746 if (t
& VT_EXTERN
) {
2747 /* external variable */
2748 /* XXX: factorize with external function def */
2749 n
= (int)dlsym(NULL
, get_tok_str(v
, 0));
2751 error("unknown external variable");
2752 sym_push(v
, VT_CONST
| t
, n
);
2758 size
= type_size(t
, &align
);
2760 error("invalid size");
2761 if ((u
& VT_VALMASK
) == VT_LOCAL
) {
2762 /* allocate space down on the stack */
2763 loc
= (loc
- size
) & -align
;
2764 sym_push(v
, u
, loc
);
2766 /* allocate space up in the data space */
2767 glo
= (glo
+ align
- 1) & -align
;
2768 sym_push(v
, u
, glo
);
2783 int main(int argc
, char **argv
)
2790 include_paths
[0] = "/usr/include";
2791 include_paths
[1] = "/usr/lib/tcc";
2792 include_paths
[2] = "/usr/local/lib/tcc";
2793 nb_include_paths
= 3;
2795 /* add all tokens */
2796 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";
2800 tok_alloc(p
, r
- p
- 1);
2806 if (optind
>= argc
) {
2807 printf("usage: tcc [-Idir] infile [infile_arg...]\n");
2814 if (nb_include_paths
>= INCLUDE_PATHS_MAX
)
2815 error("too many include paths");
2816 include_paths
[nb_include_paths
++] = r
+ 2;
2818 error("invalid option");
2823 filename
= argv
[optind
];
2825 file
= fopen(filename
, "r");
2830 include_stack_ptr
= include_stack
;
2831 ifdef_stack_ptr
= ifdef_stack
;
2833 glo
= (int)malloc(DATA_SIZE
);
2834 memset((void *)glo
, 0, DATA_SIZE
);
2835 prog
= (int)malloc(TEXT_SIZE
);
2836 vstack_ptr
= vstack
;
2837 anon_sym
= 1 << (31 - VT_STRUCT_SHIFT
);
2840 ch
= '\n'; /* needed to parse correctly first preprocessor command */
2844 expect("declaration");
2848 f
= fopen(v
[1], "w");
2849 fwrite((void *)prog
, 1, ind
- prog
, f
);
2854 s
= sym_find(TOK_MAIN
);
2856 error("main() not defined");
2858 return (*t
)(argc
- optind
, argv
+ optind
);