Rev 6410 | Rev 6441 | Go to most recent revision | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 6410 | Rev 6429 | ||
---|---|---|---|
Line 15... | Line 15... | ||
15 | * |
15 | * |
16 | * You should have received a copy of the GNU Lesser General Public |
16 | * You should have received a copy of the GNU Lesser General Public |
17 | * License along with this library; if not, write to the Free Software |
17 | * License along with this library; if not, write to the Free Software |
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
19 | */ |
19 | */ |
20 | #define _GNU_SOURCE |
- | |
21 | #include "config.h" |
- | |
22 | - | ||
23 | #ifdef CONFIG_TCCBOOT |
- | |
24 | - | ||
25 | #include "tccboot.h" |
- | |
26 | #define CONFIG_TCC_STATIC |
- | |
Line -... | Line 20... | ||
- | 20 | ||
- | 21 | #ifdef ONE_SOURCE |
|
27 | 22 | #include "libtcc.c" |
|
28 | #else |
- | |
29 | - | ||
30 | #include |
- | |
31 | #include |
- | |
32 | #include |
- | |
33 | #include |
- | |
34 | //#include |
- | |
35 | #include |
- | |
36 | #include |
- | |
37 | //#include |
- | |
38 | #include |
- | |
39 | #include |
- | |
40 | #include |
- | |
41 | #ifdef WIN32 |
- | |
42 | #include |
- | |
43 | #endif |
- | |
44 | //#ifndef WIN32 |
- | |
45 | - | ||
46 | #include |
- | |
47 | //#include |
- | |
48 | //#endif |
- | |
49 | - | ||
50 | #endif /* !CONFIG_TCCBOOT */ |
- | |
51 | - | ||
52 | #include "elf.h" |
- | |
53 | #include "stab.h" |
- | |
54 | - | ||
55 | #ifndef O_BINARY |
- | |
56 | #define O_BINARY 0 |
- | |
57 | #endif |
- | |
58 | 23 | #else |
|
59 | #include "libtcc.h" |
- | |
60 | - | ||
61 | /* parser debug */ |
- | |
62 | //#define PARSE_DEBUG |
- | |
63 | /* preprocessor debug */ |
- | |
64 | //#define PP_DEBUG |
- | |
65 | /* include file debug */ |
- | |
66 | //#define INC_DEBUG |
- | |
67 | - | ||
68 | //#define MEM_DEBUG |
- | |
69 | - | ||
70 | /* assembler debug */ |
- | |
71 | //#define ASM_DEBUG |
- | |
72 | - | ||
73 | /* target selection */ |
- | |
74 | //#define TCC_TARGET_I386 /* i386 code generator */ |
- | |
75 | //#define TCC_TARGET_ARM /* ARMv4 code generator */ |
- | |
76 | //#define TCC_TARGET_C67 /* TMS320C67xx code generator */ |
- | |
77 | //---------------------------------------------------------------- |
- | |
78 | #define TCC_TARGET_MEOS |
- | |
79 | - | ||
80 | /* default target is I386 */ |
- | |
81 | #if !defined(TCC_TARGET_I386) && !defined(TCC_TARGET_ARM) && \ |
- | |
82 | !defined(TCC_TARGET_C67) |
- | |
83 | #define TCC_TARGET_I386 |
- | |
84 | #endif |
- | |
85 | - | ||
86 | #if !defined(WIN32) && !defined(TCC_UCLIBC) && !defined(TCC_TARGET_ARM) && \ |
- | |
87 | !defined(TCC_TARGET_C67) |
- | |
88 | #define CONFIG_TCC_BCHECK /* enable bound checking code */ |
- | |
89 | #endif |
- | |
90 | - | ||
91 | #if defined(WIN32) && !defined(TCC_TARGET_PE) && !defined(TCC_TARGET_MEOS) |
- | |
92 | #define CONFIG_TCC_STATIC |
- | |
93 | #endif |
- | |
94 | - | ||
95 | /* define it to include assembler support */ |
- | |
96 | #if !defined(TCC_TARGET_ARM) && !defined(TCC_TARGET_C67) |
- | |
97 | #define CONFIG_TCC_ASM |
- | |
98 | #endif |
- | |
99 | - | ||
100 | /* object format selection */ |
- | |
101 | #if defined(TCC_TARGET_C67) |
- | |
102 | #define TCC_TARGET_COFF |
- | |
103 | #endif |
- | |
104 | - | ||
105 | #define FALSE 0 |
- | |
106 | #define false 0 |
- | |
107 | #define TRUE 1 |
- | |
108 | #define true 1 |
- | |
109 | typedef int BOOL; |
- | |
110 | - | ||
111 | /* path to find crt1.o, crti.o and crtn.o. Only needed when generating |
- | |
112 | executables or dlls */ |
- | |
113 | #define CONFIG_TCC_CRT_PREFIX "/usr/lib" |
- | |
114 | - | ||
115 | #define INCLUDE_STACK_SIZE 32 |
- | |
116 | #define IFDEF_STACK_SIZE 64 |
- | |
117 | #define VSTACK_SIZE 256 |
- | |
118 | #define STRING_MAX_SIZE 1024 |
- | |
119 | #define PACK_STACK_SIZE 8 |
- | |
120 | - | ||
121 | #define TOK_HASH_SIZE 8192 /* must be a power of two */ |
- | |
122 | #define TOK_ALLOC_INCR 512 /* must be a power of two */ |
- | |
123 | #define TOK_MAX_SIZE 4 /* token max size in int unit when stored in string */ |
- | |
124 | - | ||
125 | /* token symbol management */ |
- | |
126 | typedef struct TokenSym { |
- | |
127 | struct TokenSym *hash_next; |
- | |
128 | struct Sym *sym_define; /* direct pointer to define */ |
- | |
129 | struct Sym *sym_label; /* direct pointer to label */ |
- | |
130 | struct Sym *sym_struct; /* direct pointer to structure */ |
- | |
131 | struct Sym *sym_identifier; /* direct pointer to identifier */ |
- | |
132 | int tok; /* token number */ |
- | |
133 | int len; |
- | |
134 | char str[1]; |
- | |
135 | } TokenSym; |
- | |
136 | - | ||
137 | typedef struct CString { |
- | |
138 | int size; /* size in bytes */ |
- | |
139 | void *data; /* either 'char *' or 'int *' */ |
- | |
140 | int size_allocated; |
- | |
141 | void *data_allocated; /* if non NULL, data has been malloced */ |
- | |
142 | } CString; |
- | |
143 | - | ||
144 | /* type definition */ |
- | |
145 | typedef struct CType { |
- | |
146 | int t; |
- | |
147 | struct Sym *ref; |
- | |
148 | } CType; |
- | |
149 | - | ||
150 | /* constant value */ |
- | |
151 | typedef union CValue { |
- | |
152 | long double ld; |
- | |
153 | double d; |
- | |
154 | float f; |
- | |
155 | int i; |
- | |
156 | unsigned int ui; |
- | |
157 | unsigned int ul; /* address (should be unsigned long on 64 bit cpu) */ |
- | |
158 | long long ll; |
- | |
159 | unsigned long long ull; |
- | |
160 | struct CString *cstr; |
- | |
161 | void *ptr; |
- | |
162 | int tab[1]; |
- | |
163 | } CValue; |
- | |
164 | - | ||
165 | /* value on stack */ |
- | |
166 | typedef struct SValue { |
- | |
167 | CType type; /* type */ |
- | |
168 | unsigned short r; /* register + flags */ |
- | |
169 | unsigned short r2; /* second register, used for 'long long' |
- | |
170 | type. If not used, set to VT_CONST */ |
- | |
171 | CValue c; /* constant, if VT_CONST */ |
- | |
172 | struct Sym *sym; /* symbol, if (VT_SYM | VT_CONST) */ |
- | |
173 | } SValue; |
- | |
174 | - | ||
175 | /* symbol management */ |
- | |
176 | typedef struct Sym { |
- | |
177 | int v; /* symbol token */ |
- | |
178 | int r; /* associated register */ |
- | |
179 | int c; /* associated number */ |
- | |
180 | CType type; /* associated type */ |
- | |
181 | struct Sym *next; /* next related symbol */ |
- | |
182 | struct Sym *prev; /* prev symbol in stack */ |
- | |
183 | struct Sym *prev_tok; /* previous symbol for this token */ |
- | |
184 | } Sym; |
- | |
185 | - | ||
186 | /* section definition */ |
- | |
187 | /* XXX: use directly ELF structure for parameters ? */ |
- | |
188 | /* special flag to indicate that the section should not be linked to |
- | |
189 | the other ones */ |
- | |
190 | #define SHF_PRIVATE 0x80000000 |
- | |
191 | - | ||
192 | typedef struct Section { |
- | |
193 | unsigned long data_offset; /* current data offset */ |
- | |
194 | unsigned char *data; /* section data */ |
- | |
195 | unsigned long data_allocated; /* used for realloc() handling */ |
- | |
196 | int sh_name; /* elf section name (only used during output) */ |
- | |
197 | int sh_num; /* elf section number */ |
- | |
198 | int sh_type; /* elf section type */ |
- | |
199 | int sh_flags; /* elf section flags */ |
- | |
200 | int sh_info; /* elf section info */ |
- | |
201 | int sh_addralign; /* elf section alignment */ |
- | |
202 | int sh_entsize; /* elf entry size */ |
- | |
203 | unsigned long sh_size; /* section size (only used during output) */ |
- | |
204 | unsigned long sh_addr; /* address at which the section is relocated */ |
- | |
205 | unsigned long sh_offset; /* address at which the section is relocated */ |
- | |
206 | int nb_hashed_syms; /* used to resize the hash table */ |
- | |
207 | struct Section *link; /* link to another section */ |
- | |
208 | struct Section *reloc; /* corresponding section for relocation, if any */ |
- | |
209 | struct Section *hash; /* hash table for symbols */ |
- | |
210 | struct Section *next; |
- | |
211 | char name[1]; /* section name */ |
- | |
212 | } Section; |
- | |
213 | - | ||
214 | typedef struct DLLReference { |
- | |
215 | int level; |
- | |
216 | char name[1]; |
- | |
217 | } DLLReference; |
- | |
218 | - | ||
219 | /* GNUC attribute definition */ |
- | |
220 | typedef struct AttributeDef { |
- | |
221 | int aligned; |
- | |
222 | int packed; |
- | |
223 | Section *section; |
- | |
224 | unsigned char func_call; /* FUNC_CDECL, FUNC_STDCALL, FUNC_FASTCALLx */ |
- | |
225 | unsigned char dllexport; |
- | |
226 | } AttributeDef; |
- | |
227 | - | ||
228 | #define SYM_STRUCT 0x40000000 /* struct/union/enum symbol space */ |
- | |
229 | #define SYM_FIELD 0x20000000 /* struct/union field symbol space */ |
- | |
230 | #define SYM_FIRST_ANOM 0x10000000 /* first anonymous sym */ |
- | |
231 | - | ||
232 | /* stored in 'Sym.c' field */ |
- | |
233 | #define FUNC_NEW 1 /* ansi function prototype */ |
- | |
234 | #define FUNC_OLD 2 /* old function prototype */ |
- | |
235 | #define FUNC_ELLIPSIS 3 /* ansi function prototype with ... */ |
- | |
236 | - | ||
237 | /* stored in 'Sym.r' field */ |
- | |
238 | #define FUNC_CDECL 0 /* standard c call */ |
- | |
239 | #define FUNC_STDCALL 1 /* pascal c call */ |
- | |
240 | #define FUNC_FASTCALL1 2 /* first param in %eax */ |
- | |
241 | #define FUNC_FASTCALL2 3 /* first parameters in %eax, %edx */ |
- | |
242 | #define FUNC_FASTCALL3 4 /* first parameter in %eax, %edx, %ecx */ |
- | |
243 | - | ||
244 | /* field 'Sym.t' for macros */ |
- | |
245 | #define MACRO_OBJ 0 /* object like macro */ |
- | |
246 | #define MACRO_FUNC 1 /* function like macro */ |
- | |
247 | - | ||
248 | /* field 'Sym.r' for C labels */ |
- | |
249 | #define LABEL_DEFINED 0 /* label is defined */ |
- | |
250 | #define LABEL_FORWARD 1 /* label is forward defined */ |
- | |
251 | #define LABEL_DECLARED 2 /* label is declared but never used */ |
- | |
252 | - | ||
253 | /* type_decl() types */ |
- | |
254 | #define TYPE_ABSTRACT 1 /* type without variable */ |
- | |
255 | #define TYPE_DIRECT 2 /* type with variable */ |
- | |
256 | - | ||
257 | #define IO_BUF_SIZE 8192 |
- | |
258 | - | ||
259 | typedef struct BufferedFile { |
- | |
260 | uint8_t *buf_ptr; |
- | |
261 | uint8_t *buf_end; |
- | |
262 | int fd; |
- | |
263 | int line_num; /* current line number - here to simplify code */ |
- | |
264 | int ifndef_macro; /* #ifndef macro / #endif search */ |
- | |
265 | int ifndef_macro_saved; /* saved ifndef_macro */ |
- | |
266 | int *ifdef_stack_ptr; /* ifdef_stack value at the start of the file */ |
- | |
267 | char inc_type; /* type of include */ |
- | |
268 | char inc_filename[512]; /* filename specified by the user */ |
- | |
269 | char filename[1024]; /* current filename - here to simplify code */ |
- | |
270 | unsigned char buffer[IO_BUF_SIZE + 1]; /* extra size for CH_EOB char */ |
- | |
271 | } BufferedFile; |
- | |
272 | - | ||
273 | #define CH_EOB '\\' /* end of buffer or '\0' char in file */ |
- | |
274 | #define CH_EOF (-1) /* end of file */ |
- | |
275 | - | ||
276 | /* parsing state (used to save parser state to reparse part of the |
- | |
277 | source several times) */ |
- | |
278 | typedef struct ParseState { |
- | |
279 | int *macro_ptr; |
- | |
280 | int line_num; |
- | |
281 | int tok; |
- | |
282 | CValue tokc; |
- | |
283 | } ParseState; |
- | |
284 | - | ||
285 | /* used to record tokens */ |
- | |
286 | typedef struct TokenString { |
- | |
287 | int *str; |
- | |
288 | int len; |
- | |
289 | int allocated_len; |
- | |
290 | int last_line_num; |
- | |
291 | } TokenString; |
- | |
292 | - | ||
293 | /* include file cache, used to find files faster and also to eliminate |
- | |
294 | inclusion if the include file is protected by #ifndef ... #endif */ |
- | |
295 | typedef struct CachedInclude { |
- | |
296 | int ifndef_macro; |
- | |
297 | int hash_next; /* -1 if none */ |
- | |
298 | char type; /* '"' or '>' to give include type */ |
- | |
299 | char filename[1]; /* path specified in #include */ |
- | |
300 | } CachedInclude; |
- | |
301 | - | ||
302 | #define CACHED_INCLUDES_HASH_SIZE 512 |
- | |
303 | - | ||
304 | /* parser */ |
- | |
305 | static struct BufferedFile *file; |
- | |
306 | static int ch, tok; |
- | |
307 | static CValue tokc; |
- | |
308 | static CString tokcstr; /* current parsed string, if any */ |
- | |
309 | /* additional informations about token */ |
- | |
310 | static int tok_flags; |
- | |
311 | #define TOK_FLAG_BOL 0x0001 /* beginning of line before */ |
- | |
312 | #define TOK_FLAG_BOF 0x0002 /* beginning of file before */ |
- | |
313 | #define TOK_FLAG_ENDIF 0x0004 /* a endif was found matching starting #ifdef */ |
- | |
314 | - | ||
315 | static int *macro_ptr, *macro_ptr_allocated; |
- | |
316 | static int *unget_saved_macro_ptr; |
- | |
317 | static int unget_saved_buffer[TOK_MAX_SIZE + 1]; |
- | |
318 | static int unget_buffer_enabled; |
- | |
319 | static int parse_flags; |
- | |
320 | #define PARSE_FLAG_PREPROCESS 0x0001 /* activate preprocessing */ |
- | |
321 | #define PARSE_FLAG_TOK_NUM 0x0002 /* return numbers instead of TOK_PPNUM */ |
- | |
322 | #define PARSE_FLAG_LINEFEED 0x0004 /* line feed is returned as a |
- | |
323 | token. line feed is also |
- | |
324 | returned at eof */ |
- | |
325 | #define PARSE_FLAG_ASM_COMMENTS 0x0008 /* '#' can be used for line comment */ |
- | |
326 | - | ||
327 | static Section *text_section, *data_section, *bss_section; /* predefined sections */ |
- | |
328 | static Section *cur_text_section; /* current section where function code is |
- | |
329 | generated */ |
- | |
330 | #ifdef CONFIG_TCC_ASM |
- | |
331 | static Section *last_text_section; /* to handle .previous asm directive */ |
- | |
332 | #endif |
- | |
333 | /* bound check related sections */ |
- | |
334 | static Section *bounds_section; /* contains global data bound description */ |
- | |
335 | static Section *lbounds_section; /* contains local data bound description */ |
- | |
336 | /* symbol sections */ |
- | |
337 | static Section *symtab_section, *strtab_section; |
- | |
338 | - | ||
339 | /* debug sections */ |
- | |
340 | static Section *stab_section, *stabstr_section; |
- | |
341 | - | ||
342 | /* loc : local variable index |
- | |
343 | ind : output code index |
- | |
344 | rsym: return symbol |
- | |
345 | anon_sym: anonymous symbol index |
- | |
346 | */ |
- | |
347 | static int rsym, anon_sym, ind, loc; |
- | |
348 | /* expression generation modifiers */ |
- | |
349 | static int const_wanted; /* true if constant wanted */ |
- | |
350 | static int nocode_wanted; /* true if no code generation wanted for an expression */ |
- | |
351 | static int global_expr; /* true if compound literals must be allocated |
- | |
352 | globally (used during initializers parsing */ |
- | |
353 | static CType func_vt; /* current function return type (used by return |
- | |
354 | instruction) */ |
- | |
355 | static int func_vc; |
- | |
356 | static int last_line_num, last_ind, func_ind; /* debug last line number and pc */ |
- | |
357 | static int tok_ident; |
- | |
358 | static TokenSym **table_ident; |
- | |
359 | static TokenSym *hash_ident[TOK_HASH_SIZE]; |
- | |
360 | static char token_buf[STRING_MAX_SIZE + 1]; |
- | |
361 | static char *funcname; |
- | |
362 | static Sym *global_stack, *local_stack; |
- | |
363 | static Sym *define_stack; |
- | |
364 | static Sym *global_label_stack, *local_label_stack; |
- | |
365 | /* symbol allocator */ |
- | |
366 | #define SYM_POOL_NB (8192 / sizeof(Sym)) |
- | |
367 | static Sym *sym_free_first; |
- | |
368 | - | ||
369 | static SValue vstack[VSTACK_SIZE], *vtop; |
- | |
370 | /* some predefined types */ |
- | |
371 | static CType char_pointer_type, func_old_type, int_type; |
- | |
372 | /* true if isid(c) || isnum(c) */ |
- | |
373 | static unsigned char isidnum_table[256]; |
- | |
374 | - | ||
375 | /* compile with debug symbol (and use them if error during execution) */ |
- | |
376 | static int do_debug = 0; |
- | |
377 | - | ||
378 | /* compile with built-in memory and bounds checker */ |
- | |
379 | static int do_bounds_check = 0; |
- | |
380 | - | ||
381 | /* display benchmark infos */ |
- | |
382 | #if !defined(LIBTCC) |
- | |
383 | static int do_bench = 0; |
- | |
384 | #endif |
- | |
385 | static int total_lines; |
- | |
386 | static int total_bytes; |
- | |
387 | - | ||
388 | /* use GNU C extensions */ |
- | |
389 | static int gnu_ext = 1; |
- | |
390 | - | ||
391 | /* use Tiny C extensions */ |
- | |
392 | static int tcc_ext = 1; |
- | |
393 | - | ||
394 | /* max number of callers shown if error */ |
- | |
395 | static int num_callers = 6; |
- | |
396 | static const char **rt_bound_error_msg; |
- | |
397 | - | ||
398 | /* XXX: get rid of this ASAP */ |
- | |
399 | static struct TCCState *tcc_state; |
- | |
400 | - | ||
401 | /* give the path of the tcc libraries */ |
- | |
402 | static const char *tcc_lib_path = CONFIG_TCCDIR; |
- | |
403 | - | ||
404 | struct TCCState { |
- | |
405 | int output_type; |
- | |
406 | - | ||
407 | BufferedFile **include_stack_ptr; |
- | |
408 | int *ifdef_stack_ptr; |
- | |
409 | - | ||
410 | /* include file handling */ |
- | |
411 | char **include_paths; |
- | |
412 | int nb_include_paths; |
- | |
413 | char **sysinclude_paths; |
- | |
414 | int nb_sysinclude_paths; |
- | |
415 | CachedInclude **cached_includes; |
- | |
416 | int nb_cached_includes; |
- | |
417 | - | ||
418 | char **library_paths; |
- | |
419 | int nb_library_paths; |
- | |
420 | - | ||
421 | /* array of all loaded dlls (including those referenced by loaded |
- | |
422 | dlls) */ |
- | |
423 | DLLReference **loaded_dlls; |
- | |
424 | int nb_loaded_dlls; |
- | |
425 | - | ||
426 | /* sections */ |
- | |
427 | Section **sections; |
- | |
428 | int nb_sections; /* number of sections, including first dummy section */ |
- | |
429 | - | ||
430 | /* got handling */ |
- | |
431 | Section *got; |
- | |
432 | Section *plt; |
- | |
433 | unsigned long *got_offsets; |
- | |
434 | int nb_got_offsets; |
- | |
435 | /* give the correspondance from symtab indexes to dynsym indexes */ |
- | |
436 | int *symtab_to_dynsym; |
- | |
437 | - | ||
438 | /* temporary dynamic symbol sections (for dll loading) */ |
- | |
439 | Section *dynsymtab_section; |
- | |
440 | /* exported dynamic symbol section */ |
- | |
441 | Section *dynsym; |
- | |
442 | - | ||
443 | int nostdinc; /* if true, no standard headers are added */ |
- | |
444 | int nostdlib; /* if true, no standard libraries are added */ |
- | |
445 | - | ||
446 | int nocommon; /* if true, do not use common symbols for .bss data */ |
- | |
447 | - | ||
448 | /* if true, static linking is performed */ |
- | |
449 | int static_link; |
- | |
450 | - | ||
451 | /* if true, all symbols are exported */ |
- | |
452 | int rdynamic; |
- | |
453 | - | ||
454 | /* if true, only link in referenced objects from archive */ |
- | |
455 | int alacarte_link; |
- | |
456 | - | ||
457 | /* address of text section */ |
- | |
458 | unsigned long text_addr; |
- | |
459 | int has_text_addr; |
- | |
460 | - | ||
461 | /* output format, see TCC_OUTPUT_FORMAT_xxx */ |
- | |
462 | int output_format; |
- | |
463 | - | ||
464 | /* C language options */ |
- | |
465 | int char_is_unsigned; |
- | |
466 | int leading_underscore; |
- | |
467 | - | ||
468 | /* warning switches */ |
- | |
469 | int warn_write_strings; |
- | |
470 | int warn_unsupported; |
- | |
471 | int warn_error; |
- | |
472 | int warn_none; |
- | |
473 | int warn_implicit_function_declaration; |
- | |
474 | - | ||
475 | /* error handling */ |
- | |
476 | void *error_opaque; |
- | |
477 | void (*error_func)(void *opaque, const char *msg); |
- | |
478 | int error_set_jmp_enabled; |
- | |
479 | jmp_buf error_jmp_buf; |
- | |
480 | int nb_errors; |
- | |
481 | - | ||
482 | /* tiny assembler state */ |
- | |
483 | Sym *asm_labels; |
- | |
484 | - | ||
485 | /* see include_stack_ptr */ |
- | |
486 | BufferedFile *include_stack[INCLUDE_STACK_SIZE]; |
- | |
487 | - | ||
488 | /* see ifdef_stack_ptr */ |
- | |
489 | int ifdef_stack[IFDEF_STACK_SIZE]; |
- | |
490 | - | ||
491 | /* see cached_includes */ |
- | |
492 | int cached_includes_hash[CACHED_INCLUDES_HASH_SIZE]; |
- | |
493 | - | ||
494 | /* pack stack */ |
- | |
495 | int pack_stack[PACK_STACK_SIZE]; |
- | |
496 | int *pack_stack_ptr; |
- | |
497 | }; |
- | |
498 | - | ||
499 | /* The current value can be: */ |
- | |
500 | #define VT_VALMASK 0x00ff |
- | |
501 | #define VT_CONST 0x00f0 /* constant in vc |
- | |
502 | (must be first non register value) */ |
- | |
503 | #define VT_LLOCAL 0x00f1 /* lvalue, offset on stack */ |
- | |
504 | #define VT_LOCAL 0x00f2 /* offset on stack */ |
- | |
505 | #define VT_CMP 0x00f3 /* the value is stored in processor flags (in vc) */ |
- | |
506 | #define VT_JMP 0x00f4 /* value is the consequence of jmp true (even) */ |
- | |
507 | #define VT_JMPI 0x00f5 /* value is the consequence of jmp false (odd) */ |
- | |
508 | #define VT_LVAL 0x0100 /* var is an lvalue */ |
- | |
509 | #define VT_SYM 0x0200 /* a symbol value is added */ |
- | |
510 | #define VT_MUSTCAST 0x0400 /* value must be casted to be correct (used for |
- | |
511 | char/short stored in integer registers) */ |
- | |
512 | #define VT_MUSTBOUND 0x0800 /* bound checking must be done before |
- | |
513 | dereferencing value */ |
- | |
514 | #define VT_BOUNDED 0x8000 /* value is bounded. The address of the |
- | |
515 | bounding function call point is in vc */ |
- | |
516 | #define VT_LVAL_BYTE 0x1000 /* lvalue is a byte */ |
- | |
517 | #define VT_LVAL_SHORT 0x2000 /* lvalue is a short */ |
- | |
518 | #define VT_LVAL_UNSIGNED 0x4000 /* lvalue is unsigned */ |
- | |
519 | #define VT_LVAL_TYPE (VT_LVAL_BYTE | VT_LVAL_SHORT | VT_LVAL_UNSIGNED) |
- | |
520 | - | ||
521 | /* types */ |
- | |
522 | #define VT_INT 0 /* integer type */ |
- | |
523 | #define VT_BYTE 1 /* signed byte type */ |
- | |
524 | #define VT_SHORT 2 /* short type */ |
- | |
525 | #define VT_VOID 3 /* void type */ |
- | |
526 | #define VT_PTR 4 /* pointer */ |
- | |
527 | #define VT_ENUM 5 /* enum definition */ |
- | |
528 | #define VT_FUNC 6 /* function type */ |
- | |
529 | #define VT_STRUCT 7 /* struct/union definition */ |
- | |
530 | #define VT_FLOAT 8 /* IEEE float */ |
- | |
531 | #define VT_DOUBLE 9 /* IEEE double */ |
- | |
532 | #define VT_LDOUBLE 10 /* IEEE long double */ |
- | |
533 | #define VT_BOOL 11 /* ISOC99 boolean type */ |
- | |
534 | #define VT_LLONG 12 /* 64 bit integer */ |
- | |
535 | #define VT_LONG 13 /* long integer (NEVER USED as type, only |
- | |
536 | during parsing) */ |
- | |
537 | #define VT_BTYPE 0x000f /* mask for basic type */ |
- | |
538 | #define VT_UNSIGNED 0x0010 /* unsigned type */ |
- | |
539 | #define VT_ARRAY 0x0020 /* array type (also has VT_PTR) */ |
- | |
540 | #define VT_BITFIELD 0x0040 /* bitfield modifier */ |
- | |
541 | #define VT_CONSTANT 0x0800 /* const modifier */ |
- | |
542 | #define VT_VOLATILE 0x1000 /* volatile modifier */ |
- | |
543 | #define VT_SIGNED 0x2000 /* signed type */ |
- | |
544 | - | ||
545 | /* storage */ |
- | |
546 | #define VT_EXTERN 0x00000080 /* extern definition */ |
- | |
547 | #define VT_STATIC 0x00000100 /* static variable */ |
- | |
548 | #define VT_TYPEDEF 0x00000200 /* typedef definition */ |
- | |
549 | #define VT_INLINE 0x00000400 /* inline definition */ |
- | |
550 | - | ||
551 | #define VT_STRUCT_SHIFT 16 /* shift for bitfield shift values */ |
- | |
552 | - | ||
553 | /* type mask (except storage) */ |
- | |
554 | #define VT_STORAGE (VT_EXTERN | VT_STATIC | VT_TYPEDEF | VT_INLINE) |
- | |
555 | #define VT_TYPE (~(VT_STORAGE)) |
- | |
556 | - | ||
557 | /* token values */ |
- | |
558 | - | ||
559 | /* warning: the following compare tokens depend on i386 asm code */ |
- | |
560 | #define TOK_ULT 0x92 |
- | |
561 | #define TOK_UGE 0x93 |
- | |
562 | #define TOK_EQ 0x94 |
- | |
563 | #define TOK_NE 0x95 |
- | |
564 | #define TOK_ULE 0x96 |
- | |
565 | #define TOK_UGT 0x97 |
- | |
566 | #define TOK_LT 0x9c |
- | |
567 | #define TOK_GE 0x9d |
- | |
568 | #define TOK_LE 0x9e |
- | |
569 | #define TOK_GT 0x9f |
- | |
570 | - | ||
571 | #define TOK_LAND 0xa0 |
- | |
572 | #define TOK_LOR 0xa1 |
- | |
573 | - | ||
574 | #define TOK_DEC 0xa2 |
- | |
575 | #define TOK_MID 0xa3 /* inc/dec, to void constant */ |
- | |
576 | #define TOK_INC 0xa4 |
- | |
577 | #define TOK_UDIV 0xb0 /* unsigned division */ |
- | |
578 | #define TOK_UMOD 0xb1 /* unsigned modulo */ |
- | |
579 | #define TOK_PDIV 0xb2 /* fast division with undefined rounding for pointers */ |
- | |
580 | #define TOK_CINT 0xb3 /* number in tokc */ |
- | |
581 | #define TOK_CCHAR 0xb4 /* char constant in tokc */ |
- | |
582 | #define TOK_STR 0xb5 /* pointer to string in tokc */ |
- | |
583 | #define TOK_TWOSHARPS 0xb6 /* ## preprocessing token */ |
- | |
584 | #define TOK_LCHAR 0xb7 |
- | |
585 | #define TOK_LSTR 0xb8 |
- | |
586 | #define TOK_CFLOAT 0xb9 /* float constant */ |
- | |
587 | #define TOK_LINENUM 0xba /* line number info */ |
- | |
588 | #define TOK_CDOUBLE 0xc0 /* double constant */ |
- | |
589 | #define TOK_CLDOUBLE 0xc1 /* long double constant */ |
- | |
590 | #define TOK_UMULL 0xc2 /* unsigned 32x32 -> 64 mul */ |
- | |
591 | #define TOK_ADDC1 0xc3 /* add with carry generation */ |
- | |
592 | #define TOK_ADDC2 0xc4 /* add with carry use */ |
- | |
593 | #define TOK_SUBC1 0xc5 /* add with carry generation */ |
- | |
594 | #define TOK_SUBC2 0xc6 /* add with carry use */ |
- | |
595 | #define TOK_CUINT 0xc8 /* unsigned int constant */ |
- | |
596 | #define TOK_CLLONG 0xc9 /* long long constant */ |
- | |
597 | #define TOK_CULLONG 0xca /* unsigned long long constant */ |
- | |
598 | #define TOK_ARROW 0xcb |
- | |
599 | #define TOK_DOTS 0xcc /* three dots */ |
- | |
600 | #define TOK_SHR 0xcd /* unsigned shift right */ |
- | |
601 | #define TOK_PPNUM 0xce /* preprocessor number */ |
- | |
602 | - | ||
603 | #define TOK_SHL 0x01 /* shift left */ |
- | |
604 | #define TOK_SAR 0x02 /* signed shift right */ |
- | |
605 | - | ||
606 | /* assignement operators : normal operator or 0x80 */ |
- | |
607 | #define TOK_A_MOD 0xa5 |
- | |
608 | #define TOK_A_AND 0xa6 |
- | |
609 | #define TOK_A_MUL 0xaa |
- | |
610 | #define TOK_A_ADD 0xab |
- | |
611 | #define TOK_A_SUB 0xad |
- | |
612 | #define TOK_A_DIV 0xaf |
- | |
613 | #define TOK_A_XOR 0xde |
- | |
614 | #define TOK_A_OR 0xfc |
- | |
615 | #define TOK_A_SHL 0x81 |
- | |
616 | #define TOK_A_SAR 0x82 |
- | |
617 | - | ||
618 | #ifndef offsetof |
- | |
619 | #define offsetof(type, field) ((size_t) &((type *)0)->field) |
- | |
620 | #endif |
- | |
621 | - | ||
622 | #ifndef countof |
- | |
623 | #define countof(tab) (sizeof(tab) / sizeof((tab)[0])) |
- | |
624 | #endif |
- | |
625 | - | ||
626 | /* WARNING: the content of this string encodes token numbers */ |
- | |
627 | static char tok_two_chars[] = "<=\236>=\235!=\225&&\240||\241++\244--\242==\224<<\1>>\2+=\253-=\255*=\252/=\257%=\245&=\246^=\336|=\374->\313..\250##\266"; |
- | |
628 | - | ||
629 | #define TOK_EOF (-1) /* end of file */ |
- | |
630 | #define TOK_LINEFEED 10 /* line feed */ |
- | |
631 | - | ||
632 | /* all identificators and strings have token above that */ |
- | |
633 | #define TOK_IDENT 256 |
- | |
634 | - | ||
635 | /* only used for i386 asm opcodes definitions */ |
- | |
636 | #define DEF_ASM(x) DEF(TOK_ASM_ ## x, #x) |
- | |
637 | - | ||
638 | #define DEF_BWL(x) \ |
- | |
639 | DEF(TOK_ASM_ ## x ## b, #x "b") \ |
- | |
640 | DEF(TOK_ASM_ ## x ## w, #x "w") \ |
- | |
641 | DEF(TOK_ASM_ ## x ## l, #x "l") \ |
- | |
642 | DEF(TOK_ASM_ ## x, #x) |
- | |
643 | - | ||
644 | #define DEF_WL(x) \ |
- | |
645 | DEF(TOK_ASM_ ## x ## w, #x "w") \ |
- | |
646 | DEF(TOK_ASM_ ## x ## l, #x "l") \ |
- | |
647 | DEF(TOK_ASM_ ## x, #x) |
- | |
648 | - | ||
649 | #define DEF_FP1(x) \ |
- | |
650 | DEF(TOK_ASM_ ## f ## x ## s, "f" #x "s") \ |
- | |
651 | DEF(TOK_ASM_ ## fi ## x ## l, "fi" #x "l") \ |
- | |
652 | DEF(TOK_ASM_ ## f ## x ## l, "f" #x "l") \ |
- | |
653 | DEF(TOK_ASM_ ## fi ## x ## s, "fi" #x "s") |
- | |
654 | - | ||
655 | #define DEF_FP(x) \ |
- | |
656 | DEF(TOK_ASM_ ## f ## x, "f" #x ) \ |
- | |
657 | DEF(TOK_ASM_ ## f ## x ## p, "f" #x "p") \ |
- | |
658 | DEF_FP1(x) |
- | |
659 | - | ||
660 | #define DEF_ASMTEST(x) \ |
- | |
661 | DEF_ASM(x ## o) \ |
- | |
662 | DEF_ASM(x ## no) \ |
- | |
663 | DEF_ASM(x ## b) \ |
- | |
664 | DEF_ASM(x ## c) \ |
- | |
665 | DEF_ASM(x ## nae) \ |
- | |
666 | DEF_ASM(x ## nb) \ |
- | |
667 | DEF_ASM(x ## nc) \ |
- | |
668 | DEF_ASM(x ## ae) \ |
- | |
669 | DEF_ASM(x ## e) \ |
- | |
670 | DEF_ASM(x ## z) \ |
- | |
671 | DEF_ASM(x ## ne) \ |
- | |
672 | DEF_ASM(x ## nz) \ |
- | |
673 | DEF_ASM(x ## be) \ |
- | |
674 | DEF_ASM(x ## na) \ |
- | |
675 | DEF_ASM(x ## nbe) \ |
- | |
676 | DEF_ASM(x ## a) \ |
- | |
677 | DEF_ASM(x ## s) \ |
- | |
678 | DEF_ASM(x ## ns) \ |
- | |
679 | DEF_ASM(x ## p) \ |
- | |
680 | DEF_ASM(x ## pe) \ |
- | |
681 | DEF_ASM(x ## np) \ |
- | |
682 | DEF_ASM(x ## po) \ |
- | |
683 | DEF_ASM(x ## l) \ |
- | |
684 | DEF_ASM(x ## nge) \ |
- | |
685 | DEF_ASM(x ## nl) \ |
- | |
686 | DEF_ASM(x ## ge) \ |
- | |
687 | DEF_ASM(x ## le) \ |
- | |
688 | DEF_ASM(x ## ng) \ |
- | |
689 | DEF_ASM(x ## nle) \ |
- | |
690 | DEF_ASM(x ## g) |
- | |
691 | - | ||
692 | #define TOK_ASM_int TOK_INT |
- | |
693 | - | ||
694 | enum tcc_token { |
- | |
695 | TOK_LAST = TOK_IDENT - 1, |
- | |
696 | #define DEF(id, str) id, |
- | |
697 | #include "tcctok.h" |
- | |
698 | #undef DEF |
- | |
699 | }; |
- | |
700 | - | ||
701 | static const char tcc_keywords[] = |
- | |
702 | #define DEF(id, str) str "\0" |
- | |
703 | #include "tcctok.h" |
- | |
704 | #undef DEF |
- | |
705 | ; |
- | |
706 | - | ||
707 | #define TOK_UIDENT TOK_DEFINE |
- | |
708 | - | ||
709 | #ifdef WIN32 |
- | |
710 | int __stdcall GetModuleFileNameA(void *, char *, int); |
- | |
711 | void *__stdcall GetProcAddress(void *, const char *); |
- | |
712 | void *__stdcall GetModuleHandleA(const char *); |
- | |
713 | void *__stdcall LoadLibraryA(const char *); |
- | |
714 | int __stdcall FreeConsole(void); |
- | |
715 | - | ||
716 | #define snprintf _snprintf |
- | |
717 | #define vsnprintf _vsnprintf |
- | |
718 | #ifndef __GNUC__ |
- | |
719 | #define strtold (long double)strtod |
- | |
720 | #define strtof (float)strtod |
- | |
721 | #define strtoll (long long)strtol |
- | |
722 | #endif |
- | |
723 | #elif defined(TCC_UCLIBC) || defined(__FreeBSD__) |
- | |
724 | - | ||
725 | long double strtold(const char *nptr, char **endptr) |
- | |
726 | { |
- | |
727 | return (long double)strtod(nptr, endptr); |
- | |
728 | } |
- | |
729 | float strtof(const char *nptr, char **endptr) |
- | |
730 | { |
- | |
731 | return (float)strtod(nptr, endptr); |
- | |
732 | } |
- | |
733 | - | ||
734 | #else |
- | |
735 | - | ||
736 | /* XXX: need to define this to use them in non ISOC99 context */ |
- | |
737 | extern float strtof (const char *__nptr, char **__endptr); |
- | |
738 | extern long double strtold (const char *__nptr, char **__endptr); |
- | |
739 | //extern long long strtoll(const char *__nptr, char **__endptr, int __base) |
- | |
740 | #endif |
- | |
741 | - | ||
742 | #define strtold (long double)strtod |
- | |
743 | #define strtof (float)strtod |
- | |
744 | #define strtoll (long long)strtol |
- | |
745 | - | ||
746 | - | ||
747 | static char *pstrcpy(char *buf, int buf_size, const char *s); |
- | |
748 | static char *pstrcat(char *buf, int buf_size, const char *s); |
- | |
749 | static const char *tcc_basename(const char *name); |
- | |
750 | - | ||
751 | static void next(void); |
- | |
752 | static void next_nomacro(void); |
- | |
753 | static void parse_expr_type(CType *type); |
- | |
754 | static void expr_type(CType *type); |
- | |
755 | static void unary_type(CType *type); |
- | |
756 | static void block(int *bsym, int *csym, int *case_sym, int *def_sym, |
- | |
757 | int case_reg, int is_expr); |
- | |
758 | static int expr_const(void); |
- | |
759 | static void expr_eq(void); |
- | |
760 | static void gexpr(void); |
- | |
761 | static void gen_inline_functions(void); |
- | |
762 | static void decl(int l); |
- | |
763 | static void decl_initializer(CType *type, Section *sec, unsigned long c, |
- | |
764 | int first, int size_only); |
- | |
765 | static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, |
- | |
766 | int has_init, int v, int scope); |
- | |
767 | int gv(int rc); |
- | |
768 | void gv2(int rc1, int rc2); |
- | |
769 | void move_reg(int r, int s); |
- | |
770 | void save_regs(int n); |
- | |
771 | void save_reg(int r); |
- | |
772 | void vpop(void); |
- | |
773 | void vswap(void); |
- | |
774 | void vdup(void); |
- | |
775 | int get_reg(int rc); |
- | |
776 | int get_reg_ex(int rc,int rc2); |
- | |
777 | - | ||
778 | struct macro_level { |
- | |
779 | struct macro_level *prev; |
- | |
780 | int *p; |
- | |
781 | }; |
- | |
782 | - | ||
783 | static void macro_subst(TokenString *tok_str, Sym **nested_list, |
- | |
784 | const int *macro_str, struct macro_level **can_read_stream); |
- | |
785 | void gen_op(int op); |
- | |
786 | void force_charshort_cast(int t); |
- | |
787 | static void gen_cast(CType *type); |
- | |
788 | void vstore(void); |
- | |
789 | static Sym *sym_find(int v); |
- | |
790 | static Sym *sym_push(int v, CType *type, int r, int c); |
- | |
791 | - | ||
792 | /* type handling */ |
- | |
793 | static int type_size(CType *type, int *a); |
- | |
794 | static inline CType *pointed_type(CType *type); |
- | |
795 | static int pointed_size(CType *type); |
- | |
796 | static int lvalue_type(int t); |
- | |
797 | static int parse_btype(CType *type, AttributeDef *ad); |
- | |
798 | static void type_decl(CType *type, AttributeDef *ad, int *v, int td); |
- | |
799 | static int is_compatible_types(CType *type1, CType *type2); |
- | |
800 | - | ||
801 | int ieee_finite(double d); |
- | |
802 | void error(const char *fmt, ...); |
- | |
803 | void vpushi(int v); |
- | |
804 | void vrott(int n); |
- | |
805 | void vnrott(int n); |
- | |
806 | void lexpand_nr(void); |
- | |
807 | static void vpush_global_sym(CType *type, int v); |
- | |
808 | void vset(CType *type, int r, int v); |
- | |
809 | void type_to_str(char *buf, int buf_size, |
- | |
810 | CType *type, const char *varstr); |
- | |
811 | char *get_tok_str(int v, CValue *cv); |
- | |
812 | static Sym *get_sym_ref(CType *type, Section *sec, |
- | |
813 | unsigned long offset, unsigned long size); |
- | |
814 | static Sym *external_global_sym(int v, CType *type, int r); |
- | |
815 | - | ||
816 | /* section generation */ |
- | |
817 | static void section_realloc(Section *sec, unsigned long new_size); |
- | |
818 | static void *section_ptr_add(Section *sec, unsigned long size); |
- | |
819 | static void put_extern_sym(Sym *sym, Section *section, |
- | |
820 | unsigned long value, unsigned long size); |
- | |
821 | static void greloc(Section *s, Sym *sym, unsigned long addr, int type); |
- | |
822 | static int put_elf_str(Section *s, const char *sym); |
- | |
823 | static int put_elf_sym(Section *s, |
- | |
824 | unsigned long value, unsigned long size, |
- | |
825 | int info, int other, int shndx, const char *name); |
- | |
826 | static int add_elf_sym(Section *s, unsigned long value, unsigned long size, |
- | |
827 | int info, int other, int sh_num, const char *name); |
- | |
828 | static void put_elf_reloc(Section *symtab, Section *s, unsigned long offset, |
- | |
829 | int type, int symbol); |
- | |
830 | static void put_stabs(const char *str, int type, int other, int desc, |
- | |
831 | unsigned long value); |
- | |
832 | static void put_stabs_r(const char *str, int type, int other, int desc, |
- | |
833 | unsigned long value, Section *sec, int sym_index); |
- | |
834 | static void put_stabn(int type, int other, int desc, int value); |
- | |
835 | static void put_stabd(int type, int other, int desc); |
- | |
836 | static int tcc_add_dll(TCCState *s, const char *filename, int flags); |
- | |
837 | - | ||
838 | #define AFF_PRINT_ERROR 0x0001 /* print error if file not found */ |
- | |
839 | #define AFF_REFERENCED_DLL 0x0002 /* load a referenced dll from another dll */ |
- | |
840 | static int tcc_add_file_internal(TCCState *s, const char *filename, int flags); |
- | |
841 | - | ||
842 | /* tcccoff.c */ |
- | |
843 | int tcc_output_coff(TCCState *s1, FILE *f); |
- | |
844 | - | ||
845 | /* tccpe.c */ |
- | |
846 | void *resolve_sym(TCCState *s1, const char *sym, int type); |
- | |
847 | int pe_load_def_file(struct TCCState *s1, FILE *fp); |
- | |
848 | void pe_setup_paths(struct TCCState *s1, int *p_output_type, const char **p_outfile, char *first_file); |
- | |
849 | unsigned long pe_add_runtime(struct TCCState *s1); |
- | |
850 | int tcc_output_pe(struct TCCState *s1, const char *filename); |
- | |
851 | - | ||
852 | /* tccasm.c */ |
- | |
853 | - | ||
854 | #ifdef CONFIG_TCC_ASM |
- | |
855 | - | ||
856 | typedef struct ExprValue { |
- | |
857 | uint32_t v; |
- | |
858 | Sym *sym; |
- | |
859 | } ExprValue; |
- | |
860 | - | ||
861 | #define MAX_ASM_OPERANDS 30 |
- | |
862 | - | ||
863 | typedef struct ASMOperand { |
- | |
864 | int id; /* GCC 3 optionnal identifier (0 if number only supported */ |
- | |
865 | char *constraint; |
- | |
866 | char asm_str[16]; /* computed asm string for operand */ |
- | |
867 | SValue *vt; /* C value of the expression */ |
- | |
868 | int ref_index; /* if >= 0, gives reference to a output constraint */ |
- | |
869 | int input_index; /* if >= 0, gives reference to an input constraint */ |
- | |
870 | int priority; /* priority, used to assign registers */ |
- | |
871 | int reg; /* if >= 0, register number used for this operand */ |
- | |
872 | int is_llong; /* true if double register value */ |
- | |
873 | int is_memory; /* true if memory operand */ |
- | |
874 | int is_rw; /* for '+' modifier */ |
- | |
875 | } ASMOperand; |
- | |
876 | - | ||
877 | static void asm_expr(TCCState *s1, ExprValue *pe); |
- | |
878 | static int asm_int_expr(TCCState *s1); |
- | |
879 | static int find_constraint(ASMOperand *operands, int nb_operands, |
- | |
880 | const char *name, const char **pp); |
- | |
881 | - | ||
882 | static int tcc_assemble(TCCState *s1, int do_preprocess); |
- | |
883 | - | ||
884 | #endif |
- | |
885 | - | ||
886 | static void asm_instr(void); |
- | |
887 | static void asm_global_instr(void); |
- | |
888 | - | ||
889 | /* true if float/double/long double type */ |
- | |
890 | static inline int is_float(int t) |
- | |
891 | { |
- | |
892 | int bt; |
- | |
893 | bt = t & VT_BTYPE; |
- | |
894 | return bt == VT_LDOUBLE || bt == VT_DOUBLE || bt == VT_FLOAT; |
- | |
895 | } |
- | |
896 | - | ||
897 | #ifdef TCC_TARGET_I386 |
- | |
898 | #include "i386-gen.c" |
- | |
899 | #endif |
- | |
900 | - | ||
901 | #ifdef TCC_TARGET_ARM |
- | |
902 | #include "arm-gen.c" |
- | |
903 | #endif |
- | |
904 | - | ||
905 | #ifdef TCC_TARGET_C67 |
- | |
906 | #include "c67-gen.c" |
- | |
907 | #endif |
- | |
908 | - | ||
909 | #ifdef CONFIG_TCC_STATIC |
- | |
910 | - | ||
911 | #define RTLD_LAZY 0x001 |
- | |
912 | #define RTLD_NOW 0x002 |
- | |
913 | #define RTLD_GLOBAL 0x100 |
- | |
914 | #define RTLD_DEFAULT NULL |
- | |
915 | - | ||
916 | /* dummy function for profiling */ |
- | |
917 | void *dlopen(const char *filename, int flag) |
- | |
918 | { |
- | |
919 | return NULL; |
- | |
920 | } |
- | |
921 | - | ||
922 | const char *dlerror(void) |
- | |
923 | { |
- | |
924 | return "error"; |
- | |
925 | } |
- | |
926 | - | ||
927 | typedef struct TCCSyms { |
- | |
928 | char *str; |
- | |
929 | void *ptr; |
- | |
930 | } TCCSyms; |
- | |
931 | - | ||
932 | #define TCCSYM(a) { #a, &a, }, |
- | |
933 | - | ||
934 | /* add the symbol you want here if no dynamic linking is done */ |
- | |
935 | static TCCSyms tcc_syms[] = { |
- | |
936 | #if !defined(CONFIG_TCCBOOT) |
- | |
937 | TCCSYM(printf) |
- | |
938 | TCCSYM(printf) |
- | |
939 | TCCSYM(fopen) |
- | |
940 | TCCSYM(fclose) |
- | |
941 | #endif |
- | |
942 | { NULL, NULL }, |
- | |
943 | }; |
- | |
944 | - | ||
945 | void *resolve_sym(TCCState *s1, const char *symbol, int type) |
- | |
946 | { |
- | |
947 | TCCSyms *p; |
- | |
948 | p = tcc_syms; |
- | |
949 | while (p->str != NULL) { |
- | |
950 | if (!strcmp(p->str, symbol)) |
- | |
951 | return p->ptr; |
- | |
952 | p++; |
- | |
953 | } |
- | |
954 | return NULL; |
- | |
955 | } |
- | |
956 | - | ||
957 | #elif !defined(WIN32) |
- | |
958 | //------------------------------------------------------------------------- |
- | |
959 | //#include |
- | |
960 | - | ||
961 | void *resolve_sym(TCCState *s1, const char *sym, int type) |
- | |
962 | { |
- | |
963 | return(0); |
- | |
964 | //return dlsym(RTLD_DEFAULT, sym); |
- | |
965 | } |
- | |
966 | //------------------------------------------------------------------------- |
- | |
967 | #endif |
- | |
968 | - | ||
969 | /********************************************************/ |
- | |
970 | - | ||
971 | /* we use our own 'finite' function to avoid potential problems with |
- | |
972 | non standard math libs */ |
- | |
973 | /* XXX: endianness dependent */ |
- | |
974 | int ieee_finite(double d) |
- | |
975 | { |
- | |
976 | int *p = (int *)&d; |
- | |
977 | return ((unsigned)((p[1] | 0x800fffff) + 1)) >> 31; |
- | |
978 | } |
- | |
979 | - | ||
980 | /* copy a string and truncate it. */ |
- | |
981 | static char *pstrcpy(char *buf, int buf_size, const char *s) |
- | |
982 | { |
- | |
983 | char *q, *q_end; |
- | |
984 | int c; |
- | |
985 | - | ||
986 | if (buf_size > 0) { |
- | |
987 | q = buf; |
- | |
988 | q_end = buf + buf_size - 1; |
- | |
989 | while (q < q_end) { |
- | |
990 | c = *s++; |
- | |
991 | if (c == '\0') |
- | |
992 | break; |
- | |
993 | *q++ = c; |
- | |
994 | } |
- | |
995 | *q = '\0'; |
- | |
996 | } |
- | |
997 | return buf; |
- | |
998 | } |
- | |
999 | - | ||
1000 | /* strcat and truncate. */ |
- | |
1001 | static char *pstrcat(char *buf, int buf_size, const char *s) |
- | |
1002 | { |
- | |
1003 | int len; |
- | |
1004 | len = strlen(buf); |
- | |
1005 | if (len < buf_size) |
- | |
1006 | pstrcpy(buf + len, buf_size - len, s); |
- | |
1007 | return buf; |
- | |
1008 | } |
- | |
1009 | - | ||
1010 | static int strstart(const char *str, const char *val, const char **ptr) |
- | |
1011 | { |
- | |
1012 | const char *p, *q; |
- | |
1013 | p = str; |
- | |
1014 | q = val; |
- | |
1015 | while (*q != '\0') { |
- | |
1016 | if (*p != *q) |
- | |
1017 | return 0; |
- | |
1018 | p++; |
- | |
1019 | q++; |
- | |
1020 | } |
- | |
1021 | if (ptr) |
- | |
1022 | *ptr = p; |
- | |
1023 | return 1; |
- | |
1024 | } |
- | |
1025 | - | ||
1026 | /* memory management */ |
- | |
1027 | #ifdef MEM_DEBUG |
- | |
1028 | int mem_cur_size; |
- | |
1029 | int mem_max_size; |
- | |
1030 | #endif |
- | |
1031 | - | ||
1032 | static inline void tcc_free(void *ptr) |
- | |
1033 | { |
- | |
1034 | #ifdef MEM_DEBUG |
- | |
1035 | mem_cur_size -= malloc_usable_size(ptr); |
- | |
1036 | #endif |
- | |
1037 | //2016-04-27 siemargl commented to fix crash temporally. Need to fix |
- | |
1038 | // free(ptr); |
- | |
1039 | } |
- | |
1040 | - | ||
1041 | static void *tcc_malloc(unsigned long size) |
- | |
1042 | { |
- | |
1043 | void *ptr; |
- | |
1044 | ptr = malloc(size); |
- | |
1045 | if (!ptr && size) |
- | |
1046 | error("memory full"); |
- | |
1047 | #ifdef MEM_DEBUG |
- | |
1048 | mem_cur_size += malloc_usable_size(ptr); |
- | |
1049 | if (mem_cur_size > mem_max_size) |
- | |
1050 | mem_max_size = mem_cur_size; |
- | |
1051 | #endif |
- | |
1052 | return ptr; |
- | |
1053 | } |
- | |
1054 | - | ||
1055 | static void *tcc_mallocz(unsigned long size) |
- | |
1056 | { |
- | |
1057 | void *ptr; |
- | |
1058 | ptr = tcc_malloc(size); |
- | |
1059 | memset(ptr, 0, size); |
- | |
1060 | return ptr; |
- | |
1061 | } |
- | |
1062 | - | ||
1063 | static inline void *tcc_realloc(void *ptr, unsigned long size) |
- | |
1064 | { |
- | |
1065 | void *ptr1; |
- | |
1066 | #ifdef MEM_DEBUG |
- | |
1067 | mem_cur_size -= malloc_usable_size(ptr); |
- | |
1068 | #endif |
- | |
1069 | ptr1 = realloc(ptr, size); |
- | |
1070 | #ifdef MEM_DEBUG |
- | |
1071 | /* NOTE: count not correct if alloc error, but not critical */ |
- | |
1072 | mem_cur_size += malloc_usable_size(ptr1); |
- | |
1073 | if (mem_cur_size > mem_max_size) |
- | |
1074 | mem_max_size = mem_cur_size; |
- | |
1075 | #endif |
- | |
1076 | return ptr1; |
- | |
1077 | } |
- | |
1078 | - | ||
1079 | static char *tcc_strdup(const char *str) |
- | |
1080 | { |
- | |
1081 | char *ptr; |
- | |
1082 | ptr = tcc_malloc(strlen(str) + 1); |
- | |
1083 | strcpy(ptr, str); |
- | |
1084 | return ptr; |
- | |
1085 | } |
- | |
1086 | - | ||
1087 | #define free(p) use_tcc_free(p) |
- | |
1088 | #define malloc(s) use_tcc_malloc(s) |
- | |
1089 | #define realloc(p, s) use_tcc_realloc(p, s) |
- | |
1090 | - | ||
1091 | static void dynarray_add(void ***ptab, int *nb_ptr, void *data) |
- | |
1092 | { |
- | |
1093 | int nb, nb_alloc; |
- | |
1094 | void **pp; |
- | |
1095 | - | ||
1096 | nb = *nb_ptr; |
- | |
1097 | pp = *ptab; |
- | |
1098 | /* every power of two we double array size */ |
- | |
1099 | if ((nb & (nb - 1)) == 0) { |
- | |
1100 | if (!nb) |
- | |
1101 | nb_alloc = 1; |
- | |
1102 | else |
- | |
1103 | nb_alloc = nb * 2; |
- | |
1104 | pp = tcc_realloc(pp, nb_alloc * sizeof(void *)); |
- | |
1105 | if (!pp) |
- | |
1106 | error("memory full"); |
- | |
1107 | *ptab = pp; |
- | |
1108 | } |
- | |
1109 | pp[nb++] = data; |
- | |
1110 | *nb_ptr = nb; |
- | |
1111 | } |
- | |
1112 | - | ||
1113 | /* symbol allocator */ |
- | |
1114 | static Sym *__sym_malloc(void) |
- | |
1115 | { |
- | |
1116 | Sym *sym_pool, *sym, *last_sym; |
- | |
1117 | int i; |
- | |
1118 | - | ||
1119 | sym_pool = tcc_malloc(SYM_POOL_NB * sizeof(Sym)); |
- | |
1120 | - | ||
1121 | last_sym = sym_free_first; |
- | |
1122 | sym = sym_pool; |
- | |
1123 | for(i = 0; i < SYM_POOL_NB; i++) { |
- | |
1124 | sym->next = last_sym; |
- | |
1125 | last_sym = sym; |
- | |
1126 | sym++; |
- | |
1127 | } |
- | |
1128 | sym_free_first = last_sym; |
- | |
1129 | return last_sym; |
- | |
1130 | } |
- | |
1131 | - | ||
1132 | static inline Sym *sym_malloc(void) |
- | |
1133 | { |
- | |
1134 | Sym *sym; |
- | |
1135 | sym = sym_free_first; |
- | |
1136 | if (!sym) |
- | |
1137 | sym = __sym_malloc(); |
- | |
1138 | sym_free_first = sym->next; |
- | |
1139 | return sym; |
- | |
1140 | } |
- | |
1141 | - | ||
1142 | static inline void sym_free(Sym *sym) |
- | |
1143 | { |
- | |
1144 | sym->next = sym_free_first; |
- | |
1145 | sym_free_first = sym; |
- | |
1146 | } |
- | |
1147 | - | ||
1148 | Section *new_section(TCCState *s1, const char *name, int sh_type, int sh_flags) |
- | |
1149 | { |
- | |
1150 | Section *sec; |
- | |
1151 | - | ||
1152 | sec = tcc_mallocz(sizeof(Section) + strlen(name)); |
- | |
1153 | strcpy(sec->name, name); |
- | |
1154 | sec->sh_type = sh_type; |
- | |
1155 | sec->sh_flags = sh_flags; |
- | |
1156 | switch(sh_type) { |
- | |
1157 | case SHT_HASH: |
- | |
1158 | case SHT_REL: |
- | |
1159 | case SHT_DYNSYM: |
- | |
1160 | case SHT_SYMTAB: |
- | |
1161 | case SHT_DYNAMIC: |
- | |
1162 | sec->sh_addralign = 4; |
- | |
1163 | break; |
- | |
1164 | case SHT_STRTAB: |
- | |
1165 | sec->sh_addralign = 1; |
- | |
1166 | break; |
- | |
1167 | default: |
- | |
1168 | sec->sh_addralign = 32; /* default conservative alignment */ |
- | |
1169 | break; |
- | |
1170 | } |
- | |
1171 | - | ||
1172 | /* only add section if not private */ |
- | |
1173 | if (!(sh_flags & SHF_PRIVATE)) { |
- | |
1174 | sec->sh_num = s1->nb_sections; |
- | |
1175 | dynarray_add((void ***)&s1->sections, &s1->nb_sections, sec); |
- | |
1176 | } |
- | |
1177 | return sec; |
- | |
1178 | } |
- | |
1179 | - | ||
1180 | static void free_section(Section *s) |
- | |
1181 | { |
- | |
1182 | tcc_free(s->data); |
- | |
1183 | tcc_free(s); |
- | |
1184 | } |
- | |
1185 | - | ||
1186 | /* realloc section and set its content to zero */ |
- | |
1187 | static void section_realloc(Section *sec, unsigned long new_size) |
- | |
1188 | { |
- | |
1189 | unsigned long size; |
- | |
1190 | unsigned char *data; |
- | |
1191 | - | ||
1192 | size = sec->data_allocated; |
- | |
1193 | if (size == 0) |
- | |
1194 | size = 1; |
- | |
1195 | while (size < new_size) |
- | |
1196 | size = size * 2; |
- | |
1197 | data = tcc_realloc(sec->data, size); |
- | |
1198 | if (!data) |
- | |
1199 | error("memory full"); |
- | |
1200 | memset(data + sec->data_allocated, 0, size - sec->data_allocated); |
- | |
1201 | sec->data = data; |
- | |
1202 | sec->data_allocated = size; |
- | |
1203 | } |
- | |
1204 | - | ||
1205 | /* reserve at least 'size' bytes in section 'sec' from |
- | |
1206 | sec->data_offset. */ |
- | |
1207 | static void *section_ptr_add(Section *sec, unsigned long size) |
- | |
1208 | { |
- | |
1209 | unsigned long offset, offset1; |
- | |
1210 | - | ||
1211 | offset = sec->data_offset; |
- | |
1212 | offset1 = offset + size; |
- | |
1213 | if (offset1 > sec->data_allocated) |
- | |
1214 | section_realloc(sec, offset1); |
- | |
1215 | sec->data_offset = offset1; |
- | |
1216 | return sec->data + offset; |
- | |
1217 | } |
- | |
1218 | - | ||
1219 | /* return a reference to a section, and create it if it does not |
- | |
1220 | exists */ |
- | |
1221 | Section *find_section(TCCState *s1, const char *name) |
- | |
1222 | { |
- | |
1223 | Section *sec; |
- | |
1224 | int i; |
- | |
1225 | for(i = 1; i < s1->nb_sections; i++) { |
- | |
1226 | sec = s1->sections[i]; |
- | |
1227 | if (!strcmp(name, sec->name)) |
- | |
1228 | return sec; |
- | |
1229 | } |
- | |
1230 | /* sections are created as PROGBITS */ |
- | |
1231 | return new_section(s1, name, SHT_PROGBITS, SHF_ALLOC); |
- | |
1232 | } |
- | |
1233 | - | ||
1234 | #define SECTION_ABS ((void *)1) |
- | |
1235 | - | ||
1236 | /* update sym->c so that it points to an external symbol in section |
- | |
1237 | 'section' with value 'value' */ |
- | |
1238 | static void put_extern_sym2(Sym *sym, Section *section, |
- | |
1239 | unsigned long value, unsigned long size, |
- | |
1240 | int can_add_underscore) |
- | |
1241 | { |
- | |
1242 | int sym_type, sym_bind, sh_num, info; |
- | |
1243 | Elf32_Sym *esym; |
- | |
1244 | const char *name; |
- | |
1245 | char buf1[256]; |
- | |
1246 | - | ||
1247 | if (section == NULL) |
- | |
1248 | sh_num = SHN_UNDEF; |
- | |
1249 | else if (section == SECTION_ABS) |
- | |
1250 | sh_num = SHN_ABS; |
- | |
1251 | else |
- | |
1252 | sh_num = section->sh_num; |
- | |
1253 | if (!sym->c) { |
- | |
1254 | if ((sym->type.t & VT_BTYPE) == VT_FUNC) |
- | |
1255 | sym_type = STT_FUNC; |
- | |
1256 | else |
- | |
1257 | sym_type = STT_OBJECT; |
- | |
1258 | if (sym->type.t & VT_STATIC) |
- | |
1259 | sym_bind = STB_LOCAL; |
- | |
1260 | else |
- | |
1261 | sym_bind = STB_GLOBAL; |
- | |
1262 | - | ||
1263 | name = get_tok_str(sym->v, NULL); |
- | |
1264 | #ifdef CONFIG_TCC_BCHECK |
- | |
1265 | if (do_bounds_check) { |
- | |
1266 | char buf[32]; |
- | |
1267 | - | ||
1268 | /* XXX: avoid doing that for statics ? */ |
- | |
1269 | /* if bound checking is activated, we change some function |
- | |
1270 | names by adding the "__bound" prefix */ |
- | |
1271 | switch(sym->v) { |
- | |
1272 | #if 0 |
- | |
1273 | /* XXX: we rely only on malloc hooks */ |
- | |
1274 | case TOK_malloc: |
- | |
1275 | case TOK_free: |
- | |
1276 | case TOK_realloc: |
- | |
1277 | case TOK_memalign: |
- | |
1278 | case TOK_calloc: |
- | |
1279 | #endif |
- | |
1280 | case TOK_memcpy: |
- | |
1281 | case TOK_memmove: |
- | |
1282 | case TOK_memset: |
- | |
1283 | case TOK_strlen: |
- | |
1284 | case TOK_strcpy: |
- | |
1285 | strcpy(buf, "__bound_"); |
- | |
1286 | strcat(buf, name); |
- | |
1287 | name = buf; |
- | |
1288 | break; |
- | |
1289 | } |
- | |
1290 | } |
- | |
1291 | #endif |
- | |
1292 | if (tcc_state->leading_underscore && can_add_underscore) { |
- | |
1293 | buf1[0] = '_'; |
- | |
1294 | pstrcpy(buf1 + 1, sizeof(buf1) - 1, name); |
- | |
1295 | name = buf1; |
- | |
1296 | } |
- | |
1297 | info = ELF32_ST_INFO(sym_bind, sym_type); |
- | |
1298 | sym->c = add_elf_sym(symtab_section, value, size, info, 0, sh_num, name); |
- | |
1299 | } else { |
- | |
1300 | esym = &((Elf32_Sym *)symtab_section->data)[sym->c]; |
- | |
1301 | esym->st_value = value; |
- | |
1302 | esym->st_size = size; |
- | |
1303 | esym->st_shndx = sh_num; |
- | |
1304 | } |
- | |
1305 | } |
- | |
1306 | - | ||
1307 | static void put_extern_sym(Sym *sym, Section *section, |
- | |
1308 | unsigned long value, unsigned long size) |
- | |
1309 | { |
- | |
1310 | put_extern_sym2(sym, section, value, size, 1); |
- | |
1311 | } |
- | |
1312 | - | ||
1313 | /* add a new relocation entry to symbol 'sym' in section 's' */ |
- | |
1314 | static void greloc(Section *s, Sym *sym, unsigned long offset, int type) |
- | |
1315 | { |
- | |
1316 | if (!sym->c) |
- | |
1317 | put_extern_sym(sym, NULL, 0, 0); |
- | |
1318 | /* now we can add ELF relocation info */ |
- | |
1319 | put_elf_reloc(symtab_section, s, offset, type, sym->c); |
- | |
1320 | } |
- | |
1321 | - | ||
1322 | static inline int isid(int c) |
- | |
1323 | { |
- | |
1324 | return (c >= 'a' && c <= 'z') || |
- | |
1325 | (c >= 'A' && c <= 'Z') || |
- | |
1326 | c == '_'; |
- | |
1327 | } |
- | |
1328 | - | ||
1329 | static inline int isnum(int c) |
- | |
1330 | { |
- | |
1331 | return c >= '0' && c <= '9'; |
- | |
1332 | } |
- | |
1333 | - | ||
1334 | static inline int isoct(int c) |
- | |
1335 | { |
- | |
1336 | return c >= '0' && c <= '7'; |
- | |
1337 | } |
- | |
1338 | - | ||
1339 | static inline int toup(int c) |
- | |
1340 | { |
- | |
1341 | if (c >= 'a' && c <= 'z') |
- | |
1342 | return c - 'a' + 'A'; |
- | |
1343 | else |
- | |
1344 | return c; |
- | |
1345 | } |
- | |
1346 | - | ||
1347 | static void strcat_vprintf(char *buf, int buf_size, const char *fmt, va_list ap) |
- | |
1348 | { |
- | |
1349 | int len; |
- | |
1350 | len = strlen(buf); |
- | |
1351 | vsnprintf(buf + len, buf_size - len, fmt, ap); |
- | |
1352 | } |
- | |
1353 | - | ||
1354 | static void strcat_printf(char *buf, int buf_size, const char *fmt, ...) |
- | |
1355 | { |
- | |
1356 | va_list ap; |
- | |
1357 | va_start(ap, fmt); |
- | |
1358 | strcat_vprintf(buf, buf_size, fmt, ap); |
- | |
1359 | va_end(ap); |
- | |
1360 | } |
- | |
1361 | - | ||
1362 | void error1(TCCState *s1, int is_warning, const char *fmt, va_list ap) |
- | |
1363 | { |
- | |
1364 | char buf[2048]; |
- | |
1365 | BufferedFile **f; |
- | |
1366 | - | ||
1367 | buf[0] = '\0'; |
- | |
1368 | if (file) { |
- | |
1369 | for(f = s1->include_stack; f < s1->include_stack_ptr; f++) |
- | |
1370 | strcat_printf(buf, sizeof(buf), "In file included from %s:%d:\n", |
- | |
1371 | (*f)->filename, (*f)->line_num); |
- | |
1372 | if (file->line_num > 0) { |
- | |
1373 | strcat_printf(buf, sizeof(buf), |
- | |
1374 | "%s:%d: ", file->filename, file->line_num); |
- | |
1375 | } else { |
- | |
1376 | strcat_printf(buf, sizeof(buf), |
- | |
1377 | "%s: ", file->filename); |
- | |
1378 | } |
- | |
1379 | } else { |
- | |
1380 | strcat_printf(buf, sizeof(buf), |
- | |
1381 | "tcc: "); |
- | |
1382 | } |
- | |
1383 | if (is_warning) |
- | |
1384 | strcat_printf(buf, sizeof(buf), "warning: "); |
- | |
1385 | strcat_vprintf(buf, sizeof(buf), fmt, ap); |
- | |
1386 | - | ||
1387 | if (!s1->error_func) { |
- | |
1388 | /* default case: stderr */ |
- | |
1389 | printf("%s\n", buf); |
- | |
1390 | } else { |
- | |
1391 | s1->error_func(s1->error_opaque, buf); |
- | |
1392 | } |
- | |
1393 | if (!is_warning || s1->warn_error) |
- | |
1394 | s1->nb_errors++; |
- | |
1395 | } |
- | |
1396 | - | ||
1397 | #ifdef LIBTCC |
- | |
1398 | void tcc_set_error_func(TCCState *s, void *error_opaque, |
- | |
1399 | void (*error_func)(void *opaque, const char *msg)) |
- | |
1400 | { |
- | |
1401 | s->error_opaque = error_opaque; |
- | |
1402 | s->error_func = error_func; |
- | |
1403 | } |
- | |
1404 | #endif |
- | |
1405 | - | ||
1406 | /* error without aborting current compilation */ |
- | |
1407 | void error_noabort(const char *fmt, ...) |
- | |
1408 | { |
- | |
1409 | TCCState *s1 = tcc_state; |
- | |
1410 | va_list ap; |
- | |
1411 | - | ||
1412 | va_start(ap, fmt); |
- | |
1413 | error1(s1, 0, fmt, ap); |
- | |
1414 | va_end(ap); |
- | |
1415 | } |
- | |
1416 | - | ||
1417 | void error(const char *fmt, ...) |
- | |
1418 | { |
- | |
1419 | TCCState *s1 = tcc_state; |
- | |
1420 | va_list ap; |
- | |
1421 | - | ||
1422 | va_start(ap, fmt); |
- | |
1423 | error1(s1, 0, fmt, ap); |
- | |
1424 | va_end(ap); |
- | |
1425 | /* better than nothing: in some cases, we accept to handle errors */ |
- | |
1426 | if (s1->error_set_jmp_enabled) { |
- | |
1427 | longjmp(s1->error_jmp_buf, 1); |
- | |
1428 | } else { |
- | |
1429 | /* XXX: eliminate this someday */ |
- | |
1430 | exit(1); |
- | |
1431 | } |
- | |
1432 | } |
- | |
1433 | - | ||
1434 | void expect(const char *msg) |
- | |
1435 | { |
- | |
1436 | error("%s expected", msg); |
- | |
1437 | } |
- | |
1438 | - | ||
1439 | void warning(const char *fmt, ...) |
- | |
1440 | { |
- | |
1441 | TCCState *s1 = tcc_state; |
- | |
1442 | va_list ap; |
- | |
1443 | - | ||
1444 | if (s1->warn_none) |
- | |
1445 | return; |
- | |
1446 | - | ||
1447 | va_start(ap, fmt); |
- | |
1448 | error1(s1, 1, fmt, ap); |
- | |
1449 | va_end(ap); |
- | |
1450 | } |
- | |
1451 | - | ||
1452 | void skip(int c) |
- | |
1453 | { |
- | |
1454 | if (tok != c) |
- | |
1455 | error("'%c' expected", c); |
- | |
1456 | next(); |
- | |
1457 | } |
- | |
1458 | - | ||
1459 | static void test_lvalue(void) |
- | |
1460 | { |
- | |
1461 | if (!(vtop->r & VT_LVAL)) |
- | |
1462 | expect("lvalue"); |
- | |
1463 | } |
- | |
1464 | - | ||
1465 | /* allocate a new token */ |
- | |
1466 | static TokenSym *tok_alloc_new(TokenSym **pts, const char *str, int len) |
- | |
1467 | { |
- | |
1468 | TokenSym *ts, **ptable; |
- | |
1469 | int i; |
- | |
1470 | - | ||
1471 | if (tok_ident >= SYM_FIRST_ANOM) |
- | |
1472 | error("memory full"); |
- | |
1473 | - | ||
1474 | /* expand token table if needed */ |
- | |
1475 | i = tok_ident - TOK_IDENT; |
- | |
1476 | if ((i % TOK_ALLOC_INCR) == 0) { |
- | |
1477 | ptable = tcc_realloc(table_ident, (i + TOK_ALLOC_INCR) * sizeof(TokenSym *)); |
- | |
1478 | if (!ptable) |
- | |
1479 | error("memory full"); |
- | |
1480 | table_ident = ptable; |
- | |
1481 | } |
- | |
1482 | - | ||
1483 | ts = tcc_malloc(sizeof(TokenSym) + len); |
- | |
1484 | table_ident[i] = ts; |
- | |
1485 | ts->tok = tok_ident++; |
- | |
1486 | ts->sym_define = NULL; |
- | |
1487 | ts->sym_label = NULL; |
- | |
1488 | ts->sym_struct = NULL; |
- | |
1489 | ts->sym_identifier = NULL; |
- | |
1490 | ts->len = len; |
- | |
1491 | ts->hash_next = NULL; |
- | |
1492 | memcpy(ts->str, str, len); |
- | |
1493 | ts->str[len] = '\0'; |
- | |
1494 | *pts = ts; |
- | |
1495 | return ts; |
- | |
1496 | } |
- | |
1497 | - | ||
1498 | #define TOK_HASH_INIT 1 |
- | |
1499 | #define TOK_HASH_FUNC(h, c) ((h) * 263 + (c)) |
- | |
1500 | - | ||
1501 | /* find a token and add it if not found */ |
- | |
1502 | static TokenSym *tok_alloc(const char *str, int len) |
- | |
1503 | { |
- | |
1504 | TokenSym *ts, **pts; |
- | |
1505 | int i; |
- | |
1506 | unsigned int h; |
- | |
1507 | - | ||
1508 | h = TOK_HASH_INIT; |
- | |
1509 | for(i=0;i |
- | |
1510 | h = TOK_HASH_FUNC(h, ((unsigned char *)str)[i]); |
- | |
1511 | h &= (TOK_HASH_SIZE - 1); |
- | |
1512 | - | ||
1513 | pts = &hash_ident[h]; |
- | |
1514 | for(;;) { |
- | |
1515 | ts = *pts; |
- | |
1516 | if (!ts) |
- | |
1517 | break; |
- | |
1518 | if (ts->len == len && !memcmp(ts->str, str, len)) |
- | |
1519 | return ts; |
- | |
1520 | pts = &(ts->hash_next); |
- | |
1521 | } |
- | |
1522 | return tok_alloc_new(pts, str, len); |
- | |
1523 | } |
- | |
1524 | - | ||
1525 | /* CString handling */ |
- | |
1526 | - | ||
1527 | static void cstr_realloc(CString *cstr, int new_size) |
- | |
1528 | { |
- | |
1529 | int size; |
- | |
1530 | void *data; |
- | |
1531 | - | ||
1532 | size = cstr->size_allocated; |
- | |
1533 | if (size == 0) |
- | |
1534 | size = 8; /* no need to allocate a too small first string */ |
- | |
1535 | while (size < new_size) |
- | |
1536 | size = size * 2; |
- | |
1537 | data = tcc_realloc(cstr->data_allocated, size); |
- | |
1538 | if (!data) |
- | |
1539 | error("memory full"); |
- | |
1540 | cstr->data_allocated = data; |
- | |
1541 | cstr->size_allocated = size; |
- | |
1542 | cstr->data = data; |
- | |
1543 | } |
- | |
1544 | - | ||
1545 | /* add a byte */ |
- | |
1546 | static inline void cstr_ccat(CString *cstr, int ch) |
- | |
1547 | { |
- | |
1548 | int size; |
- | |
1549 | size = cstr->size + 1; |
- | |
1550 | if (size > cstr->size_allocated) |
- | |
1551 | cstr_realloc(cstr, size); |
- | |
1552 | ((unsigned char *)cstr->data)[size - 1] = ch; |
- | |
1553 | cstr->size = size; |
- | |
1554 | } |
- | |
1555 | - | ||
1556 | static void cstr_cat(CString *cstr, const char *str) |
- | |
1557 | { |
- | |
1558 | int c; |
- | |
1559 | for(;;) { |
- | |
1560 | c = *str; |
- | |
1561 | if (c == '\0') |
- | |
1562 | break; |
- | |
1563 | cstr_ccat(cstr, c); |
- | |
1564 | str++; |
- | |
1565 | } |
- | |
1566 | } |
- | |
1567 | - | ||
1568 | /* add a wide char */ |
- | |
1569 | static void cstr_wccat(CString *cstr, int ch) |
- | |
1570 | { |
- | |
1571 | int size; |
- | |
1572 | size = cstr->size + sizeof(int); |
- | |
1573 | if (size > cstr->size_allocated) |
- | |
1574 | cstr_realloc(cstr, size); |
- | |
1575 | *(int *)(((unsigned char *)cstr->data) + size - sizeof(int)) = ch; |
- | |
1576 | cstr->size = size; |
- | |
1577 | } |
- | |
1578 | - | ||
1579 | static void cstr_new(CString *cstr) |
- | |
1580 | { |
- | |
1581 | memset(cstr, 0, sizeof(CString)); |
- | |
1582 | } |
- | |
1583 | - | ||
1584 | /* free string and reset it to NULL */ |
- | |
1585 | static void cstr_free(CString *cstr) |
- | |
1586 | { |
- | |
1587 | tcc_free(cstr->data_allocated); |
- | |
1588 | cstr_new(cstr); |
- | |
1589 | } |
- | |
1590 | - | ||
1591 | #define cstr_reset(cstr) cstr_free(cstr) |
- | |
1592 | - | ||
1593 | /* XXX: unicode ? */ |
- | |
1594 | static void add_char(CString *cstr, int c) |
- | |
1595 | { |
- | |
1596 | if (c == '\'' || c == '\"' || c == '\\') { |
- | |
1597 | /* XXX: could be more precise if char or string */ |
- | |
1598 | cstr_ccat(cstr, '\\'); |
- | |
1599 | } |
- | |
1600 | if (c >= 32 && c <= 126) { |
- | |
1601 | cstr_ccat(cstr, c); |
- | |
1602 | } else { |
- | |
1603 | cstr_ccat(cstr, '\\'); |
- | |
1604 | if (c == '\n') { |
- | |
1605 | cstr_ccat(cstr, 'n'); |
- | |
1606 | } else { |
- | |
1607 | cstr_ccat(cstr, '0' + ((c >> 6) & 7)); |
- | |
1608 | cstr_ccat(cstr, '0' + ((c >> 3) & 7)); |
- | |
1609 | cstr_ccat(cstr, '0' + (c & 7)); |
- | |
1610 | } |
- | |
1611 | } |
- | |
1612 | } |
- | |
1613 | - | ||
1614 | /* XXX: buffer overflow */ |
- | |
1615 | /* XXX: float tokens */ |
- | |
1616 | char *get_tok_str(int v, CValue *cv) |
- | |
1617 | { |
- | |
1618 | static char buf[STRING_MAX_SIZE + 1]; |
- | |
1619 | static CString cstr_buf; |
- | |
1620 | CString *cstr; |
- | |
1621 | unsigned char *q; |
- | |
1622 | char *p; |
- | |
1623 | int i, len; |
- | |
1624 | - | ||
1625 | /* NOTE: to go faster, we give a fixed buffer for small strings */ |
- | |
1626 | cstr_reset(&cstr_buf); |
- | |
1627 | cstr_buf.data = buf; |
- | |
1628 | cstr_buf.size_allocated = sizeof(buf); |
- | |
1629 | p = buf; |
- | |
1630 | - | ||
1631 | switch(v) { |
- | |
1632 | case TOK_CINT: |
- | |
1633 | case TOK_CUINT: |
- | |
1634 | /* XXX: not quite exact, but only useful for testing */ |
- | |
1635 | sprintf(p, "%u", cv->ui); |
- | |
1636 | break; |
- | |
1637 | case TOK_CLLONG: |
- | |
1638 | case TOK_CULLONG: |
- | |
1639 | /* XXX: not quite exact, but only useful for testing */ |
- | |
1640 | sprintf(p, "%Lu", cv->ull); |
- | |
1641 | break; |
- | |
1642 | case TOK_CCHAR: |
- | |
1643 | case TOK_LCHAR: |
- | |
1644 | cstr_ccat(&cstr_buf, '\''); |
- | |
1645 | add_char(&cstr_buf, cv->i); |
- | |
1646 | cstr_ccat(&cstr_buf, '\''); |
- | |
1647 | cstr_ccat(&cstr_buf, '\0'); |
- | |
1648 | break; |
- | |
1649 | case TOK_PPNUM: |
- | |
1650 | cstr = cv->cstr; |
- | |
1651 | len = cstr->size - 1; |
- | |
1652 | for(i=0;i |
- | |
1653 | add_char(&cstr_buf, ((unsigned char *)cstr->data)[i]); |
- | |
1654 | cstr_ccat(&cstr_buf, '\0'); |
- | |
1655 | break; |
- | |
1656 | case TOK_STR: |
- | |
1657 | case TOK_LSTR: |
- | |
1658 | cstr = cv->cstr; |
- | |
1659 | cstr_ccat(&cstr_buf, '\"'); |
- | |
1660 | if (v == TOK_STR) { |
- | |
1661 | len = cstr->size - 1; |
- | |
1662 | for(i=0;i |
- | |
1663 | add_char(&cstr_buf, ((unsigned char *)cstr->data)[i]); |
- | |
1664 | } else { |
- | |
1665 | len = (cstr->size / sizeof(int)) - 1; |
- | |
1666 | for(i=0;i |
- | |
1667 | add_char(&cstr_buf, ((int *)cstr->data)[i]); |
- | |
1668 | } |
- | |
1669 | cstr_ccat(&cstr_buf, '\"'); |
- | |
1670 | cstr_ccat(&cstr_buf, '\0'); |
- | |
1671 | break; |
- | |
1672 | case TOK_LT: |
- | |
1673 | v = '<'; |
- | |
1674 | goto addv; |
- | |
1675 | case TOK_GT: |
- | |
1676 | v = '>'; |
- | |
1677 | goto addv; |
- | |
1678 | case TOK_A_SHL: |
- | |
1679 | return strcpy(p, "<<="); |
- | |
1680 | case TOK_A_SAR: |
- | |
1681 | return strcpy(p, ">>="); |
- | |
1682 | default: |
- | |
1683 | if (v < TOK_IDENT) { |
- | |
1684 | /* search in two bytes table */ |
- | |
1685 | q = tok_two_chars; |
- | |
1686 | while (*q) { |
- | |
1687 | if (q[2] == v) { |
- | |
1688 | *p++ = q[0]; |
- | |
1689 | *p++ = q[1]; |
- | |
1690 | *p = '\0'; |
- | |
1691 | return buf; |
- | |
1692 | } |
- | |
1693 | q += 3; |
- | |
1694 | } |
- | |
1695 | addv: |
- | |
1696 | *p++ = v; |
- | |
1697 | *p = '\0'; |
- | |
1698 | } else if (v < tok_ident) { |
- | |
1699 | return table_ident[v - TOK_IDENT]->str; |
- | |
1700 | } else if (v >= SYM_FIRST_ANOM) { |
- | |
1701 | /* special name for anonymous symbol */ |
- | |
1702 | sprintf(p, "L.%u", v - SYM_FIRST_ANOM); |
- | |
1703 | } else { |
- | |
1704 | /* should never happen */ |
- | |
1705 | return NULL; |
- | |
1706 | } |
- | |
1707 | break; |
- | |
1708 | } |
- | |
1709 | return cstr_buf.data; |
- | |
1710 | } |
- | |
1711 | - | ||
1712 | /* push, without hashing */ |
- | |
1713 | static Sym *sym_push2(Sym **ps, int v, int t, int c) |
- | |
1714 | { |
- | |
1715 | Sym *s; |
- | |
1716 | s = sym_malloc(); |
- | |
1717 | s->v = v; |
- | |
1718 | s->type.t = t; |
- | |
1719 | s->c = c; |
- | |
1720 | s->next = NULL; |
- | |
1721 | /* add in stack */ |
- | |
1722 | s->prev = *ps; |
- | |
1723 | *ps = s; |
- | |
1724 | return s; |
- | |
1725 | } |
- | |
1726 | - | ||
1727 | /* find a symbol and return its associated structure. 's' is the top |
- | |
1728 | of the symbol stack */ |
- | |
1729 | static Sym *sym_find2(Sym *s, int v) |
- | |
1730 | { |
- | |
1731 | while (s) { |
- | |
1732 | if (s->v == v) |
- | |
1733 | return s; |
- | |
1734 | s = s->prev; |
- | |
1735 | } |
- | |
1736 | return NULL; |
- | |
1737 | } |
- | |
1738 | - | ||
1739 | /* structure lookup */ |
- | |
1740 | static inline Sym *struct_find(int v) |
- | |
1741 | { |
- | |
1742 | v -= TOK_IDENT; |
- | |
1743 | if ((unsigned)v >= (unsigned)(tok_ident - TOK_IDENT)) |
- | |
1744 | return NULL; |
- | |
1745 | return table_ident[v]->sym_struct; |
- | |
1746 | } |
- | |
1747 | - | ||
1748 | /* find an identifier */ |
- | |
1749 | static inline Sym *sym_find(int v) |
- | |
1750 | { |
- | |
1751 | v -= TOK_IDENT; |
- | |
1752 | if ((unsigned)v >= (unsigned)(tok_ident - TOK_IDENT)) |
- | |
1753 | return NULL; |
- | |
1754 | return table_ident[v]->sym_identifier; |
- | |
1755 | } |
- | |
1756 | - | ||
1757 | /* push a given symbol on the symbol stack */ |
- | |
1758 | static Sym *sym_push(int v, CType *type, int r, int c) |
- | |
1759 | { |
- | |
1760 | Sym *s, **ps; |
- | |
1761 | TokenSym *ts; |
- | |
1762 | - | ||
1763 | if (local_stack) |
- | |
1764 | ps = &local_stack; |
- | |
1765 | else |
- | |
1766 | ps = &global_stack; |
- | |
1767 | s = sym_push2(ps, v, type->t, c); |
- | |
1768 | s->type.ref = type->ref; |
- | |
1769 | s->r = r; |
- | |
1770 | /* don't record fields or anonymous symbols */ |
- | |
1771 | /* XXX: simplify */ |
- | |
1772 | if (!(v & SYM_FIELD) && (v & ~SYM_STRUCT) < SYM_FIRST_ANOM) { |
- | |
1773 | /* record symbol in token array */ |
- | |
1774 | ts = table_ident[(v & ~SYM_STRUCT) - TOK_IDENT]; |
- | |
1775 | if (v & SYM_STRUCT) |
- | |
1776 | ps = &ts->sym_struct; |
- | |
1777 | else |
- | |
1778 | ps = &ts->sym_identifier; |
- | |
1779 | s->prev_tok = *ps; |
- | |
1780 | *ps = s; |
- | |
1781 | } |
- | |
1782 | return s; |
- | |
1783 | } |
- | |
1784 | - | ||
1785 | /* push a global identifier */ |
- | |
1786 | static Sym *global_identifier_push(int v, int t, int c) |
- | |
1787 | { |
- | |
1788 | Sym *s, **ps; |
- | |
1789 | s = sym_push2(&global_stack, v, t, c); |
- | |
1790 | /* don't record anonymous symbol */ |
- | |
1791 | if (v < SYM_FIRST_ANOM) { |
- | |
1792 | ps = &table_ident[v - TOK_IDENT]->sym_identifier; |
- | |
1793 | /* modify the top most local identifier, so that |
- | |
1794 | sym_identifier will point to 's' when popped */ |
- | |
1795 | while (*ps != NULL) |
- | |
1796 | ps = &(*ps)->prev_tok; |
- | |
1797 | s->prev_tok = NULL; |
- | |
1798 | *ps = s; |
- | |
1799 | } |
- | |
1800 | return s; |
- | |
1801 | } |
- | |
1802 | - | ||
1803 | /* pop symbols until top reaches 'b' */ |
- | |
1804 | static void sym_pop(Sym **ptop, Sym *b) |
- | |
1805 | { |
- | |
1806 | Sym *s, *ss, **ps; |
- | |
1807 | TokenSym *ts; |
- | |
1808 | int v; |
- | |
1809 | - | ||
1810 | s = *ptop; |
- | |
1811 | while(s != b) { |
- | |
1812 | ss = s->prev; |
- | |
1813 | v = s->v; |
- | |
1814 | /* remove symbol in token array */ |
- | |
1815 | /* XXX: simplify */ |
- | |
1816 | if (!(v & SYM_FIELD) && (v & ~SYM_STRUCT) < SYM_FIRST_ANOM) { |
- | |
1817 | ts = table_ident[(v & ~SYM_STRUCT) - TOK_IDENT]; |
- | |
1818 | if (v & SYM_STRUCT) |
- | |
1819 | ps = &ts->sym_struct; |
- | |
1820 | else |
- | |
1821 | ps = &ts->sym_identifier; |
- | |
1822 | *ps = s->prev_tok; |
- | |
1823 | } |
- | |
1824 | sym_free(s); |
- | |
1825 | s = ss; |
- | |
1826 | } |
- | |
1827 | *ptop = b; |
- | |
1828 | } |
- | |
1829 | - | ||
1830 | /* I/O layer */ |
- | |
1831 | - | ||
1832 | BufferedFile *tcc_open(TCCState *s1, const char *filename) |
- | |
1833 | { |
- | |
1834 | int fd; |
- | |
1835 | BufferedFile *bf; |
- | |
1836 | - | ||
1837 | fd = open(filename, O_RDONLY | O_BINARY); |
- | |
1838 | if (fd < 0) |
- | |
1839 | return NULL; |
- | |
1840 | bf = tcc_malloc(sizeof(BufferedFile)); |
- | |
1841 | if (!bf) { |
- | |
1842 | close(fd); |
- | |
1843 | return NULL; |
- | |
1844 | } |
- | |
1845 | bf->fd = fd; |
- | |
1846 | bf->buf_ptr = bf->buffer; |
- | |
1847 | bf->buf_end = bf->buffer; |
- | |
1848 | bf->buffer[0] = CH_EOB; /* put eob symbol */ |
- | |
1849 | pstrcpy(bf->filename, sizeof(bf->filename), filename); |
- | |
1850 | bf->line_num = 1; |
- | |
1851 | bf->ifndef_macro = 0; |
- | |
1852 | bf->ifdef_stack_ptr = s1->ifdef_stack_ptr; |
- | |
1853 | // printf("opening '%s'\n", filename); |
- | |
1854 | return bf; |
- | |
1855 | } |
- | |
1856 | - | ||
1857 | void tcc_close(BufferedFile *bf) |
- | |
1858 | { |
- | |
1859 | total_lines += bf->line_num; |
- | |
1860 | close(bf->fd); |
- | |
1861 | tcc_free(bf); |
- | |
1862 | } |
- | |
1863 | - | ||
1864 | /* fill input buffer and peek next char */ |
- | |
1865 | static int tcc_peekc_slow(BufferedFile *bf) |
- | |
1866 | { |
- | |
1867 | int len; |
- | |
1868 | /* only tries to read if really end of buffer */ |
- | |
1869 | if (bf->buf_ptr >= bf->buf_end) { |
- | |
1870 | if (bf->fd != -1) { |
- | |
1871 | #if defined(PARSE_DEBUG) |
- | |
1872 | len = 8; |
- | |
1873 | #else |
- | |
1874 | len = IO_BUF_SIZE; |
- | |
1875 | #endif |
- | |
1876 | len = read(bf->fd, bf->buffer, len); |
- | |
1877 | if (len < 0) |
- | |
1878 | len = 0; |
- | |
1879 | } else { |
- | |
1880 | len = 0; |
- | |
1881 | } |
- | |
1882 | total_bytes += len; |
- | |
1883 | bf->buf_ptr = bf->buffer; |
- | |
1884 | bf->buf_end = bf->buffer + len; |
- | |
1885 | *bf->buf_end = CH_EOB; |
- | |
1886 | } |
- | |
1887 | if (bf->buf_ptr < bf->buf_end) { |
- | |
1888 | return bf->buf_ptr[0]; |
- | |
1889 | } else { |
- | |
1890 | bf->buf_ptr = bf->buf_end; |
- | |
1891 | return CH_EOF; |
- | |
1892 | } |
- | |
1893 | } |
- | |
1894 | - | ||
1895 | /* return the current character, handling end of block if necessary |
- | |
1896 | (but not stray) */ |
- | |
1897 | static int handle_eob(void) |
- | |
1898 | { |
- | |
1899 | return tcc_peekc_slow(file); |
- | |
1900 | } |
- | |
1901 | - | ||
1902 | /* read next char from current input file and handle end of input buffer */ |
- | |
1903 | static inline void input(void) |
- | |
1904 | { |
- | |
1905 | ch = *(++(file->buf_ptr)); |
- | |
1906 | /* end of buffer/file handling */ |
- | |
1907 | if (ch == CH_EOB) |
- | |
1908 | ch = handle_eob(); |
- | |
1909 | } |
- | |
1910 | - | ||
1911 | /* handle '\[\r]\n' */ |
- | |
1912 | static void handle_stray(void) |
- | |
1913 | { |
- | |
1914 | while (ch == '\\') { |
- | |
1915 | input(); |
- | |
1916 | if (ch == '\n') { |
- | |
1917 | file->line_num++; |
- | |
1918 | input(); |
- | |
1919 | } else if (ch == '\r') { |
- | |
1920 | input(); |
- | |
1921 | if (ch != '\n') |
- | |
1922 | goto fail; |
- | |
1923 | file->line_num++; |
- | |
1924 | input(); |
- | |
1925 | } else { |
- | |
1926 | fail: |
- | |
1927 | error("stray '\\' in program"); |
- | |
1928 | } |
- | |
1929 | } |
- | |
1930 | } |
- | |
1931 | - | ||
1932 | /* skip the stray and handle the \\n case. Output an error if |
- | |
1933 | incorrect char after the stray */ |
- | |
1934 | static int handle_stray1(uint8_t *p) |
- | |
1935 | { |
- | |
1936 | int c; |
- | |
1937 | - | ||
1938 | if (p >= file->buf_end) { |
- | |
1939 | file->buf_ptr = p; |
- | |
1940 | c = handle_eob(); |
- | |
1941 | p = file->buf_ptr; |
- | |
1942 | if (c == '\\') |
- | |
1943 | goto parse_stray; |
- | |
1944 | } else { |
- | |
1945 | parse_stray: |
- | |
1946 | file->buf_ptr = p; |
- | |
1947 | ch = *p; |
- | |
1948 | handle_stray(); |
- | |
1949 | p = file->buf_ptr; |
- | |
1950 | c = *p; |
- | |
1951 | } |
- | |
1952 | return c; |
- | |
1953 | } |
- | |
1954 | - | ||
1955 | /* handle just the EOB case, but not stray */ |
- | |
1956 | #define PEEKC_EOB(c, p)\ |
- | |
1957 | {\ |
- | |
1958 | p++;\ |
- | |
1959 | c = *p;\ |
- | |
1960 | if (c == '\\') {\ |
- | |
1961 | file->buf_ptr = p;\ |
- | |
1962 | c = handle_eob();\ |
- | |
1963 | p = file->buf_ptr;\ |
- | |
1964 | }\ |
- | |
1965 | } |
- | |
1966 | - | ||
1967 | /* handle the complicated stray case */ |
- | |
1968 | #define PEEKC(c, p)\ |
- | |
1969 | {\ |
- | |
1970 | p++;\ |
- | |
1971 | c = *p;\ |
- | |
1972 | if (c == '\\') {\ |
- | |
1973 | c = handle_stray1(p);\ |
- | |
1974 | p = file->buf_ptr;\ |
- | |
1975 | }\ |
- | |
1976 | } |
- | |
1977 | - | ||
1978 | /* input with '\[\r]\n' handling. Note that this function cannot |
- | |
1979 | handle other characters after '\', so you cannot call it inside |
- | |
1980 | strings or comments */ |
- | |
1981 | static void minp(void) |
- | |
1982 | { |
- | |
1983 | input(); |
- | |
1984 | if (ch == '\\') |
- | |
1985 | handle_stray(); |
- | |
1986 | } |
- | |
1987 | - | ||
1988 | - | ||
1989 | /* single line C++ comments */ |
- | |
1990 | static uint8_t *parse_line_comment(uint8_t *p) |
- | |
1991 | { |
- | |
1992 | int c; |
- | |
1993 | - | ||
1994 | p++; |
- | |
1995 | for(;;) { |
- | |
1996 | c = *p; |
- | |
1997 | redo: |
- | |
1998 | if (c == '\n' || c == CH_EOF) { |
- | |
1999 | break; |
- | |
2000 | } else if (c == '\\') { |
- | |
2001 | file->buf_ptr = p; |
- | |
2002 | c = handle_eob(); |
- | |
2003 | p = file->buf_ptr; |
- | |
2004 | if (c == '\\') { |
- | |
2005 | PEEKC_EOB(c, p); |
- | |
2006 | if (c == '\n') { |
- | |
2007 | file->line_num++; |
- | |
2008 | PEEKC_EOB(c, p); |
- | |
2009 | } else if (c == '\r') { |
- | |
2010 | PEEKC_EOB(c, p); |
- | |
2011 | if (c == '\n') { |
- | |
2012 | file->line_num++; |
- | |
2013 | PEEKC_EOB(c, p); |
- | |
2014 | } |
- | |
2015 | } |
- | |
2016 | } else { |
- | |
2017 | goto redo; |
- | |
2018 | } |
- | |
2019 | } else { |
- | |
2020 | p++; |
- | |
2021 | } |
- | |
2022 | } |
- | |
2023 | return p; |
- | |
2024 | } |
- | |
2025 | - | ||
2026 | /* C comments */ |
- | |
2027 | static uint8_t *parse_comment(uint8_t *p) |
- | |
2028 | { |
- | |
2029 | int c; |
- | |
2030 | - | ||
2031 | p++; |
- | |
2032 | for(;;) { |
- | |
2033 | /* fast skip loop */ |
- | |
2034 | for(;;) { |
- | |
2035 | c = *p; |
- | |
2036 | if (c == '\n' || c == '*' || c == '\\') |
- | |
2037 | break; |
- | |
2038 | p++; |
- | |
2039 | c = *p; |
- | |
2040 | if (c == '\n' || c == '*' || c == '\\') |
- | |
2041 | break; |
- | |
2042 | p++; |
- | |
2043 | } |
- | |
2044 | /* now we can handle all the cases */ |
- | |
2045 | if (c == '\n') { |
- | |
2046 | file->line_num++; |
- | |
2047 | p++; |
- | |
2048 | } else if (c == '*') { |
- | |
2049 | p++; |
- | |
2050 | for(;;) { |
- | |
2051 | c = *p; |
- | |
2052 | if (c == '*') { |
- | |
2053 | p++; |
- | |
2054 | } else if (c == '/') { |
- | |
2055 | goto end_of_comment; |
- | |
2056 | } else if (c == '\\') { |
- | |
2057 | file->buf_ptr = p; |
- | |
2058 | c = handle_eob(); |
- | |
2059 | p = file->buf_ptr; |
- | |
2060 | if (c == '\\') { |
- | |
2061 | /* skip '\[\r]\n', otherwise just skip the stray */ |
- | |
2062 | while (c == '\\') { |
- | |
2063 | PEEKC_EOB(c, p); |
- | |
2064 | if (c == '\n') { |
- | |
2065 | file->line_num++; |
- | |
2066 | PEEKC_EOB(c, p); |
- | |
2067 | } else if (c == '\r') { |
- | |
2068 | PEEKC_EOB(c, p); |
- | |
2069 | if (c == '\n') { |
- | |
2070 | file->line_num++; |
- | |
2071 | PEEKC_EOB(c, p); |
- | |
2072 | } |
- | |
2073 | } else { |
- | |
2074 | goto after_star; |
- | |
2075 | } |
- | |
2076 | } |
- | |
2077 | } |
- | |
2078 | } else { |
- | |
2079 | break; |
- | |
2080 | } |
- | |
2081 | } |
- | |
2082 | after_star: ; |
- | |
2083 | } else { |
- | |
2084 | /* stray, eob or eof */ |
- | |
2085 | file->buf_ptr = p; |
- | |
2086 | c = handle_eob(); |
- | |
2087 | p = file->buf_ptr; |
- | |
2088 | if (c == CH_EOF) { |
- | |
2089 | error("unexpected end of file in comment"); |
- | |
2090 | } else if (c == '\\') { |
- | |
2091 | p++; |
- | |
2092 | } |
- | |
2093 | } |
- | |
2094 | } |
- | |
2095 | end_of_comment: |
- | |
2096 | p++; |
- | |
2097 | return p; |
- | |
2098 | } |
- | |
2099 | - | ||
2100 | #define cinp minp |
- | |
2101 | - | ||
2102 | /* space excluding newline */ |
- | |
2103 | static inline int is_space(int ch) |
- | |
2104 | { |
- | |
2105 | return ch == ' ' || ch == '\t' || ch == '\v' || ch == '\f' || ch == '\r'; |
- | |
2106 | } |
- | |
2107 | - | ||
2108 | static inline void skip_spaces(void) |
- | |
2109 | { |
- | |
2110 | while (is_space(ch)) |
- | |
2111 | cinp(); |
- | |
2112 | } |
- | |
2113 | - | ||
2114 | /* parse a string without interpreting escapes */ |
- | |
2115 | static uint8_t *parse_pp_string(uint8_t *p, |
- | |
2116 | int sep, CString *str) |
- | |
2117 | { |
- | |
2118 | int c; |
- | |
2119 | p++; |
- | |
2120 | for(;;) { |
- | |
2121 | c = *p; |
- | |
2122 | if (c == sep) { |
- | |
2123 | break; |
- | |
2124 | } else if (c == '\\') { |
- | |
2125 | file->buf_ptr = p; |
- | |
2126 | c = handle_eob(); |
- | |
2127 | p = file->buf_ptr; |
- | |
2128 | if (c == CH_EOF) { |
- | |
2129 | unterminated_string: |
- | |
2130 | /* XXX: indicate line number of start of string */ |
- | |
2131 | error("missing terminating %c character", sep); |
- | |
2132 | } else if (c == '\\') { |
- | |
2133 | /* escape : just skip \[\r]\n */ |
- | |
2134 | PEEKC_EOB(c, p); |
- | |
2135 | if (c == '\n') { |
- | |
2136 | file->line_num++; |
- | |
2137 | p++; |
- | |
2138 | } else if (c == '\r') { |
- | |
2139 | PEEKC_EOB(c, p); |
- | |
2140 | if (c != '\n') |
- | |
2141 | expect("'\n' after '\r'"); |
- | |
2142 | file->line_num++; |
- | |
2143 | p++; |
- | |
2144 | } else if (c == CH_EOF) { |
- | |
2145 | goto unterminated_string; |
- | |
2146 | } else { |
- | |
2147 | if (str) { |
- | |
2148 | cstr_ccat(str, '\\'); |
- | |
2149 | cstr_ccat(str, c); |
- | |
2150 | } |
- | |
2151 | p++; |
- | |
2152 | } |
- | |
2153 | } |
- | |
2154 | } else if (c == '\n') { |
- | |
2155 | file->line_num++; |
- | |
2156 | goto add_char; |
- | |
2157 | } else if (c == '\r') { |
- | |
2158 | PEEKC_EOB(c, p); |
- | |
2159 | if (c != '\n') { |
- | |
2160 | if (str) |
- | |
2161 | cstr_ccat(str, '\r'); |
- | |
2162 | } else { |
- | |
2163 | file->line_num++; |
- | |
2164 | goto add_char; |
- | |
2165 | } |
- | |
2166 | } else { |
- | |
2167 | add_char: |
- | |
2168 | if (str) |
- | |
2169 | cstr_ccat(str, c); |
- | |
2170 | p++; |
- | |
2171 | } |
- | |
2172 | } |
- | |
2173 | p++; |
- | |
2174 | return p; |
- | |
2175 | } |
- | |
2176 | - | ||
2177 | /* skip block of text until #else, #elif or #endif. skip also pairs of |
- | |
2178 | #if/#endif */ |
- | |
2179 | void preprocess_skip(void) |
- | |
2180 | { |
- | |
2181 | int a, start_of_line, c; |
- | |
2182 | uint8_t *p; |
- | |
2183 | - | ||
2184 | p = file->buf_ptr; |
- | |
2185 | start_of_line = 1; |
- | |
2186 | a = 0; |
- | |
2187 | for(;;) { |
- | |
2188 | redo_no_start: |
- | |
2189 | c = *p; |
- | |
2190 | switch(c) { |
- | |
2191 | case ' ': |
- | |
2192 | case '\t': |
- | |
2193 | case '\f': |
- | |
2194 | case '\v': |
- | |
2195 | case '\r': |
- | |
2196 | p++; |
- | |
2197 | goto redo_no_start; |
- | |
2198 | case '\n': |
- | |
2199 | start_of_line = 1; |
- | |
2200 | file->line_num++; |
- | |
2201 | p++; |
- | |
2202 | goto redo_no_start; |
- | |
2203 | case '\\': |
- | |
2204 | file->buf_ptr = p; |
- | |
2205 | c = handle_eob(); |
- | |
2206 | if (c == CH_EOF) { |
- | |
2207 | expect("#endif"); |
- | |
2208 | } else if (c == '\\') { |
- | |
2209 | /* XXX: incorrect: should not give an error */ |
- | |
2210 | ch = file->buf_ptr[0]; |
- | |
2211 | handle_stray(); |
- | |
2212 | } |
- | |
2213 | p = file->buf_ptr; |
- | |
2214 | goto redo_no_start; |
- | |
2215 | /* skip strings */ |
- | |
2216 | case '\"': |
- | |
2217 | case '\'': |
- | |
2218 | p = parse_pp_string(p, c, NULL); |
- | |
2219 | break; |
- | |
2220 | /* skip comments */ |
- | |
2221 | case '/': |
- | |
2222 | file->buf_ptr = p; |
- | |
2223 | ch = *p; |
- | |
2224 | minp(); |
- | |
2225 | p = file->buf_ptr; |
- | |
2226 | if (ch == '*') { |
- | |
2227 | p = parse_comment(p); |
- | |
2228 | } else if (ch == '/') { |
- | |
2229 | p = parse_line_comment(p); |
- | |
2230 | } |
- | |
2231 | break; |
- | |
2232 | - | ||
2233 | case '#': |
- | |
2234 | p++; |
- | |
2235 | if (start_of_line) { |
- | |
2236 | file->buf_ptr = p; |
- | |
2237 | next_nomacro(); |
- | |
2238 | p = file->buf_ptr; |
- | |
2239 | if (a == 0 && |
- | |
2240 | (tok == TOK_ELSE || tok == TOK_ELIF || tok == TOK_ENDIF)) |
- | |
2241 | goto the_end; |
- | |
2242 | if (tok == TOK_IF || tok == TOK_IFDEF || tok == TOK_IFNDEF) |
- | |
2243 | a++; |
- | |
2244 | else if (tok == TOK_ENDIF) |
- | |
2245 | a--; |
- | |
2246 | } |
- | |
2247 | break; |
- | |
2248 | default: |
- | |
2249 | p++; |
- | |
2250 | break; |
- | |
2251 | } |
- | |
2252 | start_of_line = 0; |
- | |
2253 | } |
- | |
2254 | the_end: ; |
- | |
2255 | file->buf_ptr = p; |
- | |
2256 | } |
- | |
2257 | - | ||
2258 | /* ParseState handling */ |
- | |
2259 | - | ||
2260 | /* XXX: currently, no include file info is stored. Thus, we cannot display |
- | |
2261 | accurate messages if the function or data definition spans multiple |
- | |
2262 | files */ |
- | |
2263 | - | ||
2264 | /* save current parse state in 's' */ |
- | |
2265 | void save_parse_state(ParseState *s) |
- | |
2266 | { |
- | |
2267 | s->line_num = file->line_num; |
- | |
2268 | s->macro_ptr = macro_ptr; |
- | |
2269 | s->tok = tok; |
- | |
2270 | s->tokc = tokc; |
- | |
2271 | } |
- | |
2272 | - | ||
2273 | /* restore parse state from 's' */ |
- | |
2274 | void restore_parse_state(ParseState *s) |
- | |
2275 | { |
- | |
2276 | file->line_num = s->line_num; |
- | |
2277 | macro_ptr = s->macro_ptr; |
- | |
2278 | tok = s->tok; |
- | |
2279 | tokc = s->tokc; |
- | |
2280 | } |
- | |
2281 | - | ||
2282 | /* return the number of additional 'ints' necessary to store the |
- | |
2283 | token */ |
- | |
2284 | static inline int tok_ext_size(int t) |
- | |
2285 | { |
- | |
2286 | switch(t) { |
- | |
2287 | /* 4 bytes */ |
- | |
2288 | case TOK_CINT: |
- | |
2289 | case TOK_CUINT: |
- | |
2290 | case TOK_CCHAR: |
- | |
2291 | case TOK_LCHAR: |
- | |
2292 | case TOK_CFLOAT: |
- | |
2293 | case TOK_LINENUM: |
- | |
2294 | return 1; |
- | |
2295 | case TOK_STR: |
- | |
2296 | case TOK_LSTR: |
- | |
2297 | case TOK_PPNUM: |
- | |
2298 | error("unsupported token"); |
- | |
2299 | return 1; |
- | |
2300 | case TOK_CDOUBLE: |
- | |
2301 | case TOK_CLLONG: |
- | |
2302 | case TOK_CULLONG: |
- | |
2303 | return 2; |
- | |
2304 | case TOK_CLDOUBLE: |
- | |
2305 | return LDOUBLE_SIZE / 4; |
- | |
2306 | default: |
- | |
2307 | return 0; |
- | |
2308 | } |
- | |
2309 | } |
- | |
2310 | - | ||
2311 | /* token string handling */ |
- | |
2312 | - | ||
2313 | static inline void tok_str_new(TokenString *s) |
- | |
2314 | { |
- | |
2315 | s->str = NULL; |
- | |
2316 | s->len = 0; |
- | |
2317 | s->allocated_len = 0; |
- | |
2318 | s->last_line_num = -1; |
- | |
2319 | } |
- | |
2320 | - | ||
2321 | static void tok_str_free(int *str) |
- | |
2322 | { |
- | |
2323 | tcc_free(str); |
- | |
2324 | } |
- | |
2325 | - | ||
2326 | static int *tok_str_realloc(TokenString *s) |
- | |
2327 | { |
- | |
2328 | int *str, len; |
- | |
2329 | - | ||
2330 | if (s->allocated_len == 0) { |
- | |
2331 | len = 8; |
- | |
2332 | } else { |
- | |
2333 | len = s->allocated_len * 2; |
- | |
2334 | } |
- | |
2335 | str = tcc_realloc(s->str, len * sizeof(int)); |
- | |
2336 | if (!str) |
- | |
2337 | error("memory full"); |
- | |
2338 | s->allocated_len = len; |
- | |
2339 | s->str = str; |
- | |
2340 | return str; |
- | |
2341 | } |
- | |
2342 | - | ||
2343 | static void tok_str_add(TokenString *s, int t) |
- | |
2344 | { |
- | |
2345 | int len, *str; |
- | |
2346 | - | ||
2347 | len = s->len; |
- | |
2348 | str = s->str; |
- | |
2349 | if (len >= s->allocated_len) |
- | |
2350 | str = tok_str_realloc(s); |
- | |
2351 | str[len++] = t; |
- | |
2352 | s->len = len; |
- | |
2353 | } |
- | |
2354 | - | ||
2355 | static void tok_str_add2(TokenString *s, int t, CValue *cv) |
- | |
2356 | { |
- | |
2357 | int len, *str; |
- | |
2358 | - | ||
2359 | len = s->len; |
- | |
2360 | str = s->str; |
- | |
2361 | - | ||
2362 | /* allocate space for worst case */ |
- | |
2363 | if (len + TOK_MAX_SIZE > s->allocated_len) |
- | |
2364 | str = tok_str_realloc(s); |
- | |
2365 | str[len++] = t; |
- | |
2366 | switch(t) { |
- | |
2367 | case TOK_CINT: |
- | |
2368 | case TOK_CUINT: |
- | |
2369 | case TOK_CCHAR: |
- | |
2370 | case TOK_LCHAR: |
- | |
2371 | case TOK_CFLOAT: |
- | |
2372 | case TOK_LINENUM: |
- | |
2373 | str[len++] = cv->tab[0]; |
- | |
2374 | break; |
- | |
2375 | case TOK_PPNUM: |
- | |
2376 | case TOK_STR: |
- | |
2377 | case TOK_LSTR: |
- | |
2378 | { |
- | |
2379 | int nb_words; |
- | |
2380 | CString *cstr; |
- | |
2381 | - | ||
2382 | nb_words = (sizeof(CString) + cv->cstr->size + 3) >> 2; |
- | |
2383 | while ((len + nb_words) > s->allocated_len) |
- | |
2384 | str = tok_str_realloc(s); |
- | |
2385 | cstr = (CString *)(str + len); |
- | |
2386 | cstr->data = NULL; |
- | |
2387 | cstr->size = cv->cstr->size; |
- | |
2388 | cstr->data_allocated = NULL; |
- | |
2389 | cstr->size_allocated = cstr->size; |
- | |
2390 | memcpy((char *)cstr + sizeof(CString), |
- | |
2391 | cv->cstr->data, cstr->size); |
- | |
2392 | len += nb_words; |
- | |
2393 | } |
- | |
2394 | break; |
- | |
2395 | case TOK_CDOUBLE: |
- | |
2396 | case TOK_CLLONG: |
- | |
2397 | case TOK_CULLONG: |
- | |
2398 | #if LDOUBLE_SIZE == 8 |
- | |
2399 | case TOK_CLDOUBLE: |
- | |
2400 | #endif |
- | |
2401 | str[len++] = cv->tab[0]; |
- | |
2402 | str[len++] = cv->tab[1]; |
- | |
2403 | break; |
- | |
2404 | #if LDOUBLE_SIZE == 12 |
- | |
2405 | case TOK_CLDOUBLE: |
- | |
2406 | str[len++] = cv->tab[0]; |
- | |
2407 | str[len++] = cv->tab[1]; |
- | |
2408 | str[len++] = cv->tab[2]; |
- | |
2409 | #elif LDOUBLE_SIZE != 8 |
- | |
2410 | #error add long double size support |
- | |
2411 | #endif |
- | |
2412 | break; |
- | |
2413 | default: |
- | |
2414 | break; |
- | |
2415 | } |
- | |
2416 | s->len = len; |
- | |
2417 | } |
- | |
2418 | - | ||
2419 | /* add the current parse token in token string 's' */ |
- | |
2420 | static void tok_str_add_tok(TokenString *s) |
- | |
2421 | { |
- | |
2422 | CValue cval; |
- | |
2423 | - | ||
2424 | /* save line number info */ |
- | |
2425 | if (file->line_num != s->last_line_num) { |
- | |
2426 | s->last_line_num = file->line_num; |
- | |
2427 | cval.i = s->last_line_num; |
- | |
2428 | tok_str_add2(s, TOK_LINENUM, &cval); |
- | |
2429 | } |
- | |
2430 | tok_str_add2(s, tok, &tokc); |
- | |
2431 | } |
- | |
2432 | - | ||
2433 | #if LDOUBLE_SIZE == 12 |
- | |
2434 | #define LDOUBLE_GET(p, cv) \ |
- | |
2435 | cv.tab[0] = p[0]; \ |
- | |
2436 | cv.tab[1] = p[1]; \ |
- | |
2437 | cv.tab[2] = p[2]; |
- | |
2438 | #elif LDOUBLE_SIZE == 8 |
- | |
2439 | #define LDOUBLE_GET(p, cv) \ |
- | |
2440 | cv.tab[0] = p[0]; \ |
- | |
2441 | cv.tab[1] = p[1]; |
- | |
2442 | #else |
- | |
2443 | #error add long double size support |
- | |
2444 | #endif |
- | |
2445 | - | ||
2446 | - | ||
2447 | /* get a token from an integer array and increment pointer |
- | |
2448 | accordingly. we code it as a macro to avoid pointer aliasing. */ |
- | |
2449 | #define TOK_GET(t, p, cv) \ |
- | |
2450 | { \ |
- | |
2451 | t = *p++; \ |
- | |
2452 | switch(t) { \ |
- | |
2453 | case TOK_CINT: \ |
- | |
2454 | case TOK_CUINT: \ |
- | |
2455 | case TOK_CCHAR: \ |
- | |
2456 | case TOK_LCHAR: \ |
- | |
2457 | case TOK_CFLOAT: \ |
- | |
2458 | case TOK_LINENUM: \ |
- | |
2459 | cv.tab[0] = *p++; \ |
- | |
2460 | break; \ |
- | |
2461 | case TOK_STR: \ |
- | |
2462 | case TOK_LSTR: \ |
- | |
2463 | case TOK_PPNUM: \ |
- | |
2464 | cv.cstr = (CString *)p; \ |
- | |
2465 | cv.cstr->data = (char *)p + sizeof(CString);\ |
- | |
2466 | p += (sizeof(CString) + cv.cstr->size + 3) >> 2;\ |
- | |
2467 | break; \ |
- | |
2468 | case TOK_CDOUBLE: \ |
- | |
2469 | case TOK_CLLONG: \ |
- | |
2470 | case TOK_CULLONG: \ |
- | |
2471 | cv.tab[0] = p[0]; \ |
- | |
2472 | cv.tab[1] = p[1]; \ |
- | |
2473 | p += 2; \ |
- | |
2474 | break; \ |
- | |
2475 | case TOK_CLDOUBLE: \ |
- | |
2476 | LDOUBLE_GET(p, cv); \ |
- | |
2477 | p += LDOUBLE_SIZE / 4; \ |
- | |
2478 | break; \ |
- | |
2479 | default: \ |
- | |
2480 | break; \ |
- | |
2481 | } \ |
- | |
2482 | } |
- | |
2483 | - | ||
2484 | /* defines handling */ |
- | |
2485 | static inline void define_push(int v, int macro_type, int *str, Sym *first_arg) |
- | |
2486 | { |
- | |
2487 | Sym *s; |
- | |
2488 | - | ||
2489 | s = sym_push2(&define_stack, v, macro_type, (int)str); |
- | |
2490 | s->next = first_arg; |
- | |
2491 | table_ident[v - TOK_IDENT]->sym_define = s; |
- | |
2492 | } |
- | |
2493 | - | ||
2494 | /* undefined a define symbol. Its name is just set to zero */ |
- | |
2495 | static void define_undef(Sym *s) |
- | |
2496 | { |
- | |
2497 | int v; |
- | |
2498 | v = s->v; |
- | |
2499 | if (v >= TOK_IDENT && v < tok_ident) |
- | |
2500 | table_ident[v - TOK_IDENT]->sym_define = NULL; |
- | |
2501 | s->v = 0; |
- | |
2502 | } |
- | |
2503 | - | ||
2504 | static inline Sym *define_find(int v) |
- | |
2505 | { |
- | |
2506 | v -= TOK_IDENT; |
- | |
2507 | if ((unsigned)v >= (unsigned)(tok_ident - TOK_IDENT)) |
- | |
2508 | return NULL; |
- | |
2509 | return table_ident[v]->sym_define; |
- | |
2510 | } |
- | |
2511 | - | ||
2512 | /* free define stack until top reaches 'b' */ |
- | |
2513 | static void free_defines(Sym *b) |
- | |
2514 | { |
- | |
2515 | Sym *top, *top1; |
- | |
2516 | int v; |
- | |
2517 | - | ||
2518 | top = define_stack; |
- | |
2519 | while (top != b) { |
- | |
2520 | top1 = top->prev; |
- | |
2521 | /* do not free args or predefined defines */ |
- | |
2522 | if (top->c) |
- | |
2523 | tok_str_free((int *)top->c); |
- | |
2524 | v = top->v; |
- | |
2525 | if (v >= TOK_IDENT && v < tok_ident) |
- | |
2526 | table_ident[v - TOK_IDENT]->sym_define = NULL; |
- | |
2527 | sym_free(top); |
- | |
2528 | top = top1; |
- | |
2529 | } |
- | |
2530 | define_stack = b; |
- | |
2531 | } |
- | |
2532 | - | ||
2533 | /* label lookup */ |
- | |
2534 | static Sym *label_find(int v) |
- | |
2535 | { |
- | |
2536 | v -= TOK_IDENT; |
- | |
2537 | if ((unsigned)v >= (unsigned)(tok_ident - TOK_IDENT)) |
- | |
2538 | return NULL; |
- | |
2539 | return table_ident[v]->sym_label; |
- | |
2540 | } |
- | |
2541 | - | ||
2542 | static Sym *label_push(Sym **ptop, int v, int flags) |
- | |
2543 | { |
- | |
2544 | Sym *s, **ps; |
- | |
2545 | s = sym_push2(ptop, v, 0, 0); |
- | |
2546 | s->r = flags; |
- | |
2547 | ps = &table_ident[v - TOK_IDENT]->sym_label; |
- | |
2548 | if (ptop == &global_label_stack) { |
- | |
2549 | /* modify the top most local identifier, so that |
- | |
2550 | sym_identifier will point to 's' when popped */ |
- | |
2551 | while (*ps != NULL) |
- | |
2552 | ps = &(*ps)->prev_tok; |
- | |
2553 | } |
- | |
2554 | s->prev_tok = *ps; |
- | |
2555 | *ps = s; |
- | |
2556 | return s; |
- | |
2557 | } |
- | |
2558 | - | ||
2559 | /* pop labels until element last is reached. Look if any labels are |
- | |
2560 | undefined. Define symbols if '&&label' was used. */ |
- | |
2561 | static void label_pop(Sym **ptop, Sym *slast) |
- | |
2562 | { |
- | |
2563 | Sym *s, *s1; |
- | |
2564 | for(s = *ptop; s != slast; s = s1) { |
- | |
2565 | s1 = s->prev; |
- | |
2566 | if (s->r == LABEL_DECLARED) { |
- | |
2567 | warning("label '%s' declared but not used", get_tok_str(s->v, NULL)); |
- | |
2568 | } else if (s->r == LABEL_FORWARD) { |
- | |
2569 | error("label '%s' used but not defined", |
- | |
2570 | get_tok_str(s->v, NULL)); |
- | |
2571 | } else { |
- | |
2572 | if (s->c) { |
- | |
2573 | /* define corresponding symbol. A size of |
- | |
2574 | 1 is put. */ |
- | |
2575 | put_extern_sym(s, cur_text_section, (long)s->next, 1); |
- | |
2576 | } |
- | |
2577 | } |
- | |
2578 | /* remove label */ |
- | |
2579 | table_ident[s->v - TOK_IDENT]->sym_label = s->prev_tok; |
- | |
2580 | sym_free(s); |
- | |
2581 | } |
- | |
2582 | *ptop = slast; |
- | |
2583 | } |
- | |
2584 | - | ||
2585 | /* eval an expression for #if/#elif */ |
- | |
2586 | static int expr_preprocess(void) |
- | |
2587 | { |
- | |
2588 | int c, t; |
- | |
2589 | TokenString str; |
- | |
2590 | - | ||
2591 | tok_str_new(&str); |
- | |
2592 | while (tok != TOK_LINEFEED && tok != TOK_EOF) { |
- | |
2593 | next(); /* do macro subst */ |
- | |
2594 | if (tok == TOK_DEFINED) { |
- | |
2595 | next_nomacro(); |
- | |
2596 | t = tok; |
- | |
2597 | if (t == '(') |
- | |
2598 | next_nomacro(); |
- | |
2599 | c = define_find(tok) != 0; |
- | |
2600 | if (t == '(') |
- | |
2601 | next_nomacro(); |
- | |
2602 | tok = TOK_CINT; |
- | |
2603 | tokc.i = c; |
- | |
2604 | } else if (tok >= TOK_IDENT) { |
- | |
2605 | /* if undefined macro */ |
- | |
2606 | tok = TOK_CINT; |
- | |
2607 | tokc.i = 0; |
- | |
2608 | } |
- | |
2609 | tok_str_add_tok(&str); |
- | |
2610 | } |
- | |
2611 | tok_str_add(&str, -1); /* simulate end of file */ |
- | |
2612 | tok_str_add(&str, 0); |
- | |
2613 | /* now evaluate C constant expression */ |
- | |
2614 | macro_ptr = str.str; |
- | |
2615 | next(); |
- | |
2616 | c = expr_const(); |
- | |
2617 | macro_ptr = NULL; |
- | |
2618 | tok_str_free(str.str); |
- | |
2619 | return c != 0; |
- | |
2620 | } |
- | |
2621 | - | ||
2622 | #if defined(PARSE_DEBUG) || defined(PP_DEBUG) |
- | |
2623 | static void tok_print(int *str) |
- | |
2624 | { |
- | |
2625 | int t; |
- | |
2626 | CValue cval; |
- | |
2627 | - | ||
2628 | while (1) { |
- | |
2629 | TOK_GET(t, str, cval); |
- | |
2630 | if (!t) |
- | |
2631 | break; |
- | |
2632 | printf(" %s", get_tok_str(t, &cval)); |
- | |
2633 | } |
- | |
2634 | printf("\n"); |
- | |
2635 | } |
- | |
2636 | #endif |
- | |
2637 | - | ||
2638 | /* parse after #define */ |
- | |
2639 | static void parse_define(void) |
- | |
2640 | { |
- | |
2641 | Sym *s, *first, **ps; |
- | |
2642 | int v, t, varg, is_vaargs, c; |
- | |
2643 | TokenString str; |
- | |
2644 | - | ||
2645 | v = tok; |
- | |
2646 | if (v < TOK_IDENT) |
- | |
2647 | error("invalid macro name '%s'", get_tok_str(tok, &tokc)); |
- | |
2648 | /* XXX: should check if same macro (ANSI) */ |
- | |
2649 | first = NULL; |
- | |
2650 | t = MACRO_OBJ; |
- | |
2651 | /* '(' must be just after macro definition for MACRO_FUNC */ |
- | |
2652 | c = file->buf_ptr[0]; |
- | |
2653 | if (c == '\\') |
- | |
2654 | c = handle_stray1(file->buf_ptr); |
- | |
2655 | if (c == '(') { |
- | |
2656 | next_nomacro(); |
- | |
2657 | next_nomacro(); |
- | |
2658 | ps = &first; |
- | |
2659 | while (tok != ')') { |
- | |
2660 | varg = tok; |
- | |
2661 | next_nomacro(); |
- | |
2662 | is_vaargs = 0; |
- | |
2663 | if (varg == TOK_DOTS) { |
- | |
2664 | varg = TOK___VA_ARGS__; |
- | |
2665 | is_vaargs = 1; |
- | |
2666 | } else if (tok == TOK_DOTS && gnu_ext) { |
- | |
2667 | is_vaargs = 1; |
- | |
2668 | next_nomacro(); |
- | |
2669 | } |
- | |
2670 | if (varg < TOK_IDENT) |
- | |
2671 | error("badly punctuated parameter list"); |
- | |
2672 | s = sym_push2(&define_stack, varg | SYM_FIELD, is_vaargs, 0); |
- | |
2673 | *ps = s; |
- | |
2674 | ps = &s->next; |
- | |
2675 | if (tok != ',') |
- | |
2676 | break; |
- | |
2677 | next_nomacro(); |
- | |
2678 | } |
- | |
2679 | t = MACRO_FUNC; |
- | |
2680 | } |
- | |
2681 | tok_str_new(&str); |
- | |
2682 | next_nomacro(); |
- | |
2683 | /* EOF testing necessary for '-D' handling */ |
- | |
2684 | while (tok != TOK_LINEFEED && tok != TOK_EOF) { |
- | |
2685 | tok_str_add2(&str, tok, &tokc); |
- | |
2686 | next_nomacro(); |
- | |
2687 | } |
- | |
2688 | tok_str_add(&str, 0); |
- | |
2689 | #ifdef PP_DEBUG |
- | |
2690 | printf("define %s %d: ", get_tok_str(v, NULL), t); |
- | |
2691 | tok_print(str.str); |
- | |
2692 | #endif |
- | |
2693 | define_push(v, t, str.str, first); |
- | |
2694 | } |
- | |
2695 | - | ||
2696 | static inline int hash_cached_include(int type, const char *filename) |
- | |
2697 | { |
- | |
2698 | const unsigned char *s; |
- | |
2699 | unsigned int h; |
- | |
2700 | - | ||
2701 | h = TOK_HASH_INIT; |
- | |
2702 | h = TOK_HASH_FUNC(h, type); |
- | |
2703 | s = filename; |
- | |
2704 | while (*s) { |
- | |
2705 | h = TOK_HASH_FUNC(h, *s); |
- | |
2706 | s++; |
- | |
2707 | } |
- | |
2708 | h &= (CACHED_INCLUDES_HASH_SIZE - 1); |
- | |
2709 | return h; |
- | |
2710 | } |
- | |
2711 | - | ||
2712 | /* XXX: use a token or a hash table to accelerate matching ? */ |
- | |
2713 | static CachedInclude *search_cached_include(TCCState *s1, |
- | |
2714 | int type, const char *filename) |
- | |
2715 | { |
- | |
2716 | CachedInclude *e; |
- | |
2717 | int i, h; |
- | |
2718 | h = hash_cached_include(type, filename); |
- | |
2719 | i = s1->cached_includes_hash[h]; |
- | |
2720 | for(;;) { |
- | |
2721 | if (i == 0) |
- | |
2722 | break; |
- | |
2723 | e = s1->cached_includes[i - 1]; |
- | |
2724 | if (e->type == type && !strcmp(e->filename, filename)) |
- | |
2725 | return e; |
- | |
2726 | i = e->hash_next; |
- | |
2727 | } |
- | |
2728 | return NULL; |
- | |
2729 | } |
- | |
2730 | - | ||
2731 | static inline void add_cached_include(TCCState *s1, int type, |
- | |
2732 | const char *filename, int ifndef_macro) |
- | |
2733 | { |
- | |
2734 | CachedInclude *e; |
- | |
2735 | int h; |
- | |
2736 | - | ||
2737 | if (search_cached_include(s1, type, filename)) |
- | |
2738 | return; |
- | |
2739 | #ifdef INC_DEBUG |
- | |
2740 | printf("adding cached '%s' %s\n", filename, get_tok_str(ifndef_macro, NULL)); |
24 | #include "tcc.h" |
2741 | #endif |
- | |
2742 | e = tcc_malloc(sizeof(CachedInclude) + strlen(filename)); |
- | |
2743 | if (!e) |
- | |
2744 | return; |
- | |
2745 | e->type = type; |
- | |
2746 | strcpy(e->filename, filename); |
- | |
2747 | e->ifndef_macro = ifndef_macro; |
- | |
2748 | dynarray_add((void ***)&s1->cached_includes, &s1->nb_cached_includes, e); |
- | |
2749 | /* add in hash table */ |
- | |
2750 | h = hash_cached_include(type, filename); |
- | |
2751 | e->hash_next = s1->cached_includes_hash[h]; |
- | |
2752 | s1->cached_includes_hash[h] = s1->nb_cached_includes; |
- | |
Line 2753... | Line -... | ||
2753 | } |
- | |
2754 | - | ||
2755 | static void pragma_parse(TCCState *s1) |
- | |
2756 | { |
- | |
2757 | int val; |
- | |
2758 | - | ||
2759 | next(); |
- | |
2760 | if (tok == TOK_pack) { |
- | |
2761 | /* |
- | |
2762 | This may be: |
- | |
2763 | #pragma pack(1) // set |
- | |
2764 | #pragma pack() // reset to default |
- | |
2765 | #pragma pack(push,1) // push & set |
- | |
2766 | #pragma pack(pop) // restore previous |
- | |
2767 | */ |
- | |
2768 | next(); |
- | |
2769 | skip('('); |
- | |
2770 | if (tok == TOK_ASM_pop) { |
- | |
2771 | next(); |
- | |
2772 | if (s1->pack_stack_ptr <= s1->pack_stack) { |
- | |
2773 | stk_error: |
- | |
2774 | error("out of pack stack"); |
- | |
2775 | } |
- | |
2776 | s1->pack_stack_ptr--; |
- | |
2777 | } else { |
- | |
2778 | val = 0; |
- | |
2779 | if (tok != ')') { |
- | |
2780 | if (tok == TOK_ASM_push) { |
- | |
2781 | next(); |
- | |
2782 | if (s1->pack_stack_ptr >= s1->pack_stack + PACK_STACK_SIZE - 1) |
- | |
2783 | goto stk_error; |
- | |
2784 | s1->pack_stack_ptr++; |
- | |
2785 | skip(','); |
- | |
2786 | } |
- | |
2787 | if (tok != TOK_CINT) { |
- | |
2788 | pack_error: |
- | |
2789 | error("invalid pack pragma"); |
- | |
2790 | } |
- | |
2791 | val = tokc.i; |
- | |
2792 | if (val < 1 || val > 16 || (val & (val - 1)) != 0) |
- | |
2793 | goto pack_error; |
- | |
2794 | next(); |
- | |
2795 | } |
- | |
2796 | *s1->pack_stack_ptr = val; |
- | |
2797 | skip(')'); |
- | |
2798 | } |
- | |
2799 | } |
- | |
2800 | } |
- | |
2801 | - | ||
2802 | /* is_bof is true if first non space token at beginning of file */ |
- | |
2803 | static void preprocess(int is_bof) |
- | |
2804 | { |
- | |
2805 | TCCState *s1 = tcc_state; |
- | |
2806 | int size, i, c, n, saved_parse_flags; |
- | |
2807 | char buf[1024], *q, *p; |
- | |
2808 | char buf1[1024]; |
- | |
2809 | BufferedFile *f; |
- | |
2810 | Sym *s; |
- | |
2811 | CachedInclude *e; |
- | |
2812 | - | ||
2813 | saved_parse_flags = parse_flags; |
- | |
2814 | parse_flags = PARSE_FLAG_PREPROCESS | PARSE_FLAG_TOK_NUM | |
- | |
2815 | PARSE_FLAG_LINEFEED; |
- | |
2816 | next_nomacro(); |
- | |
2817 | redo: |
- | |
2818 | switch(tok) { |
- | |
2819 | case TOK_DEFINE: |
- | |
2820 | next_nomacro(); |
- | |
2821 | parse_define(); |
- | |
2822 | break; |
- | |
2823 | case TOK_UNDEF: |
- | |
2824 | next_nomacro(); |
- | |
2825 | s = define_find(tok); |
- | |
2826 | /* undefine symbol by putting an invalid name */ |
- | |
2827 | if (s) |
- | |
2828 | define_undef(s); |
- | |
2829 | break; |
- | |
2830 | case TOK_INCLUDE: |
- | |
2831 | case TOK_INCLUDE_NEXT: |
- | |
2832 | ch = file->buf_ptr[0]; |
- | |
2833 | /* XXX: incorrect if comments : use next_nomacro with a special mode */ |
- | |
2834 | skip_spaces(); |
- | |
2835 | if (ch == '<') { |
- | |
2836 | c = '>'; |
- | |
2837 | goto read_name; |
- | |
2838 | } else if (ch == '\"') { |
- | |
2839 | c = ch; |
- | |
2840 | read_name: |
- | |
2841 | /* XXX: better stray handling */ |
- | |
2842 | minp(); |
- | |
2843 | q = buf; |
- | |
2844 | while (ch != c && ch != '\n' && ch != CH_EOF) { |
- | |
2845 | if ((q - buf) < sizeof(buf) - 1) |
- | |
2846 | *q++ = ch; |
- | |
2847 | minp(); |
- | |
2848 | } |
- | |
2849 | *q = '\0'; |
- | |
2850 | minp(); |
- | |
2851 | #if 0 |
- | |
2852 | /* eat all spaces and comments after include */ |
- | |
2853 | /* XXX: slightly incorrect */ |
- | |
2854 | while (ch1 != '\n' && ch1 != CH_EOF) |
- | |
2855 | input(); |
- | |
2856 | #endif |
- | |
2857 | } else { |
- | |
2858 | /* computed #include : either we have only strings or |
- | |
2859 | we have anything enclosed in '<>' */ |
- | |
2860 | next(); |
- | |
2861 | buf[0] = '\0'; |
- | |
2862 | if (tok == TOK_STR) { |
- | |
2863 | while (tok != TOK_LINEFEED) { |
- | |
2864 | if (tok != TOK_STR) { |
- | |
2865 | include_syntax: |
- | |
2866 | error("'#include' expects \"FILENAME\" or |
- | |
2867 | } |
- | |
2868 | pstrcat(buf, sizeof(buf), (char *)tokc.cstr->data); |
- | |
2869 | next(); |
- | |
2870 | } |
- | |
2871 | c = '\"'; |
- | |
2872 | } else { |
- | |
2873 | int len; |
- | |
2874 | while (tok != TOK_LINEFEED) { |
- | |
2875 | pstrcat(buf, sizeof(buf), get_tok_str(tok, &tokc)); |
- | |
2876 | next(); |
- | |
2877 | } |
- | |
2878 | len = strlen(buf); |
- | |
2879 | /* check syntax and remove '<>' */ |
- | |
2880 | if (len < 2 || buf[0] != '<' || buf[len - 1] != '>') |
- | |
2881 | goto include_syntax; |
- | |
2882 | memmove(buf, buf + 1, len - 2); |
- | |
2883 | buf[len - 2] = '\0'; |
- | |
2884 | c = '>'; |
- | |
2885 | } |
- | |
2886 | } |
- | |
2887 | - | ||
2888 | e = search_cached_include(s1, c, buf); |
- | |
2889 | if (e && define_find(e->ifndef_macro)) { |
- | |
2890 | /* no need to parse the include because the 'ifndef macro' |
- | |
2891 | is defined */ |
- | |
2892 | #ifdef INC_DEBUG |
- | |
2893 | printf("%s: skipping %s\n", file->filename, buf); |
- | |
2894 | #endif |
- | |
2895 | } else { |
- | |
2896 | if (c == '\"') { |
- | |
2897 | /* first search in current dir if "header.h" */ |
- | |
2898 | size = 0; |
- | |
2899 | p = strrchr(file->filename, '/'); |
- | |
2900 | if (p) |
- | |
2901 | size = p + 1 - file->filename; |
- | |
2902 | if (size > sizeof(buf1) - 1) |
- | |
2903 | size = sizeof(buf1) - 1; |
- | |
2904 | memcpy(buf1, file->filename, size); |
- | |
2905 | buf1[size] = '\0'; |
- | |
2906 | pstrcat(buf1, sizeof(buf1), buf); |
- | |
2907 | f = tcc_open(s1, buf1); |
- | |
2908 | if (f) { |
- | |
2909 | if (tok == TOK_INCLUDE_NEXT) |
- | |
2910 | tok = TOK_INCLUDE; |
- | |
2911 | else |
- | |
2912 | goto found; |
- | |
2913 | } |
- | |
2914 | } |
- | |
2915 | if (s1->include_stack_ptr >= s1->include_stack + INCLUDE_STACK_SIZE) |
- | |
2916 | error("#include recursion too deep"); |
- | |
2917 | /* now search in all the include paths */ |
- | |
2918 | n = s1->nb_include_paths + s1->nb_sysinclude_paths; |
- | |
2919 | for(i = 0; i < n; i++) { |
- | |
2920 | const char *path; |
- | |
2921 | if (i < s1->nb_include_paths) |
- | |
2922 | path = s1->include_paths[i]; |
- | |
2923 | else |
- | |
2924 | path = s1->sysinclude_paths[i - s1->nb_include_paths]; |
- | |
2925 | pstrcpy(buf1, sizeof(buf1), path); |
- | |
2926 | pstrcat(buf1, sizeof(buf1), "/"); |
- | |
2927 | pstrcat(buf1, sizeof(buf1), buf); |
- | |
2928 | f = tcc_open(s1, buf1); |
- | |
2929 | if (f) { |
- | |
2930 | if (tok == TOK_INCLUDE_NEXT) |
- | |
2931 | tok = TOK_INCLUDE; |
- | |
2932 | else |
- | |
2933 | goto found; |
- | |
2934 | } |
- | |
2935 | } |
- | |
2936 | error("include file '%s' not found", buf); |
- | |
2937 | f = NULL; |
- | |
2938 | found: |
- | |
2939 | #ifdef INC_DEBUG |
- | |
2940 | printf("%s: including %s\n", file->filename, buf1); |
- | |
2941 | #endif |
- | |
2942 | f->inc_type = c; |
- | |
2943 | pstrcpy(f->inc_filename, sizeof(f->inc_filename), buf); |
- | |
2944 | /* push current file in stack */ |
- | |
2945 | /* XXX: fix current line init */ |
- | |
2946 | *s1->include_stack_ptr++ = file; |
- | |
2947 | file = f; |
- | |
2948 | /* add include file debug info */ |
- | |
2949 | if (do_debug) { |
- | |
2950 | put_stabs(file->filename, N_BINCL, 0, 0, 0); |
- | |
2951 | } |
- | |
2952 | tok_flags |= TOK_FLAG_BOF | TOK_FLAG_BOL; |
- | |
2953 | ch = file->buf_ptr[0]; |
- | |
2954 | goto the_end; |
- | |
2955 | } |
- | |
2956 | break; |
- | |
2957 | case TOK_IFNDEF: |
- | |
2958 | c = 1; |
- | |
2959 | goto do_ifdef; |
- | |
2960 | case TOK_IF: |
- | |
2961 | c = expr_preprocess(); |
- | |
2962 | goto do_if; |
- | |
2963 | case TOK_IFDEF: |
- | |
2964 | c = 0; |
- | |
2965 | do_ifdef: |
- | |
2966 | next_nomacro(); |
- | |
2967 | if (tok < TOK_IDENT) |
- | |
2968 | error("invalid argument for '#if%sdef'", c ? "n" : ""); |
- | |
2969 | if (is_bof) { |
- | |
2970 | if (c) { |
- | |
2971 | #ifdef INC_DEBUG |
- | |
2972 | printf("#ifndef %s\n", get_tok_str(tok, NULL)); |
- | |
2973 | #endif |
- | |
2974 | file->ifndef_macro = tok; |
- | |
2975 | } |
- | |
2976 | } |
- | |
2977 | c = (define_find(tok) != 0) ^ c; |
- | |
2978 | do_if: |
- | |
2979 | if (s1->ifdef_stack_ptr >= s1->ifdef_stack + IFDEF_STACK_SIZE) |
- | |
2980 | error("memory full"); |
- | |
2981 | *s1->ifdef_stack_ptr++ = c; |
- | |
2982 | goto test_skip; |
- | |
2983 | case TOK_ELSE: |
- | |
2984 | if (s1->ifdef_stack_ptr == s1->ifdef_stack) |
- | |
2985 | error("#else without matching #if"); |
- | |
2986 | if (s1->ifdef_stack_ptr[-1] & 2) |
- | |
2987 | error("#else after #else"); |
- | |
2988 | c = (s1->ifdef_stack_ptr[-1] ^= 3); |
- | |
2989 | goto test_skip; |
- | |
2990 | case TOK_ELIF: |
- | |
2991 | if (s1->ifdef_stack_ptr == s1->ifdef_stack) |
- | |
2992 | error("#elif without matching #if"); |
- | |
2993 | c = s1->ifdef_stack_ptr[-1]; |
- | |
2994 | if (c > 1) |
- | |
2995 | error("#elif after #else"); |
- | |
2996 | /* last #if/#elif expression was true: we skip */ |
- | |
2997 | if (c == 1) |
- | |
2998 | goto skip; |
- | |
2999 | c = expr_preprocess(); |
- | |
3000 | s1->ifdef_stack_ptr[-1] = c; |
- | |
3001 | test_skip: |
- | |
3002 | if (!(c & 1)) { |
- | |
3003 | skip: |
- | |
3004 | preprocess_skip(); |
- | |
3005 | is_bof = 0; |
- | |
3006 | goto redo; |
- | |
3007 | } |
- | |
3008 | break; |
- | |
3009 | case TOK_ENDIF: |
- | |
3010 | if (s1->ifdef_stack_ptr <= file->ifdef_stack_ptr) |
- | |
3011 | error("#endif without matching #if"); |
- | |
3012 | s1->ifdef_stack_ptr--; |
- | |
3013 | /* '#ifndef macro' was at the start of file. Now we check if |
- | |
3014 | an '#endif' is exactly at the end of file */ |
- | |
3015 | if (file->ifndef_macro && |
- | |
3016 | s1->ifdef_stack_ptr == file->ifdef_stack_ptr) { |
- | |
3017 | file->ifndef_macro_saved = file->ifndef_macro; |
- | |
3018 | /* need to set to zero to avoid false matches if another |
- | |
3019 | #ifndef at middle of file */ |
- | |
3020 | file->ifndef_macro = 0; |
- | |
3021 | while (tok != TOK_LINEFEED) |
- | |
3022 | next_nomacro(); |
- | |
3023 | tok_flags |= TOK_FLAG_ENDIF; |
- | |
3024 | goto the_end; |
- | |
3025 | } |
- | |
3026 | break; |
- | |
3027 | case TOK_LINE: |
- | |
3028 | next(); |
- | |
3029 | if (tok != TOK_CINT) |
- | |
3030 | error("#line"); |
- | |
3031 | file->line_num = tokc.i - 1; /* the line number will be incremented after */ |
- | |
3032 | next(); |
- | |
3033 | if (tok != TOK_LINEFEED) { |
- | |
3034 | if (tok != TOK_STR) |
- | |
3035 | error("#line"); |
- | |
3036 | pstrcpy(file->filename, sizeof(file->filename), |
- | |
3037 | (char *)tokc.cstr->data); |
- | |
3038 | } |
- | |
3039 | break; |
- | |
3040 | case TOK_ERROR: |
- | |
3041 | case TOK_WARNING: |
- | |
3042 | c = tok; |
- | |
3043 | ch = file->buf_ptr[0]; |
- | |
3044 | skip_spaces(); |
- | |
3045 | q = buf; |
- | |
3046 | while (ch != '\n' && ch != CH_EOF) { |
- | |
3047 | if ((q - buf) < sizeof(buf) - 1) |
- | |
3048 | *q++ = ch; |
- | |
3049 | minp(); |
- | |
3050 | } |
- | |
3051 | *q = '\0'; |
- | |
3052 | if (c == TOK_ERROR) |
- | |
3053 | error("#error %s", buf); |
- | |
3054 | else |
- | |
3055 | warning("#warning %s", buf); |
- | |
3056 | break; |
- | |
3057 | case TOK_PRAGMA: |
- | |
3058 | pragma_parse(s1); |
- | |
3059 | break; |
- | |
3060 | default: |
- | |
3061 | if (tok == TOK_LINEFEED || tok == '!' || tok == TOK_CINT) { |
- | |
3062 | /* '!' is ignored to allow C scripts. numbers are ignored |
- | |
3063 | to emulate cpp behaviour */ |
- | |
3064 | } else { |
- | |
3065 | if (!(saved_parse_flags & PARSE_FLAG_ASM_COMMENTS)) |
- | |
3066 | error("invalid preprocessing directive #%s", get_tok_str(tok, &tokc)); |
- | |
3067 | } |
- | |
3068 | break; |
- | |
3069 | } |
- | |
3070 | /* ignore other preprocess commands or #! for C scripts */ |
- | |
3071 | while (tok != TOK_LINEFEED) |
- | |
3072 | next_nomacro(); |
- | |
3073 | the_end: |
- | |
3074 | parse_flags = saved_parse_flags; |
- | |
3075 | } |
- | |
3076 | 25 | #endif |
|
3077 | /* evaluate escape codes in a string. */ |
- | |
3078 | static void parse_escape_string(CString *outstr, const uint8_t *buf, int is_long) |
- | |
3079 | { |
- | |
3080 | int c, n; |
- | |
3081 | const uint8_t *p; |
- | |
3082 | - | ||
3083 | p = buf; |
- | |
3084 | for(;;) { |
- | |
3085 | c = *p; |
- | |
3086 | if (c == '\0') |
- | |
3087 | break; |
- | |
3088 | if (c == '\\') { |
- | |
3089 | p++; |
- | |
3090 | /* escape */ |
- | |
3091 | c = *p; |
- | |
3092 | switch(c) { |
- | |
3093 | case '0': case '1': case '2': case '3': |
- | |
3094 | case '4': case '5': case '6': case '7': |
- | |
3095 | /* at most three octal digits */ |
- | |
3096 | n = c - '0'; |
- | |
3097 | p++; |
- | |
3098 | c = *p; |
- | |
3099 | if (isoct(c)) { |
- | |
3100 | n = n * 8 + c - '0'; |
- | |
3101 | p++; |
- | |
3102 | c = *p; |
- | |
3103 | if (isoct(c)) { |
- | |
3104 | n = n * 8 + c - '0'; |
- | |
3105 | p++; |
- | |
3106 | } |
- | |
3107 | } |
- | |
3108 | c = n; |
- | |
3109 | goto add_char_nonext; |
- | |
3110 | case 'x': |
- | |
3111 | p++; |
- | |
3112 | n = 0; |
- | |
3113 | for(;;) { |
- | |
3114 | c = *p; |
- | |
3115 | if (c >= 'a' && c <= 'f') |
- | |
3116 | c = c - 'a' + 10; |
- | |
3117 | else if (c >= 'A' && c <= 'F') |
- | |
3118 | c = c - 'A' + 10; |
- | |
3119 | else if (isnum(c)) |
- | |
3120 | c = c - '0'; |
- | |
3121 | else |
- | |
3122 | break; |
- | |
3123 | n = n * 16 + c; |
- | |
3124 | p++; |
- | |
3125 | } |
- | |
3126 | c = n; |
- | |
3127 | goto add_char_nonext; |
- | |
3128 | case 'a': |
- | |
3129 | c = '\a'; |
- | |
3130 | break; |
- | |
3131 | case 'b': |
- | |
3132 | c = '\b'; |
- | |
3133 | break; |
- | |
3134 | case 'f': |
- | |
3135 | c = '\f'; |
- | |
3136 | break; |
- | |
3137 | case 'n': |
- | |
3138 | c = '\n'; |
- | |
3139 | break; |
- | |
3140 | case 'r': |
- | |
3141 | c = '\r'; |
- | |
3142 | break; |
- | |
3143 | case 't': |
- | |
3144 | c = '\t'; |
- | |
3145 | break; |
- | |
3146 | case 'v': |
- | |
3147 | c = '\v'; |
- | |
3148 | break; |
- | |
3149 | case 'e': |
- | |
3150 | if (!gnu_ext) |
- | |
3151 | goto invalid_escape; |
- | |
3152 | c = 27; |
- | |
3153 | break; |
- | |
3154 | case '\'': |
- | |
3155 | case '\"': |
- | |
3156 | case '\\': |
- | |
3157 | case '?': |
- | |
3158 | break; |
- | |
3159 | default: |
- | |
3160 | invalid_escape: |
- | |
3161 | if (c >= '!' && c <= '~') |
- | |
3162 | warning("unknown escape sequence: \'\\%c\'", c); |
- | |
3163 | else |
- | |
3164 | warning("unknown escape sequence: \'\\x%x\'", c); |
- | |
3165 | break; |
- | |
3166 | } |
- | |
3167 | } |
- | |
3168 | p++; |
- | |
3169 | add_char_nonext: |
- | |
3170 | if (!is_long) |
- | |
3171 | cstr_ccat(outstr, c); |
- | |
3172 | else |
- | |
3173 | cstr_wccat(outstr, c); |
- | |
3174 | } |
- | |
3175 | /* add a trailing '\0' */ |
- | |
3176 | if (!is_long) |
- | |
3177 | cstr_ccat(outstr, '\0'); |
- | |
3178 | else |
- | |
3179 | cstr_wccat(outstr, '\0'); |
- | |
3180 | } |
- | |
3181 | - | ||
3182 | /* we use 64 bit numbers */ |
- | |
3183 | #define BN_SIZE 2 |
- | |
3184 | - | ||
3185 | /* bn = (bn << shift) | or_val */ |
- | |
3186 | void bn_lshift(unsigned int *bn, int shift, int or_val) |
- | |
3187 | { |
- | |
3188 | int i; |
- | |
3189 | unsigned int v; |
- | |
3190 | for(i=0;i |
- | |
3191 | v = bn[i]; |
- | |
3192 | bn[i] = (v << shift) | or_val; |
- | |
3193 | or_val = v >> (32 - shift); |
- | |
3194 | } |
- | |
3195 | } |
- | |
3196 | 26 | ||
3197 | void bn_zero(unsigned int *bn) |
27 | static void print_paths(const char *msg, char **paths, int nb_paths) |
- | 28 | { |
|
3198 | { |
29 | int i; |
3199 | int i; |
30 | printf("%s:\n%s", msg, nb_paths ? "" : " -\n"); |
3200 | for(i=0;i |
- | |
3201 | bn[i] = 0; |
31 | for(i = 0; i < nb_paths; i++) |
Line 3202... | Line -... | ||
3202 | } |
- | |
3203 | } |
- | |
3204 | 32 | printf(" %s\n", paths[i]); |
|
3205 | /* parse number in null terminated string 'p' and return it in the |
33 | } |
3206 | current token */ |
- | |
3207 | void parse_number(const char *p) |
- | |
3208 | { |
- | |
3209 | int b, t, shift, frac_bits, s, exp_val, ch; |
- | |
3210 | char *q; |
- | |
3211 | unsigned int bn[BN_SIZE]; |
- | |
3212 | double d; |
- | |
3213 | - | ||
3214 | /* number */ |
- | |
3215 | q = token_buf; |
- | |
3216 | ch = *p++; |
- | |
3217 | t = ch; |
- | |
3218 | ch = *p++; |
- | |
3219 | *q++ = t; |
- | |
3220 | b = 10; |
- | |
3221 | if (t == '.') { |
- | |
3222 | goto float_frac_parse; |
- | |
3223 | } else if (t == '0') { |
- | |
3224 | if (ch == 'x' || ch == 'X') { |
- | |
3225 | q--; |
- | |
3226 | ch = *p++; |
- | |
3227 | b = 16; |
- | |
3228 | } else if (tcc_ext && (ch == 'b' || ch == 'B')) { |
- | |
3229 | q--; |
- | |
3230 | ch = *p++; |
- | |
3231 | b = 2; |
- | |
3232 | } |
- | |
3233 | } |
- | |
3234 | /* parse all digits. cannot check octal numbers at this stage |
- | |
3235 | because of floating point constants */ |
- | |
3236 | while (1) { |
- | |
3237 | if (ch >= 'a' && ch <= 'f') |
- | |
3238 | t = ch - 'a' + 10; |
- | |
3239 | else if (ch >= 'A' && ch <= 'F') |
- | |
3240 | t = ch - 'A' + 10; |
- | |
3241 | else if (isnum(ch)) |
- | |
3242 | t = ch - '0'; |
- | |
3243 | else |
- | |
3244 | break; |
- | |
3245 | if (t >= b) |
- | |
3246 | break; |
- | |
3247 | if (q >= token_buf + STRING_MAX_SIZE) { |
- | |
3248 | num_too_long: |
- | |
3249 | error("number too long"); |
- | |
3250 | } |
- | |
3251 | *q++ = ch; |
- | |
3252 | ch = *p++; |
- | |
3253 | } |
- | |
3254 | if (ch == '.' || |
- | |
3255 | ((ch == 'e' || ch == 'E') && b == 10) || |
- | |
3256 | ((ch == 'p' || ch == 'P') && (b == 16 || b == 2))) { |
- | |
3257 | if (b != 10) { |
- | |
3258 | /* NOTE: strtox should support that for hexa numbers, but |
- | |
3259 | non ISOC99 libcs do not support it, so we prefer to do |
- | |
3260 | it by hand */ |
- | |
3261 | /* hexadecimal or binary floats */ |
- | |
3262 | /* XXX: handle overflows */ |
- | |
3263 | *q = '\0'; |
- | |
3264 | if (b == 16) |
- | |
3265 | shift = 4; |
- | |
3266 | else |
- | |
3267 | shift = 2; |
- | |
3268 | bn_zero(bn); |
- | |
3269 | q = token_buf; |
- | |
3270 | while (1) { |
- | |
3271 | t = *q++; |
- | |
3272 | if (t == '\0') { |
- | |
3273 | break; |
- | |
3274 | } else if (t >= 'a') { |
- | |
3275 | t = t - 'a' + 10; |
- | |
3276 | } else if (t >= 'A') { |
- | |
3277 | t = t - 'A' + 10; |
- | |
3278 | } else { |
- | |
3279 | t = t - '0'; |
- | |
3280 | } |
- | |
3281 | bn_lshift(bn, shift, t); |
- | |
3282 | } |
- | |
3283 | frac_bits = 0; |
- | |
3284 | if (ch == '.') { |
- | |
3285 | ch = *p++; |
- | |
3286 | while (1) { |
- | |
3287 | t = ch; |
- | |
3288 | if (t >= 'a' && t <= 'f') { |
- | |
3289 | t = t - 'a' + 10; |
- | |
3290 | } else if (t >= 'A' && t <= 'F') { |
- | |
3291 | t = t - 'A' + 10; |
- | |
3292 | } else if (t >= '0' && t <= '9') { |
- | |
3293 | t = t - '0'; |
- | |
3294 | } else { |
- | |
3295 | break; |
- | |
3296 | } |
- | |
3297 | if (t >= b) |
- | |
3298 | error("invalid digit"); |
- | |
3299 | bn_lshift(bn, shift, t); |
- | |
3300 | frac_bits += shift; |
- | |
3301 | ch = *p++; |
- | |
3302 | } |
- | |
3303 | } |
- | |
3304 | if (ch != 'p' && ch != 'P') |
- | |
3305 | expect("exponent"); |
- | |
3306 | ch = *p++; |
- | |
3307 | s = 1; |
- | |
3308 | exp_val = 0; |
- | |
3309 | if (ch == '+') { |
- | |
3310 | ch = *p++; |
- | |
3311 | } else if (ch == '-') { |
- | |
3312 | s = -1; |
- | |
3313 | ch = *p++; |
- | |
3314 | } |
- | |
3315 | if (ch < '0' || ch > '9') |
- | |
3316 | expect("exponent digits"); |
- | |
3317 | while (ch >= '0' && ch <= '9') { |
- | |
3318 | exp_val = exp_val * 10 + ch - '0'; |
- | |
3319 | ch = *p++; |
- | |
3320 | } |
- | |
3321 | exp_val = exp_val * s; |
- | |
3322 | - | ||
3323 | /* now we can generate the number */ |
- | |
3324 | /* XXX: should patch directly float number */ |
- | |
3325 | d = (double)bn[1] * 4294967296.0 + (double)bn[0]; |
- | |
3326 | d = ldexp(d, exp_val - frac_bits); |
- | |
3327 | t = toup(ch); |
- | |
3328 | if (t == 'F') { |
- | |
3329 | ch = *p++; |
- | |
3330 | tok = TOK_CFLOAT; |
- | |
3331 | /* float : should handle overflow */ |
- | |
3332 | tokc.f = (float)d; |
- | |
3333 | } else if (t == 'L') { |
- | |
3334 | ch = *p++; |
- | |
3335 | tok = TOK_CLDOUBLE; |
- | |
3336 | /* XXX: not large enough */ |
- | |
3337 | tokc.ld = (long double)d; |
- | |
3338 | } else { |
- | |
3339 | tok = TOK_CDOUBLE; |
- | |
3340 | tokc.d = d; |
- | |
3341 | } |
- | |
3342 | } else { |
- | |
3343 | /* decimal floats */ |
- | |
3344 | if (ch == '.') { |
- | |
3345 | if (q >= token_buf + STRING_MAX_SIZE) |
- | |
3346 | goto num_too_long; |
- | |
3347 | *q++ = ch; |
- | |
3348 | ch = *p++; |
- | |
3349 | float_frac_parse: |
- | |
3350 | while (ch >= '0' && ch <= '9') { |
- | |
3351 | if (q >= token_buf + STRING_MAX_SIZE) |
- | |
3352 | goto num_too_long; |
- | |
3353 | *q++ = ch; |
- | |
3354 | ch = *p++; |
- | |
3355 | } |
- | |
3356 | } |
- | |
3357 | if (ch == 'e' || ch == 'E') { |
- | |
3358 | if (q >= token_buf + STRING_MAX_SIZE) |
- | |
3359 | goto num_too_long; |
- | |
3360 | *q++ = ch; |
- | |
3361 | ch = *p++; |
- | |
3362 | if (ch == '-' || ch == '+') { |
- | |
3363 | if (q >= token_buf + STRING_MAX_SIZE) |
- | |
3364 | goto num_too_long; |
- | |
3365 | *q++ = ch; |
- | |
3366 | ch = *p++; |
- | |
3367 | } |
- | |
3368 | if (ch < '0' || ch > '9') |
- | |
3369 | expect("exponent digits"); |
- | |
3370 | while (ch >= '0' && ch <= '9') { |
- | |
3371 | if (q >= token_buf + STRING_MAX_SIZE) |
- | |
3372 | goto num_too_long; |
- | |
3373 | *q++ = ch; |
- | |
3374 | ch = *p++; |
- | |
3375 | } |
- | |
3376 | } |
- | |
3377 | *q = '\0'; |
- | |
3378 | t = toup(ch); |
- | |
3379 | //errno = 0; |
- | |
3380 | if (t == 'F') { |
- | |
3381 | ch = *p++; |
- | |
3382 | tok = TOK_CFLOAT; |
- | |
3383 | tokc.f = strtof(token_buf, NULL); |
- | |
3384 | } else if (t == 'L') { |
- | |
3385 | ch = *p++; |
- | |
3386 | tok = TOK_CLDOUBLE; |
- | |
3387 | tokc.ld = strtold(token_buf, NULL); |
- | |
3388 | } else { |
- | |
3389 | tok = TOK_CDOUBLE; |
- | |
3390 | tokc.d = strtod(token_buf, NULL); |
- | |
3391 | } |
- | |
3392 | } |
- | |
3393 | } else { |
- | |
3394 | unsigned long long n, n1; |
- | |
3395 | int lcount, ucount; |
- | |
3396 | - | ||
3397 | /* integer number */ |
- | |
3398 | *q = '\0'; |
- | |
3399 | q = token_buf; |
- | |
3400 | if (b == 10 && *q == '0') { |
- | |
3401 | b = 8; |
- | |
3402 | q++; |
- | |
3403 | } |
- | |
3404 | n = 0; |
- | |
3405 | while(1) { |
- | |
3406 | t = *q++; |
- | |
3407 | /* no need for checks except for base 10 / 8 errors */ |
- | |
3408 | if (t == '\0') { |
- | |
3409 | break; |
- | |
3410 | } else if (t >= 'a') { |
- | |
3411 | t = t - 'a' + 10; |
- | |
3412 | } else if (t >= 'A') { |
- | |
3413 | t = t - 'A' + 10; |
- | |
3414 | } else { |
- | |
3415 | t = t - '0'; |
- | |
3416 | if (t >= b) |
- | |
3417 | error("invalid digit"); |
- | |
3418 | } |
- | |
3419 | n1 = n; |
- | |
3420 | n = n * b + t; |
- | |
3421 | /* detect overflow */ |
- | |
3422 | /* XXX: this test is not reliable */ |
- | |
3423 | if (n < n1) |
- | |
3424 | error("integer constant overflow"); |
- | |
3425 | } |
- | |
3426 | - | ||
3427 | /* XXX: not exactly ANSI compliant */ |
- | |
3428 | if ((n & 0xffffffff00000000LL) != 0) { |
- | |
3429 | if ((n >> 63) != 0) |
- | |
3430 | tok = TOK_CULLONG; |
- | |
3431 | else |
- | |
3432 | tok = TOK_CLLONG; |
- | |
3433 | } else if (n > 0x7fffffff) { |
- | |
3434 | tok = TOK_CUINT; |
- | |
3435 | } else { |
- | |
3436 | tok = TOK_CINT; |
- | |
3437 | } |
- | |
3438 | lcount = 0; |
- | |
3439 | ucount = 0; |
- | |
3440 | for(;;) { |
- | |
3441 | t = toup(ch); |
- | |
3442 | if (t == 'L') { |
- | |
3443 | if (lcount >= 2) |
- | |
3444 | error("three 'l's in integer constant"); |
- | |
3445 | lcount++; |
- | |
3446 | if (lcount == 2) { |
- | |
3447 | if (tok == TOK_CINT) |
- | |
3448 | tok = TOK_CLLONG; |
- | |
3449 | else if (tok == TOK_CUINT) |
- | |
3450 | tok = TOK_CULLONG; |
- | |
3451 | } |
- | |
3452 | ch = *p++; |
- | |
3453 | } else if (t == 'U') { |
- | |
3454 | if (ucount >= 1) |
- | |
3455 | error("two 'u's in integer constant"); |
- | |
3456 | ucount++; |
- | |
3457 | if (tok == TOK_CINT) |
- | |
3458 | tok = TOK_CUINT; |
- | |
3459 | else if (tok == TOK_CLLONG) |
- | |
3460 | tok = TOK_CULLONG; |
- | |
3461 | ch = *p++; |
- | |
3462 | } else { |
- | |
3463 | break; |
- | |
3464 | } |
- | |
3465 | } |
- | |
3466 | if (tok == TOK_CINT || tok == TOK_CUINT) |
- | |
3467 | tokc.ui = n; |
- | |
3468 | else |
- | |
3469 | tokc.ull = n; |
- | |
3470 | } |
- | |
3471 | } |
- | |
3472 | - | ||
3473 | - | ||
3474 | #define PARSE2(c1, tok1, c2, tok2) \ |
- | |
3475 | case c1: \ |
- | |
3476 | PEEKC(c, p); \ |
- | |
3477 | if (c == c2) { \ |
- | |
3478 | p++; \ |
- | |
3479 | tok = tok2; \ |
- | |
3480 | } else { \ |
- | |
3481 | tok = tok1; \ |
- | |
3482 | } \ |
- | |
3483 | break; |
- | |
3484 | - | ||
3485 | /* return next token without macro substitution */ |
- | |
3486 | static inline void next_nomacro1(void) |
- | |
3487 | { |
- | |
3488 | int t, c, is_long; |
- | |
3489 | TokenSym *ts; |
- | |
3490 | uint8_t *p, *p1; |
- | |
3491 | unsigned int h; |
- | |
3492 | - | ||
3493 | p = file->buf_ptr; |
34 | |
3494 | redo_no_start: |
- | |
3495 | c = *p; |
- | |
3496 | switch(c) { |
- | |
3497 | case ' ': |
- | |
3498 | case '\t': |
- | |
3499 | case '\f': |
- | |
3500 | case '\v': |
- | |
3501 | case '\r': |
- | |
3502 | p++; |
- | |
3503 | goto redo_no_start; |
- | |
3504 | - | ||
3505 | case '\\': |
- | |
3506 | /* first look if it is in fact an end of buffer */ |
- | |
3507 | if (p >= file->buf_end) { |
- | |
3508 | file->buf_ptr = p; |
- | |
3509 | handle_eob(); |
- | |
3510 | p = file->buf_ptr; |
- | |
3511 | if (p >= file->buf_end) |
- | |
3512 | goto parse_eof; |
- | |
3513 | else |
- | |
3514 | goto redo_no_start; |
- | |
3515 | } else { |
- | |
3516 | file->buf_ptr = p; |
- | |
3517 | ch = *p; |
- | |
3518 | handle_stray(); |
- | |
3519 | p = file->buf_ptr; |
- | |
3520 | goto redo_no_start; |
- | |
3521 | } |
- | |
3522 | parse_eof: |
- | |
3523 | { |
- | |
3524 | TCCState *s1 = tcc_state; |
- | |
3525 | if (parse_flags & PARSE_FLAG_LINEFEED) { |
- | |
3526 | tok = TOK_LINEFEED; |
- | |
3527 | } else if (s1->include_stack_ptr == s1->include_stack || |
- | |
3528 | !(parse_flags & PARSE_FLAG_PREPROCESS)) { |
- | |
3529 | /* no include left : end of file. */ |
- | |
3530 | tok = TOK_EOF; |
- | |
3531 | } else { |
- | |
3532 | /* pop include file */ |
- | |
3533 | - | ||
3534 | /* test if previous '#endif' was after a #ifdef at |
- | |
3535 | start of file */ |
- | |
3536 | if (tok_flags & TOK_FLAG_ENDIF) { |
- | |
3537 | #ifdef INC_DEBUG |
- | |
3538 | printf("#endif %s\n", get_tok_str(file->ifndef_macro_saved, NULL)); |
- | |
3539 | #endif |
- | |
3540 | add_cached_include(s1, file->inc_type, file->inc_filename, |
- | |
3541 | file->ifndef_macro_saved); |
- | |
3542 | } |
- | |
3543 | - | ||
3544 | /* add end of include file debug info */ |
- | |
3545 | if (do_debug) { |
- | |
3546 | put_stabd(N_EINCL, 0, 0); |
- | |
3547 | } |
- | |
3548 | /* pop include stack */ |
- | |
3549 | tcc_close(file); |
- | |
3550 | s1->include_stack_ptr--; |
- | |
3551 | file = *s1->include_stack_ptr; |
- | |
3552 | p = file->buf_ptr; |
- | |
3553 | goto redo_no_start; |
- | |
3554 | } |
- | |
3555 | } |
- | |
3556 | break; |
- | |
3557 | - | ||
3558 | case '\n': |
- | |
3559 | if (parse_flags & PARSE_FLAG_LINEFEED) { |
- | |
3560 | tok = TOK_LINEFEED; |
- | |
3561 | } else { |
- | |
3562 | file->line_num++; |
- | |
3563 | tok_flags |= TOK_FLAG_BOL; |
- | |
3564 | p++; |
- | |
3565 | goto redo_no_start; |
- | |
3566 | } |
- | |
3567 | break; |
- | |
3568 | - | ||
3569 | case '#': |
- | |
3570 | /* XXX: simplify */ |
- | |
3571 | PEEKC(c, p); |
- | |
3572 | if ((tok_flags & TOK_FLAG_BOL) && |
- | |
3573 | (parse_flags & PARSE_FLAG_PREPROCESS)) { |
- | |
3574 | file->buf_ptr = p; |
- | |
3575 | preprocess(tok_flags & TOK_FLAG_BOF); |
- | |
3576 | p = file->buf_ptr; |
- | |
3577 | goto redo_no_start; |
- | |
3578 | } else { |
- | |
3579 | if (c == '#') { |
- | |
3580 | p++; |
- | |
3581 | tok = TOK_TWOSHARPS; |
- | |
3582 | } else { |
- | |
3583 | if (parse_flags & PARSE_FLAG_ASM_COMMENTS) { |
- | |
3584 | p = parse_line_comment(p - 1); |
- | |
3585 | goto redo_no_start; |
- | |
3586 | } else { |
- | |
3587 | tok = '#'; |
- | |
3588 | } |
- | |
3589 | } |
- | |
3590 | } |
- | |
3591 | break; |
- | |
3592 | - | ||
3593 | case 'a': case 'b': case 'c': case 'd': |
- | |
3594 | case 'e': case 'f': case 'g': case 'h': |
- | |
3595 | case 'i': case 'j': case 'k': case 'l': |
- | |
3596 | case 'm': case 'n': case 'o': case 'p': |
- | |
3597 | case 'q': case 'r': case 's': case 't': |
- | |
3598 | case 'u': case 'v': case 'w': case 'x': |
- | |
3599 | case 'y': case 'z': |
- | |
3600 | case 'A': case 'B': case 'C': case 'D': |
- | |
3601 | case 'E': case 'F': case 'G': case 'H': |
- | |
3602 | case 'I': case 'J': case 'K': |
- | |
3603 | case 'M': case 'N': case 'O': case 'P': |
- | |
3604 | case 'Q': case 'R': case 'S': case 'T': |
- | |
3605 | case 'U': case 'V': case 'W': case 'X': |
- | |
3606 | case 'Y': case 'Z': |
- | |
3607 | case '_': |
- | |
3608 | parse_ident_fast: |
- | |
3609 | p1 = p; |
- | |
3610 | h = TOK_HASH_INIT; |
- | |
3611 | h = TOK_HASH_FUNC(h, c); |
- | |
3612 | p++; |
- | |
3613 | for(;;) { |
- | |
3614 | c = *p; |
- | |
3615 | if (!isidnum_table[c]) |
- | |
3616 | break; |
- | |
3617 | h = TOK_HASH_FUNC(h, c); |
- | |
3618 | p++; |
- | |
3619 | } |
- | |
3620 | if (c != '\\') { |
- | |
3621 | TokenSym **pts; |
- | |
3622 | int len; |
- | |
3623 | - | ||
3624 | /* fast case : no stray found, so we have the full token |
- | |
3625 | and we have already hashed it */ |
- | |
3626 | len = p - p1; |
- | |
3627 | h &= (TOK_HASH_SIZE - 1); |
- | |
3628 | pts = &hash_ident[h]; |
- | |
3629 | for(;;) { |
- | |
3630 | ts = *pts; |
- | |
3631 | if (!ts) |
- | |
3632 | break; |
- | |
3633 | if (ts->len == len && !memcmp(ts->str, p1, len)) |
- | |
3634 | goto token_found; |
- | |
3635 | pts = &(ts->hash_next); |
- | |
3636 | } |
- | |
3637 | ts = tok_alloc_new(pts, p1, len); |
- | |
3638 | token_found: ; |
- | |
3639 | } else { |
- | |
3640 | /* slower case */ |
- | |
3641 | cstr_reset(&tokcstr); |
- | |
3642 | - | ||
3643 | while (p1 < p) { |
- | |
3644 | cstr_ccat(&tokcstr, *p1); |
- | |
3645 | p1++; |
- | |
3646 | } |
- | |
3647 | p--; |
- | |
3648 | PEEKC(c, p); |
- | |
3649 | parse_ident_slow: |
- | |
3650 | while (isidnum_table[c]) { |
- | |
3651 | cstr_ccat(&tokcstr, c); |
- | |
3652 | PEEKC(c, p); |
- | |
3653 | } |
- | |
3654 | ts = tok_alloc(tokcstr.data, tokcstr.size); |
- | |
3655 | } |
- | |
3656 | tok = ts->tok; |
- | |
3657 | break; |
- | |
3658 | case 'L': |
- | |
3659 | t = p[1]; |
- | |
3660 | if (t != '\\' && t != '\'' && t != '\"') { |
- | |
3661 | /* fast case */ |
- | |
3662 | goto parse_ident_fast; |
- | |
3663 | } else { |
- | |
3664 | PEEKC(c, p); |
- | |
3665 | if (c == '\'' || c == '\"') { |
- | |
3666 | is_long = 1; |
- | |
3667 | goto str_const; |
- | |
3668 | } else { |
- | |
3669 | cstr_reset(&tokcstr); |
- | |
3670 | cstr_ccat(&tokcstr, 'L'); |
- | |
3671 | goto parse_ident_slow; |
- | |
3672 | } |
- | |
3673 | } |
- | |
3674 | break; |
- | |
3675 | case '0': case '1': case '2': case '3': |
- | |
3676 | case '4': case '5': case '6': case '7': |
- | |
3677 | case '8': case '9': |
- | |
3678 | - | ||
3679 | cstr_reset(&tokcstr); |
- | |
3680 | /* after the first digit, accept digits, alpha, '.' or sign if |
- | |
3681 | prefixed by 'eEpP' */ |
- | |
3682 | parse_num: |
- | |
3683 | for(;;) { |
- | |
3684 | t = c; |
- | |
3685 | cstr_ccat(&tokcstr, c); |
- | |
3686 | PEEKC(c, p); |
- | |
3687 | if (!(isnum(c) || isid(c) || c == '.' || |
- | |
3688 | ((c == '+' || c == '-') && |
- | |
3689 | (t == 'e' || t == 'E' || t == 'p' || t == 'P')))) |
- | |
3690 | break; |
- | |
3691 | } |
- | |
3692 | /* We add a trailing '\0' to ease parsing */ |
- | |
3693 | cstr_ccat(&tokcstr, '\0'); |
- | |
3694 | tokc.cstr = &tokcstr; |
35 | static void display_info(TCCState *s, int what) |
3695 | tok = TOK_PPNUM; |
- | |
3696 | break; |
- | |
3697 | case '.': |
- | |
3698 | /* special dot handling because it can also start a number */ |
- | |
3699 | PEEKC(c, p); |
- | |
3700 | if (isnum(c)) { |
- | |
3701 | cstr_reset(&tokcstr); |
- | |
3702 | cstr_ccat(&tokcstr, '.'); |
- | |
3703 | goto parse_num; |
- | |
3704 | } else if (c == '.') { |
- | |
3705 | PEEKC(c, p); |
- | |
3706 | if (c != '.') |
- | |
3707 | expect("'.'"); |
- | |
3708 | PEEKC(c, p); |
- | |
3709 | tok = TOK_DOTS; |
- | |
3710 | } else { |
- | |
3711 | tok = '.'; |
- | |
3712 | } |
- | |
3713 | break; |
- | |
3714 | case '\'': |
- | |
3715 | case '\"': |
- | |
3716 | is_long = 0; |
- | |
3717 | str_const: |
- | |
3718 | { |
- | |
3719 | CString str; |
- | |
3720 | int sep; |
- | |
3721 | - | ||
3722 | sep = c; |
- | |
3723 | - | ||
3724 | /* parse the string */ |
- | |
3725 | cstr_new(&str); |
- | |
3726 | p = parse_pp_string(p, sep, &str); |
- | |
3727 | cstr_ccat(&str, '\0'); |
- | |
3728 | - | ||
3729 | /* eval the escape (should be done as TOK_PPNUM) */ |
- | |
3730 | cstr_reset(&tokcstr); |
- | |
3731 | parse_escape_string(&tokcstr, str.data, is_long); |
- | |
3732 | cstr_free(&str); |
- | |
3733 | - | ||
3734 | if (sep == '\'') { |
- | |
3735 | int char_size; |
36 | { |
3736 | /* XXX: make it portable */ |
- | |
3737 | if (!is_long) |
- | |
3738 | char_size = 1; |
- | |
3739 | else |
- | |
3740 | char_size = sizeof(int); |
- | |
3741 | if (tokcstr.size <= char_size) |
- | |
3742 | error("empty character constant"); |
- | |
3743 | if (tokcstr.size > 2 * char_size) |
- | |
3744 | warning("multi-character character constant"); |
- | |
3745 | if (!is_long) { |
- | |
3746 | tokc.i = *(int8_t *)tokcstr.data; |
- | |
3747 | tok = TOK_CCHAR; |
- | |
3748 | } else { |
- | |
3749 | tokc.i = *(int *)tokcstr.data; |
- | |
3750 | tok = TOK_LCHAR; |
- | |
3751 | } |
- | |
3752 | } else { |
- | |
3753 | tokc.cstr = &tokcstr; |
- | |
3754 | if (!is_long) |
- | |
3755 | tok = TOK_STR; |
- | |
3756 | else |
- | |
3757 | tok = TOK_LSTR; |
- | |
3758 | } |
- | |
3759 | } |
- | |
3760 | break; |
- | |
3761 | - | ||
3762 | case '<': |
- | |
3763 | PEEKC(c, p); |
- | |
3764 | if (c == '=') { |
- | |
3765 | p++; |
- | |
3766 | tok = TOK_LE; |
- | |
3767 | } else if (c == '<') { |
- | |
3768 | PEEKC(c, p); |
- | |
3769 | if (c == '=') { |
- | |
3770 | p++; |
- | |
3771 | tok = TOK_A_SHL; |
- | |
3772 | } else { |
- | |
3773 | tok = TOK_SHL; |
- | |
3774 | } |
- | |
3775 | } else { |
- | |
3776 | tok = TOK_LT; |
- | |
3777 | } |
- | |
3778 | break; |
- | |
3779 | - | ||
3780 | case '>': |
- | |
3781 | PEEKC(c, p); |
- | |
3782 | if (c == '=') { |
- | |
3783 | p++; |
- | |
3784 | tok = TOK_GE; |
- | |
3785 | } else if (c == '>') { |
- | |
3786 | PEEKC(c, p); |
- | |
3787 | if (c == '=') { |
- | |
3788 | p++; |
- | |
3789 | tok = TOK_A_SAR; |
- | |
3790 | } else { |
- | |
3791 | tok = TOK_SAR; |
- | |
3792 | } |
- | |
3793 | } else { |
- | |
3794 | tok = TOK_GT; |
- | |
3795 | } |
- | |
3796 | break; |
- | |
3797 | - | ||
3798 | case '&': |
- | |
3799 | PEEKC(c, p); |
- | |
3800 | if (c == '&') { |
- | |
3801 | p++; |
- | |
3802 | tok = TOK_LAND; |
- | |
3803 | } else if (c == '=') { |
- | |
3804 | p++; |
- | |
3805 | tok = TOK_A_AND; |
- | |
3806 | } else { |
- | |
3807 | tok = '&'; |
- | |
3808 | } |
- | |
3809 | break; |
- | |
3810 | - | ||
3811 | case '|': |
- | |
3812 | PEEKC(c, p); |
- | |
3813 | if (c == '|') { |
- | |
3814 | p++; |
- | |
3815 | tok = TOK_LOR; |
- | |
3816 | } else if (c == '=') { |
- | |
3817 | p++; |
- | |
3818 | tok = TOK_A_OR; |
- | |
3819 | } else { |
- | |
3820 | tok = '|'; |
- | |
3821 | } |
- | |
3822 | break; |
- | |
3823 | - | ||
3824 | case '+': |
- | |
3825 | PEEKC(c, p); |
- | |
3826 | if (c == '+') { |
- | |
3827 | p++; |
- | |
3828 | tok = TOK_INC; |
- | |
3829 | } else if (c == '=') { |
- | |
3830 | p++; |
- | |
3831 | tok = TOK_A_ADD; |
- | |
3832 | } else { |
- | |
3833 | tok = '+'; |
- | |
3834 | } |
- | |
3835 | break; |
- | |
3836 | - | ||
3837 | case '-': |
- | |
3838 | PEEKC(c, p); |
- | |
3839 | if (c == '-') { |
- | |
3840 | p++; |
- | |
3841 | tok = TOK_DEC; |
- | |
3842 | } else if (c == '=') { |
- | |
3843 | p++; |
- | |
3844 | tok = TOK_A_SUB; |
- | |
3845 | } else if (c == '>') { |
- | |
3846 | p++; |
- | |
3847 | tok = TOK_ARROW; |
- | |
3848 | } else { |
- | |
3849 | tok = '-'; |
- | |
3850 | } |
- | |
3851 | break; |
- | |
3852 | - | ||
3853 | PARSE2('!', '!', '=', TOK_NE) |
- | |
3854 | PARSE2('=', '=', '=', TOK_EQ) |
- | |
3855 | PARSE2('*', '*', '=', TOK_A_MUL) |
- | |
3856 | PARSE2('%', '%', '=', TOK_A_MOD) |
- | |
3857 | PARSE2('^', '^', '=', TOK_A_XOR) |
- | |
3858 | - | ||
3859 | /* comments or operator */ |
- | |
3860 | case '/': |
- | |
3861 | PEEKC(c, p); |
- | |
3862 | if (c == '*') { |
- | |
3863 | p = parse_comment(p); |
- | |
3864 | goto redo_no_start; |
- | |
3865 | } else if (c == '/') { |
- | |
3866 | p = parse_line_comment(p); |
- | |
3867 | goto redo_no_start; |
- | |
3868 | } else if (c == '=') { |
- | |
3869 | p++; |
- | |
3870 | tok = TOK_A_DIV; |
- | |
3871 | } else { |
- | |
3872 | tok = '/'; |
- | |
3873 | } |
- | |
3874 | break; |
- | |
3875 | - | ||
3876 | /* simple tokens */ |
- | |
3877 | case '(': |
- | |
3878 | case ')': |
- | |
3879 | case '[': |
- | |
3880 | case ']': |
- | |
3881 | case '{': |
- | |
3882 | case '}': |
- | |
3883 | case ',': |
- | |
3884 | case ';': |
- | |
3885 | case ':': |
- | |
3886 | case '?': |
- | |
3887 | case '~': |
- | |
3888 | case '$': /* only used in assembler */ |
- | |
3889 | case '@': /* dito */ |
- | |
3890 | tok = c; |
- | |
3891 | p++; |
- | |
3892 | break; |
- | |
3893 | default: |
- | |
3894 | error("unrecognized character \\x%02x", c); |
- | |
3895 | break; |
- | |
3896 | } |
- | |
3897 | file->buf_ptr = p; |
- | |
3898 | tok_flags = 0; |
- | |
3899 | #if defined(PARSE_DEBUG) |
- | |
3900 | printf("token = %s\n", get_tok_str(tok, &tokc)); |
- | |
3901 | #endif |
- | |
3902 | } |
- | |
3903 | - | ||
3904 | /* return next token without macro substitution. Can read input from |
- | |
3905 | macro_ptr buffer */ |
- | |
3906 | static void next_nomacro(void) |
- | |
3907 | { |
- | |
3908 | if (macro_ptr) { |
- | |
3909 | redo: |
- | |
3910 | tok = *macro_ptr; |
- | |
3911 | if (tok) { |
- | |
3912 | TOK_GET(tok, macro_ptr, tokc); |
- | |
3913 | if (tok == TOK_LINENUM) { |
- | |
3914 | file->line_num = tokc.i; |
- | |
3915 | goto redo; |
- | |
3916 | } |
- | |
3917 | } |
- | |
3918 | } else { |
- | |
3919 | next_nomacro1(); |
- | |
3920 | } |
- | |
3921 | } |
- | |
3922 | - | ||
3923 | /* substitute args in macro_str and return allocated string */ |
- | |
3924 | static int *macro_arg_subst(Sym **nested_list, int *macro_str, Sym *args) |
- | |
3925 | { |
- | |
3926 | int *st, last_tok, t, notfirst; |
- | |
3927 | Sym *s; |
- | |
3928 | CValue cval; |
- | |
3929 | TokenString str; |
- | |
3930 | CString cstr; |
- | |
3931 | - | ||
3932 | tok_str_new(&str); |
- | |
3933 | last_tok = 0; |
- | |
3934 | while(1) { |
- | |
3935 | TOK_GET(t, macro_str, cval); |
- | |
3936 | if (!t) |
- | |
3937 | break; |
- | |
3938 | if (t == '#') { |
- | |
3939 | /* stringize */ |
- | |
3940 | TOK_GET(t, macro_str, cval); |
- | |
3941 | if (!t) |
- | |
3942 | break; |
- | |
3943 | s = sym_find2(args, t); |
- | |
3944 | if (s) { |
- | |
3945 | cstr_new(&cstr); |
- | |
3946 | st = (int *)s->c; |
- | |
3947 | notfirst = 0; |
- | |
3948 | while (*st) { |
- | |
3949 | if (notfirst) |
- | |
3950 | cstr_ccat(&cstr, ' '); |
- | |
3951 | TOK_GET(t, st, cval); |
- | |
3952 | cstr_cat(&cstr, get_tok_str(t, &cval)); |
- | |
3953 | notfirst = 1; |
- | |
3954 | } |
- | |
3955 | cstr_ccat(&cstr, '\0'); |
- | |
3956 | #ifdef PP_DEBUG |
- | |
3957 | printf("stringize: %s\n", (char *)cstr.data); |
- | |
3958 | #endif |
- | |
3959 | /* add string */ |
- | |
3960 | cval.cstr = &cstr; |
- | |
3961 | tok_str_add2(&str, TOK_STR, &cval); |
- | |
3962 | cstr_free(&cstr); |
- | |
3963 | } else { |
- | |
3964 | tok_str_add2(&str, t, &cval); |
- | |
3965 | } |
- | |
3966 | } else if (t >= TOK_IDENT) { |
- | |
3967 | s = sym_find2(args, t); |
- | |
3968 | if (s) { |
- | |
3969 | st = (int *)s->c; |
- | |
3970 | /* if '##' is present before or after, no arg substitution */ |
- | |
3971 | if (*macro_str == TOK_TWOSHARPS || last_tok == TOK_TWOSHARPS) { |
- | |
3972 | /* special case for var arg macros : ## eats the |
- | |
3973 | ',' if empty VA_ARGS variable. */ |
- | |
3974 | /* XXX: test of the ',' is not 100% |
- | |
3975 | reliable. should fix it to avoid security |
- | |
3976 | problems */ |
- | |
3977 | if (gnu_ext && s->type.t && |
- | |
3978 | last_tok == TOK_TWOSHARPS && |
- | |
3979 | str.len >= 2 && str.str[str.len - 2] == ',') { |
- | |
3980 | if (*st == 0) { |
- | |
3981 | /* suppress ',' '##' */ |
- | |
3982 | str.len -= 2; |
- | |
3983 | } else { |
- | |
3984 | /* suppress '##' and add variable */ |
- | |
3985 | str.len--; |
- | |
3986 | goto add_var; |
- | |
3987 | } |
- | |
3988 | } else { |
- | |
3989 | int t1; |
- | |
3990 | add_var: |
- | |
3991 | for(;;) { |
- | |
3992 | TOK_GET(t1, st, cval); |
- | |
3993 | if (!t1) |
- | |
3994 | break; |
- | |
3995 | tok_str_add2(&str, t1, &cval); |
- | |
3996 | } |
- | |
3997 | } |
- | |
3998 | } else { |
- | |
3999 | /* NOTE: the stream cannot be read when macro |
- | |
4000 | substituing an argument */ |
- | |
4001 | macro_subst(&str, nested_list, st, NULL); |
- | |
4002 | } |
- | |
4003 | } else { |
- | |
4004 | tok_str_add(&str, t); |
- | |
4005 | } |
- | |
4006 | } else { |
- | |
4007 | tok_str_add2(&str, t, &cval); |
- | |
4008 | } |
- | |
4009 | last_tok = t; |
- | |
4010 | } |
- | |
4011 | tok_str_add(&str, 0); |
- | |
4012 | return str.str; |
- | |
4013 | } |
- | |
4014 | - | ||
4015 | static char const ab_month_name[12][4] = |
- | |
4016 | { |
- | |
4017 | "Jan", "Feb", "Mar", "Apr", "May", "Jun", |
- | |
4018 | "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" |
- | |
4019 | }; |
- | |
4020 | - | ||
4021 | /* do macro substitution of current token with macro 's' and add |
- | |
4022 | result to (tok_str,tok_len). 'nested_list' is the list of all |
- | |
4023 | macros we got inside to avoid recursing. Return non zero if no |
- | |
4024 | substitution needs to be done */ |
- | |
4025 | static int macro_subst_tok(TokenString *tok_str, |
- | |
4026 | Sym **nested_list, Sym *s, struct macro_level **can_read_stream) |
- | |
4027 | { |
- | |
4028 | Sym *args, *sa, *sa1; |
- | |
4029 | int mstr_allocated, parlevel, *mstr, t, t1; |
- | |
4030 | TokenString str; |
- | |
4031 | char *cstrval; |
- | |
4032 | CValue cval; |
- | |
4033 | CString cstr; |
- | |
4034 | char buf[32]; |
- | |
4035 | - | ||
4036 | /* if symbol is a macro, prepare substitution */ |
- | |
4037 | /* special macros */ |
- | |
4038 | if (tok == TOK___LINE__) { |
- | |
4039 | snprintf(buf, sizeof(buf), "%d", file->line_num); |
- | |
4040 | cstrval = buf; |
- | |
4041 | t1 = TOK_PPNUM; |
- | |
4042 | goto add_cstr1; |
- | |
4043 | } else if (tok == TOK___FILE__) { |
- | |
4044 | cstrval = file->filename; |
- | |
4045 | goto add_cstr; |
- | |
4046 | } else if (tok == TOK___DATE__ || tok == TOK___TIME__) { |
- | |
4047 | time_t ti; |
- | |
4048 | struct tm *tm; |
- | |
4049 | - | ||
4050 | time(&ti); |
- | |
4051 | tm = localtime(&ti); |
- | |
4052 | if (tok == TOK___DATE__) { |
- | |
4053 | snprintf(buf, sizeof(buf), "%s %2d %d", |
- | |
4054 | ab_month_name[tm->tm_mon], tm->tm_mday, tm->tm_year + 1900); |
- | |
4055 | } else { |
- | |
4056 | snprintf(buf, sizeof(buf), "%02d:%02d:%02d", |
- | |
4057 | tm->tm_hour, tm->tm_min, tm->tm_sec); |
- | |
4058 | } |
- | |
4059 | cstrval = buf; |
- | |
4060 | add_cstr: |
- | |
4061 | t1 = TOK_STR; |
- | |
4062 | add_cstr1: |
- | |
4063 | cstr_new(&cstr); |
- | |
4064 | cstr_cat(&cstr, cstrval); |
- | |
4065 | cstr_ccat(&cstr, '\0'); |
- | |
4066 | cval.cstr = &cstr; |
- | |
4067 | tok_str_add2(tok_str, t1, &cval); |
- | |
4068 | cstr_free(&cstr); |
- | |
4069 | } else { |
- | |
4070 | mstr = (int *)s->c; |
- | |
4071 | mstr_allocated = 0; |
- | |
4072 | if (s->type.t == MACRO_FUNC) { |
- | |
4073 | /* NOTE: we do not use next_nomacro to avoid eating the |
- | |
4074 | next token. XXX: find better solution */ |
- | |
4075 | redo: |
- | |
4076 | if (macro_ptr) { |
- | |
4077 | t = *macro_ptr; |
- | |
4078 | if (t == 0 && can_read_stream) { |
- | |
4079 | /* end of macro stream: we must look at the token |
- | |
4080 | after in the file */ |
- | |
4081 | struct macro_level *ml = *can_read_stream; |
- | |
4082 | macro_ptr = NULL; |
- | |
4083 | if (ml) |
- | |
4084 | { |
- | |
4085 | macro_ptr = ml->p; |
- | |
4086 | ml->p = NULL; |
- | |
4087 | *can_read_stream = ml -> prev; |
- | |
4088 | } |
- | |
4089 | goto redo; |
- | |
4090 | } |
- | |
4091 | } else { |
- | |
4092 | /* XXX: incorrect with comments */ |
- | |
4093 | ch = file->buf_ptr[0]; |
- | |
4094 | while (is_space(ch) || ch == '\n') |
- | |
4095 | cinp(); |
- | |
4096 | t = ch; |
- | |
4097 | } |
- | |
4098 | if (t != '(') /* no macro subst */ |
- | |
4099 | return -1; |
- | |
4100 | - | ||
4101 | /* argument macro */ |
- | |
4102 | next_nomacro(); |
- | |
4103 | next_nomacro(); |
- | |
4104 | args = NULL; |
- | |
4105 | sa = s->next; |
- | |
4106 | /* NOTE: empty args are allowed, except if no args */ |
- | |
4107 | for(;;) { |
- | |
4108 | /* handle '()' case */ |
- | |
4109 | if (!args && !sa && tok == ')') |
- | |
4110 | break; |
- | |
4111 | if (!sa) |
- | |
4112 | error("macro '%s' used with too many args", |
- | |
4113 | get_tok_str(s->v, 0)); |
- | |
4114 | tok_str_new(&str); |
- | |
4115 | parlevel = 0; |
- | |
4116 | /* NOTE: non zero sa->t indicates VA_ARGS */ |
- | |
4117 | while ((parlevel > 0 || |
- | |
4118 | (tok != ')' && |
- | |
4119 | (tok != ',' || sa->type.t))) && |
- | |
4120 | tok != -1) { |
- | |
4121 | if (tok == '(') |
- | |
4122 | parlevel++; |
- | |
4123 | else if (tok == ')') |
- | |
4124 | parlevel--; |
- | |
4125 | tok_str_add2(&str, tok, &tokc); |
- | |
4126 | next_nomacro(); |
- | |
4127 | } |
- | |
4128 | tok_str_add(&str, 0); |
- | |
4129 | sym_push2(&args, sa->v & ~SYM_FIELD, sa->type.t, (int)str.str); |
- | |
4130 | sa = sa->next; |
- | |
4131 | if (tok == ')') { |
- | |
4132 | /* special case for gcc var args: add an empty |
- | |
4133 | var arg argument if it is omitted */ |
- | |
4134 | if (sa && sa->type.t && gnu_ext) |
- | |
4135 | continue; |
- | |
4136 | else |
- | |
4137 | break; |
- | |
4138 | } |
- | |
4139 | if (tok != ',') |
- | |
4140 | expect(","); |
- | |
4141 | next_nomacro(); |
- | |
4142 | } |
- | |
4143 | if (sa) { |
- | |
4144 | error("macro '%s' used with too few args", |
- | |
4145 | get_tok_str(s->v, 0)); |
- | |
4146 | } |
- | |
4147 | - | ||
4148 | /* now subst each arg */ |
- | |
4149 | mstr = macro_arg_subst(nested_list, mstr, args); |
- | |
4150 | /* free memory */ |
- | |
4151 | sa = args; |
- | |
4152 | while (sa) { |
- | |
4153 | sa1 = sa->prev; |
- | |
4154 | tok_str_free((int *)sa->c); |
- | |
4155 | sym_free(sa); |
- | |
4156 | sa = sa1; |
- | |
4157 | } |
- | |
4158 | mstr_allocated = 1; |
- | |
4159 | } |
- | |
4160 | sym_push2(nested_list, s->v, 0, 0); |
- | |
4161 | macro_subst(tok_str, nested_list, mstr, can_read_stream); |
- | |
4162 | /* pop nested defined symbol */ |
- | |
4163 | sa1 = *nested_list; |
- | |
4164 | *nested_list = sa1->prev; |
- | |
4165 | sym_free(sa1); |
- | |
4166 | if (mstr_allocated) |
- | |
4167 | tok_str_free(mstr); |
- | |
4168 | } |
- | |
4169 | return 0; |
- | |
4170 | } |
- | |
4171 | - | ||
4172 | /* handle the '##' operator. Return NULL if no '##' seen. Otherwise |
- | |
4173 | return the resulting string (which must be freed). */ |
- | |
4174 | static inline int *macro_twosharps(const int *macro_str) |
- | |
4175 | { |
- | |
4176 | TokenSym *ts; |
- | |
4177 | const int *macro_ptr1, *start_macro_ptr, *ptr, *saved_macro_ptr; |
- | |
4178 | int t; |
- | |
4179 | const char *p1, *p2; |
- | |
4180 | CValue cval; |
- | |
4181 | TokenString macro_str1; |
- | |
4182 | CString cstr; |
- | |
4183 | - | ||
4184 | start_macro_ptr = macro_str; |
- | |
4185 | /* we search the first '##' */ |
- | |
4186 | for(;;) { |
- | |
4187 | macro_ptr1 = macro_str; |
- | |
4188 | TOK_GET(t, macro_str, cval); |
- | |
4189 | /* nothing more to do if end of string */ |
- | |
4190 | if (t == 0) |
- | |
4191 | return NULL; |
- | |
4192 | if (*macro_str == TOK_TWOSHARPS) |
- | |
4193 | break; |
- | |
4194 | } |
- | |
4195 | - | ||
4196 | /* we saw '##', so we need more processing to handle it */ |
- | |
4197 | cstr_new(&cstr); |
- | |
4198 | tok_str_new(¯o_str1); |
- | |
4199 | tok = t; |
- | |
4200 | tokc = cval; |
- | |
4201 | - | ||
4202 | /* add all tokens seen so far */ |
- | |
4203 | for(ptr = start_macro_ptr; ptr < macro_ptr1;) { |
- | |
4204 | TOK_GET(t, ptr, cval); |
- | |
4205 | tok_str_add2(¯o_str1, t, &cval); |
- | |
4206 | } |
- | |
4207 | saved_macro_ptr = macro_ptr; |
- | |
4208 | /* XXX: get rid of the use of macro_ptr here */ |
- | |
4209 | macro_ptr = (int *)macro_str; |
- | |
4210 | for(;;) { |
- | |
4211 | while (*macro_ptr == TOK_TWOSHARPS) { |
- | |
4212 | macro_ptr++; |
- | |
4213 | macro_ptr1 = macro_ptr; |
- | |
4214 | t = *macro_ptr; |
- | |
4215 | if (t) { |
- | |
4216 | TOK_GET(t, macro_ptr, cval); |
- | |
4217 | /* We concatenate the two tokens if we have an |
- | |
4218 | identifier or a preprocessing number */ |
- | |
4219 | cstr_reset(&cstr); |
- | |
4220 | p1 = get_tok_str(tok, &tokc); |
- | |
4221 | cstr_cat(&cstr, p1); |
- | |
4222 | p2 = get_tok_str(t, &cval); |
- | |
4223 | cstr_cat(&cstr, p2); |
- | |
4224 | cstr_ccat(&cstr, '\0'); |
- | |
4225 | - | ||
4226 | if ((tok >= TOK_IDENT || tok == TOK_PPNUM) && |
- | |
4227 | (t >= TOK_IDENT || t == TOK_PPNUM)) { |
- | |
4228 | if (tok == TOK_PPNUM) { |
- | |
4229 | /* if number, then create a number token */ |
- | |
4230 | /* NOTE: no need to allocate because |
- | |
4231 | tok_str_add2() does it */ |
- | |
4232 | tokc.cstr = &cstr; |
- | |
4233 | } else { |
- | |
4234 | /* if identifier, we must do a test to |
- | |
4235 | validate we have a correct identifier */ |
- | |
4236 | if (t == TOK_PPNUM) { |
- | |
4237 | const char *p; |
- | |
4238 | int c; |
- | |
4239 | - | ||
4240 | p = p2; |
- | |
4241 | for(;;) { |
- | |
4242 | c = *p; |
- | |
4243 | if (c == '\0') |
- | |
4244 | break; |
- | |
4245 | p++; |
- | |
4246 | if (!isnum(c) && !isid(c)) |
- | |
4247 | goto error_pasting; |
- | |
4248 | } |
- | |
4249 | } |
- | |
4250 | ts = tok_alloc(cstr.data, strlen(cstr.data)); |
- | |
4251 | tok = ts->tok; /* modify current token */ |
- | |
4252 | } |
- | |
4253 | } else { |
- | |
4254 | const char *str = cstr.data; |
- | |
4255 | const unsigned char *q; |
- | |
4256 | - | ||
4257 | /* we look for a valid token */ |
- | |
4258 | /* XXX: do more extensive checks */ |
- | |
4259 | if (!strcmp(str, ">>=")) { |
- | |
4260 | tok = TOK_A_SAR; |
- | |
4261 | } else if (!strcmp(str, "<<=")) { |
- | |
4262 | tok = TOK_A_SHL; |
- | |
4263 | } else if (strlen(str) == 2) { |
- | |
4264 | /* search in two bytes table */ |
- | |
4265 | q = tok_two_chars; |
- | |
4266 | for(;;) { |
- | |
4267 | if (!*q) |
- | |
4268 | goto error_pasting; |
- | |
4269 | if (q[0] == str[0] && q[1] == str[1]) |
- | |
4270 | break; |
- | |
4271 | q += 3; |
- | |
4272 | } |
- | |
4273 | tok = q[2]; |
- | |
4274 | } else { |
- | |
4275 | error_pasting: |
- | |
4276 | /* NOTE: because get_tok_str use a static buffer, |
- | |
4277 | we must save it */ |
- | |
4278 | cstr_reset(&cstr); |
- | |
4279 | p1 = get_tok_str(tok, &tokc); |
- | |
4280 | cstr_cat(&cstr, p1); |
- | |
4281 | cstr_ccat(&cstr, '\0'); |
- | |
4282 | p2 = get_tok_str(t, &cval); |
- | |
4283 | warning("pasting \"%s\" and \"%s\" does not give a valid preprocessing token", cstr.data, p2); |
- | |
4284 | /* cannot merge tokens: just add them separately */ |
- | |
4285 | tok_str_add2(¯o_str1, tok, &tokc); |
- | |
4286 | /* XXX: free associated memory ? */ |
- | |
4287 | tok = t; |
- | |
4288 | tokc = cval; |
- | |
4289 | } |
- | |
4290 | } |
- | |
4291 | } |
- | |
4292 | } |
- | |
4293 | tok_str_add2(¯o_str1, tok, &tokc); |
- | |
4294 | next_nomacro(); |
- | |
4295 | if (tok == 0) |
- | |
4296 | break; |
- | |
4297 | } |
- | |
4298 | macro_ptr = (int *)saved_macro_ptr; |
- | |
4299 | cstr_free(&cstr); |
- | |
4300 | tok_str_add(¯o_str1, 0); |
- | |
4301 | return macro_str1.str; |
- | |
4302 | } |
- | |
4303 | - | ||
4304 | - | ||
4305 | /* do macro substitution of macro_str and add result to |
- | |
4306 | (tok_str,tok_len). 'nested_list' is the list of all macros we got |
- | |
4307 | inside to avoid recursing. */ |
- | |
4308 | static void macro_subst(TokenString *tok_str, Sym **nested_list, |
- | |
4309 | const int *macro_str, struct macro_level ** can_read_stream) |
- | |
4310 | { |
- | |
4311 | Sym *s; |
- | |
4312 | int *macro_str1; |
- | |
4313 | const int *ptr; |
- | |
4314 | int t, ret; |
- | |
4315 | CValue cval; |
- | |
4316 | struct macro_level ml; |
- | |
4317 | - | ||
4318 | /* first scan for '##' operator handling */ |
- | |
4319 | ptr = macro_str; |
- | |
4320 | macro_str1 = macro_twosharps(ptr); |
- | |
4321 | if (macro_str1) |
- | |
4322 | ptr = macro_str1; |
- | |
4323 | while (1) { |
- | |
4324 | /* NOTE: ptr == NULL can only happen if tokens are read from |
- | |
4325 | file stream due to a macro function call */ |
- | |
4326 | if (ptr == NULL) |
- | |
4327 | break; |
- | |
4328 | TOK_GET(t, ptr, cval); |
- | |
4329 | if (t == 0) |
- | |
4330 | break; |
- | |
4331 | s = define_find(t); |
- | |
4332 | if (s != NULL) { |
- | |
4333 | /* if nested substitution, do nothing */ |
- | |
4334 | if (sym_find2(*nested_list, t)) |
- | |
4335 | goto no_subst; |
- | |
4336 | ml.p = macro_ptr; |
- | |
4337 | if (can_read_stream) |
- | |
4338 | ml.prev = *can_read_stream, *can_read_stream = &ml; |
- | |
4339 | macro_ptr = (int *)ptr; |
- | |
4340 | tok = t; |
- | |
4341 | ret = macro_subst_tok(tok_str, nested_list, s, can_read_stream); |
- | |
4342 | ptr = (int *)macro_ptr; |
- | |
4343 | macro_ptr = ml.p; |
- | |
4344 | if (can_read_stream && *can_read_stream == &ml) |
- | |
4345 | *can_read_stream = ml.prev; |
- | |
4346 | if (ret != 0) |
- | |
4347 | goto no_subst; |
- | |
4348 | } else { |
- | |
4349 | no_subst: |
- | |
4350 | tok_str_add2(tok_str, t, &cval); |
- | |
4351 | } |
- | |
4352 | } |
- | |
4353 | if (macro_str1) |
- | |
4354 | tok_str_free(macro_str1); |
- | |
4355 | } |
- | |
4356 | - | ||
4357 | /* return next token with macro substitution */ |
- | |
4358 | static void next(void) |
- | |
4359 | { |
- | |
4360 | Sym *nested_list, *s; |
- | |
4361 | TokenString str; |
- | |
4362 | struct macro_level *ml; |
- | |
4363 | - | ||
4364 | redo: |
- | |
4365 | next_nomacro(); |
- | |
4366 | if (!macro_ptr) { |
- | |
4367 | /* if not reading from macro substituted string, then try |
- | |
4368 | to substitute macros */ |
- | |
4369 | if (tok >= TOK_IDENT && |
- | |
4370 | (parse_flags & PARSE_FLAG_PREPROCESS)) { |
- | |
4371 | s = define_find(tok); |
- | |
4372 | if (s) { |
- | |
4373 | /* we have a macro: we try to substitute */ |
- | |
4374 | tok_str_new(&str); |
- | |
4375 | nested_list = NULL; |
- | |
4376 | ml = NULL; |
- | |
4377 | if (macro_subst_tok(&str, &nested_list, s, &ml) == 0) { |
- | |
4378 | /* substitution done, NOTE: maybe empty */ |
- | |
4379 | tok_str_add(&str, 0); |
- | |
4380 | macro_ptr = str.str; |
- | |
4381 | macro_ptr_allocated = str.str; |
- | |
4382 | goto redo; |
- | |
4383 | } |
- | |
4384 | } |
- | |
4385 | } |
- | |
4386 | } else { |
- | |
4387 | if (tok == 0) { |
- | |
4388 | /* end of macro or end of unget buffer */ |
- | |
4389 | if (unget_buffer_enabled) { |
- | |
4390 | macro_ptr = unget_saved_macro_ptr; |
- | |
4391 | unget_buffer_enabled = 0; |
- | |
4392 | } else { |
- | |
4393 | /* end of macro string: free it */ |
- | |
4394 | tok_str_free(macro_ptr_allocated); |
- | |
4395 | macro_ptr = NULL; |
- | |
4396 | } |
- | |
4397 | goto redo; |
- | |
4398 | } |
- | |
4399 | } |
- | |
4400 | - | ||
4401 | /* convert preprocessor tokens into C tokens */ |
- | |
4402 | if (tok == TOK_PPNUM && |
- | |
4403 | (parse_flags & PARSE_FLAG_TOK_NUM)) { |
- | |
4404 | parse_number((char *)tokc.cstr->data); |
- | |
4405 | } |
- | |
4406 | } |
- | |
4407 | - | ||
4408 | /* push back current token and set current token to 'last_tok'. Only |
- | |
4409 | identifier case handled for labels. */ |
- | |
4410 | static inline void unget_tok(int last_tok) |
- | |
4411 | { |
- | |
4412 | int i, n; |
- | |
4413 | int *q; |
- | |
4414 | unget_saved_macro_ptr = macro_ptr; |
- | |
4415 | unget_buffer_enabled = 1; |
- | |
4416 | q = unget_saved_buffer; |
- | |
4417 | macro_ptr = q; |
- | |
4418 | *q++ = tok; |
- | |
4419 | n = tok_ext_size(tok) - 1; |
- | |
4420 | for(i=0;i |
- | |
4421 | *q++ = tokc.tab[i]; |
- | |
4422 | *q = 0; /* end of token string */ |
- | |
4423 | tok = last_tok; |
- | |
4424 | } |
- | |
4425 | - | ||
4426 | - | ||
4427 | void swap(int *p, int *q) |
- | |
4428 | { |
- | |
4429 | int t; |
- | |
4430 | t = *p; |
- | |
4431 | *p = *q; |
- | |
4432 | *q = t; |
- | |
4433 | } |
- | |
4434 | - | ||
4435 | void vsetc(CType *type, int r, CValue *vc) |
- | |
4436 | { |
- | |
4437 | int v; |
- | |
4438 | - | ||
4439 | if (vtop >= vstack + (VSTACK_SIZE - 1)) |
- | |
4440 | error("memory full"); |
- | |
4441 | /* cannot let cpu flags if other instruction are generated. Also |
- | |
4442 | avoid leaving VT_JMP anywhere except on the top of the stack |
- | |
4443 | because it would complicate the code generator. */ |
- | |
4444 | if (vtop >= vstack) { |
- | |
4445 | v = vtop->r & VT_VALMASK; |
- | |
4446 | if (v == VT_CMP || (v & ~1) == VT_JMP) |
- | |
4447 | gv(RC_INT); |
- | |
4448 | } |
- | |
4449 | vtop++; |
- | |
4450 | vtop->type = *type; |
- | |
4451 | vtop->r = r; |
- | |
4452 | vtop->r2 = VT_CONST; |
- | |
4453 | vtop->c = *vc; |
- | |
4454 | } |
- | |
4455 | - | ||
4456 | /* push integer constant */ |
- | |
4457 | void vpushi(int v) |
- | |
4458 | { |
- | |
4459 | CValue cval; |
- | |
4460 | cval.i = v; |
- | |
4461 | vsetc(&int_type, VT_CONST, &cval); |
- | |
4462 | } |
- | |
4463 | - | ||
4464 | /* Return a static symbol pointing to a section */ |
- | |
4465 | static Sym *get_sym_ref(CType *type, Section *sec, |
- | |
4466 | unsigned long offset, unsigned long size) |
- | |
4467 | { |
- | |
4468 | int v; |
- | |
4469 | Sym *sym; |
- | |
4470 | - | ||
4471 | v = anon_sym++; |
- | |
4472 | sym = global_identifier_push(v, type->t | VT_STATIC, 0); |
- | |
4473 | sym->type.ref = type->ref; |
- | |
4474 | sym->r = VT_CONST | VT_SYM; |
- | |
4475 | put_extern_sym(sym, sec, offset, size); |
- | |
4476 | return sym; |
- | |
4477 | } |
- | |
4478 | - | ||
4479 | /* push a reference to a section offset by adding a dummy symbol */ |
- | |
4480 | static void vpush_ref(CType *type, Section *sec, unsigned long offset, unsigned long size) |
- | |
4481 | { |
- | |
4482 | CValue cval; |
- | |
4483 | - | ||
4484 | cval.ul = 0; |
- | |
4485 | vsetc(type, VT_CONST | VT_SYM, &cval); |
- | |
4486 | vtop->sym = get_sym_ref(type, sec, offset, size); |
- | |
4487 | } |
- | |
4488 | - | ||
4489 | /* define a new external reference to a symbol 'v' of type 'u' */ |
- | |
4490 | static Sym *external_global_sym(int v, CType *type, int r) |
- | |
4491 | { |
- | |
4492 | Sym *s; |
- | |
4493 | - | ||
4494 | s = sym_find(v); |
- | |
4495 | if (!s) { |
- | |
4496 | /* push forward reference */ |
- | |
4497 | s = global_identifier_push(v, type->t | VT_EXTERN, 0); |
- | |
4498 | s->type.ref = type->ref; |
- | |
4499 | s->r = r | VT_CONST | VT_SYM; |
- | |
4500 | } |
- | |
4501 | return s; |
- | |
4502 | } |
- | |
4503 | - | ||
4504 | /* define a new external reference to a symbol 'v' of type 'u' */ |
- | |
4505 | static Sym *external_sym(int v, CType *type, int r) |
- | |
4506 | { |
- | |
4507 | Sym *s; |
- | |
4508 | - | ||
4509 | s = sym_find(v); |
- | |
4510 | if (!s) { |
- | |
4511 | /* push forward reference */ |
- | |
4512 | s = sym_push(v, type, r | VT_CONST | VT_SYM, 0); |
- | |
4513 | s->type.t |= VT_EXTERN; |
- | |
4514 | } else { |
- | |
4515 | if (!is_compatible_types(&s->type, type)) |
- | |
4516 | error("incompatible types for redefinition of '%s'", |
- | |
4517 | get_tok_str(v, NULL)); |
- | |
4518 | } |
- | |
4519 | return s; |
- | |
4520 | } |
- | |
4521 | - | ||
4522 | /* push a reference to global symbol v */ |
- | |
4523 | static void vpush_global_sym(CType *type, int v) |
- | |
4524 | { |
- | |
4525 | Sym *sym; |
- | |
4526 | CValue cval; |
- | |
4527 | - | ||
4528 | sym = external_global_sym(v, type, 0); |
- | |
4529 | cval.ul = 0; |
- | |
4530 | vsetc(type, VT_CONST | VT_SYM, &cval); |
- | |
4531 | vtop->sym = sym; |
- | |
4532 | } |
- | |
4533 | - | ||
4534 | void vset(CType *type, int r, int v) |
- | |
4535 | { |
- | |
4536 | CValue cval; |
- | |
4537 | - | ||
4538 | cval.i = v; |
- | |
4539 | vsetc(type, r, &cval); |
- | |
4540 | } |
- | |
4541 | - | ||
4542 | void vseti(int r, int v) |
- | |
4543 | { |
- | |
4544 | CType type; |
- | |
4545 | type.t = VT_INT; |
- | |
4546 | vset(&type, r, v); |
- | |
4547 | } |
- | |
4548 | - | ||
4549 | void vswap(void) |
- | |
4550 | { |
- | |
4551 | SValue tmp; |
- | |
4552 | - | ||
4553 | tmp = vtop[0]; |
- | |
4554 | vtop[0] = vtop[-1]; |
- | |
4555 | vtop[-1] = tmp; |
- | |
4556 | } |
- | |
4557 | - | ||
4558 | void vpushv(SValue *v) |
- | |
4559 | { |
- | |
4560 | if (vtop >= vstack + (VSTACK_SIZE - 1)) |
- | |
4561 | error("memory full"); |
- | |
4562 | vtop++; |
- | |
4563 | *vtop = *v; |
- | |
4564 | } |
- | |
4565 | - | ||
4566 | void vdup(void) |
- | |
4567 | { |
- | |
4568 | vpushv(vtop); |
- | |
4569 | } |
- | |
4570 | - | ||
4571 | /* save r to the memory stack, and mark it as being free */ |
- | |
4572 | void save_reg(int r) |
- | |
4573 | { |
- | |
4574 | int l, saved, size, align; |
- | |
4575 | SValue *p, sv; |
- | |
4576 | CType *type; |
- | |
4577 | - | ||
4578 | /* modify all stack values */ |
- | |
4579 | saved = 0; |
- | |
4580 | l = 0; |
- | |
4581 | for(p=vstack;p<=vtop;p++) { |
- | |
4582 | if ((p->r & VT_VALMASK) == r || |
- | |
4583 | (p->r2 & VT_VALMASK) == r) { |
- | |
4584 | /* must save value on stack if not already done */ |
- | |
4585 | if (!saved) { |
- | |
4586 | /* NOTE: must reload 'r' because r might be equal to r2 */ |
- | |
4587 | r = p->r & VT_VALMASK; |
- | |
4588 | /* store register in the stack */ |
- | |
4589 | type = &p->type; |
- | |
4590 | if ((p->r & VT_LVAL) || |
- | |
4591 | (!is_float(type->t) && (type->t & VT_BTYPE) != VT_LLONG)) |
- | |
4592 | type = &int_type; |
- | |
4593 | size = type_size(type, &align); |
- | |
4594 | loc = (loc - size) & -align; |
- | |
4595 | sv.type.t = type->t; |
- | |
4596 | sv.r = VT_LOCAL | VT_LVAL; |
- | |
4597 | sv.c.ul = loc; |
- | |
4598 | store(r, &sv); |
- | |
4599 | #ifdef TCC_TARGET_I386 |
- | |
4600 | /* x86 specific: need to pop fp register ST0 if saved */ |
- | |
4601 | if (r == TREG_ST0) { |
- | |
4602 | o(0xd9dd); /* fstp %st(1) */ |
- | |
4603 | } |
- | |
4604 | #endif |
- | |
4605 | /* special long long case */ |
- | |
4606 | if ((type->t & VT_BTYPE) == VT_LLONG) { |
- | |
4607 | sv.c.ul += 4; |
- | |
4608 | store(p->r2, &sv); |
- | |
4609 | } |
- | |
4610 | l = loc; |
- | |
4611 | saved = 1; |
- | |
4612 | } |
- | |
4613 | /* mark that stack entry as being saved on the stack */ |
- | |
4614 | if (p->r & VT_LVAL) { |
- | |
4615 | /* also clear the bounded flag because the |
- | |
4616 | relocation address of the function was stored in |
- | |
4617 | p->c.ul */ |
- | |
4618 | p->r = (p->r & ~(VT_VALMASK | VT_BOUNDED)) | VT_LLOCAL; |
- | |
4619 | } else { |
- | |
4620 | p->r = lvalue_type(p->type.t) | VT_LOCAL; |
- | |
4621 | } |
- | |
4622 | p->r2 = VT_CONST; |
- | |
4623 | p->c.ul = l; |
- | |
4624 | } |
- | |
4625 | } |
- | |
4626 | } |
- | |
4627 | - | ||
4628 | /* find a register of class 'rc2' with at most one reference on stack. |
- | |
4629 | * If none, call get_reg(rc) */ |
- | |
4630 | int get_reg_ex(int rc, int rc2) |
- | |
4631 | { |
- | |
4632 | int r; |
- | |
4633 | SValue *p; |
- | |
4634 | - | ||
4635 | for(r=0;r |
- | |
4636 | if (reg_classes[r] & rc2) { |
- | |
4637 | int n; |
- | |
4638 | n=0; |
- | |
4639 | for(p = vstack; p <= vtop; p++) { |
- | |
4640 | if ((p->r & VT_VALMASK) == r || |
- | |
4641 | (p->r2 & VT_VALMASK) == r) |
- | |
4642 | n++; |
- | |
4643 | } |
- | |
4644 | if (n <= 1) |
- | |
4645 | return r; |
- | |
4646 | } |
- | |
4647 | } |
- | |
4648 | return get_reg(rc); |
- | |
4649 | } |
- | |
4650 | - | ||
4651 | /* find a free register of class 'rc'. If none, save one register */ |
- | |
4652 | int get_reg(int rc) |
- | |
4653 | { |
- | |
4654 | int r; |
- | |
4655 | SValue *p; |
- | |
4656 | - | ||
4657 | /* find a free register */ |
- | |
4658 | for(r=0;r |
- | |
4659 | if (reg_classes[r] & rc) { |
- | |
4660 | for(p=vstack;p<=vtop;p++) { |
- | |
4661 | if ((p->r & VT_VALMASK) == r || |
- | |
4662 | (p->r2 & VT_VALMASK) == r) |
- | |
4663 | goto notfound; |
- | |
4664 | } |
- | |
4665 | return r; |
- | |
4666 | } |
- | |
4667 | notfound: ; |
- | |
4668 | } |
- | |
4669 | - | ||
4670 | /* no register left : free the first one on the stack (VERY |
- | |
4671 | IMPORTANT to start from the bottom to ensure that we don't |
- | |
4672 | spill registers used in gen_opi()) */ |
- | |
4673 | for(p=vstack;p<=vtop;p++) { |
- | |
4674 | r = p->r & VT_VALMASK; |
- | |
4675 | if (r < VT_CONST && (reg_classes[r] & rc)) |
- | |
4676 | goto save_found; |
- | |
4677 | /* also look at second register (if long long) */ |
- | |
4678 | r = p->r2 & VT_VALMASK; |
- | |
4679 | if (r < VT_CONST && (reg_classes[r] & rc)) { |
- | |
4680 | save_found: |
- | |
4681 | save_reg(r); |
- | |
4682 | return r; |
- | |
4683 | } |
- | |
4684 | } |
- | |
4685 | /* Should never comes here */ |
- | |
4686 | return -1; |
- | |
4687 | } |
- | |
4688 | - | ||
4689 | /* save registers up to (vtop - n) stack entry */ |
- | |
4690 | void save_regs(int n) |
- | |
4691 | { |
- | |
4692 | int r; |
- | |
4693 | SValue *p, *p1; |
- | |
4694 | p1 = vtop - n; |
- | |
4695 | for(p = vstack;p <= p1; p++) { |
- | |
4696 | r = p->r & VT_VALMASK; |
- | |
4697 | if (r < VT_CONST) { |
- | |
4698 | save_reg(r); |
- | |
4699 | } |
- | |
4700 | } |
- | |
4701 | } |
- | |
4702 | - | ||
4703 | /* move register 's' to 'r', and flush previous value of r to memory |
- | |
4704 | if needed */ |
- | |
4705 | void move_reg(int r, int s) |
- | |
4706 | { |
- | |
4707 | SValue sv; |
- | |
4708 | - | ||
4709 | if (r != s) { |
- | |
4710 | save_reg(r); |
- | |
4711 | sv.type.t = VT_INT; |
- | |
4712 | sv.r = s; |
- | |
4713 | sv.c.ul = 0; |
- | |
4714 | load(r, &sv); |
- | |
4715 | } |
- | |
4716 | } |
- | |
4717 | - | ||
4718 | /* get address of vtop (vtop MUST BE an lvalue) */ |
- | |
4719 | void gaddrof(void) |
- | |
4720 | { |
- | |
4721 | vtop->r &= ~VT_LVAL; |
- | |
4722 | /* tricky: if saved lvalue, then we can go back to lvalue */ |
- | |
4723 | if ((vtop->r & VT_VALMASK) == VT_LLOCAL) |
- | |
4724 | vtop->r = (vtop->r & ~(VT_VALMASK | VT_LVAL_TYPE)) | VT_LOCAL | VT_LVAL; |
- | |
4725 | } |
- | |
4726 | - | ||
4727 | #ifdef CONFIG_TCC_BCHECK |
- | |
4728 | /* generate lvalue bound code */ |
- | |
4729 | void gbound(void) |
- | |
4730 | { |
- | |
4731 | int lval_type; |
- | |
4732 | CType type1; |
- | |
4733 | - | ||
4734 | vtop->r &= ~VT_MUSTBOUND; |
- | |
4735 | /* if lvalue, then use checking code before dereferencing */ |
- | |
4736 | if (vtop->r & VT_LVAL) { |
- | |
4737 | /* if not VT_BOUNDED value, then make one */ |
- | |
4738 | if (!(vtop->r & VT_BOUNDED)) { |
- | |
4739 | lval_type = vtop->r & (VT_LVAL_TYPE | VT_LVAL); |
- | |
4740 | /* must save type because we must set it to int to get pointer */ |
- | |
4741 | type1 = vtop->type; |
- | |
4742 | vtop->type.t = VT_INT; |
- | |
4743 | gaddrof(); |
- | |
4744 | vpushi(0); |
- | |
4745 | gen_bounded_ptr_add(); |
- | |
4746 | vtop->r |= lval_type; |
- | |
4747 | vtop->type = type1; |
- | |
4748 | } |
- | |
4749 | /* then check for dereferencing */ |
- | |
4750 | gen_bounded_ptr_deref(); |
- | |
4751 | } |
- | |
4752 | } |
- | |
4753 | #endif |
- | |
4754 | - | ||
4755 | /* store vtop a register belonging to class 'rc'. lvalues are |
- | |
4756 | converted to values. Cannot be used if cannot be converted to |
- | |
4757 | register value (such as structures). */ |
- | |
4758 | int gv(int rc) |
- | |
4759 | { |
- | |
4760 | int r, r2, rc2, bit_pos, bit_size, size, align, i; |
- | |
4761 | unsigned long long ll; |
- | |
4762 | - | ||
4763 | /* NOTE: get_reg can modify vstack[] */ |
- | |
4764 | if (vtop->type.t & VT_BITFIELD) { |
- | |
4765 | bit_pos = (vtop->type.t >> VT_STRUCT_SHIFT) & 0x3f; |
- | |
4766 | bit_size = (vtop->type.t >> (VT_STRUCT_SHIFT + 6)) & 0x3f; |
- | |
4767 | /* remove bit field info to avoid loops */ |
- | |
4768 | vtop->type.t &= ~(VT_BITFIELD | (-1 << VT_STRUCT_SHIFT)); |
- | |
4769 | /* generate shifts */ |
- | |
4770 | vpushi(32 - (bit_pos + bit_size)); |
- | |
4771 | gen_op(TOK_SHL); |
- | |
4772 | vpushi(32 - bit_size); |
- | |
4773 | /* NOTE: transformed to SHR if unsigned */ |
- | |
4774 | gen_op(TOK_SAR); |
- | |
4775 | r = gv(rc); |
- | |
4776 | } else { |
- | |
4777 | if (is_float(vtop->type.t) && |
- | |
4778 | (vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) { |
- | |
4779 | Sym *sym; |
- | |
4780 | int *ptr; |
- | |
4781 | unsigned long offset; |
- | |
4782 | - | ||
4783 | /* XXX: unify with initializers handling ? */ |
- | |
4784 | /* CPUs usually cannot use float constants, so we store them |
- | |
4785 | generically in data segment */ |
- | |
4786 | size = type_size(&vtop->type, &align); |
- | |
4787 | offset = (data_section->data_offset + align - 1) & -align; |
- | |
4788 | data_section->data_offset = offset; |
- | |
4789 | /* XXX: not portable yet */ |
- | |
4790 | ptr = section_ptr_add(data_section, size); |
- | |
4791 | size = size >> 2; |
- | |
4792 | for(i=0;i |
- | |
4793 | ptr[i] = vtop->c.tab[i]; |
- | |
4794 | sym = get_sym_ref(&vtop->type, data_section, offset, size << 2); |
- | |
4795 | vtop->r |= VT_LVAL | VT_SYM; |
- | |
4796 | vtop->sym = sym; |
- | |
4797 | vtop->c.ul = 0; |
- | |
4798 | } |
- | |
4799 | #ifdef CONFIG_TCC_BCHECK |
- | |
4800 | if (vtop->r & VT_MUSTBOUND) |
- | |
4801 | gbound(); |
- | |
4802 | #endif |
- | |
4803 | - | ||
4804 | r = vtop->r & VT_VALMASK; |
- | |
4805 | /* need to reload if: |
- | |
4806 | - constant |
- | |
4807 | - lvalue (need to dereference pointer) |
- | |
4808 | - already a register, but not in the right class */ |
- | |
4809 | if (r >= VT_CONST || |
- | |
4810 | (vtop->r & VT_LVAL) || |
- | |
4811 | !(reg_classes[r] & rc) || |
- | |
4812 | ((vtop->type.t & VT_BTYPE) == VT_LLONG && |
- | |
4813 | !(reg_classes[vtop->r2] & rc))) { |
- | |
4814 | r = get_reg(rc); |
- | |
4815 | if ((vtop->type.t & VT_BTYPE) == VT_LLONG) { |
- | |
4816 | /* two register type load : expand to two words |
- | |
4817 | temporarily */ |
- | |
4818 | if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) { |
- | |
4819 | /* load constant */ |
- | |
4820 | ll = vtop->c.ull; |
- | |
4821 | vtop->c.ui = ll; /* first word */ |
- | |
4822 | load(r, vtop); |
- | |
4823 | vtop->r = r; /* save register value */ |
- | |
4824 | vpushi(ll >> 32); /* second word */ |
- | |
4825 | } else if (r >= VT_CONST || /* XXX: test to VT_CONST incorrect ? */ |
- | |
4826 | (vtop->r & VT_LVAL)) { |
- | |
4827 | /* We do not want to modifier the long long |
- | |
4828 | pointer here, so the safest (and less |
- | |
4829 | efficient) is to save all the other registers |
- | |
4830 | in the stack. XXX: totally inefficient. */ |
- | |
4831 | save_regs(1); |
- | |
4832 | /* load from memory */ |
- | |
4833 | load(r, vtop); |
- | |
4834 | vdup(); |
- | |
4835 | vtop[-1].r = r; /* save register value */ |
- | |
4836 | /* increment pointer to get second word */ |
- | |
4837 | vtop->type.t = VT_INT; |
- | |
4838 | gaddrof(); |
- | |
4839 | vpushi(4); |
- | |
4840 | gen_op('+'); |
- | |
4841 | vtop->r |= VT_LVAL; |
- | |
4842 | } else { |
- | |
4843 | /* move registers */ |
- | |
4844 | load(r, vtop); |
- | |
4845 | vdup(); |
- | |
4846 | vtop[-1].r = r; /* save register value */ |
- | |
4847 | vtop->r = vtop[-1].r2; |
- | |
4848 | } |
- | |
4849 | /* allocate second register */ |
- | |
4850 | rc2 = RC_INT; |
- | |
4851 | if (rc == RC_IRET) |
- | |
4852 | rc2 = RC_LRET; |
- | |
4853 | r2 = get_reg(rc2); |
- | |
4854 | load(r2, vtop); |
- | |
4855 | vpop(); |
- | |
4856 | /* write second register */ |
- | |
4857 | vtop->r2 = r2; |
- | |
4858 | } else if ((vtop->r & VT_LVAL) && !is_float(vtop->type.t)) { |
- | |
4859 | int t1, t; |
- | |
4860 | /* lvalue of scalar type : need to use lvalue type |
- | |
4861 | because of possible cast */ |
- | |
4862 | t = vtop->type.t; |
- | |
4863 | t1 = t; |
- | |
4864 | /* compute memory access type */ |
- | |
4865 | if (vtop->r & VT_LVAL_BYTE) |
- | |
4866 | t = VT_BYTE; |
- | |
4867 | else if (vtop->r & VT_LVAL_SHORT) |
- | |
4868 | t = VT_SHORT; |
- | |
4869 | if (vtop->r & VT_LVAL_UNSIGNED) |
- | |
4870 | t |= VT_UNSIGNED; |
- | |
4871 | vtop->type.t = t; |
- | |
4872 | load(r, vtop); |
- | |
4873 | /* restore wanted type */ |
- | |
4874 | vtop->type.t = t1; |
- | |
4875 | } else { |
- | |
4876 | /* one register type load */ |
- | |
4877 | load(r, vtop); |
- | |
4878 | } |
- | |
4879 | } |
- | |
4880 | vtop->r = r; |
- | |
4881 | #ifdef TCC_TARGET_C67 |
- | |
4882 | /* uses register pairs for doubles */ |
- | |
4883 | if ((vtop->type.t & VT_BTYPE) == VT_DOUBLE) |
- | |
4884 | vtop->r2 = r+1; |
- | |
4885 | #endif |
- | |
4886 | } |
- | |
4887 | return r; |
- | |
4888 | } |
- | |
4889 | - | ||
4890 | /* generate vtop[-1] and vtop[0] in resp. classes rc1 and rc2 */ |
- | |
4891 | void gv2(int rc1, int rc2) |
- | |
4892 | { |
- | |
4893 | int v; |
- | |
4894 | - | ||
4895 | /* generate more generic register first. But VT_JMP or VT_CMP |
- | |
4896 | values must be generated first in all cases to avoid possible |
- | |
4897 | reload errors */ |
- | |
4898 | v = vtop[0].r & VT_VALMASK; |
- | |
4899 | if (v != VT_CMP && (v & ~1) != VT_JMP && rc1 <= rc2) { |
- | |
4900 | vswap(); |
- | |
4901 | gv(rc1); |
- | |
4902 | vswap(); |
- | |
4903 | gv(rc2); |
- | |
4904 | /* test if reload is needed for first register */ |
- | |
4905 | if ((vtop[-1].r & VT_VALMASK) >= VT_CONST) { |
- | |
4906 | vswap(); |
- | |
4907 | gv(rc1); |
- | |
4908 | vswap(); |
- | |
4909 | } |
- | |
4910 | } else { |
- | |
4911 | gv(rc2); |
- | |
4912 | vswap(); |
- | |
4913 | gv(rc1); |
- | |
4914 | vswap(); |
- | |
4915 | /* test if reload is needed for first register */ |
- | |
4916 | if ((vtop[0].r & VT_VALMASK) >= VT_CONST) { |
- | |
4917 | gv(rc2); |
- | |
4918 | } |
- | |
4919 | } |
- | |
4920 | } |
- | |
4921 | - | ||
4922 | /* expand long long on stack in two int registers */ |
- | |
4923 | void lexpand(void) |
- | |
4924 | { |
- | |
4925 | int u; |
- | |
4926 | - | ||
4927 | u = vtop->type.t & VT_UNSIGNED; |
- | |
4928 | gv(RC_INT); |
- | |
4929 | vdup(); |
- | |
4930 | vtop[0].r = vtop[-1].r2; |
- | |
4931 | vtop[0].r2 = VT_CONST; |
- | |
4932 | vtop[-1].r2 = VT_CONST; |
- | |
4933 | vtop[0].type.t = VT_INT | u; |
- | |
4934 | vtop[-1].type.t = VT_INT | u; |
- | |
4935 | } |
- | |
4936 | - | ||
4937 | #ifdef TCC_TARGET_ARM |
- | |
4938 | /* expand long long on stack */ |
- | |
4939 | void lexpand_nr(void) |
- | |
4940 | { |
- | |
4941 | int u,v; |
- | |
4942 | - | ||
4943 | u = vtop->type.t & VT_UNSIGNED; |
- | |
4944 | vdup(); |
- | |
4945 | vtop->r2 = VT_CONST; |
- | |
4946 | vtop->type.t = VT_INT | u; |
- | |
4947 | v=vtop[-1].r & (VT_VALMASK | VT_LVAL); |
- | |
4948 | if (v == VT_CONST) { |
- | |
4949 | vtop[-1].c.ui = vtop->c.ull; |
- | |
4950 | vtop->c.ui = vtop->c.ull >> 32; |
- | |
4951 | vtop->r = VT_CONST; |
- | |
4952 | } else if (v == (VT_LVAL|VT_CONST) || v == (VT_LVAL|VT_LOCAL)) { |
- | |
4953 | vtop->c.ui += 4; |
- | |
4954 | vtop->r = vtop[-1].r; |
- | |
4955 | } else if (v > VT_CONST) { |
- | |
4956 | vtop--; |
- | |
4957 | lexpand(); |
- | |
4958 | } else |
- | |
4959 | vtop->r = vtop[-1].r2; |
- | |
4960 | vtop[-1].r2 = VT_CONST; |
- | |
4961 | vtop[-1].type.t = VT_INT | u; |
- | |
4962 | } |
- | |
4963 | #endif |
- | |
4964 | - | ||
4965 | /* build a long long from two ints */ |
- | |
4966 | void lbuild(int t) |
- | |
4967 | { |
- | |
4968 | gv2(RC_INT, RC_INT); |
- | |
4969 | vtop[-1].r2 = vtop[0].r; |
- | |
4970 | vtop[-1].type.t = t; |
- | |
4971 | vpop(); |
- | |
4972 | } |
- | |
4973 | - | ||
4974 | /* rotate n first stack elements to the bottom |
- | |
4975 | I1 ... In -> I2 ... In I1 [top is right] |
- | |
4976 | */ |
- | |
4977 | void vrotb(int n) |
- | |
4978 | { |
- | |
4979 | int i; |
- | |
4980 | SValue tmp; |
- | |
4981 | - | ||
4982 | tmp = vtop[-n + 1]; |
- | |
4983 | for(i=-n+1;i!=0;i++) |
- | |
4984 | vtop[i] = vtop[i+1]; |
- | |
4985 | vtop[0] = tmp; |
- | |
4986 | } |
- | |
4987 | - | ||
4988 | /* rotate n first stack elements to the top |
- | |
4989 | I1 ... In -> In I1 ... I(n-1) [top is right] |
- | |
4990 | */ |
- | |
4991 | void vrott(int n) |
- | |
4992 | { |
- | |
4993 | int i; |
- | |
4994 | SValue tmp; |
- | |
4995 | - | ||
4996 | tmp = vtop[0]; |
- | |
4997 | for(i = 0;i < n - 1; i++) |
- | |
4998 | vtop[-i] = vtop[-i - 1]; |
- | |
4999 | vtop[-n + 1] = tmp; |
- | |
5000 | } |
- | |
5001 | - | ||
5002 | #ifdef TCC_TARGET_ARM |
- | |
5003 | /* like vrott but in other direction |
- | |
5004 | In ... I1 -> I(n-1) ... I1 In [top is right] |
- | |
5005 | */ |
- | |
5006 | void vnrott(int n) |
- | |
5007 | { |
- | |
5008 | int i; |
- | |
5009 | SValue tmp; |
- | |
5010 | - | ||
5011 | tmp = vtop[-n + 1]; |
- | |
5012 | for(i = n - 1; i > 0; i--) |
- | |
5013 | vtop[-i] = vtop[-i + 1]; |
- | |
5014 | vtop[0] = tmp; |
- | |
5015 | } |
- | |
5016 | #endif |
- | |
5017 | - | ||
5018 | /* pop stack value */ |
- | |
5019 | void vpop(void) |
- | |
5020 | { |
37 | switch (what) { |
- | 38 | case 0: |
|
5021 | int v; |
39 | printf("tcc version %s (" |
- | 40 | #ifdef TCC_TARGET_I386 |
|
5022 | v = vtop->r & VT_VALMASK; |
41 | "i386" |
- | 42 | #elif defined TCC_TARGET_X86_64 |
|
5023 | #ifdef TCC_TARGET_I386 |
43 | "x86-64" |
5024 | /* for x86, we need to pop the FP stack */ |
44 | #elif defined TCC_TARGET_C67 |
- | 45 | "C67" |
|
- | 46 | #elif defined TCC_TARGET_ARM |
|
- | 47 | "ARM" |
|
- | 48 | # ifdef TCC_ARM_HARDFLOAT |
|
- | 49 | " Hard Float" |
|
- | 50 | # endif |
|
- | 51 | #elif defined TCC_TARGET_ARM64 |
|
5025 | if (v == TREG_ST0 && !nocode_wanted) { |
52 | "AArch64" |
5026 | o(0xd9dd); /* fstp %st(1) */ |
- | |
5027 | } else |
- | |
5028 | #endif |
- | |
5029 | if (v == VT_JMP || v == VT_JMPI) { |
- | |
5030 | /* need to put correct jump if && or || without test */ |
- | |
5031 | gsym(vtop->c.ul); |
- | |
5032 | } |
- | |
5033 | vtop--; |
- | |
5034 | } |
- | |
5035 | - | ||
5036 | /* convert stack entry to register and duplicate its value in another |
- | |
5037 | register */ |
- | |
5038 | void gv_dup(void) |
- | |
5039 | { |
- | |
5040 | int rc, t, r, r1; |
- | |
5041 | SValue sv; |
- | |
5042 | - | ||
5043 | t = vtop->type.t; |
- | |
5044 | if ((t & VT_BTYPE) == VT_LLONG) { |
- | |
5045 | lexpand(); |
- | |
5046 | gv_dup(); |
- | |
5047 | vswap(); |
- | |
5048 | vrotb(3); |
- | |
5049 | gv_dup(); |
- | |
5050 | vrotb(4); |
- | |
5051 | /* stack: H L L1 H1 */ |
- | |
5052 | lbuild(t); |
- | |
5053 | vrotb(3); |
- | |
5054 | vrotb(3); |
- | |
5055 | vswap(); |
- | |
5056 | lbuild(t); |
- | |
5057 | vswap(); |
- | |
5058 | } else { |
- | |
5059 | /* duplicate value */ |
- | |
5060 | rc = RC_INT; |
- | |
5061 | sv.type.t = VT_INT; |
- | |
5062 | if (is_float(t)) { |
- | |
5063 | rc = RC_FLOAT; |
- | |
5064 | sv.type.t = t; |
- | |
5065 | } |
- | |
5066 | r = gv(rc); |
- | |
5067 | r1 = get_reg(rc); |
- | |
5068 | sv.r = r; |
- | |
5069 | sv.c.ul = 0; |
- | |
5070 | load(r1, &sv); /* move r to r1 */ |
- | |
5071 | vdup(); |
- | |
5072 | /* duplicates value */ |
- | |
5073 | vtop->r = r1; |
- | |
5074 | } |
- | |
5075 | } |
- | |
5076 | - | ||
5077 | /* generate CPU independent (unsigned) long long operations */ |
- | |
5078 | void gen_opl(int op) |
- | |
5079 | { |
- | |
5080 | int t, a, b, op1, c, i; |
- | |
5081 | int func; |
- | |
5082 | SValue tmp; |
- | |
5083 | - | ||
5084 | switch(op) { |
- | |
5085 | case '/': |
- | |
5086 | case TOK_PDIV: |
- | |
5087 | func = TOK___divdi3; |
- | |
5088 | goto gen_func; |
- | |
5089 | case TOK_UDIV: |
- | |
5090 | func = TOK___udivdi3; |
- | |
5091 | goto gen_func; |
- | |
5092 | case '%': |
- | |
5093 | func = TOK___moddi3; |
- | |
5094 | goto gen_func; |
- | |
5095 | case TOK_UMOD: |
- | |
5096 | func = TOK___umoddi3; |
- | |
5097 | gen_func: |
- | |
5098 | /* call generic long long function */ |
- | |
5099 | vpush_global_sym(&func_old_type, func); |
- | |
5100 | vrott(3); |
- | |
5101 | gfunc_call(2); |
- | |
5102 | vpushi(0); |
- | |
5103 | vtop->r = REG_IRET; |
- | |
5104 | vtop->r2 = REG_LRET; |
- | |
5105 | break; |
- | |
5106 | case '^': |
- | |
5107 | case '&': |
- | |
5108 | case '|': |
- | |
5109 | case '*': |
- | |
5110 | case '+': |
- | |
5111 | case '-': |
- | |
5112 | t = vtop->type.t; |
- | |
5113 | vswap(); |
- | |
5114 | lexpand(); |
- | |
5115 | vrotb(3); |
- | |
5116 | lexpand(); |
- | |
5117 | /* stack: L1 H1 L2 H2 */ |
- | |
5118 | tmp = vtop[0]; |
- | |
5119 | vtop[0] = vtop[-3]; |
- | |
5120 | vtop[-3] = tmp; |
- | |
5121 | tmp = vtop[-2]; |
- | |
5122 | vtop[-2] = vtop[-3]; |
- | |
5123 | vtop[-3] = tmp; |
- | |
5124 | vswap(); |
- | |
5125 | /* stack: H1 H2 L1 L2 */ |
- | |
5126 | if (op == '*') { |
- | |
5127 | vpushv(vtop - 1); |
- | |
5128 | vpushv(vtop - 1); |
- | |
5129 | gen_op(TOK_UMULL); |
- | |
5130 | lexpand(); |
- | |
5131 | /* stack: H1 H2 L1 L2 ML MH */ |
- | |
5132 | for(i=0;i<4;i++) |
- | |
5133 | vrotb(6); |
- | |
5134 | /* stack: ML MH H1 H2 L1 L2 */ |
- | |
5135 | tmp = vtop[0]; |
- | |
5136 | vtop[0] = vtop[-2]; |
- | |
5137 | vtop[-2] = tmp; |
- | |
5138 | /* stack: ML MH H1 L2 H2 L1 */ |
- | |
5139 | gen_op('*'); |
- | |
5140 | vrotb(3); |
- | |
5141 | vrotb(3); |
- | |
5142 | gen_op('*'); |
- | |
5143 | /* stack: ML MH M1 M2 */ |
- | |
5144 | gen_op('+'); |
- | |
5145 | gen_op('+'); |
- | |
5146 | } else if (op == '+' || op == '-') { |
- | |
5147 | /* XXX: add non carry method too (for MIPS or alpha) */ |
- | |
5148 | if (op == '+') |
- | |
5149 | op1 = TOK_ADDC1; |
- | |
5150 | else |
- | |
5151 | op1 = TOK_SUBC1; |
- | |
5152 | gen_op(op1); |
- | |
5153 | /* stack: H1 H2 (L1 op L2) */ |
- | |
5154 | vrotb(3); |
- | |
5155 | vrotb(3); |
- | |
5156 | gen_op(op1 + 1); /* TOK_xxxC2 */ |
- | |
5157 | } else { |
- | |
5158 | gen_op(op); |
- | |
5159 | /* stack: H1 H2 (L1 op L2) */ |
- | |
5160 | vrotb(3); |
- | |
5161 | vrotb(3); |
- | |
5162 | /* stack: (L1 op L2) H1 H2 */ |
- | |
5163 | gen_op(op); |
- | |
5164 | /* stack: (L1 op L2) (H1 op H2) */ |
- | |
5165 | } |
- | |
5166 | /* stack: L H */ |
- | |
5167 | lbuild(t); |
- | |
5168 | break; |
- | |
5169 | case TOK_SAR: |
- | |
5170 | case TOK_SHR: |
- | |
5171 | case TOK_SHL: |
- | |
5172 | if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) { |
- | |
5173 | t = vtop[-1].type.t; |
- | |
5174 | vswap(); |
- | |
5175 | lexpand(); |
- | |
5176 | vrotb(3); |
- | |
5177 | /* stack: L H shift */ |
- | |
5178 | c = (int)vtop->c.i; |
- | |
5179 | /* constant: simpler */ |
- | |
5180 | /* NOTE: all comments are for SHL. the other cases are |
- | |
5181 | done by swaping words */ |
- | |
5182 | vpop(); |
- | |
5183 | if (op != TOK_SHL) |
- | |
5184 | vswap(); |
- | |
5185 | if (c >= 32) { |
- | |
5186 | /* stack: L H */ |
- | |
5187 | vpop(); |
- | |
5188 | if (c > 32) { |
- | |
5189 | vpushi(c - 32); |
- | |
5190 | gen_op(op); |
- | |
5191 | } |
- | |
5192 | if (op != TOK_SAR) { |
- | |
5193 | vpushi(0); |
- | |
5194 | } else { |
- | |
5195 | gv_dup(); |
- | |
5196 | vpushi(31); |
- | |
5197 | gen_op(TOK_SAR); |
- | |
5198 | } |
- | |
5199 | vswap(); |
- | |
5200 | } else { |
- | |
5201 | vswap(); |
- | |
5202 | gv_dup(); |
- | |
5203 | /* stack: H L L */ |
- | |
5204 | vpushi(c); |
- | |
5205 | gen_op(op); |
- | |
5206 | vswap(); |
- | |
5207 | vpushi(32 - c); |
- | |
5208 | if (op == TOK_SHL) |
- | |
5209 | gen_op(TOK_SHR); |
- | |
5210 | else |
- | |
5211 | gen_op(TOK_SHL); |
- | |
5212 | vrotb(3); |
- | |
5213 | /* stack: L L H */ |
- | |
5214 | vpushi(c); |
- | |
5215 | if (op == TOK_SHL) |
- | |
5216 | gen_op(TOK_SHL); |
- | |
5217 | else |
- | |
5218 | gen_op(TOK_SHR); |
- | |
5219 | gen_op('|'); |
- | |
5220 | } |
- | |
5221 | if (op != TOK_SHL) |
- | |
5222 | vswap(); |
- | |
5223 | lbuild(t); |
- | |
5224 | } else { |
- | |
5225 | /* XXX: should provide a faster fallback on x86 ? */ |
- | |
5226 | switch(op) { |
- | |
5227 | case TOK_SAR: |
- | |
5228 | func = TOK___sardi3; |
- | |
5229 | goto gen_func; |
- | |
5230 | case TOK_SHR: |
- | |
5231 | func = TOK___shrdi3; |
- | |
5232 | goto gen_func; |
- | |
5233 | case TOK_SHL: |
- | |
5234 | func = TOK___shldi3; |
- | |
5235 | goto gen_func; |
- | |
5236 | } |
- | |
5237 | } |
- | |
5238 | break; |
- | |
5239 | default: |
- | |
5240 | /* compare operations */ |
- | |
5241 | t = vtop->type.t; |
- | |
5242 | vswap(); |
- | |
5243 | lexpand(); |
- | |
5244 | vrotb(3); |
- | |
5245 | lexpand(); |
- | |
5246 | /* stack: L1 H1 L2 H2 */ |
- | |
5247 | tmp = vtop[-1]; |
- | |
5248 | vtop[-1] = vtop[-2]; |
- | |
5249 | vtop[-2] = tmp; |
- | |
5250 | /* stack: L1 L2 H1 H2 */ |
- | |
5251 | /* compare high */ |
- | |
5252 | op1 = op; |
- | |
5253 | /* when values are equal, we need to compare low words. since |
- | |
5254 | the jump is inverted, we invert the test too. */ |
- | |
5255 | if (op1 == TOK_LT) |
- | |
5256 | op1 = TOK_LE; |
- | |
5257 | else if (op1 == TOK_GT) |
- | |
5258 | op1 = TOK_GE; |
- | |
5259 | else if (op1 == TOK_ULT) |
- | |
5260 | op1 = TOK_ULE; |
- | |
5261 | else if (op1 == TOK_UGT) |
- | |
5262 | op1 = TOK_UGE; |
- | |
5263 | a = 0; |
- | |
5264 | b = 0; |
- | |
5265 | gen_op(op1); |
- | |
5266 | if (op1 != TOK_NE) { |
- | |
5267 | a = gtst(1, 0); |
- | |
5268 | } |
- | |
5269 | if (op != TOK_EQ) { |
- | |
5270 | /* generate non equal test */ |
- | |
5271 | /* XXX: NOT PORTABLE yet */ |
- | |
5272 | if (a == 0) { |
- | |
5273 | b = gtst(0, 0); |
- | |
5274 | } else { |
- | |
5275 | #if defined(TCC_TARGET_I386) |
- | |
5276 | b = psym(0x850f, 0); |
- | |
5277 | #elif defined(TCC_TARGET_ARM) |
- | |
5278 | b = ind; |
- | |
5279 | o(0x1A000000 | encbranch(ind, 0, 1)); |
- | |
5280 | #elif defined(TCC_TARGET_C67) |
- | |
5281 | error("not implemented"); |
53 | # ifdef TCC_ARM_HARDFLOAT |
5282 | #else |
- | |
5283 | #error not supported |
- | |
5284 | #endif |
- | |
5285 | } |
- | |
5286 | } |
- | |
5287 | /* compare low. Always unsigned */ |
- | |
5288 | op1 = op; |
- | |
5289 | if (op1 == TOK_LT) |
- | |
5290 | op1 = TOK_ULT; |
- | |
5291 | else if (op1 == TOK_LE) |
- | |
5292 | op1 = TOK_ULE; |
- | |
5293 | else if (op1 == TOK_GT) |
- | |
5294 | op1 = TOK_UGT; |
- | |
5295 | else if (op1 == TOK_GE) |
- | |
5296 | op1 = TOK_UGE; |
- | |
5297 | gen_op(op1); |
- | |
5298 | a = gtst(1, a); |
- | |
5299 | gsym(b); |
- | |
5300 | vseti(VT_JMPI, a); |
- | |
5301 | break; |
- | |
5302 | } |
- | |
5303 | } |
- | |
5304 | - | ||
5305 | /* handle integer constant optimizations and various machine |
- | |
5306 | independent opt */ |
- | |
5307 | void gen_opic(int op) |
- | |
5308 | { |
- | |
5309 | int fc, c1, c2, n; |
- | |
5310 | SValue *v1, *v2; |
- | |
5311 | - | ||
5312 | v1 = vtop - 1; |
- | |
5313 | v2 = vtop; |
- | |
5314 | /* currently, we cannot do computations with forward symbols */ |
- | |
5315 | c1 = (v1->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; |
- | |
5316 | c2 = (v2->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; |
- | |
5317 | if (c1 && c2) { |
- | |
5318 | fc = v2->c.i; |
- | |
5319 | switch(op) { |
- | |
5320 | case '+': v1->c.i += fc; break; |
- | |
5321 | case '-': v1->c.i -= fc; break; |
- | |
5322 | case '&': v1->c.i &= fc; break; |
- | |
5323 | case '^': v1->c.i ^= fc; break; |
- | |
5324 | case '|': v1->c.i |= fc; break; |
- | |
5325 | case '*': v1->c.i *= fc; break; |
- | |
5326 | - | ||
5327 | case TOK_PDIV: |
- | |
5328 | case '/': |
- | |
5329 | case '%': |
- | |
5330 | case TOK_UDIV: |
- | |
5331 | case TOK_UMOD: |
- | |
5332 | /* if division by zero, generate explicit division */ |
- | |
5333 | if (fc == 0) { |
- | |
5334 | if (const_wanted) |
- | |
5335 | error("division by zero in constant"); |
- | |
5336 | goto general_case; |
- | |
5337 | } |
- | |
5338 | switch(op) { |
- | |
5339 | default: v1->c.i /= fc; break; |
- | |
5340 | case '%': v1->c.i %= fc; break; |
- | |
5341 | case TOK_UDIV: v1->c.i = (unsigned)v1->c.i / fc; break; |
- | |
5342 | case TOK_UMOD: v1->c.i = (unsigned)v1->c.i % fc; break; |
- | |
5343 | } |
- | |
5344 | break; |
- | |
5345 | case TOK_SHL: v1->c.i <<= fc; break; |
- | |
5346 | case TOK_SHR: v1->c.i = (unsigned)v1->c.i >> fc; break; |
- | |
5347 | case TOK_SAR: v1->c.i >>= fc; break; |
- | |
5348 | /* tests */ |
- | |
5349 | case TOK_ULT: v1->c.i = (unsigned)v1->c.i < (unsigned)fc; break; |
- | |
5350 | case TOK_UGE: v1->c.i = (unsigned)v1->c.i >= (unsigned)fc; break; |
- | |
5351 | case TOK_EQ: v1->c.i = v1->c.i == fc; break; |
- | |
5352 | case TOK_NE: v1->c.i = v1->c.i != fc; break; |
- | |
5353 | case TOK_ULE: v1->c.i = (unsigned)v1->c.i <= (unsigned)fc; break; |
- | |
5354 | case TOK_UGT: v1->c.i = (unsigned)v1->c.i > (unsigned)fc; break; |
- | |
5355 | case TOK_LT: v1->c.i = v1->c.i < fc; break; |
- | |
5356 | case TOK_GE: v1->c.i = v1->c.i >= fc; break; |
- | |
5357 | case TOK_LE: v1->c.i = v1->c.i <= fc; break; |
- | |
5358 | case TOK_GT: v1->c.i = v1->c.i > fc; break; |
- | |
5359 | /* logical */ |
- | |
5360 | case TOK_LAND: v1->c.i = v1->c.i && fc; break; |
- | |
5361 | case TOK_LOR: v1->c.i = v1->c.i || fc; break; |
- | |
5362 | default: |
- | |
5363 | goto general_case; |
- | |
5364 | } |
- | |
5365 | vtop--; |
- | |
5366 | } else { |
- | |
5367 | /* if commutative ops, put c2 as constant */ |
- | |
5368 | if (c1 && (op == '+' || op == '&' || op == '^' || |
- | |
5369 | op == '|' || op == '*')) { |
- | |
5370 | vswap(); |
- | |
5371 | swap(&c1, &c2); |
- | |
5372 | } |
- | |
5373 | fc = vtop->c.i; |
- | |
5374 | if (c2 && (((op == '*' || op == '/' || op == TOK_UDIV || |
- | |
5375 | op == TOK_PDIV) && |
- | |
5376 | fc == 1) || |
- | |
5377 | ((op == '+' || op == '-' || op == '|' || op == '^' || |
- | |
5378 | op == TOK_SHL || op == TOK_SHR || op == TOK_SAR) && |
- | |
5379 | fc == 0) || |
- | |
5380 | (op == '&' && |
- | |
5381 | fc == -1))) { |
- | |
5382 | /* nothing to do */ |
- | |
5383 | vtop--; |
- | |
5384 | } else if (c2 && (op == '*' || op == TOK_PDIV || op == TOK_UDIV)) { |
- | |
5385 | /* try to use shifts instead of muls or divs */ |
- | |
5386 | if (fc > 0 && (fc & (fc - 1)) == 0) { |
- | |
5387 | n = -1; |
- | |
5388 | while (fc) { |
- | |
5389 | fc >>= 1; |
- | |
5390 | n++; |
- | |
5391 | } |
- | |
5392 | vtop->c.i = n; |
- | |
5393 | if (op == '*') |
- | |
5394 | op = TOK_SHL; |
- | |
5395 | else if (op == TOK_PDIV) |
- | |
5396 | op = TOK_SAR; |
- | |
5397 | else |
- | |
5398 | op = TOK_SHR; |
- | |
5399 | } |
- | |
5400 | goto general_case; |
- | |
5401 | } else if (c2 && (op == '+' || op == '-') && |
- | |
5402 | (vtop[-1].r & (VT_VALMASK | VT_LVAL | VT_SYM)) == |
- | |
5403 | (VT_CONST | VT_SYM)) { |
- | |
5404 | /* symbol + constant case */ |
- | |
5405 | if (op == '-') |
- | |
5406 | fc = -fc; |
- | |
5407 | vtop--; |
- | |
5408 | vtop->c.i += fc; |
- | |
5409 | } else { |
- | |
5410 | general_case: |
- | |
5411 | if (!nocode_wanted) { |
- | |
5412 | /* call low level op generator */ |
- | |
5413 | gen_opi(op); |
- | |
5414 | } else { |
- | |
5415 | vtop--; |
- | |
5416 | } |
- | |
5417 | } |
- | |
5418 | } |
- | |
5419 | } |
- | |
5420 | - | ||
5421 | /* generate a floating point operation with constant propagation */ |
- | |
5422 | void gen_opif(int op) |
- | |
5423 | { |
- | |
5424 | int c1, c2; |
- | |
5425 | SValue *v1, *v2; |
- | |
5426 | long double f1, f2; |
- | |
5427 | - | ||
5428 | v1 = vtop - 1; |
- | |
5429 | v2 = vtop; |
- | |
5430 | /* currently, we cannot do computations with forward symbols */ |
- | |
5431 | c1 = (v1->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; |
- | |
5432 | c2 = (v2->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; |
- | |
5433 | if (c1 && c2) { |
- | |
5434 | if (v1->type.t == VT_FLOAT) { |
- | |
5435 | f1 = v1->c.f; |
- | |
5436 | f2 = v2->c.f; |
- | |
5437 | } else if (v1->type.t == VT_DOUBLE) { |
- | |
5438 | f1 = v1->c.d; |
- | |
5439 | f2 = v2->c.d; |
- | |
5440 | } else { |
- | |
5441 | f1 = v1->c.ld; |
- | |
5442 | f2 = v2->c.ld; |
- | |
5443 | } |
- | |
5444 | - | ||
5445 | /* NOTE: we only do constant propagation if finite number (not |
- | |
5446 | NaN or infinity) (ANSI spec) */ |
- | |
5447 | if (!ieee_finite(f1) || !ieee_finite(f2)) |
- | |
5448 | goto general_case; |
- | |
5449 | - | ||
5450 | switch(op) { |
- | |
5451 | case '+': f1 += f2; break; |
- | |
5452 | case '-': f1 -= f2; break; |
- | |
5453 | case '*': f1 *= f2; break; |
- | |
5454 | case '/': |
- | |
5455 | if (f2 == 0.0) { |
- | |
5456 | if (const_wanted) |
- | |
5457 | error("division by zero in constant"); |
- | |
5458 | goto general_case; |
- | |
5459 | } |
- | |
5460 | f1 /= f2; |
- | |
5461 | break; |
- | |
5462 | /* XXX: also handles tests ? */ |
- | |
5463 | default: |
- | |
5464 | goto general_case; |
- | |
5465 | } |
- | |
5466 | /* XXX: overflow test ? */ |
- | |
5467 | if (v1->type.t == VT_FLOAT) { |
- | |
5468 | v1->c.f = f1; |
- | |
5469 | } else if (v1->type.t == VT_DOUBLE) { |
- | |
5470 | v1->c.d = f1; |
- | |
5471 | } else { |
- | |
5472 | v1->c.ld = f1; |
- | |
5473 | } |
- | |
5474 | vtop--; |
- | |
5475 | } else { |
- | |
5476 | general_case: |
- | |
5477 | if (!nocode_wanted) { |
- | |
5478 | gen_opf(op); |
- | |
5479 | } else { |
- | |
5480 | vtop--; |
- | |
5481 | } |
- | |
5482 | } |
- | |
5483 | } |
- | |
5484 | - | ||
5485 | static int pointed_size(CType *type) |
- | |
5486 | { |
- | |
5487 | int align; |
- | |
5488 | return type_size(pointed_type(type), &align); |
- | |
5489 | } |
- | |
5490 | - | ||
5491 | static inline int is_null_pointer(SValue *p) |
- | |
5492 | { |
- | |
5493 | if ((p->r & (VT_VALMASK | VT_LVAL | VT_SYM)) != VT_CONST) |
- | |
5494 | return 0; |
- | |
5495 | return ((p->type.t & VT_BTYPE) == VT_INT && p->c.i == 0) || |
- | |
5496 | ((p->type.t & VT_BTYPE) == VT_LLONG && p->c.ll == 0); |
- | |
5497 | } |
- | |
5498 | - | ||
5499 | static inline int is_integer_btype(int bt) |
- | |
5500 | { |
- | |
5501 | return (bt == VT_BYTE || bt == VT_SHORT || |
- | |
5502 | bt == VT_INT || bt == VT_LLONG); |
- | |
5503 | } |
- | |
5504 | - | ||
5505 | /* check types for comparison or substraction of pointers */ |
- | |
5506 | static void check_comparison_pointer_types(SValue *p1, SValue *p2, int op) |
- | |
5507 | { |
- | |
5508 | CType *type1, *type2, tmp_type1, tmp_type2; |
- | |
5509 | int bt1, bt2; |
- | |
5510 | - | ||
5511 | /* null pointers are accepted for all comparisons as gcc */ |
- | |
5512 | if (is_null_pointer(p1) || is_null_pointer(p2)) |
- | |
5513 | return; |
- | |
5514 | type1 = &p1->type; |
- | |
5515 | type2 = &p2->type; |
- | |
5516 | bt1 = type1->t & VT_BTYPE; |
- | |
5517 | bt2 = type2->t & VT_BTYPE; |
- | |
5518 | /* accept comparison between pointer and integer with a warning */ |
- | |
5519 | if ((is_integer_btype(bt1) || is_integer_btype(bt2)) && op != '-') { |
- | |
5520 | warning("comparison between pointer and integer"); |
- | |
5521 | return; |
- | |
5522 | } |
- | |
5523 | - | ||
5524 | /* both must be pointers or implicit function pointers */ |
- | |
5525 | if (bt1 == VT_PTR) { |
- | |
5526 | type1 = pointed_type(type1); |
- | |
5527 | } else if (bt1 != VT_FUNC) |
- | |
5528 | goto invalid_operands; |
- | |
5529 | - | ||
5530 | if (bt2 == VT_PTR) { |
- | |
5531 | type2 = pointed_type(type2); |
- | |
5532 | } else if (bt2 != VT_FUNC) { |
- | |
5533 | invalid_operands: |
- | |
5534 | error("invalid operands to binary %s", get_tok_str(op, NULL)); |
- | |
5535 | } |
- | |
5536 | if ((type1->t & VT_BTYPE) == VT_VOID || |
- | |
5537 | (type2->t & VT_BTYPE) == VT_VOID) |
- | |
5538 | return; |
- | |
5539 | tmp_type1 = *type1; |
- | |
5540 | tmp_type2 = *type2; |
- | |
5541 | tmp_type1.t &= ~(VT_UNSIGNED | VT_CONSTANT | VT_VOLATILE); |
- | |
5542 | tmp_type2.t &= ~(VT_UNSIGNED | VT_CONSTANT | VT_VOLATILE); |
- | |
5543 | if (!is_compatible_types(&tmp_type1, &tmp_type2)) { |
- | |
5544 | /* gcc-like error if '-' is used */ |
- | |
5545 | if (op == '-') |
- | |
5546 | goto invalid_operands; |
- | |
5547 | else |
- | |
5548 | warning("comparison of distinct pointer types lacks a cast"); |
- | |
5549 | } |
- | |
5550 | } |
- | |
5551 | - | ||
5552 | /* generic gen_op: handles types problems */ |
- | |
5553 | void gen_op(int op) |
- | |
5554 | { |
- | |
5555 | int u, t1, t2, bt1, bt2, t; |
- | |
5556 | CType type1; |
- | |
5557 | - | ||
5558 | t1 = vtop[-1].type.t; |
- | |
5559 | t2 = vtop[0].type.t; |
- | |
5560 | bt1 = t1 & VT_BTYPE; |
- | |
5561 | bt2 = t2 & VT_BTYPE; |
- | |
5562 | - | ||
5563 | if (bt1 == VT_PTR || bt2 == VT_PTR) { |
- | |
5564 | /* at least one operand is a pointer */ |
- | |
5565 | /* relationnal op: must be both pointers */ |
- | |
5566 | if (op >= TOK_ULT && op <= TOK_GT) { |
- | |
5567 | check_comparison_pointer_types(vtop - 1, vtop, op); |
- | |
5568 | /* pointers are handled are unsigned */ |
- | |
5569 | t = VT_INT | VT_UNSIGNED; |
- | |
5570 | goto std_op; |
- | |
5571 | } |
- | |
5572 | /* if both pointers, then it must be the '-' op */ |
- | |
5573 | if (bt1 == VT_PTR && bt2 == VT_PTR) { |
- | |
5574 | if (op != '-') |
- | |
5575 | error("cannot use pointers here"); |
- | |
5576 | check_comparison_pointer_types(vtop - 1, vtop, op); |
- | |
5577 | /* XXX: check that types are compatible */ |
- | |
5578 | u = pointed_size(&vtop[-1].type); |
- | |
5579 | gen_opic(op); |
- | |
5580 | /* set to integer type */ |
- | |
5581 | vtop->type.t = VT_INT; |
- | |
5582 | vpushi(u); |
- | |
5583 | gen_op(TOK_PDIV); |
- | |
5584 | } else { |
- | |
5585 | /* exactly one pointer : must be '+' or '-'. */ |
- | |
5586 | if (op != '-' && op != '+') |
- | |
5587 | error("cannot use pointers here"); |
- | |
5588 | /* Put pointer as first operand */ |
- | |
5589 | if (bt2 == VT_PTR) { |
- | |
5590 | vswap(); |
- | |
5591 | swap(&t1, &t2); |
- | |
5592 | } |
- | |
5593 | type1 = vtop[-1].type; |
- | |
5594 | /* XXX: cast to int ? (long long case) */ |
54 | " Hard Float" |
5595 | vpushi(pointed_size(&vtop[-1].type)); |
- | |
5596 | gen_op('*'); |
- | |
5597 | #ifdef CONFIG_TCC_BCHECK |
- | |
5598 | /* if evaluating constant expression, no code should be |
- | |
5599 | generated, so no bound check */ |
- | |
5600 | if (do_bounds_check && !const_wanted) { |
- | |
5601 | /* if bounded pointers, we generate a special code to |
- | |
5602 | test bounds */ |
- | |
5603 | if (op == '-') { |
- | |
5604 | vpushi(0); |
- | |
5605 | vswap(); |
- | |
5606 | gen_op('-'); |
55 | # endif |
5607 | } |
- | |
5608 | gen_bounded_ptr_add(); |
- | |
5609 | } else |
- | |
5610 | #endif |
- | |
5611 | { |
- | |
5612 | gen_opic(op); |
- | |
5613 | } |
- | |
5614 | /* put again type if gen_opic() swaped operands */ |
- | |
5615 | vtop->type = type1; |
- | |
5616 | } |
- | |
5617 | } else if (is_float(bt1) || is_float(bt2)) { |
- | |
5618 | /* compute bigger type and do implicit casts */ |
- | |
5619 | if (bt1 == VT_LDOUBLE || bt2 == VT_LDOUBLE) { |
- | |
5620 | t = VT_LDOUBLE; |
- | |
5621 | } else if (bt1 == VT_DOUBLE || bt2 == VT_DOUBLE) { |
- | |
5622 | t = VT_DOUBLE; |
- | |
5623 | } else { |
- | |
5624 | t = VT_FLOAT; |
- | |
5625 | } |
- | |
5626 | /* floats can only be used for a few operations */ |
- | |
5627 | if (op != '+' && op != '-' && op != '*' && op != '/' && |
- | |
5628 | (op < TOK_ULT || op > TOK_GT)) |
- | |
5629 | error("invalid operands for binary operation"); |
- | |
5630 | goto std_op; |
- | |
5631 | } else if (bt1 == VT_LLONG || bt2 == VT_LLONG) { |
- | |
5632 | /* cast to biggest op */ |
- | |
5633 | t = VT_LLONG; |
- | |
5634 | /* convert to unsigned if it does not fit in a long long */ |
- | |
5635 | if ((t1 & (VT_BTYPE | VT_UNSIGNED)) == (VT_LLONG | VT_UNSIGNED) || |
- | |
5636 | (t2 & (VT_BTYPE | VT_UNSIGNED)) == (VT_LLONG | VT_UNSIGNED)) |
- | |
5637 | t |= VT_UNSIGNED; |
- | |
5638 | goto std_op; |
- | |
5639 | } else { |
- | |
5640 | /* integer operations */ |
- | |
5641 | t = VT_INT; |
- | |
5642 | /* convert to unsigned if it does not fit in an integer */ |
- | |
5643 | if ((t1 & (VT_BTYPE | VT_UNSIGNED)) == (VT_INT | VT_UNSIGNED) || |
- | |
5644 | (t2 & (VT_BTYPE | VT_UNSIGNED)) == (VT_INT | VT_UNSIGNED)) |
- | |
5645 | t |= VT_UNSIGNED; |
- | |
5646 | std_op: |
- | |
5647 | /* XXX: currently, some unsigned operations are explicit, so |
- | |
5648 | we modify them here */ |
- | |
5649 | if (t & VT_UNSIGNED) { |
- | |
5650 | if (op == TOK_SAR) |
- | |
5651 | op = TOK_SHR; |
- | |
5652 | else if (op == '/') |
- | |
5653 | op = TOK_UDIV; |
- | |
5654 | else if (op == '%') |
- | |
5655 | op = TOK_UMOD; |
- | |
5656 | else if (op == TOK_LT) |
- | |
5657 | op = TOK_ULT; |
- | |
5658 | else if (op == TOK_GT) |
- | |
5659 | op = TOK_UGT; |
- | |
5660 | else if (op == TOK_LE) |
- | |
5661 | op = TOK_ULE; |
- | |
5662 | else if (op == TOK_GE) |
- | |
5663 | op = TOK_UGE; |
- | |
5664 | } |
- | |
5665 | vswap(); |
- | |
5666 | type1.t = t; |
- | |
5667 | gen_cast(&type1); |
- | |
5668 | vswap(); |
- | |
5669 | /* special case for shifts and long long: we keep the shift as |
- | |
5670 | an integer */ |
- | |
5671 | if (op == TOK_SHR || op == TOK_SAR || op == TOK_SHL) |
- | |
5672 | type1.t = VT_INT; |
- | |
5673 | gen_cast(&type1); |
- | |
5674 | if (is_float(t)) |
- | |
5675 | gen_opif(op); |
- | |
5676 | else if ((t & VT_BTYPE) == VT_LLONG) |
- | |
5677 | gen_opl(op); |
- | |
5678 | else |
- | |
5679 | gen_opic(op); |
- | |
5680 | if (op >= TOK_ULT && op <= TOK_GT) { |
- | |
5681 | /* relationnal op: the result is an int */ |
- | |
5682 | vtop->type.t = VT_INT; |
- | |
5683 | } else { |
- | |
5684 | vtop->type.t = t; |
- | |
5685 | } |
- | |
5686 | } |
- | |
5687 | } |
- | |
5688 | - | ||
5689 | /* generic itof for unsigned long long case */ |
- | |
5690 | void gen_cvt_itof1(int t) |
- | |
5691 | { |
- | |
5692 | if ((vtop->type.t & (VT_BTYPE | VT_UNSIGNED)) == |
- | |
5693 | (VT_LLONG | VT_UNSIGNED)) { |
- | |
5694 | - | ||
5695 | if (t == VT_FLOAT) |
- | |
5696 | vpush_global_sym(&func_old_type, TOK___ulltof); |
- | |
5697 | else if (t == VT_DOUBLE) |
- | |
5698 | vpush_global_sym(&func_old_type, TOK___ulltod); |
- | |
5699 | else |
- | |
5700 | vpush_global_sym(&func_old_type, TOK___ulltold); |
- | |
5701 | vrott(2); |
- | |
5702 | gfunc_call(1); |
- | |
5703 | vpushi(0); |
- | |
5704 | vtop->r = REG_FRET; |
- | |
5705 | } else { |
- | |
5706 | gen_cvt_itof(t); |
- | |
5707 | } |
- | |
5708 | } |
- | |
5709 | - | ||
5710 | /* generic ftoi for unsigned long long case */ |
- | |
5711 | void gen_cvt_ftoi1(int t) |
- | |
5712 | { |
- | |
5713 | int st; |
- | |
5714 | - | ||
5715 | if (t == (VT_LLONG | VT_UNSIGNED)) { |
- | |
5716 | /* not handled natively */ |
- | |
5717 | st = vtop->type.t & VT_BTYPE; |
- | |
5718 | if (st == VT_FLOAT) |
- | |
5719 | vpush_global_sym(&func_old_type, TOK___fixunssfdi); |
- | |
5720 | else if (st == VT_DOUBLE) |
- | |
5721 | vpush_global_sym(&func_old_type, TOK___fixunsdfdi); |
- | |
5722 | else |
- | |
5723 | vpush_global_sym(&func_old_type, TOK___fixunsxfdi); |
- | |
5724 | vrott(2); |
- | |
5725 | gfunc_call(1); |
- | |
5726 | vpushi(0); |
- | |
5727 | vtop->r = REG_IRET; |
- | |
5728 | vtop->r2 = REG_LRET; |
- | |
5729 | } else { |
- | |
5730 | gen_cvt_ftoi(t); |
- | |
5731 | } |
- | |
5732 | } |
- | |
5733 | - | ||
5734 | /* force char or short cast */ |
- | |
5735 | void force_charshort_cast(int t) |
- | |
5736 | { |
- | |
5737 | int bits, dbt; |
- | |
5738 | dbt = t & VT_BTYPE; |
- | |
5739 | /* XXX: add optimization if lvalue : just change type and offset */ |
- | |
5740 | if (dbt == VT_BYTE) |
- | |
5741 | bits = 8; |
- | |
5742 | else |
- | |
5743 | bits = 16; |
- | |
5744 | if (t & VT_UNSIGNED) { |
- | |
5745 | vpushi((1 << bits) - 1); |
- | |
5746 | gen_op('&'); |
- | |
5747 | } else { |
- | |
5748 | bits = 32 - bits; |
- | |
5749 | vpushi(bits); |
- | |
5750 | gen_op(TOK_SHL); |
- | |
5751 | vpushi(bits); |
- | |
5752 | gen_op(TOK_SAR); |
- | |
5753 | } |
- | |
5754 | } |
- | |
5755 | - | ||
5756 | /* cast 'vtop' to 'type'. Casting to bitfields is forbidden. */ |
- | |
5757 | static void gen_cast(CType *type) |
- | |
5758 | { |
- | |
5759 | int sbt, dbt, sf, df, c; |
- | |
5760 | - | ||
5761 | /* special delayed cast for char/short */ |
- | |
5762 | /* XXX: in some cases (multiple cascaded casts), it may still |
- | |
5763 | be incorrect */ |
- | |
5764 | if (vtop->r & VT_MUSTCAST) { |
- | |
5765 | vtop->r &= ~VT_MUSTCAST; |
- | |
5766 | force_charshort_cast(vtop->type.t); |
- | |
5767 | } |
- | |
5768 | - | ||
5769 | /* bitfields first get cast to ints */ |
- | |
5770 | if (vtop->type.t & VT_BITFIELD) { |
- | |
5771 | gv(RC_INT); |
- | |
5772 | } |
- | |
5773 | - | ||
5774 | dbt = type->t & (VT_BTYPE | VT_UNSIGNED); |
- | |
5775 | sbt = vtop->type.t & (VT_BTYPE | VT_UNSIGNED); |
- | |
5776 | - | ||
5777 | if (sbt != dbt && !nocode_wanted) { |
- | |
5778 | sf = is_float(sbt); |
- | |
5779 | df = is_float(dbt); |
- | |
5780 | c = (vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; |
- | |
5781 | if (sf && df) { |
- | |
5782 | /* convert from fp to fp */ |
- | |
5783 | if (c) { |
- | |
5784 | /* constant case: we can do it now */ |
- | |
5785 | /* XXX: in ISOC, cannot do it if error in convert */ |
- | |
5786 | if (dbt == VT_FLOAT && sbt == VT_DOUBLE) |
- | |
5787 | vtop->c.f = (float)vtop->c.d; |
- | |
5788 | else if (dbt == VT_FLOAT && sbt == VT_LDOUBLE) |
- | |
5789 | vtop->c.f = (float)vtop->c.ld; |
- | |
5790 | else if (dbt == VT_DOUBLE && sbt == VT_FLOAT) |
- | |
5791 | vtop->c.d = (double)vtop->c.f; |
- | |
5792 | else if (dbt == VT_DOUBLE && sbt == VT_LDOUBLE) |
- | |
5793 | vtop->c.d = (double)vtop->c.ld; |
- | |
5794 | else if (dbt == VT_LDOUBLE && sbt == VT_FLOAT) |
- | |
5795 | vtop->c.ld = (long double)vtop->c.f; |
- | |
5796 | else if (dbt == VT_LDOUBLE && sbt == VT_DOUBLE) |
- | |
5797 | vtop->c.ld = (long double)vtop->c.d; |
- | |
5798 | } else { |
- | |
5799 | /* non constant case: generate code */ |
- | |
5800 | gen_cvt_ftof(dbt); |
- | |
5801 | } |
- | |
5802 | } else if (df) { |
- | |
5803 | /* convert int to fp */ |
- | |
5804 | if (c) { |
- | |
5805 | switch(sbt) { |
- | |
5806 | case VT_LLONG | VT_UNSIGNED: |
- | |
5807 | case VT_LLONG: |
- | |
5808 | /* XXX: add const cases for long long */ |
- | |
5809 | goto do_itof; |
- | |
5810 | case VT_INT | VT_UNSIGNED: |
- | |
5811 | switch(dbt) { |
- | |
5812 | case VT_FLOAT: vtop->c.f = (float)vtop->c.ui; break; |
- | |
5813 | case VT_DOUBLE: vtop->c.d = (double)vtop->c.ui; break; |
- | |
5814 | case VT_LDOUBLE: vtop->c.ld = (long double)vtop->c.ui; break; |
- | |
5815 | } |
- | |
5816 | break; |
- | |
5817 | default: |
- | |
5818 | switch(dbt) { |
- | |
5819 | case VT_FLOAT: vtop->c.f = (float)vtop->c.i; break; |
- | |
5820 | case VT_DOUBLE: vtop->c.d = (double)vtop->c.i; break; |
- | |
5821 | case VT_LDOUBLE: vtop->c.ld = (long double)vtop->c.i; break; |
- | |
5822 | } |
- | |
5823 | break; |
- | |
5824 | } |
56 | #endif |
5825 | } else { |
57 | #ifdef TCC_TARGET_PE |
5826 | do_itof: |
58 | " Windows" |
5827 | #if !defined(TCC_TARGET_ARM) |
59 | #elif defined TCC_TARGET_MEOS |
5828 | gen_cvt_itof1(dbt); |
60 | " KolibriOS" |
5829 | #else |
- | |
5830 | gen_cvt_itof(dbt); |
- | |
5831 | #endif |
- | |
5832 | } |
- | |
5833 | } else if (sf) { |
- | |
5834 | /* convert fp to int */ |
- | |
5835 | /* we handle char/short/etc... with generic code */ |
- | |
5836 | if (dbt != (VT_INT | VT_UNSIGNED) && |
- | |
5837 | dbt != (VT_LLONG | VT_UNSIGNED) && |
- | |
5838 | dbt != VT_LLONG) |
- | |
5839 | dbt = VT_INT; |
- | |
5840 | if (c) { |
61 | #else |
5841 | switch(dbt) { |
- | |
5842 | case VT_LLONG | VT_UNSIGNED: |
- | |
5843 | case VT_LLONG: |
- | |
5844 | /* XXX: add const cases for long long */ |
- | |
5845 | goto do_ftoi; |
- | |
5846 | case VT_INT | VT_UNSIGNED: |
- | |
5847 | switch(sbt) { |
- | |
5848 | case VT_FLOAT: vtop->c.ui = (unsigned int)vtop->c.d; break; |
- | |
5849 | case VT_DOUBLE: vtop->c.ui = (unsigned int)vtop->c.d; break; |
62 | " Linux" |
5850 | case VT_LDOUBLE: vtop->c.ui = (unsigned int)vtop->c.d; break; |
- | |
5851 | } |
- | |
5852 | break; |
- | |
5853 | default: |
- | |
5854 | /* int case */ |
- | |
5855 | switch(sbt) { |
- | |
5856 | case VT_FLOAT: vtop->c.i = (int)vtop->c.d; break; |
- | |
5857 | case VT_DOUBLE: vtop->c.i = (int)vtop->c.d; break; |
- | |
5858 | case VT_LDOUBLE: vtop->c.i = (int)vtop->c.d; break; |
- | |
5859 | } |
- | |
5860 | break; |
- | |
5861 | } |
- | |
5862 | } else { |
63 | #endif |
5863 | do_ftoi: |
- | |
5864 | gen_cvt_ftoi1(dbt); |
- | |
5865 | } |
- | |
5866 | if (dbt == VT_INT && (type->t & (VT_BTYPE | VT_UNSIGNED)) != dbt) { |
- | |
5867 | /* additional cast for char/short/bool... */ |
- | |
5868 | vtop->type.t = dbt; |
64 | ")\n", TCC_VERSION); |
5869 | gen_cast(type); |
- | |
5870 | } |
- | |
5871 | } else if ((dbt & VT_BTYPE) == VT_LLONG) { |
- | |
5872 | if ((sbt & VT_BTYPE) != VT_LLONG) { |
- | |
5873 | /* scalar to long long */ |
- | |
5874 | if (c) { |
- | |
5875 | if (sbt == (VT_INT | VT_UNSIGNED)) |
- | |
5876 | vtop->c.ll = vtop->c.ui; |
- | |
5877 | else |
- | |
5878 | vtop->c.ll = vtop->c.i; |
- | |
5879 | } else { |
65 | break; |
5880 | /* machine independent conversion */ |
- | |
5881 | gv(RC_INT); |
- | |
5882 | /* generate high word */ |
- | |
5883 | if (sbt == (VT_INT | VT_UNSIGNED)) { |
- | |
5884 | vpushi(0); |
- | |
5885 | gv(RC_INT); |
- | |
5886 | } else { |
- | |
5887 | gv_dup(); |
- | |
5888 | vpushi(31); |
- | |
5889 | gen_op(TOK_SAR); |
- | |
5890 | } |
- | |
5891 | /* patch second register */ |
- | |
5892 | vtop[-1].r2 = vtop->r; |
- | |
5893 | vpop(); |
- | |
5894 | } |
- | |
5895 | } |
- | |
5896 | } else if (dbt == VT_BOOL) { |
- | |
5897 | /* scalar to bool */ |
- | |
5898 | vpushi(0); |
- | |
5899 | gen_op(TOK_NE); |
- | |
5900 | } else if ((dbt & VT_BTYPE) == VT_BYTE || |
- | |
5901 | (dbt & VT_BTYPE) == VT_SHORT) { |
- | |
5902 | force_charshort_cast(dbt); |
- | |
5903 | } else if ((dbt & VT_BTYPE) == VT_INT) { |
- | |
5904 | /* scalar to int */ |
- | |
5905 | if (sbt == VT_LLONG) { |
- | |
5906 | /* from long long: just take low order word */ |
- | |
5907 | lexpand(); |
66 | case 1: |
5908 | vpop(); |
67 | printf("install: %s\n", s->tcc_lib_path); |
5909 | } |
- | |
5910 | /* if lvalue and single word type, nothing to do because |
- | |
5911 | the lvalue already contains the real type size (see |
- | |
5912 | VT_LVAL_xxx constants) */ |
- | |
5913 | } |
- | |
5914 | } |
- | |
5915 | vtop->type = *type; |
- | |
5916 | } |
- | |
5917 | - | ||
5918 | /* return type size. Put alignment at 'a' */ |
- | |
5919 | static int type_size(CType *type, int *a) |
- | |
5920 | { |
- | |
5921 | Sym *s; |
- | |
5922 | int bt; |
- | |
5923 | int size; |
68 | /* print_paths("programs", NULL, 0); */ |
5924 | - | ||
5925 | bt = type->t & VT_BTYPE; |
- | |
5926 | if (bt == VT_STRUCT) { |
- | |
5927 | /* struct/union */ |
- | |
5928 | s = type->ref; |
- | |
5929 | *a = s->r; |
- | |
5930 | - | ||
5931 | return s->c; |
- | |
5932 | } else if (bt == VT_PTR) { |
- | |
5933 | - | ||
5934 | if (type->t & VT_ARRAY) { |
69 | print_paths("include", s->sysinclude_paths, s->nb_sysinclude_paths); |
5935 | s = type->ref; |
- | |
5936 | size=type_size(&s->type, a) * s->c; |
- | |
5937 | return size;//type_size(&s->type, a) * s->c; |
- | |
5938 | } else { |
- | |
5939 | *a = PTR_SIZE; |
- | |
5940 | return PTR_SIZE; |
- | |
5941 | } |
- | |
5942 | } else if (bt == VT_LDOUBLE) { |
70 | print_paths("libraries", s->library_paths, s->nb_library_paths); |
5943 | *a = LDOUBLE_ALIGN; |
- | |
5944 | return LDOUBLE_SIZE; |
- | |
5945 | } else if (bt == VT_DOUBLE || bt == VT_LLONG) { |
- | |
5946 | #ifdef TCC_TARGET_I386 |
- | |
5947 | *a = 4; |
71 | #ifndef TCC_TARGET_PE |
5948 | #else |
- | |
5949 | *a = 8; |
- | |
5950 | #endif |
- | |
5951 | return 8; |
- | |
5952 | } else if (bt == VT_INT || bt == VT_ENUM || bt == VT_FLOAT) { |
- | |
5953 | *a = 4; |
- | |
5954 | return 4; |
- | |
5955 | } else if (bt == VT_SHORT) { |
- | |
5956 | *a = 2; |
- | |
5957 | return 2; |
- | |
5958 | } else { |
- | |
5959 | /* char, void, function, _Bool */ |
- | |
5960 | *a = 1; |
- | |
5961 | return 1; |
- | |
5962 | } |
- | |
5963 | } |
- | |
5964 | - | ||
5965 | /* return the pointed type of t */ |
- | |
5966 | static inline CType *pointed_type(CType *type) |
- | |
5967 | { |
- | |
5968 | return &type->ref->type; |
- | |
5969 | } |
- | |
5970 | - | ||
5971 | /* modify type so that its it is a pointer to type. */ |
- | |
5972 | static void mk_pointer(CType *type) |
- | |
5973 | { |
- | |
5974 | Sym *s; |
- | |
5975 | s = sym_push(SYM_FIELD, type, 0, -1); |
- | |
5976 | type->t = VT_PTR | (type->t & ~VT_TYPE); |
- | |
5977 | type->ref = s; |
- | |
5978 | } |
- | |
5979 | - | ||
5980 | /* compare function types. OLD functions match any new functions */ |
- | |
5981 | static int is_compatible_func(CType *type1, CType *type2) |
- | |
5982 | { |
- | |
5983 | Sym *s1, *s2; |
- | |
5984 | - | ||
5985 | s1 = type1->ref; |
- | |
5986 | s2 = type2->ref; |
- | |
5987 | if (!is_compatible_types(&s1->type, &s2->type)) |
- | |
5988 | return 0; |
- | |
5989 | /* check func_call */ |
- | |
5990 | if (s1->r != s2->r) |
- | |
5991 | return 0; |
- | |
5992 | /* XXX: not complete */ |
- | |
5993 | if (s1->c == FUNC_OLD || s2->c == FUNC_OLD) |
- | |
5994 | return 1; |
- | |
5995 | if (s1->c != s2->c) |
- | |
5996 | return 0; |
- | |
5997 | while (s1 != NULL) { |
- | |
5998 | if (s2 == NULL) |
- | |
5999 | return 0; |
- | |
6000 | if (!is_compatible_types(&s1->type, &s2->type)) |
- | |
6001 | return 0; |
- | |
6002 | s1 = s1->next; |
- | |
6003 | s2 = s2->next; |
- | |
6004 | } |
- | |
6005 | if (s2) |
- | |
6006 | return 0; |
- | |
6007 | return 1; |
- | |
6008 | } |
- | |
6009 | - | ||
6010 | /* return true if type1 and type2 are exactly the same (including |
- | |
6011 | qualifiers). |
- | |
6012 | - | ||
6013 | - enums are not checked as gcc __builtin_types_compatible_p () |
- | |
6014 | */ |
- | |
6015 | static int is_compatible_types(CType *type1, CType *type2) |
- | |
6016 | { |
- | |
6017 | int bt1, t1, t2; |
- | |
6018 | - | ||
6019 | t1 = type1->t & VT_TYPE; |
- | |
6020 | t2 = type2->t & VT_TYPE; |
- | |
6021 | /* XXX: bitfields ? */ |
- | |
6022 | if (t1 != t2) |
- | |
6023 | return 0; |
- | |
6024 | /* test more complicated cases */ |
- | |
6025 | bt1 = t1 & VT_BTYPE; |
- | |
6026 | if (bt1 == VT_PTR) { |
- | |
6027 | type1 = pointed_type(type1); |
- | |
6028 | type2 = pointed_type(type2); |
- | |
6029 | return is_compatible_types(type1, type2); |
- | |
6030 | } else if (bt1 == VT_STRUCT) { |
- | |
6031 | return (type1->ref == type2->ref); |
- | |
6032 | } else if (bt1 == VT_FUNC) { |
- | |
6033 | return is_compatible_func(type1, type2); |
- | |
6034 | } else { |
- | |
6035 | return 1; |
- | |
6036 | } |
- | |
6037 | } |
- | |
6038 | - | ||
6039 | /* print a type. If 'varstr' is not NULL, then the variable is also |
- | |
6040 | printed in the type */ |
- | |
6041 | /* XXX: union */ |
- | |
6042 | /* XXX: add array and function pointers */ |
- | |
6043 | void type_to_str(char *buf, int buf_size, |
- | |
6044 | CType *type, const char *varstr) |
- | |
6045 | { |
- | |
6046 | int bt, v, t; |
- | |
6047 | Sym *s, *sa; |
- | |
6048 | char buf1[256]; |
- | |
6049 | const char *tstr; |
- | |
6050 | - | ||
6051 | t = type->t & VT_TYPE; |
- | |
6052 | bt = t & VT_BTYPE; |
- | |
6053 | buf[0] = '\0'; |
- | |
6054 | if (t & VT_CONSTANT) |
- | |
6055 | pstrcat(buf, buf_size, "const "); |
- | |
6056 | if (t & VT_VOLATILE) |
- | |
6057 | pstrcat(buf, buf_size, "volatile "); |
- | |
6058 | if (t & VT_UNSIGNED) |
- | |
6059 | pstrcat(buf, buf_size, "unsigned "); |
- | |
6060 | switch(bt) { |
- | |
6061 | case VT_VOID: |
- | |
6062 | tstr = "void"; |
- | |
6063 | goto add_tstr; |
- | |
6064 | case VT_BOOL: |
- | |
6065 | tstr = "_Bool"; |
- | |
6066 | goto add_tstr; |
- | |
6067 | case VT_BYTE: |
- | |
6068 | tstr = "char"; |
- | |
6069 | goto add_tstr; |
- | |
6070 | case VT_SHORT: |
- | |
6071 | tstr = "short"; |
- | |
6072 | goto add_tstr; |
- | |
6073 | case VT_INT: |
- | |
6074 | tstr = "int"; |
- | |
6075 | goto add_tstr; |
- | |
6076 | case VT_LONG: |
- | |
6077 | tstr = "long"; |
- | |
6078 | goto add_tstr; |
- | |
6079 | case VT_LLONG: |
- | |
6080 | tstr = "long long"; |
- | |
6081 | goto add_tstr; |
- | |
6082 | case VT_FLOAT: |
- | |
6083 | tstr = "float"; |
- | |
6084 | goto add_tstr; |
- | |
6085 | case VT_DOUBLE: |
- | |
6086 | tstr = "double"; |
- | |
6087 | goto add_tstr; |
- | |
6088 | case VT_LDOUBLE: |
- | |
6089 | tstr = "long double"; |
- | |
6090 | add_tstr: |
- | |
6091 | pstrcat(buf, buf_size, tstr); |
- | |
6092 | break; |
- | |
6093 | case VT_ENUM: |
- | |
6094 | case VT_STRUCT: |
- | |
6095 | if (bt == VT_STRUCT) |
- | |
6096 | tstr = "struct "; |
- | |
6097 | else |
- | |
6098 | tstr = "enum "; |
- | |
6099 | pstrcat(buf, buf_size, tstr); |
- | |
6100 | v = type->ref->v & ~SYM_STRUCT; |
- | |
6101 | if (v >= SYM_FIRST_ANOM) |
- | |
6102 | pstrcat(buf, buf_size, " |
- | |
6103 | else |
- | |
6104 | pstrcat(buf, buf_size, get_tok_str(v, NULL)); |
- | |
6105 | break; |
- | |
6106 | case VT_FUNC: |
- | |
6107 | s = type->ref; |
- | |
6108 | type_to_str(buf, buf_size, &s->type, varstr); |
- | |
6109 | pstrcat(buf, buf_size, "("); |
- | |
6110 | sa = s->next; |
- | |
6111 | while (sa != NULL) { |
- | |
6112 | type_to_str(buf1, sizeof(buf1), &sa->type, NULL); |
- | |
6113 | pstrcat(buf, buf_size, buf1); |
- | |
6114 | sa = sa->next; |
- | |
6115 | if (sa) |
- | |
6116 | pstrcat(buf, buf_size, ", "); |
- | |
6117 | } |
- | |
6118 | pstrcat(buf, buf_size, ")"); |
- | |
6119 | goto no_var; |
- | |
6120 | case VT_PTR: |
- | |
6121 | s = type->ref; |
- | |
6122 | pstrcpy(buf1, sizeof(buf1), "*"); |
- | |
6123 | if (varstr) |
- | |
6124 | pstrcat(buf1, sizeof(buf1), varstr); |
- | |
6125 | type_to_str(buf, buf_size, &s->type, buf1); |
- | |
6126 | goto no_var; |
- | |
6127 | } |
- | |
6128 | if (varstr) { |
- | |
6129 | pstrcat(buf, buf_size, " "); |
- | |
6130 | pstrcat(buf, buf_size, varstr); |
- | |
6131 | } |
- | |
6132 | no_var: ; |
- | |
6133 | } |
- | |
6134 | - | ||
6135 | /* verify type compatibility to store vtop in 'dt' type, and generate |
- | |
6136 | casts if needed. */ |
- | |
6137 | static void gen_assign_cast(CType *dt) |
- | |
6138 | { |
- | |
6139 | CType *st, *type1, *type2, tmp_type1, tmp_type2; |
- | |
6140 | char buf1[256], buf2[256]; |
- | |
6141 | int dbt, sbt; |
- | |
6142 | - | ||
6143 | st = &vtop->type; /* source type */ |
- | |
6144 | dbt = dt->t & VT_BTYPE; |
- | |
6145 | sbt = st->t & VT_BTYPE; |
- | |
6146 | if (dt->t & VT_CONSTANT) |
- | |
6147 | warning("assignment of read-only location"); |
- | |
6148 | switch(dbt) { |
- | |
6149 | case VT_PTR: |
- | |
6150 | /* special cases for pointers */ |
- | |
6151 | /* '0' can also be a pointer */ |
- | |
6152 | if (is_null_pointer(vtop)) |
- | |
6153 | goto type_ok; |
- | |
6154 | /* accept implicit pointer to integer cast with warning */ |
- | |
6155 | if (is_integer_btype(sbt)) { |
- | |
6156 | warning("assignment makes pointer from integer without a cast"); |
- | |
6157 | goto type_ok; |
- | |
6158 | } |
- | |
6159 | type1 = pointed_type(dt); |
- | |
6160 | /* a function is implicitely a function pointer */ |
- | |
6161 | if (sbt == VT_FUNC) { |
- | |
6162 | if ((type1->t & VT_BTYPE) != VT_VOID && |
- | |
6163 | !is_compatible_types(pointed_type(dt), st)) |
- | |
6164 | goto error; |
- | |
6165 | else |
- | |
6166 | goto type_ok; |
- | |
6167 | } |
- | |
6168 | if (sbt != VT_PTR) |
- | |
6169 | goto error; |
- | |
6170 | type2 = pointed_type(st); |
- | |
6171 | if ((type1->t & VT_BTYPE) == VT_VOID || |
- | |
6172 | (type2->t & VT_BTYPE) == VT_VOID) { |
- | |
6173 | /* void * can match anything */ |
- | |
6174 | } else { |
- | |
6175 | /* exact type match, except for unsigned */ |
- | |
6176 | tmp_type1 = *type1; |
- | |
6177 | tmp_type2 = *type2; |
- | |
6178 | tmp_type1.t &= ~(VT_UNSIGNED | VT_CONSTANT | VT_VOLATILE); |
- | |
6179 | tmp_type2.t &= ~(VT_UNSIGNED | VT_CONSTANT | VT_VOLATILE); |
- | |
6180 | if (!is_compatible_types(&tmp_type1, &tmp_type2)) |
- | |
6181 | goto error; |
- | |
6182 | } |
- | |
6183 | /* check const and volatile */ |
- | |
6184 | if ((!(type1->t & VT_CONSTANT) && (type2->t & VT_CONSTANT)) || |
- | |
6185 | (!(type1->t & VT_VOLATILE) && (type2->t & VT_VOLATILE))) |
- | |
6186 | warning("assignment discards qualifiers from pointer target type"); |
- | |
6187 | break; |
- | |
6188 | case VT_BYTE: |
- | |
6189 | case VT_SHORT: |
- | |
6190 | case VT_INT: |
- | |
6191 | case VT_LLONG: |
- | |
6192 | if (sbt == VT_PTR || sbt == VT_FUNC) { |
- | |
6193 | warning("assignment makes integer from pointer without a cast"); |
- | |
6194 | } |
- | |
6195 | /* XXX: more tests */ |
- | |
6196 | break; |
- | |
6197 | case VT_STRUCT: |
- | |
6198 | tmp_type1 = *dt; |
- | |
6199 | tmp_type2 = *st; |
- | |
6200 | tmp_type1.t &= ~(VT_CONSTANT | VT_VOLATILE); |
- | |
6201 | tmp_type2.t &= ~(VT_CONSTANT | VT_VOLATILE); |
- | |
6202 | if (!is_compatible_types(&tmp_type1, &tmp_type2)) { |
- | |
6203 | error: |
- | |
6204 | type_to_str(buf1, sizeof(buf1), st, NULL); |
- | |
6205 | type_to_str(buf2, sizeof(buf2), dt, NULL); |
72 | print_paths("crt", s->crt_paths, s->nb_crt_paths); |
6206 | error("cannot cast '%s' to '%s'", buf1, buf2); |
73 | printf("elfinterp:\n %s\n", DEFAULT_ELFINTERP(s)); |
6207 | } |
- | |
6208 | break; |
- | |
6209 | } |
74 | #endif |
Line 6210... | Line -... | ||
6210 | type_ok: |
- | |
6211 | gen_cast(dt); |
75 | break; |
6212 | } |
76 | } |
6213 | 77 | } |
|
6214 | /* store vtop in lvalue pushed on stack */ |
- | |
6215 | void vstore(void) |
- | |
6216 | { |
- | |
6217 | int sbt, dbt, ft, r, t, size, align, bit_size, bit_pos, rc, delayed_cast; |
- | |
6218 | 78 | ||
6219 | ft = vtop[-1].type.t; |
79 | static void help(void) |
6220 | sbt = vtop->type.t & VT_BTYPE; |
80 | { |
6221 | dbt = ft & VT_BTYPE; |
81 | printf("Tiny C Compiler "TCC_VERSION" - Copyright (C) 2001-2006 Fabrice Bellard\n" |
6222 | if (((sbt == VT_INT || sbt == VT_SHORT) && dbt == VT_BYTE) || |
82 | "Usage: tcc [options...] [-o outfile] [-c] infile(s)...\n" |
6223 | (sbt == VT_INT && dbt == VT_SHORT)) { |
83 | " tcc [options...] -run infile [arguments...]\n" |
6224 | /* optimize char/short casts */ |
84 | "General options:\n" |
6225 | delayed_cast = VT_MUSTCAST; |
85 | " -c compile only - generate an object file\n" |
6226 | vtop->type.t = ft & VT_TYPE; |
- | |
6227 | /* XXX: factorize */ |
86 | " -o outfile set output filename\n" |
6228 | if (ft & VT_CONSTANT) |
87 | " -run run compiled source\n" |
6229 | warning("assignment of read-only location"); |
88 | " -fflag set or reset (with 'no-' prefix) 'flag' (see man page)\n" |
6230 | } else { |
- | |
6231 | delayed_cast = 0; |
- | |
6232 | if (!(ft & VT_BITFIELD)) |
89 | " -Wwarning set or reset (with 'no-' prefix) 'warning' (see man page)\n" |
6233 | gen_assign_cast(&vtop[-1].type); |
90 | " -w disable all warnings\n" |
6234 | } |
91 | " -v show version\n" |
6235 | - | ||
6236 | if (sbt == VT_STRUCT) { |
- | |
6237 | /* if structure, only generate pointer */ |
92 | " -vv show included files (as sole argument: show search paths)\n" |
6238 | /* structure assignment : generate memcpy */ |
- | |
6239 | /* XXX: optimize if small size */ |
93 | " -dumpversion\n" |
6240 | if (!nocode_wanted) { |
- | |
6241 | size = type_size(&vtop->type, &align); |
94 | " -bench show compilation statistics\n" |
6242 | 95 | " -xc -xa specify type of the next infile\n" |
|
6243 | vpush_global_sym(&func_old_type, TOK_memcpy); |
96 | " - use stdin pipe as infile\n" |
6244 | - | ||
6245 | /* destination */ |
97 | " @listfile read line separated arguments from 'listfile'\n" |
6246 | vpushv(vtop - 2); |
98 | "Preprocessor options:\n" |
6247 | vtop->type.t = VT_INT; |
99 | " -Idir add include path 'dir'\n" |
6248 | gaddrof(); |
100 | " -Dsym[=val] define 'sym' with value 'val'\n" |
6249 | /* source */ |
101 | " -Usym undefine 'sym'\n" |
6250 | vpushv(vtop - 2); |
102 | " -E preprocess only\n" |
6251 | vtop->type.t = VT_INT; |
103 | " -P[1] no/alternative output of #line directives\n" |
6252 | gaddrof(); |
- | |
6253 | /* type size */ |
- | |
6254 | vpushi(size); |
- | |
6255 | gfunc_call(3); |
- | |
6256 | - | ||
6257 | vswap(); |
- | |
6258 | vpop(); |
- | |
6259 | } else { |
104 | " -d{D|M} dump defines\n" |
6260 | vswap(); |
- | |
6261 | vpop(); |
105 | " -C keep comments\n" |
6262 | } |
106 | "Linker options:\n" |
6263 | /* leave source on stack */ |
107 | " -Ldir add library path 'dir'\n" |
6264 | } else if (ft & VT_BITFIELD) { |
108 | " -llib link with dynamic or static library 'lib'\n" |
6265 | /* bitfield store handling */ |
109 | " -pthread link with -lpthread and -D_REENTRANT (POSIX Linux)\n" |
6266 | bit_pos = (ft >> VT_STRUCT_SHIFT) & 0x3f; |
- | |
6267 | bit_size = (ft >> (VT_STRUCT_SHIFT + 6)) & 0x3f; |
110 | " -r generate (relocatable) object file\n" |
6268 | /* remove bit field info to avoid loops */ |
- | |
6269 | vtop[-1].type.t = ft & ~(VT_BITFIELD | (-1 << VT_STRUCT_SHIFT)); |
- | |
6270 | - | ||
6271 | /* duplicate destination */ |
111 | " -rdynamic export all global symbols to dynamic linker\n" |
6272 | vdup(); |
112 | " -shared generate a shared library\n" |
6273 | vtop[-1] = vtop[-2]; |
- | |
6274 | - | ||
6275 | /* mask and shift source */ |
- | |
6276 | vpushi((1 << bit_size) - 1); |
113 | " -soname set name for shared library to be used at runtime\n" |
6277 | gen_op('&'); |
- | |
6278 | vpushi(bit_pos); |
- | |
6279 | gen_op(TOK_SHL); |
- | |
6280 | /* load destination, mask and or with source */ |
- | |
6281 | vswap(); |
- | |
6282 | vpushi(~(((1 << bit_size) - 1) << bit_pos)); |
- | |
6283 | gen_op('&'); |
- | |
6284 | gen_op('|'); |
114 | " -static static linking\n" |
6285 | /* store result */ |
- | |
6286 | vstore(); |
- | |
6287 | } else { |
- | |
6288 | #ifdef CONFIG_TCC_BCHECK |
- | |
6289 | /* bound check case */ |
- | |
6290 | if (vtop[-1].r & VT_MUSTBOUND) { |
- | |
6291 | vswap(); |
- | |
6292 | gbound(); |
- | |
6293 | vswap(); |
- | |
6294 | } |
- | |
6295 | #endif |
- | |
6296 | if (!nocode_wanted) { |
- | |
6297 | rc = RC_INT; |
- | |
6298 | if (is_float(ft)) |
- | |
6299 | rc = RC_FLOAT; |
- | |
6300 | r = gv(rc); /* generate value */ |
- | |
6301 | /* if lvalue was saved on stack, must read it */ |
- | |
6302 | if ((vtop[-1].r & VT_VALMASK) == VT_LLOCAL) { |
- | |
6303 | SValue sv; |
- | |
6304 | t = get_reg(RC_INT); |
- | |
6305 | sv.type.t = VT_INT; |
- | |
6306 | sv.r = VT_LOCAL | VT_LVAL; |
- | |
6307 | sv.c.ul = vtop[-1].c.ul; |
- | |
6308 | load(t, &sv); |
- | |
6309 | vtop[-1].r = t | VT_LVAL; |
- | |
6310 | } |
- | |
6311 | store(r, vtop - 1); |
- | |
6312 | /* two word case handling : store second register at word + 4 */ |
- | |
6313 | if ((ft & VT_BTYPE) == VT_LLONG) { |
- | |
6314 | vswap(); |
- | |
6315 | /* convert to int to increment easily */ |
- | |
6316 | vtop->type.t = VT_INT; |
- | |
6317 | gaddrof(); |
- | |
6318 | vpushi(4); |
- | |
6319 | gen_op('+'); |
- | |
6320 | vtop->r |= VT_LVAL; |
- | |
6321 | vswap(); |
- | |
6322 | /* XXX: it works because r2 is spilled last ! */ |
- | |
6323 | store(vtop->r2, vtop - 1); |
- | |
6324 | } |
- | |
6325 | } |
- | |
6326 | vswap(); |
- | |
6327 | vtop--; /* NOT vpop() because on x86 it would flush the fp stack */ |
- | |
6328 | vtop->r |= delayed_cast; |
- | |
6329 | } |
- | |
6330 | } |
- | |
6331 | - | ||
6332 | /* post defines POST/PRE add. c is the token ++ or -- */ |
- | |
6333 | void inc(int post, int c) |
- | |
6334 | { |
- | |
6335 | test_lvalue(); |
- | |
6336 | vdup(); /* save lvalue */ |
- | |
6337 | if (post) { |
- | |
6338 | gv_dup(); /* duplicate value */ |
- | |
6339 | vrotb(3); |
- | |
6340 | vrotb(3); |
- | |
6341 | } |
- | |
6342 | /* add constant */ |
- | |
6343 | vpushi(c - TOK_MID); |
- | |
6344 | gen_op('+'); |
- | |
6345 | vstore(); /* store value */ |
- | |
6346 | if (post) |
- | |
6347 | vpop(); /* if post op, return saved value */ |
- | |
6348 | } |
- | |
6349 | - | ||
6350 | /* Parse GNUC __attribute__ extension. Currently, the following |
- | |
6351 | extensions are recognized: |
- | |
6352 | - aligned(n) : set data/function alignment. |
- | |
6353 | - packed : force data alignment to 1 |
- | |
6354 | - section(x) : generate data/code in this section. |
- | |
6355 | - unused : currently ignored, but may be used someday. |
- | |
6356 | - regparm(n) : pass function parameters in registers (i386 only) |
- | |
6357 | */ |
- | |
6358 | static void parse_attribute(AttributeDef *ad) |
- | |
6359 | { |
- | |
6360 | int t, n; |
- | |
6361 | - | ||
6362 | while (tok == TOK_ATTRIBUTE1 || tok == TOK_ATTRIBUTE2) { |
- | |
6363 | next(); |
- | |
6364 | skip('('); |
- | |
6365 | skip('('); |
- | |
6366 | while (tok != ')') { |
- | |
6367 | if (tok < TOK_IDENT) |
- | |
6368 | expect("attribute name"); |
- | |
6369 | t = tok; |
- | |
6370 | next(); |
- | |
6371 | switch(t) { |
- | |
6372 | case TOK_SECTION1: |
- | |
6373 | case TOK_SECTION2: |
- | |
6374 | skip('('); |
- | |
6375 | if (tok != TOK_STR) |
- | |
6376 | expect("section name"); |
- | |
6377 | ad->section = find_section(tcc_state, (char *)tokc.cstr->data); |
- | |
6378 | next(); |
- | |
6379 | skip(')'); |
- | |
6380 | break; |
- | |
6381 | case TOK_ALIGNED1: |
- | |
6382 | case TOK_ALIGNED2: |
- | |
6383 | if (tok == '(') { |
- | |
6384 | next(); |
- | |
6385 | n = expr_const(); |
- | |
6386 | if (n <= 0 || (n & (n - 1)) != 0) |
- | |
6387 | error("alignment must be a positive power of two"); |
- | |
6388 | skip(')'); |
- | |
6389 | } else { |
- | |
6390 | n = MAX_ALIGN; |
- | |
6391 | } |
- | |
6392 | ad->aligned = n; |
- | |
6393 | break; |
- | |
6394 | case TOK_PACKED1: |
- | |
6395 | case TOK_PACKED2: |
- | |
6396 | ad->packed = 1; |
- | |
6397 | break; |
- | |
6398 | case TOK_UNUSED1: |
- | |
6399 | case TOK_UNUSED2: |
- | |
6400 | /* currently, no need to handle it because tcc does not |
- | |
6401 | track unused objects */ |
- | |
6402 | break; |
- | |
6403 | case TOK_NORETURN1: |
- | |
6404 | case TOK_NORETURN2: |
- | |
6405 | /* currently, no need to handle it because tcc does not |
- | |
6406 | track unused objects */ |
- | |
6407 | break; |
- | |
6408 | case TOK_CDECL1: |
- | |
6409 | case TOK_CDECL2: |
- | |
6410 | case TOK_CDECL3: |
- | |
6411 | ad->func_call = FUNC_CDECL; |
- | |
6412 | break; |
- | |
6413 | case TOK_STDCALL1: |
- | |
6414 | case TOK_STDCALL2: |
- | |
6415 | case TOK_STDCALL3: |
- | |
6416 | ad->func_call = FUNC_STDCALL; |
- | |
6417 | break; |
- | |
6418 | #ifdef TCC_TARGET_I386 |
- | |
6419 | case TOK_REGPARM1: |
- | |
6420 | case TOK_REGPARM2: |
- | |
6421 | skip('('); |
- | |
6422 | n = expr_const(); |
- | |
6423 | if (n > 3) |
- | |
6424 | n = 3; |
- | |
6425 | else if (n < 0) |
- | |
6426 | n = 0; |
- | |
6427 | if (n > 0) |
- | |
6428 | ad->func_call = FUNC_FASTCALL1 + n - 1; |
- | |
6429 | skip(')'); |
- | |
6430 | break; |
- | |
6431 | #endif |
- | |
6432 | case TOK_DLLEXPORT: |
- | |
6433 | ad->dllexport = 1; |
- | |
6434 | break; |
- | |
6435 | default: |
- | |
6436 | if (tcc_state->warn_unsupported) |
- | |
6437 | warning("'%s' attribute ignored", get_tok_str(t, NULL)); |
- | |
6438 | /* skip parameters */ |
- | |
6439 | /* XXX: skip parenthesis too */ |
- | |
6440 | if (tok == '(') { |
- | |
6441 | next(); |
- | |
6442 | while (tok != ')' && tok != -1) |
- | |
6443 | next(); |
- | |
6444 | next(); |
- | |
6445 | } |
- | |
6446 | break; |
- | |
6447 | } |
- | |
6448 | if (tok != ',') |
- | |
6449 | break; |
- | |
6450 | next(); |
- | |
6451 | } |
- | |
6452 | skip(')'); |
- | |
6453 | skip(')'); |
- | |
6454 | } |
- | |
6455 | } |
- | |
6456 | - | ||
6457 | /* enum/struct/union declaration. u is either VT_ENUM or VT_STRUCT */ |
- | |
6458 | static void struct_decl(CType *type, int u) |
- | |
6459 | { |
- | |
6460 | int a, v, size, align, maxalign, c, offset; |
- | |
6461 | int bit_size, bit_pos, bsize, bt, lbit_pos; |
- | |
6462 | Sym *s, *ss, **ps; |
- | |
6463 | AttributeDef ad; |
- | |
6464 | CType type1, btype; |
- | |
6465 | - | ||
6466 | a = tok; /* save decl type */ |
- | |
6467 | next(); |
- | |
6468 | if (tok != '{') { |
- | |
6469 | v = tok; |
- | |
6470 | next(); |
- | |
6471 | /* struct already defined ? return it */ |
- | |
6472 | if (v < TOK_IDENT) |
- | |
6473 | expect("struct/union/enum name"); |
- | |
6474 | s = struct_find(v); |
- | |
6475 | if (s) { |
- | |
6476 | if (s->type.t != a) |
- | |
6477 | error("invalid type"); |
- | |
6478 | goto do_decl; |
- | |
6479 | } |
- | |
6480 | } else { |
- | |
6481 | v = anon_sym++; |
- | |
6482 | } |
- | |
6483 | type1.t = a; |
- | |
6484 | /* we put an undefined size for struct/union */ |
- | |
6485 | s = sym_push(v | SYM_STRUCT, &type1, 0, -1); |
- | |
6486 | s->r = 0; /* default alignment is zero as gcc */ |
- | |
6487 | /* put struct/union/enum name in type */ |
- | |
6488 | do_decl: |
- | |
6489 | type->t = u; |
- | |
6490 | type->ref = s; |
- | |
6491 | - | ||
6492 | if (tok == '{') { |
- | |
6493 | next(); |
- | |
6494 | if (s->c != -1) |
- | |
6495 | error("struct/union/enum already defined"); |
- | |
6496 | /* cannot be empty */ |
- | |
6497 | c = 0; |
- | |
6498 | /* non empty enums are not allowed */ |
- | |
6499 | if (a == TOK_ENUM) { |
- | |
6500 | for(;;) { |
- | |
6501 | v = tok; |
- | |
6502 | if (v < TOK_UIDENT) |
- | |
6503 | expect("identifier"); |
- | |
6504 | next(); |
- | |
6505 | if (tok == '=') { |
- | |
6506 | next(); |
- | |
6507 | c = expr_const(); |
- | |
6508 | } |
- | |
6509 | /* enum symbols have static storage */ |
- | |
6510 | ss = sym_push(v, &int_type, VT_CONST, c); |
- | |
6511 | ss->type.t |= VT_STATIC; |
- | |
6512 | if (tok != ',') |
- | |
6513 | break; |
- | |
6514 | next(); |
- | |
6515 | c++; |
- | |
6516 | /* NOTE: we accept a trailing comma */ |
- | |
6517 | if (tok == '}') |
- | |
6518 | break; |
- | |
6519 | } |
- | |
6520 | skip('}'); |
- | |
6521 | } else { |
- | |
6522 | maxalign = 1; |
- | |
6523 | ps = &s->next; |
- | |
6524 | bit_pos = 0; |
- | |
6525 | offset = 0; |
- | |
6526 | while (tok != '}') { |
- | |
6527 | parse_btype(&btype, &ad); |
- | |
6528 | while (1) { |
- | |
6529 | bit_size = -1; |
- | |
6530 | v = 0; |
- | |
6531 | type1 = btype; |
- | |
6532 | if (tok != ':') { |
- | |
6533 | type_decl(&type1, &ad, &v, TYPE_DIRECT); |
- | |
6534 | if ((type1.t & VT_BTYPE) == VT_FUNC || |
- | |
6535 | (type1.t & (VT_TYPEDEF | VT_STATIC | VT_EXTERN | VT_INLINE))) |
- | |
6536 | error("invalid type for '%s'", |
- | |
6537 | get_tok_str(v, NULL)); |
- | |
6538 | } |
- | |
6539 | if (tok == ':') { |
- | |
6540 | next(); |
- | |
6541 | bit_size = expr_const(); |
- | |
6542 | /* XXX: handle v = 0 case for messages */ |
- | |
6543 | if (bit_size < 0) |
- | |
6544 | error("negative width in bit-field '%s'", |
- | |
6545 | get_tok_str(v, NULL)); |
- | |
6546 | if (v && bit_size == 0) |
- | |
6547 | error("zero width for bit-field '%s'", |
- | |
6548 | get_tok_str(v, NULL)); |
- | |
6549 | } |
- | |
6550 | size = type_size(&type1, &align); |
- | |
6551 | if (ad.aligned) { |
- | |
6552 | if (align < ad.aligned) |
- | |
6553 | align = ad.aligned; |
- | |
6554 | } else if (ad.packed) { |
- | |
6555 | align = 1; |
- | |
6556 | } else if (*tcc_state->pack_stack_ptr) { |
- | |
6557 | if (align > *tcc_state->pack_stack_ptr) |
- | |
6558 | align = *tcc_state->pack_stack_ptr; |
- | |
6559 | } |
- | |
6560 | lbit_pos = 0; |
- | |
6561 | if (bit_size >= 0) { |
- | |
6562 | bt = type1.t & VT_BTYPE; |
- | |
6563 | if (bt != VT_INT && |
- | |
6564 | bt != VT_BYTE && |
- | |
6565 | bt != VT_SHORT && |
- | |
6566 | bt != VT_BOOL && |
- | |
6567 | bt != VT_ENUM) |
- | |
6568 | error("bitfields must have scalar type"); |
- | |
6569 | bsize = size * 8; |
- | |
6570 | if (bit_size > bsize) { |
- | |
6571 | error("width of '%s' exceeds its type", |
- | |
6572 | get_tok_str(v, NULL)); |
- | |
6573 | } else if (bit_size == bsize) { |
- | |
6574 | /* no need for bit fields */ |
- | |
6575 | bit_pos = 0; |
- | |
6576 | } else if (bit_size == 0) { |
- | |
6577 | /* XXX: what to do if only padding in a |
- | |
6578 | structure ? */ |
- | |
6579 | /* zero size: means to pad */ |
- | |
6580 | if (bit_pos > 0) |
- | |
6581 | bit_pos = bsize; |
- | |
6582 | } else { |
- | |
6583 | /* we do not have enough room ? */ |
- | |
6584 | if ((bit_pos + bit_size) > bsize) |
- | |
6585 | bit_pos = 0; |
- | |
6586 | lbit_pos = bit_pos; |
- | |
6587 | /* XXX: handle LSB first */ |
- | |
6588 | type1.t |= VT_BITFIELD | |
- | |
6589 | (bit_pos << VT_STRUCT_SHIFT) | |
- | |
6590 | (bit_size << (VT_STRUCT_SHIFT + 6)); |
- | |
6591 | bit_pos += bit_size; |
- | |
6592 | } |
- | |
6593 | } else { |
115 | " -Wl,-opt[=val] set linker option (see manual)\n" |
6594 | bit_pos = 0; |
- | |
6595 | } |
- | |
6596 | if (v) { |
- | |
6597 | /* add new memory data only if starting |
- | |
6598 | bit field */ |
- | |
6599 | if (lbit_pos == 0) { |
- | |
6600 | if (a == TOK_STRUCT) { |
- | |
6601 | //17.09.2007 |
- | |
6602 | //c = (c + align - 1) & -align; |
- | |
6603 | offset = c; |
- | |
6604 | //c += size; |
- | |
6605 | if (size<=4) {c=c+size;} |
- | |
6606 | else |
- | |
6607 | {c=c+align;} |
- | |
6608 | } else { |
- | |
6609 | offset = 0; |
- | |
6610 | if (size > c) |
- | |
6611 | c = size; |
- | |
6612 | } |
- | |
6613 | if (align > maxalign) |
- | |
6614 | maxalign = align; |
- | |
6615 | } |
- | |
6616 | #if 0 |
- | |
6617 | printf("add field %s offset=%d", |
- | |
6618 | get_tok_str(v, NULL), offset); |
- | |
6619 | if (type1.t & VT_BITFIELD) { |
- | |
6620 | printf(" pos=%d size=%d", |
- | |
6621 | (type1.t >> VT_STRUCT_SHIFT) & 0x3f, |
116 | "Debugger options:\n" |
6622 | (type1.t >> (VT_STRUCT_SHIFT + 6)) & 0x3f); |
- | |
6623 | } |
- | |
6624 | printf("\n"); |
- | |
6625 | #endif |
- | |
6626 | ss = sym_push(v | SYM_FIELD, &type1, 0, offset); |
- | |
6627 | *ps = ss; |
- | |
6628 | ps = &ss->next; |
- | |
6629 | } |
- | |
6630 | if (tok == ';' || tok == TOK_EOF) |
- | |
6631 | break; |
- | |
6632 | skip(','); |
- | |
6633 | } |
- | |
6634 | skip(';'); |
- | |
6635 | } |
- | |
6636 | skip('}'); |
- | |
6637 | /* store size and alignment */ |
- | |
6638 | s->c = (c + maxalign - 1) & -maxalign; |
- | |
6639 | s->r = maxalign; |
- | |
6640 | } |
- | |
6641 | } |
- | |
6642 | } |
- | |
6643 | - | ||
6644 | /* return 0 if no type declaration. otherwise, return the basic type |
- | |
6645 | and skip it. |
- | |
6646 | */ |
- | |
6647 | static int parse_btype(CType *type, AttributeDef *ad) |
- | |
6648 | { |
- | |
6649 | int t, u, type_found, typespec_found; |
- | |
6650 | Sym *s; |
- | |
6651 | CType type1; |
- | |
6652 | - | ||
6653 | memset(ad, 0, sizeof(AttributeDef)); |
- | |
6654 | type_found = 0; |
- | |
6655 | typespec_found = 0; |
- | |
6656 | t = 0; |
- | |
6657 | while(1) { |
- | |
6658 | switch(tok) { |
- | |
6659 | case TOK_EXTENSION: |
- | |
6660 | /* currently, we really ignore extension */ |
- | |
6661 | next(); |
- | |
6662 | continue; |
- | |
6663 | - | ||
6664 | /* basic types */ |
- | |
6665 | case TOK_CHAR: |
- | |
6666 | u = VT_BYTE; |
- | |
6667 | basic_type: |
- | |
6668 | next(); |
- | |
6669 | basic_type1: |
- | |
6670 | if ((t & VT_BTYPE) != 0) |
- | |
6671 | error("too many basic types"); |
- | |
6672 | t |= u; |
- | |
6673 | typespec_found = 1; |
- | |
6674 | break; |
- | |
6675 | case TOK_VOID: |
- | |
6676 | u = VT_VOID; |
- | |
6677 | goto basic_type; |
- | |
6678 | case TOK_SHORT: |
- | |
6679 | u = VT_SHORT; |
- | |
6680 | goto basic_type; |
- | |
6681 | case TOK_INT: |
- | |
6682 | next(); |
- | |
6683 | typespec_found = 1; |
- | |
6684 | break; |
- | |
6685 | case TOK_LONG: |
- | |
6686 | next(); |
- | |
6687 | if ((t & VT_BTYPE) == VT_DOUBLE) { |
- | |
6688 | t = (t & ~VT_BTYPE) | VT_LDOUBLE; |
- | |
6689 | } else if ((t & VT_BTYPE) == VT_LONG) { |
- | |
6690 | t = (t & ~VT_BTYPE) | VT_LLONG; |
- | |
6691 | } else { |
- | |
6692 | u = VT_LONG; |
- | |
6693 | goto basic_type1; |
- | |
6694 | } |
- | |
6695 | break; |
- | |
6696 | case TOK_BOOL: |
- | |
6697 | u = VT_BOOL; |
- | |
6698 | goto basic_type; |
- | |
6699 | case TOK_FLOAT: |
- | |
6700 | u = VT_FLOAT; |
- | |
6701 | goto basic_type; |
- | |
6702 | case TOK_DOUBLE: |
- | |
6703 | next(); |
- | |
6704 | if ((t & VT_BTYPE) == VT_LONG) { |
- | |
6705 | t = (t & ~VT_BTYPE) | VT_LDOUBLE; |
- | |
6706 | } else { |
- | |
6707 | u = VT_DOUBLE; |
- | |
6708 | goto basic_type1; |
- | |
6709 | } |
- | |
6710 | break; |
- | |
6711 | case TOK_ENUM: |
- | |
6712 | struct_decl(&type1, VT_ENUM); |
- | |
6713 | basic_type2: |
- | |
6714 | u = type1.t; |
- | |
6715 | type->ref = type1.ref; |
- | |
6716 | goto basic_type1; |
- | |
6717 | case TOK_STRUCT: |
- | |
6718 | case TOK_UNION: |
- | |
6719 | struct_decl(&type1, VT_STRUCT); |
- | |
6720 | goto basic_type2; |
- | |
6721 | - | ||
6722 | /* type modifiers */ |
- | |
6723 | case TOK_CONST1: |
- | |
6724 | case TOK_CONST2: |
- | |
6725 | case TOK_CONST3: |
- | |
6726 | t |= VT_CONSTANT; |
- | |
6727 | next(); |
- | |
6728 | break; |
- | |
6729 | case TOK_VOLATILE1: |
- | |
6730 | case TOK_VOLATILE2: |
- | |
6731 | case TOK_VOLATILE3: |
- | |
6732 | t |= VT_VOLATILE; |
- | |
6733 | next(); |
- | |
6734 | break; |
- | |
6735 | case TOK_SIGNED1: |
- | |
6736 | case TOK_SIGNED2: |
- | |
6737 | case TOK_SIGNED3: |
- | |
6738 | typespec_found = 1; |
- | |
6739 | t |= VT_SIGNED; |
- | |
6740 | next(); |
- | |
6741 | break; |
- | |
6742 | case TOK_REGISTER: |
- | |
6743 | case TOK_AUTO: |
- | |
6744 | case TOK_RESTRICT1: |
- | |
6745 | case TOK_RESTRICT2: |
- | |
6746 | case TOK_RESTRICT3: |
- | |
6747 | next(); |
- | |
6748 | break; |
- | |
6749 | case TOK_UNSIGNED: |
- | |
6750 | t |= VT_UNSIGNED; |
- | |
6751 | next(); |
- | |
6752 | typespec_found = 1; |
- | |
6753 | break; |
- | |
6754 | - | ||
6755 | /* storage */ |
- | |
6756 | case TOK_EXTERN: |
- | |
6757 | t |= VT_EXTERN; |
- | |
6758 | next(); |
- | |
6759 | break; |
- | |
6760 | case TOK_STATIC: |
- | |
6761 | t |= VT_STATIC; |
- | |
6762 | next(); |
- | |
6763 | break; |
- | |
6764 | case TOK_TYPEDEF: |
- | |
6765 | t |= VT_TYPEDEF; |
- | |
6766 | next(); |
- | |
6767 | break; |
- | |
6768 | case TOK_INLINE1: |
- | |
6769 | case TOK_INLINE2: |
- | |
6770 | case TOK_INLINE3: |
- | |
6771 | t |= VT_INLINE; |
- | |
6772 | next(); |
- | |
6773 | break; |
- | |
6774 | - | ||
6775 | /* GNUC attribute */ |
- | |
6776 | case TOK_ATTRIBUTE1: |
- | |
6777 | case TOK_ATTRIBUTE2: |
- | |
6778 | parse_attribute(ad); |
- | |
6779 | break; |
- | |
6780 | /* GNUC typeof */ |
- | |
6781 | case TOK_TYPEOF1: |
- | |
6782 | case TOK_TYPEOF2: |
- | |
6783 | case TOK_TYPEOF3: |
- | |
6784 | next(); |
- | |
6785 | parse_expr_type(&type1); |
- | |
6786 | goto basic_type2; |
- | |
6787 | default: |
- | |
6788 | if (typespec_found) |
- | |
6789 | goto the_end; |
- | |
6790 | s = sym_find(tok); |
- | |
6791 | if (!s || !(s->type.t & VT_TYPEDEF)) |
- | |
6792 | goto the_end; |
- | |
6793 | t |= (s->type.t & ~VT_TYPEDEF); |
- | |
6794 | type->ref = s->type.ref; |
- | |
6795 | next(); |
- | |
6796 | break; |
- | |
6797 | } |
- | |
6798 | type_found = 1; |
- | |
6799 | } |
- | |
6800 | the_end: |
- | |
6801 | if ((t & (VT_SIGNED|VT_UNSIGNED)) == (VT_SIGNED|VT_UNSIGNED)) |
- | |
6802 | error("signed and unsigned modifier"); |
- | |
6803 | if (tcc_state->char_is_unsigned) { |
- | |
6804 | if ((t & (VT_SIGNED|VT_UNSIGNED|VT_BTYPE)) == VT_BYTE) |
- | |
6805 | t |= VT_UNSIGNED; |
- | |
6806 | } |
- | |
6807 | t &= ~VT_SIGNED; |
- | |
6808 | - | ||
6809 | /* long is never used as type */ |
- | |
6810 | if ((t & VT_BTYPE) == VT_LONG) |
- | |
6811 | t = (t & ~VT_BTYPE) | VT_INT; |
- | |
6812 | type->t = t; |
- | |
6813 | return type_found; |
- | |
6814 | } |
- | |
6815 | - | ||
6816 | /* convert a function parameter type (array to pointer and function to |
- | |
6817 | function pointer) */ |
- | |
6818 | static inline void convert_parameter_type(CType *pt) |
- | |
6819 | { |
- | |
6820 | /* remove const and volatile qualifiers (XXX: const could be used |
- | |
6821 | to indicate a const function parameter */ |
- | |
6822 | pt->t &= ~(VT_CONSTANT | VT_VOLATILE); |
- | |
6823 | /* array must be transformed to pointer according to ANSI C */ |
- | |
6824 | pt->t &= ~VT_ARRAY; |
- | |
6825 | if ((pt->t & VT_BTYPE) == VT_FUNC) { |
- | |
6826 | mk_pointer(pt); |
- | |
6827 | } |
- | |
6828 | } |
- | |
6829 | - | ||
6830 | static void post_type(CType *type, AttributeDef *ad) |
- | |
6831 | { |
- | |
6832 | int n, l, t1; |
- | |
6833 | Sym **plast, *s, *first; |
- | |
6834 | AttributeDef ad1; |
- | |
6835 | CType pt; |
- | |
6836 | - | ||
6837 | if (tok == '(') { |
- | |
6838 | /* function declaration */ |
- | |
6839 | next(); |
- | |
6840 | l = 0; |
- | |
6841 | first = NULL; |
- | |
6842 | plast = &first; |
- | |
6843 | while (tok != ')') { |
- | |
6844 | /* read param name and compute offset */ |
- | |
6845 | if (l != FUNC_OLD) { |
- | |
6846 | if (!parse_btype(&pt, &ad1)) { |
- | |
6847 | if (l) { |
- | |
6848 | error("invalid type"); |
- | |
6849 | } else { |
- | |
6850 | l = FUNC_OLD; |
- | |
6851 | goto old_proto; |
- | |
6852 | } |
- | |
6853 | } |
- | |
6854 | l = FUNC_NEW; |
- | |
6855 | if ((pt.t & VT_BTYPE) == VT_VOID && tok == ')') |
- | |
6856 | break; |
- | |
6857 | type_decl(&pt, &ad1, &n, TYPE_DIRECT | TYPE_ABSTRACT); |
- | |
6858 | if ((pt.t & VT_BTYPE) == VT_VOID) |
- | |
6859 | error("parameter declared as void"); |
- | |
6860 | } else { |
- | |
6861 | old_proto: |
- | |
6862 | n = tok; |
- | |
6863 | pt.t = VT_INT; |
- | |
6864 | next(); |
- | |
6865 | } |
- | |
6866 | convert_parameter_type(&pt); |
- | |
6867 | s = sym_push(n | SYM_FIELD, &pt, 0, 0); |
- | |
6868 | *plast = s; |
- | |
6869 | plast = &s->next; |
- | |
6870 | if (tok == ',') { |
- | |
6871 | next(); |
- | |
6872 | if (l == FUNC_NEW && tok == TOK_DOTS) { |
- | |
6873 | l = FUNC_ELLIPSIS; |
- | |
6874 | next(); |
- | |
6875 | break; |
- | |
6876 | } |
- | |
6877 | } |
- | |
6878 | } |
- | |
6879 | /* if no parameters, then old type prototype */ |
- | |
6880 | if (l == 0) |
- | |
6881 | l = FUNC_OLD; |
- | |
6882 | skip(')'); |
- | |
6883 | t1 = type->t & VT_STORAGE; |
- | |
6884 | /* NOTE: const is ignored in returned type as it has a special |
- | |
6885 | meaning in gcc / C++ */ |
- | |
6886 | type->t &= ~(VT_STORAGE | VT_CONSTANT); |
- | |
6887 | post_type(type, ad); |
- | |
6888 | /* we push a anonymous symbol which will contain the function prototype */ |
- | |
6889 | s = sym_push(SYM_FIELD, type, ad->func_call, l); |
- | |
6890 | s->next = first; |
- | |
6891 | type->t = t1 | VT_FUNC; |
- | |
6892 | type->ref = s; |
- | |
6893 | } else if (tok == '[') { |
- | |
6894 | /* array definition */ |
- | |
6895 | next(); |
- | |
6896 | n = -1; |
- | |
6897 | if (tok != ']') { |
- | |
6898 | n = expr_const(); |
- | |
6899 | if (n < 0) |
- | |
6900 | error("invalid array size"); |
- | |
6901 | } |
- | |
6902 | skip(']'); |
- | |
6903 | /* parse next post type */ |
- | |
6904 | t1 = type->t & VT_STORAGE; |
- | |
6905 | type->t &= ~VT_STORAGE; |
- | |
6906 | post_type(type, ad); |
- | |
6907 | - | ||
6908 | /* we push a anonymous symbol which will contain the array |
- | |
6909 | element type */ |
- | |
6910 | s = sym_push(SYM_FIELD, type, 0, n); |
- | |
6911 | type->t = t1 | VT_ARRAY | VT_PTR; |
- | |
6912 | type->ref = s; |
- | |
6913 | } |
- | |
6914 | } |
- | |
6915 | - | ||
6916 | /* Parse a type declaration (except basic type), and return the type |
- | |
6917 | in 'type'. 'td' is a bitmask indicating which kind of type decl is |
- | |
6918 | expected. 'type' should contain the basic type. 'ad' is the |
- | |
6919 | attribute definition of the basic type. It can be modified by |
- | |
6920 | type_decl(). |
- | |
6921 | */ |
- | |
6922 | static void type_decl(CType *type, AttributeDef *ad, int *v, int td) |
- | |
6923 | { |
- | |
6924 | Sym *s; |
- | |
6925 | CType type1, *type2; |
- | |
6926 | int qualifiers; |
- | |
6927 | - | ||
6928 | while (tok == '*') { |
- | |
6929 | qualifiers = 0; |
- | |
6930 | redo: |
- | |
6931 | next(); |
- | |
6932 | switch(tok) { |
- | |
6933 | case TOK_CONST1: |
- | |
6934 | case TOK_CONST2: |
- | |
6935 | case TOK_CONST3: |
- | |
6936 | qualifiers |= VT_CONSTANT; |
- | |
6937 | goto redo; |
- | |
6938 | case TOK_VOLATILE1: |
- | |
6939 | case TOK_VOLATILE2: |
- | |
6940 | case TOK_VOLATILE3: |
- | |
6941 | qualifiers |= VT_VOLATILE; |
- | |
6942 | goto redo; |
- | |
6943 | case TOK_RESTRICT1: |
- | |
6944 | case TOK_RESTRICT2: |
- | |
6945 | case TOK_RESTRICT3: |
- | |
6946 | goto redo; |
- | |
6947 | } |
- | |
6948 | mk_pointer(type); |
- | |
6949 | type->t |= qualifiers; |
- | |
6950 | } |
- | |
6951 | - | ||
6952 | /* XXX: clarify attribute handling */ |
- | |
6953 | if (tok == TOK_ATTRIBUTE1 || tok == TOK_ATTRIBUTE2) |
- | |
6954 | parse_attribute(ad); |
- | |
6955 | - | ||
6956 | /* recursive type */ |
- | |
6957 | /* XXX: incorrect if abstract type for functions (e.g. 'int ()') */ |
- | |
6958 | type1.t = 0; /* XXX: same as int */ |
- | |
6959 | if (tok == '(') { |
- | |
6960 | next(); |
- | |
6961 | /* XXX: this is not correct to modify 'ad' at this point, but |
- | |
6962 | the syntax is not clear */ |
- | |
6963 | if (tok == TOK_ATTRIBUTE1 || tok == TOK_ATTRIBUTE2) |
- | |
6964 | parse_attribute(ad); |
- | |
6965 | type_decl(&type1, ad, v, td); |
- | |
6966 | skip(')'); |
- | |
6967 | } else { |
- | |
6968 | /* type identifier */ |
- | |
6969 | if (tok >= TOK_IDENT && (td & TYPE_DIRECT)) { |
- | |
6970 | *v = tok; |
- | |
6971 | next(); |
- | |
6972 | } else { |
- | |
6973 | if (!(td & TYPE_ABSTRACT)) |
- | |
6974 | expect("identifier"); |
- | |
6975 | *v = 0; |
- | |
6976 | } |
- | |
6977 | } |
- | |
6978 | post_type(type, ad); |
- | |
6979 | if (tok == TOK_ATTRIBUTE1 || tok == TOK_ATTRIBUTE2) |
- | |
6980 | parse_attribute(ad); |
- | |
6981 | if (!type1.t) |
- | |
6982 | return; |
- | |
6983 | /* append type at the end of type1 */ |
- | |
6984 | type2 = &type1; |
- | |
6985 | for(;;) { |
- | |
6986 | s = type2->ref; |
- | |
6987 | type2 = &s->type; |
- | |
6988 | if (!type2->t) { |
- | |
6989 | *type2 = *type; |
- | |
6990 | break; |
- | |
6991 | } |
- | |
6992 | } |
- | |
6993 | *type = type1; |
- | |
6994 | } |
- | |
6995 | - | ||
6996 | /* compute the lvalue VT_LVAL_xxx needed to match type t. */ |
- | |
6997 | static int lvalue_type(int t) |
- | |
6998 | { |
- | |
6999 | int bt, r; |
- | |
7000 | r = VT_LVAL; |
- | |
7001 | bt = t & VT_BTYPE; |
- | |
7002 | if (bt == VT_BYTE || bt == VT_BOOL) |
- | |
7003 | r |= VT_LVAL_BYTE; |
- | |
7004 | else if (bt == VT_SHORT) |
- | |
7005 | r |= VT_LVAL_SHORT; |
- | |
7006 | else |
- | |
7007 | return r; |
- | |
7008 | if (t & VT_UNSIGNED) |
- | |
7009 | r |= VT_LVAL_UNSIGNED; |
- | |
7010 | return r; |
- | |
7011 | } |
- | |
7012 | - | ||
7013 | /* indirection with full error checking and bound check */ |
- | |
7014 | static void indir(void) |
- | |
7015 | { |
- | |
7016 | if ((vtop->type.t & VT_BTYPE) != VT_PTR) |
- | |
7017 | expect("pointer"); |
- | |
7018 | if ((vtop->r & VT_LVAL) && !nocode_wanted) |
- | |
7019 | gv(RC_INT); |
- | |
7020 | vtop->type = *pointed_type(&vtop->type); |
- | |
7021 | /* an array is never an lvalue */ |
- | |
7022 | if (!(vtop->type.t & VT_ARRAY)) { |
- | |
7023 | vtop->r |= lvalue_type(vtop->type.t); |
- | |
7024 | /* if bound checking, the referenced pointer must be checked */ |
- | |
7025 | if (do_bounds_check) |
- | |
7026 | vtop->r |= VT_MUSTBOUND; |
- | |
7027 | } |
- | |
7028 | } |
- | |
7029 | - | ||
7030 | /* pass a parameter to a function and do type checking and casting */ |
- | |
7031 | static void gfunc_param_typed(Sym *func, Sym *arg) |
- | |
7032 | { |
- | |
7033 | int func_type; |
- | |
7034 | CType type; |
- | |
7035 | - | ||
7036 | func_type = func->c; |
- | |
7037 | if (func_type == FUNC_OLD || |
- | |
7038 | (func_type == FUNC_ELLIPSIS && arg == NULL)) { |
- | |
7039 | /* default casting : only need to convert float to double */ |
- | |
7040 | if ((vtop->type.t & VT_BTYPE) == VT_FLOAT) { |
- | |
7041 | type.t = VT_DOUBLE; |
- | |
7042 | gen_cast(&type); |
- | |
7043 | } |
- | |
7044 | } else if (arg == NULL) { |
- | |
7045 | error("too many arguments to function"); |
- | |
7046 | } else { |
- | |
7047 | type = arg->type; |
- | |
7048 | type.t &= ~VT_CONSTANT; /* need to do that to avoid false warning */ |
- | |
7049 | gen_assign_cast(&type); |
- | |
7050 | } |
- | |
7051 | } |
- | |
7052 | - | ||
7053 | /* parse an expression of the form '(type)' or '(expr)' and return its |
- | |
7054 | type */ |
- | |
7055 | static void parse_expr_type(CType *type) |
- | |
7056 | { |
- | |
7057 | int n; |
- | |
7058 | AttributeDef ad; |
- | |
7059 | - | ||
7060 | skip('('); |
- | |
7061 | if (parse_btype(type, &ad)) { |
- | |
7062 | type_decl(type, &ad, &n, TYPE_ABSTRACT); |
- | |
7063 | } else { |
- | |
7064 | expr_type(type); |
- | |
7065 | } |
- | |
7066 | skip(')'); |
- | |
7067 | } |
- | |
7068 | - | ||
7069 | static void parse_type(CType *type) |
- | |
7070 | { |
- | |
7071 | AttributeDef ad; |
- | |
7072 | int n; |
- | |
7073 | - | ||
7074 | if (!parse_btype(type, &ad)) { |
- | |
7075 | expect("type"); |
- | |
7076 | } |
- | |
7077 | type_decl(type, &ad, &n, TYPE_ABSTRACT); |
- | |
7078 | } |
- | |
7079 | - | ||
7080 | static void vpush_tokc(int t) |
- | |
7081 | { |
- | |
7082 | CType type; |
- | |
7083 | type.t = t; |
- | |
7084 | vsetc(&type, VT_CONST, &tokc); |
- | |
7085 | } |
- | |
7086 | - | ||
7087 | static void unary(void) |
- | |
7088 | { |
- | |
7089 | int n, t, align, size, r; |
- | |
7090 | CType type; |
- | |
7091 | Sym *s; |
- | |
7092 | AttributeDef ad; |
- | |
7093 | - | ||
7094 | /* XXX: GCC 2.95.3 does not generate a table although it should be |
- | |
7095 | better here */ |
- | |
7096 | tok_next: |
- | |
7097 | switch(tok) { |
- | |
7098 | case TOK_EXTENSION: |
- | |
7099 | next(); |
- | |
7100 | goto tok_next; |
- | |
7101 | case TOK_CINT: |
- | |
7102 | case TOK_CCHAR: |
- | |
7103 | case TOK_LCHAR: |
- | |
7104 | vpushi(tokc.i); |
- | |
7105 | next(); |
- | |
7106 | break; |
- | |
7107 | case TOK_CUINT: |
- | |
7108 | vpush_tokc(VT_INT | VT_UNSIGNED); |
- | |
7109 | next(); |
- | |
7110 | break; |
- | |
7111 | case TOK_CLLONG: |
- | |
7112 | vpush_tokc(VT_LLONG); |
- | |
7113 | next(); |
- | |
7114 | break; |
- | |
7115 | case TOK_CULLONG: |
- | |
7116 | vpush_tokc(VT_LLONG | VT_UNSIGNED); |
- | |
7117 | next(); |
- | |
7118 | break; |
- | |
7119 | case TOK_CFLOAT: |
- | |
7120 | vpush_tokc(VT_FLOAT); |
- | |
7121 | next(); |
- | |
7122 | break; |
- | |
7123 | case TOK_CDOUBLE: |
- | |
7124 | vpush_tokc(VT_DOUBLE); |
- | |
7125 | next(); |
- | |
7126 | break; |
- | |
7127 | case TOK_CLDOUBLE: |
- | |
7128 | vpush_tokc(VT_LDOUBLE); |
- | |
7129 | next(); |
- | |
7130 | break; |
- | |
7131 | case TOK___FUNCTION__: |
- | |
7132 | if (!gnu_ext) |
- | |
7133 | goto tok_identifier; |
- | |
7134 | /* fall thru */ |
- | |
7135 | case TOK___FUNC__: |
- | |
7136 | { |
- | |
7137 | void *ptr; |
- | |
7138 | int len; |
- | |
7139 | /* special function name identifier */ |
- | |
7140 | len = strlen(funcname) + 1; |
- | |
7141 | /* generate char[len] type */ |
- | |
7142 | type.t = VT_BYTE; |
- | |
7143 | mk_pointer(&type); |
- | |
7144 | type.t |= VT_ARRAY; |
- | |
7145 | type.ref->c = len; |
- | |
7146 | vpush_ref(&type, data_section, data_section->data_offset, len); |
- | |
7147 | ptr = section_ptr_add(data_section, len); |
- | |
7148 | memcpy(ptr, funcname, len); |
- | |
7149 | next(); |
- | |
7150 | } |
- | |
7151 | break; |
- | |
7152 | case TOK_LSTR: |
- | |
7153 | t = VT_INT; |
- | |
7154 | goto str_init; |
- | |
7155 | case TOK_STR: |
- | |
7156 | /* string parsing */ |
- | |
7157 | t = VT_BYTE; |
- | |
7158 | str_init: |
- | |
7159 | if (tcc_state->warn_write_strings) |
- | |
7160 | t |= VT_CONSTANT; |
- | |
7161 | type.t = t; |
- | |
7162 | mk_pointer(&type); |
- | |
7163 | type.t |= VT_ARRAY; |
- | |
7164 | memset(&ad, 0, sizeof(AttributeDef)); |
- | |
7165 | decl_initializer_alloc(&type, &ad, VT_CONST, 2, 0, 0); |
- | |
7166 | break; |
- | |
7167 | case '(': |
- | |
7168 | next(); |
- | |
7169 | /* cast ? */ |
- | |
7170 | if (parse_btype(&type, &ad)) { |
- | |
7171 | type_decl(&type, &ad, &n, TYPE_ABSTRACT); |
- | |
7172 | skip(')'); |
- | |
7173 | /* check ISOC99 compound literal */ |
- | |
7174 | if (tok == '{') { |
- | |
7175 | /* data is allocated locally by default */ |
- | |
7176 | if (global_expr) |
- | |
7177 | r = VT_CONST; |
- | |
7178 | else |
- | |
7179 | r = VT_LOCAL; |
- | |
7180 | /* all except arrays are lvalues */ |
- | |
7181 | if (!(type.t & VT_ARRAY)) |
- | |
7182 | r |= lvalue_type(type.t); |
- | |
7183 | memset(&ad, 0, sizeof(AttributeDef)); |
- | |
7184 | decl_initializer_alloc(&type, &ad, r, 1, 0, 0); |
- | |
7185 | } else { |
- | |
7186 | unary(); |
- | |
7187 | gen_cast(&type); |
- | |
7188 | } |
- | |
7189 | } else if (tok == '{') { |
- | |
7190 | /* save all registers */ |
- | |
7191 | save_regs(0); |
- | |
7192 | /* statement expression : we do not accept break/continue |
- | |
7193 | inside as GCC does */ |
- | |
7194 | block(NULL, NULL, NULL, NULL, 0, 1); |
- | |
7195 | skip(')'); |
- | |
7196 | } else { |
- | |
7197 | gexpr(); |
- | |
7198 | skip(')'); |
- | |
7199 | } |
- | |
7200 | break; |
- | |
7201 | case '*': |
- | |
7202 | next(); |
- | |
7203 | unary(); |
- | |
7204 | indir(); |
- | |
7205 | break; |
- | |
7206 | case '&': |
- | |
7207 | next(); |
- | |
7208 | unary(); |
- | |
7209 | /* functions names must be treated as function pointers, |
- | |
7210 | except for unary '&' and sizeof. Since we consider that |
- | |
7211 | functions are not lvalues, we only have to handle it |
- | |
7212 | there and in function calls. */ |
- | |
7213 | /* arrays can also be used although they are not lvalues */ |
- | |
7214 | if ((vtop->type.t & VT_BTYPE) != VT_FUNC && |
- | |
7215 | !(vtop->type.t & VT_ARRAY)) |
- | |
7216 | test_lvalue(); |
- | |
7217 | mk_pointer(&vtop->type); |
- | |
7218 | gaddrof(); |
- | |
7219 | break; |
- | |
7220 | case '!': |
- | |
7221 | next(); |
- | |
7222 | unary(); |
- | |
7223 | if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) |
- | |
7224 | vtop->c.i = !vtop->c.i; |
- | |
7225 | else if ((vtop->r & VT_VALMASK) == VT_CMP) |
- | |
7226 | vtop->c.i = vtop->c.i ^ 1; |
- | |
7227 | else |
- | |
7228 | vseti(VT_JMP, gtst(1, 0)); |
- | |
7229 | break; |
- | |
7230 | case '~': |
- | |
7231 | next(); |
- | |
7232 | unary(); |
- | |
7233 | vpushi(-1); |
- | |
7234 | gen_op('^'); |
- | |
7235 | break; |
- | |
7236 | case '+': |
- | |
7237 | next(); |
- | |
7238 | /* in order to force cast, we add zero */ |
- | |
7239 | unary(); |
- | |
7240 | if ((vtop->type.t & VT_BTYPE) == VT_PTR) |
- | |
7241 | error("pointer not accepted for unary plus"); |
- | |
7242 | vpushi(0); |
- | |
7243 | gen_op('+'); |
- | |
7244 | break; |
- | |
7245 | case TOK_SIZEOF: |
- | |
7246 | case TOK_ALIGNOF1: |
- | |
7247 | case TOK_ALIGNOF2: |
- | |
7248 | t = tok; |
- | |
7249 | next(); |
- | |
7250 | if (tok == '(') { |
- | |
7251 | parse_expr_type(&type); |
- | |
7252 | } else { |
- | |
7253 | unary_type(&type); |
- | |
7254 | } |
- | |
7255 | size = type_size(&type, &align); |
- | |
7256 | if (t == TOK_SIZEOF) { |
- | |
7257 | if (size < 0) |
- | |
7258 | error("sizeof applied to an incomplete type"); |
- | |
7259 | vpushi(size); |
- | |
7260 | } else { |
- | |
7261 | vpushi(align); |
- | |
7262 | } |
- | |
7263 | break; |
- | |
7264 | - | ||
7265 | case TOK_builtin_types_compatible_p: |
- | |
7266 | { |
- | |
7267 | CType type1, type2; |
- | |
7268 | next(); |
- | |
7269 | skip('('); |
- | |
7270 | parse_type(&type1); |
- | |
7271 | skip(','); |
- | |
7272 | parse_type(&type2); |
- | |
7273 | skip(')'); |
- | |
7274 | type1.t &= ~(VT_CONSTANT | VT_VOLATILE); |
- | |
7275 | type2.t &= ~(VT_CONSTANT | VT_VOLATILE); |
- | |
7276 | vpushi(is_compatible_types(&type1, &type2)); |
- | |
7277 | } |
- | |
7278 | break; |
- | |
7279 | case TOK_builtin_constant_p: |
- | |
7280 | { |
- | |
7281 | int saved_nocode_wanted, res; |
- | |
7282 | next(); |
- | |
7283 | skip('('); |
- | |
7284 | saved_nocode_wanted = nocode_wanted; |
- | |
7285 | nocode_wanted = 1; |
- | |
7286 | gexpr(); |
- | |
7287 | res = (vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; |
- | |
7288 | vpop(); |
- | |
7289 | nocode_wanted = saved_nocode_wanted; |
- | |
7290 | skip(')'); |
- | |
7291 | vpushi(res); |
- | |
7292 | } |
- | |
7293 | break; |
- | |
7294 | case TOK_INC: |
- | |
7295 | case TOK_DEC: |
- | |
7296 | t = tok; |
- | |
7297 | next(); |
- | |
7298 | unary(); |
- | |
7299 | inc(0, t); |
- | |
7300 | break; |
- | |
7301 | case '-': |
- | |
7302 | next(); |
- | |
7303 | vpushi(0); |
- | |
7304 | unary(); |
- | |
7305 | gen_op('-'); |
- | |
7306 | break; |
- | |
7307 | case TOK_LAND: |
- | |
7308 | if (!gnu_ext) |
- | |
7309 | goto tok_identifier; |
- | |
7310 | next(); |
- | |
7311 | /* allow to take the address of a label */ |
- | |
7312 | if (tok < TOK_UIDENT) |
- | |
7313 | expect("label identifier"); |
- | |
7314 | s = label_find(tok); |
- | |
7315 | if (!s) { |
- | |
7316 | s = label_push(&global_label_stack, tok, LABEL_FORWARD); |
- | |
7317 | } else { |
- | |
7318 | if (s->r == LABEL_DECLARED) |
- | |
7319 | s->r = LABEL_FORWARD; |
- | |
7320 | } |
- | |
7321 | if (!s->type.t) { |
- | |
7322 | s->type.t = VT_VOID; |
- | |
7323 | mk_pointer(&s->type); |
- | |
7324 | s->type.t |= VT_STATIC; |
- | |
7325 | } |
- | |
7326 | vset(&s->type, VT_CONST | VT_SYM, 0); |
- | |
7327 | vtop->sym = s; |
- | |
7328 | next(); |
- | |
7329 | break; |
- | |
7330 | default: |
- | |
7331 | tok_identifier: |
- | |
7332 | t = tok; |
- | |
7333 | next(); |
- | |
7334 | if (t < TOK_UIDENT) |
- | |
7335 | expect("identifier"); |
- | |
7336 | s = sym_find(t); |
- | |
7337 | if (!s) { |
- | |
7338 | if (tok != '(') |
- | |
7339 | error("'%s' undeclared", get_tok_str(t, NULL)); |
- | |
7340 | /* for simple function calls, we tolerate undeclared |
- | |
7341 | external reference to int() function */ |
- | |
7342 | if (tcc_state->warn_implicit_function_declaration) |
- | |
7343 | warning("implicit declaration of function '%s'", |
- | |
7344 | get_tok_str(t, NULL)); |
- | |
7345 | s = external_global_sym(t, &func_old_type, 0); |
- | |
7346 | } |
- | |
7347 | if ((s->type.t & (VT_STATIC | VT_INLINE | VT_BTYPE)) == |
- | |
7348 | (VT_STATIC | VT_INLINE | VT_FUNC)) { |
- | |
7349 | /* if referencing an inline function, then we generate a |
- | |
7350 | symbol to it if not already done. It will have the |
- | |
7351 | effect to generate code for it at the end of the |
- | |
7352 | compilation unit. Inline function as always |
- | |
7353 | generated in the text section. */ |
- | |
7354 | if (!s->c) |
- | |
7355 | put_extern_sym(s, text_section, 0, 0); |
- | |
7356 | r = VT_SYM | VT_CONST; |
- | |
7357 | } else { |
- | |
7358 | r = s->r; |
- | |
7359 | } |
- | |
7360 | vset(&s->type, r, s->c); |
- | |
7361 | /* if forward reference, we must point to s */ |
- | |
7362 | if (vtop->r & VT_SYM) { |
- | |
7363 | vtop->sym = s; |
- | |
7364 | vtop->c.ul = 0; |
- | |
7365 | } |
- | |
7366 | break; |
- | |
7367 | } |
- | |
7368 | - | ||
7369 | /* post operations */ |
- | |
7370 | while (1) { |
- | |
7371 | if (tok == TOK_INC || tok == TOK_DEC) { |
- | |
7372 | inc(1, tok); |
- | |
7373 | next(); |
- | |
7374 | } else if (tok == '.' || tok == TOK_ARROW) { |
- | |
7375 | /* field */ |
- | |
7376 | if (tok == TOK_ARROW) |
- | |
7377 | indir(); |
- | |
7378 | test_lvalue(); |
- | |
7379 | gaddrof(); |
- | |
7380 | next(); |
- | |
7381 | /* expect pointer on structure */ |
- | |
7382 | if ((vtop->type.t & VT_BTYPE) != VT_STRUCT) |
- | |
7383 | expect("struct or union"); |
- | |
7384 | s = vtop->type.ref; |
- | |
7385 | /* find field */ |
- | |
7386 | tok |= SYM_FIELD; |
- | |
7387 | while ((s = s->next) != NULL) { |
- | |
7388 | if (s->v == tok) |
- | |
7389 | break; |
- | |
7390 | } |
- | |
7391 | if (!s) |
- | |
7392 | error("field not found"); |
- | |
7393 | /* add field offset to pointer */ |
- | |
7394 | vtop->type = char_pointer_type; /* change type to 'char *' */ |
- | |
7395 | vpushi(s->c); |
- | |
7396 | gen_op('+'); |
- | |
7397 | /* change type to field type, and set to lvalue */ |
- | |
7398 | vtop->type = s->type; |
- | |
7399 | /* an array is never an lvalue */ |
- | |
7400 | if (!(vtop->type.t & VT_ARRAY)) { |
- | |
7401 | vtop->r |= lvalue_type(vtop->type.t); |
- | |
7402 | /* if bound checking, the referenced pointer must be checked */ |
- | |
7403 | if (do_bounds_check) |
- | |
7404 | vtop->r |= VT_MUSTBOUND; |
- | |
7405 | } |
- | |
7406 | next(); |
- | |
7407 | } else if (tok == '[') { |
- | |
7408 | next(); |
- | |
7409 | gexpr(); |
- | |
7410 | gen_op('+'); |
- | |
7411 | indir(); |
- | |
7412 | skip(']'); |
- | |
7413 | } else if (tok == '(') { |
- | |
7414 | SValue ret; |
- | |
7415 | Sym *sa; |
- | |
7416 | int nb_args; |
- | |
7417 | - | ||
7418 | /* function call */ |
- | |
7419 | if ((vtop->type.t & VT_BTYPE) != VT_FUNC) { |
- | |
7420 | /* pointer test (no array accepted) */ |
- | |
7421 | if ((vtop->type.t & (VT_BTYPE | VT_ARRAY)) == VT_PTR) { |
- | |
7422 | vtop->type = *pointed_type(&vtop->type); |
- | |
7423 | if ((vtop->type.t & VT_BTYPE) != VT_FUNC) |
- | |
7424 | goto error_func; |
- | |
7425 | } else { |
- | |
7426 | error_func: |
- | |
7427 | expect("function pointer"); |
- | |
7428 | } |
- | |
7429 | } else { |
- | |
7430 | vtop->r &= ~VT_LVAL; /* no lvalue */ |
- | |
7431 | } |
- | |
7432 | /* get return type */ |
- | |
7433 | s = vtop->type.ref; |
- | |
7434 | next(); |
- | |
7435 | sa = s->next; /* first parameter */ |
- | |
7436 | nb_args = 0; |
- | |
7437 | /* compute first implicit argument if a structure is returned */ |
- | |
7438 | if ((s->type.t & VT_BTYPE) == VT_STRUCT) { |
- | |
7439 | /* get some space for the returned structure */ |
- | |
7440 | size = type_size(&s->type, &align); |
- | |
7441 | loc = (loc - size) & -align; |
- | |
7442 | ret.type = s->type; |
- | |
7443 | ret.r = VT_LOCAL | VT_LVAL; |
- | |
7444 | /* pass it as 'int' to avoid structure arg passing |
- | |
7445 | problems */ |
- | |
7446 | vseti(VT_LOCAL, loc); |
- | |
7447 | ret.c = vtop->c; |
- | |
7448 | nb_args++; |
- | |
7449 | } else { |
- | |
7450 | ret.type = s->type; |
- | |
7451 | ret.r2 = VT_CONST; |
- | |
7452 | /* return in register */ |
- | |
7453 | if (is_float(ret.type.t)) { |
- | |
7454 | ret.r = REG_FRET; |
- | |
7455 | } else { |
- | |
7456 | if ((ret.type.t & VT_BTYPE) == VT_LLONG) |
- | |
7457 | ret.r2 = REG_LRET; |
- | |
7458 | ret.r = REG_IRET; |
- | |
7459 | } |
- | |
7460 | ret.c.i = 0; |
- | |
7461 | } |
- | |
7462 | if (tok != ')') { |
- | |
7463 | for(;;) { |
- | |
7464 | expr_eq(); |
- | |
7465 | gfunc_param_typed(s, sa); |
- | |
7466 | nb_args++; |
- | |
7467 | if (sa) |
- | |
7468 | sa = sa->next; |
- | |
7469 | if (tok == ')') |
- | |
7470 | break; |
- | |
7471 | skip(','); |
- | |
7472 | } |
- | |
7473 | } |
- | |
7474 | if (sa) |
- | |
7475 | error("too few arguments to function"); |
- | |
7476 | skip(')'); |
- | |
7477 | if (!nocode_wanted) { |
- | |
7478 | gfunc_call(nb_args); |
- | |
7479 | } else { |
- | |
7480 | vtop -= (nb_args + 1); |
- | |
7481 | } |
- | |
7482 | /* return value */ |
- | |
7483 | vsetc(&ret.type, ret.r, &ret.c); |
- | |
7484 | vtop->r2 = ret.r2; |
- | |
7485 | } else { |
- | |
7486 | break; |
- | |
7487 | } |
- | |
7488 | } |
- | |
7489 | } |
- | |
7490 | - | ||
7491 | static void uneq(void) |
- | |
7492 | { |
- | |
7493 | int t; |
- | |
7494 | - | ||
7495 | unary(); |
- | |
7496 | if (tok == '=' || |
- | |
7497 | (tok >= TOK_A_MOD && tok <= TOK_A_DIV) || |
- | |
7498 | tok == TOK_A_XOR || tok == TOK_A_OR || |
- | |
7499 | tok == TOK_A_SHL || tok == TOK_A_SAR) { |
- | |
7500 | test_lvalue(); |
- | |
7501 | t = tok; |
- | |
7502 | next(); |
- | |
7503 | if (t == '=') { |
- | |
7504 | expr_eq(); |
- | |
7505 | } else { |
- | |
7506 | vdup(); |
- | |
7507 | expr_eq(); |
- | |
7508 | gen_op(t & 0x7f); |
- | |
7509 | } |
- | |
7510 | vstore(); |
- | |
7511 | } |
- | |
7512 | } |
- | |
7513 | - | ||
7514 | static void expr_prod(void) |
- | |
7515 | { |
- | |
7516 | int t; |
- | |
7517 | - | ||
7518 | uneq(); |
- | |
7519 | while (tok == '*' || tok == '/' || tok == '%') { |
- | |
7520 | t = tok; |
- | |
7521 | next(); |
- | |
7522 | uneq(); |
- | |
7523 | gen_op(t); |
- | |
7524 | } |
- | |
7525 | } |
- | |
7526 | - | ||
7527 | static void expr_sum(void) |
- | |
7528 | { |
- | |
7529 | int t; |
- | |
7530 | - | ||
7531 | expr_prod(); |
- | |
7532 | while (tok == '+' || tok == '-') { |
- | |
7533 | t = tok; |
- | |
7534 | next(); |
- | |
7535 | expr_prod(); |
- | |
7536 | gen_op(t); |
- | |
7537 | } |
- | |
7538 | } |
- | |
7539 | - | ||
7540 | static void expr_shift(void) |
- | |
7541 | { |
- | |
7542 | int t; |
- | |
7543 | - | ||
7544 | expr_sum(); |
- | |
7545 | while (tok == TOK_SHL || tok == TOK_SAR) { |
- | |
7546 | t = tok; |
- | |
7547 | next(); |
- | |
7548 | expr_sum(); |
- | |
7549 | gen_op(t); |
- | |
7550 | } |
- | |
7551 | } |
- | |
7552 | - | ||
7553 | static void expr_cmp(void) |
- | |
7554 | { |
- | |
7555 | int t; |
- | |
7556 | - | ||
7557 | expr_shift(); |
- | |
7558 | while ((tok >= TOK_ULE && tok <= TOK_GT) || |
- | |
7559 | tok == TOK_ULT || tok == TOK_UGE) { |
- | |
7560 | t = tok; |
- | |
7561 | next(); |
- | |
7562 | expr_shift(); |
- | |
7563 | gen_op(t); |
- | |
7564 | } |
- | |
7565 | } |
- | |
7566 | - | ||
7567 | static void expr_cmpeq(void) |
- | |
7568 | { |
- | |
7569 | int t; |
- | |
7570 | - | ||
7571 | expr_cmp(); |
- | |
7572 | while (tok == TOK_EQ || tok == TOK_NE) { |
- | |
7573 | t = tok; |
- | |
7574 | next(); |
- | |
7575 | expr_cmp(); |
- | |
7576 | gen_op(t); |
- | |
7577 | } |
- | |
7578 | } |
- | |
7579 | - | ||
7580 | static void expr_and(void) |
- | |
7581 | { |
- | |
7582 | expr_cmpeq(); |
- | |
7583 | while (tok == '&') { |
- | |
7584 | next(); |
- | |
7585 | expr_cmpeq(); |
- | |
7586 | gen_op('&'); |
- | |
7587 | } |
- | |
7588 | } |
- | |
7589 | - | ||
7590 | static void expr_xor(void) |
- | |
7591 | { |
- | |
7592 | expr_and(); |
- | |
7593 | while (tok == '^') { |
- | |
7594 | next(); |
- | |
7595 | expr_and(); |
- | |
7596 | gen_op('^'); |
- | |
7597 | } |
- | |
7598 | } |
- | |
7599 | - | ||
7600 | static void expr_or(void) |
- | |
7601 | { |
- | |
7602 | expr_xor(); |
- | |
7603 | while (tok == '|') { |
- | |
7604 | next(); |
- | |
7605 | expr_xor(); |
- | |
7606 | gen_op('|'); |
- | |
7607 | } |
- | |
7608 | } |
- | |
7609 | - | ||
7610 | /* XXX: fix this mess */ |
- | |
7611 | static void expr_land_const(void) |
- | |
7612 | { |
- | |
7613 | expr_or(); |
- | |
7614 | while (tok == TOK_LAND) { |
- | |
7615 | next(); |
- | |
7616 | expr_or(); |
- | |
7617 | gen_op(TOK_LAND); |
- | |
7618 | } |
- | |
7619 | } |
- | |
7620 | - | ||
7621 | /* XXX: fix this mess */ |
- | |
7622 | static void expr_lor_const(void) |
- | |
7623 | { |
- | |
7624 | expr_land_const(); |
- | |
7625 | while (tok == TOK_LOR) { |
- | |
7626 | next(); |
- | |
7627 | expr_land_const(); |
- | |
7628 | gen_op(TOK_LOR); |
- | |
7629 | } |
- | |
7630 | } |
- | |
7631 | - | ||
7632 | /* only used if non constant */ |
- | |
7633 | static void expr_land(void) |
- | |
7634 | { |
- | |
7635 | int t; |
- | |
7636 | - | ||
7637 | expr_or(); |
- | |
7638 | if (tok == TOK_LAND) { |
- | |
7639 | t = 0; |
- | |
7640 | for(;;) { |
- | |
7641 | t = gtst(1, t); |
- | |
7642 | if (tok != TOK_LAND) { |
- | |
7643 | vseti(VT_JMPI, t); |
- | |
7644 | break; |
- | |
7645 | } |
- | |
7646 | next(); |
- | |
7647 | expr_or(); |
- | |
7648 | } |
- | |
7649 | } |
- | |
7650 | } |
- | |
7651 | - | ||
7652 | static void expr_lor(void) |
- | |
7653 | { |
- | |
7654 | int t; |
- | |
7655 | - | ||
7656 | expr_land(); |
- | |
7657 | if (tok == TOK_LOR) { |
- | |
7658 | t = 0; |
- | |
7659 | for(;;) { |
- | |
7660 | t = gtst(0, t); |
- | |
7661 | if (tok != TOK_LOR) { |
- | |
7662 | vseti(VT_JMP, t); |
- | |
7663 | break; |
- | |
7664 | } |
- | |
7665 | next(); |
- | |
7666 | expr_land(); |
- | |
7667 | } |
- | |
7668 | } |
- | |
7669 | } |
- | |
7670 | - | ||
7671 | /* XXX: better constant handling */ |
- | |
7672 | static void expr_eq(void) |
- | |
7673 | { |
- | |
7674 | int tt, u, r1, r2, rc, t1, t2, bt1, bt2; |
- | |
7675 | SValue sv; |
- | |
7676 | CType type, type1, type2; |
- | |
7677 | - | ||
7678 | if (const_wanted) { |
- | |
7679 | int c1, c; |
- | |
7680 | expr_lor_const(); |
- | |
7681 | if (tok == '?') { |
- | |
7682 | c = vtop->c.i; |
- | |
7683 | vpop(); |
- | |
7684 | next(); |
- | |
7685 | if (tok == ':' && gnu_ext) { |
- | |
7686 | c1 = c; |
- | |
7687 | } else { |
- | |
7688 | gexpr(); |
- | |
7689 | c1 = vtop->c.i; |
- | |
7690 | vpop(); |
- | |
7691 | } |
- | |
7692 | skip(':'); |
- | |
7693 | expr_eq(); |
- | |
7694 | if (c) |
- | |
7695 | vtop->c.i = c1; |
- | |
7696 | } |
- | |
7697 | } else { |
- | |
7698 | expr_lor(); |
- | |
7699 | if (tok == '?') { |
- | |
7700 | next(); |
- | |
7701 | if (vtop != vstack) { |
- | |
7702 | /* needed to avoid having different registers saved in |
- | |
7703 | each branch */ |
- | |
7704 | if (is_float(vtop->type.t)) |
- | |
7705 | rc = RC_FLOAT; |
- | |
7706 | else |
- | |
7707 | rc = RC_INT; |
- | |
7708 | gv(rc); |
- | |
7709 | save_regs(1); |
- | |
7710 | } |
- | |
7711 | if (tok == ':' && gnu_ext) { |
- | |
7712 | gv_dup(); |
- | |
7713 | tt = gtst(1, 0); |
- | |
7714 | } else { |
- | |
7715 | tt = gtst(1, 0); |
- | |
7716 | gexpr(); |
- | |
7717 | } |
- | |
7718 | type1 = vtop->type; |
- | |
7719 | sv = *vtop; /* save value to handle it later */ |
- | |
7720 | vtop--; /* no vpop so that FP stack is not flushed */ |
- | |
7721 | skip(':'); |
- | |
7722 | u = gjmp(0); |
- | |
7723 | gsym(tt); |
- | |
7724 | expr_eq(); |
- | |
7725 | type2 = vtop->type; |
- | |
7726 | - | ||
7727 | t1 = type1.t; |
- | |
7728 | bt1 = t1 & VT_BTYPE; |
- | |
7729 | t2 = type2.t; |
- | |
7730 | bt2 = t2 & VT_BTYPE; |
- | |
7731 | /* cast operands to correct type according to ISOC rules */ |
- | |
7732 | if (is_float(bt1) || is_float(bt2)) { |
- | |
7733 | if (bt1 == VT_LDOUBLE || bt2 == VT_LDOUBLE) { |
- | |
7734 | type.t = VT_LDOUBLE; |
- | |
7735 | } else if (bt1 == VT_DOUBLE || bt2 == VT_DOUBLE) { |
- | |
7736 | type.t = VT_DOUBLE; |
- | |
7737 | } else { |
- | |
7738 | type.t = VT_FLOAT; |
- | |
7739 | } |
- | |
7740 | } else if (bt1 == VT_LLONG || bt2 == VT_LLONG) { |
- | |
7741 | /* cast to biggest op */ |
- | |
7742 | type.t = VT_LLONG; |
- | |
7743 | /* convert to unsigned if it does not fit in a long long */ |
- | |
7744 | if ((t1 & (VT_BTYPE | VT_UNSIGNED)) == (VT_LLONG | VT_UNSIGNED) || |
- | |
7745 | (t2 & (VT_BTYPE | VT_UNSIGNED)) == (VT_LLONG | VT_UNSIGNED)) |
- | |
7746 | type.t |= VT_UNSIGNED; |
- | |
7747 | } else if (bt1 == VT_PTR || bt2 == VT_PTR) { |
- | |
7748 | /* XXX: test pointer compatibility */ |
- | |
7749 | type = type1; |
- | |
7750 | } else if (bt1 == VT_STRUCT || bt2 == VT_STRUCT) { |
- | |
7751 | /* XXX: test structure compatibility */ |
- | |
7752 | type = type1; |
- | |
7753 | } else if (bt1 == VT_VOID || bt2 == VT_VOID) { |
- | |
7754 | /* NOTE: as an extension, we accept void on only one side */ |
- | |
7755 | type.t = VT_VOID; |
- | |
7756 | } else { |
- | |
7757 | /* integer operations */ |
- | |
7758 | type.t = VT_INT; |
- | |
7759 | /* convert to unsigned if it does not fit in an integer */ |
- | |
7760 | if ((t1 & (VT_BTYPE | VT_UNSIGNED)) == (VT_INT | VT_UNSIGNED) || |
- | |
7761 | (t2 & (VT_BTYPE | VT_UNSIGNED)) == (VT_INT | VT_UNSIGNED)) |
- | |
7762 | type.t |= VT_UNSIGNED; |
- | |
7763 | } |
- | |
7764 | - | ||
7765 | /* now we convert second operand */ |
- | |
7766 | gen_cast(&type); |
- | |
7767 | rc = RC_INT; |
- | |
7768 | if (is_float(type.t)) { |
- | |
7769 | rc = RC_FLOAT; |
- | |
7770 | } else if ((type.t & VT_BTYPE) == VT_LLONG) { |
- | |
7771 | /* for long longs, we use fixed registers to avoid having |
- | |
7772 | to handle a complicated move */ |
- | |
7773 | rc = RC_IRET; |
- | |
7774 | } |
- | |
7775 | - | ||
7776 | r2 = gv(rc); |
- | |
7777 | /* this is horrible, but we must also convert first |
- | |
7778 | operand */ |
- | |
7779 | tt = gjmp(0); |
- | |
7780 | gsym(u); |
- | |
7781 | /* put again first value and cast it */ |
- | |
7782 | *vtop = sv; |
- | |
7783 | gen_cast(&type); |
- | |
7784 | r1 = gv(rc); |
- | |
7785 | move_reg(r2, r1); |
- | |
7786 | vtop->r = r2; |
- | |
7787 | gsym(tt); |
- | |
7788 | } |
- | |
7789 | } |
- | |
7790 | } |
- | |
7791 | - | ||
7792 | static void gexpr(void) |
- | |
7793 | { |
- | |
7794 | while (1) { |
- | |
7795 | expr_eq(); |
- | |
7796 | if (tok != ',') |
- | |
7797 | break; |
- | |
7798 | vpop(); |
- | |
7799 | next(); |
- | |
7800 | } |
- | |
7801 | } |
- | |
7802 | - | ||
7803 | /* parse an expression and return its type without any side effect. */ |
- | |
7804 | static void expr_type(CType *type) |
- | |
7805 | { |
- | |
7806 | int saved_nocode_wanted; |
- | |
7807 | - | ||
7808 | saved_nocode_wanted = nocode_wanted; |
- | |
7809 | nocode_wanted = 1; |
- | |
7810 | gexpr(); |
- | |
7811 | *type = vtop->type; |
- | |
7812 | vpop(); |
- | |
7813 | nocode_wanted = saved_nocode_wanted; |
- | |
7814 | } |
- | |
7815 | - | ||
7816 | /* parse a unary expression and return its type without any side |
- | |
7817 | effect. */ |
- | |
7818 | static void unary_type(CType *type) |
- | |
7819 | { |
- | |
7820 | int a; |
- | |
7821 | - | ||
7822 | a = nocode_wanted; |
- | |
7823 | nocode_wanted = 1; |
- | |
7824 | unary(); |
- | |
7825 | *type = vtop->type; |
- | |
7826 | vpop(); |
- | |
7827 | nocode_wanted = a; |
- | |
7828 | } |
- | |
7829 | - | ||
7830 | /* parse a constant expression and return value in vtop. */ |
- | |
7831 | static void expr_const1(void) |
- | |
7832 | { |
- | |
7833 | int a; |
- | |
7834 | a = const_wanted; |
- | |
7835 | const_wanted = 1; |
- | |
7836 | expr_eq(); |
- | |
7837 | const_wanted = a; |
- | |
7838 | } |
- | |
7839 | - | ||
7840 | /* parse an integer constant and return its value. */ |
- | |
7841 | static int expr_const(void) |
- | |
7842 | { |
- | |
7843 | int c; |
- | |
7844 | expr_const1(); |
- | |
7845 | if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) != VT_CONST) |
- | |
7846 | expect("constant expression"); |
- | |
7847 | c = vtop->c.i; |
- | |
7848 | vpop(); |
- | |
7849 | return c; |
- | |
7850 | } |
- | |
7851 | - | ||
7852 | /* return the label token if current token is a label, otherwise |
- | |
7853 | return zero */ |
- | |
7854 | static int is_label(void) |
- | |
7855 | { |
- | |
7856 | int last_tok; |
- | |
7857 | - | ||
7858 | /* fast test first */ |
- | |
7859 | if (tok < TOK_UIDENT) |
- | |
7860 | return 0; |
- | |
7861 | /* no need to save tokc because tok is an identifier */ |
- | |
7862 | last_tok = tok; |
- | |
7863 | next(); |
- | |
7864 | if (tok == ':') { |
- | |
7865 | next(); |
- | |
7866 | return last_tok; |
- | |
7867 | } else { |
- | |
7868 | unget_tok(last_tok); |
- | |
7869 | return 0; |
- | |
7870 | } |
- | |
7871 | } |
- | |
7872 | - | ||
7873 | static void block(int *bsym, int *csym, int *case_sym, int *def_sym, |
- | |
7874 | int case_reg, int is_expr) |
- | |
7875 | { |
- | |
7876 | int a, b, c, d; |
- | |
7877 | Sym *s; |
- | |
7878 | - | ||
7879 | /* generate line number info */ |
- | |
7880 | if (do_debug && |
- | |
7881 | (last_line_num != file->line_num || last_ind != ind)) { |
- | |
7882 | put_stabn(N_SLINE, 0, file->line_num, ind - func_ind); |
- | |
7883 | last_ind = ind; |
- | |
7884 | last_line_num = file->line_num; |
- | |
7885 | } |
- | |
7886 | - | ||
7887 | if (is_expr) { |
- | |
7888 | /* default return value is (void) */ |
- | |
7889 | vpushi(0); |
- | |
7890 | vtop->type.t = VT_VOID; |
- | |
7891 | } |
- | |
7892 | - | ||
7893 | if (tok == TOK_IF) { |
- | |
7894 | /* if test */ |
- | |
7895 | next(); |
- | |
7896 | skip('('); |
- | |
7897 | gexpr(); |
- | |
7898 | skip(')'); |
- | |
7899 | a = gtst(1, 0); |
- | |
7900 | block(bsym, csym, case_sym, def_sym, case_reg, 0); |
- | |
7901 | c = tok; |
- | |
7902 | if (c == TOK_ELSE) { |
- | |
7903 | next(); |
- | |
7904 | d = gjmp(0); |
- | |
7905 | gsym(a); |
- | |
7906 | block(bsym, csym, case_sym, def_sym, case_reg, 0); |
- | |
7907 | gsym(d); /* patch else jmp */ |
- | |
7908 | } else |
- | |
7909 | gsym(a); |
- | |
7910 | } else if (tok == TOK_WHILE) { |
- | |
7911 | next(); |
- | |
7912 | d = ind; |
- | |
7913 | skip('('); |
- | |
7914 | gexpr(); |
- | |
7915 | skip(')'); |
- | |
7916 | a = gtst(1, 0); |
- | |
7917 | b = 0; |
- | |
7918 | block(&a, &b, case_sym, def_sym, case_reg, 0); |
- | |
7919 | gjmp_addr(d); |
- | |
7920 | gsym(a); |
- | |
7921 | gsym_addr(b, d); |
- | |
7922 | } else if (tok == '{') { |
- | |
7923 | Sym *llabel; |
- | |
7924 | - | ||
7925 | next(); |
- | |
7926 | /* record local declaration stack position */ |
- | |
7927 | s = local_stack; |
- | |
7928 | llabel = local_label_stack; |
- | |
7929 | /* handle local labels declarations */ |
- | |
7930 | if (tok == TOK_LABEL) { |
- | |
7931 | next(); |
- | |
7932 | for(;;) { |
- | |
7933 | if (tok < TOK_UIDENT) |
- | |
7934 | expect("label identifier"); |
- | |
7935 | label_push(&local_label_stack, tok, LABEL_DECLARED); |
- | |
7936 | next(); |
- | |
7937 | if (tok == ',') { |
- | |
7938 | next(); |
- | |
7939 | } else { |
- | |
7940 | skip(';'); |
- | |
7941 | break; |
- | |
7942 | } |
- | |
7943 | } |
- | |
7944 | } |
- | |
7945 | while (tok != '}') { |
- | |
7946 | decl(VT_LOCAL); |
- | |
7947 | if (tok != '}') { |
- | |
7948 | if (is_expr) |
- | |
7949 | vpop(); |
- | |
7950 | block(bsym, csym, case_sym, def_sym, case_reg, is_expr); |
- | |
7951 | } |
- | |
7952 | } |
- | |
7953 | /* pop locally defined labels */ |
- | |
7954 | label_pop(&local_label_stack, llabel); |
- | |
7955 | /* pop locally defined symbols */ |
- | |
7956 | sym_pop(&local_stack, s); |
- | |
7957 | next(); |
- | |
7958 | } else if (tok == TOK_RETURN) { |
- | |
7959 | next(); |
- | |
7960 | if (tok != ';') { |
- | |
7961 | gexpr(); |
- | |
7962 | gen_assign_cast(&func_vt); |
- | |
7963 | if ((func_vt.t & VT_BTYPE) == VT_STRUCT) { |
- | |
7964 | CType type; |
- | |
7965 | /* if returning structure, must copy it to implicit |
- | |
7966 | first pointer arg location */ |
- | |
7967 | type = func_vt; |
- | |
7968 | mk_pointer(&type); |
- | |
7969 | vset(&type, VT_LOCAL | VT_LVAL, func_vc); |
- | |
7970 | indir(); |
- | |
7971 | vswap(); |
- | |
7972 | /* copy structure value to pointer */ |
- | |
7973 | vstore(); |
- | |
7974 | } else if (is_float(func_vt.t)) { |
- | |
7975 | gv(RC_FRET); |
- | |
7976 | } else { |
- | |
7977 | gv(RC_IRET); |
- | |
7978 | } |
- | |
7979 | vtop--; /* NOT vpop() because on x86 it would flush the fp stack */ |
- | |
7980 | } |
- | |
7981 | skip(';'); |
- | |
7982 | rsym = gjmp(rsym); /* jmp */ |
- | |
7983 | } else if (tok == TOK_BREAK) { |
- | |
7984 | /* compute jump */ |
- | |
7985 | if (!bsym) |
- | |
7986 | error("cannot break"); |
- | |
7987 | *bsym = gjmp(*bsym); |
- | |
7988 | next(); |
- | |
7989 | skip(';'); |
- | |
7990 | } else if (tok == TOK_CONTINUE) { |
- | |
7991 | /* compute jump */ |
- | |
7992 | if (!csym) |
- | |
7993 | error("cannot continue"); |
- | |
7994 | *csym = gjmp(*csym); |
- | |
7995 | next(); |
- | |
7996 | skip(';'); |
- | |
7997 | } else if (tok == TOK_FOR) { |
- | |
7998 | int e; |
- | |
7999 | next(); |
- | |
8000 | skip('('); |
- | |
8001 | if (tok != ';') { |
- | |
8002 | gexpr(); |
- | |
8003 | vpop(); |
- | |
8004 | } |
- | |
8005 | skip(';'); |
- | |
8006 | d = ind; |
- | |
8007 | c = ind; |
- | |
8008 | a = 0; |
- | |
8009 | b = 0; |
- | |
8010 | if (tok != ';') { |
- | |
8011 | gexpr(); |
- | |
8012 | a = gtst(1, 0); |
- | |
8013 | } |
- | |
8014 | skip(';'); |
- | |
8015 | if (tok != ')') { |
- | |
8016 | e = gjmp(0); |
- | |
8017 | c = ind; |
- | |
8018 | gexpr(); |
- | |
8019 | vpop(); |
- | |
8020 | gjmp_addr(d); |
- | |
8021 | gsym(e); |
- | |
8022 | } |
- | |
8023 | skip(')'); |
- | |
8024 | block(&a, &b, case_sym, def_sym, case_reg, 0); |
- | |
8025 | gjmp_addr(c); |
- | |
8026 | gsym(a); |
- | |
8027 | gsym_addr(b, c); |
- | |
8028 | } else |
- | |
8029 | if (tok == TOK_DO) { |
- | |
8030 | next(); |
- | |
8031 | a = 0; |
- | |
8032 | b = 0; |
- | |
8033 | d = ind; |
- | |
8034 | block(&a, &b, case_sym, def_sym, case_reg, 0); |
- | |
8035 | skip(TOK_WHILE); |
- | |
8036 | skip('('); |
- | |
8037 | gsym(b); |
- | |
8038 | gexpr(); |
- | |
8039 | c = gtst(0, 0); |
- | |
8040 | gsym_addr(c, d); |
- | |
8041 | skip(')'); |
- | |
8042 | gsym(a); |
- | |
8043 | skip(';'); |
- | |
8044 | } else |
- | |
8045 | if (tok == TOK_SWITCH) { |
- | |
8046 | next(); |
- | |
8047 | skip('('); |
- | |
8048 | gexpr(); |
- | |
8049 | /* XXX: other types than integer */ |
- | |
8050 | case_reg = gv(RC_INT); |
- | |
8051 | vpop(); |
- | |
8052 | skip(')'); |
- | |
8053 | a = 0; |
- | |
8054 | b = gjmp(0); /* jump to first case */ |
- | |
8055 | c = 0; |
- | |
8056 | block(&a, csym, &b, &c, case_reg, 0); |
- | |
8057 | /* if no default, jmp after switch */ |
- | |
8058 | if (c == 0) |
- | |
8059 | c = ind; |
- | |
8060 | /* default label */ |
- | |
8061 | gsym_addr(b, c); |
- | |
8062 | /* break label */ |
- | |
8063 | gsym(a); |
- | |
8064 | } else |
- | |
8065 | if (tok == TOK_CASE) { |
- | |
8066 | int v1, v2; |
- | |
8067 | if (!case_sym) |
- | |
8068 | expect("switch"); |
- | |
8069 | next(); |
- | |
8070 | v1 = expr_const(); |
- | |
8071 | v2 = v1; |
- | |
8072 | if (gnu_ext && tok == TOK_DOTS) { |
- | |
8073 | next(); |
- | |
8074 | v2 = expr_const(); |
- | |
8075 | if (v2 < v1) |
- | |
8076 | warning("empty case range"); |
- | |
8077 | } |
- | |
8078 | /* since a case is like a label, we must skip it with a jmp */ |
- | |
8079 | b = gjmp(0); |
- | |
8080 | gsym(*case_sym); |
- | |
8081 | vseti(case_reg, 0); |
- | |
8082 | vpushi(v1); |
- | |
8083 | if (v1 == v2) { |
- | |
8084 | gen_op(TOK_EQ); |
- | |
8085 | *case_sym = gtst(1, 0); |
- | |
8086 | } else { |
- | |
8087 | gen_op(TOK_GE); |
- | |
8088 | *case_sym = gtst(1, 0); |
- | |
8089 | vseti(case_reg, 0); |
- | |
8090 | vpushi(v2); |
- | |
8091 | gen_op(TOK_LE); |
- | |
8092 | *case_sym = gtst(1, *case_sym); |
- | |
8093 | } |
- | |
8094 | gsym(b); |
- | |
8095 | skip(':'); |
- | |
8096 | is_expr = 0; |
- | |
8097 | goto block_after_label; |
- | |
8098 | } else |
- | |
8099 | if (tok == TOK_DEFAULT) { |
- | |
8100 | next(); |
- | |
8101 | skip(':'); |
- | |
8102 | if (!def_sym) |
- | |
8103 | expect("switch"); |
- | |
8104 | if (*def_sym) |
- | |
8105 | error("too many 'default'"); |
- | |
8106 | *def_sym = ind; |
- | |
8107 | is_expr = 0; |
- | |
8108 | goto block_after_label; |
- | |
8109 | } else |
- | |
8110 | if (tok == TOK_GOTO) { |
- | |
8111 | next(); |
- | |
8112 | if (tok == '*' && gnu_ext) { |
- | |
8113 | /* computed goto */ |
- | |
8114 | next(); |
- | |
8115 | gexpr(); |
- | |
8116 | if ((vtop->type.t & VT_BTYPE) != VT_PTR) |
- | |
8117 | expect("pointer"); |
- | |
8118 | ggoto(); |
- | |
8119 | } else if (tok >= TOK_UIDENT) { |
- | |
8120 | s = label_find(tok); |
- | |
8121 | /* put forward definition if needed */ |
- | |
8122 | if (!s) { |
- | |
8123 | s = label_push(&global_label_stack, tok, LABEL_FORWARD); |
- | |
8124 | } else { |
- | |
8125 | if (s->r == LABEL_DECLARED) |
- | |
8126 | s->r = LABEL_FORWARD; |
- | |
8127 | } |
- | |
8128 | /* label already defined */ |
- | |
8129 | if (s->r & LABEL_FORWARD) |
- | |
8130 | s->next = (void *)gjmp((long)s->next); |
- | |
8131 | else |
- | |
8132 | gjmp_addr((long)s->next); |
- | |
8133 | next(); |
- | |
8134 | } else { |
- | |
8135 | expect("label identifier"); |
- | |
8136 | } |
- | |
8137 | skip(';'); |
- | |
8138 | } else if (tok == TOK_ASM1 || tok == TOK_ASM2 || tok == TOK_ASM3) { |
- | |
8139 | asm_instr(); |
- | |
8140 | } else { |
- | |
8141 | b = is_label(); |
- | |
8142 | if (b) { |
- | |
8143 | /* label case */ |
- | |
8144 | s = label_find(b); |
- | |
8145 | if (s) { |
- | |
8146 | if (s->r == LABEL_DEFINED) |
- | |
8147 | error("duplicate label '%s'", get_tok_str(s->v, NULL)); |
- | |
8148 | gsym((long)s->next); |
- | |
8149 | s->r = LABEL_DEFINED; |
- | |
8150 | } else { |
- | |
8151 | s = label_push(&global_label_stack, b, LABEL_DEFINED); |
- | |
8152 | } |
- | |
8153 | s->next = (void *)ind; |
- | |
8154 | /* we accept this, but it is a mistake */ |
- | |
8155 | block_after_label: |
- | |
8156 | if (tok == '}') { |
- | |
8157 | warning("deprecated use of label at end of compound statement"); |
- | |
8158 | } else { |
- | |
8159 | if (is_expr) |
- | |
8160 | vpop(); |
- | |
8161 | block(bsym, csym, case_sym, def_sym, case_reg, is_expr); |
- | |
8162 | } |
- | |
8163 | } else { |
- | |
8164 | /* expression case */ |
- | |
8165 | if (tok != ';') { |
- | |
8166 | if (is_expr) { |
- | |
8167 | vpop(); |
- | |
8168 | gexpr(); |
- | |
8169 | } else { |
- | |
8170 | gexpr(); |
- | |
8171 | vpop(); |
- | |
8172 | } |
- | |
8173 | } |
- | |
8174 | skip(';'); |
- | |
8175 | } |
- | |
8176 | } |
- | |
8177 | } |
- | |
8178 | - | ||
8179 | /* t is the array or struct type. c is the array or struct |
- | |
8180 | address. cur_index/cur_field is the pointer to the current |
- | |
8181 | value. 'size_only' is true if only size info is needed (only used |
- | |
8182 | in arrays) */ |
- | |
8183 | static void decl_designator(CType *type, Section *sec, unsigned long c, |
- | |
8184 | int *cur_index, Sym **cur_field, |
- | |
8185 | int size_only) |
- | |
8186 | { |
- | |
8187 | Sym *s, *f; |
- | |
8188 | int notfirst, index, index_last, align, l, nb_elems, elem_size; |
- | |
8189 | CType type1; |
- | |
8190 | - | ||
8191 | notfirst = 0; |
- | |
8192 | elem_size = 0; |
- | |
8193 | nb_elems = 1; |
- | |
8194 | if (gnu_ext && (l = is_label()) != 0) |
- | |
8195 | goto struct_field; |
- | |
8196 | while (tok == '[' || tok == '.') { |
- | |
8197 | if (tok == '[') { |
- | |
8198 | if (!(type->t & VT_ARRAY)) |
- | |
8199 | expect("array type"); |
- | |
8200 | s = type->ref; |
- | |
8201 | next(); |
- | |
8202 | index = expr_const(); |
- | |
8203 | if (index < 0 || (s->c >= 0 && index >= s->c)) |
- | |
8204 | expect("invalid index"); |
- | |
8205 | if (tok == TOK_DOTS && gnu_ext) { |
- | |
8206 | next(); |
- | |
8207 | index_last = expr_const(); |
- | |
8208 | if (index_last < 0 || |
- | |
8209 | (s->c >= 0 && index_last >= s->c) || |
- | |
8210 | index_last < index) |
- | |
8211 | expect("invalid index"); |
- | |
8212 | } else { |
- | |
8213 | index_last = index; |
- | |
8214 | } |
- | |
8215 | skip(']'); |
- | |
8216 | if (!notfirst) |
- | |
8217 | *cur_index = index_last; |
- | |
8218 | type = pointed_type(type); |
- | |
8219 | elem_size = type_size(type, &align); |
- | |
8220 | c += index * elem_size; |
- | |
8221 | /* NOTE: we only support ranges for last designator */ |
- | |
8222 | nb_elems = index_last - index + 1; |
- | |
8223 | if (nb_elems != 1) { |
- | |
8224 | notfirst = 1; |
- | |
8225 | break; |
- | |
8226 | } |
- | |
8227 | } else { |
- | |
8228 | next(); |
- | |
8229 | l = tok; |
- | |
8230 | next(); |
- | |
8231 | struct_field: |
- | |
8232 | if ((type->t & VT_BTYPE) != VT_STRUCT) |
- | |
8233 | expect("struct/union type"); |
- | |
8234 | s = type->ref; |
- | |
8235 | l |= SYM_FIELD; |
- | |
8236 | f = s->next; |
- | |
8237 | while (f) { |
- | |
8238 | if (f->v == l) |
- | |
8239 | break; |
- | |
8240 | f = f->next; |
- | |
8241 | } |
- | |
8242 | if (!f) |
- | |
8243 | expect("field"); |
- | |
8244 | if (!notfirst) |
- | |
8245 | *cur_field = f; |
- | |
8246 | /* XXX: fix this mess by using explicit storage field */ |
- | |
8247 | type1 = f->type; |
- | |
8248 | type1.t |= (type->t & ~VT_TYPE); |
- | |
8249 | type = &type1; |
- | |
8250 | c += f->c; |
- | |
8251 | } |
- | |
8252 | notfirst = 1; |
- | |
8253 | } |
- | |
8254 | if (notfirst) { |
- | |
8255 | if (tok == '=') { |
- | |
8256 | next(); |
- | |
8257 | } else { |
- | |
8258 | if (!gnu_ext) |
- | |
8259 | expect("="); |
- | |
8260 | } |
- | |
8261 | } else { |
- | |
8262 | if (type->t & VT_ARRAY) { |
- | |
8263 | index = *cur_index; |
- | |
8264 | type = pointed_type(type); |
- | |
8265 | c += index * type_size(type, &align); |
- | |
8266 | } else { |
- | |
8267 | f = *cur_field; |
- | |
8268 | if (!f) |
- | |
8269 | error("too many field init"); |
- | |
8270 | /* XXX: fix this mess by using explicit storage field */ |
- | |
8271 | type1 = f->type; |
- | |
8272 | type1.t |= (type->t & ~VT_TYPE); |
- | |
8273 | type = &type1; |
- | |
8274 | c += f->c; |
- | |
8275 | } |
- | |
8276 | } |
- | |
8277 | decl_initializer(type, sec, c, 0, size_only); |
- | |
8278 | - | ||
8279 | /* XXX: make it more general */ |
- | |
8280 | if (!size_only && nb_elems > 1) { |
- | |
8281 | unsigned long c_end; |
- | |
8282 | uint8_t *src, *dst; |
- | |
8283 | int i; |
- | |
8284 | - | ||
8285 | if (!sec) |
- | |
8286 | error("range init not supported yet for dynamic storage"); |
- | |
8287 | c_end = c + nb_elems * elem_size; |
- | |
8288 | if (c_end > sec->data_allocated) |
- | |
8289 | section_realloc(sec, c_end); |
- | |
8290 | src = sec->data + c; |
- | |
8291 | dst = src; |
- | |
8292 | for(i = 1; i < nb_elems; i++) { |
- | |
8293 | dst += elem_size; |
- | |
8294 | memcpy(dst, src, elem_size); |
- | |
8295 | } |
- | |
8296 | } |
- | |
8297 | } |
- | |
8298 | - | ||
8299 | #define EXPR_VAL 0 |
- | |
8300 | #define EXPR_CONST 1 |
- | |
8301 | #define EXPR_ANY 2 |
- | |
8302 | - | ||
8303 | /* store a value or an expression directly in global data or in local array */ |
- | |
8304 | static void init_putv(CType *type, Section *sec, unsigned long c, |
- | |
8305 | int v, int expr_type) |
- | |
8306 | { |
- | |
8307 | int saved_global_expr, bt, bit_pos, bit_size; |
- | |
8308 | void *ptr; |
- | |
8309 | unsigned long long bit_mask; |
- | |
8310 | CType dtype; |
- | |
8311 | - | ||
8312 | switch(expr_type) { |
- | |
8313 | case EXPR_VAL: |
- | |
8314 | vpushi(v); |
- | |
8315 | break; |
- | |
8316 | case EXPR_CONST: |
- | |
8317 | /* compound literals must be allocated globally in this case */ |
- | |
8318 | saved_global_expr = global_expr; |
- | |
8319 | global_expr = 1; |
- | |
8320 | expr_const1(); |
- | |
8321 | global_expr = saved_global_expr; |
- | |
8322 | /* NOTE: symbols are accepted */ |
- | |
8323 | if ((vtop->r & (VT_VALMASK | VT_LVAL)) != VT_CONST) |
- | |
8324 | error("initializer element is not constant"); |
- | |
8325 | break; |
- | |
8326 | case EXPR_ANY: |
- | |
8327 | expr_eq(); |
- | |
8328 | break; |
- | |
8329 | } |
- | |
8330 | - | ||
8331 | dtype = *type; |
- | |
8332 | dtype.t &= ~VT_CONSTANT; /* need to do that to avoid false warning */ |
- | |
8333 | - | ||
8334 | if (sec) { |
- | |
8335 | /* XXX: not portable */ |
- | |
8336 | /* XXX: generate error if incorrect relocation */ |
- | |
8337 | gen_assign_cast(&dtype); |
- | |
8338 | bt = type->t & VT_BTYPE; |
- | |
8339 | ptr = sec->data + c; |
- | |
8340 | /* XXX: make code faster ? */ |
- | |
8341 | if (!(type->t & VT_BITFIELD)) { |
- | |
8342 | bit_pos = 0; |
- | |
8343 | bit_size = 32; |
- | |
8344 | bit_mask = -1LL; |
- | |
8345 | } else { |
- | |
8346 | bit_pos = (vtop->type.t >> VT_STRUCT_SHIFT) & 0x3f; |
- | |
8347 | bit_size = (vtop->type.t >> (VT_STRUCT_SHIFT + 6)) & 0x3f; |
- | |
8348 | bit_mask = (1LL << bit_size) - 1; |
- | |
8349 | } |
- | |
8350 | if ((vtop->r & VT_SYM) && |
- | |
8351 | (bt == VT_BYTE || |
- | |
8352 | bt == VT_SHORT || |
- | |
8353 | bt == VT_DOUBLE || |
- | |
8354 | bt == VT_LDOUBLE || |
- | |
8355 | bt == VT_LLONG || |
- | |
8356 | (bt == VT_INT && bit_size != 32))) |
- | |
8357 | error("initializer element is not computable at load time"); |
- | |
8358 | switch(bt) { |
- | |
8359 | case VT_BYTE: |
- | |
8360 | *(char *)ptr |= (vtop->c.i & bit_mask) << bit_pos; |
- | |
8361 | break; |
- | |
8362 | case VT_SHORT: |
- | |
8363 | *(short *)ptr |= (vtop->c.i & bit_mask) << bit_pos; |
- | |
8364 | break; |
- | |
8365 | case VT_DOUBLE: |
- | |
8366 | *(double *)ptr = vtop->c.d; |
- | |
8367 | break; |
- | |
8368 | case VT_LDOUBLE: |
- | |
8369 | *(long double *)ptr = vtop->c.ld; |
- | |
8370 | break; |
- | |
8371 | case VT_LLONG: |
- | |
8372 | *(long long *)ptr |= (vtop->c.ll & bit_mask) << bit_pos; |
- | |
8373 | break; |
- | |
8374 | default: |
- | |
8375 | if (vtop->r & VT_SYM) { |
- | |
8376 | greloc(sec, vtop->sym, c, R_DATA_32); |
- | |
8377 | } |
- | |
8378 | *(int *)ptr |= (vtop->c.i & bit_mask) << bit_pos; |
- | |
8379 | break; |
- | |
8380 | } |
- | |
8381 | vtop--; |
- | |
8382 | } else { |
- | |
8383 | vset(&dtype, VT_LOCAL, c); |
- | |
8384 | vswap(); |
- | |
8385 | vstore(); |
- | |
8386 | vpop(); |
- | |
8387 | } |
- | |
8388 | } |
- | |
8389 | - | ||
8390 | /* put zeros for variable based init */ |
- | |
8391 | static void init_putz(CType *t, Section *sec, unsigned long c, int size) |
- | |
8392 | { |
- | |
8393 | if (sec) { |
- | |
8394 | /* nothing to do because globals are already set to zero */ |
- | |
8395 | } else { |
- | |
8396 | vpush_global_sym(&func_old_type, TOK_memset); |
- | |
8397 | vseti(VT_LOCAL, c); |
- | |
8398 | vpushi(0); |
- | |
8399 | vpushi(size); |
- | |
8400 | gfunc_call(3); |
- | |
8401 | } |
- | |
8402 | } |
- | |
8403 | - | ||
8404 | /* 't' contains the type and storage info. 'c' is the offset of the |
- | |
8405 | object in section 'sec'. If 'sec' is NULL, it means stack based |
- | |
8406 | allocation. 'first' is true if array '{' must be read (multi |
- | |
8407 | dimension implicit array init handling). 'size_only' is true if |
- | |
8408 | size only evaluation is wanted (only for arrays). */ |
- | |
8409 | static void decl_initializer(CType *type, Section *sec, unsigned long c, |
- | |
8410 | int first, int size_only) |
- | |
8411 | { |
- | |
8412 | int index, array_length, n, no_oblock, nb, parlevel, i; |
- | |
8413 | int size1, align1, expr_type; |
- | |
8414 | Sym *s, *f; |
- | |
8415 | CType *t1; |
- | |
8416 | - | ||
8417 | if (type->t & VT_ARRAY) { |
- | |
8418 | s = type->ref; |
- | |
8419 | n = s->c; |
- | |
8420 | array_length = 0; |
- | |
8421 | t1 = pointed_type(type); |
- | |
8422 | size1 = type_size(t1, &align1); |
- | |
8423 | - | ||
8424 | no_oblock = 1; |
- | |
8425 | if ((first && tok != TOK_LSTR && tok != TOK_STR) || |
- | |
8426 | tok == '{') { |
- | |
8427 | skip('{'); |
- | |
8428 | no_oblock = 0; |
- | |
8429 | } |
- | |
8430 | - | ||
8431 | /* only parse strings here if correct type (otherwise: handle |
- | |
8432 | them as ((w)char *) expressions */ |
- | |
8433 | if ((tok == TOK_LSTR && |
- | |
8434 | (t1->t & VT_BTYPE) == VT_INT) || |
- | |
8435 | (tok == TOK_STR && |
- | |
8436 | (t1->t & VT_BTYPE) == VT_BYTE)) { |
- | |
8437 | while (tok == TOK_STR || tok == TOK_LSTR) { |
- | |
8438 | int cstr_len, ch; |
- | |
8439 | CString *cstr; |
- | |
8440 | - | ||
8441 | cstr = tokc.cstr; |
- | |
8442 | /* compute maximum number of chars wanted */ |
- | |
8443 | if (tok == TOK_STR) |
- | |
8444 | cstr_len = cstr->size; |
- | |
8445 | else |
- | |
8446 | cstr_len = cstr->size / sizeof(int); |
- | |
8447 | cstr_len--; |
- | |
8448 | nb = cstr_len; |
- | |
8449 | if (n >= 0 && nb > (n - array_length)) |
- | |
8450 | nb = n - array_length; |
- | |
8451 | if (!size_only) { |
- | |
8452 | if (cstr_len > nb) |
- | |
8453 | warning("initializer-string for array is too long"); |
- | |
8454 | /* in order to go faster for common case (char |
- | |
8455 | string in global variable, we handle it |
- | |
8456 | specifically */ |
- | |
8457 | if (sec && tok == TOK_STR && size1 == 1) { |
- | |
8458 | memcpy(sec->data + c + array_length, cstr->data, nb); |
- | |
8459 | } else { |
- | |
8460 | for(i=0;i |
- | |
8461 | if (tok == TOK_STR) |
- | |
8462 | ch = ((unsigned char *)cstr->data)[i]; |
- | |
8463 | else |
- | |
8464 | ch = ((int *)cstr->data)[i]; |
- | |
8465 | init_putv(t1, sec, c + (array_length + i) * size1, |
- | |
8466 | ch, EXPR_VAL); |
- | |
8467 | } |
- | |
8468 | } |
- | |
8469 | } |
- | |
8470 | array_length += nb; |
- | |
8471 | next(); |
- | |
8472 | } |
- | |
8473 | /* only add trailing zero if enough storage (no |
- | |
8474 | warning in this case since it is standard) */ |
- | |
8475 | if (n < 0 || array_length < n) { |
- | |
8476 | if (!size_only) { |
- | |
8477 | init_putv(t1, sec, c + (array_length * size1), 0, EXPR_VAL); |
- | |
8478 | } |
- | |
8479 | array_length++; |
- | |
8480 | } |
- | |
8481 | } else { |
- | |
8482 | index = 0; |
- | |
8483 | while (tok != '}') { |
- | |
8484 | decl_designator(type, sec, c, &index, NULL, size_only); |
- | |
8485 | if (n >= 0 && index >= n) |
- | |
8486 | error("index too large"); |
- | |
8487 | /* must put zero in holes (note that doing it that way |
- | |
8488 | ensures that it even works with designators) */ |
- | |
8489 | if (!size_only && array_length < index) { |
- | |
8490 | init_putz(t1, sec, c + array_length * size1, |
- | |
8491 | (index - array_length) * size1); |
- | |
8492 | } |
- | |
8493 | index++; |
- | |
8494 | if (index > array_length) |
- | |
8495 | array_length = index; |
- | |
8496 | /* special test for multi dimensional arrays (may not |
- | |
8497 | be strictly correct if designators are used at the |
- | |
8498 | same time) */ |
- | |
8499 | if (index >= n && no_oblock) |
- | |
8500 | break; |
- | |
8501 | if (tok == '}') |
- | |
8502 | break; |
- | |
8503 | skip(','); |
- | |
8504 | } |
- | |
8505 | } |
- | |
8506 | if (!no_oblock) |
- | |
8507 | skip('}'); |
- | |
8508 | /* put zeros at the end */ |
- | |
8509 | if (!size_only && n >= 0 && array_length < n) { |
- | |
8510 | init_putz(t1, sec, c + array_length * size1, |
- | |
8511 | (n - array_length) * size1); |
- | |
8512 | } |
- | |
8513 | /* patch type size if needed */ |
- | |
8514 | if (n < 0) |
- | |
8515 | s->c = array_length; |
- | |
8516 | } else if ((type->t & VT_BTYPE) == VT_STRUCT && |
- | |
8517 | (sec || !first || tok == '{')) { |
- | |
8518 | int par_count; |
- | |
8519 | - | ||
8520 | /* NOTE: the previous test is a specific case for automatic |
- | |
8521 | struct/union init */ |
- | |
8522 | /* XXX: union needs only one init */ |
- | |
8523 | - | ||
8524 | /* XXX: this test is incorrect for local initializers |
- | |
8525 | beginning with ( without {. It would be much more difficult |
- | |
8526 | to do it correctly (ideally, the expression parser should |
- | |
8527 | be used in all cases) */ |
- | |
8528 | par_count = 0; |
- | |
8529 | if (tok == '(') { |
- | |
8530 | AttributeDef ad1; |
- | |
8531 | CType type1; |
- | |
8532 | next(); |
- | |
8533 | while (tok == '(') { |
- | |
8534 | par_count++; |
- | |
8535 | next(); |
- | |
8536 | } |
- | |
8537 | if (!parse_btype(&type1, &ad1)) |
- | |
8538 | expect("cast"); |
- | |
8539 | type_decl(&type1, &ad1, &n, TYPE_ABSTRACT); |
- | |
8540 | #if 0 |
- | |
8541 | if (!is_assignable_types(type, &type1)) |
- | |
8542 | error("invalid type for cast"); |
- | |
8543 | #endif |
- | |
8544 | skip(')'); |
- | |
8545 | } |
- | |
8546 | no_oblock = 1; |
- | |
8547 | if (first || tok == '{') { |
- | |
8548 | skip('{'); |
- | |
8549 | no_oblock = 0; |
- | |
8550 | } |
- | |
8551 | s = type->ref; |
- | |
8552 | f = s->next; |
- | |
8553 | array_length = 0; |
- | |
8554 | index = 0; |
- | |
8555 | n = s->c; |
- | |
8556 | while (tok != '}') { |
- | |
8557 | decl_designator(type, sec, c, NULL, &f, size_only); |
- | |
8558 | index = f->c; |
- | |
8559 | if (!size_only && array_length < index) { |
- | |
8560 | init_putz(type, sec, c + array_length, |
- | |
8561 | index - array_length); |
- | |
8562 | } |
- | |
8563 | index = index + type_size(&f->type, &align1); |
- | |
8564 | if (index > array_length) |
- | |
8565 | array_length = index; |
- | |
8566 | f = f->next; |
- | |
8567 | if (no_oblock && f == NULL) |
- | |
8568 | break; |
- | |
8569 | if (tok == '}') |
- | |
8570 | break; |
- | |
8571 | skip(','); |
- | |
8572 | } |
- | |
8573 | /* put zeros at the end */ |
- | |
8574 | if (!size_only && array_length < n) { |
- | |
8575 | init_putz(type, sec, c + array_length, |
- | |
8576 | n - array_length); |
- | |
8577 | } |
- | |
8578 | if (!no_oblock) |
- | |
8579 | skip('}'); |
- | |
8580 | while (par_count) { |
- | |
8581 | skip(')'); |
- | |
8582 | par_count--; |
- | |
8583 | } |
- | |
8584 | } else if (tok == '{') { |
- | |
8585 | next(); |
- | |
8586 | decl_initializer(type, sec, c, first, size_only); |
- | |
8587 | skip('}'); |
- | |
8588 | } else if (size_only) { |
- | |
8589 | /* just skip expression */ |
- | |
8590 | parlevel = 0; |
- | |
8591 | while ((parlevel > 0 || (tok != '}' && tok != ',')) && |
- | |
8592 | tok != -1) { |
- | |
8593 | if (tok == '(') |
- | |
8594 | parlevel++; |
- | |
8595 | else if (tok == ')') |
- | |
8596 | parlevel--; |
- | |
8597 | next(); |
- | |
8598 | } |
- | |
8599 | } else { |
- | |
8600 | /* currently, we always use constant expression for globals |
- | |
8601 | (may change for scripting case) */ |
- | |
8602 | expr_type = EXPR_CONST; |
- | |
8603 | if (!sec) |
- | |
8604 | expr_type = EXPR_ANY; |
- | |
8605 | init_putv(type, sec, c, 0, expr_type); |
- | |
8606 | } |
- | |
8607 | } |
- | |
8608 | - | ||
8609 | /* parse an initializer for type 't' if 'has_init' is non zero, and |
- | |
8610 | allocate space in local or global data space ('r' is either |
- | |
8611 | VT_LOCAL or VT_CONST). If 'v' is non zero, then an associated |
- | |
8612 | variable 'v' of scope 'scope' is declared before initializers are |
- | |
8613 | parsed. If 'v' is zero, then a reference to the new object is put |
- | |
8614 | in the value stack. If 'has_init' is 2, a special parsing is done |
- | |
8615 | to handle string constants. */ |
- | |
8616 | static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, |
- | |
8617 | int has_init, int v, int scope) |
- | |
8618 | { |
- | |
8619 | int size, align, addr, data_offset; |
- | |
8620 | int level; |
- | |
8621 | ParseState saved_parse_state; |
- | |
8622 | TokenString init_str; |
- | |
8623 | Section *sec; |
- | |
8624 | - | ||
8625 | size = type_size(type, &align); |
- | |
8626 | /* If unknown size, we must evaluate it before |
- | |
8627 | evaluating initializers because |
- | |
8628 | initializers can generate global data too |
- | |
8629 | (e.g. string pointers or ISOC99 compound |
- | |
8630 | literals). It also simplifies local |
- | |
8631 | initializers handling */ |
- | |
8632 | tok_str_new(&init_str); |
- | |
8633 | if (size < 0) { |
- | |
8634 | if (!has_init) |
- | |
8635 | error("unknown type size"); |
- | |
8636 | /* get all init string */ |
- | |
8637 | if (has_init == 2) { |
- | |
8638 | /* only get strings */ |
- | |
8639 | while (tok == TOK_STR || tok == TOK_LSTR) { |
- | |
8640 | tok_str_add_tok(&init_str); |
- | |
8641 | next(); |
- | |
8642 | } |
- | |
8643 | } else { |
- | |
8644 | level = 0; |
- | |
8645 | while (level > 0 || (tok != ',' && tok != ';')) { |
- | |
8646 | if (tok < 0) |
- | |
8647 | error("unexpected end of file in initializer"); |
- | |
8648 | tok_str_add_tok(&init_str); |
- | |
8649 | if (tok == '{') |
- | |
8650 | level++; |
- | |
8651 | else if (tok == '}') { |
- | |
8652 | if (level == 0) |
- | |
8653 | break; |
- | |
8654 | level--; |
- | |
8655 | } |
- | |
8656 | next(); |
- | |
8657 | } |
- | |
8658 | } |
- | |
8659 | tok_str_add(&init_str, -1); |
- | |
8660 | tok_str_add(&init_str, 0); |
- | |
8661 | - | ||
8662 | /* compute size */ |
- | |
8663 | save_parse_state(&saved_parse_state); |
- | |
8664 | - | ||
8665 | macro_ptr = init_str.str; |
- | |
8666 | next(); |
- | |
8667 | decl_initializer(type, NULL, 0, 1, 1); |
- | |
8668 | /* prepare second initializer parsing */ |
- | |
8669 | macro_ptr = init_str.str; |
- | |
8670 | next(); |
- | |
8671 | - | ||
8672 | /* if still unknown size, error */ |
- | |
8673 | size = type_size(type, &align); |
- | |
8674 | if (size < 0) |
- | |
8675 | error("unknown type size"); |
- | |
8676 | } |
- | |
8677 | /* take into account specified alignment if bigger */ |
- | |
8678 | if (ad->aligned) { |
- | |
8679 | if (ad->aligned > align) |
- | |
8680 | align = ad->aligned; |
- | |
8681 | } else if (ad->packed) { |
- | |
8682 | align = 1; |
- | |
8683 | } |
- | |
8684 | if ((r & VT_VALMASK) == VT_LOCAL) { |
- | |
8685 | sec = NULL; |
- | |
8686 | if (do_bounds_check && (type->t & VT_ARRAY)) |
- | |
8687 | loc--; |
- | |
8688 | loc = (loc - size) & -align; |
- | |
8689 | addr = loc; |
- | |
8690 | /* handles bounds */ |
- | |
8691 | /* XXX: currently, since we do only one pass, we cannot track |
- | |
8692 | '&' operators, so we add only arrays */ |
- | |
8693 | if (do_bounds_check && (type->t & VT_ARRAY)) { |
- | |
8694 | unsigned long *bounds_ptr; |
- | |
8695 | /* add padding between regions */ |
- | |
8696 | loc--; |
- | |
8697 | /* then add local bound info */ |
- | |
8698 | bounds_ptr = section_ptr_add(lbounds_section, 2 * sizeof(unsigned long)); |
- | |
8699 | bounds_ptr[0] = addr; |
- | |
8700 | bounds_ptr[1] = size; |
- | |
8701 | } |
- | |
8702 | if (v) { |
- | |
8703 | /* local variable */ |
- | |
8704 | sym_push(v, type, r, addr); |
- | |
8705 | } else { |
- | |
8706 | /* push local reference */ |
- | |
8707 | vset(type, r, addr); |
- | |
8708 | } |
- | |
8709 | } else { |
- | |
8710 | Sym *sym; |
- | |
8711 | - | ||
8712 | sym = NULL; |
- | |
8713 | if (v && scope == VT_CONST) { |
- | |
8714 | /* see if the symbol was already defined */ |
- | |
8715 | sym = sym_find(v); |
- | |
8716 | if (sym) { |
- | |
8717 | if (!is_compatible_types(&sym->type, type)) |
- | |
8718 | error("incompatible types for redefinition of '%s'", |
- | |
8719 | get_tok_str(v, NULL)); |
- | |
8720 | if (sym->type.t & VT_EXTERN) { |
- | |
8721 | /* if the variable is extern, it was not allocated */ |
- | |
8722 | sym->type.t &= ~VT_EXTERN; |
- | |
8723 | /* set array size if it was ommited in extern |
- | |
8724 | declaration */ |
- | |
8725 | if ((sym->type.t & VT_ARRAY) && |
- | |
8726 | sym->type.ref->c < 0 && |
- | |
8727 | type->ref->c >= 0) |
- | |
8728 | sym->type.ref->c = type->ref->c; |
- | |
8729 | } else { |
- | |
8730 | /* we accept several definitions of the same |
- | |
8731 | global variable. this is tricky, because we |
- | |
8732 | must play with the SHN_COMMON type of the symbol */ |
- | |
8733 | /* XXX: should check if the variable was already |
- | |
8734 | initialized. It is incorrect to initialized it |
- | |
8735 | twice */ |
- | |
8736 | /* no init data, we won't add more to the symbol */ |
- | |
8737 | if (!has_init) |
- | |
8738 | goto no_alloc; |
- | |
8739 | } |
- | |
8740 | } |
- | |
8741 | } |
- | |
8742 | - | ||
8743 | /* allocate symbol in corresponding section */ |
- | |
8744 | sec = ad->section; |
- | |
8745 | if (!sec) { |
- | |
8746 | if (has_init) |
- | |
8747 | sec = data_section; |
- | |
8748 | else if (tcc_state->nocommon) |
- | |
8749 | sec = bss_section; |
- | |
8750 | } |
- | |
8751 | if (sec) { |
- | |
8752 | data_offset = sec->data_offset; |
- | |
8753 | data_offset = (data_offset + align - 1) & -align; |
- | |
8754 | addr = data_offset; |
- | |
8755 | /* very important to increment global pointer at this time |
- | |
8756 | because initializers themselves can create new initializers */ |
- | |
8757 | data_offset += size; |
- | |
8758 | /* add padding if bound check */ |
- | |
8759 | if (do_bounds_check) |
- | |
8760 | data_offset++; |
- | |
8761 | sec->data_offset = data_offset; |
- | |
8762 | /* allocate section space to put the data */ |
- | |
8763 | if (sec->sh_type != SHT_NOBITS && |
- | |
8764 | data_offset > sec->data_allocated) |
- | |
8765 | section_realloc(sec, data_offset); |
- | |
8766 | /* align section if needed */ |
- | |
8767 | if (align > sec->sh_addralign) |
- | |
8768 | sec->sh_addralign = align; |
- | |
8769 | } else { |
- | |
8770 | addr = 0; /* avoid warning */ |
- | |
8771 | } |
- | |
8772 | - | ||
8773 | if (v) { |
- | |
8774 | if (scope == VT_CONST) { |
- | |
8775 | if (!sym) |
- | |
8776 | goto do_def; |
- | |
8777 | } else { |
- | |
8778 | do_def: |
- | |
8779 | sym = sym_push(v, type, r | VT_SYM, 0); |
- | |
8780 | } |
- | |
8781 | /* update symbol definition */ |
- | |
8782 | if (sec) { |
- | |
8783 | put_extern_sym(sym, sec, addr, size); |
- | |
8784 | } else { |
- | |
8785 | Elf32_Sym *esym; |
- | |
8786 | /* put a common area */ |
- | |
8787 | put_extern_sym(sym, NULL, align, size); |
- | |
8788 | /* XXX: find a nicer way */ |
- | |
8789 | esym = &((Elf32_Sym *)symtab_section->data)[sym->c]; |
- | |
8790 | esym->st_shndx = SHN_COMMON; |
- | |
8791 | } |
- | |
8792 | } else { |
- | |
8793 | CValue cval; |
- | |
8794 | - | ||
8795 | /* push global reference */ |
- | |
8796 | sym = get_sym_ref(type, sec, addr, size); |
- | |
8797 | cval.ul = 0; |
- | |
8798 | vsetc(type, VT_CONST | VT_SYM, &cval); |
- | |
8799 | vtop->sym = sym; |
- | |
8800 | } |
- | |
8801 | - | ||
8802 | /* handles bounds now because the symbol must be defined |
- | |
8803 | before for the relocation */ |
- | |
8804 | if (do_bounds_check) { |
- | |
8805 | unsigned long *bounds_ptr; |
- | |
8806 | - | ||
8807 | greloc(bounds_section, sym, bounds_section->data_offset, R_DATA_32); |
- | |
8808 | /* then add global bound info */ |
- | |
8809 | bounds_ptr = section_ptr_add(bounds_section, 2 * sizeof(long)); |
- | |
8810 | bounds_ptr[0] = 0; /* relocated */ |
- | |
8811 | bounds_ptr[1] = size; |
- | |
8812 | } |
- | |
8813 | } |
- | |
8814 | if (has_init) { |
- | |
8815 | decl_initializer(type, sec, addr, 1, 0); |
- | |
8816 | /* restore parse state if needed */ |
- | |
8817 | if (init_str.str) { |
- | |
8818 | tok_str_free(init_str.str); |
- | |
8819 | restore_parse_state(&saved_parse_state); |
- | |
8820 | } |
- | |
8821 | } |
- | |
8822 | no_alloc: ; |
- | |
8823 | } |
- | |
8824 | - | ||
8825 | void put_func_debug(Sym *sym) |
- | |
8826 | { |
- | |
8827 | char buf[512]; |
- | |
8828 | - | ||
8829 | /* stabs info */ |
- | |
8830 | /* XXX: we put here a dummy type */ |
- | |
8831 | snprintf(buf, sizeof(buf), "%s:%c1", |
- | |
8832 | funcname, sym->type.t & VT_STATIC ? 'f' : 'F'); |
- | |
8833 | put_stabs_r(buf, N_FUN, 0, file->line_num, 0, |
- | |
8834 | cur_text_section, sym->c); |
- | |
8835 | last_ind = 0; |
- | |
8836 | last_line_num = 0; |
- | |
8837 | } |
- | |
8838 | - | ||
8839 | /* parse an old style function declaration list */ |
- | |
8840 | /* XXX: check multiple parameter */ |
- | |
8841 | static void func_decl_list(Sym *func_sym) |
- | |
8842 | { |
- | |
8843 | AttributeDef ad; |
- | |
8844 | int v; |
- | |
8845 | Sym *s; |
- | |
8846 | CType btype, type; |
- | |
8847 | - | ||
8848 | /* parse each declaration */ |
- | |
8849 | while (tok != '{' && tok != ';' && tok != ',' && tok != TOK_EOF) { |
- | |
8850 | if (!parse_btype(&btype, &ad)) |
- | |
8851 | expect("declaration list"); |
- | |
8852 | if (((btype.t & VT_BTYPE) == VT_ENUM || |
- | |
8853 | (btype.t & VT_BTYPE) == VT_STRUCT) && |
- | |
8854 | tok == ';') { |
- | |
8855 | /* we accept no variable after */ |
- | |
8856 | } else { |
- | |
8857 | for(;;) { |
- | |
8858 | type = btype; |
- | |
8859 | type_decl(&type, &ad, &v, TYPE_DIRECT); |
- | |
8860 | /* find parameter in function parameter list */ |
- | |
8861 | s = func_sym->next; |
- | |
8862 | while (s != NULL) { |
- | |
8863 | if ((s->v & ~SYM_FIELD) == v) |
- | |
8864 | goto found; |
- | |
8865 | s = s->next; |
- | |
8866 | } |
- | |
8867 | error("declaration for parameter '%s' but no such parameter", |
- | |
8868 | get_tok_str(v, NULL)); |
- | |
8869 | found: |
- | |
8870 | /* check that no storage specifier except 'register' was given */ |
- | |
8871 | if (type.t & VT_STORAGE) |
- | |
8872 | error("storage class specified for '%s'", get_tok_str(v, NULL)); |
- | |
8873 | convert_parameter_type(&type); |
- | |
8874 | /* we can add the type (NOTE: it could be local to the function) */ |
- | |
8875 | s->type = type; |
- | |
8876 | /* accept other parameters */ |
- | |
8877 | if (tok == ',') |
- | |
8878 | next(); |
- | |
8879 | else |
- | |
8880 | break; |
- | |
8881 | } |
- | |
8882 | } |
- | |
8883 | skip(';'); |
- | |
8884 | } |
- | |
8885 | } |
- | |
8886 | - | ||
8887 | /* parse a function defined by symbol 'sym' and generate its code in |
- | |
8888 | 'cur_text_section' */ |
- | |
8889 | static void gen_function(Sym *sym) |
- | |
8890 | { |
- | |
8891 | ind = cur_text_section->data_offset; |
- | |
8892 | /* NOTE: we patch the symbol size later */ |
- | |
8893 | put_extern_sym(sym, cur_text_section, ind, 0); |
- | |
8894 | funcname = get_tok_str(sym->v, NULL); |
- | |
8895 | func_ind = ind; |
- | |
8896 | /* put debug symbol */ |
- | |
8897 | if (do_debug) |
- | |
8898 | put_func_debug(sym); |
- | |
8899 | /* push a dummy symbol to enable local sym storage */ |
- | |
8900 | sym_push2(&local_stack, SYM_FIELD, 0, 0); |
- | |
8901 | gfunc_prolog(&sym->type); |
- | |
8902 | rsym = 0; |
- | |
8903 | block(NULL, NULL, NULL, NULL, 0, 0); |
- | |
8904 | gsym(rsym); |
- | |
8905 | gfunc_epilog(); |
- | |
8906 | cur_text_section->data_offset = ind; |
- | |
8907 | label_pop(&global_label_stack, NULL); |
- | |
8908 | sym_pop(&local_stack, NULL); /* reset local stack */ |
- | |
8909 | /* end of function */ |
- | |
8910 | /* patch symbol size */ |
- | |
8911 | ((Elf32_Sym *)symtab_section->data)[sym->c].st_size = |
- | |
8912 | ind - func_ind; |
- | |
8913 | if (do_debug) { |
- | |
8914 | put_stabn(N_FUN, 0, 0, ind - func_ind); |
- | |
8915 | } |
- | |
8916 | funcname = ""; /* for safety */ |
- | |
8917 | func_vt.t = VT_VOID; /* for safety */ |
- | |
8918 | ind = 0; /* for safety */ |
- | |
8919 | } |
- | |
8920 | - | ||
8921 | static void gen_inline_functions(void) |
- | |
8922 | { |
- | |
8923 | Sym *sym; |
- | |
8924 | CType *type; |
- | |
8925 | int *str, inline_generated; |
- | |
8926 | - | ||
8927 | /* iterate while inline function are referenced */ |
- | |
8928 | for(;;) { |
- | |
8929 | inline_generated = 0; |
- | |
8930 | for(sym = global_stack; sym != NULL; sym = sym->prev) { |
- | |
8931 | type = &sym->type; |
- | |
8932 | if (((type->t & VT_BTYPE) == VT_FUNC) && |
- | |
8933 | (type->t & (VT_STATIC | VT_INLINE)) == |
- | |
8934 | (VT_STATIC | VT_INLINE) && |
- | |
8935 | sym->c != 0) { |
- | |
8936 | /* the function was used: generate its code and |
- | |
8937 | convert it to a normal function */ |
- | |
8938 | str = (int *)sym->r; |
- | |
8939 | sym->r = VT_SYM | VT_CONST; |
- | |
8940 | type->t &= ~VT_INLINE; |
- | |
8941 | - | ||
8942 | macro_ptr = str; |
- | |
8943 | next(); |
- | |
8944 | cur_text_section = text_section; |
- | |
8945 | gen_function(sym); |
- | |
8946 | macro_ptr = NULL; /* fail safe */ |
- | |
8947 | - | ||
8948 | tok_str_free(str); |
- | |
8949 | inline_generated = 1; |
- | |
8950 | } |
- | |
8951 | } |
- | |
8952 | if (!inline_generated) |
- | |
8953 | break; |
- | |
8954 | } |
- | |
8955 | - | ||
8956 | /* free all remaining inline function tokens */ |
- | |
8957 | for(sym = global_stack; sym != NULL; sym = sym->prev) { |
- | |
8958 | type = &sym->type; |
- | |
8959 | if (((type->t & VT_BTYPE) == VT_FUNC) && |
- | |
8960 | (type->t & (VT_STATIC | VT_INLINE)) == |
- | |
8961 | (VT_STATIC | VT_INLINE)) { |
- | |
8962 | str = (int *)sym->r; |
- | |
8963 | tok_str_free(str); |
- | |
8964 | sym->r = 0; /* fail safe */ |
- | |
8965 | } |
- | |
8966 | } |
- | |
8967 | } |
- | |
8968 | - | ||
8969 | /* 'l' is VT_LOCAL or VT_CONST to define default storage type */ |
- | |
8970 | static void decl(int l) |
- | |
8971 | { |
- | |
8972 | int v, has_init, r; |
- | |
8973 | CType type, btype; |
- | |
8974 | Sym *sym; |
- | |
8975 | AttributeDef ad; |
- | |
8976 | - | ||
8977 | while (1) { |
- | |
8978 | if (!parse_btype(&btype, &ad)) { |
- | |
8979 | /* skip redundant ';' */ |
- | |
8980 | /* XXX: find more elegant solution */ |
- | |
8981 | if (tok == ';') { |
- | |
8982 | next(); |
- | |
8983 | continue; |
- | |
8984 | } |
- | |
8985 | if (l == VT_CONST && |
- | |
8986 | (tok == TOK_ASM1 || tok == TOK_ASM2 || tok == TOK_ASM3)) { |
- | |
8987 | /* global asm block */ |
- | |
8988 | asm_global_instr(); |
- | |
8989 | continue; |
- | |
8990 | } |
- | |
8991 | /* special test for old K&R protos without explicit int |
- | |
8992 | type. Only accepted when defining global data */ |
- | |
8993 | if (l == VT_LOCAL || tok < TOK_DEFINE) |
- | |
8994 | break; |
- | |
8995 | btype.t = VT_INT; |
- | |
8996 | } |
- | |
8997 | if (((btype.t & VT_BTYPE) == VT_ENUM || |
- | |
8998 | (btype.t & VT_BTYPE) == VT_STRUCT) && |
- | |
8999 | tok == ';') { |
- | |
9000 | /* we accept no variable after */ |
- | |
9001 | next(); |
- | |
9002 | continue; |
- | |
9003 | } |
- | |
9004 | while (1) { /* iterate thru each declaration */ |
- | |
9005 | type = btype; |
- | |
9006 | type_decl(&type, &ad, &v, TYPE_DIRECT); |
- | |
9007 | #if 0 |
- | |
9008 | { |
- | |
9009 | char buf[500]; |
- | |
9010 | type_to_str(buf, sizeof(buf), t, get_tok_str(v, NULL)); |
- | |
9011 | printf("type = '%s'\n", buf); |
- | |
9012 | } |
- | |
9013 | #endif |
- | |
9014 | if ((type.t & VT_BTYPE) == VT_FUNC) { |
- | |
9015 | /* if old style function prototype, we accept a |
- | |
9016 | declaration list */ |
- | |
9017 | sym = type.ref; |
- | |
9018 | if (sym->c == FUNC_OLD) |
- | |
9019 | func_decl_list(sym); |
- | |
9020 | } |
- | |
9021 | - | ||
9022 | if (tok == '{') { |
- | |
9023 | if (l == VT_LOCAL) |
- | |
9024 | error("cannot use local functions"); |
- | |
9025 | if (!(type.t & VT_FUNC)) |
- | |
9026 | expect("function definition"); |
- | |
9027 | - | ||
9028 | /* reject abstract declarators in function definition */ |
- | |
9029 | sym = type.ref; |
- | |
9030 | while ((sym = sym->next) != NULL) |
- | |
9031 | if (!(sym->v & ~SYM_FIELD)) |
- | |
9032 | expect("identifier"); |
- | |
9033 | - | ||
9034 | /* XXX: cannot do better now: convert extern line to static inline */ |
- | |
9035 | if ((type.t & (VT_EXTERN | VT_INLINE)) == (VT_EXTERN | VT_INLINE)) |
- | |
9036 | type.t = (type.t & ~VT_EXTERN) | VT_STATIC; |
- | |
9037 | - | ||
9038 | sym = sym_find(v); |
- | |
9039 | if (sym) { |
- | |
9040 | if ((sym->type.t & VT_BTYPE) != VT_FUNC) |
- | |
9041 | goto func_error1; |
- | |
9042 | /* specific case: if not func_call defined, we put |
- | |
9043 | the one of the prototype */ |
- | |
9044 | /* XXX: should have default value */ |
- | |
9045 | if (sym->type.ref->r != FUNC_CDECL && |
- | |
9046 | type.ref->r == FUNC_CDECL) |
- | |
9047 | type.ref->r = sym->type.ref->r; |
- | |
9048 | if (!is_compatible_types(&sym->type, &type)) { |
- | |
9049 | func_error1: |
- | |
9050 | error("incompatible types for redefinition of '%s'", |
- | |
9051 | get_tok_str(v, NULL)); |
- | |
9052 | } |
- | |
9053 | /* if symbol is already defined, then put complete type */ |
- | |
9054 | sym->type = type; |
- | |
9055 | } else { |
- | |
9056 | /* put function symbol */ |
- | |
9057 | sym = global_identifier_push(v, type.t, 0); |
- | |
9058 | sym->type.ref = type.ref; |
- | |
9059 | } |
- | |
9060 | - | ||
9061 | /* static inline functions are just recorded as a kind |
- | |
9062 | of macro. Their code will be emitted at the end of |
- | |
9063 | the compilation unit only if they are used */ |
- | |
9064 | if ((type.t & (VT_INLINE | VT_STATIC)) == |
- | |
9065 | (VT_INLINE | VT_STATIC)) { |
- | |
9066 | TokenString func_str; |
- | |
9067 | int block_level; |
- | |
9068 | - | ||
9069 | tok_str_new(&func_str); |
- | |
9070 | - | ||
9071 | block_level = 0; |
- | |
9072 | for(;;) { |
- | |
9073 | int t; |
- | |
9074 | if (tok == TOK_EOF) |
- | |
9075 | error("unexpected end of file"); |
- | |
9076 | tok_str_add_tok(&func_str); |
- | |
9077 | t = tok; |
- | |
9078 | next(); |
- | |
9079 | if (t == '{') { |
- | |
9080 | block_level++; |
- | |
9081 | } else if (t == '}') { |
- | |
9082 | block_level--; |
- | |
9083 | if (block_level == 0) |
- | |
9084 | break; |
- | |
9085 | } |
- | |
9086 | } |
- | |
9087 | tok_str_add(&func_str, -1); |
- | |
9088 | tok_str_add(&func_str, 0); |
- | |
9089 | sym->r = (int)func_str.str; |
- | |
9090 | } else { |
- | |
9091 | /* compute text section */ |
- | |
9092 | cur_text_section = ad.section; |
- | |
9093 | if (!cur_text_section) |
117 | " -g generate runtime debug info\n" |
9094 | cur_text_section = text_section; |
- | |
9095 | sym->r = VT_SYM | VT_CONST; |
- | |
9096 | gen_function(sym); |
- | |
9097 | #ifdef TCC_TARGET_PE |
- | |
9098 | if (ad.dllexport) { |
- | |
9099 | ((Elf32_Sym *)symtab_section->data)[sym->c].st_other |= 1; |
- | |
9100 | } |
- | |
9101 | #endif |
- | |
9102 | } |
- | |
9103 | break; |
- | |
9104 | } else { |
- | |
9105 | if (btype.t & VT_TYPEDEF) { |
- | |
9106 | /* save typedefed type */ |
- | |
9107 | /* XXX: test storage specifiers ? */ |
- | |
9108 | sym = sym_push(v, &type, 0, 0); |
- | |
9109 | sym->type.t |= VT_TYPEDEF; |
- | |
9110 | } else if ((type.t & VT_BTYPE) == VT_FUNC) { |
- | |
9111 | /* external function definition */ |
- | |
9112 | /* specific case for func_call attribute */ |
- | |
9113 | if (ad.func_call) |
118 | #ifdef CONFIG_TCC_BCHECK |
9114 | type.ref->r = ad.func_call; |
- | |
9115 | external_sym(v, &type, 0); |
- | |
9116 | } else { |
- | |
9117 | /* not lvalue if array */ |
- | |
9118 | r = 0; |
- | |
9119 | if (!(type.t & VT_ARRAY)) |
- | |
9120 | r |= lvalue_type(type.t); |
- | |
9121 | has_init = (tok == '='); |
- | |
9122 | if ((btype.t & VT_EXTERN) || |
- | |
9123 | ((type.t & VT_ARRAY) && (type.t & VT_STATIC) && |
- | |
9124 | !has_init && l == VT_CONST && type.ref->c < 0)) { |
- | |
9125 | /* external variable */ |
- | |
9126 | /* NOTE: as GCC, uninitialized global static |
- | |
9127 | arrays of null size are considered as |
- | |
9128 | extern */ |
- | |
9129 | external_sym(v, &type, r); |
- | |
9130 | } else { |
- | |
9131 | if (type.t & VT_STATIC) |
- | |
9132 | r |= VT_CONST; |
- | |
9133 | else |
- | |
9134 | r |= l; |
- | |
9135 | if (has_init) |
- | |
9136 | next(); |
- | |
9137 | decl_initializer_alloc(&type, &ad, r, |
- | |
9138 | has_init, v, l); |
- | |
9139 | } |
- | |
9140 | } |
- | |
9141 | if (tok != ',') { |
- | |
9142 | skip(';'); |
- | |
9143 | break; |
- | |
9144 | } |
- | |
9145 | next(); |
- | |
9146 | } |
- | |
9147 | } |
- | |
9148 | } |
- | |
9149 | } |
- | |
9150 | - | ||
9151 | /* better than nothing, but needs extension to handle '-E' option |
- | |
9152 | correctly too */ |
- | |
9153 | static void preprocess_init(TCCState *s1) |
- | |
9154 | { |
- | |
9155 | s1->include_stack_ptr = s1->include_stack; |
- | |
9156 | /* XXX: move that before to avoid having to initialize |
- | |
9157 | file->ifdef_stack_ptr ? */ |
- | |
9158 | s1->ifdef_stack_ptr = s1->ifdef_stack; |
- | |
9159 | file->ifdef_stack_ptr = s1->ifdef_stack_ptr; |
- | |
9160 | - | ||
9161 | /* XXX: not ANSI compliant: bound checking says error */ |
- | |
9162 | vtop = vstack - 1; |
- | |
9163 | s1->pack_stack[0] = 0; |
- | |
9164 | s1->pack_stack_ptr = s1->pack_stack; |
- | |
9165 | } |
- | |
9166 | - | ||
9167 | /* compile the C file opened in 'file'. Return non zero if errors. */ |
- | |
9168 | static int tcc_compile(TCCState *s1) |
- | |
9169 | { |
- | |
9170 | Sym *define_start; |
- | |
9171 | char buf[512]; |
- | |
9172 | volatile int section_sym; |
- | |
9173 | - | ||
9174 | #ifdef INC_DEBUG |
- | |
9175 | printf("%s: **** new file\n", file->filename); |
- | |
9176 | #endif |
- | |
9177 | preprocess_init(s1); |
- | |
9178 | - | ||
9179 | funcname = ""; |
- | |
9180 | anon_sym = SYM_FIRST_ANOM; |
- | |
9181 | - | ||
9182 | /* file info: full path + filename */ |
- | |
9183 | section_sym = 0; /* avoid warning */ |
- | |
9184 | if (do_debug) { |
- | |
9185 | section_sym = put_elf_sym(symtab_section, 0, 0, |
- | |
9186 | ELF32_ST_INFO(STB_LOCAL, STT_SECTION), 0, |
- | |
9187 | text_section->sh_num, NULL); |
- | |
9188 | getcwd(buf, sizeof(buf)); |
- | |
9189 | pstrcat(buf, sizeof(buf), "/"); |
- | |
9190 | put_stabs_r(buf, N_SO, 0, 0, |
- | |
9191 | text_section->data_offset, text_section, section_sym); |
- | |
9192 | put_stabs_r(file->filename, N_SO, 0, 0, |
- | |
9193 | text_section->data_offset, text_section, section_sym); |
- | |
9194 | } |
- | |
9195 | /* an elf symbol of type STT_FILE must be put so that STB_LOCAL |
- | |
9196 | symbols can be safely used */ |
- | |
9197 | put_elf_sym(symtab_section, 0, 0, |
- | |
9198 | ELF32_ST_INFO(STB_LOCAL, STT_FILE), 0, |
- | |
9199 | SHN_ABS, file->filename); |
- | |
9200 | - | ||
9201 | /* define some often used types */ |
- | |
9202 | int_type.t = VT_INT; |
- | |
9203 | - | ||
9204 | char_pointer_type.t = VT_BYTE; |
- | |
9205 | mk_pointer(&char_pointer_type); |
- | |
9206 | - | ||
9207 | func_old_type.t = VT_FUNC; |
- | |
9208 | func_old_type.ref = sym_push(SYM_FIELD, &int_type, FUNC_CDECL, FUNC_OLD); |
- | |
9209 | - | ||
9210 | #if 0 |
- | |
9211 | /* define 'void *alloca(unsigned int)' builtin function */ |
- | |
9212 | { |
- | |
9213 | Sym *s1; |
- | |
9214 | - | ||
9215 | p = anon_sym++; |
- | |
9216 | sym = sym_push(p, mk_pointer(VT_VOID), FUNC_CDECL, FUNC_NEW); |
- | |
9217 | s1 = sym_push(SYM_FIELD, VT_UNSIGNED | VT_INT, 0, 0); |
- | |
9218 | s1->next = NULL; |
119 | " -b compile with built-in memory and bounds checker (implies -g)\n" |
9219 | sym->next = s1; |
- | |
9220 | sym_push(TOK_alloca, VT_FUNC | (p << VT_STRUCT_SHIFT), VT_CONST, 0); |
- | |
9221 | } |
- | |
9222 | #endif |
- | |
9223 | - | ||
9224 | define_start = define_stack; |
- | |
9225 | - | ||
9226 | if (setjmp(s1->error_jmp_buf) == 0) { |
120 | #endif |
9227 | s1->nb_errors = 0; |
121 | #ifdef CONFIG_TCC_BACKTRACE |
9228 | s1->error_set_jmp_enabled = 1; |
122 | " -bt N show N callers in stack traces\n" |
9229 | - | ||
9230 | ch = file->buf_ptr[0]; |
- | |
9231 | tok_flags = TOK_FLAG_BOL | TOK_FLAG_BOF; |
- | |
9232 | parse_flags = PARSE_FLAG_PREPROCESS | PARSE_FLAG_TOK_NUM; |
- | |
9233 | next(); |
- | |
9234 | decl(VT_CONST); |
123 | #endif |
9235 | if (tok != TOK_EOF) |
- | |
9236 | expect("declaration"); |
124 | "Misc options:\n" |
9237 | 125 | " -nostdinc do not use standard system include paths\n" |
|
9238 | /* end of translation unit info */ |
126 | " -nostdlib do not link with standard crt and libraries\n" |
9239 | if (do_debug) { |
- | |
9240 | put_stabs_r(NULL, N_SO, 0, 0, |
- | |
9241 | text_section->data_offset, text_section, section_sym); |
- | |
9242 | } |
- | |
9243 | } |
- | |
9244 | s1->error_set_jmp_enabled = 0; |
- | |
9245 | - | ||
9246 | /* reset define stack, but leave -Dsymbols (may be incorrect if |
- | |
9247 | they are undefined) */ |
- | |
9248 | free_defines(define_start); |
- | |
9249 | - | ||
9250 | gen_inline_functions(); |
- | |
9251 | 127 | " -Bdir use 'dir' as tcc internal library and include path\n" |
|
Line -... | Line 128... | ||
- | 128 | " -MD generate target dependencies for make\n" |
|
- | 129 | " -MF depfile put generated dependencies here\n" |
|
9252 | sym_pop(&global_stack, NULL); |
130 | ); |
- | 131 | } |
|
9253 | 132 | ||
9254 | return s1->nb_errors != 0 ? -1 : 0; |
133 | /* re-execute the i386/x86_64 cross-compilers with tcc -m32/-m64: */ |
9255 | } |
- | |
9256 | - | ||
9257 | #ifdef LIBTCC |
- | |
9258 | int tcc_compile_string(TCCState *s, const char *str) |
- | |
9259 | { |
- | |
9260 | BufferedFile bf1, *bf = &bf1; |
- | |
9261 | int ret, len; |
- | |
9262 | char *buf; |
- | |
9263 | - | ||
9264 | /* init file structure */ |
- | |
9265 | bf->fd = -1; |
- | |
9266 | /* XXX: avoid copying */ |
- | |
9267 | len = strlen(str); |
- | |
9268 | buf = tcc_malloc(len + 1); |
- | |
9269 | if (!buf) |
- | |
9270 | return -1; |
134 | #if (defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64) && !defined(TCC_TARGET_MEOS) |
9271 | memcpy(buf, str, len); |
- | |
9272 | buf[len] = CH_EOB; |
135 | #ifdef _WIN32 |
9273 | bf->buf_ptr = buf; |
- | |
9274 | bf->buf_end = buf + len; |
- | |
9275 | pstrcpy(bf->filename, sizeof(bf->filename), " |
- | |
9276 | bf->line_num = 1; |
- | |
9277 | file = bf; |
- | |
9278 | - | ||
9279 | ret = tcc_compile(s); |
136 | #include |
- | 137 | static int execvp_win32(const char *prog, char **argv) |
|
- | 138 | { |
|
9280 | 139 | int ret = spawnvp(P_NOWAIT, prog, (const char *const*)argv); |
|
- | 140 | if (-1 == ret) |
|
9281 | tcc_free(buf); |
141 | return ret; |
9282 | - | ||
9283 | /* currently, no need to close */ |
- | |
9284 | return ret; |
142 | cwait(&ret, ret, WAIT_CHILD); |
9285 | } |
143 | exit(ret); |
9286 | #endif |
- | |
9287 | - | ||
9288 | /* define a preprocessor symbol. A value can also be provided with the '=' operator */ |
- | |
9289 | void tcc_define_symbol(TCCState *s1, const char *sym, const char *value) |
- | |
9290 | { |
- | |
9291 | BufferedFile bf1, *bf = &bf1; |
- | |
9292 | - | ||
9293 | pstrcpy(bf->buffer, IO_BUF_SIZE, sym); |
- | |
9294 | pstrcat(bf->buffer, IO_BUF_SIZE, " "); |
- | |
9295 | /* default value */ |
- | |
9296 | if (!value) |
- | |
9297 | value = "1"; |
- | |
9298 | pstrcat(bf->buffer, IO_BUF_SIZE, value); |
- | |
9299 | - | ||
9300 | /* init file structure */ |
- | |
9301 | bf->fd = -1; |
- | |
9302 | bf->buf_ptr = bf->buffer; |
- | |
9303 | bf->buf_end = bf->buffer + strlen(bf->buffer); |
- | |
9304 | *bf->buf_end = CH_EOB; |
- | |
9305 | bf->filename[0] = '\0'; |
- | |
9306 | bf->line_num = 1; |
- | |
9307 | file = bf; |
- | |
9308 | - | ||
9309 | s1->include_stack_ptr = s1->include_stack; |
- | |
9310 | - | ||
9311 | /* parse with define parser */ |
- | |
9312 | ch = file->buf_ptr[0]; |
- | |
9313 | next_nomacro(); |
- | |
9314 | parse_define(); |
144 | } |
9315 | file = NULL; |
- | |
9316 | } |
- | |
9317 | - | ||
9318 | /* undefine a preprocessor symbol */ |
- | |
9319 | void tcc_undefine_symbol(TCCState *s1, const char *sym) |
145 | #define execvp execvp_win32 |
9320 | { |
- | |
9321 | TokenSym *ts; |
- | |
9322 | Sym *s; |
- | |
9323 | ts = tok_alloc(sym, strlen(sym)); |
- | |
9324 | s = define_find(ts->tok); |
- | |
9325 | /* undefine symbol by putting an invalid name */ |
- | |
9326 | if (s) |
- | |
9327 | define_undef(s); |
146 | #endif |
9328 | } |
- | |
9329 | - | ||
9330 | #ifdef CONFIG_TCC_ASM |
- | |
9331 | - | ||
9332 | #ifdef TCC_TARGET_I386 |
- | |
9333 | #include "i386-asm.c" |
- | |
9334 | #endif |
- | |
9335 | #include "tccasm.c" |
- | |
9336 | - | ||
9337 | #else |
- | |
9338 | static void asm_instr(void) |
- | |
9339 | { |
- | |
9340 | error("inline asm() not supported"); |
- | |
9341 | } |
- | |
9342 | static void asm_global_instr(void) |
- | |
9343 | { |
- | |
9344 | error("inline asm() not supported"); |
- | |
9345 | } |
- | |
9346 | #endif |
- | |
9347 | - | ||
9348 | #include "tccelf.c" |
- | |
9349 | - | ||
9350 | #ifdef TCC_TARGET_COFF |
- | |
9351 | #include "tcccoff.c" |
- | |
9352 | #endif |
- | |
9353 | - | ||
9354 | #if defined(TCC_TARGET_PE) || defined(TCC_TARGET_MEOS) |
- | |
9355 | #include "tccpe.c" |
- | |
9356 | #endif |
- | |
9357 | - | ||
9358 | #ifdef TCC_TARGET_MEOS |
- | |
9359 | #include "tccmeos.c" |
- | |
9360 | #endif |
- | |
9361 | - | ||
9362 | /* print the position in the source file of PC value 'pc' by reading |
- | |
9363 | the stabs debug information */ |
- | |
9364 | static void rt_printline(unsigned long wanted_pc) |
- | |
9365 | { |
- | |
9366 | Stab_Sym *sym, *sym_end; |
- | |
9367 | char func_name[128], last_func_name[128]; |
- | |
9368 | unsigned long func_addr, last_pc, pc; |
- | |
9369 | const char *incl_files[INCLUDE_STACK_SIZE]; |
- | |
9370 | int incl_index, len, last_line_num, i; |
- | |
9371 | const char *str, *p; |
- | |
9372 | - | ||
9373 | printf("0x%08lx:", wanted_pc); |
- | |
9374 | - | ||
9375 | func_name[0] = '\0'; |
- | |
9376 | func_addr = 0; |
- | |
9377 | incl_index = 0; |
- | |
9378 | last_func_name[0] = '\0'; |
- | |
9379 | last_pc = 0xffffffff; |
- | |
9380 | last_line_num = 1; |
- | |
9381 | sym = (Stab_Sym *)stab_section->data + 1; |
- | |
9382 | sym_end = (Stab_Sym *)(stab_section->data + stab_section->data_offset); |
- | |
9383 | while (sym < sym_end) { |
- | |
9384 | switch(sym->n_type) { |
- | |
9385 | /* function start or end */ |
- | |
9386 | case N_FUN: |
- | |
9387 | if (sym->n_strx == 0) { |
- | |
9388 | /* we test if between last line and end of function */ |
- | |
9389 | pc = sym->n_value + func_addr; |
- | |
9390 | if (wanted_pc >= last_pc && wanted_pc < pc) |
- | |
9391 | goto found; |
- | |
9392 | func_name[0] = '\0'; |
- | |
9393 | func_addr = 0; |
- | |
9394 | } else { |
- | |
9395 | str = stabstr_section->data + sym->n_strx; |
- | |
9396 | p = strchr(str, ':'); |
- | |
9397 | if (!p) { |
- | |
9398 | pstrcpy(func_name, sizeof(func_name), str); |
- | |
9399 | } else { |
- | |
9400 | len = p - str; |
- | |
9401 | if (len > sizeof(func_name) - 1) |
- | |
9402 | len = sizeof(func_name) - 1; |
- | |
9403 | memcpy(func_name, str, len); |
- | |
9404 | func_name[len] = '\0'; |
- | |
9405 | } |
- | |
9406 | func_addr = sym->n_value; |
- | |
9407 | } |
- | |
9408 | break; |
- | |
9409 | /* line number info */ |
- | |
9410 | case N_SLINE: |
- | |
9411 | pc = sym->n_value + func_addr; |
- | |
9412 | if (wanted_pc >= last_pc && wanted_pc < pc) |
- | |
9413 | goto found; |
- | |
9414 | last_pc = pc; |
- | |
9415 | last_line_num = sym->n_desc; |
- | |
9416 | /* XXX: slow! */ |
- | |
9417 | strcpy(last_func_name, func_name); |
- | |
9418 | break; |
- | |
9419 | /* include files */ |
- | |
9420 | case N_BINCL: |
- | |
9421 | str = stabstr_section->data + sym->n_strx; |
- | |
9422 | add_incl: |
- | |
9423 | if (incl_index < INCLUDE_STACK_SIZE) { |
- | |
9424 | incl_files[incl_index++] = str; |
- | |
9425 | } |
147 | static void exec_other_tcc(TCCState *s, char **argv, const char *optarg) |
9426 | break; |
- | |
9427 | case N_EINCL: |
- | |
9428 | if (incl_index > 1) |
- | |
9429 | incl_index--; |
- | |
9430 | break; |
- | |
9431 | case N_SO: |
- | |
9432 | if (sym->n_strx == 0) { |
- | |
9433 | incl_index = 0; /* end of translation unit */ |
- | |
9434 | } else { |
148 | { |
9435 | str = stabstr_section->data + sym->n_strx; |
- | |
9436 | /* do not add path */ |
- | |
9437 | len = strlen(str); |
- | |
9438 | if (len > 0 && str[len - 1] != '/') |
- | |
9439 | goto add_incl; |
- | |
9440 | } |
- | |
9441 | break; |
- | |
9442 | } |
- | |
9443 | sym++; |
- | |
9444 | } |
- | |
9445 | - | ||
9446 | /* second pass: we try symtab symbols (no line number info) */ |
- | |
9447 | incl_index = 0; |
- | |
9448 | { |
- | |
9449 | Elf32_Sym *sym, *sym_end; |
- | |
9450 | int type; |
- | |
9451 | - | ||
9452 | sym_end = (Elf32_Sym *)(symtab_section->data + symtab_section->data_offset); |
- | |
9453 | for(sym = (Elf32_Sym *)symtab_section->data + 1; |
- | |
9454 | sym < sym_end; |
- | |
9455 | sym++) { |
- | |
9456 | type = ELF32_ST_TYPE(sym->st_info); |
- | |
9457 | if (type == STT_FUNC) { |
- | |
9458 | if (wanted_pc >= sym->st_value && |
- | |
9459 | wanted_pc < sym->st_value + sym->st_size) { |
- | |
9460 | pstrcpy(last_func_name, sizeof(last_func_name), |
- | |
9461 | strtab_section->data + sym->st_name); |
- | |
9462 | goto found; |
- | |
9463 | } |
- | |
9464 | } |
- | |
9465 | } |
- | |
9466 | } |
- | |
9467 | /* did not find any info: */ |
- | |
9468 | printf(" ???\n"); |
- | |
9469 | return; |
- | |
9470 | found: |
- | |
9471 | if (last_func_name[0] != '\0') { |
- | |
9472 | printf(" %s()", last_func_name); |
- | |
9473 | } |
- | |
9474 | if (incl_index > 0) { |
- | |
9475 | printf(" (%s:%d", |
- | |
9476 | incl_files[incl_index - 1], last_line_num); |
- | |
9477 | for(i = incl_index - 2; i >= 0; i--) |
- | |
9478 | printf(", included from %s", incl_files[i]); |
- | |
9479 | printf(")"); |
- | |
9480 | } |
- | |
9481 | printf("\n"); |
- | |
9482 | } |
- | |
9483 | - | ||
9484 | #if !defined(WIN32) && !defined(CONFIG_TCCBOOT) |
- | |
9485 | - | ||
9486 | #ifdef __i386__ |
- | |
9487 | - | ||
9488 | /* fix for glibc 2.1 */ |
- | |
9489 | #ifndef REG_EIP |
- | |
9490 | #define REG_EIP EIP |
- | |
9491 | #define REG_EBP EBP |
- | |
9492 | #endif |
- | |
9493 | - | ||
9494 | /* return the PC at frame level 'level'. Return non zero if not found */ |
- | |
9495 | /* |
- | |
9496 | static int rt_get_caller_pc(unsigned long *paddr, |
- | |
9497 | ucontext_t *uc, int level) |
- | |
9498 | { |
- | |
9499 | unsigned long fp; |
- | |
9500 | int i; |
- | |
9501 | - | ||
9502 | if (level == 0) { |
149 | char child_path[4096], *child_name; const char *target; |
- | 150 | switch (atoi(optarg)) { |
|
9503 | #if defined(__FreeBSD__) |
151 | #ifdef TCC_TARGET_I386 |
9504 | *paddr = uc->uc_mcontext.mc_eip; |
152 | case 32: break; |
9505 | #elif defined(__dietlibc__) |
- | |
9506 | *paddr = uc->uc_mcontext.eip; |
- | |
9507 | #else |
- | |
9508 | *paddr = uc->uc_mcontext.gregs[REG_EIP]; |
153 | case 64: target = "x86_64"; |
9509 | #endif |
- | |
9510 | return 0; |
- | |
9511 | } else { |
- | |
9512 | #if defined(__FreeBSD__) |
154 | #else |
9513 | fp = uc->uc_mcontext.mc_ebp; |
- | |
9514 | #elif defined(__dietlibc__) |
155 | case 64: break; |
9515 | fp = uc->uc_mcontext.ebp; |
- | |
9516 | #else |
- | |
9517 | fp = uc->uc_mcontext.gregs[REG_EBP]; |
156 | case 32: target = "i386"; |
9518 | #endif |
157 | #endif |
9519 | for(i=1;i |
- | |
9520 | // XXX: check address validity with program info |
- | |
9521 | if (fp <= 0x1000 || fp >= 0xc0000000) |
- | |
9522 | return -1; |
- | |
9523 | fp = ((unsigned long *)fp)[0]; |
- | |
9524 | } |
- | |
9525 | *paddr = ((unsigned long *)fp)[1]; |
- | |
9526 | return 0; |
- | |
9527 | } |
158 | pstrcpy(child_path, sizeof child_path - 40, argv[0]); |
9528 | } |
- | |
9529 | */ |
- | |
9530 | #else |
159 | child_name = tcc_basename(child_path); |
9531 | - | ||
9532 | #warning add arch specific rt_get_caller_pc() |
- | |
9533 | /* |
- | |
9534 | static int rt_get_caller_pc(unsigned long *paddr, |
- | |
9535 | ucontext_t *uc, int level) |
160 | strcpy(child_name, target); |
9536 | { |
- | |
9537 | return -1; |
- | |
9538 | } |
- | |
9539 | */ |
- | |
9540 | #endif |
- | |
9541 | - | ||
9542 | /* emit a run time error at position 'pc' */ |
- | |
9543 | /* |
- | |
9544 | void rt_error(ucontext_t *uc, const char *fmt, ...) |
- | |
9545 | { |
- | |
9546 | va_list ap; |
- | |
9547 | unsigned long pc; |
161 | #ifdef TCC_TARGET_PE |
9548 | int i; |
- | |
9549 | - | ||
9550 | va_start(ap, fmt); |
162 | strcat(child_name, "-win32"); |
9551 | printf("Runtime error: "); |
- | |
9552 | //vfprintf(stderr, fmt, ap); |
163 | #elif defined TCC_TARGET_MEOS |
9553 | printf("\n"); |
164 | strcat(child_name, "-kos32"); |
9554 | for(i=0;i |
- | |
9555 | if (rt_get_caller_pc(&pc, uc, i) < 0) |
165 | #endif |
9556 | break; |
- | |
9557 | if (i == 0) |
- | |
9558 | printf("at "); |
- | |
9559 | else |
- | |
9560 | printf("by "); |
166 | strcat(child_name, "-tcc"); |
9561 | rt_printline(pc); |
- | |
9562 | } |
- | |
9563 | exit(255); |
- | |
9564 | va_end(ap); |
- | |
9565 | } |
167 | if (strcmp(argv[0], child_path)) { |
9566 | - | ||
9567 | */ |
- | |
9568 | /* signal handler for fatal errors */ |
- | |
9569 | /* |
- | |
9570 | static void sig_error(int signum, siginfo_t *siginf, void *puc) |
- | |
9571 | { |
168 | if (s->verbose > 0) |
9572 | ucontext_t *uc = puc; |
- | |
9573 | - | ||
9574 | switch(signum) { |
- | |
9575 | case SIGFPE: |
169 | printf("tcc: using '%s'\n", child_name), fflush(stdout); |
9576 | switch(siginf->si_code) { |
170 | execvp(argv[0] = child_path, argv); |
9577 | case FPE_INTDIV: |
- | |
9578 | case FPE_FLTDIV: |
- | |
9579 | rt_error(uc, "division by zero"); |
- | |
9580 | break; |
- | |
9581 | default: |
- | |
9582 | rt_error(uc, "floating point exception"); |
- | |
9583 | break; |
- | |
9584 | } |
- | |
9585 | break; |
- | |
9586 | case SIGBUS: |
171 | } |
9587 | case SIGSEGV: |
- | |
9588 | if (rt_bound_error_msg && *rt_bound_error_msg) |
- | |
9589 | rt_error(uc, *rt_bound_error_msg); |
- | |
9590 | else |
- | |
9591 | rt_error(uc, "dereferencing invalid pointer"); |
- | |
9592 | break; |
- | |
9593 | case SIGILL: |
- | |
9594 | rt_error(uc, "illegal instruction"); |
- | |
9595 | break; |
- | |
9596 | case SIGABRT: |
- | |
9597 | rt_error(uc, "abort() called"); |
- | |
9598 | break; |
- | |
9599 | default: |
- | |
9600 | rt_error(uc, "caught signal %d", signum); |
- | |
9601 | break; |
- | |
9602 | } |
- | |
9603 | exit(255); |
- | |
9604 | } |
- | |
9605 | */ |
- | |
9606 | #endif |
- | |
9607 | - | ||
9608 | - | ||
9609 | /* do all relocations (needed before using tcc_get_symbol()) */ |
- | |
9610 | int tcc_relocate(TCCState *s1) |
- | |
9611 | { |
- | |
9612 | Section *s; |
- | |
9613 | int i; |
- | |
9614 | - | ||
9615 | s1->nb_errors = 0; |
- | |
9616 | - | ||
9617 | #if defined(TCC_TARGET_PE) || defined(TCC_TARGET_MEOS) |
- | |
9618 | pe_add_runtime(s1); |
- | |
9619 | #else |
- | |
9620 | tcc_add_runtime(s1); |
- | |
9621 | #endif |
- | |
9622 | - | ||
9623 | relocate_common_syms(); |
- | |
9624 | - | ||
9625 | tcc_add_linker_symbols(s1); |
- | |
9626 | - | ||
9627 | build_got_entries(s1); |
- | |
9628 | - | ||
9629 | /* compute relocation address : section are relocated in place. We |
- | |
9630 | also alloc the bss space */ |
- | |
9631 | for(i = 1; i < s1->nb_sections; i++) { |
- | |
9632 | s = s1->sections[i]; |
- | |
9633 | if (s->sh_flags & SHF_ALLOC) { |
- | |
9634 | if (s->sh_type == SHT_NOBITS) |
- | |
9635 | s->data = tcc_mallocz(s->data_offset); |
- | |
9636 | s->sh_addr = (unsigned long)s->data; |
- | |
9637 | } |
- | |
9638 | } |
- | |
9639 | - | ||
9640 | relocate_syms(s1, 1); |
- | |
9641 | - | ||
9642 | if (s1->nb_errors != 0) |
- | |
9643 | return -1; |
- | |
9644 | - | ||
9645 | /* relocate each section */ |
- | |
9646 | for(i = 1; i < s1->nb_sections; i++) { |
- | |
9647 | s = s1->sections[i]; |
- | |
9648 | if (s->reloc) |
- | |
9649 | relocate_section(s1, s); |
- | |
9650 | } |
- | |
9651 | return 0; |
- | |
9652 | } |
- | |
9653 | - | ||
9654 | /* launch the compiled program with the given arguments */ |
- | |
9655 | int tcc_run(TCCState *s1, int argc, char **argv) |
- | |
9656 | { |
- | |
9657 | int (*prog_main)(int, char **); |
- | |
9658 | - | ||
9659 | if (tcc_relocate(s1) < 0) |
- | |
9660 | return -1; |
- | |
9661 | - | ||
9662 | prog_main = tcc_get_symbol_err(s1, "main"); |
- | |
9663 | - | ||
9664 | if (do_debug) { |
- | |
9665 | #if defined(WIN32) || defined(CONFIG_TCCBOOT) |
- | |
9666 | error("debug mode currently not available for Windows"); |
- | |
9667 | #else |
- | |
9668 | //struct sigaction sigact; |
- | |
9669 | /* install TCC signal handlers to print debug info on fatal |
- | |
9670 | runtime errors */ |
- | |
9671 | //sigact.sa_flags = SA_SIGINFO | SA_RESETHAND; |
- | |
9672 | //sigact.sa_sigaction = sig_error; |
- | |
9673 | //sigemptyset(&sigact.sa_mask); |
- | |
9674 | //sigaction(SIGFPE, &sigact, NULL); |
- | |
9675 | //sigaction(SIGILL, &sigact, NULL); |
- | |
9676 | //sigaction(SIGSEGV, &sigact, NULL); |
- | |
9677 | //sigaction(SIGBUS, &sigact, NULL); |
- | |
9678 | //sigaction(SIGABRT, &sigact, NULL); |
- | |
9679 | #endif |
- | |
9680 | } |
- | |
9681 | - | ||
9682 | #ifdef CONFIG_TCC_BCHECK |
- | |
9683 | if (do_bounds_check) { |
- | |
9684 | void (*bound_init)(void); |
- | |
9685 | - | ||
9686 | /* set error function */ |
- | |
9687 | rt_bound_error_msg = (void *)tcc_get_symbol_err(s1, |
- | |
9688 | "__bound_error_msg"); |
- | |
9689 | - | ||
9690 | /* XXX: use .init section so that it also work in binary ? */ |
- | |
9691 | bound_init = (void *)tcc_get_symbol_err(s1, "__bound_init"); |
172 | tcc_error("'%s' not found", child_name); |
9692 | bound_init(); |
- | |
9693 | } |
- | |
9694 | #endif |
- | |
9695 | return (*prog_main)(argc, argv); |
- | |
9696 | } |
- | |
9697 | - | ||
9698 | TCCState *tcc_new(void) |
- | |
9699 | { |
- | |
9700 | const char *p, *r; |
- | |
9701 | TCCState *s; |
- | |
9702 | TokenSym *ts; |
- | |
9703 | int i, c; |
- | |
9704 | - | ||
9705 | s = tcc_mallocz(sizeof(TCCState)); |
- | |
9706 | if (!s) |
- | |
9707 | return NULL; |
- | |
9708 | tcc_state = s; |
- | |
9709 | s->output_type = TCC_OUTPUT_MEMORY; |
- | |
9710 | - | ||
9711 | /* init isid table */ |
- | |
9712 | for(i=0;i<256;i++) |
- | |
9713 | isidnum_table[i] = isid(i) || isnum(i); |
- | |
9714 | - | ||
9715 | /* add all tokens */ |
- | |
9716 | table_ident = NULL; |
- | |
9717 | memset(hash_ident, 0, TOK_HASH_SIZE * sizeof(TokenSym *)); |
- | |
9718 | - | ||
9719 | tok_ident = TOK_IDENT; |
- | |
9720 | p = tcc_keywords; |
- | |
9721 | while (*p) { |
- | |
9722 | r = p; |
173 | case 0: /* ignore -march etc. */ |
9723 | for(;;) { |
- | |
9724 | c = *r++; |
- | |
9725 | if (c == '\0') |
- | |
9726 | break; |
- | |
9727 | } |
- | |
9728 | ts = tok_alloc(p, r - p - 1); |
- | |
9729 | p = r; |
- | |
9730 | } |
- | |
9731 | - | ||
9732 | /* we add dummy defines for some special macros to speed up tests |
- | |
9733 | and to have working defined() */ |
- | |
9734 | define_push(TOK___LINE__, MACRO_OBJ, NULL, NULL); |
- | |
9735 | define_push(TOK___FILE__, MACRO_OBJ, NULL, NULL); |
- | |
9736 | define_push(TOK___DATE__, MACRO_OBJ, NULL, NULL); |
- | |
9737 | define_push(TOK___TIME__, MACRO_OBJ, NULL, NULL); |
- | |
9738 | - | ||
9739 | /* standard defines */ |
- | |
9740 | tcc_define_symbol(s, "__STDC__", NULL); |
- | |
9741 | #if defined(TCC_TARGET_I386) |
- | |
9742 | tcc_define_symbol(s, "__i386__", NULL); |
- | |
9743 | #endif |
- | |
9744 | #if defined(TCC_TARGET_ARM) |
- | |
9745 | tcc_define_symbol(s, "__ARM_ARCH_4__", NULL); |
- | |
9746 | tcc_define_symbol(s, "__arm_elf__", NULL); |
- | |
9747 | tcc_define_symbol(s, "__arm_elf", NULL); |
- | |
9748 | tcc_define_symbol(s, "arm_elf", NULL); |
- | |
9749 | tcc_define_symbol(s, "__arm__", NULL); |
- | |
9750 | tcc_define_symbol(s, "__arm", NULL); |
- | |
9751 | tcc_define_symbol(s, "arm", NULL); |
- | |
9752 | tcc_define_symbol(s, "__APCS_32__", NULL); |
- | |
9753 | #endif |
- | |
9754 | #if defined(linux) |
- | |
9755 | tcc_define_symbol(s, "__linux__", NULL); |
- | |
9756 | tcc_define_symbol(s, "linux", NULL); |
- | |
9757 | #endif |
- | |
9758 | /* tiny C specific defines */ |
- | |
9759 | tcc_define_symbol(s, "__TINYC__", NULL); |
- | |
9760 | - | ||
9761 | /* tiny C & gcc defines */ |
- | |
9762 | tcc_define_symbol(s, "__SIZE_TYPE__", "unsigned int"); |
- | |
9763 | tcc_define_symbol(s, "__PTRDIFF_TYPE__", "int"); |
- | |
9764 | tcc_define_symbol(s, "__WCHAR_TYPE__", "int"); |
- | |
9765 | - | ||
9766 | /* default library paths */ |
- | |
9767 | #ifdef TCC_TARGET_PE |
- | |
9768 | { |
- | |
9769 | char buf[1024]; |
- | |
9770 | snprintf(buf, sizeof(buf), "%s/lib", tcc_lib_path); |
- | |
9771 | tcc_add_library_path(s, buf); |
174 | break; |
9772 | } |
- | |
9773 | #else |
- | |
9774 | #ifdef TCC_TARGET_MEOS |
- | |
9775 | tcc_add_library_path(s, ".//lib"); |
- | |
9776 | #else |
- | |
9777 | tcc_add_library_path(s, "/usr/local/lib"); |
- | |
9778 | tcc_add_library_path(s, "/usr/lib"); |
- | |
9779 | tcc_add_library_path(s, "/lib"); |
- | |
9780 | #endif |
- | |
9781 | #endif |
- | |
9782 | - | ||
9783 | /* no section zero */ |
- | |
9784 | dynarray_add((void ***)&s->sections, &s->nb_sections, NULL); |
- | |
9785 | - | ||
9786 | /* create standard sections */ |
- | |
9787 | text_section = new_section(s, ".text", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR); |
- | |
9788 | data_section = new_section(s, ".data", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE); |
- | |
9789 | bss_section = new_section(s, ".bss", SHT_NOBITS, SHF_ALLOC | SHF_WRITE); |
- | |
9790 | - | ||
9791 | /* symbols are always generated for linking stage */ |
- | |
9792 | symtab_section = new_symtab(s, ".symtab", SHT_SYMTAB, 0, |
- | |
9793 | ".strtab", |
- | |
9794 | ".hashtab", SHF_PRIVATE); |
- | |
9795 | strtab_section = symtab_section->link; |
- | |
9796 | - | ||
9797 | /* private symbol table for dynamic symbols */ |
- | |
9798 | s->dynsymtab_section = new_symtab(s, ".dynsymtab", SHT_SYMTAB, SHF_PRIVATE, |
- | |
9799 | ".dynstrtab", |
- | |
9800 | ".dynhashtab", SHF_PRIVATE); |
- | |
9801 | s->alacarte_link = 1; |
- | |
9802 | - | ||
9803 | #ifdef CHAR_IS_UNSIGNED |
- | |
9804 | s->char_is_unsigned = 1; |
- | |
9805 | #endif |
- | |
9806 | #if defined(TCC_TARGET_PE) && 0 |
- | |
9807 | /* XXX: currently the PE linker is not ready to support that */ |
- | |
9808 | s->leading_underscore = 1; |
- | |
9809 | #endif |
- | |
9810 | return s; |
- | |
9811 | } |
- | |
9812 | - | ||
9813 | void tcc_delete(TCCState *s1) |
- | |
9814 | { |
- | |
9815 | int i, n; |
- | |
9816 | - | ||
9817 | /* free -D defines */ |
- | |
9818 | free_defines(NULL); |
- | |
9819 | - | ||
9820 | /* free tokens */ |
- | |
9821 | n = tok_ident - TOK_IDENT; |
- | |
9822 | for(i = 0; i < n; i++) |
- | |
9823 | tcc_free(table_ident[i]); |
- | |
9824 | tcc_free(table_ident); |
- | |
9825 | - | ||
9826 | /* free all sections */ |
- | |
9827 | - | ||
9828 | free_section(symtab_section->hash); |
- | |
9829 | - | ||
9830 | free_section(s1->dynsymtab_section->hash); |
- | |
9831 | free_section(s1->dynsymtab_section->link); |
- | |
9832 | free_section(s1->dynsymtab_section); |
- | |
9833 | - | ||
9834 | for(i = 1; i < s1->nb_sections; i++) |
- | |
9835 | free_section(s1->sections[i]); |
- | |
9836 | tcc_free(s1->sections); |
- | |
9837 | - | ||
9838 | /* free loaded dlls array */ |
- | |
9839 | for(i = 0; i < s1->nb_loaded_dlls; i++) |
- | |
9840 | tcc_free(s1->loaded_dlls[i]); |
- | |
9841 | tcc_free(s1->loaded_dlls); |
- | |
9842 | - | ||
9843 | /* library paths */ |
- | |
9844 | for(i = 0; i < s1->nb_library_paths; i++) |
- | |
9845 | tcc_free(s1->library_paths[i]); |
- | |
9846 | tcc_free(s1->library_paths); |
- | |
9847 | - | ||
9848 | /* cached includes */ |
- | |
9849 | for(i = 0; i < s1->nb_cached_includes; i++) |
- | |
9850 | tcc_free(s1->cached_includes[i]); |
- | |
9851 | tcc_free(s1->cached_includes); |
- | |
9852 | - | ||
9853 | for(i = 0; i < s1->nb_include_paths; i++) |
- | |
9854 | tcc_free(s1->include_paths[i]); |
- | |
9855 | tcc_free(s1->include_paths); |
- | |
9856 | - | ||
9857 | for(i = 0; i < s1->nb_sysinclude_paths; i++) |
- | |
9858 | tcc_free(s1->sysinclude_paths[i]); |
- | |
9859 | tcc_free(s1->sysinclude_paths); |
- | |
9860 | - | ||
9861 | tcc_free(s1); |
- | |
9862 | } |
- | |
9863 | - | ||
9864 | int tcc_add_include_path(TCCState *s1, const char *pathname) |
- | |
9865 | { |
- | |
9866 | char *pathname1; |
- | |
9867 | - | ||
9868 | pathname1 = tcc_strdup(pathname); |
- | |
9869 | dynarray_add((void ***)&s1->include_paths, &s1->nb_include_paths, pathname1); |
- | |
9870 | return 0; |
- | |
9871 | } |
- | |
9872 | - | ||
9873 | int tcc_add_sysinclude_path(TCCState *s1, const char *pathname) |
- | |
9874 | { |
- | |
9875 | char *pathname1; |
- | |
9876 | - | ||
9877 | pathname1 = tcc_strdup(pathname); |
- | |
9878 | dynarray_add((void ***)&s1->sysinclude_paths, &s1->nb_sysinclude_paths, pathname1); |
- | |
9879 | return 0; |
- | |
9880 | } |
- | |
9881 | - | ||
9882 | static int tcc_add_file_internal(TCCState *s1, const char *filename, int flags) |
- | |
9883 | { |
- | |
9884 | const char *ext, *filename1; |
- | |
9885 | Elf32_Ehdr ehdr; |
- | |
9886 | int fd, ret; |
- | |
9887 | BufferedFile *saved_file; |
- | |
9888 | - | ||
9889 | /* find source file type with extension */ |
- | |
9890 | filename1 = strrchr(filename, '/'); |
- | |
9891 | if (filename1) |
- | |
9892 | filename1++; |
- | |
9893 | else |
- | |
9894 | filename1 = filename; |
- | |
9895 | ext = strrchr(filename1, '.'); |
- | |
9896 | if (ext) |
175 | default: |
9897 | ext++; |
- | |
9898 | - | ||
9899 | /* open the file */ |
- | |
9900 | saved_file = file; |
- | |
9901 | file = tcc_open(s1, filename); |
- | |
9902 | if (!file) { |
- | |
9903 | if (flags & AFF_PRINT_ERROR) { |
- | |
9904 | error_noabort("file '%s' not found", filename); |
- | |
9905 | } |
- | |
9906 | ret = -1; |
- | |
9907 | goto fail1; |
- | |
9908 | } |
- | |
9909 | - | ||
9910 | if (!ext || !strcmp(ext, "c")) { |
- | |
9911 | /* C file assumed */ |
- | |
9912 | ret = tcc_compile(s1); |
- | |
9913 | } else |
- | |
9914 | #ifdef CONFIG_TCC_ASM |
- | |
9915 | if (!strcmp(ext, "S")) { |
- | |
9916 | /* preprocessed assembler */ |
- | |
9917 | ret = tcc_assemble(s1, 1); |
- | |
9918 | } else if (!strcmp(ext, "s")) { |
- | |
9919 | /* non preprocessed assembler */ |
- | |
9920 | ret = tcc_assemble(s1, 0); |
- | |
9921 | } else |
- | |
9922 | #endif |
- | |
9923 | #ifdef TCC_TARGET_PE |
- | |
9924 | if (!strcmp(ext, "def")) { |
- | |
9925 | ret = pe_load_def_file(s1, fdopen(file->fd, "rb")); |
- | |
9926 | } else |
- | |
9927 | #endif |
- | |
9928 | { |
- | |
9929 | fd = file->fd; |
- | |
9930 | /* assume executable format: auto guess file type */ |
- | |
9931 | ret = read(fd, &ehdr, sizeof(ehdr)); |
- | |
9932 | lseek(fd, 0, SEEK_SET); |
- | |
9933 | if (ret <= 0) { |
- | |
9934 | error_noabort("could not read header"); |
- | |
9935 | goto fail; |
- | |
9936 | } else if (ret != sizeof(ehdr)) { |
- | |
9937 | goto try_load_script; |
- | |
9938 | } |
- | |
9939 | - | ||
9940 | if (ehdr.e_ident[0] == ELFMAG0 && |
- | |
9941 | ehdr.e_ident[1] == ELFMAG1 && |
- | |
9942 | ehdr.e_ident[2] == ELFMAG2 && |
- | |
9943 | ehdr.e_ident[3] == ELFMAG3) { |
- | |
9944 | file->line_num = 0; /* do not display line number if error */ |
- | |
9945 | if (ehdr.e_type == ET_REL) { |
- | |
9946 | ret = tcc_load_object_file(s1, fd, 0); |
- | |
9947 | } else if (ehdr.e_type == ET_DYN) { |
- | |
9948 | if (s1->output_type == TCC_OUTPUT_MEMORY) { |
- | |
9949 | #if defined(TCC_TARGET_PE) || defined(TCC_TARGET_MEOS) |
- | |
9950 | ret = -1; |
- | |
9951 | #else |
- | |
9952 | void *h; |
- | |
9953 | h = dlopen(filename, RTLD_GLOBAL | RTLD_LAZY); |
- | |
9954 | if (h) |
- | |
9955 | ret = 0; |
- | |
9956 | else |
- | |
9957 | ret = -1; |
- | |
9958 | #endif |
- | |
9959 | } else { |
- | |
9960 | ret = tcc_load_dll(s1, fd, filename, |
- | |
9961 | (flags & AFF_REFERENCED_DLL) != 0); |
- | |
9962 | } |
- | |
9963 | } else { |
- | |
9964 | error_noabort("unrecognized ELF file"); |
- | |
9965 | goto fail; |
- | |
9966 | } |
- | |
9967 | } else if (memcmp((char *)&ehdr, ARMAG, 8) == 0) { |
- | |
9968 | file->line_num = 0; /* do not display line number if error */ |
- | |
9969 | ret = tcc_load_archive(s1, fd); |
- | |
9970 | } else |
176 | tcc_warning("unsupported option \"-m%s\"", optarg); |
9971 | #ifdef TCC_TARGET_COFF |
- | |
9972 | if (*(uint16_t *)(&ehdr) == COFF_C67_MAGIC) { |
- | |
9973 | ret = tcc_load_coff(s1, fd); |
- | |
9974 | } else |
- | |
9975 | #endif |
- | |
9976 | { |
- | |
9977 | /* as GNU ld, consider it is an ld script if not recognized */ |
- | |
9978 | try_load_script: |
- | |
9979 | ret = tcc_load_ldscript(s1); |
- | |
9980 | if (ret < 0) { |
- | |
9981 | error_noabort("unrecognized file type"); |
- | |
9982 | goto fail; |
- | |
9983 | } |
- | |
9984 | } |
- | |
9985 | } |
- | |
9986 | the_end: |
- | |
9987 | tcc_close(file); |
- | |
9988 | fail1: |
- | |
9989 | file = saved_file; |
- | |
Line 9990... | Line 177... | ||
9990 | return ret; |
177 | } |
9991 | fail: |
178 | } |
9992 | ret = -1; |
- | |
9993 | goto the_end; |
- | |
9994 | } |
- | |
9995 | - | ||
9996 | int tcc_add_file(TCCState *s, const char *filename) |
- | |
9997 | { |
179 | #else |
9998 | return tcc_add_file_internal(s, filename, AFF_PRINT_ERROR); |
- | |
9999 | } |
- | |
10000 | - | ||
10001 | int tcc_add_library_path(TCCState *s, const char *pathname) |
- | |
10002 | { |
- | |
10003 | char *pathname1; |
- | |
10004 | - | ||
10005 | pathname1 = tcc_strdup(pathname); |
- | |
10006 | dynarray_add((void ***)&s->library_paths, &s->nb_library_paths, pathname1); |
- | |
10007 | return 0; |
- | |
10008 | } |
180 | #define exec_other_tcc(s, argv, optarg) |
10009 | 181 | #endif |
|
Line 10010... | Line 182... | ||
10010 | /* find and load a dll. Return non zero if not found */ |
182 | |
10011 | /* XXX: add '-rpath' option support ? */ |
183 | static void gen_makedeps(TCCState *s, const char *target, const char *filename) |
10012 | static int tcc_add_dll(TCCState *s, const char *filename, int flags) |
184 | { |
10013 | { |
185 | FILE *depout; |
10014 | char buf[1024]; |
186 | char buf[1024], *ext; |
10015 | int i; |
187 | int i; |
10016 | 188 | ||
10017 | for(i = 0; i < s->nb_library_paths; i++) { |
189 | if (!filename) { |
Line 10018... | Line -... | ||
10018 | snprintf(buf, sizeof(buf), "%s/%s", |
- | |
10019 | s->library_paths[i], filename); |
- | |
10020 | if (tcc_add_file_internal(s, buf, flags) == 0) |
- | |
10021 | return 0; |
- | |
10022 | } |
- | |
10023 | return -1; |
- | |
10024 | } |
- | |
10025 | 190 | /* compute filename automatically |
|
10026 | /* the library name is the same as the argument of the '-l' option */ |
- | |
10027 | int tcc_add_library(TCCState *s, const char *libraryname) |
191 | * dir/file.o -> dir/file.d */ |
10028 | { |
- | |
10029 | char buf[1024]; |
- | |
10030 | int i; |
- | |
10031 | - | ||
10032 | /* first we look for the dynamic library if not static linking */ |
- | |
10033 | if (!s->static_link) { |
- | |
Line 10034... | Line 192... | ||
10034 | #ifdef TCC_TARGET_PE |
192 | pstrcpy(buf, sizeof(buf), target); |
10035 | snprintf(buf, sizeof(buf), "%s.def", libraryname); |
193 | ext = tcc_fileextension(buf); |
10036 | #else |
194 | pstrcpy(ext, sizeof(buf) - (ext-buf), ".d"); |
10037 | snprintf(buf, sizeof(buf), "lib%s.so", libraryname); |
195 | filename = buf; |
10038 | #endif |
- | |
10039 | if (tcc_add_dll(s, buf, 0) == 0) |
- | |
10040 | return 0; |
- | |
10041 | } |
- | |
10042 | - | ||
Line 10043... | Line 196... | ||
10043 | /* then we look for the static library */ |
196 | } |
10044 | for(i = 0; i < s->nb_library_paths; i++) { |
- | |
10045 | snprintf(buf, sizeof(buf), "%s/lib%s.a", |
197 | |
10046 | s->library_paths[i], libraryname); |
198 | if (s->verbose) |
10047 | if (tcc_add_file_internal(s, buf, 0) == 0) |
199 | printf("<- %s\n", filename); |
10048 | return 0; |
200 | |
10049 | } |
201 | /* XXX return err codes instead of error() ? */ |
Line 10050... | Line 202... | ||
10050 | return -1; |
202 | depout = fopen(filename, "w"); |
10051 | } |
203 | if (!depout) |
10052 | - | ||
10053 | int tcc_add_symbol(TCCState *s, const char *name, unsigned long val) |
- | |
10054 | { |
- | |
10055 | add_elf_sym(symtab_section, val, 0, |
204 | tcc_error("could not open '%s'", filename); |
- | 205 | ||
- | 206 | fprintf(depout, "%s : \\\n", target); |
|
Line 10056... | Line -... | ||
10056 | ELF32_ST_INFO(STB_GLOBAL, STT_NOTYPE), 0, |
- | |
10057 | SHN_ABS, name); |
- | |
10058 | return 0; |
- | |
10059 | } |
- | |
10060 | 207 | for (i=0; i |
|
10061 | int tcc_set_output_type(TCCState *s, int output_type) |
- | |
10062 | { |
- | |
10063 | s->output_type = output_type; |
- | |
10064 | 208 | fprintf(depout, " %s \\\n", s->target_deps[i]); |
|
10065 | if (!s->nostdinc) { |
- | |
10066 | char buf[1024]; |
209 | fprintf(depout, "\n"); |
10067 | 210 | fclose(depout); |
|
10068 | /* default include paths */ |
211 | } |
10069 | /* XXX: reverse order needed if -isystem support */ |
- | |
10070 | #if !defined(TCC_TARGET_PE) && !defined(TCC_TARGET_MEOS) |
- | |
10071 | tcc_add_sysinclude_path(s, "/usr/local/include"); |
- | |
10072 | tcc_add_sysinclude_path(s, "/usr/include"); |
- | |
10073 | #endif |
- | |
10074 | - | ||
10075 | #if defined(TCC_TARGET_MEOS) |
- | |
10076 | tcc_add_sysinclude_path(s, ".//include"); |
- | |
10077 | #endif |
- | |
10078 | snprintf(buf, sizeof(buf), "%s/include", tcc_lib_path); |
- | |
10079 | tcc_add_sysinclude_path(s, buf); |
- | |
10080 | #ifdef TCC_TARGET_PE |
- | |
10081 | snprintf(buf, sizeof(buf), "%s/include/winapi", tcc_lib_path); |
- | |
10082 | tcc_add_sysinclude_path(s, buf); |
- | |
10083 | #endif |
- | |
10084 | } |
- | |
10085 | - | ||
10086 | /* if bound checking, then add corresponding sections */ |
- | |
10087 | #ifdef CONFIG_TCC_BCHECK |
- | |
10088 | if (do_bounds_check) { |
- | |
10089 | /* define symbol */ |
- | |
10090 | tcc_define_symbol(s, "__BOUNDS_CHECKING_ON", NULL); |
- | |
10091 | /* create bounds sections */ |
- | |
10092 | bounds_section = new_section(s, ".bounds", |
- | |
10093 | SHT_PROGBITS, SHF_ALLOC); |
- | |
10094 | lbounds_section = new_section(s, ".lbounds", |
- | |
10095 | SHT_PROGBITS, SHF_ALLOC); |
- | |
10096 | } |
- | |
10097 | #endif |
- | |
10098 | - | ||
10099 | if (s->char_is_unsigned) { |
- | |
10100 | tcc_define_symbol(s, "__CHAR_UNSIGNED__", NULL); |
- | |
10101 | } |
- | |
10102 | - | ||
10103 | /* add debug sections */ |
- | |
10104 | if (do_debug) { |
- | |
10105 | /* stab symbols */ |
- | |
10106 | stab_section = new_section(s, ".stab", SHT_PROGBITS, 0); |
- | |
10107 | stab_section->sh_entsize = sizeof(Stab_Sym); |
212 | |
10108 | stabstr_section = new_section(s, ".stabstr", SHT_STRTAB, 0); |
- | |
10109 | put_elf_str(stabstr_section, ""); |
213 | static char *default_outputfile(TCCState *s, const char *first_file) |
10110 | stab_section->link = stabstr_section; |
214 | { |
10111 | /* put first entry */ |
- | |
10112 | put_stabs("", 0, 0, 0, 0); |
- | |
10113 | } |
215 | char buf[1024]; |
10114 | - | ||
10115 | /* add libc crt1/crti objects */ |
- | |
10116 | #if !defined(TCC_TARGET_PE) && !defined(TCC_TARGET_MEOS) |
- | |
10117 | if ((output_type == TCC_OUTPUT_EXE || output_type == TCC_OUTPUT_DLL) && |
- | |
10118 | !s->nostdlib) { |
- | |
10119 | if (output_type != TCC_OUTPUT_DLL) |
- | |
10120 | tcc_add_file(s, CONFIG_TCC_CRT_PREFIX "/crt1.o"); |
- | |
10121 | tcc_add_file(s, CONFIG_TCC_CRT_PREFIX "/crti.o"); |
- | |
10122 | } |
- | |
10123 | #endif |
- | |
10124 | #if defined(TCC_TARGET_MEOS) |
- | |
10125 | if (s->output_type != TCC_OUTPUT_OBJ) |
- | |
10126 | tcc_add_file(s,".//start.o"); |
- | |
10127 | #endif |
- | |
10128 | return 0; |
- | |
10129 | } |
- | |
10130 | - | ||
10131 | #define WD_ALL 0x0001 /* warning is activated when using -Wall */ |
- | |
10132 | #define FD_INVERT 0x0002 /* invert value before storing */ |
- | |
10133 | - | ||
10134 | typedef struct FlagDef { |
- | |
10135 | uint16_t offset; |
- | |
10136 | uint16_t flags; |
- | |
10137 | const char *name; |
- | |
10138 | } FlagDef; |
- | |
10139 | - | ||
10140 | static const FlagDef warning_defs[] = { |
- | |
10141 | { offsetof(TCCState, warn_unsupported), 0, "unsupported" }, |
- | |
10142 | { offsetof(TCCState, warn_write_strings), 0, "write-strings" }, |
- | |
10143 | { offsetof(TCCState, warn_error), 0, "error" }, |
- | |
10144 | { offsetof(TCCState, warn_implicit_function_declaration), WD_ALL, |
- | |
10145 | "implicit-function-declaration" }, |
- | |
10146 | }; |
- | |
10147 | - | ||
10148 | static int set_flag(TCCState *s, const FlagDef *flags, int nb_flags, |
- | |
10149 | const char *name, int value) |
216 | char *ext; |
10150 | { |
- | |
10151 | int i; |
- | |
10152 | const FlagDef *p; |
- | |
10153 | const char *r; |
- | |
10154 | - | ||
10155 | r = name; |
- | |
10156 | if (r[0] == 'n' && r[1] == 'o' && r[2] == '-') { |
- | |
10157 | r += 3; |
- | |
10158 | value = !value; |
- | |
10159 | } |
- | |
10160 | for(i = 0, p = flags; i < nb_flags; i++, p++) { |
- | |
10161 | if (!strcmp(r, p->name)) |
- | |
10162 | goto found; |
- | |
10163 | } |
- | |
10164 | return -1; |
- | |
10165 | found: |
- | |
10166 | if (p->flags & FD_INVERT) |
- | |
10167 | value = !value; |
- | |
10168 | *(int *)((uint8_t *)s + p->offset) = value; |
- | |
10169 | return 0; |
- | |
10170 | } |
- | |
10171 | - | ||
10172 | - | ||
10173 | /* set/reset a warning */ |
217 | const char *name = "a"; |
10174 | int tcc_set_warning(TCCState *s, const char *warning_name, int value) |
- | |
10175 | { |
- | |
10176 | int i; |
- | |
10177 | const FlagDef *p; |
- | |
10178 | - | ||
10179 | if (!strcmp(warning_name, "all")) { |
- | |
10180 | for(i = 0, p = warning_defs; i < countof(warning_defs); i++, p++) { |
- | |
10181 | if (p->flags & WD_ALL) |
- | |
10182 | *(int *)((uint8_t *)s + p->offset) = 1; |
- | |
10183 | } |
- | |
10184 | return 0; |
- | |
10185 | } else { |
- | |
10186 | return set_flag(s, warning_defs, countof(warning_defs), |
- | |
10187 | warning_name, value); |
- | |
10188 | } |
- | |
10189 | } |
- | |
10190 | - | ||
10191 | static const FlagDef flag_defs[] = { |
- | |
10192 | { offsetof(TCCState, char_is_unsigned), 0, "unsigned-char" }, |
- | |
10193 | { offsetof(TCCState, char_is_unsigned), FD_INVERT, "signed-char" }, |
- | |
10194 | { offsetof(TCCState, nocommon), FD_INVERT, "common" }, |
- | |
10195 | { offsetof(TCCState, leading_underscore), 0, "leading-underscore" }, |
- | |
10196 | }; |
- | |
10197 | - | ||
10198 | /* set/reset a flag */ |
- | |
10199 | int tcc_set_flag(TCCState *s, const char *flag_name, int value) |
- | |
10200 | { |
- | |
10201 | return set_flag(s, flag_defs, countof(flag_defs), |
- | |
10202 | flag_name, value); |
- | |
10203 | } |
218 | |
- | 219 | if (first_file && strcmp(first_file, "-")) |
|
- | 220 | name = tcc_basename(first_file); |
|
10204 | 221 | pstrcpy(buf, sizeof(buf), name); |
|
10205 | #if !defined(LIBTCC) |
222 | ext = tcc_fileextension(buf); |
10206 | 223 | #ifdef TCC_TARGET_PE |
|
10207 | /* extract the basename of a file */ |
224 | if (s->output_type == TCC_OUTPUT_DLL) |
- | 225 | strcpy(ext, ".dll"); |
|
10208 | static const char *tcc_basename(const char *name) |
226 | else |
10209 | { |
227 | if (s->output_type == TCC_OUTPUT_EXE) |
Line 10210... | Line 228... | ||
10210 | const char *p; |
228 | strcpy(ext, ".exe"); |
10211 | p = strrchr(name, '/'); |
229 | else |
10212 | #ifdef WIN32 |
230 | #endif |
10213 | if (!p) |
231 | if (( (s->output_type == TCC_OUTPUT_OBJ && !s->option_r) || |
- | 232 | (s->output_type == TCC_OUTPUT_PREPROCESS) ) |
|
10214 | p = strrchr(name, '\\'); |
233 | && *ext) |
10215 | #endif |
234 | strcpy(ext, ".o"); |
10216 | if (!p) |
235 | else |
10217 | p = name; |
236 | strcpy(buf, "a.out"); |
10218 | else |
237 | |
10219 | p++; |
238 | return tcc_strdup(buf); |
10220 | return p; |
239 | } |
10221 | } |
240 | |
Line 10222... | Line -... | ||
10222 | - | ||
10223 | static int64_t getclock_us(void) |
- | |
10224 | { |
- | |
10225 | #ifdef WIN32 |
- | |
10226 | struct _timeb tb; |
- | |
10227 | _ftime(&tb); |
- | |
10228 | return (tb.time * 1000LL + tb.millitm) * 1000LL; |
- | |
10229 | #else |
- | |
10230 | struct timeval tv; |
- | |
10231 | gettimeofday(&tv, NULL); |
- | |
10232 | return tv.tv_sec * 1000000LL + tv.tv_usec; |
- | |
10233 | #endif |
- | |
10234 | } |
- | |
10235 | - | ||
10236 | void help(void) |
- | |
10237 | { |
- | |
10238 | printf("tcc version " TCC_VERSION " - Tiny C Compiler - Copyright (C) 2001-2005 Fabrice Bellard\n" |
- | |
10239 | "usage: tcc [-v] [-c] [-o outfile] [-Bdir] [-bench] [-Idir] [-Dsym[=val]] [-Usym]\n" |
- | |
10240 | " [-Wwarn] [-g] [-b] [-bt N] [-Ldir] [-llib] [-shared] [-static]\n" |
- | |
10241 | " [infile1 infile2...] [-run infile args...]\n" |
- | |
10242 | "\n" |
- | |
10243 | "General options:\n" |
- | |
10244 | " -v display current version\n" |
- | |
10245 | " -c compile only - generate an object file\n" |
- | |
10246 | " -o outfile set output filename\n" |
- | |
10247 | " -Bdir set tcc internal library path\n" |
- | |
10248 | " -bench output compilation statistics\n" |
- | |
10249 | " -run run compiled source\n" |
- | |
10250 | " -fflag set or reset (with 'no-' prefix) 'flag' (see man page)\n" |
- | |
10251 | " -Wwarning set or reset (with 'no-' prefix) 'warning' (see man page)\n" |
- | |
10252 | " -w disable all warnings\n" |
- | |
10253 | "Preprocessor options:\n" |
- | |
10254 | " -Idir add include path 'dir'\n" |
- | |
10255 | " -Dsym[=val] define 'sym' with value 'val'\n" |
- | |
10256 | " -Usym undefine 'sym'\n" |
- | |
10257 | "Linker options:\n" |
- | |
10258 | " -Ldir add library path 'dir'\n" |
- | |
10259 | " -llib link with dynamic or static library 'lib'\n" |
- | |
10260 | " -shared generate a shared library\n" |
241 | static int64_t getclock_us(void) |
10261 | " -static static linking\n" |
- | |
10262 | " -rdynamic export all global symbols to dynamic linker\n" |
- | |
10263 | " -r relocatable output\n" |
- | |
10264 | "Debugger options:\n" |
- | |
10265 | " -g generate runtime debug info\n" |
- | |
10266 | " -bt N show N callers in stack traces\n" |
- | |
10267 | ); |
- | |
10268 | } |
- | |
10269 | - | ||
10270 | #define TCC_OPTION_HAS_ARG 0x0001 |
- | |
10271 | #define TCC_OPTION_NOSEP 0x0002 /* cannot have space before option and arg */ |
- | |
10272 | - | ||
10273 | typedef struct TCCOption { |
- | |
10274 | const char *name; |
- | |
10275 | uint16_t index; |
- | |
10276 | uint16_t flags; |
- | |
10277 | } TCCOption; |
- | |
10278 | - | ||
10279 | enum { |
- | |
10280 | TCC_OPTION_HELP, |
- | |
10281 | TCC_OPTION_I, |
- | |
10282 | TCC_OPTION_D, |
- | |
10283 | TCC_OPTION_U, |
- | |
10284 | TCC_OPTION_L, |
- | |
10285 | TCC_OPTION_B, |
- | |
10286 | TCC_OPTION_l, |
- | |
10287 | TCC_OPTION_bench, |
- | |
10288 | TCC_OPTION_bt, |
- | |
10289 | TCC_OPTION_b, |
- | |
10290 | TCC_OPTION_g, |
- | |
10291 | TCC_OPTION_c, |
- | |
10292 | TCC_OPTION_static, |
- | |
10293 | TCC_OPTION_shared, |
- | |
10294 | TCC_OPTION_o, |
- | |
10295 | TCC_OPTION_r, |
- | |
10296 | TCC_OPTION_Wl, |
- | |
10297 | TCC_OPTION_W, |
- | |
10298 | TCC_OPTION_O, |
- | |
10299 | TCC_OPTION_m, |
- | |
10300 | TCC_OPTION_f, |
- | |
10301 | TCC_OPTION_nostdinc, |
- | |
10302 | TCC_OPTION_nostdlib, |
- | |
10303 | TCC_OPTION_print_search_dirs, |
- | |
10304 | TCC_OPTION_rdynamic, |
- | |
10305 | TCC_OPTION_run, |
- | |
10306 | TCC_OPTION_v, |
- | |
10307 | TCC_OPTION_w, |
- | |
10308 | TCC_OPTION_pipe, |
- | |
10309 | }; |
- | |
10310 | - | ||
10311 | static const TCCOption tcc_options[] = { |
- | |
10312 | { "h", TCC_OPTION_HELP, 0 }, |
- | |
10313 | { "?", TCC_OPTION_HELP, 0 }, |
- | |
10314 | { "I", TCC_OPTION_I, TCC_OPTION_HAS_ARG }, |
- | |
10315 | { "D", TCC_OPTION_D, TCC_OPTION_HAS_ARG }, |
- | |
10316 | { "U", TCC_OPTION_U, TCC_OPTION_HAS_ARG }, |
- | |
10317 | { "L", TCC_OPTION_L, TCC_OPTION_HAS_ARG }, |
- | |
10318 | { "B", TCC_OPTION_B, TCC_OPTION_HAS_ARG }, |
- | |
10319 | { "l", TCC_OPTION_l, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, |
- | |
10320 | { "bench", TCC_OPTION_bench, 0 }, |
- | |
10321 | { "bt", TCC_OPTION_bt, TCC_OPTION_HAS_ARG }, |
- | |
10322 | #ifdef CONFIG_TCC_BCHECK |
- | |
10323 | { "b", TCC_OPTION_b, 0 }, |
- | |
10324 | #endif |
- | |
10325 | { "g", TCC_OPTION_g, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, |
- | |
10326 | { "c", TCC_OPTION_c, 0 }, |
- | |
10327 | { "static", TCC_OPTION_static, 0 }, |
- | |
10328 | { "shared", TCC_OPTION_shared, 0 }, |
- | |
10329 | { "o", TCC_OPTION_o, TCC_OPTION_HAS_ARG }, |
- | |
10330 | { "run", TCC_OPTION_run, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, |
- | |
10331 | { "rdynamic", TCC_OPTION_rdynamic, 0 }, |
- | |
10332 | { "r", TCC_OPTION_r, 0 }, |
- | |
10333 | { "Wl,", TCC_OPTION_Wl, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, |
- | |
10334 | { "W", TCC_OPTION_W, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, |
- | |
10335 | { "O", TCC_OPTION_O, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, |
242 | { |
10336 | { "m", TCC_OPTION_m, TCC_OPTION_HAS_ARG }, |
243 | #ifdef _WIN32 |
10337 | { "f", TCC_OPTION_f, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, |
- | |
10338 | { "nostdinc", TCC_OPTION_nostdinc, 0 }, |
244 | LARGE_INTEGER frequency, t1; |
10339 | { "nostdlib", TCC_OPTION_nostdlib, 0 }, |
- | |
10340 | { "print-search-dirs", TCC_OPTION_print_search_dirs, 0 }, |
- | |
10341 | { "v", TCC_OPTION_v, 0 }, |
- | |
10342 | { "w", TCC_OPTION_w, 0 }, |
- | |
10343 | { "pipe", TCC_OPTION_pipe, 0}, |
- | |
10344 | { NULL }, |
- | |
10345 | }; |
- | |
10346 | - | ||
10347 | /* convert 'str' into an array of space separated strings */ |
- | |
10348 | static int expand_args(char ***pargv, const char *str) |
- | |
10349 | { |
- | |
10350 | const char *s1; |
- | |
10351 | char **argv, *arg; |
- | |
10352 | int argc, len; |
- | |
10353 | 245 | QueryPerformanceFrequency(&frequency); |
|
10354 | argc = 0; |
- | |
10355 | argv = NULL; |
- | |
10356 | for(;;) { |
- | |
10357 | while (is_space(*str)) |
- | |
10358 | str++; |
- | |
Line 10359... | Line -... | ||
10359 | if (*str == '\0') |
- | |
10360 | break; |
- | |
10361 | s1 = str; |
- | |
10362 | while (*str != '\0' && !is_space(*str)) |
- | |
10363 | str++; |
- | |
10364 | len = str - s1; |
246 | QueryPerformanceCounter(&t1); |
10365 | arg = tcc_malloc(len + 1); |
- | |
Line 10366... | Line -... | ||
10366 | memcpy(arg, s1, len); |
- | |
10367 | arg[len] = '\0'; |
- | |
10368 | dynarray_add((void ***)&argv, &argc, arg); |
- | |
10369 | } |
- | |
10370 | *pargv = argv; |
- | |
10371 | return argc; |
247 | return t1.QuadPart * 1000000LL / frequency.QuadPart; |
10372 | } |
- | |
10373 | - | ||
10374 | static char **files; |
- | |
Line 10375... | Line 248... | ||
10375 | static int nb_files, nb_libraries; |
248 | #else |
10376 | static int multiple_files; |
- | |
10377 | static int print_search_dirs; |
- | |
10378 | static int output_type; |
- | |
10379 | static int reloc_output; |
- | |
10380 | static const char *outfile; |
- | |
10381 | - | ||
10382 | int parse_args(TCCState *s, int argc, char **argv) |
- | |
10383 | { |
- | |
10384 | int optind; |
- | |
10385 | int i; |
249 | struct timeval tv; |
10386 | const TCCOption *popt; |
- | |
10387 | const char *optarg, *p1, *r1; |
- | |
10388 | char *r; |
- | |
10389 | /* |
- | |
10390 | printf("\n%d\n",argc); |
- | |
Line 10391... | Line -... | ||
10391 | - | ||
10392 | for(i=0;i |
- | |
10393 | { |
- | |
10394 | printf("\n parameter %d = %s",i+1,argv[i]); |
250 | gettimeofday(&tv, NULL); |
10395 | } |
- | |
10396 | printf("\n"); |
- | |
10397 | */ |
- | |
10398 | optind = 0; |
- | |
10399 | while (1) { |
- | |
10400 | if (optind >= argc) { |
- | |
10401 | if (nb_files == 0 && !print_search_dirs) |
- | |
10402 | goto show_help; |
- | |
10403 | else |
- | |
10404 | break; |
- | |
10405 | } |
- | |
10406 | r = argv[optind++]; |
- | |
10407 | if (r[0] != '-') { |
- | |
10408 | - | ||
10409 | /* add a new file */ |
- | |
10410 | dynarray_add((void ***)&files, &nb_files, r); |
- | |
10411 | if (!multiple_files) { |
- | |
10412 | optind--; |
- | |
10413 | /* argv[0] will be this file */ |
- | |
10414 | break; |
- | |
10415 | } |
- | |
10416 | } else { |
- | |
10417 | /* find option in table (match only the first chars */ |
- | |
10418 | popt = tcc_options; |
- | |
10419 | for(;;) { |
- | |
10420 | p1 = popt->name; |
- | |
10421 | if (p1 == NULL) |
- | |
10422 | printf("\n invalid option -- '%s'", r); |
- | |
10423 | r1 = r + 1; |
- | |
10424 | for(;;) { |
- | |
10425 | if (*p1 == '\0') |
- | |
10426 | goto option_found; |
- | |
10427 | if (*r1 != *p1) |
- | |
10428 | break; |
- | |
10429 | p1++; |
- | |
Line 10430... | Line -... | ||
10430 | r1++; |
- | |
10431 | } |
- | |
10432 | popt++; |
251 | return tv.tv_sec * 1000000LL + tv.tv_usec; |
10433 | } |
252 | #endif |
10434 | option_found: |
- | |
10435 | if (popt->flags & TCC_OPTION_HAS_ARG) { |
- | |
10436 | if (*r1 != '\0' || (popt->flags & TCC_OPTION_NOSEP)) { |
- | |
10437 | optarg = r1; |
- | |
10438 | } else { |
- | |
10439 | if (optind >= argc) |
- | |
10440 | printf("\n argument to '%s' is missing", r); |
- | |
10441 | optarg = argv[optind++]; |
- | |
10442 | } |
- | |
10443 | } else { |
- | |
10444 | if (*r1 != '\0') |
- | |
10445 | goto show_help; |
- | |
10446 | optarg = NULL; |
- | |
10447 | } |
- | |
10448 | - | ||
10449 | switch(popt->index) { |
- | |
10450 | case TCC_OPTION_HELP: |
- | |
10451 | show_help: |
- | |
10452 | help(); |
- | |
10453 | exit(1); |
- | |
10454 | case TCC_OPTION_I: |
- | |
10455 | if (tcc_add_include_path(s, optarg) < 0) |
- | |
10456 | printf("\n too many include paths"); |
- | |
10457 | break; |
- | |
10458 | case TCC_OPTION_D: |
- | |
10459 | { |
- | |
10460 | char *sym, *value; |
- | |
10461 | sym = (char *)optarg; |
- | |
10462 | value = strchr(sym, '='); |
- | |
10463 | if (value) { |
- | |
10464 | *value = '\0'; |
- | |
10465 | value++; |
- | |
10466 | } |
- | |
10467 | tcc_define_symbol(s, sym, value); |
- | |
10468 | } |
- | |
10469 | break; |
- | |
10470 | case TCC_OPTION_U: |
- | |
10471 | tcc_undefine_symbol(s, optarg); |
- | |
10472 | break; |
- | |
10473 | case TCC_OPTION_L: |
- | |
10474 | tcc_add_library_path(s, optarg); |
- | |
10475 | break; |
- | |
10476 | case TCC_OPTION_B: |
- | |
10477 | /* set tcc utilities path (mainly for tcc development) */ |
- | |
10478 | tcc_lib_path = optarg; |
- | |
10479 | break; |
- | |
10480 | case TCC_OPTION_l: |
- | |
10481 | dynarray_add((void ***)&files, &nb_files, r); |
- | |
10482 | nb_libraries++; |
- | |
10483 | break; |
- | |
10484 | case TCC_OPTION_bench: |
- | |
10485 | do_bench = 1; |
- | |
10486 | break; |
- | |
10487 | case TCC_OPTION_bt: |
- | |
10488 | num_callers = atoi(optarg); |
- | |
10489 | break; |
- | |
10490 | #ifdef CONFIG_TCC_BCHECK |
- | |
10491 | case TCC_OPTION_b: |
- | |
10492 | do_bounds_check = 1; |
- | |
10493 | do_debug = 1; |
- | |
10494 | break; |
- | |
10495 | #endif |
- | |
10496 | case TCC_OPTION_g: |
- | |
10497 | do_debug = 1; |
- | |
10498 | break; |
- | |
10499 | case TCC_OPTION_c: |
- | |
10500 | multiple_files = 1; |
- | |
10501 | output_type = TCC_OUTPUT_OBJ; |
- | |
10502 | break; |
- | |
10503 | case TCC_OPTION_static: |
- | |
10504 | s->static_link = 1; |
- | |
10505 | break; |
- | |
10506 | case TCC_OPTION_shared: |
- | |
10507 | output_type = TCC_OUTPUT_DLL; |
- | |
10508 | break; |
- | |
10509 | case TCC_OPTION_o: |
- | |
10510 | multiple_files = 1; |
- | |
10511 | outfile = optarg; |
- | |
10512 | break; |
- | |
10513 | case TCC_OPTION_r: |
- | |
10514 | /* generate a .o merging several output files */ |
- | |
10515 | reloc_output = 1; |
- | |
10516 | output_type = TCC_OUTPUT_OBJ; |
- | |
10517 | break; |
- | |
10518 | case TCC_OPTION_nostdinc: |
- | |
10519 | s->nostdinc = 1; |
- | |
10520 | break; |
- | |
10521 | case TCC_OPTION_nostdlib: |
- | |
10522 | s->nostdlib = 1; |
- | |
10523 | break; |
- | |
10524 | case TCC_OPTION_print_search_dirs: |
- | |
10525 | print_search_dirs = 1; |
- | |
10526 | break; |
- | |
10527 | case TCC_OPTION_run: |
- | |
10528 | { |
- | |
10529 | int argc1; |
- | |
10530 | char **argv1; |
- | |
10531 | argc1 = expand_args(&argv1, optarg); |
- | |
10532 | if (argc1 > 0) { |
- | |
10533 | parse_args(s, argc1, argv1); |
- | |
10534 | } |
- | |
10535 | multiple_files = 0; |
- | |
10536 | output_type = TCC_OUTPUT_MEMORY; |
- | |
10537 | } |
- | |
10538 | break; |
- | |
10539 | case TCC_OPTION_v: |
- | |
10540 | printf("tcc version %s\n", TCC_VERSION); |
- | |
10541 | exit(0); |
- | |
10542 | case TCC_OPTION_f: |
- | |
10543 | if (tcc_set_flag(s, optarg, 1) < 0 && s->warn_unsupported) |
- | |
10544 | goto unsupported_option; |
- | |
10545 | break; |
- | |
10546 | case TCC_OPTION_W: |
- | |
10547 | if (tcc_set_warning(s, optarg, 1) < 0 && |
- | |
10548 | s->warn_unsupported) |
- | |
10549 | goto unsupported_option; |
- | |
10550 | break; |
- | |
10551 | case TCC_OPTION_w: |
- | |
10552 | s->warn_none = 1; |
- | |
10553 | break; |
- | |
10554 | case TCC_OPTION_rdynamic: |
- | |
10555 | s->rdynamic = 1; |
- | |
10556 | break; |
- | |
10557 | case TCC_OPTION_Wl: |
- | |
10558 | { |
- | |
10559 | const char *p; |
- | |
10560 | if (strstart(optarg, "-Ttext,", &p)) { |
- | |
10561 | s->text_addr = strtoul(p, NULL, 16); |
- | |
10562 | s->has_text_addr = 1; |
- | |
10563 | } else if (strstart(optarg, "--oformat,", &p)) { |
- | |
10564 | if (strstart(p, "elf32-", NULL)) { |
- | |
10565 | s->output_format = TCC_OUTPUT_FORMAT_ELF; |
- | |
10566 | } else if (!strcmp(p, "binary")) { |
- | |
10567 | s->output_format = TCC_OUTPUT_FORMAT_BINARY; |
- | |
10568 | } else |
253 | } |
10569 | #ifdef TCC_TARGET_COFF |
- | |
10570 | if (!strcmp(p, "coff")) { |
- | |
10571 | s->output_format = TCC_OUTPUT_FORMAT_COFF; |
- | |
10572 | } else |
- | |
10573 | #endif |
- | |
10574 | { |
254 | |
Line 10575... | Line -... | ||
10575 | printf("\n target %s not found", p); |
- | |
10576 | } |
- | |
10577 | } else { |
- | |
10578 | printf("\n unsupported linker option '%s'", optarg); |
255 | int main(int argc, char **argv) |
10579 | } |
256 | { |
10580 | } |
- | |
10581 | break; |
- | |
10582 | default: |
- | |
10583 | if (s->warn_unsupported) { |
- | |
10584 | unsupported_option: |
- | |
10585 | warning("unsupported option '%s'", r); |
- | |
10586 | printf("\n unsupported option '%s'", r); |
- | |
10587 | } |
- | |
10588 | break; |
- | |
10589 | } |
- | |
10590 | } |
- | |
Line 10591... | Line -... | ||
10591 | } |
- | |
10592 | return optind; |
- | |
10593 | } |
257 | TCCState *s; |
10594 | - | ||
10595 | int main(int argc, char **argv) |
- | |
10596 | { |
- | |
10597 | int i; |
- | |
10598 | TCCState *s; |
- | |
10599 | int nb_objfiles, ret, optind; |
258 | int ret, optind, i; |
10600 | char objfilename[1024]; |
- | |
10601 | int64_t start_time = 0; |
- | |
Line 10602... | Line 259... | ||
10602 | int bug; |
259 | int64_t start_time = 0; |
10603 | 260 | ||
10604 | printf("\nTinyC compiler started.\n "); |
- | |
10605 | #ifdef WIN32 |
261 | s = tcc_new(); |
10606 | /* on win32, we suppose the lib and includes are at the location |
- | |
10607 | of 'tcc.exe' */ |
- | |
10608 | { |
- | |
10609 | static char path[1024]; |
- | |
10610 | char *p, *d; |
- | |
10611 | - | ||
10612 | GetModuleFileNameA(NULL, path, sizeof path); |
- | |
10613 | p = d = strlwr(path); |
- | |
10614 | while (*d) |
- | |
10615 | { |
- | |
10616 | if (*d == '\\') *d = '/', p = d; |
- | |
10617 | ++d; |
- | |
10618 | } |
- | |
10619 | *p = '\0'; |
- | |
10620 | tcc_lib_path = path; |
262 | |
10621 | } |
263 | optind = tcc_parse_args(s, argc - 1, argv + 1); |
Line 10622... | Line 264... | ||
10622 | #endif |
264 | |
- | 265 | if (s->do_bench) |
|
Line 10623... | Line -... | ||
10623 | - | ||
10624 | s = tcc_new(); |
266 | start_time = getclock_us(); |
10625 | output_type = TCC_OUTPUT_EXE; |
- | |
10626 | outfile = NULL; |
267 | |
Line 10627... | Line -... | ||
10627 | multiple_files = 1; |
- | |
10628 | files = NULL; |
268 | tcc_set_environment(s); |
10629 | nb_files = 0; |
269 | |
- | 270 | if (optind == 0) { |
|
- | 271 | help(); |
|
10630 | nb_libraries = 0; |
272 | return 1; |
10631 | reloc_output = 0; |
273 | } |
10632 | print_search_dirs = 0; |
274 | |
10633 | printf("TinyC initializated.\n"); |
- | |
10634 | bug=argc; |
- | |
10635 | if (bug==0) {bug==1;} |
- | |
10636 | optind = parse_args(s, bug - 1, argv + 1) + 1; |
- | |
10637 | printf("\n Arguments parsed.\n"); |
- | |
10638 | - | ||
10639 | if (print_search_dirs) { |
- | |
10640 | /* enough for Linux kernel */ |
- | |
10641 | printf("install: %s/\n", tcc_lib_path); |
- | |
10642 | return 0; |
- | |
10643 | } |
- | |
10644 | - | ||
10645 | nb_objfiles = nb_files - nb_libraries; |
- | |
10646 | - | ||
10647 | /* if outfile provided without other options, we output an |
- | |
10648 | executable */ |
- | |
10649 | if (outfile && output_type == TCC_OUTPUT_MEMORY) |
- | |
10650 | output_type = TCC_OUTPUT_EXE; |
- | |
10651 | - | ||
10652 | /* check -c |
- | |
10653 | consistency : only single file handled. XXX: checks file type */ |
- | |
10654 | if (output_type == TCC_OUTPUT_OBJ && !reloc_output) { |
- | |
10655 | /* accepts only a single input file */ |
- | |
10656 | if (nb_objfiles != 1) |
- | |
10657 | printf("\n cannot specify multiple files with -c"); |
- | |
10658 | if (nb_libraries != 0) |
275 | if (s->option_m) |
10659 | printf("\n cannot specify libraries with -c"); |
276 | exec_other_tcc(s, argv, s->option_m); |
Line 10660... | Line -... | ||
10660 | } |
- | |
10661 | - | ||
10662 | if (output_type != TCC_OUTPUT_MEMORY) { |
- | |
10663 | if (!outfile) { |
- | |
10664 | /* compute default outfile name */ |
277 | |
Line 10665... | Line 278... | ||
10665 | pstrcpy(objfilename, sizeof(objfilename) - 1, |
278 | if (s->verbose) |
10666 | /* strip path */ |
279 | display_info(s, 0); |
10667 | tcc_basename(files[0])); |
280 | |
10668 | #ifdef TCC_TARGET_PE |
- | |
10669 | pe_guess_outfile(objfilename, output_type); |
281 | if (s->print_search_dirs || (s->verbose == 2 && optind == 1)) { |
10670 | #else |
282 | tcc_set_output_type(s, TCC_OUTPUT_MEMORY); |
10671 | if (output_type == TCC_OUTPUT_OBJ && !reloc_output) { |
283 | display_info(s, 1); |
- | 284 | return 0; |
|
- | 285 | } |
|
10672 | char *ext = strrchr(objfilename, '.'); |
286 | |
- | 287 | if (s->verbose && optind == 1) |
|
- | 288 | return 0; |
|
- | 289 | ||
10673 | if (!ext) |
290 | if (s->nb_files == 0) |
- | 291 | tcc_error("no input files\n"); |
|
- | 292 | ||
- | 293 | /* check -c consistency : only single file handled. XXX: checks file type */ |
|
- | 294 | if (s->output_type == TCC_OUTPUT_OBJ && !s->option_r) { |
|
10674 | goto default_outfile; |
295 | if (s->nb_libraries != 0) |
10675 | /* add .o extension */ |
296 | tcc_error("cannot specify libraries with -c"); |
- | 297 | /* accepts only a single input file */ |
|
- | 298 | if ((s->nb_files != 1) && s->outfile) { |
|
- | 299 | tcc_error("cannot specify multiple files with -c and -o"); |
|
- | 300 | } |
|
- | 301 | } |
|
10676 | strcpy(ext + 1, "o"); |
302 | |
- | 303 | tcc_set_output_type(s, s->output_type); |
|
- | 304 | ||
- | 305 | /* compile or add each files or library */ |
|
- | 306 | for(i = ret = 0; i < s->nb_files && ret == 0; i++) { |
|
- | 307 | int filetype = *(unsigned char *)s->files[i]; |
|
- | 308 | const char *filename = s->files[i] + 1; |
|
- | 309 | if (filename[0] == '-' && filename[1] == 'l') { |
|
- | 310 | if (tcc_add_library(s, filename + 2) < 0) { |
|
- | 311 | /* don't fail on -lm as it's harmless to skip math lib */ |
|
10677 | } else { |
312 | if (strcmp(filename + 2, "m")) { |
10678 | default_outfile: |
313 | tcc_error_noabort("cannot find library 'lib%s'", filename + 2); |
10679 | pstrcpy(objfilename, sizeof(objfilename), "a.out"); |
314 | ret = 1; |
10680 | } |
- | |
10681 | #endif |
- | |
10682 | outfile = objfilename; |
- | |
10683 | } |
- | |
10684 | } |
- | |
10685 | - | ||
10686 | if (do_bench) { |
- | |
10687 | start_time = getclock_us(); |
- | |
10688 | } |
- | |
10689 | - | ||
10690 | tcc_set_output_type(s, output_type); |
- | |
10691 | - | ||
10692 | /* compile or add each files or library */ |
- | |
10693 | for(i = 0;i < nb_files; i++) { |
- | |
10694 | const char *filename; |
- | |
10695 | 315 | } |
|
Line -... | Line 316... | ||
- | 316 | } |
|
10696 | filename = files[i]; |
317 | } else { |
10697 | if (filename[0] == '-') { |
- | |
10698 | if (tcc_add_library(s, filename + 2) < 0) |
- | |
10699 | error("cannot find %s", filename); |
318 | if (1 == s->verbose) |
10700 | } else { |
- | |
10701 | if (tcc_add_file(s, filename) < 0) { |
319 | printf("-> %s\n", filename); |
10702 | ret = 1; |
- | |
10703 | goto the_end; |
320 | if (!s->outfile) |
10704 | } |
- | |
10705 | } |
- | |
10706 | } |
321 | s->outfile = default_outputfile(s, filename); |
10707 | 322 | if (tcc_add_file(s, filename, filetype) < 0) |
|
10708 | /* free all files */ |
- | |
10709 | tcc_free(files); |
323 | ret = 1; |
10710 | 324 | else |
|
- | 325 | if (s->output_type == TCC_OUTPUT_OBJ) { |
|
- | 326 | ret = !!tcc_output_file(s, s->outfile); |
|
10711 | if (do_bench) { |
327 | if (s->gen_deps && !ret) |
10712 | double total_time; |
328 | gen_makedeps(s, s->outfile, s->deps_outfile); |
10713 | total_time = (double)(getclock_us() - start_time) / 1000000.0; |
329 | if (!ret) { |
- | 330 | if ((i+1) < s->nb_files) { |
|
10714 | if (total_time < 0.001) |
331 | tcc_delete(s); |
10715 | total_time = 0.001; |
- | |
10716 | if (total_bytes < 1) |
- | |
10717 | total_bytes = 1; |
- | |
10718 | printf("%d idents, %d lines, %d bytes, %0.3f s, %d lines/s, %0.1f MB/s\n", |
- | |
10719 | tok_ident - TOK_IDENT, total_lines, total_bytes, |
- | |
10720 | total_time, (int)(total_lines / total_time), |
- | |
10721 | total_bytes / total_time / 1000000.0); |
- | |
10722 | } |
- | |
10723 | 332 | s = tcc_new(); |
|
- | 333 | tcc_parse_args(s, argc - 1, argv + 1); |
|
10724 | if (s->output_type == TCC_OUTPUT_MEMORY) { |
334 | tcc_set_environment(s); |
10725 | ret = tcc_run(s, argc - optind, argv + optind); |
335 | if (s->output_type != TCC_OUTPUT_OBJ) |
- | 336 | tcc_error("internal error"); |
|
- | 337 | tcc_set_output_type(s, s->output_type); |
|
10726 | } else |
338 | } |
10727 | #ifdef TCC_TARGET_PE |
339 | } |
10728 | if (s->output_type != TCC_OUTPUT_OBJ) { |
- | |
10729 | ret = tcc_output_pe(s, outfile); |
- |