Rev 609 | Go to most recent revision | Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
145 | halyavin | 1 | /* |
2 | * TCC - Tiny C Compiler |
||
3 | * |
||
4 | * Copyright (c) 2001-2004 Fabrice Bellard |
||
5 | * |
||
6 | * This library is free software; you can redistribute it and/or |
||
7 | * modify it under the terms of the GNU Lesser General Public |
||
8 | * License as published by the Free Software Foundation; either |
||
9 | * version 2 of the License, or (at your option) any later version. |
||
10 | * |
||
11 | * This library is distributed in the hope that it will be useful, |
||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
||
14 | * Lesser General Public License for more details. |
||
15 | * |
||
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 |
||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||
19 | */ |
||
20 | #define _GNU_SOURCE |
||
21 | #include "config.h" |
||
22 | |||
23 | #ifdef CONFIG_TCCBOOT |
||
24 | |||
25 | #include "tccboot.h" |
||
26 | #define CONFIG_TCC_STATIC |
||
27 | |||
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 | #include |
||
46 | #include |
||
47 | #endif |
||
48 | |||
49 | #endif /* !CONFIG_TCCBOOT */ |
||
50 | |||
51 | #include "elf.h" |
||
52 | #include "stab.h" |
||
53 | |||
54 | #ifndef O_BINARY |
||
55 | #define O_BINARY 0 |
||
56 | #endif |
||
57 | |||
58 | #include "libtcc.h" |
||
59 | |||
60 | /* parser debug */ |
||
61 | //#define PARSE_DEBUG |
||
62 | /* preprocessor debug */ |
||
63 | //#define PP_DEBUG |
||
64 | /* include file debug */ |
||
65 | //#define INC_DEBUG |
||
66 | |||
67 | //#define MEM_DEBUG |
||
68 | |||
69 | /* assembler debug */ |
||
70 | //#define ASM_DEBUG |
||
71 | |||
72 | /* target selection */ |
||
73 | //#define TCC_TARGET_I386 /* i386 code generator */ |
||
74 | //#define TCC_TARGET_ARM /* ARMv4 code generator */ |
||
75 | //#define TCC_TARGET_C67 /* TMS320C67xx code generator */ |
||
76 | |||
77 | /* default target is I386 */ |
||
78 | #if !defined(TCC_TARGET_I386) && !defined(TCC_TARGET_ARM) && \ |
||
79 | !defined(TCC_TARGET_C67) |
||
80 | #define TCC_TARGET_I386 |
||
81 | #endif |
||
82 | |||
83 | #if !defined(WIN32) && !defined(TCC_UCLIBC) && !defined(TCC_TARGET_ARM) && \ |
||
84 | !defined(TCC_TARGET_C67) |
||
85 | #define CONFIG_TCC_BCHECK /* enable bound checking code */ |
||
86 | #endif |
||
87 | |||
88 | #if defined(WIN32) && !defined(TCC_TARGET_PE) && !defined(TCC_TARGET_MEOS) |
||
89 | #define CONFIG_TCC_STATIC |
||
90 | #endif |
||
91 | |||
92 | /* define it to include assembler support */ |
||
93 | #if !defined(TCC_TARGET_ARM) && !defined(TCC_TARGET_C67) |
||
94 | #define CONFIG_TCC_ASM |
||
95 | #endif |
||
96 | |||
97 | /* object format selection */ |
||
98 | #if defined(TCC_TARGET_C67) |
||
99 | #define TCC_TARGET_COFF |
||
100 | #endif |
||
101 | |||
102 | #define FALSE 0 |
||
103 | #define false 0 |
||
104 | #define TRUE 1 |
||
105 | #define true 1 |
||
106 | typedef int BOOL; |
||
107 | |||
108 | /* path to find crt1.o, crti.o and crtn.o. Only needed when generating |
||
109 | executables or dlls */ |
||
110 | #define CONFIG_TCC_CRT_PREFIX "/usr/lib" |
||
111 | |||
112 | #define INCLUDE_STACK_SIZE 32 |
||
113 | #define IFDEF_STACK_SIZE 64 |
||
114 | #define VSTACK_SIZE 256 |
||
115 | #define STRING_MAX_SIZE 1024 |
||
116 | #define PACK_STACK_SIZE 8 |
||
117 | |||
118 | #define TOK_HASH_SIZE 8192 /* must be a power of two */ |
||
119 | #define TOK_ALLOC_INCR 512 /* must be a power of two */ |
||
120 | #define TOK_MAX_SIZE 4 /* token max size in int unit when stored in string */ |
||
121 | |||
122 | /* token symbol management */ |
||
123 | typedef struct TokenSym { |
||
124 | struct TokenSym *hash_next; |
||
125 | struct Sym *sym_define; /* direct pointer to define */ |
||
126 | struct Sym *sym_label; /* direct pointer to label */ |
||
127 | struct Sym *sym_struct; /* direct pointer to structure */ |
||
128 | struct Sym *sym_identifier; /* direct pointer to identifier */ |
||
129 | int tok; /* token number */ |
||
130 | int len; |
||
131 | char str[1]; |
||
132 | } TokenSym; |
||
133 | |||
134 | typedef struct CString { |
||
135 | int size; /* size in bytes */ |
||
136 | void *data; /* either 'char *' or 'int *' */ |
||
137 | int size_allocated; |
||
138 | void *data_allocated; /* if non NULL, data has been malloced */ |
||
139 | } CString; |
||
140 | |||
141 | /* type definition */ |
||
142 | typedef struct CType { |
||
143 | int t; |
||
144 | struct Sym *ref; |
||
145 | } CType; |
||
146 | |||
147 | /* constant value */ |
||
148 | typedef union CValue { |
||
149 | long double ld; |
||
150 | double d; |
||
151 | float f; |
||
152 | int i; |
||
153 | unsigned int ui; |
||
154 | unsigned int ul; /* address (should be unsigned long on 64 bit cpu) */ |
||
155 | long long ll; |
||
156 | unsigned long long ull; |
||
157 | struct CString *cstr; |
||
158 | void *ptr; |
||
159 | int tab[1]; |
||
160 | } CValue; |
||
161 | |||
162 | /* value on stack */ |
||
163 | typedef struct SValue { |
||
164 | CType type; /* type */ |
||
165 | unsigned short r; /* register + flags */ |
||
166 | unsigned short r2; /* second register, used for 'long long' |
||
167 | type. If not used, set to VT_CONST */ |
||
168 | CValue c; /* constant, if VT_CONST */ |
||
169 | struct Sym *sym; /* symbol, if (VT_SYM | VT_CONST) */ |
||
170 | } SValue; |
||
171 | |||
172 | /* symbol management */ |
||
173 | typedef struct Sym { |
||
174 | int v; /* symbol token */ |
||
175 | int r; /* associated register */ |
||
176 | int c; /* associated number */ |
||
177 | CType type; /* associated type */ |
||
178 | struct Sym *next; /* next related symbol */ |
||
179 | struct Sym *prev; /* prev symbol in stack */ |
||
180 | struct Sym *prev_tok; /* previous symbol for this token */ |
||
181 | } Sym; |
||
182 | |||
183 | /* section definition */ |
||
184 | /* XXX: use directly ELF structure for parameters ? */ |
||
185 | /* special flag to indicate that the section should not be linked to |
||
186 | the other ones */ |
||
187 | #define SHF_PRIVATE 0x80000000 |
||
188 | |||
189 | typedef struct Section { |
||
190 | unsigned long data_offset; /* current data offset */ |
||
191 | unsigned char *data; /* section data */ |
||
192 | unsigned long data_allocated; /* used for realloc() handling */ |
||
193 | int sh_name; /* elf section name (only used during output) */ |
||
194 | int sh_num; /* elf section number */ |
||
195 | int sh_type; /* elf section type */ |
||
196 | int sh_flags; /* elf section flags */ |
||
197 | int sh_info; /* elf section info */ |
||
198 | int sh_addralign; /* elf section alignment */ |
||
199 | int sh_entsize; /* elf entry size */ |
||
200 | unsigned long sh_size; /* section size (only used during output) */ |
||
201 | unsigned long sh_addr; /* address at which the section is relocated */ |
||
202 | unsigned long sh_offset; /* address at which the section is relocated */ |
||
203 | int nb_hashed_syms; /* used to resize the hash table */ |
||
204 | struct Section *link; /* link to another section */ |
||
205 | struct Section *reloc; /* corresponding section for relocation, if any */ |
||
206 | struct Section *hash; /* hash table for symbols */ |
||
207 | struct Section *next; |
||
208 | char name[1]; /* section name */ |
||
209 | } Section; |
||
210 | |||
211 | typedef struct DLLReference { |
||
212 | int level; |
||
213 | char name[1]; |
||
214 | } DLLReference; |
||
215 | |||
216 | /* GNUC attribute definition */ |
||
217 | typedef struct AttributeDef { |
||
218 | int aligned; |
||
219 | int packed; |
||
220 | Section *section; |
||
221 | unsigned char func_call; /* FUNC_CDECL, FUNC_STDCALL, FUNC_FASTCALLx */ |
||
222 | unsigned char dllexport; |
||
223 | } AttributeDef; |
||
224 | |||
225 | #define SYM_STRUCT 0x40000000 /* struct/union/enum symbol space */ |
||
226 | #define SYM_FIELD 0x20000000 /* struct/union field symbol space */ |
||
227 | #define SYM_FIRST_ANOM 0x10000000 /* first anonymous sym */ |
||
228 | |||
229 | /* stored in 'Sym.c' field */ |
||
230 | #define FUNC_NEW 1 /* ansi function prototype */ |
||
231 | #define FUNC_OLD 2 /* old function prototype */ |
||
232 | #define FUNC_ELLIPSIS 3 /* ansi function prototype with ... */ |
||
233 | |||
234 | /* stored in 'Sym.r' field */ |
||
235 | #define FUNC_CDECL 0 /* standard c call */ |
||
236 | #define FUNC_STDCALL 1 /* pascal c call */ |
||
237 | #define FUNC_FASTCALL1 2 /* first param in %eax */ |
||
238 | #define FUNC_FASTCALL2 3 /* first parameters in %eax, %edx */ |
||
239 | #define FUNC_FASTCALL3 4 /* first parameter in %eax, %edx, %ecx */ |
||
240 | |||
241 | /* field 'Sym.t' for macros */ |
||
242 | #define MACRO_OBJ 0 /* object like macro */ |
||
243 | #define MACRO_FUNC 1 /* function like macro */ |
||
244 | |||
245 | /* field 'Sym.r' for C labels */ |
||
246 | #define LABEL_DEFINED 0 /* label is defined */ |
||
247 | #define LABEL_FORWARD 1 /* label is forward defined */ |
||
248 | #define LABEL_DECLARED 2 /* label is declared but never used */ |
||
249 | |||
250 | /* type_decl() types */ |
||
251 | #define TYPE_ABSTRACT 1 /* type without variable */ |
||
252 | #define TYPE_DIRECT 2 /* type with variable */ |
||
253 | |||
254 | #define IO_BUF_SIZE 8192 |
||
255 | |||
256 | typedef struct BufferedFile { |
||
257 | uint8_t *buf_ptr; |
||
258 | uint8_t *buf_end; |
||
259 | int fd; |
||
260 | int line_num; /* current line number - here to simplify code */ |
||
261 | int ifndef_macro; /* #ifndef macro / #endif search */ |
||
262 | int ifndef_macro_saved; /* saved ifndef_macro */ |
||
263 | int *ifdef_stack_ptr; /* ifdef_stack value at the start of the file */ |
||
264 | char inc_type; /* type of include */ |
||
265 | char inc_filename[512]; /* filename specified by the user */ |
||
266 | char filename[1024]; /* current filename - here to simplify code */ |
||
267 | unsigned char buffer[IO_BUF_SIZE + 1]; /* extra size for CH_EOB char */ |
||
268 | } BufferedFile; |
||
269 | |||
270 | #define CH_EOB '\\' /* end of buffer or '\0' char in file */ |
||
271 | #define CH_EOF (-1) /* end of file */ |
||
272 | |||
273 | /* parsing state (used to save parser state to reparse part of the |
||
274 | source several times) */ |
||
275 | typedef struct ParseState { |
||
276 | int *macro_ptr; |
||
277 | int line_num; |
||
278 | int tok; |
||
279 | CValue tokc; |
||
280 | } ParseState; |
||
281 | |||
282 | /* used to record tokens */ |
||
283 | typedef struct TokenString { |
||
284 | int *str; |
||
285 | int len; |
||
286 | int allocated_len; |
||
287 | int last_line_num; |
||
288 | } TokenString; |
||
289 | |||
290 | /* include file cache, used to find files faster and also to eliminate |
||
291 | inclusion if the include file is protected by #ifndef ... #endif */ |
||
292 | typedef struct CachedInclude { |
||
293 | int ifndef_macro; |
||
294 | int hash_next; /* -1 if none */ |
||
295 | char type; /* '"' or '>' to give include type */ |
||
296 | char filename[1]; /* path specified in #include */ |
||
297 | } CachedInclude; |
||
298 | |||
299 | #define CACHED_INCLUDES_HASH_SIZE 512 |
||
300 | |||
301 | /* parser */ |
||
302 | static struct BufferedFile *file; |
||
303 | static int ch, tok; |
||
304 | static CValue tokc; |
||
305 | static CString tokcstr; /* current parsed string, if any */ |
||
306 | /* additional informations about token */ |
||
307 | static int tok_flags; |
||
308 | #define TOK_FLAG_BOL 0x0001 /* beginning of line before */ |
||
309 | #define TOK_FLAG_BOF 0x0002 /* beginning of file before */ |
||
310 | #define TOK_FLAG_ENDIF 0x0004 /* a endif was found matching starting #ifdef */ |
||
311 | |||
312 | static int *macro_ptr, *macro_ptr_allocated; |
||
313 | static int *unget_saved_macro_ptr; |
||
314 | static int unget_saved_buffer[TOK_MAX_SIZE + 1]; |
||
315 | static int unget_buffer_enabled; |
||
316 | static int parse_flags; |
||
317 | #define PARSE_FLAG_PREPROCESS 0x0001 /* activate preprocessing */ |
||
318 | #define PARSE_FLAG_TOK_NUM 0x0002 /* return numbers instead of TOK_PPNUM */ |
||
319 | #define PARSE_FLAG_LINEFEED 0x0004 /* line feed is returned as a |
||
320 | token. line feed is also |
||
321 | returned at eof */ |
||
322 | #define PARSE_FLAG_ASM_COMMENTS 0x0008 /* '#' can be used for line comment */ |
||
323 | |||
324 | static Section *text_section, *data_section, *bss_section; /* predefined sections */ |
||
325 | static Section *cur_text_section; /* current section where function code is |
||
326 | generated */ |
||
327 | #ifdef CONFIG_TCC_ASM |
||
328 | static Section *last_text_section; /* to handle .previous asm directive */ |
||
329 | #endif |
||
330 | /* bound check related sections */ |
||
331 | static Section *bounds_section; /* contains global data bound description */ |
||
332 | static Section *lbounds_section; /* contains local data bound description */ |
||
333 | /* symbol sections */ |
||
334 | static Section *symtab_section, *strtab_section; |
||
335 | |||
336 | /* debug sections */ |
||
337 | static Section *stab_section, *stabstr_section; |
||
338 | |||
339 | /* loc : local variable index |
||
340 | ind : output code index |
||
341 | rsym: return symbol |
||
342 | anon_sym: anonymous symbol index |
||
343 | */ |
||
344 | static int rsym, anon_sym, ind, loc; |
||
345 | /* expression generation modifiers */ |
||
346 | static int const_wanted; /* true if constant wanted */ |
||
347 | static int nocode_wanted; /* true if no code generation wanted for an expression */ |
||
348 | static int global_expr; /* true if compound literals must be allocated |
||
349 | globally (used during initializers parsing */ |
||
350 | static CType func_vt; /* current function return type (used by return |
||
351 | instruction) */ |
||
352 | static int func_vc; |
||
353 | static int last_line_num, last_ind, func_ind; /* debug last line number and pc */ |
||
354 | static int tok_ident; |
||
355 | static TokenSym **table_ident; |
||
356 | static TokenSym *hash_ident[TOK_HASH_SIZE]; |
||
357 | static char token_buf[STRING_MAX_SIZE + 1]; |
||
358 | static char *funcname; |
||
359 | static Sym *global_stack, *local_stack; |
||
360 | static Sym *define_stack; |
||
361 | static Sym *global_label_stack, *local_label_stack; |
||
362 | /* symbol allocator */ |
||
363 | #define SYM_POOL_NB (8192 / sizeof(Sym)) |
||
364 | static Sym *sym_free_first; |
||
365 | |||
366 | static SValue vstack[VSTACK_SIZE], *vtop; |
||
367 | /* some predefined types */ |
||
368 | static CType char_pointer_type, func_old_type, int_type; |
||
369 | /* true if isid(c) || isnum(c) */ |
||
370 | static unsigned char isidnum_table[256]; |
||
371 | |||
372 | /* compile with debug symbol (and use them if error during execution) */ |
||
373 | static int do_debug = 0; |
||
374 | |||
375 | /* compile with built-in memory and bounds checker */ |
||
376 | static int do_bounds_check = 0; |
||
377 | |||
378 | /* display benchmark infos */ |
||
379 | #if !defined(LIBTCC) |
||
380 | static int do_bench = 0; |
||
381 | #endif |
||
382 | static int total_lines; |
||
383 | static int total_bytes; |
||
384 | |||
385 | /* use GNU C extensions */ |
||
386 | static int gnu_ext = 1; |
||
387 | |||
388 | /* use Tiny C extensions */ |
||
389 | static int tcc_ext = 1; |
||
390 | |||
391 | /* max number of callers shown if error */ |
||
392 | static int num_callers = 6; |
||
393 | static const char **rt_bound_error_msg; |
||
394 | |||
395 | /* XXX: get rid of this ASAP */ |
||
396 | static struct TCCState *tcc_state; |
||
397 | |||
398 | /* give the path of the tcc libraries */ |
||
399 | static const char *tcc_lib_path = CONFIG_TCCDIR; |
||
400 | |||
401 | struct TCCState { |
||
402 | int output_type; |
||
403 | |||
404 | BufferedFile **include_stack_ptr; |
||
405 | int *ifdef_stack_ptr; |
||
406 | |||
407 | /* include file handling */ |
||
408 | char **include_paths; |
||
409 | int nb_include_paths; |
||
410 | char **sysinclude_paths; |
||
411 | int nb_sysinclude_paths; |
||
412 | CachedInclude **cached_includes; |
||
413 | int nb_cached_includes; |
||
414 | |||
415 | char **library_paths; |
||
416 | int nb_library_paths; |
||
417 | |||
418 | /* array of all loaded dlls (including those referenced by loaded |
||
419 | dlls) */ |
||
420 | DLLReference **loaded_dlls; |
||
421 | int nb_loaded_dlls; |
||
422 | |||
423 | /* sections */ |
||
424 | Section **sections; |
||
425 | int nb_sections; /* number of sections, including first dummy section */ |
||
426 | |||
427 | /* got handling */ |
||
428 | Section *got; |
||
429 | Section *plt; |
||
430 | unsigned long *got_offsets; |
||
431 | int nb_got_offsets; |
||
432 | /* give the correspondance from symtab indexes to dynsym indexes */ |
||
433 | int *symtab_to_dynsym; |
||
434 | |||
435 | /* temporary dynamic symbol sections (for dll loading) */ |
||
436 | Section *dynsymtab_section; |
||
437 | /* exported dynamic symbol section */ |
||
438 | Section *dynsym; |
||
439 | |||
440 | int nostdinc; /* if true, no standard headers are added */ |
||
441 | int nostdlib; /* if true, no standard libraries are added */ |
||
442 | |||
443 | int nocommon; /* if true, do not use common symbols for .bss data */ |
||
444 | |||
445 | /* if true, static linking is performed */ |
||
446 | int static_link; |
||
447 | |||
448 | /* if true, all symbols are exported */ |
||
449 | int rdynamic; |
||
450 | |||
451 | /* if true, only link in referenced objects from archive */ |
||
452 | int alacarte_link; |
||
453 | |||
454 | /* address of text section */ |
||
455 | unsigned long text_addr; |
||
456 | int has_text_addr; |
||
457 | |||
458 | /* output format, see TCC_OUTPUT_FORMAT_xxx */ |
||
459 | int output_format; |
||
460 | |||
461 | /* C language options */ |
||
462 | int char_is_unsigned; |
||
463 | int leading_underscore; |
||
464 | |||
465 | /* warning switches */ |
||
466 | int warn_write_strings; |
||
467 | int warn_unsupported; |
||
468 | int warn_error; |
||
469 | int warn_none; |
||
470 | int warn_implicit_function_declaration; |
||
471 | |||
472 | /* error handling */ |
||
473 | void *error_opaque; |
||
474 | void (*error_func)(void *opaque, const char *msg); |
||
475 | int error_set_jmp_enabled; |
||
476 | jmp_buf error_jmp_buf; |
||
477 | int nb_errors; |
||
478 | |||
479 | /* tiny assembler state */ |
||
480 | Sym *asm_labels; |
||
481 | |||
482 | /* see include_stack_ptr */ |
||
483 | BufferedFile *include_stack[INCLUDE_STACK_SIZE]; |
||
484 | |||
485 | /* see ifdef_stack_ptr */ |
||
486 | int ifdef_stack[IFDEF_STACK_SIZE]; |
||
487 | |||
488 | /* see cached_includes */ |
||
489 | int cached_includes_hash[CACHED_INCLUDES_HASH_SIZE]; |
||
490 | |||
491 | /* pack stack */ |
||
492 | int pack_stack[PACK_STACK_SIZE]; |
||
493 | int *pack_stack_ptr; |
||
494 | }; |
||
495 | |||
496 | /* The current value can be: */ |
||
497 | #define VT_VALMASK 0x00ff |
||
498 | #define VT_CONST 0x00f0 /* constant in vc |
||
499 | (must be first non register value) */ |
||
500 | #define VT_LLOCAL 0x00f1 /* lvalue, offset on stack */ |
||
501 | #define VT_LOCAL 0x00f2 /* offset on stack */ |
||
502 | #define VT_CMP 0x00f3 /* the value is stored in processor flags (in vc) */ |
||
503 | #define VT_JMP 0x00f4 /* value is the consequence of jmp true (even) */ |
||
504 | #define VT_JMPI 0x00f5 /* value is the consequence of jmp false (odd) */ |
||
505 | #define VT_LVAL 0x0100 /* var is an lvalue */ |
||
506 | #define VT_SYM 0x0200 /* a symbol value is added */ |
||
507 | #define VT_MUSTCAST 0x0400 /* value must be casted to be correct (used for |
||
508 | char/short stored in integer registers) */ |
||
509 | #define VT_MUSTBOUND 0x0800 /* bound checking must be done before |
||
510 | dereferencing value */ |
||
511 | #define VT_BOUNDED 0x8000 /* value is bounded. The address of the |
||
512 | bounding function call point is in vc */ |
||
513 | #define VT_LVAL_BYTE 0x1000 /* lvalue is a byte */ |
||
514 | #define VT_LVAL_SHORT 0x2000 /* lvalue is a short */ |
||
515 | #define VT_LVAL_UNSIGNED 0x4000 /* lvalue is unsigned */ |
||
516 | #define VT_LVAL_TYPE (VT_LVAL_BYTE | VT_LVAL_SHORT | VT_LVAL_UNSIGNED) |
||
517 | |||
518 | /* types */ |
||
519 | #define VT_INT 0 /* integer type */ |
||
520 | #define VT_BYTE 1 /* signed byte type */ |
||
521 | #define VT_SHORT 2 /* short type */ |
||
522 | #define VT_VOID 3 /* void type */ |
||
523 | #define VT_PTR 4 /* pointer */ |
||
524 | #define VT_ENUM 5 /* enum definition */ |
||
525 | #define VT_FUNC 6 /* function type */ |
||
526 | #define VT_STRUCT 7 /* struct/union definition */ |
||
527 | #define VT_FLOAT 8 /* IEEE float */ |
||
528 | #define VT_DOUBLE 9 /* IEEE double */ |
||
529 | #define VT_LDOUBLE 10 /* IEEE long double */ |
||
530 | #define VT_BOOL 11 /* ISOC99 boolean type */ |
||
531 | #define VT_LLONG 12 /* 64 bit integer */ |
||
532 | #define VT_LONG 13 /* long integer (NEVER USED as type, only |
||
533 | during parsing) */ |
||
534 | #define VT_BTYPE 0x000f /* mask for basic type */ |
||
535 | #define VT_UNSIGNED 0x0010 /* unsigned type */ |
||
536 | #define VT_ARRAY 0x0020 /* array type (also has VT_PTR) */ |
||
537 | #define VT_BITFIELD 0x0040 /* bitfield modifier */ |
||
538 | #define VT_CONSTANT 0x0800 /* const modifier */ |
||
539 | #define VT_VOLATILE 0x1000 /* volatile modifier */ |
||
540 | #define VT_SIGNED 0x2000 /* signed type */ |
||
541 | |||
542 | /* storage */ |
||
543 | #define VT_EXTERN 0x00000080 /* extern definition */ |
||
544 | #define VT_STATIC 0x00000100 /* static variable */ |
||
545 | #define VT_TYPEDEF 0x00000200 /* typedef definition */ |
||
546 | #define VT_INLINE 0x00000400 /* inline definition */ |
||
547 | |||
548 | #define VT_STRUCT_SHIFT 16 /* shift for bitfield shift values */ |
||
549 | |||
550 | /* type mask (except storage) */ |
||
551 | #define VT_STORAGE (VT_EXTERN | VT_STATIC | VT_TYPEDEF | VT_INLINE) |
||
552 | #define VT_TYPE (~(VT_STORAGE)) |
||
553 | |||
554 | /* token values */ |
||
555 | |||
556 | /* warning: the following compare tokens depend on i386 asm code */ |
||
557 | #define TOK_ULT 0x92 |
||
558 | #define TOK_UGE 0x93 |
||
559 | #define TOK_EQ 0x94 |
||
560 | #define TOK_NE 0x95 |
||
561 | #define TOK_ULE 0x96 |
||
562 | #define TOK_UGT 0x97 |
||
563 | #define TOK_LT 0x9c |
||
564 | #define TOK_GE 0x9d |
||
565 | #define TOK_LE 0x9e |
||
566 | #define TOK_GT 0x9f |
||
567 | |||
568 | #define TOK_LAND 0xa0 |
||
569 | #define TOK_LOR 0xa1 |
||
570 | |||
571 | #define TOK_DEC 0xa2 |
||
572 | #define TOK_MID 0xa3 /* inc/dec, to void constant */ |
||
573 | #define TOK_INC 0xa4 |
||
574 | #define TOK_UDIV 0xb0 /* unsigned division */ |
||
575 | #define TOK_UMOD 0xb1 /* unsigned modulo */ |
||
576 | #define TOK_PDIV 0xb2 /* fast division with undefined rounding for pointers */ |
||
577 | #define TOK_CINT 0xb3 /* number in tokc */ |
||
578 | #define TOK_CCHAR 0xb4 /* char constant in tokc */ |
||
579 | #define TOK_STR 0xb5 /* pointer to string in tokc */ |
||
580 | #define TOK_TWOSHARPS 0xb6 /* ## preprocessing token */ |
||
581 | #define TOK_LCHAR 0xb7 |
||
582 | #define TOK_LSTR 0xb8 |
||
583 | #define TOK_CFLOAT 0xb9 /* float constant */ |
||
584 | #define TOK_LINENUM 0xba /* line number info */ |
||
585 | #define TOK_CDOUBLE 0xc0 /* double constant */ |
||
586 | #define TOK_CLDOUBLE 0xc1 /* long double constant */ |
||
587 | #define TOK_UMULL 0xc2 /* unsigned 32x32 -> 64 mul */ |
||
588 | #define TOK_ADDC1 0xc3 /* add with carry generation */ |
||
589 | #define TOK_ADDC2 0xc4 /* add with carry use */ |
||
590 | #define TOK_SUBC1 0xc5 /* add with carry generation */ |
||
591 | #define TOK_SUBC2 0xc6 /* add with carry use */ |
||
592 | #define TOK_CUINT 0xc8 /* unsigned int constant */ |
||
593 | #define TOK_CLLONG 0xc9 /* long long constant */ |
||
594 | #define TOK_CULLONG 0xca /* unsigned long long constant */ |
||
595 | #define TOK_ARROW 0xcb |
||
596 | #define TOK_DOTS 0xcc /* three dots */ |
||
597 | #define TOK_SHR 0xcd /* unsigned shift right */ |
||
598 | #define TOK_PPNUM 0xce /* preprocessor number */ |
||
599 | |||
600 | #define TOK_SHL 0x01 /* shift left */ |
||
601 | #define TOK_SAR 0x02 /* signed shift right */ |
||
602 | |||
603 | /* assignement operators : normal operator or 0x80 */ |
||
604 | #define TOK_A_MOD 0xa5 |
||
605 | #define TOK_A_AND 0xa6 |
||
606 | #define TOK_A_MUL 0xaa |
||
607 | #define TOK_A_ADD 0xab |
||
608 | #define TOK_A_SUB 0xad |
||
609 | #define TOK_A_DIV 0xaf |
||
610 | #define TOK_A_XOR 0xde |
||
611 | #define TOK_A_OR 0xfc |
||
612 | #define TOK_A_SHL 0x81 |
||
613 | #define TOK_A_SAR 0x82 |
||
614 | |||
615 | #ifndef offsetof |
||
616 | #define offsetof(type, field) ((size_t) &((type *)0)->field) |
||
617 | #endif |
||
618 | |||
619 | #ifndef countof |
||
620 | #define countof(tab) (sizeof(tab) / sizeof((tab)[0])) |
||
621 | #endif |
||
622 | |||
623 | /* WARNING: the content of this string encodes token numbers */ |
||
624 | 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"; |
||
625 | |||
626 | #define TOK_EOF (-1) /* end of file */ |
||
627 | #define TOK_LINEFEED 10 /* line feed */ |
||
628 | |||
629 | /* all identificators and strings have token above that */ |
||
630 | #define TOK_IDENT 256 |
||
631 | |||
632 | /* only used for i386 asm opcodes definitions */ |
||
633 | #define DEF_ASM(x) DEF(TOK_ASM_ ## x, #x) |
||
634 | |||
635 | #define DEF_BWL(x) \ |
||
636 | DEF(TOK_ASM_ ## x ## b, #x "b") \ |
||
637 | DEF(TOK_ASM_ ## x ## w, #x "w") \ |
||
638 | DEF(TOK_ASM_ ## x ## l, #x "l") \ |
||
639 | DEF(TOK_ASM_ ## x, #x) |
||
640 | |||
641 | #define DEF_WL(x) \ |
||
642 | DEF(TOK_ASM_ ## x ## w, #x "w") \ |
||
643 | DEF(TOK_ASM_ ## x ## l, #x "l") \ |
||
644 | DEF(TOK_ASM_ ## x, #x) |
||
645 | |||
646 | #define DEF_FP1(x) \ |
||
647 | DEF(TOK_ASM_ ## f ## x ## s, "f" #x "s") \ |
||
648 | DEF(TOK_ASM_ ## fi ## x ## l, "fi" #x "l") \ |
||
649 | DEF(TOK_ASM_ ## f ## x ## l, "f" #x "l") \ |
||
650 | DEF(TOK_ASM_ ## fi ## x ## s, "fi" #x "s") |
||
651 | |||
652 | #define DEF_FP(x) \ |
||
653 | DEF(TOK_ASM_ ## f ## x, "f" #x ) \ |
||
654 | DEF(TOK_ASM_ ## f ## x ## p, "f" #x "p") \ |
||
655 | DEF_FP1(x) |
||
656 | |||
657 | #define DEF_ASMTEST(x) \ |
||
658 | DEF_ASM(x ## o) \ |
||
659 | DEF_ASM(x ## no) \ |
||
660 | DEF_ASM(x ## b) \ |
||
661 | DEF_ASM(x ## c) \ |
||
662 | DEF_ASM(x ## nae) \ |
||
663 | DEF_ASM(x ## nb) \ |
||
664 | DEF_ASM(x ## nc) \ |
||
665 | DEF_ASM(x ## ae) \ |
||
666 | DEF_ASM(x ## e) \ |
||
667 | DEF_ASM(x ## z) \ |
||
668 | DEF_ASM(x ## ne) \ |
||
669 | DEF_ASM(x ## nz) \ |
||
670 | DEF_ASM(x ## be) \ |
||
671 | DEF_ASM(x ## na) \ |
||
672 | DEF_ASM(x ## nbe) \ |
||
673 | DEF_ASM(x ## a) \ |
||
674 | DEF_ASM(x ## s) \ |
||
675 | DEF_ASM(x ## ns) \ |
||
676 | DEF_ASM(x ## p) \ |
||
677 | DEF_ASM(x ## pe) \ |
||
678 | DEF_ASM(x ## np) \ |
||
679 | DEF_ASM(x ## po) \ |
||
680 | DEF_ASM(x ## l) \ |
||
681 | DEF_ASM(x ## nge) \ |
||
682 | DEF_ASM(x ## nl) \ |
||
683 | DEF_ASM(x ## ge) \ |
||
684 | DEF_ASM(x ## le) \ |
||
685 | DEF_ASM(x ## ng) \ |
||
686 | DEF_ASM(x ## nle) \ |
||
687 | DEF_ASM(x ## g) |
||
688 | |||
689 | #define TOK_ASM_int TOK_INT |
||
690 | |||
691 | enum tcc_token { |
||
692 | TOK_LAST = TOK_IDENT - 1, |
||
693 | #define DEF(id, str) id, |
||
694 | #include "tcctok.h" |
||
695 | #undef DEF |
||
696 | }; |
||
697 | |||
698 | static const char tcc_keywords[] = |
||
699 | #define DEF(id, str) str "\0" |
||
700 | #include "tcctok.h" |
||
701 | #undef DEF |
||
702 | ; |
||
703 | |||
704 | #define TOK_UIDENT TOK_DEFINE |
||
705 | |||
706 | #ifdef WIN32 |
||
707 | int __stdcall GetModuleFileNameA(void *, char *, int); |
||
708 | void *__stdcall GetProcAddress(void *, const char *); |
||
709 | void *__stdcall GetModuleHandleA(const char *); |
||
710 | void *__stdcall LoadLibraryA(const char *); |
||
711 | int __stdcall FreeConsole(void); |
||
712 | |||
713 | #define snprintf _snprintf |
||
714 | #define vsnprintf _vsnprintf |
||
715 | #ifndef __GNUC__ |
||
716 | #define strtold (long double)strtod |
||
717 | #define strtof (float)strtod |
||
718 | #define strtoll (long long)strtol |
||
719 | #endif |
||
720 | #elif defined(TCC_UCLIBC) || defined(__FreeBSD__) |
||
721 | /* currently incorrect */ |
||
722 | long double strtold(const char *nptr, char **endptr) |
||
723 | { |
||
724 | return (long double)strtod(nptr, endptr); |
||
725 | } |
||
726 | float strtof(const char *nptr, char **endptr) |
||
727 | { |
||
728 | return (float)strtod(nptr, endptr); |
||
729 | } |
||
730 | #else |
||
731 | /* XXX: need to define this to use them in non ISOC99 context */ |
||
732 | extern float strtof (const char *__nptr, char **__endptr); |
||
733 | extern long double strtold (const char *__nptr, char **__endptr); |
||
734 | #endif |
||
735 | |||
736 | static char *pstrcpy(char *buf, int buf_size, const char *s); |
||
737 | static char *pstrcat(char *buf, int buf_size, const char *s); |
||
738 | static const char *tcc_basename(const char *name); |
||
739 | |||
740 | static void next(void); |
||
741 | static void next_nomacro(void); |
||
742 | static void parse_expr_type(CType *type); |
||
743 | static void expr_type(CType *type); |
||
744 | static void unary_type(CType *type); |
||
745 | static void block(int *bsym, int *csym, int *case_sym, int *def_sym, |
||
746 | int case_reg, int is_expr); |
||
747 | static int expr_const(void); |
||
748 | static void expr_eq(void); |
||
749 | static void gexpr(void); |
||
750 | static void gen_inline_functions(void); |
||
751 | static void decl(int l); |
||
752 | static void decl_initializer(CType *type, Section *sec, unsigned long c, |
||
753 | int first, int size_only); |
||
754 | static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, |
||
755 | int has_init, int v, int scope); |
||
756 | int gv(int rc); |
||
757 | void gv2(int rc1, int rc2); |
||
758 | void move_reg(int r, int s); |
||
759 | void save_regs(int n); |
||
760 | void save_reg(int r); |
||
761 | void vpop(void); |
||
762 | void vswap(void); |
||
763 | void vdup(void); |
||
764 | int get_reg(int rc); |
||
765 | int get_reg_ex(int rc,int rc2); |
||
766 | |||
767 | struct macro_level { |
||
768 | struct macro_level *prev; |
||
769 | int *p; |
||
770 | }; |
||
771 | |||
772 | static void macro_subst(TokenString *tok_str, Sym **nested_list, |
||
773 | const int *macro_str, struct macro_level **can_read_stream); |
||
774 | void gen_op(int op); |
||
775 | void force_charshort_cast(int t); |
||
776 | static void gen_cast(CType *type); |
||
777 | void vstore(void); |
||
778 | static Sym *sym_find(int v); |
||
779 | static Sym *sym_push(int v, CType *type, int r, int c); |
||
780 | |||
781 | /* type handling */ |
||
782 | static int type_size(CType *type, int *a); |
||
783 | static inline CType *pointed_type(CType *type); |
||
784 | static int pointed_size(CType *type); |
||
785 | static int lvalue_type(int t); |
||
786 | static int parse_btype(CType *type, AttributeDef *ad); |
||
787 | static void type_decl(CType *type, AttributeDef *ad, int *v, int td); |
||
788 | static int is_compatible_types(CType *type1, CType *type2); |
||
789 | |||
790 | int ieee_finite(double d); |
||
791 | void error(const char *fmt, ...); |
||
792 | void vpushi(int v); |
||
793 | void vrott(int n); |
||
794 | void vnrott(int n); |
||
795 | void lexpand_nr(void); |
||
796 | static void vpush_global_sym(CType *type, int v); |
||
797 | void vset(CType *type, int r, int v); |
||
798 | void type_to_str(char *buf, int buf_size, |
||
799 | CType *type, const char *varstr); |
||
800 | char *get_tok_str(int v, CValue *cv); |
||
801 | static Sym *get_sym_ref(CType *type, Section *sec, |
||
802 | unsigned long offset, unsigned long size); |
||
803 | static Sym *external_global_sym(int v, CType *type, int r); |
||
804 | |||
805 | /* section generation */ |
||
806 | static void section_realloc(Section *sec, unsigned long new_size); |
||
807 | static void *section_ptr_add(Section *sec, unsigned long size); |
||
808 | static void put_extern_sym(Sym *sym, Section *section, |
||
809 | unsigned long value, unsigned long size); |
||
810 | static void greloc(Section *s, Sym *sym, unsigned long addr, int type); |
||
811 | static int put_elf_str(Section *s, const char *sym); |
||
812 | static int put_elf_sym(Section *s, |
||
813 | unsigned long value, unsigned long size, |
||
814 | int info, int other, int shndx, const char *name); |
||
815 | static int add_elf_sym(Section *s, unsigned long value, unsigned long size, |
||
816 | int info, int other, int sh_num, const char *name); |
||
817 | static void put_elf_reloc(Section *symtab, Section *s, unsigned long offset, |
||
818 | int type, int symbol); |
||
819 | static void put_stabs(const char *str, int type, int other, int desc, |
||
820 | unsigned long value); |
||
821 | static void put_stabs_r(const char *str, int type, int other, int desc, |
||
822 | unsigned long value, Section *sec, int sym_index); |
||
823 | static void put_stabn(int type, int other, int desc, int value); |
||
824 | static void put_stabd(int type, int other, int desc); |
||
825 | static int tcc_add_dll(TCCState *s, const char *filename, int flags); |
||
826 | |||
827 | #define AFF_PRINT_ERROR 0x0001 /* print error if file not found */ |
||
828 | #define AFF_REFERENCED_DLL 0x0002 /* load a referenced dll from another dll */ |
||
829 | static int tcc_add_file_internal(TCCState *s, const char *filename, int flags); |
||
830 | |||
831 | /* tcccoff.c */ |
||
832 | int tcc_output_coff(TCCState *s1, FILE *f); |
||
833 | |||
834 | /* tccpe.c */ |
||
835 | void *resolve_sym(TCCState *s1, const char *sym, int type); |
||
836 | int pe_load_def_file(struct TCCState *s1, FILE *fp); |
||
837 | void pe_setup_paths(struct TCCState *s1, int *p_output_type, const char **p_outfile, char *first_file); |
||
838 | unsigned long pe_add_runtime(struct TCCState *s1); |
||
839 | int tcc_output_pe(struct TCCState *s1, const char *filename); |
||
840 | |||
841 | /* tccasm.c */ |
||
842 | |||
843 | #ifdef CONFIG_TCC_ASM |
||
844 | |||
845 | typedef struct ExprValue { |
||
846 | uint32_t v; |
||
847 | Sym *sym; |
||
848 | } ExprValue; |
||
849 | |||
850 | #define MAX_ASM_OPERANDS 30 |
||
851 | |||
852 | typedef struct ASMOperand { |
||
853 | int id; /* GCC 3 optionnal identifier (0 if number only supported */ |
||
854 | char *constraint; |
||
855 | char asm_str[16]; /* computed asm string for operand */ |
||
856 | SValue *vt; /* C value of the expression */ |
||
857 | int ref_index; /* if >= 0, gives reference to a output constraint */ |
||
858 | int input_index; /* if >= 0, gives reference to an input constraint */ |
||
859 | int priority; /* priority, used to assign registers */ |
||
860 | int reg; /* if >= 0, register number used for this operand */ |
||
861 | int is_llong; /* true if double register value */ |
||
862 | int is_memory; /* true if memory operand */ |
||
863 | int is_rw; /* for '+' modifier */ |
||
864 | } ASMOperand; |
||
865 | |||
866 | static void asm_expr(TCCState *s1, ExprValue *pe); |
||
867 | static int asm_int_expr(TCCState *s1); |
||
868 | static int find_constraint(ASMOperand *operands, int nb_operands, |
||
869 | const char *name, const char **pp); |
||
870 | |||
871 | static int tcc_assemble(TCCState *s1, int do_preprocess); |
||
872 | |||
873 | #endif |
||
874 | |||
875 | static void asm_instr(void); |
||
876 | static void asm_global_instr(void); |
||
877 | |||
878 | /* true if float/double/long double type */ |
||
879 | static inline int is_float(int t) |
||
880 | { |
||
881 | int bt; |
||
882 | bt = t & VT_BTYPE; |
||
883 | return bt == VT_LDOUBLE || bt == VT_DOUBLE || bt == VT_FLOAT; |
||
884 | } |
||
885 | |||
886 | #ifdef TCC_TARGET_I386 |
||
887 | #include "i386-gen.c" |
||
888 | #endif |
||
889 | |||
890 | #ifdef TCC_TARGET_ARM |
||
891 | #include "arm-gen.c" |
||
892 | #endif |
||
893 | |||
894 | #ifdef TCC_TARGET_C67 |
||
895 | #include "c67-gen.c" |
||
896 | #endif |
||
897 | |||
898 | #ifdef CONFIG_TCC_STATIC |
||
899 | |||
900 | #define RTLD_LAZY 0x001 |
||
901 | #define RTLD_NOW 0x002 |
||
902 | #define RTLD_GLOBAL 0x100 |
||
903 | #define RTLD_DEFAULT NULL |
||
904 | |||
905 | /* dummy function for profiling */ |
||
906 | void *dlopen(const char *filename, int flag) |
||
907 | { |
||
908 | return NULL; |
||
909 | } |
||
910 | |||
911 | const char *dlerror(void) |
||
912 | { |
||
913 | return "error"; |
||
914 | } |
||
915 | |||
916 | typedef struct TCCSyms { |
||
917 | char *str; |
||
918 | void *ptr; |
||
919 | } TCCSyms; |
||
920 | |||
921 | #define TCCSYM(a) { #a, &a, }, |
||
922 | |||
923 | /* add the symbol you want here if no dynamic linking is done */ |
||
924 | static TCCSyms tcc_syms[] = { |
||
925 | #if !defined(CONFIG_TCCBOOT) |
||
926 | TCCSYM(printf) |
||
927 | TCCSYM(fprintf) |
||
928 | TCCSYM(fopen) |
||
929 | TCCSYM(fclose) |
||
930 | #endif |
||
931 | { NULL, NULL }, |
||
932 | }; |
||
933 | |||
934 | void *resolve_sym(TCCState *s1, const char *symbol, int type) |
||
935 | { |
||
936 | TCCSyms *p; |
||
937 | p = tcc_syms; |
||
938 | while (p->str != NULL) { |
||
939 | if (!strcmp(p->str, symbol)) |
||
940 | return p->ptr; |
||
941 | p++; |
||
942 | } |
||
943 | return NULL; |
||
944 | } |
||
945 | |||
946 | #elif !defined(WIN32) |
||
947 | |||
948 | #include |
||
949 | |||
950 | void *resolve_sym(TCCState *s1, const char *sym, int type) |
||
951 | { |
||
952 | return dlsym(RTLD_DEFAULT, sym); |
||
953 | } |
||
954 | |||
955 | #endif |
||
956 | |||
957 | /********************************************************/ |
||
958 | |||
959 | /* we use our own 'finite' function to avoid potential problems with |
||
960 | non standard math libs */ |
||
961 | /* XXX: endianness dependent */ |
||
962 | int ieee_finite(double d) |
||
963 | { |
||
964 | int *p = (int *)&d; |
||
965 | return ((unsigned)((p[1] | 0x800fffff) + 1)) >> 31; |
||
966 | } |
||
967 | |||
968 | /* copy a string and truncate it. */ |
||
969 | static char *pstrcpy(char *buf, int buf_size, const char *s) |
||
970 | { |
||
971 | char *q, *q_end; |
||
972 | int c; |
||
973 | |||
974 | if (buf_size > 0) { |
||
975 | q = buf; |
||
976 | q_end = buf + buf_size - 1; |
||
977 | while (q < q_end) { |
||
978 | c = *s++; |
||
979 | if (c == '\0') |
||
980 | break; |
||
981 | *q++ = c; |
||
982 | } |
||
983 | *q = '\0'; |
||
984 | } |
||
985 | return buf; |
||
986 | } |
||
987 | |||
988 | /* strcat and truncate. */ |
||
989 | static char *pstrcat(char *buf, int buf_size, const char *s) |
||
990 | { |
||
991 | int len; |
||
992 | len = strlen(buf); |
||
993 | if (len < buf_size) |
||
994 | pstrcpy(buf + len, buf_size - len, s); |
||
995 | return buf; |
||
996 | } |
||
997 | |||
998 | static int strstart(const char *str, const char *val, const char **ptr) |
||
999 | { |
||
1000 | const char *p, *q; |
||
1001 | p = str; |
||
1002 | q = val; |
||
1003 | while (*q != '\0') { |
||
1004 | if (*p != *q) |
||
1005 | return 0; |
||
1006 | p++; |
||
1007 | q++; |
||
1008 | } |
||
1009 | if (ptr) |
||
1010 | *ptr = p; |
||
1011 | return 1; |
||
1012 | } |
||
1013 | |||
1014 | /* memory management */ |
||
1015 | #ifdef MEM_DEBUG |
||
1016 | int mem_cur_size; |
||
1017 | int mem_max_size; |
||
1018 | #endif |
||
1019 | |||
1020 | static inline void tcc_free(void *ptr) |
||
1021 | { |
||
1022 | #ifdef MEM_DEBUG |
||
1023 | mem_cur_size -= malloc_usable_size(ptr); |
||
1024 | #endif |
||
1025 | free(ptr); |
||
1026 | } |
||
1027 | |||
1028 | static void *tcc_malloc(unsigned long size) |
||
1029 | { |
||
1030 | void *ptr; |
||
1031 | ptr = malloc(size); |
||
1032 | if (!ptr && size) |
||
1033 | error("memory full"); |
||
1034 | #ifdef MEM_DEBUG |
||
1035 | mem_cur_size += malloc_usable_size(ptr); |
||
1036 | if (mem_cur_size > mem_max_size) |
||
1037 | mem_max_size = mem_cur_size; |
||
1038 | #endif |
||
1039 | return ptr; |
||
1040 | } |
||
1041 | |||
1042 | static void *tcc_mallocz(unsigned long size) |
||
1043 | { |
||
1044 | void *ptr; |
||
1045 | ptr = tcc_malloc(size); |
||
1046 | memset(ptr, 0, size); |
||
1047 | return ptr; |
||
1048 | } |
||
1049 | |||
1050 | static inline void *tcc_realloc(void *ptr, unsigned long size) |
||
1051 | { |
||
1052 | void *ptr1; |
||
1053 | #ifdef MEM_DEBUG |
||
1054 | mem_cur_size -= malloc_usable_size(ptr); |
||
1055 | #endif |
||
1056 | ptr1 = realloc(ptr, size); |
||
1057 | #ifdef MEM_DEBUG |
||
1058 | /* NOTE: count not correct if alloc error, but not critical */ |
||
1059 | mem_cur_size += malloc_usable_size(ptr1); |
||
1060 | if (mem_cur_size > mem_max_size) |
||
1061 | mem_max_size = mem_cur_size; |
||
1062 | #endif |
||
1063 | return ptr1; |
||
1064 | } |
||
1065 | |||
1066 | static char *tcc_strdup(const char *str) |
||
1067 | { |
||
1068 | char *ptr; |
||
1069 | ptr = tcc_malloc(strlen(str) + 1); |
||
1070 | strcpy(ptr, str); |
||
1071 | return ptr; |
||
1072 | } |
||
1073 | |||
1074 | #define free(p) use_tcc_free(p) |
||
1075 | #define malloc(s) use_tcc_malloc(s) |
||
1076 | #define realloc(p, s) use_tcc_realloc(p, s) |
||
1077 | |||
1078 | static void dynarray_add(void ***ptab, int *nb_ptr, void *data) |
||
1079 | { |
||
1080 | int nb, nb_alloc; |
||
1081 | void **pp; |
||
1082 | |||
1083 | nb = *nb_ptr; |
||
1084 | pp = *ptab; |
||
1085 | /* every power of two we double array size */ |
||
1086 | if ((nb & (nb - 1)) == 0) { |
||
1087 | if (!nb) |
||
1088 | nb_alloc = 1; |
||
1089 | else |
||
1090 | nb_alloc = nb * 2; |
||
1091 | pp = tcc_realloc(pp, nb_alloc * sizeof(void *)); |
||
1092 | if (!pp) |
||
1093 | error("memory full"); |
||
1094 | *ptab = pp; |
||
1095 | } |
||
1096 | pp[nb++] = data; |
||
1097 | *nb_ptr = nb; |
||
1098 | } |
||
1099 | |||
1100 | /* symbol allocator */ |
||
1101 | static Sym *__sym_malloc(void) |
||
1102 | { |
||
1103 | Sym *sym_pool, *sym, *last_sym; |
||
1104 | int i; |
||
1105 | |||
1106 | sym_pool = tcc_malloc(SYM_POOL_NB * sizeof(Sym)); |
||
1107 | |||
1108 | last_sym = sym_free_first; |
||
1109 | sym = sym_pool; |
||
1110 | for(i = 0; i < SYM_POOL_NB; i++) { |
||
1111 | sym->next = last_sym; |
||
1112 | last_sym = sym; |
||
1113 | sym++; |
||
1114 | } |
||
1115 | sym_free_first = last_sym; |
||
1116 | return last_sym; |
||
1117 | } |
||
1118 | |||
1119 | static inline Sym *sym_malloc(void) |
||
1120 | { |
||
1121 | Sym *sym; |
||
1122 | sym = sym_free_first; |
||
1123 | if (!sym) |
||
1124 | sym = __sym_malloc(); |
||
1125 | sym_free_first = sym->next; |
||
1126 | return sym; |
||
1127 | } |
||
1128 | |||
1129 | static inline void sym_free(Sym *sym) |
||
1130 | { |
||
1131 | sym->next = sym_free_first; |
||
1132 | sym_free_first = sym; |
||
1133 | } |
||
1134 | |||
1135 | Section *new_section(TCCState *s1, const char *name, int sh_type, int sh_flags) |
||
1136 | { |
||
1137 | Section *sec; |
||
1138 | |||
1139 | sec = tcc_mallocz(sizeof(Section) + strlen(name)); |
||
1140 | strcpy(sec->name, name); |
||
1141 | sec->sh_type = sh_type; |
||
1142 | sec->sh_flags = sh_flags; |
||
1143 | switch(sh_type) { |
||
1144 | case SHT_HASH: |
||
1145 | case SHT_REL: |
||
1146 | case SHT_DYNSYM: |
||
1147 | case SHT_SYMTAB: |
||
1148 | case SHT_DYNAMIC: |
||
1149 | sec->sh_addralign = 4; |
||
1150 | break; |
||
1151 | case SHT_STRTAB: |
||
1152 | sec->sh_addralign = 1; |
||
1153 | break; |
||
1154 | default: |
||
1155 | sec->sh_addralign = 32; /* default conservative alignment */ |
||
1156 | break; |
||
1157 | } |
||
1158 | |||
1159 | /* only add section if not private */ |
||
1160 | if (!(sh_flags & SHF_PRIVATE)) { |
||
1161 | sec->sh_num = s1->nb_sections; |
||
1162 | dynarray_add((void ***)&s1->sections, &s1->nb_sections, sec); |
||
1163 | } |
||
1164 | return sec; |
||
1165 | } |
||
1166 | |||
1167 | static void free_section(Section *s) |
||
1168 | { |
||
1169 | tcc_free(s->data); |
||
1170 | tcc_free(s); |
||
1171 | } |
||
1172 | |||
1173 | /* realloc section and set its content to zero */ |
||
1174 | static void section_realloc(Section *sec, unsigned long new_size) |
||
1175 | { |
||
1176 | unsigned long size; |
||
1177 | unsigned char *data; |
||
1178 | |||
1179 | size = sec->data_allocated; |
||
1180 | if (size == 0) |
||
1181 | size = 1; |
||
1182 | while (size < new_size) |
||
1183 | size = size * 2; |
||
1184 | data = tcc_realloc(sec->data, size); |
||
1185 | if (!data) |
||
1186 | error("memory full"); |
||
1187 | memset(data + sec->data_allocated, 0, size - sec->data_allocated); |
||
1188 | sec->data = data; |
||
1189 | sec->data_allocated = size; |
||
1190 | } |
||
1191 | |||
1192 | /* reserve at least 'size' bytes in section 'sec' from |
||
1193 | sec->data_offset. */ |
||
1194 | static void *section_ptr_add(Section *sec, unsigned long size) |
||
1195 | { |
||
1196 | unsigned long offset, offset1; |
||
1197 | |||
1198 | offset = sec->data_offset; |
||
1199 | offset1 = offset + size; |
||
1200 | if (offset1 > sec->data_allocated) |
||
1201 | section_realloc(sec, offset1); |
||
1202 | sec->data_offset = offset1; |
||
1203 | return sec->data + offset; |
||
1204 | } |
||
1205 | |||
1206 | /* return a reference to a section, and create it if it does not |
||
1207 | exists */ |
||
1208 | Section *find_section(TCCState *s1, const char *name) |
||
1209 | { |
||
1210 | Section *sec; |
||
1211 | int i; |
||
1212 | for(i = 1; i < s1->nb_sections; i++) { |
||
1213 | sec = s1->sections[i]; |
||
1214 | if (!strcmp(name, sec->name)) |
||
1215 | return sec; |
||
1216 | } |
||
1217 | /* sections are created as PROGBITS */ |
||
1218 | return new_section(s1, name, SHT_PROGBITS, SHF_ALLOC); |
||
1219 | } |
||
1220 | |||
1221 | #define SECTION_ABS ((void *)1) |
||
1222 | |||
1223 | /* update sym->c so that it points to an external symbol in section |
||
1224 | 'section' with value 'value' */ |
||
1225 | static void put_extern_sym2(Sym *sym, Section *section, |
||
1226 | unsigned long value, unsigned long size, |
||
1227 | int can_add_underscore) |
||
1228 | { |
||
1229 | int sym_type, sym_bind, sh_num, info; |
||
1230 | Elf32_Sym *esym; |
||
1231 | const char *name; |
||
1232 | char buf1[256]; |
||
1233 | |||
1234 | if (section == NULL) |
||
1235 | sh_num = SHN_UNDEF; |
||
1236 | else if (section == SECTION_ABS) |
||
1237 | sh_num = SHN_ABS; |
||
1238 | else |
||
1239 | sh_num = section->sh_num; |
||
1240 | if (!sym->c) { |
||
1241 | if ((sym->type.t & VT_BTYPE) == VT_FUNC) |
||
1242 | sym_type = STT_FUNC; |
||
1243 | else |
||
1244 | sym_type = STT_OBJECT; |
||
1245 | if (sym->type.t & VT_STATIC) |
||
1246 | sym_bind = STB_LOCAL; |
||
1247 | else |
||
1248 | sym_bind = STB_GLOBAL; |
||
1249 | |||
1250 | name = get_tok_str(sym->v, NULL); |
||
1251 | #ifdef CONFIG_TCC_BCHECK |
||
1252 | if (do_bounds_check) { |
||
1253 | char buf[32]; |
||
1254 | |||
1255 | /* XXX: avoid doing that for statics ? */ |
||
1256 | /* if bound checking is activated, we change some function |
||
1257 | names by adding the "__bound" prefix */ |
||
1258 | switch(sym->v) { |
||
1259 | #if 0 |
||
1260 | /* XXX: we rely only on malloc hooks */ |
||
1261 | case TOK_malloc: |
||
1262 | case TOK_free: |
||
1263 | case TOK_realloc: |
||
1264 | case TOK_memalign: |
||
1265 | case TOK_calloc: |
||
1266 | #endif |
||
1267 | case TOK_memcpy: |
||
1268 | case TOK_memmove: |
||
1269 | case TOK_memset: |
||
1270 | case TOK_strlen: |
||
1271 | case TOK_strcpy: |
||
1272 | strcpy(buf, "__bound_"); |
||
1273 | strcat(buf, name); |
||
1274 | name = buf; |
||
1275 | break; |
||
1276 | } |
||
1277 | } |
||
1278 | #endif |
||
1279 | if (tcc_state->leading_underscore && can_add_underscore) { |
||
1280 | buf1[0] = '_'; |
||
1281 | pstrcpy(buf1 + 1, sizeof(buf1) - 1, name); |
||
1282 | name = buf1; |
||
1283 | } |
||
1284 | info = ELF32_ST_INFO(sym_bind, sym_type); |
||
1285 | sym->c = add_elf_sym(symtab_section, value, size, info, 0, sh_num, name); |
||
1286 | } else { |
||
1287 | esym = &((Elf32_Sym *)symtab_section->data)[sym->c]; |
||
1288 | esym->st_value = value; |
||
1289 | esym->st_size = size; |
||
1290 | esym->st_shndx = sh_num; |
||
1291 | } |
||
1292 | } |
||
1293 | |||
1294 | static void put_extern_sym(Sym *sym, Section *section, |
||
1295 | unsigned long value, unsigned long size) |
||
1296 | { |
||
1297 | put_extern_sym2(sym, section, value, size, 1); |
||
1298 | } |
||
1299 | |||
1300 | /* add a new relocation entry to symbol 'sym' in section 's' */ |
||
1301 | static void greloc(Section *s, Sym *sym, unsigned long offset, int type) |
||
1302 | { |
||
1303 | if (!sym->c) |
||
1304 | put_extern_sym(sym, NULL, 0, 0); |
||
1305 | /* now we can add ELF relocation info */ |
||
1306 | put_elf_reloc(symtab_section, s, offset, type, sym->c); |
||
1307 | } |
||
1308 | |||
1309 | static inline int isid(int c) |
||
1310 | { |
||
1311 | return (c >= 'a' && c <= 'z') || |
||
1312 | (c >= 'A' && c <= 'Z') || |
||
1313 | c == '_'; |
||
1314 | } |
||
1315 | |||
1316 | static inline int isnum(int c) |
||
1317 | { |
||
1318 | return c >= '0' && c <= '9'; |
||
1319 | } |
||
1320 | |||
1321 | static inline int isoct(int c) |
||
1322 | { |
||
1323 | return c >= '0' && c <= '7'; |
||
1324 | } |
||
1325 | |||
1326 | static inline int toup(int c) |
||
1327 | { |
||
1328 | if (c >= 'a' && c <= 'z') |
||
1329 | return c - 'a' + 'A'; |
||
1330 | else |
||
1331 | return c; |
||
1332 | } |
||
1333 | |||
1334 | static void strcat_vprintf(char *buf, int buf_size, const char *fmt, va_list ap) |
||
1335 | { |
||
1336 | int len; |
||
1337 | len = strlen(buf); |
||
1338 | vsnprintf(buf + len, buf_size - len, fmt, ap); |
||
1339 | } |
||
1340 | |||
1341 | static void strcat_printf(char *buf, int buf_size, const char *fmt, ...) |
||
1342 | { |
||
1343 | va_list ap; |
||
1344 | va_start(ap, fmt); |
||
1345 | strcat_vprintf(buf, buf_size, fmt, ap); |
||
1346 | va_end(ap); |
||
1347 | } |
||
1348 | |||
1349 | void error1(TCCState *s1, int is_warning, const char *fmt, va_list ap) |
||
1350 | { |
||
1351 | char buf[2048]; |
||
1352 | BufferedFile **f; |
||
1353 | |||
1354 | buf[0] = '\0'; |
||
1355 | if (file) { |
||
1356 | for(f = s1->include_stack; f < s1->include_stack_ptr; f++) |
||
1357 | strcat_printf(buf, sizeof(buf), "In file included from %s:%d:\n", |
||
1358 | (*f)->filename, (*f)->line_num); |
||
1359 | if (file->line_num > 0) { |
||
1360 | strcat_printf(buf, sizeof(buf), |
||
1361 | "%s:%d: ", file->filename, file->line_num); |
||
1362 | } else { |
||
1363 | strcat_printf(buf, sizeof(buf), |
||
1364 | "%s: ", file->filename); |
||
1365 | } |
||
1366 | } else { |
||
1367 | strcat_printf(buf, sizeof(buf), |
||
1368 | "tcc: "); |
||
1369 | } |
||
1370 | if (is_warning) |
||
1371 | strcat_printf(buf, sizeof(buf), "warning: "); |
||
1372 | strcat_vprintf(buf, sizeof(buf), fmt, ap); |
||
1373 | |||
1374 | if (!s1->error_func) { |
||
1375 | /* default case: stderr */ |
||
1376 | fprintf(stderr, "%s\n", buf); |
||
1377 | } else { |
||
1378 | s1->error_func(s1->error_opaque, buf); |
||
1379 | } |
||
1380 | if (!is_warning || s1->warn_error) |
||
1381 | s1->nb_errors++; |
||
1382 | } |
||
1383 | |||
1384 | #ifdef LIBTCC |
||
1385 | void tcc_set_error_func(TCCState *s, void *error_opaque, |
||
1386 | void (*error_func)(void *opaque, const char *msg)) |
||
1387 | { |
||
1388 | s->error_opaque = error_opaque; |
||
1389 | s->error_func = error_func; |
||
1390 | } |
||
1391 | #endif |
||
1392 | |||
1393 | /* error without aborting current compilation */ |
||
1394 | void error_noabort(const char *fmt, ...) |
||
1395 | { |
||
1396 | TCCState *s1 = tcc_state; |
||
1397 | va_list ap; |
||
1398 | |||
1399 | va_start(ap, fmt); |
||
1400 | error1(s1, 0, fmt, ap); |
||
1401 | va_end(ap); |
||
1402 | } |
||
1403 | |||
1404 | void error(const char *fmt, ...) |
||
1405 | { |
||
1406 | TCCState *s1 = tcc_state; |
||
1407 | va_list ap; |
||
1408 | |||
1409 | va_start(ap, fmt); |
||
1410 | error1(s1, 0, fmt, ap); |
||
1411 | va_end(ap); |
||
1412 | /* better than nothing: in some cases, we accept to handle errors */ |
||
1413 | if (s1->error_set_jmp_enabled) { |
||
1414 | longjmp(s1->error_jmp_buf, 1); |
||
1415 | } else { |
||
1416 | /* XXX: eliminate this someday */ |
||
1417 | exit(1); |
||
1418 | } |
||
1419 | } |
||
1420 | |||
1421 | void expect(const char *msg) |
||
1422 | { |
||
1423 | error("%s expected", msg); |
||
1424 | } |
||
1425 | |||
1426 | void warning(const char *fmt, ...) |
||
1427 | { |
||
1428 | TCCState *s1 = tcc_state; |
||
1429 | va_list ap; |
||
1430 | |||
1431 | if (s1->warn_none) |
||
1432 | return; |
||
1433 | |||
1434 | va_start(ap, fmt); |
||
1435 | error1(s1, 1, fmt, ap); |
||
1436 | va_end(ap); |
||
1437 | } |
||
1438 | |||
1439 | void skip(int c) |
||
1440 | { |
||
1441 | if (tok != c) |
||
1442 | error("'%c' expected", c); |
||
1443 | next(); |
||
1444 | } |
||
1445 | |||
1446 | static void test_lvalue(void) |
||
1447 | { |
||
1448 | if (!(vtop->r & VT_LVAL)) |
||
1449 | expect("lvalue"); |
||
1450 | } |
||
1451 | |||
1452 | /* allocate a new token */ |
||
1453 | static TokenSym *tok_alloc_new(TokenSym **pts, const char *str, int len) |
||
1454 | { |
||
1455 | TokenSym *ts, **ptable; |
||
1456 | int i; |
||
1457 | |||
1458 | if (tok_ident >= SYM_FIRST_ANOM) |
||
1459 | error("memory full"); |
||
1460 | |||
1461 | /* expand token table if needed */ |
||
1462 | i = tok_ident - TOK_IDENT; |
||
1463 | if ((i % TOK_ALLOC_INCR) == 0) { |
||
1464 | ptable = tcc_realloc(table_ident, (i + TOK_ALLOC_INCR) * sizeof(TokenSym *)); |
||
1465 | if (!ptable) |
||
1466 | error("memory full"); |
||
1467 | table_ident = ptable; |
||
1468 | } |
||
1469 | |||
1470 | ts = tcc_malloc(sizeof(TokenSym) + len); |
||
1471 | table_ident[i] = ts; |
||
1472 | ts->tok = tok_ident++; |
||
1473 | ts->sym_define = NULL; |
||
1474 | ts->sym_label = NULL; |
||
1475 | ts->sym_struct = NULL; |
||
1476 | ts->sym_identifier = NULL; |
||
1477 | ts->len = len; |
||
1478 | ts->hash_next = NULL; |
||
1479 | memcpy(ts->str, str, len); |
||
1480 | ts->str[len] = '\0'; |
||
1481 | *pts = ts; |
||
1482 | return ts; |
||
1483 | } |
||
1484 | |||
1485 | #define TOK_HASH_INIT 1 |
||
1486 | #define TOK_HASH_FUNC(h, c) ((h) * 263 + (c)) |
||
1487 | |||
1488 | /* find a token and add it if not found */ |
||
1489 | static TokenSym *tok_alloc(const char *str, int len) |
||
1490 | { |
||
1491 | TokenSym *ts, **pts; |
||
1492 | int i; |
||
1493 | unsigned int h; |
||
1494 | |||
1495 | h = TOK_HASH_INIT; |
||
1496 | for(i=0;i |
||
1497 | h = TOK_HASH_FUNC(h, ((unsigned char *)str)[i]); |
||
1498 | h &= (TOK_HASH_SIZE - 1); |
||
1499 | |||
1500 | pts = &hash_ident[h]; |
||
1501 | for(;;) { |
||
1502 | ts = *pts; |
||
1503 | if (!ts) |
||
1504 | break; |
||
1505 | if (ts->len == len && !memcmp(ts->str, str, len)) |
||
1506 | return ts; |
||
1507 | pts = &(ts->hash_next); |
||
1508 | } |
||
1509 | return tok_alloc_new(pts, str, len); |
||
1510 | } |
||
1511 | |||
1512 | /* CString handling */ |
||
1513 | |||
1514 | static void cstr_realloc(CString *cstr, int new_size) |
||
1515 | { |
||
1516 | int size; |
||
1517 | void *data; |
||
1518 | |||
1519 | size = cstr->size_allocated; |
||
1520 | if (size == 0) |
||
1521 | size = 8; /* no need to allocate a too small first string */ |
||
1522 | while (size < new_size) |
||
1523 | size = size * 2; |
||
1524 | data = tcc_realloc(cstr->data_allocated, size); |
||
1525 | if (!data) |
||
1526 | error("memory full"); |
||
1527 | cstr->data_allocated = data; |
||
1528 | cstr->size_allocated = size; |
||
1529 | cstr->data = data; |
||
1530 | } |
||
1531 | |||
1532 | /* add a byte */ |
||
1533 | static inline void cstr_ccat(CString *cstr, int ch) |
||
1534 | { |
||
1535 | int size; |
||
1536 | size = cstr->size + 1; |
||
1537 | if (size > cstr->size_allocated) |
||
1538 | cstr_realloc(cstr, size); |
||
1539 | ((unsigned char *)cstr->data)[size - 1] = ch; |
||
1540 | cstr->size = size; |
||
1541 | } |
||
1542 | |||
1543 | static void cstr_cat(CString *cstr, const char *str) |
||
1544 | { |
||
1545 | int c; |
||
1546 | for(;;) { |
||
1547 | c = *str; |
||
1548 | if (c == '\0') |
||
1549 | break; |
||
1550 | cstr_ccat(cstr, c); |
||
1551 | str++; |
||
1552 | } |
||
1553 | } |
||
1554 | |||
1555 | /* add a wide char */ |
||
1556 | static void cstr_wccat(CString *cstr, int ch) |
||
1557 | { |
||
1558 | int size; |
||
1559 | size = cstr->size + sizeof(int); |
||
1560 | if (size > cstr->size_allocated) |
||
1561 | cstr_realloc(cstr, size); |
||
1562 | *(int *)(((unsigned char *)cstr->data) + size - sizeof(int)) = ch; |
||
1563 | cstr->size = size; |
||
1564 | } |
||
1565 | |||
1566 | static void cstr_new(CString *cstr) |
||
1567 | { |
||
1568 | memset(cstr, 0, sizeof(CString)); |
||
1569 | } |
||
1570 | |||
1571 | /* free string and reset it to NULL */ |
||
1572 | static void cstr_free(CString *cstr) |
||
1573 | { |
||
1574 | tcc_free(cstr->data_allocated); |
||
1575 | cstr_new(cstr); |
||
1576 | } |
||
1577 | |||
1578 | #define cstr_reset(cstr) cstr_free(cstr) |
||
1579 | |||
1580 | /* XXX: unicode ? */ |
||
1581 | static void add_char(CString *cstr, int c) |
||
1582 | { |
||
1583 | if (c == '\'' || c == '\"' || c == '\\') { |
||
1584 | /* XXX: could be more precise if char or string */ |
||
1585 | cstr_ccat(cstr, '\\'); |
||
1586 | } |
||
1587 | if (c >= 32 && c <= 126) { |
||
1588 | cstr_ccat(cstr, c); |
||
1589 | } else { |
||
1590 | cstr_ccat(cstr, '\\'); |
||
1591 | if (c == '\n') { |
||
1592 | cstr_ccat(cstr, 'n'); |
||
1593 | } else { |
||
1594 | cstr_ccat(cstr, '0' + ((c >> 6) & 7)); |
||
1595 | cstr_ccat(cstr, '0' + ((c >> 3) & 7)); |
||
1596 | cstr_ccat(cstr, '0' + (c & 7)); |
||
1597 | } |
||
1598 | } |
||
1599 | } |
||
1600 | |||
1601 | /* XXX: buffer overflow */ |
||
1602 | /* XXX: float tokens */ |
||
1603 | char *get_tok_str(int v, CValue *cv) |
||
1604 | { |
||
1605 | static char buf[STRING_MAX_SIZE + 1]; |
||
1606 | static CString cstr_buf; |
||
1607 | CString *cstr; |
||
1608 | unsigned char *q; |
||
1609 | char *p; |
||
1610 | int i, len; |
||
1611 | |||
1612 | /* NOTE: to go faster, we give a fixed buffer for small strings */ |
||
1613 | cstr_reset(&cstr_buf); |
||
1614 | cstr_buf.data = buf; |
||
1615 | cstr_buf.size_allocated = sizeof(buf); |
||
1616 | p = buf; |
||
1617 | |||
1618 | switch(v) { |
||
1619 | case TOK_CINT: |
||
1620 | case TOK_CUINT: |
||
1621 | /* XXX: not quite exact, but only useful for testing */ |
||
1622 | sprintf(p, "%u", cv->ui); |
||
1623 | break; |
||
1624 | case TOK_CLLONG: |
||
1625 | case TOK_CULLONG: |
||
1626 | /* XXX: not quite exact, but only useful for testing */ |
||
1627 | sprintf(p, "%Lu", cv->ull); |
||
1628 | break; |
||
1629 | case TOK_CCHAR: |
||
1630 | case TOK_LCHAR: |
||
1631 | cstr_ccat(&cstr_buf, '\''); |
||
1632 | add_char(&cstr_buf, cv->i); |
||
1633 | cstr_ccat(&cstr_buf, '\''); |
||
1634 | cstr_ccat(&cstr_buf, '\0'); |
||
1635 | break; |
||
1636 | case TOK_PPNUM: |
||
1637 | cstr = cv->cstr; |
||
1638 | len = cstr->size - 1; |
||
1639 | for(i=0;i |
||
1640 | add_char(&cstr_buf, ((unsigned char *)cstr->data)[i]); |
||
1641 | cstr_ccat(&cstr_buf, '\0'); |
||
1642 | break; |
||
1643 | case TOK_STR: |
||
1644 | case TOK_LSTR: |
||
1645 | cstr = cv->cstr; |
||
1646 | cstr_ccat(&cstr_buf, '\"'); |
||
1647 | if (v == TOK_STR) { |
||
1648 | len = cstr->size - 1; |
||
1649 | for(i=0;i |
||
1650 | add_char(&cstr_buf, ((unsigned char *)cstr->data)[i]); |
||
1651 | } else { |
||
1652 | len = (cstr->size / sizeof(int)) - 1; |
||
1653 | for(i=0;i |
||
1654 | add_char(&cstr_buf, ((int *)cstr->data)[i]); |
||
1655 | } |
||
1656 | cstr_ccat(&cstr_buf, '\"'); |
||
1657 | cstr_ccat(&cstr_buf, '\0'); |
||
1658 | break; |
||
1659 | case TOK_LT: |
||
1660 | v = '<'; |
||
1661 | goto addv; |
||
1662 | case TOK_GT: |
||
1663 | v = '>'; |
||
1664 | goto addv; |
||
1665 | case TOK_A_SHL: |
||
1666 | return strcpy(p, "<<="); |
||
1667 | case TOK_A_SAR: |
||
1668 | return strcpy(p, ">>="); |
||
1669 | default: |
||
1670 | if (v < TOK_IDENT) { |
||
1671 | /* search in two bytes table */ |
||
1672 | q = tok_two_chars; |
||
1673 | while (*q) { |
||
1674 | if (q[2] == v) { |
||
1675 | *p++ = q[0]; |
||
1676 | *p++ = q[1]; |
||
1677 | *p = '\0'; |
||
1678 | return buf; |
||
1679 | } |
||
1680 | q += 3; |
||
1681 | } |
||
1682 | addv: |
||
1683 | *p++ = v; |
||
1684 | *p = '\0'; |
||
1685 | } else if (v < tok_ident) { |
||
1686 | return table_ident[v - TOK_IDENT]->str; |
||
1687 | } else if (v >= SYM_FIRST_ANOM) { |
||
1688 | /* special name for anonymous symbol */ |
||
1689 | sprintf(p, "L.%u", v - SYM_FIRST_ANOM); |
||
1690 | } else { |
||
1691 | /* should never happen */ |
||
1692 | return NULL; |
||
1693 | } |
||
1694 | break; |
||
1695 | } |
||
1696 | return cstr_buf.data; |
||
1697 | } |
||
1698 | |||
1699 | /* push, without hashing */ |
||
1700 | static Sym *sym_push2(Sym **ps, int v, int t, int c) |
||
1701 | { |
||
1702 | Sym *s; |
||
1703 | s = sym_malloc(); |
||
1704 | s->v = v; |
||
1705 | s->type.t = t; |
||
1706 | s->c = c; |
||
1707 | s->next = NULL; |
||
1708 | /* add in stack */ |
||
1709 | s->prev = *ps; |
||
1710 | *ps = s; |
||
1711 | return s; |
||
1712 | } |
||
1713 | |||
1714 | /* find a symbol and return its associated structure. 's' is the top |
||
1715 | of the symbol stack */ |
||
1716 | static Sym *sym_find2(Sym *s, int v) |
||
1717 | { |
||
1718 | while (s) { |
||
1719 | if (s->v == v) |
||
1720 | return s; |
||
1721 | s = s->prev; |
||
1722 | } |
||
1723 | return NULL; |
||
1724 | } |
||
1725 | |||
1726 | /* structure lookup */ |
||
1727 | static inline Sym *struct_find(int v) |
||
1728 | { |
||
1729 | v -= TOK_IDENT; |
||
1730 | if ((unsigned)v >= (unsigned)(tok_ident - TOK_IDENT)) |
||
1731 | return NULL; |
||
1732 | return table_ident[v]->sym_struct; |
||
1733 | } |
||
1734 | |||
1735 | /* find an identifier */ |
||
1736 | static inline Sym *sym_find(int v) |
||
1737 | { |
||
1738 | v -= TOK_IDENT; |
||
1739 | if ((unsigned)v >= (unsigned)(tok_ident - TOK_IDENT)) |
||
1740 | return NULL; |
||
1741 | return table_ident[v]->sym_identifier; |
||
1742 | } |
||
1743 | |||
1744 | /* push a given symbol on the symbol stack */ |
||
1745 | static Sym *sym_push(int v, CType *type, int r, int c) |
||
1746 | { |
||
1747 | Sym *s, **ps; |
||
1748 | TokenSym *ts; |
||
1749 | |||
1750 | if (local_stack) |
||
1751 | ps = &local_stack; |
||
1752 | else |
||
1753 | ps = &global_stack; |
||
1754 | s = sym_push2(ps, v, type->t, c); |
||
1755 | s->type.ref = type->ref; |
||
1756 | s->r = r; |
||
1757 | /* don't record fields or anonymous symbols */ |
||
1758 | /* XXX: simplify */ |
||
1759 | if (!(v & SYM_FIELD) && (v & ~SYM_STRUCT) < SYM_FIRST_ANOM) { |
||
1760 | /* record symbol in token array */ |
||
1761 | ts = table_ident[(v & ~SYM_STRUCT) - TOK_IDENT]; |
||
1762 | if (v & SYM_STRUCT) |
||
1763 | ps = &ts->sym_struct; |
||
1764 | else |
||
1765 | ps = &ts->sym_identifier; |
||
1766 | s->prev_tok = *ps; |
||
1767 | *ps = s; |
||
1768 | } |
||
1769 | return s; |
||
1770 | } |
||
1771 | |||
1772 | /* push a global identifier */ |
||
1773 | static Sym *global_identifier_push(int v, int t, int c) |
||
1774 | { |
||
1775 | Sym *s, **ps; |
||
1776 | s = sym_push2(&global_stack, v, t, c); |
||
1777 | /* don't record anonymous symbol */ |
||
1778 | if (v < SYM_FIRST_ANOM) { |
||
1779 | ps = &table_ident[v - TOK_IDENT]->sym_identifier; |
||
1780 | /* modify the top most local identifier, so that |
||
1781 | sym_identifier will point to 's' when popped */ |
||
1782 | while (*ps != NULL) |
||
1783 | ps = &(*ps)->prev_tok; |
||
1784 | s->prev_tok = NULL; |
||
1785 | *ps = s; |
||
1786 | } |
||
1787 | return s; |
||
1788 | } |
||
1789 | |||
1790 | /* pop symbols until top reaches 'b' */ |
||
1791 | static void sym_pop(Sym **ptop, Sym *b) |
||
1792 | { |
||
1793 | Sym *s, *ss, **ps; |
||
1794 | TokenSym *ts; |
||
1795 | int v; |
||
1796 | |||
1797 | s = *ptop; |
||
1798 | while(s != b) { |
||
1799 | ss = s->prev; |
||
1800 | v = s->v; |
||
1801 | /* remove symbol in token array */ |
||
1802 | /* XXX: simplify */ |
||
1803 | if (!(v & SYM_FIELD) && (v & ~SYM_STRUCT) < SYM_FIRST_ANOM) { |
||
1804 | ts = table_ident[(v & ~SYM_STRUCT) - TOK_IDENT]; |
||
1805 | if (v & SYM_STRUCT) |
||
1806 | ps = &ts->sym_struct; |
||
1807 | else |
||
1808 | ps = &ts->sym_identifier; |
||
1809 | *ps = s->prev_tok; |
||
1810 | } |
||
1811 | sym_free(s); |
||
1812 | s = ss; |
||
1813 | } |
||
1814 | *ptop = b; |
||
1815 | } |
||
1816 | |||
1817 | /* I/O layer */ |
||
1818 | |||
1819 | BufferedFile *tcc_open(TCCState *s1, const char *filename) |
||
1820 | { |
||
1821 | int fd; |
||
1822 | BufferedFile *bf; |
||
1823 | |||
1824 | fd = open(filename, O_RDONLY | O_BINARY); |
||
1825 | if (fd < 0) |
||
1826 | return NULL; |
||
1827 | bf = tcc_malloc(sizeof(BufferedFile)); |
||
1828 | if (!bf) { |
||
1829 | close(fd); |
||
1830 | return NULL; |
||
1831 | } |
||
1832 | bf->fd = fd; |
||
1833 | bf->buf_ptr = bf->buffer; |
||
1834 | bf->buf_end = bf->buffer; |
||
1835 | bf->buffer[0] = CH_EOB; /* put eob symbol */ |
||
1836 | pstrcpy(bf->filename, sizeof(bf->filename), filename); |
||
1837 | bf->line_num = 1; |
||
1838 | bf->ifndef_macro = 0; |
||
1839 | bf->ifdef_stack_ptr = s1->ifdef_stack_ptr; |
||
1840 | // printf("opening '%s'\n", filename); |
||
1841 | return bf; |
||
1842 | } |
||
1843 | |||
1844 | void tcc_close(BufferedFile *bf) |
||
1845 | { |
||
1846 | total_lines += bf->line_num; |
||
1847 | close(bf->fd); |
||
1848 | tcc_free(bf); |
||
1849 | } |
||
1850 | |||
1851 | /* fill input buffer and peek next char */ |
||
1852 | static int tcc_peekc_slow(BufferedFile *bf) |
||
1853 | { |
||
1854 | int len; |
||
1855 | /* only tries to read if really end of buffer */ |
||
1856 | if (bf->buf_ptr >= bf->buf_end) { |
||
1857 | if (bf->fd != -1) { |
||
1858 | #if defined(PARSE_DEBUG) |
||
1859 | len = 8; |
||
1860 | #else |
||
1861 | len = IO_BUF_SIZE; |
||
1862 | #endif |
||
1863 | len = read(bf->fd, bf->buffer, len); |
||
1864 | if (len < 0) |
||
1865 | len = 0; |
||
1866 | } else { |
||
1867 | len = 0; |
||
1868 | } |
||
1869 | total_bytes += len; |
||
1870 | bf->buf_ptr = bf->buffer; |
||
1871 | bf->buf_end = bf->buffer + len; |
||
1872 | *bf->buf_end = CH_EOB; |
||
1873 | } |
||
1874 | if (bf->buf_ptr < bf->buf_end) { |
||
1875 | return bf->buf_ptr[0]; |
||
1876 | } else { |
||
1877 | bf->buf_ptr = bf->buf_end; |
||
1878 | return CH_EOF; |
||
1879 | } |
||
1880 | } |
||
1881 | |||
1882 | /* return the current character, handling end of block if necessary |
||
1883 | (but not stray) */ |
||
1884 | static int handle_eob(void) |
||
1885 | { |
||
1886 | return tcc_peekc_slow(file); |
||
1887 | } |
||
1888 | |||
1889 | /* read next char from current input file and handle end of input buffer */ |
||
1890 | static inline void inp(void) |
||
1891 | { |
||
1892 | ch = *(++(file->buf_ptr)); |
||
1893 | /* end of buffer/file handling */ |
||
1894 | if (ch == CH_EOB) |
||
1895 | ch = handle_eob(); |
||
1896 | } |
||
1897 | |||
1898 | /* handle '\[\r]\n' */ |
||
1899 | static void handle_stray(void) |
||
1900 | { |
||
1901 | while (ch == '\\') { |
||
1902 | inp(); |
||
1903 | if (ch == '\n') { |
||
1904 | file->line_num++; |
||
1905 | inp(); |
||
1906 | } else if (ch == '\r') { |
||
1907 | inp(); |
||
1908 | if (ch != '\n') |
||
1909 | goto fail; |
||
1910 | file->line_num++; |
||
1911 | inp(); |
||
1912 | } else { |
||
1913 | fail: |
||
1914 | error("stray '\\' in program"); |
||
1915 | } |
||
1916 | } |
||
1917 | } |
||
1918 | |||
1919 | /* skip the stray and handle the \\n case. Output an error if |
||
1920 | incorrect char after the stray */ |
||
1921 | static int handle_stray1(uint8_t *p) |
||
1922 | { |
||
1923 | int c; |
||
1924 | |||
1925 | if (p >= file->buf_end) { |
||
1926 | file->buf_ptr = p; |
||
1927 | c = handle_eob(); |
||
1928 | p = file->buf_ptr; |
||
1929 | if (c == '\\') |
||
1930 | goto parse_stray; |
||
1931 | } else { |
||
1932 | parse_stray: |
||
1933 | file->buf_ptr = p; |
||
1934 | ch = *p; |
||
1935 | handle_stray(); |
||
1936 | p = file->buf_ptr; |
||
1937 | c = *p; |
||
1938 | } |
||
1939 | return c; |
||
1940 | } |
||
1941 | |||
1942 | /* handle just the EOB case, but not stray */ |
||
1943 | #define PEEKC_EOB(c, p)\ |
||
1944 | {\ |
||
1945 | p++;\ |
||
1946 | c = *p;\ |
||
1947 | if (c == '\\') {\ |
||
1948 | file->buf_ptr = p;\ |
||
1949 | c = handle_eob();\ |
||
1950 | p = file->buf_ptr;\ |
||
1951 | }\ |
||
1952 | } |
||
1953 | |||
1954 | /* handle the complicated stray case */ |
||
1955 | #define PEEKC(c, p)\ |
||
1956 | {\ |
||
1957 | p++;\ |
||
1958 | c = *p;\ |
||
1959 | if (c == '\\') {\ |
||
1960 | c = handle_stray1(p);\ |
||
1961 | p = file->buf_ptr;\ |
||
1962 | }\ |
||
1963 | } |
||
1964 | |||
1965 | /* input with '\[\r]\n' handling. Note that this function cannot |
||
1966 | handle other characters after '\', so you cannot call it inside |
||
1967 | strings or comments */ |
||
1968 | static void minp(void) |
||
1969 | { |
||
1970 | inp(); |
||
1971 | if (ch == '\\') |
||
1972 | handle_stray(); |
||
1973 | } |
||
1974 | |||
1975 | |||
1976 | /* single line C++ comments */ |
||
1977 | static uint8_t *parse_line_comment(uint8_t *p) |
||
1978 | { |
||
1979 | int c; |
||
1980 | |||
1981 | p++; |
||
1982 | for(;;) { |
||
1983 | c = *p; |
||
1984 | redo: |
||
1985 | if (c == '\n' || c == CH_EOF) { |
||
1986 | break; |
||
1987 | } else if (c == '\\') { |
||
1988 | file->buf_ptr = p; |
||
1989 | c = handle_eob(); |
||
1990 | p = file->buf_ptr; |
||
1991 | if (c == '\\') { |
||
1992 | PEEKC_EOB(c, p); |
||
1993 | if (c == '\n') { |
||
1994 | file->line_num++; |
||
1995 | PEEKC_EOB(c, p); |
||
1996 | } else if (c == '\r') { |
||
1997 | PEEKC_EOB(c, p); |
||
1998 | if (c == '\n') { |
||
1999 | file->line_num++; |
||
2000 | PEEKC_EOB(c, p); |
||
2001 | } |
||
2002 | } |
||
2003 | } else { |
||
2004 | goto redo; |
||
2005 | } |
||
2006 | } else { |
||
2007 | p++; |
||
2008 | } |
||
2009 | } |
||
2010 | return p; |
||
2011 | } |
||
2012 | |||
2013 | /* C comments */ |
||
2014 | static uint8_t *parse_comment(uint8_t *p) |
||
2015 | { |
||
2016 | int c; |
||
2017 | |||
2018 | p++; |
||
2019 | for(;;) { |
||
2020 | /* fast skip loop */ |
||
2021 | for(;;) { |
||
2022 | c = *p; |
||
2023 | if (c == '\n' || c == '*' || c == '\\') |
||
2024 | break; |
||
2025 | p++; |
||
2026 | c = *p; |
||
2027 | if (c == '\n' || c == '*' || c == '\\') |
||
2028 | break; |
||
2029 | p++; |
||
2030 | } |
||
2031 | /* now we can handle all the cases */ |
||
2032 | if (c == '\n') { |
||
2033 | file->line_num++; |
||
2034 | p++; |
||
2035 | } else if (c == '*') { |
||
2036 | p++; |
||
2037 | for(;;) { |
||
2038 | c = *p; |
||
2039 | if (c == '*') { |
||
2040 | p++; |
||
2041 | } else if (c == '/') { |
||
2042 | goto end_of_comment; |
||
2043 | } else if (c == '\\') { |
||
2044 | file->buf_ptr = p; |
||
2045 | c = handle_eob(); |
||
2046 | p = file->buf_ptr; |
||
2047 | if (c == '\\') { |
||
2048 | /* skip '\[\r]\n', otherwise just skip the stray */ |
||
2049 | while (c == '\\') { |
||
2050 | PEEKC_EOB(c, p); |
||
2051 | if (c == '\n') { |
||
2052 | file->line_num++; |
||
2053 | PEEKC_EOB(c, p); |
||
2054 | } else if (c == '\r') { |
||
2055 | PEEKC_EOB(c, p); |
||
2056 | if (c == '\n') { |
||
2057 | file->line_num++; |
||
2058 | PEEKC_EOB(c, p); |
||
2059 | } |
||
2060 | } else { |
||
2061 | goto after_star; |
||
2062 | } |
||
2063 | } |
||
2064 | } |
||
2065 | } else { |
||
2066 | break; |
||
2067 | } |
||
2068 | } |
||
2069 | after_star: ; |
||
2070 | } else { |
||
2071 | /* stray, eob or eof */ |
||
2072 | file->buf_ptr = p; |
||
2073 | c = handle_eob(); |
||
2074 | p = file->buf_ptr; |
||
2075 | if (c == CH_EOF) { |
||
2076 | error("unexpected end of file in comment"); |
||
2077 | } else if (c == '\\') { |
||
2078 | p++; |
||
2079 | } |
||
2080 | } |
||
2081 | } |
||
2082 | end_of_comment: |
||
2083 | p++; |
||
2084 | return p; |
||
2085 | } |
||
2086 | |||
2087 | #define cinp minp |
||
2088 | |||
2089 | /* space excluding newline */ |
||
2090 | static inline int is_space(int ch) |
||
2091 | { |
||
2092 | return ch == ' ' || ch == '\t' || ch == '\v' || ch == '\f' || ch == '\r'; |
||
2093 | } |
||
2094 | |||
2095 | static inline void skip_spaces(void) |
||
2096 | { |
||
2097 | while (is_space(ch)) |
||
2098 | cinp(); |
||
2099 | } |
||
2100 | |||
2101 | /* parse a string without interpreting escapes */ |
||
2102 | static uint8_t *parse_pp_string(uint8_t *p, |
||
2103 | int sep, CString *str) |
||
2104 | { |
||
2105 | int c; |
||
2106 | p++; |
||
2107 | for(;;) { |
||
2108 | c = *p; |
||
2109 | if (c == sep) { |
||
2110 | break; |
||
2111 | } else if (c == '\\') { |
||
2112 | file->buf_ptr = p; |
||
2113 | c = handle_eob(); |
||
2114 | p = file->buf_ptr; |
||
2115 | if (c == CH_EOF) { |
||
2116 | unterminated_string: |
||
2117 | /* XXX: indicate line number of start of string */ |
||
2118 | error("missing terminating %c character", sep); |
||
2119 | } else if (c == '\\') { |
||
2120 | /* escape : just skip \[\r]\n */ |
||
2121 | PEEKC_EOB(c, p); |
||
2122 | if (c == '\n') { |
||
2123 | file->line_num++; |
||
2124 | p++; |
||
2125 | } else if (c == '\r') { |
||
2126 | PEEKC_EOB(c, p); |
||
2127 | if (c != '\n') |
||
2128 | expect("'\n' after '\r'"); |
||
2129 | file->line_num++; |
||
2130 | p++; |
||
2131 | } else if (c == CH_EOF) { |
||
2132 | goto unterminated_string; |
||
2133 | } else { |
||
2134 | if (str) { |
||
2135 | cstr_ccat(str, '\\'); |
||
2136 | cstr_ccat(str, c); |
||
2137 | } |
||
2138 | p++; |
||
2139 | } |
||
2140 | } |
||
2141 | } else if (c == '\n') { |
||
2142 | file->line_num++; |
||
2143 | goto add_char; |
||
2144 | } else if (c == '\r') { |
||
2145 | PEEKC_EOB(c, p); |
||
2146 | if (c != '\n') { |
||
2147 | if (str) |
||
2148 | cstr_ccat(str, '\r'); |
||
2149 | } else { |
||
2150 | file->line_num++; |
||
2151 | goto add_char; |
||
2152 | } |
||
2153 | } else { |
||
2154 | add_char: |
||
2155 | if (str) |
||
2156 | cstr_ccat(str, c); |
||
2157 | p++; |
||
2158 | } |
||
2159 | } |
||
2160 | p++; |
||
2161 | return p; |
||
2162 | } |
||
2163 | |||
2164 | /* skip block of text until #else, #elif or #endif. skip also pairs of |
||
2165 | #if/#endif */ |
||
2166 | void preprocess_skip(void) |
||
2167 | { |
||
2168 | int a, start_of_line, c; |
||
2169 | uint8_t *p; |
||
2170 | |||
2171 | p = file->buf_ptr; |
||
2172 | start_of_line = 1; |
||
2173 | a = 0; |
||
2174 | for(;;) { |
||
2175 | redo_no_start: |
||
2176 | c = *p; |
||
2177 | switch(c) { |
||
2178 | case ' ': |
||
2179 | case '\t': |
||
2180 | case '\f': |
||
2181 | case '\v': |
||
2182 | case '\r': |
||
2183 | p++; |
||
2184 | goto redo_no_start; |
||
2185 | case '\n': |
||
2186 | start_of_line = 1; |
||
2187 | file->line_num++; |
||
2188 | p++; |
||
2189 | goto redo_no_start; |
||
2190 | case '\\': |
||
2191 | file->buf_ptr = p; |
||
2192 | c = handle_eob(); |
||
2193 | if (c == CH_EOF) { |
||
2194 | expect("#endif"); |
||
2195 | } else if (c == '\\') { |
||
2196 | /* XXX: incorrect: should not give an error */ |
||
2197 | ch = file->buf_ptr[0]; |
||
2198 | handle_stray(); |
||
2199 | } |
||
2200 | p = file->buf_ptr; |
||
2201 | goto redo_no_start; |
||
2202 | /* skip strings */ |
||
2203 | case '\"': |
||
2204 | case '\'': |
||
2205 | p = parse_pp_string(p, c, NULL); |
||
2206 | break; |
||
2207 | /* skip comments */ |
||
2208 | case '/': |
||
2209 | file->buf_ptr = p; |
||
2210 | ch = *p; |
||
2211 | minp(); |
||
2212 | p = file->buf_ptr; |
||
2213 | if (ch == '*') { |
||
2214 | p = parse_comment(p); |
||
2215 | } else if (ch == '/') { |
||
2216 | p = parse_line_comment(p); |
||
2217 | } |
||
2218 | break; |
||
2219 | |||
2220 | case '#': |
||
2221 | p++; |
||
2222 | if (start_of_line) { |
||
2223 | file->buf_ptr = p; |
||
2224 | next_nomacro(); |
||
2225 | p = file->buf_ptr; |
||
2226 | if (a == 0 && |
||
2227 | (tok == TOK_ELSE || tok == TOK_ELIF || tok == TOK_ENDIF)) |
||
2228 | goto the_end; |
||
2229 | if (tok == TOK_IF || tok == TOK_IFDEF || tok == TOK_IFNDEF) |
||
2230 | a++; |
||
2231 | else if (tok == TOK_ENDIF) |
||
2232 | a--; |
||
2233 | } |
||
2234 | break; |
||
2235 | default: |
||
2236 | p++; |
||
2237 | break; |
||
2238 | } |
||
2239 | start_of_line = 0; |
||
2240 | } |
||
2241 | the_end: ; |
||
2242 | file->buf_ptr = p; |
||
2243 | } |
||
2244 | |||
2245 | /* ParseState handling */ |
||
2246 | |||
2247 | /* XXX: currently, no include file info is stored. Thus, we cannot display |
||
2248 | accurate messages if the function or data definition spans multiple |
||
2249 | files */ |
||
2250 | |||
2251 | /* save current parse state in 's' */ |
||
2252 | void save_parse_state(ParseState *s) |
||
2253 | { |
||
2254 | s->line_num = file->line_num; |
||
2255 | s->macro_ptr = macro_ptr; |
||
2256 | s->tok = tok; |
||
2257 | s->tokc = tokc; |
||
2258 | } |
||
2259 | |||
2260 | /* restore parse state from 's' */ |
||
2261 | void restore_parse_state(ParseState *s) |
||
2262 | { |
||
2263 | file->line_num = s->line_num; |
||
2264 | macro_ptr = s->macro_ptr; |
||
2265 | tok = s->tok; |
||
2266 | tokc = s->tokc; |
||
2267 | } |
||
2268 | |||
2269 | /* return the number of additional 'ints' necessary to store the |
||
2270 | token */ |
||
2271 | static inline int tok_ext_size(int t) |
||
2272 | { |
||
2273 | switch(t) { |
||
2274 | /* 4 bytes */ |
||
2275 | case TOK_CINT: |
||
2276 | case TOK_CUINT: |
||
2277 | case TOK_CCHAR: |
||
2278 | case TOK_LCHAR: |
||
2279 | case TOK_CFLOAT: |
||
2280 | case TOK_LINENUM: |
||
2281 | return 1; |
||
2282 | case TOK_STR: |
||
2283 | case TOK_LSTR: |
||
2284 | case TOK_PPNUM: |
||
2285 | error("unsupported token"); |
||
2286 | return 1; |
||
2287 | case TOK_CDOUBLE: |
||
2288 | case TOK_CLLONG: |
||
2289 | case TOK_CULLONG: |
||
2290 | return 2; |
||
2291 | case TOK_CLDOUBLE: |
||
2292 | return LDOUBLE_SIZE / 4; |
||
2293 | default: |
||
2294 | return 0; |
||
2295 | } |
||
2296 | } |
||
2297 | |||
2298 | /* token string handling */ |
||
2299 | |||
2300 | static inline void tok_str_new(TokenString *s) |
||
2301 | { |
||
2302 | s->str = NULL; |
||
2303 | s->len = 0; |
||
2304 | s->allocated_len = 0; |
||
2305 | s->last_line_num = -1; |
||
2306 | } |
||
2307 | |||
2308 | static void tok_str_free(int *str) |
||
2309 | { |
||
2310 | tcc_free(str); |
||
2311 | } |
||
2312 | |||
2313 | static int *tok_str_realloc(TokenString *s) |
||
2314 | { |
||
2315 | int *str, len; |
||
2316 | |||
2317 | if (s->allocated_len == 0) { |
||
2318 | len = 8; |
||
2319 | } else { |
||
2320 | len = s->allocated_len * 2; |
||
2321 | } |
||
2322 | str = tcc_realloc(s->str, len * sizeof(int)); |
||
2323 | if (!str) |
||
2324 | error("memory full"); |
||
2325 | s->allocated_len = len; |
||
2326 | s->str = str; |
||
2327 | return str; |
||
2328 | } |
||
2329 | |||
2330 | static void tok_str_add(TokenString *s, int t) |
||
2331 | { |
||
2332 | int len, *str; |
||
2333 | |||
2334 | len = s->len; |
||
2335 | str = s->str; |
||
2336 | if (len >= s->allocated_len) |
||
2337 | str = tok_str_realloc(s); |
||
2338 | str[len++] = t; |
||
2339 | s->len = len; |
||
2340 | } |
||
2341 | |||
2342 | static void tok_str_add2(TokenString *s, int t, CValue *cv) |
||
2343 | { |
||
2344 | int len, *str; |
||
2345 | |||
2346 | len = s->len; |
||
2347 | str = s->str; |
||
2348 | |||
2349 | /* allocate space for worst case */ |
||
2350 | if (len + TOK_MAX_SIZE > s->allocated_len) |
||
2351 | str = tok_str_realloc(s); |
||
2352 | str[len++] = t; |
||
2353 | switch(t) { |
||
2354 | case TOK_CINT: |
||
2355 | case TOK_CUINT: |
||
2356 | case TOK_CCHAR: |
||
2357 | case TOK_LCHAR: |
||
2358 | case TOK_CFLOAT: |
||
2359 | case TOK_LINENUM: |
||
2360 | str[len++] = cv->tab[0]; |
||
2361 | break; |
||
2362 | case TOK_PPNUM: |
||
2363 | case TOK_STR: |
||
2364 | case TOK_LSTR: |
||
2365 | { |
||
2366 | int nb_words; |
||
2367 | CString *cstr; |
||
2368 | |||
2369 | nb_words = (sizeof(CString) + cv->cstr->size + 3) >> 2; |
||
2370 | while ((len + nb_words) > s->allocated_len) |
||
2371 | str = tok_str_realloc(s); |
||
2372 | cstr = (CString *)(str + len); |
||
2373 | cstr->data = NULL; |
||
2374 | cstr->size = cv->cstr->size; |
||
2375 | cstr->data_allocated = NULL; |
||
2376 | cstr->size_allocated = cstr->size; |
||
2377 | memcpy((char *)cstr + sizeof(CString), |
||
2378 | cv->cstr->data, cstr->size); |
||
2379 | len += nb_words; |
||
2380 | } |
||
2381 | break; |
||
2382 | case TOK_CDOUBLE: |
||
2383 | case TOK_CLLONG: |
||
2384 | case TOK_CULLONG: |
||
2385 | #if LDOUBLE_SIZE == 8 |
||
2386 | case TOK_CLDOUBLE: |
||
2387 | #endif |
||
2388 | str[len++] = cv->tab[0]; |
||
2389 | str[len++] = cv->tab[1]; |
||
2390 | break; |
||
2391 | #if LDOUBLE_SIZE == 12 |
||
2392 | case TOK_CLDOUBLE: |
||
2393 | str[len++] = cv->tab[0]; |
||
2394 | str[len++] = cv->tab[1]; |
||
2395 | str[len++] = cv->tab[2]; |
||
2396 | #elif LDOUBLE_SIZE != 8 |
||
2397 | #error add long double size support |
||
2398 | #endif |
||
2399 | break; |
||
2400 | default: |
||
2401 | break; |
||
2402 | } |
||
2403 | s->len = len; |
||
2404 | } |
||
2405 | |||
2406 | /* add the current parse token in token string 's' */ |
||
2407 | static void tok_str_add_tok(TokenString *s) |
||
2408 | { |
||
2409 | CValue cval; |
||
2410 | |||
2411 | /* save line number info */ |
||
2412 | if (file->line_num != s->last_line_num) { |
||
2413 | s->last_line_num = file->line_num; |
||
2414 | cval.i = s->last_line_num; |
||
2415 | tok_str_add2(s, TOK_LINENUM, &cval); |
||
2416 | } |
||
2417 | tok_str_add2(s, tok, &tokc); |
||
2418 | } |
||
2419 | |||
2420 | #if LDOUBLE_SIZE == 12 |
||
2421 | #define LDOUBLE_GET(p, cv) \ |
||
2422 | cv.tab[0] = p[0]; \ |
||
2423 | cv.tab[1] = p[1]; \ |
||
2424 | cv.tab[2] = p[2]; |
||
2425 | #elif LDOUBLE_SIZE == 8 |
||
2426 | #define LDOUBLE_GET(p, cv) \ |
||
2427 | cv.tab[0] = p[0]; \ |
||
2428 | cv.tab[1] = p[1]; |
||
2429 | #else |
||
2430 | #error add long double size support |
||
2431 | #endif |
||
2432 | |||
2433 | |||
2434 | /* get a token from an integer array and increment pointer |
||
2435 | accordingly. we code it as a macro to avoid pointer aliasing. */ |
||
2436 | #define TOK_GET(t, p, cv) \ |
||
2437 | { \ |
||
2438 | t = *p++; \ |
||
2439 | switch(t) { \ |
||
2440 | case TOK_CINT: \ |
||
2441 | case TOK_CUINT: \ |
||
2442 | case TOK_CCHAR: \ |
||
2443 | case TOK_LCHAR: \ |
||
2444 | case TOK_CFLOAT: \ |
||
2445 | case TOK_LINENUM: \ |
||
2446 | cv.tab[0] = *p++; \ |
||
2447 | break; \ |
||
2448 | case TOK_STR: \ |
||
2449 | case TOK_LSTR: \ |
||
2450 | case TOK_PPNUM: \ |
||
2451 | cv.cstr = (CString *)p; \ |
||
2452 | cv.cstr->data = (char *)p + sizeof(CString);\ |
||
2453 | p += (sizeof(CString) + cv.cstr->size + 3) >> 2;\ |
||
2454 | break; \ |
||
2455 | case TOK_CDOUBLE: \ |
||
2456 | case TOK_CLLONG: \ |
||
2457 | case TOK_CULLONG: \ |
||
2458 | cv.tab[0] = p[0]; \ |
||
2459 | cv.tab[1] = p[1]; \ |
||
2460 | p += 2; \ |
||
2461 | break; \ |
||
2462 | case TOK_CLDOUBLE: \ |
||
2463 | LDOUBLE_GET(p, cv); \ |
||
2464 | p += LDOUBLE_SIZE / 4; \ |
||
2465 | break; \ |
||
2466 | default: \ |
||
2467 | break; \ |
||
2468 | } \ |
||
2469 | } |
||
2470 | |||
2471 | /* defines handling */ |
||
2472 | static inline void define_push(int v, int macro_type, int *str, Sym *first_arg) |
||
2473 | { |
||
2474 | Sym *s; |
||
2475 | |||
2476 | s = sym_push2(&define_stack, v, macro_type, (int)str); |
||
2477 | s->next = first_arg; |
||
2478 | table_ident[v - TOK_IDENT]->sym_define = s; |
||
2479 | } |
||
2480 | |||
2481 | /* undefined a define symbol. Its name is just set to zero */ |
||
2482 | static void define_undef(Sym *s) |
||
2483 | { |
||
2484 | int v; |
||
2485 | v = s->v; |
||
2486 | if (v >= TOK_IDENT && v < tok_ident) |
||
2487 | table_ident[v - TOK_IDENT]->sym_define = NULL; |
||
2488 | s->v = 0; |
||
2489 | } |
||
2490 | |||
2491 | static inline Sym *define_find(int v) |
||
2492 | { |
||
2493 | v -= TOK_IDENT; |
||
2494 | if ((unsigned)v >= (unsigned)(tok_ident - TOK_IDENT)) |
||
2495 | return NULL; |
||
2496 | return table_ident[v]->sym_define; |
||
2497 | } |
||
2498 | |||
2499 | /* free define stack until top reaches 'b' */ |
||
2500 | static void free_defines(Sym *b) |
||
2501 | { |
||
2502 | Sym *top, *top1; |
||
2503 | int v; |
||
2504 | |||
2505 | top = define_stack; |
||
2506 | while (top != b) { |
||
2507 | top1 = top->prev; |
||
2508 | /* do not free args or predefined defines */ |
||
2509 | if (top->c) |
||
2510 | tok_str_free((int *)top->c); |
||
2511 | v = top->v; |
||
2512 | if (v >= TOK_IDENT && v < tok_ident) |
||
2513 | table_ident[v - TOK_IDENT]->sym_define = NULL; |
||
2514 | sym_free(top); |
||
2515 | top = top1; |
||
2516 | } |
||
2517 | define_stack = b; |
||
2518 | } |
||
2519 | |||
2520 | /* label lookup */ |
||
2521 | static Sym *label_find(int v) |
||
2522 | { |
||
2523 | v -= TOK_IDENT; |
||
2524 | if ((unsigned)v >= (unsigned)(tok_ident - TOK_IDENT)) |
||
2525 | return NULL; |
||
2526 | return table_ident[v]->sym_label; |
||
2527 | } |
||
2528 | |||
2529 | static Sym *label_push(Sym **ptop, int v, int flags) |
||
2530 | { |
||
2531 | Sym *s, **ps; |
||
2532 | s = sym_push2(ptop, v, 0, 0); |
||
2533 | s->r = flags; |
||
2534 | ps = &table_ident[v - TOK_IDENT]->sym_label; |
||
2535 | if (ptop == &global_label_stack) { |
||
2536 | /* modify the top most local identifier, so that |
||
2537 | sym_identifier will point to 's' when popped */ |
||
2538 | while (*ps != NULL) |
||
2539 | ps = &(*ps)->prev_tok; |
||
2540 | } |
||
2541 | s->prev_tok = *ps; |
||
2542 | *ps = s; |
||
2543 | return s; |
||
2544 | } |
||
2545 | |||
2546 | /* pop labels until element last is reached. Look if any labels are |
||
2547 | undefined. Define symbols if '&&label' was used. */ |
||
2548 | static void label_pop(Sym **ptop, Sym *slast) |
||
2549 | { |
||
2550 | Sym *s, *s1; |
||
2551 | for(s = *ptop; s != slast; s = s1) { |
||
2552 | s1 = s->prev; |
||
2553 | if (s->r == LABEL_DECLARED) { |
||
2554 | warning("label '%s' declared but not used", get_tok_str(s->v, NULL)); |
||
2555 | } else if (s->r == LABEL_FORWARD) { |
||
2556 | error("label '%s' used but not defined", |
||
2557 | get_tok_str(s->v, NULL)); |
||
2558 | } else { |
||
2559 | if (s->c) { |
||
2560 | /* define corresponding symbol. A size of |
||
2561 | 1 is put. */ |
||
2562 | put_extern_sym(s, cur_text_section, (long)s->next, 1); |
||
2563 | } |
||
2564 | } |
||
2565 | /* remove label */ |
||
2566 | table_ident[s->v - TOK_IDENT]->sym_label = s->prev_tok; |
||
2567 | sym_free(s); |
||
2568 | } |
||
2569 | *ptop = slast; |
||
2570 | } |
||
2571 | |||
2572 | /* eval an expression for #if/#elif */ |
||
2573 | static int expr_preprocess(void) |
||
2574 | { |
||
2575 | int c, t; |
||
2576 | TokenString str; |
||
2577 | |||
2578 | tok_str_new(&str); |
||
2579 | while (tok != TOK_LINEFEED && tok != TOK_EOF) { |
||
2580 | next(); /* do macro subst */ |
||
2581 | if (tok == TOK_DEFINED) { |
||
2582 | next_nomacro(); |
||
2583 | t = tok; |
||
2584 | if (t == '(') |
||
2585 | next_nomacro(); |
||
2586 | c = define_find(tok) != 0; |
||
2587 | if (t == '(') |
||
2588 | next_nomacro(); |
||
2589 | tok = TOK_CINT; |
||
2590 | tokc.i = c; |
||
2591 | } else if (tok >= TOK_IDENT) { |
||
2592 | /* if undefined macro */ |
||
2593 | tok = TOK_CINT; |
||
2594 | tokc.i = 0; |
||
2595 | } |
||
2596 | tok_str_add_tok(&str); |
||
2597 | } |
||
2598 | tok_str_add(&str, -1); /* simulate end of file */ |
||
2599 | tok_str_add(&str, 0); |
||
2600 | /* now evaluate C constant expression */ |
||
2601 | macro_ptr = str.str; |
||
2602 | next(); |
||
2603 | c = expr_const(); |
||
2604 | macro_ptr = NULL; |
||
2605 | tok_str_free(str.str); |
||
2606 | return c != 0; |
||
2607 | } |
||
2608 | |||
2609 | #if defined(PARSE_DEBUG) || defined(PP_DEBUG) |
||
2610 | static void tok_print(int *str) |
||
2611 | { |
||
2612 | int t; |
||
2613 | CValue cval; |
||
2614 | |||
2615 | while (1) { |
||
2616 | TOK_GET(t, str, cval); |
||
2617 | if (!t) |
||
2618 | break; |
||
2619 | printf(" %s", get_tok_str(t, &cval)); |
||
2620 | } |
||
2621 | printf("\n"); |
||
2622 | } |
||
2623 | #endif |
||
2624 | |||
2625 | /* parse after #define */ |
||
2626 | static void parse_define(void) |
||
2627 | { |
||
2628 | Sym *s, *first, **ps; |
||
2629 | int v, t, varg, is_vaargs, c; |
||
2630 | TokenString str; |
||
2631 | |||
2632 | v = tok; |
||
2633 | if (v < TOK_IDENT) |
||
2634 | error("invalid macro name '%s'", get_tok_str(tok, &tokc)); |
||
2635 | /* XXX: should check if same macro (ANSI) */ |
||
2636 | first = NULL; |
||
2637 | t = MACRO_OBJ; |
||
2638 | /* '(' must be just after macro definition for MACRO_FUNC */ |
||
2639 | c = file->buf_ptr[0]; |
||
2640 | if (c == '\\') |
||
2641 | c = handle_stray1(file->buf_ptr); |
||
2642 | if (c == '(') { |
||
2643 | next_nomacro(); |
||
2644 | next_nomacro(); |
||
2645 | ps = &first; |
||
2646 | while (tok != ')') { |
||
2647 | varg = tok; |
||
2648 | next_nomacro(); |
||
2649 | is_vaargs = 0; |
||
2650 | if (varg == TOK_DOTS) { |
||
2651 | varg = TOK___VA_ARGS__; |
||
2652 | is_vaargs = 1; |
||
2653 | } else if (tok == TOK_DOTS && gnu_ext) { |
||
2654 | is_vaargs = 1; |
||
2655 | next_nomacro(); |
||
2656 | } |
||
2657 | if (varg < TOK_IDENT) |
||
2658 | error("badly punctuated parameter list"); |
||
2659 | s = sym_push2(&define_stack, varg | SYM_FIELD, is_vaargs, 0); |
||
2660 | *ps = s; |
||
2661 | ps = &s->next; |
||
2662 | if (tok != ',') |
||
2663 | break; |
||
2664 | next_nomacro(); |
||
2665 | } |
||
2666 | t = MACRO_FUNC; |
||
2667 | } |
||
2668 | tok_str_new(&str); |
||
2669 | next_nomacro(); |
||
2670 | /* EOF testing necessary for '-D' handling */ |
||
2671 | while (tok != TOK_LINEFEED && tok != TOK_EOF) { |
||
2672 | tok_str_add2(&str, tok, &tokc); |
||
2673 | next_nomacro(); |
||
2674 | } |
||
2675 | tok_str_add(&str, 0); |
||
2676 | #ifdef PP_DEBUG |
||
2677 | printf("define %s %d: ", get_tok_str(v, NULL), t); |
||
2678 | tok_print(str.str); |
||
2679 | #endif |
||
2680 | define_push(v, t, str.str, first); |
||
2681 | } |
||
2682 | |||
2683 | static inline int hash_cached_include(int type, const char *filename) |
||
2684 | { |
||
2685 | const unsigned char *s; |
||
2686 | unsigned int h; |
||
2687 | |||
2688 | h = TOK_HASH_INIT; |
||
2689 | h = TOK_HASH_FUNC(h, type); |
||
2690 | s = filename; |
||
2691 | while (*s) { |
||
2692 | h = TOK_HASH_FUNC(h, *s); |
||
2693 | s++; |
||
2694 | } |
||
2695 | h &= (CACHED_INCLUDES_HASH_SIZE - 1); |
||
2696 | return h; |
||
2697 | } |
||
2698 | |||
2699 | /* XXX: use a token or a hash table to accelerate matching ? */ |
||
2700 | static CachedInclude *search_cached_include(TCCState *s1, |
||
2701 | int type, const char *filename) |
||
2702 | { |
||
2703 | CachedInclude *e; |
||
2704 | int i, h; |
||
2705 | h = hash_cached_include(type, filename); |
||
2706 | i = s1->cached_includes_hash[h]; |
||
2707 | for(;;) { |
||
2708 | if (i == 0) |
||
2709 | break; |
||
2710 | e = s1->cached_includes[i - 1]; |
||
2711 | if (e->type == type && !strcmp(e->filename, filename)) |
||
2712 | return e; |
||
2713 | i = e->hash_next; |
||
2714 | } |
||
2715 | return NULL; |
||
2716 | } |
||
2717 | |||
2718 | static inline void add_cached_include(TCCState *s1, int type, |
||
2719 | const char *filename, int ifndef_macro) |
||
2720 | { |
||
2721 | CachedInclude *e; |
||
2722 | int h; |
||
2723 | |||
2724 | if (search_cached_include(s1, type, filename)) |
||
2725 | return; |
||
2726 | #ifdef INC_DEBUG |
||
2727 | printf("adding cached '%s' %s\n", filename, get_tok_str(ifndef_macro, NULL)); |
||
2728 | #endif |
||
2729 | e = tcc_malloc(sizeof(CachedInclude) + strlen(filename)); |
||
2730 | if (!e) |
||
2731 | return; |
||
2732 | e->type = type; |
||
2733 | strcpy(e->filename, filename); |
||
2734 | e->ifndef_macro = ifndef_macro; |
||
2735 | dynarray_add((void ***)&s1->cached_includes, &s1->nb_cached_includes, e); |
||
2736 | /* add in hash table */ |
||
2737 | h = hash_cached_include(type, filename); |
||
2738 | e->hash_next = s1->cached_includes_hash[h]; |
||
2739 | s1->cached_includes_hash[h] = s1->nb_cached_includes; |
||
2740 | } |
||
2741 | |||
2742 | static void pragma_parse(TCCState *s1) |
||
2743 | { |
||
2744 | int val; |
||
2745 | |||
2746 | next(); |
||
2747 | if (tok == TOK_pack) { |
||
2748 | /* |
||
2749 | This may be: |
||
2750 | #pragma pack(1) // set |
||
2751 | #pragma pack() // reset to default |
||
2752 | #pragma pack(push,1) // push & set |
||
2753 | #pragma pack(pop) // restore previous |
||
2754 | */ |
||
2755 | next(); |
||
2756 | skip('('); |
||
2757 | if (tok == TOK_ASM_pop) { |
||
2758 | next(); |
||
2759 | if (s1->pack_stack_ptr <= s1->pack_stack) { |
||
2760 | stk_error: |
||
2761 | error("out of pack stack"); |
||
2762 | } |
||
2763 | s1->pack_stack_ptr--; |
||
2764 | } else { |
||
2765 | val = 0; |
||
2766 | if (tok != ')') { |
||
2767 | if (tok == TOK_ASM_push) { |
||
2768 | next(); |
||
2769 | if (s1->pack_stack_ptr >= s1->pack_stack + PACK_STACK_SIZE - 1) |
||
2770 | goto stk_error; |
||
2771 | s1->pack_stack_ptr++; |
||
2772 | skip(','); |
||
2773 | } |
||
2774 | if (tok != TOK_CINT) { |
||
2775 | pack_error: |
||
2776 | error("invalid pack pragma"); |
||
2777 | } |
||
2778 | val = tokc.i; |
||
2779 | if (val < 1 || val > 16 || (val & (val - 1)) != 0) |
||
2780 | goto pack_error; |
||
2781 | next(); |
||
2782 | } |
||
2783 | *s1->pack_stack_ptr = val; |
||
2784 | skip(')'); |
||
2785 | } |
||
2786 | } |
||
2787 | } |
||
2788 | |||
2789 | /* is_bof is true if first non space token at beginning of file */ |
||
2790 | static void preprocess(int is_bof) |
||
2791 | { |
||
2792 | TCCState *s1 = tcc_state; |
||
2793 | int size, i, c, n, saved_parse_flags; |
||
2794 | char buf[1024], *q, *p; |
||
2795 | char buf1[1024]; |
||
2796 | BufferedFile *f; |
||
2797 | Sym *s; |
||
2798 | CachedInclude *e; |
||
2799 | |||
2800 | saved_parse_flags = parse_flags; |
||
2801 | parse_flags = PARSE_FLAG_PREPROCESS | PARSE_FLAG_TOK_NUM | |
||
2802 | PARSE_FLAG_LINEFEED; |
||
2803 | next_nomacro(); |
||
2804 | redo: |
||
2805 | switch(tok) { |
||
2806 | case TOK_DEFINE: |
||
2807 | next_nomacro(); |
||
2808 | parse_define(); |
||
2809 | break; |
||
2810 | case TOK_UNDEF: |
||
2811 | next_nomacro(); |
||
2812 | s = define_find(tok); |
||
2813 | /* undefine symbol by putting an invalid name */ |
||
2814 | if (s) |
||
2815 | define_undef(s); |
||
2816 | break; |
||
2817 | case TOK_INCLUDE: |
||
2818 | case TOK_INCLUDE_NEXT: |
||
2819 | ch = file->buf_ptr[0]; |
||
2820 | /* XXX: incorrect if comments : use next_nomacro with a special mode */ |
||
2821 | skip_spaces(); |
||
2822 | if (ch == '<') { |
||
2823 | c = '>'; |
||
2824 | goto read_name; |
||
2825 | } else if (ch == '\"') { |
||
2826 | c = ch; |
||
2827 | read_name: |
||
2828 | /* XXX: better stray handling */ |
||
2829 | minp(); |
||
2830 | q = buf; |
||
2831 | while (ch != c && ch != '\n' && ch != CH_EOF) { |
||
2832 | if ((q - buf) < sizeof(buf) - 1) |
||
2833 | *q++ = ch; |
||
2834 | minp(); |
||
2835 | } |
||
2836 | *q = '\0'; |
||
2837 | minp(); |
||
2838 | #if 0 |
||
2839 | /* eat all spaces and comments after include */ |
||
2840 | /* XXX: slightly incorrect */ |
||
2841 | while (ch1 != '\n' && ch1 != CH_EOF) |
||
2842 | inp(); |
||
2843 | #endif |
||
2844 | } else { |
||
2845 | /* computed #include : either we have only strings or |
||
2846 | we have anything enclosed in '<>' */ |
||
2847 | next(); |
||
2848 | buf[0] = '\0'; |
||
2849 | if (tok == TOK_STR) { |
||
2850 | while (tok != TOK_LINEFEED) { |
||
2851 | if (tok != TOK_STR) { |
||
2852 | include_syntax: |
||
2853 | error("'#include' expects \"FILENAME\" or |
||
2854 | } |
||
2855 | pstrcat(buf, sizeof(buf), (char *)tokc.cstr->data); |
||
2856 | next(); |
||
2857 | } |
||
2858 | c = '\"'; |
||
2859 | } else { |
||
2860 | int len; |
||
2861 | while (tok != TOK_LINEFEED) { |
||
2862 | pstrcat(buf, sizeof(buf), get_tok_str(tok, &tokc)); |
||
2863 | next(); |
||
2864 | } |
||
2865 | len = strlen(buf); |
||
2866 | /* check syntax and remove '<>' */ |
||
2867 | if (len < 2 || buf[0] != '<' || buf[len - 1] != '>') |
||
2868 | goto include_syntax; |
||
2869 | memmove(buf, buf + 1, len - 2); |
||
2870 | buf[len - 2] = '\0'; |
||
2871 | c = '>'; |
||
2872 | } |
||
2873 | } |
||
2874 | |||
2875 | e = search_cached_include(s1, c, buf); |
||
2876 | if (e && define_find(e->ifndef_macro)) { |
||
2877 | /* no need to parse the include because the 'ifndef macro' |
||
2878 | is defined */ |
||
2879 | #ifdef INC_DEBUG |
||
2880 | printf("%s: skipping %s\n", file->filename, buf); |
||
2881 | #endif |
||
2882 | } else { |
||
2883 | if (c == '\"') { |
||
2884 | /* first search in current dir if "header.h" */ |
||
2885 | size = 0; |
||
2886 | p = strrchr(file->filename, '/'); |
||
2887 | if (p) |
||
2888 | size = p + 1 - file->filename; |
||
2889 | if (size > sizeof(buf1) - 1) |
||
2890 | size = sizeof(buf1) - 1; |
||
2891 | memcpy(buf1, file->filename, size); |
||
2892 | buf1[size] = '\0'; |
||
2893 | pstrcat(buf1, sizeof(buf1), buf); |
||
2894 | f = tcc_open(s1, buf1); |
||
2895 | if (f) { |
||
2896 | if (tok == TOK_INCLUDE_NEXT) |
||
2897 | tok = TOK_INCLUDE; |
||
2898 | else |
||
2899 | goto found; |
||
2900 | } |
||
2901 | } |
||
2902 | if (s1->include_stack_ptr >= s1->include_stack + INCLUDE_STACK_SIZE) |
||
2903 | error("#include recursion too deep"); |
||
2904 | /* now search in all the include paths */ |
||
2905 | n = s1->nb_include_paths + s1->nb_sysinclude_paths; |
||
2906 | for(i = 0; i < n; i++) { |
||
2907 | const char *path; |
||
2908 | if (i < s1->nb_include_paths) |
||
2909 | path = s1->include_paths[i]; |
||
2910 | else |
||
2911 | path = s1->sysinclude_paths[i - s1->nb_include_paths]; |
||
2912 | pstrcpy(buf1, sizeof(buf1), path); |
||
2913 | pstrcat(buf1, sizeof(buf1), "/"); |
||
2914 | pstrcat(buf1, sizeof(buf1), buf); |
||
2915 | f = tcc_open(s1, buf1); |
||
2916 | if (f) { |
||
2917 | if (tok == TOK_INCLUDE_NEXT) |
||
2918 | tok = TOK_INCLUDE; |
||
2919 | else |
||
2920 | goto found; |
||
2921 | } |
||
2922 | } |
||
2923 | error("include file '%s' not found", buf); |
||
2924 | f = NULL; |
||
2925 | found: |
||
2926 | #ifdef INC_DEBUG |
||
2927 | printf("%s: including %s\n", file->filename, buf1); |
||
2928 | #endif |
||
2929 | f->inc_type = c; |
||
2930 | pstrcpy(f->inc_filename, sizeof(f->inc_filename), buf); |
||
2931 | /* push current file in stack */ |
||
2932 | /* XXX: fix current line init */ |
||
2933 | *s1->include_stack_ptr++ = file; |
||
2934 | file = f; |
||
2935 | /* add include file debug info */ |
||
2936 | if (do_debug) { |
||
2937 | put_stabs(file->filename, N_BINCL, 0, 0, 0); |
||
2938 | } |
||
2939 | tok_flags |= TOK_FLAG_BOF | TOK_FLAG_BOL; |
||
2940 | ch = file->buf_ptr[0]; |
||
2941 | goto the_end; |
||
2942 | } |
||
2943 | break; |
||
2944 | case TOK_IFNDEF: |
||
2945 | c = 1; |
||
2946 | goto do_ifdef; |
||
2947 | case TOK_IF: |
||
2948 | c = expr_preprocess(); |
||
2949 | goto do_if; |
||
2950 | case TOK_IFDEF: |
||
2951 | c = 0; |
||
2952 | do_ifdef: |
||
2953 | next_nomacro(); |
||
2954 | if (tok < TOK_IDENT) |
||
2955 | error("invalid argument for '#if%sdef'", c ? "n" : ""); |
||
2956 | if (is_bof) { |
||
2957 | if (c) { |
||
2958 | #ifdef INC_DEBUG |
||
2959 | printf("#ifndef %s\n", get_tok_str(tok, NULL)); |
||
2960 | #endif |
||
2961 | file->ifndef_macro = tok; |
||
2962 | } |
||
2963 | } |
||
2964 | c = (define_find(tok) != 0) ^ c; |
||
2965 | do_if: |
||
2966 | if (s1->ifdef_stack_ptr >= s1->ifdef_stack + IFDEF_STACK_SIZE) |
||
2967 | error("memory full"); |
||
2968 | *s1->ifdef_stack_ptr++ = c; |
||
2969 | goto test_skip; |
||
2970 | case TOK_ELSE: |
||
2971 | if (s1->ifdef_stack_ptr == s1->ifdef_stack) |
||
2972 | error("#else without matching #if"); |
||
2973 | if (s1->ifdef_stack_ptr[-1] & 2) |
||
2974 | error("#else after #else"); |
||
2975 | c = (s1->ifdef_stack_ptr[-1] ^= 3); |
||
2976 | goto test_skip; |
||
2977 | case TOK_ELIF: |
||
2978 | if (s1->ifdef_stack_ptr == s1->ifdef_stack) |
||
2979 | error("#elif without matching #if"); |
||
2980 | c = s1->ifdef_stack_ptr[-1]; |
||
2981 | if (c > 1) |
||
2982 | error("#elif after #else"); |
||
2983 | /* last #if/#elif expression was true: we skip */ |
||
2984 | if (c == 1) |
||
2985 | goto skip; |
||
2986 | c = expr_preprocess(); |
||
2987 | s1->ifdef_stack_ptr[-1] = c; |
||
2988 | test_skip: |
||
2989 | if (!(c & 1)) { |
||
2990 | skip: |
||
2991 | preprocess_skip(); |
||
2992 | is_bof = 0; |
||
2993 | goto redo; |
||
2994 | } |
||
2995 | break; |
||
2996 | case TOK_ENDIF: |
||
2997 | if (s1->ifdef_stack_ptr <= file->ifdef_stack_ptr) |
||
2998 | error("#endif without matching #if"); |
||
2999 | s1->ifdef_stack_ptr--; |
||
3000 | /* '#ifndef macro' was at the start of file. Now we check if |
||
3001 | an '#endif' is exactly at the end of file */ |
||
3002 | if (file->ifndef_macro && |
||
3003 | s1->ifdef_stack_ptr == file->ifdef_stack_ptr) { |
||
3004 | file->ifndef_macro_saved = file->ifndef_macro; |
||
3005 | /* need to set to zero to avoid false matches if another |
||
3006 | #ifndef at middle of file */ |
||
3007 | file->ifndef_macro = 0; |
||
3008 | while (tok != TOK_LINEFEED) |
||
3009 | next_nomacro(); |
||
3010 | tok_flags |= TOK_FLAG_ENDIF; |
||
3011 | goto the_end; |
||
3012 | } |
||
3013 | break; |
||
3014 | case TOK_LINE: |
||
3015 | next(); |
||
3016 | if (tok != TOK_CINT) |
||
3017 | error("#line"); |
||
3018 | file->line_num = tokc.i - 1; /* the line number will be incremented after */ |
||
3019 | next(); |
||
3020 | if (tok != TOK_LINEFEED) { |
||
3021 | if (tok != TOK_STR) |
||
3022 | error("#line"); |
||
3023 | pstrcpy(file->filename, sizeof(file->filename), |
||
3024 | (char *)tokc.cstr->data); |
||
3025 | } |
||
3026 | break; |
||
3027 | case TOK_ERROR: |
||
3028 | case TOK_WARNING: |
||
3029 | c = tok; |
||
3030 | ch = file->buf_ptr[0]; |
||
3031 | skip_spaces(); |
||
3032 | q = buf; |
||
3033 | while (ch != '\n' && ch != CH_EOF) { |
||
3034 | if ((q - buf) < sizeof(buf) - 1) |
||
3035 | *q++ = ch; |
||
3036 | minp(); |
||
3037 | } |
||
3038 | *q = '\0'; |
||
3039 | if (c == TOK_ERROR) |
||
3040 | error("#error %s", buf); |
||
3041 | else |
||
3042 | warning("#warning %s", buf); |
||
3043 | break; |
||
3044 | case TOK_PRAGMA: |
||
3045 | pragma_parse(s1); |
||
3046 | break; |
||
3047 | default: |
||
3048 | if (tok == TOK_LINEFEED || tok == '!' || tok == TOK_CINT) { |
||
3049 | /* '!' is ignored to allow C scripts. numbers are ignored |
||
3050 | to emulate cpp behaviour */ |
||
3051 | } else { |
||
3052 | if (!(saved_parse_flags & PARSE_FLAG_ASM_COMMENTS)) |
||
3053 | error("invalid preprocessing directive #%s", get_tok_str(tok, &tokc)); |
||
3054 | } |
||
3055 | break; |
||
3056 | } |
||
3057 | /* ignore other preprocess commands or #! for C scripts */ |
||
3058 | while (tok != TOK_LINEFEED) |
||
3059 | next_nomacro(); |
||
3060 | the_end: |
||
3061 | parse_flags = saved_parse_flags; |
||
3062 | } |
||
3063 | |||
3064 | /* evaluate escape codes in a string. */ |
||
3065 | static void parse_escape_string(CString *outstr, const uint8_t *buf, int is_long) |
||
3066 | { |
||
3067 | int c, n; |
||
3068 | const uint8_t *p; |
||
3069 | |||
3070 | p = buf; |
||
3071 | for(;;) { |
||
3072 | c = *p; |
||
3073 | if (c == '\0') |
||
3074 | break; |
||
3075 | if (c == '\\') { |
||
3076 | p++; |
||
3077 | /* escape */ |
||
3078 | c = *p; |
||
3079 | switch(c) { |
||
3080 | case '0': case '1': case '2': case '3': |
||
3081 | case '4': case '5': case '6': case '7': |
||
3082 | /* at most three octal digits */ |
||
3083 | n = c - '0'; |
||
3084 | p++; |
||
3085 | c = *p; |
||
3086 | if (isoct(c)) { |
||
3087 | n = n * 8 + c - '0'; |
||
3088 | p++; |
||
3089 | c = *p; |
||
3090 | if (isoct(c)) { |
||
3091 | n = n * 8 + c - '0'; |
||
3092 | p++; |
||
3093 | } |
||
3094 | } |
||
3095 | c = n; |
||
3096 | goto add_char_nonext; |
||
3097 | case 'x': |
||
3098 | p++; |
||
3099 | n = 0; |
||
3100 | for(;;) { |
||
3101 | c = *p; |
||
3102 | if (c >= 'a' && c <= 'f') |
||
3103 | c = c - 'a' + 10; |
||
3104 | else if (c >= 'A' && c <= 'F') |
||
3105 | c = c - 'A' + 10; |
||
3106 | else if (isnum(c)) |
||
3107 | c = c - '0'; |
||
3108 | else |
||
3109 | break; |
||
3110 | n = n * 16 + c; |
||
3111 | p++; |
||
3112 | } |
||
3113 | c = n; |
||
3114 | goto add_char_nonext; |
||
3115 | case 'a': |
||
3116 | c = '\a'; |
||
3117 | break; |
||
3118 | case 'b': |
||
3119 | c = '\b'; |
||
3120 | break; |
||
3121 | case 'f': |
||
3122 | c = '\f'; |
||
3123 | break; |
||
3124 | case 'n': |
||
3125 | c = '\n'; |
||
3126 | break; |
||
3127 | case 'r': |
||
3128 | c = '\r'; |
||
3129 | break; |
||
3130 | case 't': |
||
3131 | c = '\t'; |
||
3132 | break; |
||
3133 | case 'v': |
||
3134 | c = '\v'; |
||
3135 | break; |
||
3136 | case 'e': |
||
3137 | if (!gnu_ext) |
||
3138 | goto invalid_escape; |
||
3139 | c = 27; |
||
3140 | break; |
||
3141 | case '\'': |
||
3142 | case '\"': |
||
3143 | case '\\': |
||
3144 | case '?': |
||
3145 | break; |
||
3146 | default: |
||
3147 | invalid_escape: |
||
3148 | if (c >= '!' && c <= '~') |
||
3149 | warning("unknown escape sequence: \'\\%c\'", c); |
||
3150 | else |
||
3151 | warning("unknown escape sequence: \'\\x%x\'", c); |
||
3152 | break; |
||
3153 | } |
||
3154 | } |
||
3155 | p++; |
||
3156 | add_char_nonext: |
||
3157 | if (!is_long) |
||
3158 | cstr_ccat(outstr, c); |
||
3159 | else |
||
3160 | cstr_wccat(outstr, c); |
||
3161 | } |
||
3162 | /* add a trailing '\0' */ |
||
3163 | if (!is_long) |
||
3164 | cstr_ccat(outstr, '\0'); |
||
3165 | else |
||
3166 | cstr_wccat(outstr, '\0'); |
||
3167 | } |
||
3168 | |||
3169 | /* we use 64 bit numbers */ |
||
3170 | #define BN_SIZE 2 |
||
3171 | |||
3172 | /* bn = (bn << shift) | or_val */ |
||
3173 | void bn_lshift(unsigned int *bn, int shift, int or_val) |
||
3174 | { |
||
3175 | int i; |
||
3176 | unsigned int v; |
||
3177 | for(i=0;i |
||
3178 | v = bn[i]; |
||
3179 | bn[i] = (v << shift) | or_val; |
||
3180 | or_val = v >> (32 - shift); |
||
3181 | } |
||
3182 | } |
||
3183 | |||
3184 | void bn_zero(unsigned int *bn) |
||
3185 | { |
||
3186 | int i; |
||
3187 | for(i=0;i |
||
3188 | bn[i] = 0; |
||
3189 | } |
||
3190 | } |
||
3191 | |||
3192 | /* parse number in null terminated string 'p' and return it in the |
||
3193 | current token */ |
||
3194 | void parse_number(const char *p) |
||
3195 | { |
||
3196 | int b, t, shift, frac_bits, s, exp_val, ch; |
||
3197 | char *q; |
||
3198 | unsigned int bn[BN_SIZE]; |
||
3199 | double d; |
||
3200 | |||
3201 | /* number */ |
||
3202 | q = token_buf; |
||
3203 | ch = *p++; |
||
3204 | t = ch; |
||
3205 | ch = *p++; |
||
3206 | *q++ = t; |
||
3207 | b = 10; |
||
3208 | if (t == '.') { |
||
3209 | goto float_frac_parse; |
||
3210 | } else if (t == '0') { |
||
3211 | if (ch == 'x' || ch == 'X') { |
||
3212 | q--; |
||
3213 | ch = *p++; |
||
3214 | b = 16; |
||
3215 | } else if (tcc_ext && (ch == 'b' || ch == 'B')) { |
||
3216 | q--; |
||
3217 | ch = *p++; |
||
3218 | b = 2; |
||
3219 | } |
||
3220 | } |
||
3221 | /* parse all digits. cannot check octal numbers at this stage |
||
3222 | because of floating point constants */ |
||
3223 | while (1) { |
||
3224 | if (ch >= 'a' && ch <= 'f') |
||
3225 | t = ch - 'a' + 10; |
||
3226 | else if (ch >= 'A' && ch <= 'F') |
||
3227 | t = ch - 'A' + 10; |
||
3228 | else if (isnum(ch)) |
||
3229 | t = ch - '0'; |
||
3230 | else |
||
3231 | break; |
||
3232 | if (t >= b) |
||
3233 | break; |
||
3234 | if (q >= token_buf + STRING_MAX_SIZE) { |
||
3235 | num_too_long: |
||
3236 | error("number too long"); |
||
3237 | } |
||
3238 | *q++ = ch; |
||
3239 | ch = *p++; |
||
3240 | } |
||
3241 | if (ch == '.' || |
||
3242 | ((ch == 'e' || ch == 'E') && b == 10) || |
||
3243 | ((ch == 'p' || ch == 'P') && (b == 16 || b == 2))) { |
||
3244 | if (b != 10) { |
||
3245 | /* NOTE: strtox should support that for hexa numbers, but |
||
3246 | non ISOC99 libcs do not support it, so we prefer to do |
||
3247 | it by hand */ |
||
3248 | /* hexadecimal or binary floats */ |
||
3249 | /* XXX: handle overflows */ |
||
3250 | *q = '\0'; |
||
3251 | if (b == 16) |
||
3252 | shift = 4; |
||
3253 | else |
||
3254 | shift = 2; |
||
3255 | bn_zero(bn); |
||
3256 | q = token_buf; |
||
3257 | while (1) { |
||
3258 | t = *q++; |
||
3259 | if (t == '\0') { |
||
3260 | break; |
||
3261 | } else if (t >= 'a') { |
||
3262 | t = t - 'a' + 10; |
||
3263 | } else if (t >= 'A') { |
||
3264 | t = t - 'A' + 10; |
||
3265 | } else { |
||
3266 | t = t - '0'; |
||
3267 | } |
||
3268 | bn_lshift(bn, shift, t); |
||
3269 | } |
||
3270 | frac_bits = 0; |
||
3271 | if (ch == '.') { |
||
3272 | ch = *p++; |
||
3273 | while (1) { |
||
3274 | t = ch; |
||
3275 | if (t >= 'a' && t <= 'f') { |
||
3276 | t = t - 'a' + 10; |
||
3277 | } else if (t >= 'A' && t <= 'F') { |
||
3278 | t = t - 'A' + 10; |
||
3279 | } else if (t >= '0' && t <= '9') { |
||
3280 | t = t - '0'; |
||
3281 | } else { |
||
3282 | break; |
||
3283 | } |
||
3284 | if (t >= b) |
||
3285 | error("invalid digit"); |
||
3286 | bn_lshift(bn, shift, t); |
||
3287 | frac_bits += shift; |
||
3288 | ch = *p++; |
||
3289 | } |
||
3290 | } |
||
3291 | if (ch != 'p' && ch != 'P') |
||
3292 | expect("exponent"); |
||
3293 | ch = *p++; |
||
3294 | s = 1; |
||
3295 | exp_val = 0; |
||
3296 | if (ch == '+') { |
||
3297 | ch = *p++; |
||
3298 | } else if (ch == '-') { |
||
3299 | s = -1; |
||
3300 | ch = *p++; |
||
3301 | } |
||
3302 | if (ch < '0' || ch > '9') |
||
3303 | expect("exponent digits"); |
||
3304 | while (ch >= '0' && ch <= '9') { |
||
3305 | exp_val = exp_val * 10 + ch - '0'; |
||
3306 | ch = *p++; |
||
3307 | } |
||
3308 | exp_val = exp_val * s; |
||
3309 | |||
3310 | /* now we can generate the number */ |
||
3311 | /* XXX: should patch directly float number */ |
||
3312 | d = (double)bn[1] * 4294967296.0 + (double)bn[0]; |
||
3313 | d = ldexp(d, exp_val - frac_bits); |
||
3314 | t = toup(ch); |
||
3315 | if (t == 'F') { |
||
3316 | ch = *p++; |
||
3317 | tok = TOK_CFLOAT; |
||
3318 | /* float : should handle overflow */ |
||
3319 | tokc.f = (float)d; |
||
3320 | } else if (t == 'L') { |
||
3321 | ch = *p++; |
||
3322 | tok = TOK_CLDOUBLE; |
||
3323 | /* XXX: not large enough */ |
||
3324 | tokc.ld = (long double)d; |
||
3325 | } else { |
||
3326 | tok = TOK_CDOUBLE; |
||
3327 | tokc.d = d; |
||
3328 | } |
||
3329 | } else { |
||
3330 | /* decimal floats */ |
||
3331 | if (ch == '.') { |
||
3332 | if (q >= token_buf + STRING_MAX_SIZE) |
||
3333 | goto num_too_long; |
||
3334 | *q++ = ch; |
||
3335 | ch = *p++; |
||
3336 | float_frac_parse: |
||
3337 | while (ch >= '0' && ch <= '9') { |
||
3338 | if (q >= token_buf + STRING_MAX_SIZE) |
||
3339 | goto num_too_long; |
||
3340 | *q++ = ch; |
||
3341 | ch = *p++; |
||
3342 | } |
||
3343 | } |
||
3344 | if (ch == 'e' || ch == 'E') { |
||
3345 | if (q >= token_buf + STRING_MAX_SIZE) |
||
3346 | goto num_too_long; |
||
3347 | *q++ = ch; |
||
3348 | ch = *p++; |
||
3349 | if (ch == '-' || ch == '+') { |
||
3350 | if (q >= token_buf + STRING_MAX_SIZE) |
||
3351 | goto num_too_long; |
||
3352 | *q++ = ch; |
||
3353 | ch = *p++; |
||
3354 | } |
||
3355 | if (ch < '0' || ch > '9') |
||
3356 | expect("exponent digits"); |
||
3357 | while (ch >= '0' && ch <= '9') { |
||
3358 | if (q >= token_buf + STRING_MAX_SIZE) |
||
3359 | goto num_too_long; |
||
3360 | *q++ = ch; |
||
3361 | ch = *p++; |
||
3362 | } |
||
3363 | } |
||
3364 | *q = '\0'; |
||
3365 | t = toup(ch); |
||
3366 | errno = 0; |
||
3367 | if (t == 'F') { |
||
3368 | ch = *p++; |
||
3369 | tok = TOK_CFLOAT; |
||
3370 | tokc.f = strtof(token_buf, NULL); |
||
3371 | } else if (t == 'L') { |
||
3372 | ch = *p++; |
||
3373 | tok = TOK_CLDOUBLE; |
||
3374 | tokc.ld = strtold(token_buf, NULL); |
||
3375 | } else { |
||
3376 | tok = TOK_CDOUBLE; |
||
3377 | tokc.d = strtod(token_buf, NULL); |
||
3378 | } |
||
3379 | } |
||
3380 | } else { |
||
3381 | unsigned long long n, n1; |
||
3382 | int lcount, ucount; |
||
3383 | |||
3384 | /* integer number */ |
||
3385 | *q = '\0'; |
||
3386 | q = token_buf; |
||
3387 | if (b == 10 && *q == '0') { |
||
3388 | b = 8; |
||
3389 | q++; |
||
3390 | } |
||
3391 | n = 0; |
||
3392 | while(1) { |
||
3393 | t = *q++; |
||
3394 | /* no need for checks except for base 10 / 8 errors */ |
||
3395 | if (t == '\0') { |
||
3396 | break; |
||
3397 | } else if (t >= 'a') { |
||
3398 | t = t - 'a' + 10; |
||
3399 | } else if (t >= 'A') { |
||
3400 | t = t - 'A' + 10; |
||
3401 | } else { |
||
3402 | t = t - '0'; |
||
3403 | if (t >= b) |
||
3404 | error("invalid digit"); |
||
3405 | } |
||
3406 | n1 = n; |
||
3407 | n = n * b + t; |
||
3408 | /* detect overflow */ |
||
3409 | /* XXX: this test is not reliable */ |
||
3410 | if (n < n1) |
||
3411 | error("integer constant overflow"); |
||
3412 | } |
||
3413 | |||
3414 | /* XXX: not exactly ANSI compliant */ |
||
3415 | if ((n & 0xffffffff00000000LL) != 0) { |
||
3416 | if ((n >> 63) != 0) |
||
3417 | tok = TOK_CULLONG; |
||
3418 | else |
||
3419 | tok = TOK_CLLONG; |
||
3420 | } else if (n > 0x7fffffff) { |
||
3421 | tok = TOK_CUINT; |
||
3422 | } else { |
||
3423 | tok = TOK_CINT; |
||
3424 | } |
||
3425 | lcount = 0; |
||
3426 | ucount = 0; |
||
3427 | for(;;) { |
||
3428 | t = toup(ch); |
||
3429 | if (t == 'L') { |
||
3430 | if (lcount >= 2) |
||
3431 | error("three 'l's in integer constant"); |
||
3432 | lcount++; |
||
3433 | if (lcount == 2) { |
||
3434 | if (tok == TOK_CINT) |
||
3435 | tok = TOK_CLLONG; |
||
3436 | else if (tok == TOK_CUINT) |
||
3437 | tok = TOK_CULLONG; |
||
3438 | } |
||
3439 | ch = *p++; |
||
3440 | } else if (t == 'U') { |
||
3441 | if (ucount >= 1) |
||
3442 | error("two 'u's in integer constant"); |
||
3443 | ucount++; |
||
3444 | if (tok == TOK_CINT) |
||
3445 | tok = TOK_CUINT; |
||
3446 | else if (tok == TOK_CLLONG) |
||
3447 | tok = TOK_CULLONG; |
||
3448 | ch = *p++; |
||
3449 | } else { |
||
3450 | break; |
||
3451 | } |
||
3452 | } |
||
3453 | if (tok == TOK_CINT || tok == TOK_CUINT) |
||
3454 | tokc.ui = n; |
||
3455 | else |
||
3456 | tokc.ull = n; |
||
3457 | } |
||
3458 | } |
||
3459 | |||
3460 | |||
3461 | #define PARSE2(c1, tok1, c2, tok2) \ |
||
3462 | case c1: \ |
||
3463 | PEEKC(c, p); \ |
||
3464 | if (c == c2) { \ |
||
3465 | p++; \ |
||
3466 | tok = tok2; \ |
||
3467 | } else { \ |
||
3468 | tok = tok1; \ |
||
3469 | } \ |
||
3470 | break; |
||
3471 | |||
3472 | /* return next token without macro substitution */ |
||
3473 | static inline void next_nomacro1(void) |
||
3474 | { |
||
3475 | int t, c, is_long; |
||
3476 | TokenSym *ts; |
||
3477 | uint8_t *p, *p1; |
||
3478 | unsigned int h; |
||
3479 | |||
3480 | p = file->buf_ptr; |
||
3481 | redo_no_start: |
||
3482 | c = *p; |
||
3483 | switch(c) { |
||
3484 | case ' ': |
||
3485 | case '\t': |
||
3486 | case '\f': |
||
3487 | case '\v': |
||
3488 | case '\r': |
||
3489 | p++; |
||
3490 | goto redo_no_start; |
||
3491 | |||
3492 | case '\\': |
||
3493 | /* first look if it is in fact an end of buffer */ |
||
3494 | if (p >= file->buf_end) { |
||
3495 | file->buf_ptr = p; |
||
3496 | handle_eob(); |
||
3497 | p = file->buf_ptr; |
||
3498 | if (p >= file->buf_end) |
||
3499 | goto parse_eof; |
||
3500 | else |
||
3501 | goto redo_no_start; |
||
3502 | } else { |
||
3503 | file->buf_ptr = p; |
||
3504 | ch = *p; |
||
3505 | handle_stray(); |
||
3506 | p = file->buf_ptr; |
||
3507 | goto redo_no_start; |
||
3508 | } |
||
3509 | parse_eof: |
||
3510 | { |
||
3511 | TCCState *s1 = tcc_state; |
||
3512 | if (parse_flags & PARSE_FLAG_LINEFEED) { |
||
3513 | tok = TOK_LINEFEED; |
||
3514 | } else if (s1->include_stack_ptr == s1->include_stack || |
||
3515 | !(parse_flags & PARSE_FLAG_PREPROCESS)) { |
||
3516 | /* no include left : end of file. */ |
||
3517 | tok = TOK_EOF; |
||
3518 | } else { |
||
3519 | /* pop include file */ |
||
3520 | |||
3521 | /* test if previous '#endif' was after a #ifdef at |
||
3522 | start of file */ |
||
3523 | if (tok_flags & TOK_FLAG_ENDIF) { |
||
3524 | #ifdef INC_DEBUG |
||
3525 | printf("#endif %s\n", get_tok_str(file->ifndef_macro_saved, NULL)); |
||
3526 | #endif |
||
3527 | add_cached_include(s1, file->inc_type, file->inc_filename, |
||
3528 | file->ifndef_macro_saved); |
||
3529 | } |
||
3530 | |||
3531 | /* add end of include file debug info */ |
||
3532 | if (do_debug) { |
||
3533 | put_stabd(N_EINCL, 0, 0); |
||
3534 | } |
||
3535 | /* pop include stack */ |
||
3536 | tcc_close(file); |
||
3537 | s1->include_stack_ptr--; |
||
3538 | file = *s1->include_stack_ptr; |
||
3539 | p = file->buf_ptr; |
||
3540 | goto redo_no_start; |
||
3541 | } |
||
3542 | } |
||
3543 | break; |
||
3544 | |||
3545 | case '\n': |
||
3546 | if (parse_flags & PARSE_FLAG_LINEFEED) { |
||
3547 | tok = TOK_LINEFEED; |
||
3548 | } else { |
||
3549 | file->line_num++; |
||
3550 | tok_flags |= TOK_FLAG_BOL; |
||
3551 | p++; |
||
3552 | goto redo_no_start; |
||
3553 | } |
||
3554 | break; |
||
3555 | |||
3556 | case '#': |
||
3557 | /* XXX: simplify */ |
||
3558 | PEEKC(c, p); |
||
3559 | if ((tok_flags & TOK_FLAG_BOL) && |
||
3560 | (parse_flags & PARSE_FLAG_PREPROCESS)) { |
||
3561 | file->buf_ptr = p; |
||
3562 | preprocess(tok_flags & TOK_FLAG_BOF); |
||
3563 | p = file->buf_ptr; |
||
3564 | goto redo_no_start; |
||
3565 | } else { |
||
3566 | if (c == '#') { |
||
3567 | p++; |
||
3568 | tok = TOK_TWOSHARPS; |
||
3569 | } else { |
||
3570 | if (parse_flags & PARSE_FLAG_ASM_COMMENTS) { |
||
3571 | p = parse_line_comment(p - 1); |
||
3572 | goto redo_no_start; |
||
3573 | } else { |
||
3574 | tok = '#'; |
||
3575 | } |
||
3576 | } |
||
3577 | } |
||
3578 | break; |
||
3579 | |||
3580 | case 'a': case 'b': case 'c': case 'd': |
||
3581 | case 'e': case 'f': case 'g': case 'h': |
||
3582 | case 'i': case 'j': case 'k': case 'l': |
||
3583 | case 'm': case 'n': case 'o': case 'p': |
||
3584 | case 'q': case 'r': case 's': case 't': |
||
3585 | case 'u': case 'v': case 'w': case 'x': |
||
3586 | case 'y': case 'z': |
||
3587 | case 'A': case 'B': case 'C': case 'D': |
||
3588 | case 'E': case 'F': case 'G': case 'H': |
||
3589 | case 'I': case 'J': case 'K': |
||
3590 | case 'M': case 'N': case 'O': case 'P': |
||
3591 | case 'Q': case 'R': case 'S': case 'T': |
||
3592 | case 'U': case 'V': case 'W': case 'X': |
||
3593 | case 'Y': case 'Z': |
||
3594 | case '_': |
||
3595 | parse_ident_fast: |
||
3596 | p1 = p; |
||
3597 | h = TOK_HASH_INIT; |
||
3598 | h = TOK_HASH_FUNC(h, c); |
||
3599 | p++; |
||
3600 | for(;;) { |
||
3601 | c = *p; |
||
3602 | if (!isidnum_table[c]) |
||
3603 | break; |
||
3604 | h = TOK_HASH_FUNC(h, c); |
||
3605 | p++; |
||
3606 | } |
||
3607 | if (c != '\\') { |
||
3608 | TokenSym **pts; |
||
3609 | int len; |
||
3610 | |||
3611 | /* fast case : no stray found, so we have the full token |
||
3612 | and we have already hashed it */ |
||
3613 | len = p - p1; |
||
3614 | h &= (TOK_HASH_SIZE - 1); |
||
3615 | pts = &hash_ident[h]; |
||
3616 | for(;;) { |
||
3617 | ts = *pts; |
||
3618 | if (!ts) |
||
3619 | break; |
||
3620 | if (ts->len == len && !memcmp(ts->str, p1, len)) |
||
3621 | goto token_found; |
||
3622 | pts = &(ts->hash_next); |
||
3623 | } |
||
3624 | ts = tok_alloc_new(pts, p1, len); |
||
3625 | token_found: ; |
||
3626 | } else { |
||
3627 | /* slower case */ |
||
3628 | cstr_reset(&tokcstr); |
||
3629 | |||
3630 | while (p1 < p) { |
||
3631 | cstr_ccat(&tokcstr, *p1); |
||
3632 | p1++; |
||
3633 | } |
||
3634 | p--; |
||
3635 | PEEKC(c, p); |
||
3636 | parse_ident_slow: |
||
3637 | while (isidnum_table[c]) { |
||
3638 | cstr_ccat(&tokcstr, c); |
||
3639 | PEEKC(c, p); |
||
3640 | } |
||
3641 | ts = tok_alloc(tokcstr.data, tokcstr.size); |
||
3642 | } |
||
3643 | tok = ts->tok; |
||
3644 | break; |
||
3645 | case 'L': |
||
3646 | t = p[1]; |
||
3647 | if (t != '\\' && t != '\'' && t != '\"') { |
||
3648 | /* fast case */ |
||
3649 | goto parse_ident_fast; |
||
3650 | } else { |
||
3651 | PEEKC(c, p); |
||
3652 | if (c == '\'' || c == '\"') { |
||
3653 | is_long = 1; |
||
3654 | goto str_const; |
||
3655 | } else { |
||
3656 | cstr_reset(&tokcstr); |
||
3657 | cstr_ccat(&tokcstr, 'L'); |
||
3658 | goto parse_ident_slow; |
||
3659 | } |
||
3660 | } |
||
3661 | break; |
||
3662 | case '0': case '1': case '2': case '3': |
||
3663 | case '4': case '5': case '6': case '7': |
||
3664 | case '8': case '9': |
||
3665 | |||
3666 | cstr_reset(&tokcstr); |
||
3667 | /* after the first digit, accept digits, alpha, '.' or sign if |
||
3668 | prefixed by 'eEpP' */ |
||
3669 | parse_num: |
||
3670 | for(;;) { |
||
3671 | t = c; |
||
3672 | cstr_ccat(&tokcstr, c); |
||
3673 | PEEKC(c, p); |
||
3674 | if (!(isnum(c) || isid(c) || c == '.' || |
||
3675 | ((c == '+' || c == '-') && |
||
3676 | (t == 'e' || t == 'E' || t == 'p' || t == 'P')))) |
||
3677 | break; |
||
3678 | } |
||
3679 | /* We add a trailing '\0' to ease parsing */ |
||
3680 | cstr_ccat(&tokcstr, '\0'); |
||
3681 | tokc.cstr = &tokcstr; |
||
3682 | tok = TOK_PPNUM; |
||
3683 | break; |
||
3684 | case '.': |
||
3685 | /* special dot handling because it can also start a number */ |
||
3686 | PEEKC(c, p); |
||
3687 | if (isnum(c)) { |
||
3688 | cstr_reset(&tokcstr); |
||
3689 | cstr_ccat(&tokcstr, '.'); |
||
3690 | goto parse_num; |
||
3691 | } else if (c == '.') { |
||
3692 | PEEKC(c, p); |
||
3693 | if (c != '.') |
||
3694 | expect("'.'"); |
||
3695 | PEEKC(c, p); |
||
3696 | tok = TOK_DOTS; |
||
3697 | } else { |
||
3698 | tok = '.'; |
||
3699 | } |
||
3700 | break; |
||
3701 | case '\'': |
||
3702 | case '\"': |
||
3703 | is_long = 0; |
||
3704 | str_const: |
||
3705 | { |
||
3706 | CString str; |
||
3707 | int sep; |
||
3708 | |||
3709 | sep = c; |
||
3710 | |||
3711 | /* parse the string */ |
||
3712 | cstr_new(&str); |
||
3713 | p = parse_pp_string(p, sep, &str); |
||
3714 | cstr_ccat(&str, '\0'); |
||
3715 | |||
3716 | /* eval the escape (should be done as TOK_PPNUM) */ |
||
3717 | cstr_reset(&tokcstr); |
||
3718 | parse_escape_string(&tokcstr, str.data, is_long); |
||
3719 | cstr_free(&str); |
||
3720 | |||
3721 | if (sep == '\'') { |
||
3722 | int char_size; |
||
3723 | /* XXX: make it portable */ |
||
3724 | if (!is_long) |
||
3725 | char_size = 1; |
||
3726 | else |
||
3727 | char_size = sizeof(int); |
||
3728 | if (tokcstr.size <= char_size) |
||
3729 | error("empty character constant"); |
||
3730 | if (tokcstr.size > 2 * char_size) |
||
3731 | warning("multi-character character constant"); |
||
3732 | if (!is_long) { |
||
3733 | tokc.i = *(int8_t *)tokcstr.data; |
||
3734 | tok = TOK_CCHAR; |
||
3735 | } else { |
||
3736 | tokc.i = *(int *)tokcstr.data; |
||
3737 | tok = TOK_LCHAR; |
||
3738 | } |
||
3739 | } else { |
||
3740 | tokc.cstr = &tokcstr; |
||
3741 | if (!is_long) |
||
3742 | tok = TOK_STR; |
||
3743 | else |
||
3744 | tok = TOK_LSTR; |
||
3745 | } |
||
3746 | } |
||
3747 | break; |
||
3748 | |||
3749 | case '<': |
||
3750 | PEEKC(c, p); |
||
3751 | if (c == '=') { |
||
3752 | p++; |
||
3753 | tok = TOK_LE; |
||
3754 | } else if (c == '<') { |
||
3755 | PEEKC(c, p); |
||
3756 | if (c == '=') { |
||
3757 | p++; |
||
3758 | tok = TOK_A_SHL; |
||
3759 | } else { |
||
3760 | tok = TOK_SHL; |
||
3761 | } |
||
3762 | } else { |
||
3763 | tok = TOK_LT; |
||
3764 | } |
||
3765 | break; |
||
3766 | |||
3767 | case '>': |
||
3768 | PEEKC(c, p); |
||
3769 | if (c == '=') { |
||
3770 | p++; |
||
3771 | tok = TOK_GE; |
||
3772 | } else if (c == '>') { |
||
3773 | PEEKC(c, p); |
||
3774 | if (c == '=') { |
||
3775 | p++; |
||
3776 | tok = TOK_A_SAR; |
||
3777 | } else { |
||
3778 | tok = TOK_SAR; |
||
3779 | } |
||
3780 | } else { |
||
3781 | tok = TOK_GT; |
||
3782 | } |
||
3783 | break; |
||
3784 | |||
3785 | case '&': |
||
3786 | PEEKC(c, p); |
||
3787 | if (c == '&') { |
||
3788 | p++; |
||
3789 | tok = TOK_LAND; |
||
3790 | } else if (c == '=') { |
||
3791 | p++; |
||
3792 | tok = TOK_A_AND; |
||
3793 | } else { |
||
3794 | tok = '&'; |
||
3795 | } |
||
3796 | break; |
||
3797 | |||
3798 | case '|': |
||
3799 | PEEKC(c, p); |
||
3800 | if (c == '|') { |
||
3801 | p++; |
||
3802 | tok = TOK_LOR; |
||
3803 | } else if (c == '=') { |
||
3804 | p++; |
||
3805 | tok = TOK_A_OR; |
||
3806 | } else { |
||
3807 | tok = '|'; |
||
3808 | } |
||
3809 | break; |
||
3810 | |||
3811 | case '+': |
||
3812 | PEEKC(c, p); |
||
3813 | if (c == '+') { |
||
3814 | p++; |
||
3815 | tok = TOK_INC; |
||
3816 | } else if (c == '=') { |
||
3817 | p++; |
||
3818 | tok = TOK_A_ADD; |
||
3819 | } else { |
||
3820 | tok = '+'; |
||
3821 | } |
||
3822 | break; |
||
3823 | |||
3824 | case '-': |
||
3825 | PEEKC(c, p); |
||
3826 | if (c == '-') { |
||
3827 | p++; |
||
3828 | tok = TOK_DEC; |
||
3829 | } else if (c == '=') { |
||
3830 | p++; |
||
3831 | tok = TOK_A_SUB; |
||
3832 | } else if (c == '>') { |
||
3833 | p++; |
||
3834 | tok = TOK_ARROW; |
||
3835 | } else { |
||
3836 | tok = '-'; |
||
3837 | } |
||
3838 | break; |
||
3839 | |||
3840 | PARSE2('!', '!', '=', TOK_NE) |
||
3841 | PARSE2('=', '=', '=', TOK_EQ) |
||
3842 | PARSE2('*', '*', '=', TOK_A_MUL) |
||
3843 | PARSE2('%', '%', '=', TOK_A_MOD) |
||
3844 | PARSE2('^', '^', '=', TOK_A_XOR) |
||
3845 | |||
3846 | /* comments or operator */ |
||
3847 | case '/': |
||
3848 | PEEKC(c, p); |
||
3849 | if (c == '*') { |
||
3850 | p = parse_comment(p); |
||
3851 | goto redo_no_start; |
||
3852 | } else if (c == '/') { |
||
3853 | p = parse_line_comment(p); |
||
3854 | goto redo_no_start; |
||
3855 | } else if (c == '=') { |
||
3856 | p++; |
||
3857 | tok = TOK_A_DIV; |
||
3858 | } else { |
||
3859 | tok = '/'; |
||
3860 | } |
||
3861 | break; |
||
3862 | |||
3863 | /* simple tokens */ |
||
3864 | case '(': |
||
3865 | case ')': |
||
3866 | case '[': |
||
3867 | case ']': |
||
3868 | case '{': |
||
3869 | case '}': |
||
3870 | case ',': |
||
3871 | case ';': |
||
3872 | case ':': |
||
3873 | case '?': |
||
3874 | case '~': |
||
3875 | case '$': /* only used in assembler */ |
||
3876 | case '@': /* dito */ |
||
3877 | tok = c; |
||
3878 | p++; |
||
3879 | break; |
||
3880 | default: |
||
3881 | error("unrecognized character \\x%02x", c); |
||
3882 | break; |
||
3883 | } |
||
3884 | file->buf_ptr = p; |
||
3885 | tok_flags = 0; |
||
3886 | #if defined(PARSE_DEBUG) |
||
3887 | printf("token = %s\n", get_tok_str(tok, &tokc)); |
||
3888 | #endif |
||
3889 | } |
||
3890 | |||
3891 | /* return next token without macro substitution. Can read input from |
||
3892 | macro_ptr buffer */ |
||
3893 | static void next_nomacro(void) |
||
3894 | { |
||
3895 | if (macro_ptr) { |
||
3896 | redo: |
||
3897 | tok = *macro_ptr; |
||
3898 | if (tok) { |
||
3899 | TOK_GET(tok, macro_ptr, tokc); |
||
3900 | if (tok == TOK_LINENUM) { |
||
3901 | file->line_num = tokc.i; |
||
3902 | goto redo; |
||
3903 | } |
||
3904 | } |
||
3905 | } else { |
||
3906 | next_nomacro1(); |
||
3907 | } |
||
3908 | } |
||
3909 | |||
3910 | /* substitute args in macro_str and return allocated string */ |
||
3911 | static int *macro_arg_subst(Sym **nested_list, int *macro_str, Sym *args) |
||
3912 | { |
||
3913 | int *st, last_tok, t, notfirst; |
||
3914 | Sym *s; |
||
3915 | CValue cval; |
||
3916 | TokenString str; |
||
3917 | CString cstr; |
||
3918 | |||
3919 | tok_str_new(&str); |
||
3920 | last_tok = 0; |
||
3921 | while(1) { |
||
3922 | TOK_GET(t, macro_str, cval); |
||
3923 | if (!t) |
||
3924 | break; |
||
3925 | if (t == '#') { |
||
3926 | /* stringize */ |
||
3927 | TOK_GET(t, macro_str, cval); |
||
3928 | if (!t) |
||
3929 | break; |
||
3930 | s = sym_find2(args, t); |
||
3931 | if (s) { |
||
3932 | cstr_new(&cstr); |
||
3933 | st = (int *)s->c; |
||
3934 | notfirst = 0; |
||
3935 | while (*st) { |
||
3936 | if (notfirst) |
||
3937 | cstr_ccat(&cstr, ' '); |
||
3938 | TOK_GET(t, st, cval); |
||
3939 | cstr_cat(&cstr, get_tok_str(t, &cval)); |
||
3940 | notfirst = 1; |
||
3941 | } |
||
3942 | cstr_ccat(&cstr, '\0'); |
||
3943 | #ifdef PP_DEBUG |
||
3944 | printf("stringize: %s\n", (char *)cstr.data); |
||
3945 | #endif |
||
3946 | /* add string */ |
||
3947 | cval.cstr = &cstr; |
||
3948 | tok_str_add2(&str, TOK_STR, &cval); |
||
3949 | cstr_free(&cstr); |
||
3950 | } else { |
||
3951 | tok_str_add2(&str, t, &cval); |
||
3952 | } |
||
3953 | } else if (t >= TOK_IDENT) { |
||
3954 | s = sym_find2(args, t); |
||
3955 | if (s) { |
||
3956 | st = (int *)s->c; |
||
3957 | /* if '##' is present before or after, no arg substitution */ |
||
3958 | if (*macro_str == TOK_TWOSHARPS || last_tok == TOK_TWOSHARPS) { |
||
3959 | /* special case for var arg macros : ## eats the |
||
3960 | ',' if empty VA_ARGS variable. */ |
||
3961 | /* XXX: test of the ',' is not 100% |
||
3962 | reliable. should fix it to avoid security |
||
3963 | problems */ |
||
3964 | if (gnu_ext && s->type.t && |
||
3965 | last_tok == TOK_TWOSHARPS && |
||
3966 | str.len >= 2 && str.str[str.len - 2] == ',') { |
||
3967 | if (*st == 0) { |
||
3968 | /* suppress ',' '##' */ |
||
3969 | str.len -= 2; |
||
3970 | } else { |
||
3971 | /* suppress '##' and add variable */ |
||
3972 | str.len--; |
||
3973 | goto add_var; |
||
3974 | } |
||
3975 | } else { |
||
3976 | int t1; |
||
3977 | add_var: |
||
3978 | for(;;) { |
||
3979 | TOK_GET(t1, st, cval); |
||
3980 | if (!t1) |
||
3981 | break; |
||
3982 | tok_str_add2(&str, t1, &cval); |
||
3983 | } |
||
3984 | } |
||
3985 | } else { |
||
3986 | /* NOTE: the stream cannot be read when macro |
||
3987 | substituing an argument */ |
||
3988 | macro_subst(&str, nested_list, st, NULL); |
||
3989 | } |
||
3990 | } else { |
||
3991 | tok_str_add(&str, t); |
||
3992 | } |
||
3993 | } else { |
||
3994 | tok_str_add2(&str, t, &cval); |
||
3995 | } |
||
3996 | last_tok = t; |
||
3997 | } |
||
3998 | tok_str_add(&str, 0); |
||
3999 | return str.str; |
||
4000 | } |
||
4001 | |||
4002 | static char const ab_month_name[12][4] = |
||
4003 | { |
||
4004 | "Jan", "Feb", "Mar", "Apr", "May", "Jun", |
||
4005 | "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" |
||
4006 | }; |
||
4007 | |||
4008 | /* do macro substitution of current token with macro 's' and add |
||
4009 | result to (tok_str,tok_len). 'nested_list' is the list of all |
||
4010 | macros we got inside to avoid recursing. Return non zero if no |
||
4011 | substitution needs to be done */ |
||
4012 | static int macro_subst_tok(TokenString *tok_str, |
||
4013 | Sym **nested_list, Sym *s, struct macro_level **can_read_stream) |
||
4014 | { |
||
4015 | Sym *args, *sa, *sa1; |
||
4016 | int mstr_allocated, parlevel, *mstr, t, t1; |
||
4017 | TokenString str; |
||
4018 | char *cstrval; |
||
4019 | CValue cval; |
||
4020 | CString cstr; |
||
4021 | char buf[32]; |
||
4022 | |||
4023 | /* if symbol is a macro, prepare substitution */ |
||
4024 | /* special macros */ |
||
4025 | if (tok == TOK___LINE__) { |
||
4026 | snprintf(buf, sizeof(buf), "%d", file->line_num); |
||
4027 | cstrval = buf; |
||
4028 | t1 = TOK_PPNUM; |
||
4029 | goto add_cstr1; |
||
4030 | } else if (tok == TOK___FILE__) { |
||
4031 | cstrval = file->filename; |
||
4032 | goto add_cstr; |
||
4033 | } else if (tok == TOK___DATE__ || tok == TOK___TIME__) { |
||
4034 | time_t ti; |
||
4035 | struct tm *tm; |
||
4036 | |||
4037 | time(&ti); |
||
4038 | tm = localtime(&ti); |
||
4039 | if (tok == TOK___DATE__) { |
||
4040 | snprintf(buf, sizeof(buf), "%s %2d %d", |
||
4041 | ab_month_name[tm->tm_mon], tm->tm_mday, tm->tm_year + 1900); |
||
4042 | } else { |
||
4043 | snprintf(buf, sizeof(buf), "%02d:%02d:%02d", |
||
4044 | tm->tm_hour, tm->tm_min, tm->tm_sec); |
||
4045 | } |
||
4046 | cstrval = buf; |
||
4047 | add_cstr: |
||
4048 | t1 = TOK_STR; |
||
4049 | add_cstr1: |
||
4050 | cstr_new(&cstr); |
||
4051 | cstr_cat(&cstr, cstrval); |
||
4052 | cstr_ccat(&cstr, '\0'); |
||
4053 | cval.cstr = &cstr; |
||
4054 | tok_str_add2(tok_str, t1, &cval); |
||
4055 | cstr_free(&cstr); |
||
4056 | } else { |
||
4057 | mstr = (int *)s->c; |
||
4058 | mstr_allocated = 0; |
||
4059 | if (s->type.t == MACRO_FUNC) { |
||
4060 | /* NOTE: we do not use next_nomacro to avoid eating the |
||
4061 | next token. XXX: find better solution */ |
||
4062 | redo: |
||
4063 | if (macro_ptr) { |
||
4064 | t = *macro_ptr; |
||
4065 | if (t == 0 && can_read_stream) { |
||
4066 | /* end of macro stream: we must look at the token |
||
4067 | after in the file */ |
||
4068 | struct macro_level *ml = *can_read_stream; |
||
4069 | macro_ptr = NULL; |
||
4070 | if (ml) |
||
4071 | { |
||
4072 | macro_ptr = ml->p; |
||
4073 | ml->p = NULL; |
||
4074 | *can_read_stream = ml -> prev; |
||
4075 | } |
||
4076 | goto redo; |
||
4077 | } |
||
4078 | } else { |
||
4079 | /* XXX: incorrect with comments */ |
||
4080 | ch = file->buf_ptr[0]; |
||
4081 | while (is_space(ch) || ch == '\n') |
||
4082 | cinp(); |
||
4083 | t = ch; |
||
4084 | } |
||
4085 | if (t != '(') /* no macro subst */ |
||
4086 | return -1; |
||
4087 | |||
4088 | /* argument macro */ |
||
4089 | next_nomacro(); |
||
4090 | next_nomacro(); |
||
4091 | args = NULL; |
||
4092 | sa = s->next; |
||
4093 | /* NOTE: empty args are allowed, except if no args */ |
||
4094 | for(;;) { |
||
4095 | /* handle '()' case */ |
||
4096 | if (!args && !sa && tok == ')') |
||
4097 | break; |
||
4098 | if (!sa) |
||
4099 | error("macro '%s' used with too many args", |
||
4100 | get_tok_str(s->v, 0)); |
||
4101 | tok_str_new(&str); |
||
4102 | parlevel = 0; |
||
4103 | /* NOTE: non zero sa->t indicates VA_ARGS */ |
||
4104 | while ((parlevel > 0 || |
||
4105 | (tok != ')' && |
||
4106 | (tok != ',' || sa->type.t))) && |
||
4107 | tok != -1) { |
||
4108 | if (tok == '(') |
||
4109 | parlevel++; |
||
4110 | else if (tok == ')') |
||
4111 | parlevel--; |
||
4112 | tok_str_add2(&str, tok, &tokc); |
||
4113 | next_nomacro(); |
||
4114 | } |
||
4115 | tok_str_add(&str, 0); |
||
4116 | sym_push2(&args, sa->v & ~SYM_FIELD, sa->type.t, (int)str.str); |
||
4117 | sa = sa->next; |
||
4118 | if (tok == ')') { |
||
4119 | /* special case for gcc var args: add an empty |
||
4120 | var arg argument if it is omitted */ |
||
4121 | if (sa && sa->type.t && gnu_ext) |
||
4122 | continue; |
||
4123 | else |
||
4124 | break; |
||
4125 | } |
||
4126 | if (tok != ',') |
||
4127 | expect(","); |
||
4128 | next_nomacro(); |
||
4129 | } |
||
4130 | if (sa) { |
||
4131 | error("macro '%s' used with too few args", |
||
4132 | get_tok_str(s->v, 0)); |
||
4133 | } |
||
4134 | |||
4135 | /* now subst each arg */ |
||
4136 | mstr = macro_arg_subst(nested_list, mstr, args); |
||
4137 | /* free memory */ |
||
4138 | sa = args; |
||
4139 | while (sa) { |
||
4140 | sa1 = sa->prev; |
||
4141 | tok_str_free((int *)sa->c); |
||
4142 | sym_free(sa); |
||
4143 | sa = sa1; |
||
4144 | } |
||
4145 | mstr_allocated = 1; |
||
4146 | } |
||
4147 | sym_push2(nested_list, s->v, 0, 0); |
||
4148 | macro_subst(tok_str, nested_list, mstr, can_read_stream); |
||
4149 | /* pop nested defined symbol */ |
||
4150 | sa1 = *nested_list; |
||
4151 | *nested_list = sa1->prev; |
||
4152 | sym_free(sa1); |
||
4153 | if (mstr_allocated) |
||
4154 | tok_str_free(mstr); |
||
4155 | } |
||
4156 | return 0; |
||
4157 | } |
||
4158 | |||
4159 | /* handle the '##' operator. Return NULL if no '##' seen. Otherwise |
||
4160 | return the resulting string (which must be freed). */ |
||
4161 | static inline int *macro_twosharps(const int *macro_str) |
||
4162 | { |
||
4163 | TokenSym *ts; |
||
4164 | const int *macro_ptr1, *start_macro_ptr, *ptr, *saved_macro_ptr; |
||
4165 | int t; |
||
4166 | const char *p1, *p2; |
||
4167 | CValue cval; |
||
4168 | TokenString macro_str1; |
||
4169 | CString cstr; |
||
4170 | |||
4171 | start_macro_ptr = macro_str; |
||
4172 | /* we search the first '##' */ |
||
4173 | for(;;) { |
||
4174 | macro_ptr1 = macro_str; |
||
4175 | TOK_GET(t, macro_str, cval); |
||
4176 | /* nothing more to do if end of string */ |
||
4177 | if (t == 0) |
||
4178 | return NULL; |
||
4179 | if (*macro_str == TOK_TWOSHARPS) |
||
4180 | break; |
||
4181 | } |
||
4182 | |||
4183 | /* we saw '##', so we need more processing to handle it */ |
||
4184 | cstr_new(&cstr); |
||
4185 | tok_str_new(¯o_str1); |
||
4186 | tok = t; |
||
4187 | tokc = cval; |
||
4188 | |||
4189 | /* add all tokens seen so far */ |
||
4190 | for(ptr = start_macro_ptr; ptr < macro_ptr1;) { |
||
4191 | TOK_GET(t, ptr, cval); |
||
4192 | tok_str_add2(¯o_str1, t, &cval); |
||
4193 | } |
||
4194 | saved_macro_ptr = macro_ptr; |
||
4195 | /* XXX: get rid of the use of macro_ptr here */ |
||
4196 | macro_ptr = (int *)macro_str; |
||
4197 | for(;;) { |
||
4198 | while (*macro_ptr == TOK_TWOSHARPS) { |
||
4199 | macro_ptr++; |
||
4200 | macro_ptr1 = macro_ptr; |
||
4201 | t = *macro_ptr; |
||
4202 | if (t) { |
||
4203 | TOK_GET(t, macro_ptr, cval); |
||
4204 | /* We concatenate the two tokens if we have an |
||
4205 | identifier or a preprocessing number */ |
||
4206 | cstr_reset(&cstr); |
||
4207 | p1 = get_tok_str(tok, &tokc); |
||
4208 | cstr_cat(&cstr, p1); |
||
4209 | p2 = get_tok_str(t, &cval); |
||
4210 | cstr_cat(&cstr, p2); |
||
4211 | cstr_ccat(&cstr, '\0'); |
||
4212 | |||
4213 | if ((tok >= TOK_IDENT || tok == TOK_PPNUM) && |
||
4214 | (t >= TOK_IDENT || t == TOK_PPNUM)) { |
||
4215 | if (tok == TOK_PPNUM) { |
||
4216 | /* if number, then create a number token */ |
||
4217 | /* NOTE: no need to allocate because |
||
4218 | tok_str_add2() does it */ |
||
4219 | tokc.cstr = &cstr; |
||
4220 | } else { |
||
4221 | /* if identifier, we must do a test to |
||
4222 | validate we have a correct identifier */ |
||
4223 | if (t == TOK_PPNUM) { |
||
4224 | const char *p; |
||
4225 | int c; |
||
4226 | |||
4227 | p = p2; |
||
4228 | for(;;) { |
||
4229 | c = *p; |
||
4230 | if (c == '\0') |
||
4231 | break; |
||
4232 | p++; |
||
4233 | if (!isnum(c) && !isid(c)) |
||
4234 | goto error_pasting; |
||
4235 | } |
||
4236 | } |
||
4237 | ts = tok_alloc(cstr.data, strlen(cstr.data)); |
||
4238 | tok = ts->tok; /* modify current token */ |
||
4239 | } |
||
4240 | } else { |
||
4241 | const char *str = cstr.data; |
||
4242 | const unsigned char *q; |
||
4243 | |||
4244 | /* we look for a valid token */ |
||
4245 | /* XXX: do more extensive checks */ |
||
4246 | if (!strcmp(str, ">>=")) { |
||
4247 | tok = TOK_A_SAR; |
||
4248 | } else if (!strcmp(str, "<<=")) { |
||
4249 | tok = TOK_A_SHL; |
||
4250 | } else if (strlen(str) == 2) { |
||
4251 | /* search in two bytes table */ |
||
4252 | q = tok_two_chars; |
||
4253 | for(;;) { |
||
4254 | if (!*q) |
||
4255 | goto error_pasting; |
||
4256 | if (q[0] == str[0] && q[1] == str[1]) |
||
4257 | break; |
||
4258 | q += 3; |
||
4259 | } |
||
4260 | tok = q[2]; |
||
4261 | } else { |
||
4262 | error_pasting: |
||
4263 | /* NOTE: because get_tok_str use a static buffer, |
||
4264 | we must save it */ |
||
4265 | cstr_reset(&cstr); |
||
4266 | p1 = get_tok_str(tok, &tokc); |
||
4267 | cstr_cat(&cstr, p1); |
||
4268 | cstr_ccat(&cstr, '\0'); |
||
4269 | p2 = get_tok_str(t, &cval); |
||
4270 | warning("pasting \"%s\" and \"%s\" does not give a valid preprocessing token", cstr.data, p2); |
||
4271 | /* cannot merge tokens: just add them separately */ |
||
4272 | tok_str_add2(¯o_str1, tok, &tokc); |
||
4273 | /* XXX: free associated memory ? */ |
||
4274 | tok = t; |
||
4275 | tokc = cval; |
||
4276 | } |
||
4277 | } |
||
4278 | } |
||
4279 | } |
||
4280 | tok_str_add2(¯o_str1, tok, &tokc); |
||
4281 | next_nomacro(); |
||
4282 | if (tok == 0) |
||
4283 | break; |
||
4284 | } |
||
4285 | macro_ptr = (int *)saved_macro_ptr; |
||
4286 | cstr_free(&cstr); |
||
4287 | tok_str_add(¯o_str1, 0); |
||
4288 | return macro_str1.str; |
||
4289 | } |
||
4290 | |||
4291 | |||
4292 | /* do macro substitution of macro_str and add result to |
||
4293 | (tok_str,tok_len). 'nested_list' is the list of all macros we got |
||
4294 | inside to avoid recursing. */ |
||
4295 | static void macro_subst(TokenString *tok_str, Sym **nested_list, |
||
4296 | const int *macro_str, struct macro_level ** can_read_stream) |
||
4297 | { |
||
4298 | Sym *s; |
||
4299 | int *macro_str1; |
||
4300 | const int *ptr; |
||
4301 | int t, ret; |
||
4302 | CValue cval; |
||
4303 | struct macro_level ml; |
||
4304 | |||
4305 | /* first scan for '##' operator handling */ |
||
4306 | ptr = macro_str; |
||
4307 | macro_str1 = macro_twosharps(ptr); |
||
4308 | if (macro_str1) |
||
4309 | ptr = macro_str1; |
||
4310 | while (1) { |
||
4311 | /* NOTE: ptr == NULL can only happen if tokens are read from |
||
4312 | file stream due to a macro function call */ |
||
4313 | if (ptr == NULL) |
||
4314 | break; |
||
4315 | TOK_GET(t, ptr, cval); |
||
4316 | if (t == 0) |
||
4317 | break; |
||
4318 | s = define_find(t); |
||
4319 | if (s != NULL) { |
||
4320 | /* if nested substitution, do nothing */ |
||
4321 | if (sym_find2(*nested_list, t)) |
||
4322 | goto no_subst; |
||
4323 | ml.p = macro_ptr; |
||
4324 | if (can_read_stream) |
||
4325 | ml.prev = *can_read_stream, *can_read_stream = &ml; |
||
4326 | macro_ptr = (int *)ptr; |
||
4327 | tok = t; |
||
4328 | ret = macro_subst_tok(tok_str, nested_list, s, can_read_stream); |
||
4329 | ptr = (int *)macro_ptr; |
||
4330 | macro_ptr = ml.p; |
||
4331 | if (can_read_stream && *can_read_stream == &ml) |
||
4332 | *can_read_stream = ml.prev; |
||
4333 | if (ret != 0) |
||
4334 | goto no_subst; |
||
4335 | } else { |
||
4336 | no_subst: |
||
4337 | tok_str_add2(tok_str, t, &cval); |
||
4338 | } |
||
4339 | } |
||
4340 | if (macro_str1) |
||
4341 | tok_str_free(macro_str1); |
||
4342 | } |
||
4343 | |||
4344 | /* return next token with macro substitution */ |
||
4345 | static void next(void) |
||
4346 | { |
||
4347 | Sym *nested_list, *s; |
||
4348 | TokenString str; |
||
4349 | struct macro_level *ml; |
||
4350 | |||
4351 | redo: |
||
4352 | next_nomacro(); |
||
4353 | if (!macro_ptr) { |
||
4354 | /* if not reading from macro substituted string, then try |
||
4355 | to substitute macros */ |
||
4356 | if (tok >= TOK_IDENT && |
||
4357 | (parse_flags & PARSE_FLAG_PREPROCESS)) { |
||
4358 | s = define_find(tok); |
||
4359 | if (s) { |
||
4360 | /* we have a macro: we try to substitute */ |
||
4361 | tok_str_new(&str); |
||
4362 | nested_list = NULL; |
||
4363 | ml = NULL; |
||
4364 | if (macro_subst_tok(&str, &nested_list, s, &ml) == 0) { |
||
4365 | /* substitution done, NOTE: maybe empty */ |
||
4366 | tok_str_add(&str, 0); |
||
4367 | macro_ptr = str.str; |
||
4368 | macro_ptr_allocated = str.str; |
||
4369 | goto redo; |
||
4370 | } |
||
4371 | } |
||
4372 | } |
||
4373 | } else { |
||
4374 | if (tok == 0) { |
||
4375 | /* end of macro or end of unget buffer */ |
||
4376 | if (unget_buffer_enabled) { |
||
4377 | macro_ptr = unget_saved_macro_ptr; |
||
4378 | unget_buffer_enabled = 0; |
||
4379 | } else { |
||
4380 | /* end of macro string: free it */ |
||
4381 | tok_str_free(macro_ptr_allocated); |
||
4382 | macro_ptr = NULL; |
||
4383 | } |
||
4384 | goto redo; |
||
4385 | } |
||
4386 | } |
||
4387 | |||
4388 | /* convert preprocessor tokens into C tokens */ |
||
4389 | if (tok == TOK_PPNUM && |
||
4390 | (parse_flags & PARSE_FLAG_TOK_NUM)) { |
||
4391 | parse_number((char *)tokc.cstr->data); |
||
4392 | } |
||
4393 | } |
||
4394 | |||
4395 | /* push back current token and set current token to 'last_tok'. Only |
||
4396 | identifier case handled for labels. */ |
||
4397 | static inline void unget_tok(int last_tok) |
||
4398 | { |
||
4399 | int i, n; |
||
4400 | int *q; |
||
4401 | unget_saved_macro_ptr = macro_ptr; |
||
4402 | unget_buffer_enabled = 1; |
||
4403 | q = unget_saved_buffer; |
||
4404 | macro_ptr = q; |
||
4405 | *q++ = tok; |
||
4406 | n = tok_ext_size(tok) - 1; |
||
4407 | for(i=0;i |
||
4408 | *q++ = tokc.tab[i]; |
||
4409 | *q = 0; /* end of token string */ |
||
4410 | tok = last_tok; |
||
4411 | } |
||
4412 | |||
4413 | |||
4414 | void swap(int *p, int *q) |
||
4415 | { |
||
4416 | int t; |
||
4417 | t = *p; |
||
4418 | *p = *q; |
||
4419 | *q = t; |
||
4420 | } |
||
4421 | |||
4422 | void vsetc(CType *type, int r, CValue *vc) |
||
4423 | { |
||
4424 | int v; |
||
4425 | |||
4426 | if (vtop >= vstack + (VSTACK_SIZE - 1)) |
||
4427 | error("memory full"); |
||
4428 | /* cannot let cpu flags if other instruction are generated. Also |
||
4429 | avoid leaving VT_JMP anywhere except on the top of the stack |
||
4430 | because it would complicate the code generator. */ |
||
4431 | if (vtop >= vstack) { |
||
4432 | v = vtop->r & VT_VALMASK; |
||
4433 | if (v == VT_CMP || (v & ~1) == VT_JMP) |
||
4434 | gv(RC_INT); |
||
4435 | } |
||
4436 | vtop++; |
||
4437 | vtop->type = *type; |
||
4438 | vtop->r = r; |
||
4439 | vtop->r2 = VT_CONST; |
||
4440 | vtop->c = *vc; |
||
4441 | } |
||
4442 | |||
4443 | /* push integer constant */ |
||
4444 | void vpushi(int v) |
||
4445 | { |
||
4446 | CValue cval; |
||
4447 | cval.i = v; |
||
4448 | vsetc(&int_type, VT_CONST, &cval); |
||
4449 | } |
||
4450 | |||
4451 | /* Return a static symbol pointing to a section */ |
||
4452 | static Sym *get_sym_ref(CType *type, Section *sec, |
||
4453 | unsigned long offset, unsigned long size) |
||
4454 | { |
||
4455 | int v; |
||
4456 | Sym *sym; |
||
4457 | |||
4458 | v = anon_sym++; |
||
4459 | sym = global_identifier_push(v, type->t | VT_STATIC, 0); |
||
4460 | sym->type.ref = type->ref; |
||
4461 | sym->r = VT_CONST | VT_SYM; |
||
4462 | put_extern_sym(sym, sec, offset, size); |
||
4463 | return sym; |
||
4464 | } |
||
4465 | |||
4466 | /* push a reference to a section offset by adding a dummy symbol */ |
||
4467 | static void vpush_ref(CType *type, Section *sec, unsigned long offset, unsigned long size) |
||
4468 | { |
||
4469 | CValue cval; |
||
4470 | |||
4471 | cval.ul = 0; |
||
4472 | vsetc(type, VT_CONST | VT_SYM, &cval); |
||
4473 | vtop->sym = get_sym_ref(type, sec, offset, size); |
||
4474 | } |
||
4475 | |||
4476 | /* define a new external reference to a symbol 'v' of type 'u' */ |
||
4477 | static Sym *external_global_sym(int v, CType *type, int r) |
||
4478 | { |
||
4479 | Sym *s; |
||
4480 | |||
4481 | s = sym_find(v); |
||
4482 | if (!s) { |
||
4483 | /* push forward reference */ |
||
4484 | s = global_identifier_push(v, type->t | VT_EXTERN, 0); |
||
4485 | s->type.ref = type->ref; |
||
4486 | s->r = r | VT_CONST | VT_SYM; |
||
4487 | } |
||
4488 | return s; |
||
4489 | } |
||
4490 | |||
4491 | /* define a new external reference to a symbol 'v' of type 'u' */ |
||
4492 | static Sym *external_sym(int v, CType *type, int r) |
||
4493 | { |
||
4494 | Sym *s; |
||
4495 | |||
4496 | s = sym_find(v); |
||
4497 | if (!s) { |
||
4498 | /* push forward reference */ |
||
4499 | s = sym_push(v, type, r | VT_CONST | VT_SYM, 0); |
||
4500 | s->type.t |= VT_EXTERN; |
||
4501 | } else { |
||
4502 | if (!is_compatible_types(&s->type, type)) |
||
4503 | error("incompatible types for redefinition of '%s'", |
||
4504 | get_tok_str(v, NULL)); |
||
4505 | } |
||
4506 | return s; |
||
4507 | } |
||
4508 | |||
4509 | /* push a reference to global symbol v */ |
||
4510 | static void vpush_global_sym(CType *type, int v) |
||
4511 | { |
||
4512 | Sym *sym; |
||
4513 | CValue cval; |
||
4514 | |||
4515 | sym = external_global_sym(v, type, 0); |
||
4516 | cval.ul = 0; |
||
4517 | vsetc(type, VT_CONST | VT_SYM, &cval); |
||
4518 | vtop->sym = sym; |
||
4519 | } |
||
4520 | |||
4521 | void vset(CType *type, int r, int v) |
||
4522 | { |
||
4523 | CValue cval; |
||
4524 | |||
4525 | cval.i = v; |
||
4526 | vsetc(type, r, &cval); |
||
4527 | } |
||
4528 | |||
4529 | void vseti(int r, int v) |
||
4530 | { |
||
4531 | CType type; |
||
4532 | type.t = VT_INT; |
||
4533 | vset(&type, r, v); |
||
4534 | } |
||
4535 | |||
4536 | void vswap(void) |
||
4537 | { |
||
4538 | SValue tmp; |
||
4539 | |||
4540 | tmp = vtop[0]; |
||
4541 | vtop[0] = vtop[-1]; |
||
4542 | vtop[-1] = tmp; |
||
4543 | } |
||
4544 | |||
4545 | void vpushv(SValue *v) |
||
4546 | { |
||
4547 | if (vtop >= vstack + (VSTACK_SIZE - 1)) |
||
4548 | error("memory full"); |
||
4549 | vtop++; |
||
4550 | *vtop = *v; |
||
4551 | } |
||
4552 | |||
4553 | void vdup(void) |
||
4554 | { |
||
4555 | vpushv(vtop); |
||
4556 | } |
||
4557 | |||
4558 | /* save r to the memory stack, and mark it as being free */ |
||
4559 | void save_reg(int r) |
||
4560 | { |
||
4561 | int l, saved, size, align; |
||
4562 | SValue *p, sv; |
||
4563 | CType *type; |
||
4564 | |||
4565 | /* modify all stack values */ |
||
4566 | saved = 0; |
||
4567 | l = 0; |
||
4568 | for(p=vstack;p<=vtop;p++) { |
||
4569 | if ((p->r & VT_VALMASK) == r || |
||
4570 | (p->r2 & VT_VALMASK) == r) { |
||
4571 | /* must save value on stack if not already done */ |
||
4572 | if (!saved) { |
||
4573 | /* NOTE: must reload 'r' because r might be equal to r2 */ |
||
4574 | r = p->r & VT_VALMASK; |
||
4575 | /* store register in the stack */ |
||
4576 | type = &p->type; |
||
4577 | if ((p->r & VT_LVAL) || |
||
4578 | (!is_float(type->t) && (type->t & VT_BTYPE) != VT_LLONG)) |
||
4579 | type = &int_type; |
||
4580 | size = type_size(type, &align); |
||
4581 | loc = (loc - size) & -align; |
||
4582 | sv.type.t = type->t; |
||
4583 | sv.r = VT_LOCAL | VT_LVAL; |
||
4584 | sv.c.ul = loc; |
||
4585 | store(r, &sv); |
||
4586 | #ifdef TCC_TARGET_I386 |
||
4587 | /* x86 specific: need to pop fp register ST0 if saved */ |
||
4588 | if (r == TREG_ST0) { |
||
4589 | o(0xd9dd); /* fstp %st(1) */ |
||
4590 | } |
||
4591 | #endif |
||
4592 | /* special long long case */ |
||
4593 | if ((type->t & VT_BTYPE) == VT_LLONG) { |
||
4594 | sv.c.ul += 4; |
||
4595 | store(p->r2, &sv); |
||
4596 | } |
||
4597 | l = loc; |
||
4598 | saved = 1; |
||
4599 | } |
||
4600 | /* mark that stack entry as being saved on the stack */ |
||
4601 | if (p->r & VT_LVAL) { |
||
4602 | /* also clear the bounded flag because the |
||
4603 | relocation address of the function was stored in |
||
4604 | p->c.ul */ |
||
4605 | p->r = (p->r & ~(VT_VALMASK | VT_BOUNDED)) | VT_LLOCAL; |
||
4606 | } else { |
||
4607 | p->r = lvalue_type(p->type.t) | VT_LOCAL; |
||
4608 | } |
||
4609 | p->r2 = VT_CONST; |
||
4610 | p->c.ul = l; |
||
4611 | } |
||
4612 | } |
||
4613 | } |
||
4614 | |||
4615 | /* find a register of class 'rc2' with at most one reference on stack. |
||
4616 | * If none, call get_reg(rc) */ |
||
4617 | int get_reg_ex(int rc, int rc2) |
||
4618 | { |
||
4619 | int r; |
||
4620 | SValue *p; |
||
4621 | |||
4622 | for(r=0;r |
||
4623 | if (reg_classes[r] & rc2) { |
||
4624 | int n; |
||
4625 | n=0; |
||
4626 | for(p = vstack; p <= vtop; p++) { |
||
4627 | if ((p->r & VT_VALMASK) == r || |
||
4628 | (p->r2 & VT_VALMASK) == r) |
||
4629 | n++; |
||
4630 | } |
||
4631 | if (n <= 1) |
||
4632 | return r; |
||
4633 | } |
||
4634 | } |
||
4635 | return get_reg(rc); |
||
4636 | } |
||
4637 | |||
4638 | /* find a free register of class 'rc'. If none, save one register */ |
||
4639 | int get_reg(int rc) |
||
4640 | { |
||
4641 | int r; |
||
4642 | SValue *p; |
||
4643 | |||
4644 | /* find a free register */ |
||
4645 | for(r=0;r |
||
4646 | if (reg_classes[r] & rc) { |
||
4647 | for(p=vstack;p<=vtop;p++) { |
||
4648 | if ((p->r & VT_VALMASK) == r || |
||
4649 | (p->r2 & VT_VALMASK) == r) |
||
4650 | goto notfound; |
||
4651 | } |
||
4652 | return r; |
||
4653 | } |
||
4654 | notfound: ; |
||
4655 | } |
||
4656 | |||
4657 | /* no register left : free the first one on the stack (VERY |
||
4658 | IMPORTANT to start from the bottom to ensure that we don't |
||
4659 | spill registers used in gen_opi()) */ |
||
4660 | for(p=vstack;p<=vtop;p++) { |
||
4661 | r = p->r & VT_VALMASK; |
||
4662 | if (r < VT_CONST && (reg_classes[r] & rc)) |
||
4663 | goto save_found; |
||
4664 | /* also look at second register (if long long) */ |
||
4665 | r = p->r2 & VT_VALMASK; |
||
4666 | if (r < VT_CONST && (reg_classes[r] & rc)) { |
||
4667 | save_found: |
||
4668 | save_reg(r); |
||
4669 | return r; |
||
4670 | } |
||
4671 | } |
||
4672 | /* Should never comes here */ |
||
4673 | return -1; |
||
4674 | } |
||
4675 | |||
4676 | /* save registers up to (vtop - n) stack entry */ |
||
4677 | void save_regs(int n) |
||
4678 | { |
||
4679 | int r; |
||
4680 | SValue *p, *p1; |
||
4681 | p1 = vtop - n; |
||
4682 | for(p = vstack;p <= p1; p++) { |
||
4683 | r = p->r & VT_VALMASK; |
||
4684 | if (r < VT_CONST) { |
||
4685 | save_reg(r); |
||
4686 | } |
||
4687 | } |
||
4688 | } |
||
4689 | |||
4690 | /* move register 's' to 'r', and flush previous value of r to memory |
||
4691 | if needed */ |
||
4692 | void move_reg(int r, int s) |
||
4693 | { |
||
4694 | SValue sv; |
||
4695 | |||
4696 | if (r != s) { |
||
4697 | save_reg(r); |
||
4698 | sv.type.t = VT_INT; |
||
4699 | sv.r = s; |
||
4700 | sv.c.ul = 0; |
||
4701 | load(r, &sv); |
||
4702 | } |
||
4703 | } |
||
4704 | |||
4705 | /* get address of vtop (vtop MUST BE an lvalue) */ |
||
4706 | void gaddrof(void) |
||
4707 | { |
||
4708 | vtop->r &= ~VT_LVAL; |
||
4709 | /* tricky: if saved lvalue, then we can go back to lvalue */ |
||
4710 | if ((vtop->r & VT_VALMASK) == VT_LLOCAL) |
||
4711 | vtop->r = (vtop->r & ~(VT_VALMASK | VT_LVAL_TYPE)) | VT_LOCAL | VT_LVAL; |
||
4712 | } |
||
4713 | |||
4714 | #ifdef CONFIG_TCC_BCHECK |
||
4715 | /* generate lvalue bound code */ |
||
4716 | void gbound(void) |
||
4717 | { |
||
4718 | int lval_type; |
||
4719 | CType type1; |
||
4720 | |||
4721 | vtop->r &= ~VT_MUSTBOUND; |
||
4722 | /* if lvalue, then use checking code before dereferencing */ |
||
4723 | if (vtop->r & VT_LVAL) { |
||
4724 | /* if not VT_BOUNDED value, then make one */ |
||
4725 | if (!(vtop->r & VT_BOUNDED)) { |
||
4726 | lval_type = vtop->r & (VT_LVAL_TYPE | VT_LVAL); |
||
4727 | /* must save type because we must set it to int to get pointer */ |
||
4728 | type1 = vtop->type; |
||
4729 | vtop->type.t = VT_INT; |
||
4730 | gaddrof(); |
||
4731 | vpushi(0); |
||
4732 | gen_bounded_ptr_add(); |
||
4733 | vtop->r |= lval_type; |
||
4734 | vtop->type = type1; |
||
4735 | } |
||
4736 | /* then check for dereferencing */ |
||
4737 | gen_bounded_ptr_deref(); |
||
4738 | } |
||
4739 | } |
||
4740 | #endif |
||
4741 | |||
4742 | /* store vtop a register belonging to class 'rc'. lvalues are |
||
4743 | converted to values. Cannot be used if cannot be converted to |
||
4744 | register value (such as structures). */ |
||
4745 | int gv(int rc) |
||
4746 | { |
||
4747 | int r, r2, rc2, bit_pos, bit_size, size, align, i; |
||
4748 | unsigned long long ll; |
||
4749 | |||
4750 | /* NOTE: get_reg can modify vstack[] */ |
||
4751 | if (vtop->type.t & VT_BITFIELD) { |
||
4752 | bit_pos = (vtop->type.t >> VT_STRUCT_SHIFT) & 0x3f; |
||
4753 | bit_size = (vtop->type.t >> (VT_STRUCT_SHIFT + 6)) & 0x3f; |
||
4754 | /* remove bit field info to avoid loops */ |
||
4755 | vtop->type.t &= ~(VT_BITFIELD | (-1 << VT_STRUCT_SHIFT)); |
||
4756 | /* generate shifts */ |
||
4757 | vpushi(32 - (bit_pos + bit_size)); |
||
4758 | gen_op(TOK_SHL); |
||
4759 | vpushi(32 - bit_size); |
||
4760 | /* NOTE: transformed to SHR if unsigned */ |
||
4761 | gen_op(TOK_SAR); |
||
4762 | r = gv(rc); |
||
4763 | } else { |
||
4764 | if (is_float(vtop->type.t) && |
||
4765 | (vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) { |
||
4766 | Sym *sym; |
||
4767 | int *ptr; |
||
4768 | unsigned long offset; |
||
4769 | |||
4770 | /* XXX: unify with initializers handling ? */ |
||
4771 | /* CPUs usually cannot use float constants, so we store them |
||
4772 | generically in data segment */ |
||
4773 | size = type_size(&vtop->type, &align); |
||
4774 | offset = (data_section->data_offset + align - 1) & -align; |
||
4775 | data_section->data_offset = offset; |
||
4776 | /* XXX: not portable yet */ |
||
4777 | ptr = section_ptr_add(data_section, size); |
||
4778 | size = size >> 2; |
||
4779 | for(i=0;i |
||
4780 | ptr[i] = vtop->c.tab[i]; |
||
4781 | sym = get_sym_ref(&vtop->type, data_section, offset, size << 2); |
||
4782 | vtop->r |= VT_LVAL | VT_SYM; |
||
4783 | vtop->sym = sym; |
||
4784 | vtop->c.ul = 0; |
||
4785 | } |
||
4786 | #ifdef CONFIG_TCC_BCHECK |
||
4787 | if (vtop->r & VT_MUSTBOUND) |
||
4788 | gbound(); |
||
4789 | #endif |
||
4790 | |||
4791 | r = vtop->r & VT_VALMASK; |
||
4792 | /* need to reload if: |
||
4793 | - constant |
||
4794 | - lvalue (need to dereference pointer) |
||
4795 | - already a register, but not in the right class */ |
||
4796 | if (r >= VT_CONST || |
||
4797 | (vtop->r & VT_LVAL) || |
||
4798 | !(reg_classes[r] & rc) || |
||
4799 | ((vtop->type.t & VT_BTYPE) == VT_LLONG && |
||
4800 | !(reg_classes[vtop->r2] & rc))) { |
||
4801 | r = get_reg(rc); |
||
4802 | if ((vtop->type.t & VT_BTYPE) == VT_LLONG) { |
||
4803 | /* two register type load : expand to two words |
||
4804 | temporarily */ |
||
4805 | if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) { |
||
4806 | /* load constant */ |
||
4807 | ll = vtop->c.ull; |
||
4808 | vtop->c.ui = ll; /* first word */ |
||
4809 | load(r, vtop); |
||
4810 | vtop->r = r; /* save register value */ |
||
4811 | vpushi(ll >> 32); /* second word */ |
||
4812 | } else if (r >= VT_CONST || /* XXX: test to VT_CONST incorrect ? */ |
||
4813 | (vtop->r & VT_LVAL)) { |
||
4814 | /* We do not want to modifier the long long |
||
4815 | pointer here, so the safest (and less |
||
4816 | efficient) is to save all the other registers |
||
4817 | in the stack. XXX: totally inefficient. */ |
||
4818 | save_regs(1); |
||
4819 | /* load from memory */ |
||
4820 | load(r, vtop); |
||
4821 | vdup(); |
||
4822 | vtop[-1].r = r; /* save register value */ |
||
4823 | /* increment pointer to get second word */ |
||
4824 | vtop->type.t = VT_INT; |
||
4825 | gaddrof(); |
||
4826 | vpushi(4); |
||
4827 | gen_op('+'); |
||
4828 | vtop->r |= VT_LVAL; |
||
4829 | } else { |
||
4830 | /* move registers */ |
||
4831 | load(r, vtop); |
||
4832 | vdup(); |
||
4833 | vtop[-1].r = r; /* save register value */ |
||
4834 | vtop->r = vtop[-1].r2; |
||
4835 | } |
||
4836 | /* allocate second register */ |
||
4837 | rc2 = RC_INT; |
||
4838 | if (rc == RC_IRET) |
||
4839 | rc2 = RC_LRET; |
||
4840 | r2 = get_reg(rc2); |
||
4841 | load(r2, vtop); |
||
4842 | vpop(); |
||
4843 | /* write second register */ |
||
4844 | vtop->r2 = r2; |
||
4845 | } else if ((vtop->r & VT_LVAL) && !is_float(vtop->type.t)) { |
||
4846 | int t1, t; |
||
4847 | /* lvalue of scalar type : need to use lvalue type |
||
4848 | because of possible cast */ |
||
4849 | t = vtop->type.t; |
||
4850 | t1 = t; |
||
4851 | /* compute memory access type */ |
||
4852 | if (vtop->r & VT_LVAL_BYTE) |
||
4853 | t = VT_BYTE; |
||
4854 | else if (vtop->r & VT_LVAL_SHORT) |
||
4855 | t = VT_SHORT; |
||
4856 | if (vtop->r & VT_LVAL_UNSIGNED) |
||
4857 | t |= VT_UNSIGNED; |
||
4858 | vtop->type.t = t; |
||
4859 | load(r, vtop); |
||
4860 | /* restore wanted type */ |
||
4861 | vtop->type.t = t1; |
||
4862 | } else { |
||
4863 | /* one register type load */ |
||
4864 | load(r, vtop); |
||
4865 | } |
||
4866 | } |
||
4867 | vtop->r = r; |
||
4868 | #ifdef TCC_TARGET_C67 |
||
4869 | /* uses register pairs for doubles */ |
||
4870 | if ((vtop->type.t & VT_BTYPE) == VT_DOUBLE) |
||
4871 | vtop->r2 = r+1; |
||
4872 | #endif |
||
4873 | } |
||
4874 | return r; |
||
4875 | } |
||
4876 | |||
4877 | /* generate vtop[-1] and vtop[0] in resp. classes rc1 and rc2 */ |
||
4878 | void gv2(int rc1, int rc2) |
||
4879 | { |
||
4880 | int v; |
||
4881 | |||
4882 | /* generate more generic register first. But VT_JMP or VT_CMP |
||
4883 | values must be generated first in all cases to avoid possible |
||
4884 | reload errors */ |
||
4885 | v = vtop[0].r & VT_VALMASK; |
||
4886 | if (v != VT_CMP && (v & ~1) != VT_JMP && rc1 <= rc2) { |
||
4887 | vswap(); |
||
4888 | gv(rc1); |
||
4889 | vswap(); |
||
4890 | gv(rc2); |
||
4891 | /* test if reload is needed for first register */ |
||
4892 | if ((vtop[-1].r & VT_VALMASK) >= VT_CONST) { |
||
4893 | vswap(); |
||
4894 | gv(rc1); |
||
4895 | vswap(); |
||
4896 | } |
||
4897 | } else { |
||
4898 | gv(rc2); |
||
4899 | vswap(); |
||
4900 | gv(rc1); |
||
4901 | vswap(); |
||
4902 | /* test if reload is needed for first register */ |
||
4903 | if ((vtop[0].r & VT_VALMASK) >= VT_CONST) { |
||
4904 | gv(rc2); |
||
4905 | } |
||
4906 | } |
||
4907 | } |
||
4908 | |||
4909 | /* expand long long on stack in two int registers */ |
||
4910 | void lexpand(void) |
||
4911 | { |
||
4912 | int u; |
||
4913 | |||
4914 | u = vtop->type.t & VT_UNSIGNED; |
||
4915 | gv(RC_INT); |
||
4916 | vdup(); |
||
4917 | vtop[0].r = vtop[-1].r2; |
||
4918 | vtop[0].r2 = VT_CONST; |
||
4919 | vtop[-1].r2 = VT_CONST; |
||
4920 | vtop[0].type.t = VT_INT | u; |
||
4921 | vtop[-1].type.t = VT_INT | u; |
||
4922 | } |
||
4923 | |||
4924 | #ifdef TCC_TARGET_ARM |
||
4925 | /* expand long long on stack */ |
||
4926 | void lexpand_nr(void) |
||
4927 | { |
||
4928 | int u,v; |
||
4929 | |||
4930 | u = vtop->type.t & VT_UNSIGNED; |
||
4931 | vdup(); |
||
4932 | vtop->r2 = VT_CONST; |
||
4933 | vtop->type.t = VT_INT | u; |
||
4934 | v=vtop[-1].r & (VT_VALMASK | VT_LVAL); |
||
4935 | if (v == VT_CONST) { |
||
4936 | vtop[-1].c.ui = vtop->c.ull; |
||
4937 | vtop->c.ui = vtop->c.ull >> 32; |
||
4938 | vtop->r = VT_CONST; |
||
4939 | } else if (v == (VT_LVAL|VT_CONST) || v == (VT_LVAL|VT_LOCAL)) { |
||
4940 | vtop->c.ui += 4; |
||
4941 | vtop->r = vtop[-1].r; |
||
4942 | } else if (v > VT_CONST) { |
||
4943 | vtop--; |
||
4944 | lexpand(); |
||
4945 | } else |
||
4946 | vtop->r = vtop[-1].r2; |
||
4947 | vtop[-1].r2 = VT_CONST; |
||
4948 | vtop[-1].type.t = VT_INT | u; |
||
4949 | } |
||
4950 | #endif |
||
4951 | |||
4952 | /* build a long long from two ints */ |
||
4953 | void lbuild(int t) |
||
4954 | { |
||
4955 | gv2(RC_INT, RC_INT); |
||
4956 | vtop[-1].r2 = vtop[0].r; |
||
4957 | vtop[-1].type.t = t; |
||
4958 | vpop(); |
||
4959 | } |
||
4960 | |||
4961 | /* rotate n first stack elements to the bottom |
||
4962 | I1 ... In -> I2 ... In I1 [top is right] |
||
4963 | */ |
||
4964 | void vrotb(int n) |
||
4965 | { |
||
4966 | int i; |
||
4967 | SValue tmp; |
||
4968 | |||
4969 | tmp = vtop[-n + 1]; |
||
4970 | for(i=-n+1;i!=0;i++) |
||
4971 | vtop[i] = vtop[i+1]; |
||
4972 | vtop[0] = tmp; |
||
4973 | } |
||
4974 | |||
4975 | /* rotate n first stack elements to the top |
||
4976 | I1 ... In -> In I1 ... I(n-1) [top is right] |
||
4977 | */ |
||
4978 | void vrott(int n) |
||
4979 | { |
||
4980 | int i; |
||
4981 | SValue tmp; |
||
4982 | |||
4983 | tmp = vtop[0]; |
||
4984 | for(i = 0;i < n - 1; i++) |
||
4985 | vtop[-i] = vtop[-i - 1]; |
||
4986 | vtop[-n + 1] = tmp; |
||
4987 | } |
||
4988 | |||
4989 | #ifdef TCC_TARGET_ARM |
||
4990 | /* like vrott but in other direction |
||
4991 | In ... I1 -> I(n-1) ... I1 In [top is right] |
||
4992 | */ |
||
4993 | void vnrott(int n) |
||
4994 | { |
||
4995 | int i; |
||
4996 | SValue tmp; |
||
4997 | |||
4998 | tmp = vtop[-n + 1]; |
||
4999 | for(i = n - 1; i > 0; i--) |
||
5000 | vtop[-i] = vtop[-i + 1]; |
||
5001 | vtop[0] = tmp; |
||
5002 | } |
||
5003 | #endif |
||
5004 | |||
5005 | /* pop stack value */ |
||
5006 | void vpop(void) |
||
5007 | { |
||
5008 | int v; |
||
5009 | v = vtop->r & VT_VALMASK; |
||
5010 | #ifdef TCC_TARGET_I386 |
||
5011 | /* for x86, we need to pop the FP stack */ |
||
5012 | if (v == TREG_ST0 && !nocode_wanted) { |
||
5013 | o(0xd9dd); /* fstp %st(1) */ |
||
5014 | } else |
||
5015 | #endif |
||
5016 | if (v == VT_JMP || v == VT_JMPI) { |
||
5017 | /* need to put correct jump if && or || without test */ |
||
5018 | gsym(vtop->c.ul); |
||
5019 | } |
||
5020 | vtop--; |
||
5021 | } |
||
5022 | |||
5023 | /* convert stack entry to register and duplicate its value in another |
||
5024 | register */ |
||
5025 | void gv_dup(void) |
||
5026 | { |
||
5027 | int rc, t, r, r1; |
||
5028 | SValue sv; |
||
5029 | |||
5030 | t = vtop->type.t; |
||
5031 | if ((t & VT_BTYPE) == VT_LLONG) { |
||
5032 | lexpand(); |
||
5033 | gv_dup(); |
||
5034 | vswap(); |
||
5035 | vrotb(3); |
||
5036 | gv_dup(); |
||
5037 | vrotb(4); |
||
5038 | /* stack: H L L1 H1 */ |
||
5039 | lbuild(t); |
||
5040 | vrotb(3); |
||
5041 | vrotb(3); |
||
5042 | vswap(); |
||
5043 | lbuild(t); |
||
5044 | vswap(); |
||
5045 | } else { |
||
5046 | /* duplicate value */ |
||
5047 | rc = RC_INT; |
||
5048 | sv.type.t = VT_INT; |
||
5049 | if (is_float(t)) { |
||
5050 | rc = RC_FLOAT; |
||
5051 | sv.type.t = t; |
||
5052 | } |
||
5053 | r = gv(rc); |
||
5054 | r1 = get_reg(rc); |
||
5055 | sv.r = r; |
||
5056 | sv.c.ul = 0; |
||
5057 | load(r1, &sv); /* move r to r1 */ |
||
5058 | vdup(); |
||
5059 | /* duplicates value */ |
||
5060 | vtop->r = r1; |
||
5061 | } |
||
5062 | } |
||
5063 | |||
5064 | /* generate CPU independent (unsigned) long long operations */ |
||
5065 | void gen_opl(int op) |
||
5066 | { |
||
5067 | int t, a, b, op1, c, i; |
||
5068 | int func; |
||
5069 | SValue tmp; |
||
5070 | |||
5071 | switch(op) { |
||
5072 | case '/': |
||
5073 | case TOK_PDIV: |
||
5074 | func = TOK___divdi3; |
||
5075 | goto gen_func; |
||
5076 | case TOK_UDIV: |
||
5077 | func = TOK___udivdi3; |
||
5078 | goto gen_func; |
||
5079 | case '%': |
||
5080 | func = TOK___moddi3; |
||
5081 | goto gen_func; |
||
5082 | case TOK_UMOD: |
||
5083 | func = TOK___umoddi3; |
||
5084 | gen_func: |
||
5085 | /* call generic long long function */ |
||
5086 | vpush_global_sym(&func_old_type, func); |
||
5087 | vrott(3); |
||
5088 | gfunc_call(2); |
||
5089 | vpushi(0); |
||
5090 | vtop->r = REG_IRET; |
||
5091 | vtop->r2 = REG_LRET; |
||
5092 | break; |
||
5093 | case '^': |
||
5094 | case '&': |
||
5095 | case '|': |
||
5096 | case '*': |
||
5097 | case '+': |
||
5098 | case '-': |
||
5099 | t = vtop->type.t; |
||
5100 | vswap(); |
||
5101 | lexpand(); |
||
5102 | vrotb(3); |
||
5103 | lexpand(); |
||
5104 | /* stack: L1 H1 L2 H2 */ |
||
5105 | tmp = vtop[0]; |
||
5106 | vtop[0] = vtop[-3]; |
||
5107 | vtop[-3] = tmp; |
||
5108 | tmp = vtop[-2]; |
||
5109 | vtop[-2] = vtop[-3]; |
||
5110 | vtop[-3] = tmp; |
||
5111 | vswap(); |
||
5112 | /* stack: H1 H2 L1 L2 */ |
||
5113 | if (op == '*') { |
||
5114 | vpushv(vtop - 1); |
||
5115 | vpushv(vtop - 1); |
||
5116 | gen_op(TOK_UMULL); |
||
5117 | lexpand(); |
||
5118 | /* stack: H1 H2 L1 L2 ML MH */ |
||
5119 | for(i=0;i<4;i++) |
||
5120 | vrotb(6); |
||
5121 | /* stack: ML MH H1 H2 L1 L2 */ |
||
5122 | tmp = vtop[0]; |
||
5123 | vtop[0] = vtop[-2]; |
||
5124 | vtop[-2] = tmp; |
||
5125 | /* stack: ML MH H1 L2 H2 L1 */ |
||
5126 | gen_op('*'); |
||
5127 | vrotb(3); |
||
5128 | vrotb(3); |
||
5129 | gen_op('*'); |
||
5130 | /* stack: ML MH M1 M2 */ |
||
5131 | gen_op('+'); |
||
5132 | gen_op('+'); |
||
5133 | } else if (op == '+' || op == '-') { |
||
5134 | /* XXX: add non carry method too (for MIPS or alpha) */ |
||
5135 | if (op == '+') |
||
5136 | op1 = TOK_ADDC1; |
||
5137 | else |
||
5138 | op1 = TOK_SUBC1; |
||
5139 | gen_op(op1); |
||
5140 | /* stack: H1 H2 (L1 op L2) */ |
||
5141 | vrotb(3); |
||
5142 | vrotb(3); |
||
5143 | gen_op(op1 + 1); /* TOK_xxxC2 */ |
||
5144 | } else { |
||
5145 | gen_op(op); |
||
5146 | /* stack: H1 H2 (L1 op L2) */ |
||
5147 | vrotb(3); |
||
5148 | vrotb(3); |
||
5149 | /* stack: (L1 op L2) H1 H2 */ |
||
5150 | gen_op(op); |
||
5151 | /* stack: (L1 op L2) (H1 op H2) */ |
||
5152 | } |
||
5153 | /* stack: L H */ |
||
5154 | lbuild(t); |
||
5155 | break; |
||
5156 | case TOK_SAR: |
||
5157 | case TOK_SHR: |
||
5158 | case TOK_SHL: |
||
5159 | if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) { |
||
5160 | t = vtop[-1].type.t; |
||
5161 | vswap(); |
||
5162 | lexpand(); |
||
5163 | vrotb(3); |
||
5164 | /* stack: L H shift */ |
||
5165 | c = (int)vtop->c.i; |
||
5166 | /* constant: simpler */ |
||
5167 | /* NOTE: all comments are for SHL. the other cases are |
||
5168 | done by swaping words */ |
||
5169 | vpop(); |
||
5170 | if (op != TOK_SHL) |
||
5171 | vswap(); |
||
5172 | if (c >= 32) { |
||
5173 | /* stack: L H */ |
||
5174 | vpop(); |
||
5175 | if (c > 32) { |
||
5176 | vpushi(c - 32); |
||
5177 | gen_op(op); |
||
5178 | } |
||
5179 | if (op != TOK_SAR) { |
||
5180 | vpushi(0); |
||
5181 | } else { |
||
5182 | gv_dup(); |
||
5183 | vpushi(31); |
||
5184 | gen_op(TOK_SAR); |
||
5185 | } |
||
5186 | vswap(); |
||
5187 | } else { |
||
5188 | vswap(); |
||
5189 | gv_dup(); |
||
5190 | /* stack: H L L */ |
||
5191 | vpushi(c); |
||
5192 | gen_op(op); |
||
5193 | vswap(); |
||
5194 | vpushi(32 - c); |
||
5195 | if (op == TOK_SHL) |
||
5196 | gen_op(TOK_SHR); |
||
5197 | else |
||
5198 | gen_op(TOK_SHL); |
||
5199 | vrotb(3); |
||
5200 | /* stack: L L H */ |
||
5201 | vpushi(c); |
||
5202 | if (op == TOK_SHL) |
||
5203 | gen_op(TOK_SHL); |
||
5204 | else |
||
5205 | gen_op(TOK_SHR); |
||
5206 | gen_op('|'); |
||
5207 | } |
||
5208 | if (op != TOK_SHL) |
||
5209 | vswap(); |
||
5210 | lbuild(t); |
||
5211 | } else { |
||
5212 | /* XXX: should provide a faster fallback on x86 ? */ |
||
5213 | switch(op) { |
||
5214 | case TOK_SAR: |
||
5215 | func = TOK___sardi3; |
||
5216 | goto gen_func; |
||
5217 | case TOK_SHR: |
||
5218 | func = TOK___shrdi3; |
||
5219 | goto gen_func; |
||
5220 | case TOK_SHL: |
||
5221 | func = TOK___shldi3; |
||
5222 | goto gen_func; |
||
5223 | } |
||
5224 | } |
||
5225 | break; |
||
5226 | default: |
||
5227 | /* compare operations */ |
||
5228 | t = vtop->type.t; |
||
5229 | vswap(); |
||
5230 | lexpand(); |
||
5231 | vrotb(3); |
||
5232 | lexpand(); |
||
5233 | /* stack: L1 H1 L2 H2 */ |
||
5234 | tmp = vtop[-1]; |
||
5235 | vtop[-1] = vtop[-2]; |
||
5236 | vtop[-2] = tmp; |
||
5237 | /* stack: L1 L2 H1 H2 */ |
||
5238 | /* compare high */ |
||
5239 | op1 = op; |
||
5240 | /* when values are equal, we need to compare low words. since |
||
5241 | the jump is inverted, we invert the test too. */ |
||
5242 | if (op1 == TOK_LT) |
||
5243 | op1 = TOK_LE; |
||
5244 | else if (op1 == TOK_GT) |
||
5245 | op1 = TOK_GE; |
||
5246 | else if (op1 == TOK_ULT) |
||
5247 | op1 = TOK_ULE; |
||
5248 | else if (op1 == TOK_UGT) |
||
5249 | op1 = TOK_UGE; |
||
5250 | a = 0; |
||
5251 | b = 0; |
||
5252 | gen_op(op1); |
||
5253 | if (op1 != TOK_NE) { |
||
5254 | a = gtst(1, 0); |
||
5255 | } |
||
5256 | if (op != TOK_EQ) { |
||
5257 | /* generate non equal test */ |
||
5258 | /* XXX: NOT PORTABLE yet */ |
||
5259 | if (a == 0) { |
||
5260 | b = gtst(0, 0); |
||
5261 | } else { |
||
5262 | #if defined(TCC_TARGET_I386) |
||
5263 | b = psym(0x850f, 0); |
||
5264 | #elif defined(TCC_TARGET_ARM) |
||
5265 | b = ind; |
||
5266 | o(0x1A000000 | encbranch(ind, 0, 1)); |
||
5267 | #elif defined(TCC_TARGET_C67) |
||
5268 | error("not implemented"); |
||
5269 | #else |
||
5270 | #error not supported |
||
5271 | #endif |
||
5272 | } |
||
5273 | } |
||
5274 | /* compare low. Always unsigned */ |
||
5275 | op1 = op; |
||
5276 | if (op1 == TOK_LT) |
||
5277 | op1 = TOK_ULT; |
||
5278 | else if (op1 == TOK_LE) |
||
5279 | op1 = TOK_ULE; |
||
5280 | else if (op1 == TOK_GT) |
||
5281 | op1 = TOK_UGT; |
||
5282 | else if (op1 == TOK_GE) |
||
5283 | op1 = TOK_UGE; |
||
5284 | gen_op(op1); |
||
5285 | a = gtst(1, a); |
||
5286 | gsym(b); |
||
5287 | vseti(VT_JMPI, a); |
||
5288 | break; |
||
5289 | } |
||
5290 | } |
||
5291 | |||
5292 | /* handle integer constant optimizations and various machine |
||
5293 | independent opt */ |
||
5294 | void gen_opic(int op) |
||
5295 | { |
||
5296 | int fc, c1, c2, n; |
||
5297 | SValue *v1, *v2; |
||
5298 | |||
5299 | v1 = vtop - 1; |
||
5300 | v2 = vtop; |
||
5301 | /* currently, we cannot do computations with forward symbols */ |
||
5302 | c1 = (v1->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; |
||
5303 | c2 = (v2->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; |
||
5304 | if (c1 && c2) { |
||
5305 | fc = v2->c.i; |
||
5306 | switch(op) { |
||
5307 | case '+': v1->c.i += fc; break; |
||
5308 | case '-': v1->c.i -= fc; break; |
||
5309 | case '&': v1->c.i &= fc; break; |
||
5310 | case '^': v1->c.i ^= fc; break; |
||
5311 | case '|': v1->c.i |= fc; break; |
||
5312 | case '*': v1->c.i *= fc; break; |
||
5313 | |||
5314 | case TOK_PDIV: |
||
5315 | case '/': |
||
5316 | case '%': |
||
5317 | case TOK_UDIV: |
||
5318 | case TOK_UMOD: |
||
5319 | /* if division by zero, generate explicit division */ |
||
5320 | if (fc == 0) { |
||
5321 | if (const_wanted) |
||
5322 | error("division by zero in constant"); |
||
5323 | goto general_case; |
||
5324 | } |
||
5325 | switch(op) { |
||
5326 | default: v1->c.i /= fc; break; |
||
5327 | case '%': v1->c.i %= fc; break; |
||
5328 | case TOK_UDIV: v1->c.i = (unsigned)v1->c.i / fc; break; |
||
5329 | case TOK_UMOD: v1->c.i = (unsigned)v1->c.i % fc; break; |
||
5330 | } |
||
5331 | break; |
||
5332 | case TOK_SHL: v1->c.i <<= fc; break; |
||
5333 | case TOK_SHR: v1->c.i = (unsigned)v1->c.i >> fc; break; |
||
5334 | case TOK_SAR: v1->c.i >>= fc; break; |
||
5335 | /* tests */ |
||
5336 | case TOK_ULT: v1->c.i = (unsigned)v1->c.i < (unsigned)fc; break; |
||
5337 | case TOK_UGE: v1->c.i = (unsigned)v1->c.i >= (unsigned)fc; break; |
||
5338 | case TOK_EQ: v1->c.i = v1->c.i == fc; break; |
||
5339 | case TOK_NE: v1->c.i = v1->c.i != fc; break; |
||
5340 | case TOK_ULE: v1->c.i = (unsigned)v1->c.i <= (unsigned)fc; break; |
||
5341 | case TOK_UGT: v1->c.i = (unsigned)v1->c.i > (unsigned)fc; break; |
||
5342 | case TOK_LT: v1->c.i = v1->c.i < fc; break; |
||
5343 | case TOK_GE: v1->c.i = v1->c.i >= fc; break; |
||
5344 | case TOK_LE: v1->c.i = v1->c.i <= fc; break; |
||
5345 | case TOK_GT: v1->c.i = v1->c.i > fc; break; |
||
5346 | /* logical */ |
||
5347 | case TOK_LAND: v1->c.i = v1->c.i && fc; break; |
||
5348 | case TOK_LOR: v1->c.i = v1->c.i || fc; break; |
||
5349 | default: |
||
5350 | goto general_case; |
||
5351 | } |
||
5352 | vtop--; |
||
5353 | } else { |
||
5354 | /* if commutative ops, put c2 as constant */ |
||
5355 | if (c1 && (op == '+' || op == '&' || op == '^' || |
||
5356 | op == '|' || op == '*')) { |
||
5357 | vswap(); |
||
5358 | swap(&c1, &c2); |
||
5359 | } |
||
5360 | fc = vtop->c.i; |
||
5361 | if (c2 && (((op == '*' || op == '/' || op == TOK_UDIV || |
||
5362 | op == TOK_PDIV) && |
||
5363 | fc == 1) || |
||
5364 | ((op == '+' || op == '-' || op == '|' || op == '^' || |
||
5365 | op == TOK_SHL || op == TOK_SHR || op == TOK_SAR) && |
||
5366 | fc == 0) || |
||
5367 | (op == '&' && |
||
5368 | fc == -1))) { |
||
5369 | /* nothing to do */ |
||
5370 | vtop--; |
||
5371 | } else if (c2 && (op == '*' || op == TOK_PDIV || op == TOK_UDIV)) { |
||
5372 | /* try to use shifts instead of muls or divs */ |
||
5373 | if (fc > 0 && (fc & (fc - 1)) == 0) { |
||
5374 | n = -1; |
||
5375 | while (fc) { |
||
5376 | fc >>= 1; |
||
5377 | n++; |
||
5378 | } |
||
5379 | vtop->c.i = n; |
||
5380 | if (op == '*') |
||
5381 | op = TOK_SHL; |
||
5382 | else if (op == TOK_PDIV) |
||
5383 | op = TOK_SAR; |
||
5384 | else |
||
5385 | op = TOK_SHR; |
||
5386 | } |
||
5387 | goto general_case; |
||
5388 | } else if (c2 && (op == '+' || op == '-') && |
||
5389 | (vtop[-1].r & (VT_VALMASK | VT_LVAL | VT_SYM)) == |
||
5390 | (VT_CONST | VT_SYM)) { |
||
5391 | /* symbol + constant case */ |
||
5392 | if (op == '-') |
||
5393 | fc = -fc; |
||
5394 | vtop--; |
||
5395 | vtop->c.i += fc; |
||
5396 | } else { |
||
5397 | general_case: |
||
5398 | if (!nocode_wanted) { |
||
5399 | /* call low level op generator */ |
||
5400 | gen_opi(op); |
||
5401 | } else { |
||
5402 | vtop--; |
||
5403 | } |
||
5404 | } |
||
5405 | } |
||
5406 | } |
||
5407 | |||
5408 | /* generate a floating point operation with constant propagation */ |
||
5409 | void gen_opif(int op) |
||
5410 | { |
||
5411 | int c1, c2; |
||
5412 | SValue *v1, *v2; |
||
5413 | long double f1, f2; |
||
5414 | |||
5415 | v1 = vtop - 1; |
||
5416 | v2 = vtop; |
||
5417 | /* currently, we cannot do computations with forward symbols */ |
||
5418 | c1 = (v1->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; |
||
5419 | c2 = (v2->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; |
||
5420 | if (c1 && c2) { |
||
5421 | if (v1->type.t == VT_FLOAT) { |
||
5422 | f1 = v1->c.f; |
||
5423 | f2 = v2->c.f; |
||
5424 | } else if (v1->type.t == VT_DOUBLE) { |
||
5425 | f1 = v1->c.d; |
||
5426 | f2 = v2->c.d; |
||
5427 | } else { |
||
5428 | f1 = v1->c.ld; |
||
5429 | f2 = v2->c.ld; |
||
5430 | } |
||
5431 | |||
5432 | /* NOTE: we only do constant propagation if finite number (not |
||
5433 | NaN or infinity) (ANSI spec) */ |
||
5434 | if (!ieee_finite(f1) || !ieee_finite(f2)) |
||
5435 | goto general_case; |
||
5436 | |||
5437 | switch(op) { |
||
5438 | case '+': f1 += f2; break; |
||
5439 | case '-': f1 -= f2; break; |
||
5440 | case '*': f1 *= f2; break; |
||
5441 | case '/': |
||
5442 | if (f2 == 0.0) { |
||
5443 | if (const_wanted) |
||
5444 | error("division by zero in constant"); |
||
5445 | goto general_case; |
||
5446 | } |
||
5447 | f1 /= f2; |
||
5448 | break; |
||
5449 | /* XXX: also handles tests ? */ |
||
5450 | default: |
||
5451 | goto general_case; |
||
5452 | } |
||
5453 | /* XXX: overflow test ? */ |
||
5454 | if (v1->type.t == VT_FLOAT) { |
||
5455 | v1->c.f = f1; |
||
5456 | } else if (v1->type.t == VT_DOUBLE) { |
||
5457 | v1->c.d = f1; |
||
5458 | } else { |
||
5459 | v1->c.ld = f1; |
||
5460 | } |
||
5461 | vtop--; |
||
5462 | } else { |
||
5463 | general_case: |
||
5464 | if (!nocode_wanted) { |
||
5465 | gen_opf(op); |
||
5466 | } else { |
||
5467 | vtop--; |
||
5468 | } |
||
5469 | } |
||
5470 | } |
||
5471 | |||
5472 | static int pointed_size(CType *type) |
||
5473 | { |
||
5474 | int align; |
||
5475 | return type_size(pointed_type(type), &align); |
||
5476 | } |
||
5477 | |||
5478 | static inline int is_null_pointer(SValue *p) |
||
5479 | { |
||
5480 | if ((p->r & (VT_VALMASK | VT_LVAL | VT_SYM)) != VT_CONST) |
||
5481 | return 0; |
||
5482 | return ((p->type.t & VT_BTYPE) == VT_INT && p->c.i == 0) || |
||
5483 | ((p->type.t & VT_BTYPE) == VT_LLONG && p->c.ll == 0); |
||
5484 | } |
||
5485 | |||
5486 | static inline int is_integer_btype(int bt) |
||
5487 | { |
||
5488 | return (bt == VT_BYTE || bt == VT_SHORT || |
||
5489 | bt == VT_INT || bt == VT_LLONG); |
||
5490 | } |
||
5491 | |||
5492 | /* check types for comparison or substraction of pointers */ |
||
5493 | static void check_comparison_pointer_types(SValue *p1, SValue *p2, int op) |
||
5494 | { |
||
5495 | CType *type1, *type2, tmp_type1, tmp_type2; |
||
5496 | int bt1, bt2; |
||
5497 | |||
5498 | /* null pointers are accepted for all comparisons as gcc */ |
||
5499 | if (is_null_pointer(p1) || is_null_pointer(p2)) |
||
5500 | return; |
||
5501 | type1 = &p1->type; |
||
5502 | type2 = &p2->type; |
||
5503 | bt1 = type1->t & VT_BTYPE; |
||
5504 | bt2 = type2->t & VT_BTYPE; |
||
5505 | /* accept comparison between pointer and integer with a warning */ |
||
5506 | if ((is_integer_btype(bt1) || is_integer_btype(bt2)) && op != '-') { |
||
5507 | warning("comparison between pointer and integer"); |
||
5508 | return; |
||
5509 | } |
||
5510 | |||
5511 | /* both must be pointers or implicit function pointers */ |
||
5512 | if (bt1 == VT_PTR) { |
||
5513 | type1 = pointed_type(type1); |
||
5514 | } else if (bt1 != VT_FUNC) |
||
5515 | goto invalid_operands; |
||
5516 | |||
5517 | if (bt2 == VT_PTR) { |
||
5518 | type2 = pointed_type(type2); |
||
5519 | } else if (bt2 != VT_FUNC) { |
||
5520 | invalid_operands: |
||
5521 | error("invalid operands to binary %s", get_tok_str(op, NULL)); |
||
5522 | } |
||
5523 | if ((type1->t & VT_BTYPE) == VT_VOID || |
||
5524 | (type2->t & VT_BTYPE) == VT_VOID) |
||
5525 | return; |
||
5526 | tmp_type1 = *type1; |
||
5527 | tmp_type2 = *type2; |
||
5528 | tmp_type1.t &= ~(VT_UNSIGNED | VT_CONSTANT | VT_VOLATILE); |
||
5529 | tmp_type2.t &= ~(VT_UNSIGNED | VT_CONSTANT | VT_VOLATILE); |
||
5530 | if (!is_compatible_types(&tmp_type1, &tmp_type2)) { |
||
5531 | /* gcc-like error if '-' is used */ |
||
5532 | if (op == '-') |
||
5533 | goto invalid_operands; |
||
5534 | else |
||
5535 | warning("comparison of distinct pointer types lacks a cast"); |
||
5536 | } |
||
5537 | } |
||
5538 | |||
5539 | /* generic gen_op: handles types problems */ |
||
5540 | void gen_op(int op) |
||
5541 | { |
||
5542 | int u, t1, t2, bt1, bt2, t; |
||
5543 | CType type1; |
||
5544 | |||
5545 | t1 = vtop[-1].type.t; |
||
5546 | t2 = vtop[0].type.t; |
||
5547 | bt1 = t1 & VT_BTYPE; |
||
5548 | bt2 = t2 & VT_BTYPE; |
||
5549 | |||
5550 | if (bt1 == VT_PTR || bt2 == VT_PTR) { |
||
5551 | /* at least one operand is a pointer */ |
||
5552 | /* relationnal op: must be both pointers */ |
||
5553 | if (op >= TOK_ULT && op <= TOK_GT) { |
||
5554 | check_comparison_pointer_types(vtop - 1, vtop, op); |
||
5555 | /* pointers are handled are unsigned */ |
||
5556 | t = VT_INT | VT_UNSIGNED; |
||
5557 | goto std_op; |
||
5558 | } |
||
5559 | /* if both pointers, then it must be the '-' op */ |
||
5560 | if (bt1 == VT_PTR && bt2 == VT_PTR) { |
||
5561 | if (op != '-') |
||
5562 | error("cannot use pointers here"); |
||
5563 | check_comparison_pointer_types(vtop - 1, vtop, op); |
||
5564 | /* XXX: check that types are compatible */ |
||
5565 | u = pointed_size(&vtop[-1].type); |
||
5566 | gen_opic(op); |
||
5567 | /* set to integer type */ |
||
5568 | vtop->type.t = VT_INT; |
||
5569 | vpushi(u); |
||
5570 | gen_op(TOK_PDIV); |
||
5571 | } else { |
||
5572 | /* exactly one pointer : must be '+' or '-'. */ |
||
5573 | if (op != '-' && op != '+') |
||
5574 | error("cannot use pointers here"); |
||
5575 | /* Put pointer as first operand */ |
||
5576 | if (bt2 == VT_PTR) { |
||
5577 | vswap(); |
||
5578 | swap(&t1, &t2); |
||
5579 | } |
||
5580 | type1 = vtop[-1].type; |
||
5581 | /* XXX: cast to int ? (long long case) */ |
||
5582 | vpushi(pointed_size(&vtop[-1].type)); |
||
5583 | gen_op('*'); |
||
5584 | #ifdef CONFIG_TCC_BCHECK |
||
5585 | /* if evaluating constant expression, no code should be |
||
5586 | generated, so no bound check */ |
||
5587 | if (do_bounds_check && !const_wanted) { |
||
5588 | /* if bounded pointers, we generate a special code to |
||
5589 | test bounds */ |
||
5590 | if (op == '-') { |
||
5591 | vpushi(0); |
||
5592 | vswap(); |
||
5593 | gen_op('-'); |
||
5594 | } |
||
5595 | gen_bounded_ptr_add(); |
||
5596 | } else |
||
5597 | #endif |
||
5598 | { |
||
5599 | gen_opic(op); |
||
5600 | } |
||
5601 | /* put again type if gen_opic() swaped operands */ |
||
5602 | vtop->type = type1; |
||
5603 | } |
||
5604 | } else if (is_float(bt1) || is_float(bt2)) { |
||
5605 | /* compute bigger type and do implicit casts */ |
||
5606 | if (bt1 == VT_LDOUBLE || bt2 == VT_LDOUBLE) { |
||
5607 | t = VT_LDOUBLE; |
||
5608 | } else if (bt1 == VT_DOUBLE || bt2 == VT_DOUBLE) { |
||
5609 | t = VT_DOUBLE; |
||
5610 | } else { |
||
5611 | t = VT_FLOAT; |
||
5612 | } |
||
5613 | /* floats can only be used for a few operations */ |
||
5614 | if (op != '+' && op != '-' && op != '*' && op != '/' && |
||
5615 | (op < TOK_ULT || op > TOK_GT)) |
||
5616 | error("invalid operands for binary operation"); |
||
5617 | goto std_op; |
||
5618 | } else if (bt1 == VT_LLONG || bt2 == VT_LLONG) { |
||
5619 | /* cast to biggest op */ |
||
5620 | t = VT_LLONG; |
||
5621 | /* convert to unsigned if it does not fit in a long long */ |
||
5622 | if ((t1 & (VT_BTYPE | VT_UNSIGNED)) == (VT_LLONG | VT_UNSIGNED) || |
||
5623 | (t2 & (VT_BTYPE | VT_UNSIGNED)) == (VT_LLONG | VT_UNSIGNED)) |
||
5624 | t |= VT_UNSIGNED; |
||
5625 | goto std_op; |
||
5626 | } else { |
||
5627 | /* integer operations */ |
||
5628 | t = VT_INT; |
||
5629 | /* convert to unsigned if it does not fit in an integer */ |
||
5630 | if ((t1 & (VT_BTYPE | VT_UNSIGNED)) == (VT_INT | VT_UNSIGNED) || |
||
5631 | (t2 & (VT_BTYPE | VT_UNSIGNED)) == (VT_INT | VT_UNSIGNED)) |
||
5632 | t |= VT_UNSIGNED; |
||
5633 | std_op: |
||
5634 | /* XXX: currently, some unsigned operations are explicit, so |
||
5635 | we modify them here */ |
||
5636 | if (t & VT_UNSIGNED) { |
||
5637 | if (op == TOK_SAR) |
||
5638 | op = TOK_SHR; |
||
5639 | else if (op == '/') |
||
5640 | op = TOK_UDIV; |
||
5641 | else if (op == '%') |
||
5642 | op = TOK_UMOD; |
||
5643 | else if (op == TOK_LT) |
||
5644 | op = TOK_ULT; |
||
5645 | else if (op == TOK_GT) |
||
5646 | op = TOK_UGT; |
||
5647 | else if (op == TOK_LE) |
||
5648 | op = TOK_ULE; |
||
5649 | else if (op == TOK_GE) |
||
5650 | op = TOK_UGE; |
||
5651 | } |
||
5652 | vswap(); |
||
5653 | type1.t = t; |
||
5654 | gen_cast(&type1); |
||
5655 | vswap(); |
||
5656 | /* special case for shifts and long long: we keep the shift as |
||
5657 | an integer */ |
||
5658 | if (op == TOK_SHR || op == TOK_SAR || op == TOK_SHL) |
||
5659 | type1.t = VT_INT; |
||
5660 | gen_cast(&type1); |
||
5661 | if (is_float(t)) |
||
5662 | gen_opif(op); |
||
5663 | else if ((t & VT_BTYPE) == VT_LLONG) |
||
5664 | gen_opl(op); |
||
5665 | else |
||
5666 | gen_opic(op); |
||
5667 | if (op >= TOK_ULT && op <= TOK_GT) { |
||
5668 | /* relationnal op: the result is an int */ |
||
5669 | vtop->type.t = VT_INT; |
||
5670 | } else { |
||
5671 | vtop->type.t = t; |
||
5672 | } |
||
5673 | } |
||
5674 | } |
||
5675 | |||
5676 | /* generic itof for unsigned long long case */ |
||
5677 | void gen_cvt_itof1(int t) |
||
5678 | { |
||
5679 | if ((vtop->type.t & (VT_BTYPE | VT_UNSIGNED)) == |
||
5680 | (VT_LLONG | VT_UNSIGNED)) { |
||
5681 | |||
5682 | if (t == VT_FLOAT) |
||
5683 | vpush_global_sym(&func_old_type, TOK___ulltof); |
||
5684 | else if (t == VT_DOUBLE) |
||
5685 | vpush_global_sym(&func_old_type, TOK___ulltod); |
||
5686 | else |
||
5687 | vpush_global_sym(&func_old_type, TOK___ulltold); |
||
5688 | vrott(2); |
||
5689 | gfunc_call(1); |
||
5690 | vpushi(0); |
||
5691 | vtop->r = REG_FRET; |
||
5692 | } else { |
||
5693 | gen_cvt_itof(t); |
||
5694 | } |
||
5695 | } |
||
5696 | |||
5697 | /* generic ftoi for unsigned long long case */ |
||
5698 | void gen_cvt_ftoi1(int t) |
||
5699 | { |
||
5700 | int st; |
||
5701 | |||
5702 | if (t == (VT_LLONG | VT_UNSIGNED)) { |
||
5703 | /* not handled natively */ |
||
5704 | st = vtop->type.t & VT_BTYPE; |
||
5705 | if (st == VT_FLOAT) |
||
5706 | vpush_global_sym(&func_old_type, TOK___fixunssfdi); |
||
5707 | else if (st == VT_DOUBLE) |
||
5708 | vpush_global_sym(&func_old_type, TOK___fixunsdfdi); |
||
5709 | else |
||
5710 | vpush_global_sym(&func_old_type, TOK___fixunsxfdi); |
||
5711 | vrott(2); |
||
5712 | gfunc_call(1); |
||
5713 | vpushi(0); |
||
5714 | vtop->r = REG_IRET; |
||
5715 | vtop->r2 = REG_LRET; |
||
5716 | } else { |
||
5717 | gen_cvt_ftoi(t); |
||
5718 | } |
||
5719 | } |
||
5720 | |||
5721 | /* force char or short cast */ |
||
5722 | void force_charshort_cast(int t) |
||
5723 | { |
||
5724 | int bits, dbt; |
||
5725 | dbt = t & VT_BTYPE; |
||
5726 | /* XXX: add optimization if lvalue : just change type and offset */ |
||
5727 | if (dbt == VT_BYTE) |
||
5728 | bits = 8; |
||
5729 | else |
||
5730 | bits = 16; |
||
5731 | if (t & VT_UNSIGNED) { |
||
5732 | vpushi((1 << bits) - 1); |
||
5733 | gen_op('&'); |
||
5734 | } else { |
||
5735 | bits = 32 - bits; |
||
5736 | vpushi(bits); |
||
5737 | gen_op(TOK_SHL); |
||
5738 | vpushi(bits); |
||
5739 | gen_op(TOK_SAR); |
||
5740 | } |
||
5741 | } |
||
5742 | |||
5743 | /* cast 'vtop' to 'type'. Casting to bitfields is forbidden. */ |
||
5744 | static void gen_cast(CType *type) |
||
5745 | { |
||
5746 | int sbt, dbt, sf, df, c; |
||
5747 | |||
5748 | /* special delayed cast for char/short */ |
||
5749 | /* XXX: in some cases (multiple cascaded casts), it may still |
||
5750 | be incorrect */ |
||
5751 | if (vtop->r & VT_MUSTCAST) { |
||
5752 | vtop->r &= ~VT_MUSTCAST; |
||
5753 | force_charshort_cast(vtop->type.t); |
||
5754 | } |
||
5755 | |||
5756 | /* bitfields first get cast to ints */ |
||
5757 | if (vtop->type.t & VT_BITFIELD) { |
||
5758 | gv(RC_INT); |
||
5759 | } |
||
5760 | |||
5761 | dbt = type->t & (VT_BTYPE | VT_UNSIGNED); |
||
5762 | sbt = vtop->type.t & (VT_BTYPE | VT_UNSIGNED); |
||
5763 | |||
5764 | if (sbt != dbt && !nocode_wanted) { |
||
5765 | sf = is_float(sbt); |
||
5766 | df = is_float(dbt); |
||
5767 | c = (vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; |
||
5768 | if (sf && df) { |
||
5769 | /* convert from fp to fp */ |
||
5770 | if (c) { |
||
5771 | /* constant case: we can do it now */ |
||
5772 | /* XXX: in ISOC, cannot do it if error in convert */ |
||
5773 | if (dbt == VT_FLOAT && sbt == VT_DOUBLE) |
||
5774 | vtop->c.f = (float)vtop->c.d; |
||
5775 | else if (dbt == VT_FLOAT && sbt == VT_LDOUBLE) |
||
5776 | vtop->c.f = (float)vtop->c.ld; |
||
5777 | else if (dbt == VT_DOUBLE && sbt == VT_FLOAT) |
||
5778 | vtop->c.d = (double)vtop->c.f; |
||
5779 | else if (dbt == VT_DOUBLE && sbt == VT_LDOUBLE) |
||
5780 | vtop->c.d = (double)vtop->c.ld; |
||
5781 | else if (dbt == VT_LDOUBLE && sbt == VT_FLOAT) |
||
5782 | vtop->c.ld = (long double)vtop->c.f; |
||
5783 | else if (dbt == VT_LDOUBLE && sbt == VT_DOUBLE) |
||
5784 | vtop->c.ld = (long double)vtop->c.d; |
||
5785 | } else { |
||
5786 | /* non constant case: generate code */ |
||
5787 | gen_cvt_ftof(dbt); |
||
5788 | } |
||
5789 | } else if (df) { |
||
5790 | /* convert int to fp */ |
||
5791 | if (c) { |
||
5792 | switch(sbt) { |
||
5793 | case VT_LLONG | VT_UNSIGNED: |
||
5794 | case VT_LLONG: |
||
5795 | /* XXX: add const cases for long long */ |
||
5796 | goto do_itof; |
||
5797 | case VT_INT | VT_UNSIGNED: |
||
5798 | switch(dbt) { |
||
5799 | case VT_FLOAT: vtop->c.f = (float)vtop->c.ui; break; |
||
5800 | case VT_DOUBLE: vtop->c.d = (double)vtop->c.ui; break; |
||
5801 | case VT_LDOUBLE: vtop->c.ld = (long double)vtop->c.ui; break; |
||
5802 | } |
||
5803 | break; |
||
5804 | default: |
||
5805 | switch(dbt) { |
||
5806 | case VT_FLOAT: vtop->c.f = (float)vtop->c.i; break; |
||
5807 | case VT_DOUBLE: vtop->c.d = (double)vtop->c.i; break; |
||
5808 | case VT_LDOUBLE: vtop->c.ld = (long double)vtop->c.i; break; |
||
5809 | } |
||
5810 | break; |
||
5811 | } |
||
5812 | } else { |
||
5813 | do_itof: |
||
5814 | #if !defined(TCC_TARGET_ARM) |
||
5815 | gen_cvt_itof1(dbt); |
||
5816 | #else |
||
5817 | gen_cvt_itof(dbt); |
||
5818 | #endif |
||
5819 | } |
||
5820 | } else if (sf) { |
||
5821 | /* convert fp to int */ |
||
5822 | /* we handle char/short/etc... with generic code */ |
||
5823 | if (dbt != (VT_INT | VT_UNSIGNED) && |
||
5824 | dbt != (VT_LLONG | VT_UNSIGNED) && |
||
5825 | dbt != VT_LLONG) |
||
5826 | dbt = VT_INT; |
||
5827 | if (c) { |
||
5828 | switch(dbt) { |
||
5829 | case VT_LLONG | VT_UNSIGNED: |
||
5830 | case VT_LLONG: |
||
5831 | /* XXX: add const cases for long long */ |
||
5832 | goto do_ftoi; |
||
5833 | case VT_INT | VT_UNSIGNED: |
||
5834 | switch(sbt) { |
||
5835 | case VT_FLOAT: vtop->c.ui = (unsigned int)vtop->c.d; break; |
||
5836 | case VT_DOUBLE: vtop->c.ui = (unsigned int)vtop->c.d; break; |
||
5837 | case VT_LDOUBLE: vtop->c.ui = (unsigned int)vtop->c.d; break; |
||
5838 | } |
||
5839 | break; |
||
5840 | default: |
||
5841 | /* int case */ |
||
5842 | switch(sbt) { |
||
5843 | case VT_FLOAT: vtop->c.i = (int)vtop->c.d; break; |
||
5844 | case VT_DOUBLE: vtop->c.i = (int)vtop->c.d; break; |
||
5845 | case VT_LDOUBLE: vtop->c.i = (int)vtop->c.d; break; |
||
5846 | } |
||
5847 | break; |
||
5848 | } |
||
5849 | } else { |
||
5850 | do_ftoi: |
||
5851 | gen_cvt_ftoi1(dbt); |
||
5852 | } |
||
5853 | if (dbt == VT_INT && (type->t & (VT_BTYPE | VT_UNSIGNED)) != dbt) { |
||
5854 | /* additional cast for char/short/bool... */ |
||
5855 | vtop->type.t = dbt; |
||
5856 | gen_cast(type); |
||
5857 | } |
||
5858 | } else if ((dbt & VT_BTYPE) == VT_LLONG) { |
||
5859 | if ((sbt & VT_BTYPE) != VT_LLONG) { |
||
5860 | /* scalar to long long */ |
||
5861 | if (c) { |
||
5862 | if (sbt == (VT_INT | VT_UNSIGNED)) |
||
5863 | vtop->c.ll = vtop->c.ui; |
||
5864 | else |
||
5865 | vtop->c.ll = vtop->c.i; |
||
5866 | } else { |
||
5867 | /* machine independent conversion */ |
||
5868 | gv(RC_INT); |
||
5869 | /* generate high word */ |
||
5870 | if (sbt == (VT_INT | VT_UNSIGNED)) { |
||
5871 | vpushi(0); |
||
5872 | gv(RC_INT); |
||
5873 | } else { |
||
5874 | gv_dup(); |
||
5875 | vpushi(31); |
||
5876 | gen_op(TOK_SAR); |
||
5877 | } |
||
5878 | /* patch second register */ |
||
5879 | vtop[-1].r2 = vtop->r; |
||
5880 | vpop(); |
||
5881 | } |
||
5882 | } |
||
5883 | } else if (dbt == VT_BOOL) { |
||
5884 | /* scalar to bool */ |
||
5885 | vpushi(0); |
||
5886 | gen_op(TOK_NE); |
||
5887 | } else if ((dbt & VT_BTYPE) == VT_BYTE || |
||
5888 | (dbt & VT_BTYPE) == VT_SHORT) { |
||
5889 | force_charshort_cast(dbt); |
||
5890 | } else if ((dbt & VT_BTYPE) == VT_INT) { |
||
5891 | /* scalar to int */ |
||
5892 | if (sbt == VT_LLONG) { |
||
5893 | /* from long long: just take low order word */ |
||
5894 | lexpand(); |
||
5895 | vpop(); |
||
5896 | } |
||
5897 | /* if lvalue and single word type, nothing to do because |
||
5898 | the lvalue already contains the real type size (see |
||
5899 | VT_LVAL_xxx constants) */ |
||
5900 | } |
||
5901 | } |
||
5902 | vtop->type = *type; |
||
5903 | } |
||
5904 | |||
5905 | /* return type size. Put alignment at 'a' */ |
||
5906 | static int type_size(CType *type, int *a) |
||
5907 | { |
||
5908 | Sym *s; |
||
5909 | int bt; |
||
5910 | |||
5911 | bt = type->t & VT_BTYPE; |
||
5912 | if (bt == VT_STRUCT) { |
||
5913 | /* struct/union */ |
||
5914 | s = type->ref; |
||
5915 | *a = s->r; |
||
5916 | return s->c; |
||
5917 | } else if (bt == VT_PTR) { |
||
5918 | if (type->t & VT_ARRAY) { |
||
5919 | s = type->ref; |
||
5920 | return type_size(&s->type, a) * s->c; |
||
5921 | } else { |
||
5922 | *a = PTR_SIZE; |
||
5923 | return PTR_SIZE; |
||
5924 | } |
||
5925 | } else if (bt == VT_LDOUBLE) { |
||
5926 | *a = LDOUBLE_ALIGN; |
||
5927 | return LDOUBLE_SIZE; |
||
5928 | } else if (bt == VT_DOUBLE || bt == VT_LLONG) { |
||
5929 | #ifdef TCC_TARGET_I386 |
||
5930 | *a = 4; |
||
5931 | #else |
||
5932 | *a = 8; |
||
5933 | #endif |
||
5934 | return 8; |
||
5935 | } else if (bt == VT_INT || bt == VT_ENUM || bt == VT_FLOAT) { |
||
5936 | *a = 4; |
||
5937 | return 4; |
||
5938 | } else if (bt == VT_SHORT) { |
||
5939 | *a = 2; |
||
5940 | return 2; |
||
5941 | } else { |
||
5942 | /* char, void, function, _Bool */ |
||
5943 | *a = 1; |
||
5944 | return 1; |
||
5945 | } |
||
5946 | } |
||
5947 | |||
5948 | /* return the pointed type of t */ |
||
5949 | static inline CType *pointed_type(CType *type) |
||
5950 | { |
||
5951 | return &type->ref->type; |
||
5952 | } |
||
5953 | |||
5954 | /* modify type so that its it is a pointer to type. */ |
||
5955 | static void mk_pointer(CType *type) |
||
5956 | { |
||
5957 | Sym *s; |
||
5958 | s = sym_push(SYM_FIELD, type, 0, -1); |
||
5959 | type->t = VT_PTR | (type->t & ~VT_TYPE); |
||
5960 | type->ref = s; |
||
5961 | } |
||
5962 | |||
5963 | /* compare function types. OLD functions match any new functions */ |
||
5964 | static int is_compatible_func(CType *type1, CType *type2) |
||
5965 | { |
||
5966 | Sym *s1, *s2; |
||
5967 | |||
5968 | s1 = type1->ref; |
||
5969 | s2 = type2->ref; |
||
5970 | if (!is_compatible_types(&s1->type, &s2->type)) |
||
5971 | return 0; |
||
5972 | /* check func_call */ |
||
5973 | if (s1->r != s2->r) |
||
5974 | return 0; |
||
5975 | /* XXX: not complete */ |
||
5976 | if (s1->c == FUNC_OLD || s2->c == FUNC_OLD) |
||
5977 | return 1; |
||
5978 | if (s1->c != s2->c) |
||
5979 | return 0; |
||
5980 | while (s1 != NULL) { |
||
5981 | if (s2 == NULL) |
||
5982 | return 0; |
||
5983 | if (!is_compatible_types(&s1->type, &s2->type)) |
||
5984 | return 0; |
||
5985 | s1 = s1->next; |
||
5986 | s2 = s2->next; |
||
5987 | } |
||
5988 | if (s2) |
||
5989 | return 0; |
||
5990 | return 1; |
||
5991 | } |
||
5992 | |||
5993 | /* return true if type1 and type2 are exactly the same (including |
||
5994 | qualifiers). |
||
5995 | |||
5996 | - enums are not checked as gcc __builtin_types_compatible_p () |
||
5997 | */ |
||
5998 | static int is_compatible_types(CType *type1, CType *type2) |
||
5999 | { |
||
6000 | int bt1, t1, t2; |
||
6001 | |||
6002 | t1 = type1->t & VT_TYPE; |
||
6003 | t2 = type2->t & VT_TYPE; |
||
6004 | /* XXX: bitfields ? */ |
||
6005 | if (t1 != t2) |
||
6006 | return 0; |
||
6007 | /* test more complicated cases */ |
||
6008 | bt1 = t1 & VT_BTYPE; |
||
6009 | if (bt1 == VT_PTR) { |
||
6010 | type1 = pointed_type(type1); |
||
6011 | type2 = pointed_type(type2); |
||
6012 | return is_compatible_types(type1, type2); |
||
6013 | } else if (bt1 == VT_STRUCT) { |
||
6014 | return (type1->ref == type2->ref); |
||
6015 | } else if (bt1 == VT_FUNC) { |
||
6016 | return is_compatible_func(type1, type2); |
||
6017 | } else { |
||
6018 | return 1; |
||
6019 | } |
||
6020 | } |
||
6021 | |||
6022 | /* print a type. If 'varstr' is not NULL, then the variable is also |
||
6023 | printed in the type */ |
||
6024 | /* XXX: union */ |
||
6025 | /* XXX: add array and function pointers */ |
||
6026 | void type_to_str(char *buf, int buf_size, |
||
6027 | CType *type, const char *varstr) |
||
6028 | { |
||
6029 | int bt, v, t; |
||
6030 | Sym *s, *sa; |
||
6031 | char buf1[256]; |
||
6032 | const char *tstr; |
||
6033 | |||
6034 | t = type->t & VT_TYPE; |
||
6035 | bt = t & VT_BTYPE; |
||
6036 | buf[0] = '\0'; |
||
6037 | if (t & VT_CONSTANT) |
||
6038 | pstrcat(buf, buf_size, "const "); |
||
6039 | if (t & VT_VOLATILE) |
||
6040 | pstrcat(buf, buf_size, "volatile "); |
||
6041 | if (t & VT_UNSIGNED) |
||
6042 | pstrcat(buf, buf_size, "unsigned "); |
||
6043 | switch(bt) { |
||
6044 | case VT_VOID: |
||
6045 | tstr = "void"; |
||
6046 | goto add_tstr; |
||
6047 | case VT_BOOL: |
||
6048 | tstr = "_Bool"; |
||
6049 | goto add_tstr; |
||
6050 | case VT_BYTE: |
||
6051 | tstr = "char"; |
||
6052 | goto add_tstr; |
||
6053 | case VT_SHORT: |
||
6054 | tstr = "short"; |
||
6055 | goto add_tstr; |
||
6056 | case VT_INT: |
||
6057 | tstr = "int"; |
||
6058 | goto add_tstr; |
||
6059 | case VT_LONG: |
||
6060 | tstr = "long"; |
||
6061 | goto add_tstr; |
||
6062 | case VT_LLONG: |
||
6063 | tstr = "long long"; |
||
6064 | goto add_tstr; |
||
6065 | case VT_FLOAT: |
||
6066 | tstr = "float"; |
||
6067 | goto add_tstr; |
||
6068 | case VT_DOUBLE: |
||
6069 | tstr = "double"; |
||
6070 | goto add_tstr; |
||
6071 | case VT_LDOUBLE: |
||
6072 | tstr = "long double"; |
||
6073 | add_tstr: |
||
6074 | pstrcat(buf, buf_size, tstr); |
||
6075 | break; |
||
6076 | case VT_ENUM: |
||
6077 | case VT_STRUCT: |
||
6078 | if (bt == VT_STRUCT) |
||
6079 | tstr = "struct "; |
||
6080 | else |
||
6081 | tstr = "enum "; |
||
6082 | pstrcat(buf, buf_size, tstr); |
||
6083 | v = type->ref->v & ~SYM_STRUCT; |
||
6084 | if (v >= SYM_FIRST_ANOM) |
||
6085 | pstrcat(buf, buf_size, " |
||
6086 | else |
||
6087 | pstrcat(buf, buf_size, get_tok_str(v, NULL)); |
||
6088 | break; |
||
6089 | case VT_FUNC: |
||
6090 | s = type->ref; |
||
6091 | type_to_str(buf, buf_size, &s->type, varstr); |
||
6092 | pstrcat(buf, buf_size, "("); |
||
6093 | sa = s->next; |
||
6094 | while (sa != NULL) { |
||
6095 | type_to_str(buf1, sizeof(buf1), &sa->type, NULL); |
||
6096 | pstrcat(buf, buf_size, buf1); |
||
6097 | sa = sa->next; |
||
6098 | if (sa) |
||
6099 | pstrcat(buf, buf_size, ", "); |
||
6100 | } |
||
6101 | pstrcat(buf, buf_size, ")"); |
||
6102 | goto no_var; |
||
6103 | case VT_PTR: |
||
6104 | s = type->ref; |
||
6105 | pstrcpy(buf1, sizeof(buf1), "*"); |
||
6106 | if (varstr) |
||
6107 | pstrcat(buf1, sizeof(buf1), varstr); |
||
6108 | type_to_str(buf, buf_size, &s->type, buf1); |
||
6109 | goto no_var; |
||
6110 | } |
||
6111 | if (varstr) { |
||
6112 | pstrcat(buf, buf_size, " "); |
||
6113 | pstrcat(buf, buf_size, varstr); |
||
6114 | } |
||
6115 | no_var: ; |
||
6116 | } |
||
6117 | |||
6118 | /* verify type compatibility to store vtop in 'dt' type, and generate |
||
6119 | casts if needed. */ |
||
6120 | static void gen_assign_cast(CType *dt) |
||
6121 | { |
||
6122 | CType *st, *type1, *type2, tmp_type1, tmp_type2; |
||
6123 | char buf1[256], buf2[256]; |
||
6124 | int dbt, sbt; |
||
6125 | |||
6126 | st = &vtop->type; /* source type */ |
||
6127 | dbt = dt->t & VT_BTYPE; |
||
6128 | sbt = st->t & VT_BTYPE; |
||
6129 | if (dt->t & VT_CONSTANT) |
||
6130 | warning("assignment of read-only location"); |
||
6131 | switch(dbt) { |
||
6132 | case VT_PTR: |
||
6133 | /* special cases for pointers */ |
||
6134 | /* '0' can also be a pointer */ |
||
6135 | if (is_null_pointer(vtop)) |
||
6136 | goto type_ok; |
||
6137 | /* accept implicit pointer to integer cast with warning */ |
||
6138 | if (is_integer_btype(sbt)) { |
||
6139 | warning("assignment makes pointer from integer without a cast"); |
||
6140 | goto type_ok; |
||
6141 | } |
||
6142 | type1 = pointed_type(dt); |
||
6143 | /* a function is implicitely a function pointer */ |
||
6144 | if (sbt == VT_FUNC) { |
||
6145 | if ((type1->t & VT_BTYPE) != VT_VOID && |
||
6146 | !is_compatible_types(pointed_type(dt), st)) |
||
6147 | goto error; |
||
6148 | else |
||
6149 | goto type_ok; |
||
6150 | } |
||
6151 | if (sbt != VT_PTR) |
||
6152 | goto error; |
||
6153 | type2 = pointed_type(st); |
||
6154 | if ((type1->t & VT_BTYPE) == VT_VOID || |
||
6155 | (type2->t & VT_BTYPE) == VT_VOID) { |
||
6156 | /* void * can match anything */ |
||
6157 | } else { |
||
6158 | /* exact type match, except for unsigned */ |
||
6159 | tmp_type1 = *type1; |
||
6160 | tmp_type2 = *type2; |
||
6161 | tmp_type1.t &= ~(VT_UNSIGNED | VT_CONSTANT | VT_VOLATILE); |
||
6162 | tmp_type2.t &= ~(VT_UNSIGNED | VT_CONSTANT | VT_VOLATILE); |
||
6163 | if (!is_compatible_types(&tmp_type1, &tmp_type2)) |
||
6164 | goto error; |
||
6165 | } |
||
6166 | /* check const and volatile */ |
||
6167 | if ((!(type1->t & VT_CONSTANT) && (type2->t & VT_CONSTANT)) || |
||
6168 | (!(type1->t & VT_VOLATILE) && (type2->t & VT_VOLATILE))) |
||
6169 | warning("assignment discards qualifiers from pointer target type"); |
||
6170 | break; |
||
6171 | case VT_BYTE: |
||
6172 | case VT_SHORT: |
||
6173 | case VT_INT: |
||
6174 | case VT_LLONG: |
||
6175 | if (sbt == VT_PTR || sbt == VT_FUNC) { |
||
6176 | warning("assignment makes integer from pointer without a cast"); |
||
6177 | } |
||
6178 | /* XXX: more tests */ |
||
6179 | break; |
||
6180 | case VT_STRUCT: |
||
6181 | tmp_type1 = *dt; |
||
6182 | tmp_type2 = *st; |
||
6183 | tmp_type1.t &= ~(VT_CONSTANT | VT_VOLATILE); |
||
6184 | tmp_type2.t &= ~(VT_CONSTANT | VT_VOLATILE); |
||
6185 | if (!is_compatible_types(&tmp_type1, &tmp_type2)) { |
||
6186 | error: |
||
6187 | type_to_str(buf1, sizeof(buf1), st, NULL); |
||
6188 | type_to_str(buf2, sizeof(buf2), dt, NULL); |
||
6189 | error("cannot cast '%s' to '%s'", buf1, buf2); |
||
6190 | } |
||
6191 | break; |
||
6192 | } |
||
6193 | type_ok: |
||
6194 | gen_cast(dt); |
||
6195 | } |
||
6196 | |||
6197 | /* store vtop in lvalue pushed on stack */ |
||
6198 | void vstore(void) |
||
6199 | { |
||
6200 | int sbt, dbt, ft, r, t, size, align, bit_size, bit_pos, rc, delayed_cast; |
||
6201 | |||
6202 | ft = vtop[-1].type.t; |
||
6203 | sbt = vtop->type.t & VT_BTYPE; |
||
6204 | dbt = ft & VT_BTYPE; |
||
6205 | if (((sbt == VT_INT || sbt == VT_SHORT) && dbt == VT_BYTE) || |
||
6206 | (sbt == VT_INT && dbt == VT_SHORT)) { |
||
6207 | /* optimize char/short casts */ |
||
6208 | delayed_cast = VT_MUSTCAST; |
||
6209 | vtop->type.t = ft & VT_TYPE; |
||
6210 | /* XXX: factorize */ |
||
6211 | if (ft & VT_CONSTANT) |
||
6212 | warning("assignment of read-only location"); |
||
6213 | } else { |
||
6214 | delayed_cast = 0; |
||
6215 | if (!(ft & VT_BITFIELD)) |
||
6216 | gen_assign_cast(&vtop[-1].type); |
||
6217 | } |
||
6218 | |||
6219 | if (sbt == VT_STRUCT) { |
||
6220 | /* if structure, only generate pointer */ |
||
6221 | /* structure assignment : generate memcpy */ |
||
6222 | /* XXX: optimize if small size */ |
||
6223 | if (!nocode_wanted) { |
||
6224 | size = type_size(&vtop->type, &align); |
||
6225 | |||
6226 | vpush_global_sym(&func_old_type, TOK_memcpy); |
||
6227 | |||
6228 | /* destination */ |
||
6229 | vpushv(vtop - 2); |
||
6230 | vtop->type.t = VT_INT; |
||
6231 | gaddrof(); |
||
6232 | /* source */ |
||
6233 | vpushv(vtop - 2); |
||
6234 | vtop->type.t = VT_INT; |
||
6235 | gaddrof(); |
||
6236 | /* type size */ |
||
6237 | vpushi(size); |
||
6238 | gfunc_call(3); |
||
6239 | |||
6240 | vswap(); |
||
6241 | vpop(); |
||
6242 | } else { |
||
6243 | vswap(); |
||
6244 | vpop(); |
||
6245 | } |
||
6246 | /* leave source on stack */ |
||
6247 | } else if (ft & VT_BITFIELD) { |
||
6248 | /* bitfield store handling */ |
||
6249 | bit_pos = (ft >> VT_STRUCT_SHIFT) & 0x3f; |
||
6250 | bit_size = (ft >> (VT_STRUCT_SHIFT + 6)) & 0x3f; |
||
6251 | /* remove bit field info to avoid loops */ |
||
6252 | vtop[-1].type.t = ft & ~(VT_BITFIELD | (-1 << VT_STRUCT_SHIFT)); |
||
6253 | |||
6254 | /* duplicate destination */ |
||
6255 | vdup(); |
||
6256 | vtop[-1] = vtop[-2]; |
||
6257 | |||
6258 | /* mask and shift source */ |
||
6259 | vpushi((1 << bit_size) - 1); |
||
6260 | gen_op('&'); |
||
6261 | vpushi(bit_pos); |
||
6262 | gen_op(TOK_SHL); |
||
6263 | /* load destination, mask and or with source */ |
||
6264 | vswap(); |
||
6265 | vpushi(~(((1 << bit_size) - 1) << bit_pos)); |
||
6266 | gen_op('&'); |
||
6267 | gen_op('|'); |
||
6268 | /* store result */ |
||
6269 | vstore(); |
||
6270 | } else { |
||
6271 | #ifdef CONFIG_TCC_BCHECK |
||
6272 | /* bound check case */ |
||
6273 | if (vtop[-1].r & VT_MUSTBOUND) { |
||
6274 | vswap(); |
||
6275 | gbound(); |
||
6276 | vswap(); |
||
6277 | } |
||
6278 | #endif |
||
6279 | if (!nocode_wanted) { |
||
6280 | rc = RC_INT; |
||
6281 | if (is_float(ft)) |
||
6282 | rc = RC_FLOAT; |
||
6283 | r = gv(rc); /* generate value */ |
||
6284 | /* if lvalue was saved on stack, must read it */ |
||
6285 | if ((vtop[-1].r & VT_VALMASK) == VT_LLOCAL) { |
||
6286 | SValue sv; |
||
6287 | t = get_reg(RC_INT); |
||
6288 | sv.type.t = VT_INT; |
||
6289 | sv.r = VT_LOCAL | VT_LVAL; |
||
6290 | sv.c.ul = vtop[-1].c.ul; |
||
6291 | load(t, &sv); |
||
6292 | vtop[-1].r = t | VT_LVAL; |
||
6293 | } |
||
6294 | store(r, vtop - 1); |
||
6295 | /* two word case handling : store second register at word + 4 */ |
||
6296 | if ((ft & VT_BTYPE) == VT_LLONG) { |
||
6297 | vswap(); |
||
6298 | /* convert to int to increment easily */ |
||
6299 | vtop->type.t = VT_INT; |
||
6300 | gaddrof(); |
||
6301 | vpushi(4); |
||
6302 | gen_op('+'); |
||
6303 | vtop->r |= VT_LVAL; |
||
6304 | vswap(); |
||
6305 | /* XXX: it works because r2 is spilled last ! */ |
||
6306 | store(vtop->r2, vtop - 1); |
||
6307 | } |
||
6308 | } |
||
6309 | vswap(); |
||
6310 | vtop--; /* NOT vpop() because on x86 it would flush the fp stack */ |
||
6311 | vtop->r |= delayed_cast; |
||
6312 | } |
||
6313 | } |
||
6314 | |||
6315 | /* post defines POST/PRE add. c is the token ++ or -- */ |
||
6316 | void inc(int post, int c) |
||
6317 | { |
||
6318 | test_lvalue(); |
||
6319 | vdup(); /* save lvalue */ |
||
6320 | if (post) { |
||
6321 | gv_dup(); /* duplicate value */ |
||
6322 | vrotb(3); |
||
6323 | vrotb(3); |
||
6324 | } |
||
6325 | /* add constant */ |
||
6326 | vpushi(c - TOK_MID); |
||
6327 | gen_op('+'); |
||
6328 | vstore(); /* store value */ |
||
6329 | if (post) |
||
6330 | vpop(); /* if post op, return saved value */ |
||
6331 | } |
||
6332 | |||
6333 | /* Parse GNUC __attribute__ extension. Currently, the following |
||
6334 | extensions are recognized: |
||
6335 | - aligned(n) : set data/function alignment. |
||
6336 | - packed : force data alignment to 1 |
||
6337 | - section(x) : generate data/code in this section. |
||
6338 | - unused : currently ignored, but may be used someday. |
||
6339 | - regparm(n) : pass function parameters in registers (i386 only) |
||
6340 | */ |
||
6341 | static void parse_attribute(AttributeDef *ad) |
||
6342 | { |
||
6343 | int t, n; |
||
6344 | |||
6345 | while (tok == TOK_ATTRIBUTE1 || tok == TOK_ATTRIBUTE2) { |
||
6346 | next(); |
||
6347 | skip('('); |
||
6348 | skip('('); |
||
6349 | while (tok != ')') { |
||
6350 | if (tok < TOK_IDENT) |
||
6351 | expect("attribute name"); |
||
6352 | t = tok; |
||
6353 | next(); |
||
6354 | switch(t) { |
||
6355 | case TOK_SECTION1: |
||
6356 | case TOK_SECTION2: |
||
6357 | skip('('); |
||
6358 | if (tok != TOK_STR) |
||
6359 | expect("section name"); |
||
6360 | ad->section = find_section(tcc_state, (char *)tokc.cstr->data); |
||
6361 | next(); |
||
6362 | skip(')'); |
||
6363 | break; |
||
6364 | case TOK_ALIGNED1: |
||
6365 | case TOK_ALIGNED2: |
||
6366 | if (tok == '(') { |
||
6367 | next(); |
||
6368 | n = expr_const(); |
||
6369 | if (n <= 0 || (n & (n - 1)) != 0) |
||
6370 | error("alignment must be a positive power of two"); |
||
6371 | skip(')'); |
||
6372 | } else { |
||
6373 | n = MAX_ALIGN; |
||
6374 | } |
||
6375 | ad->aligned = n; |
||
6376 | break; |
||
6377 | case TOK_PACKED1: |
||
6378 | case TOK_PACKED2: |
||
6379 | ad->packed = 1; |
||
6380 | break; |
||
6381 | case TOK_UNUSED1: |
||
6382 | case TOK_UNUSED2: |
||
6383 | /* currently, no need to handle it because tcc does not |
||
6384 | track unused objects */ |
||
6385 | break; |
||
6386 | case TOK_NORETURN1: |
||
6387 | case TOK_NORETURN2: |
||
6388 | /* currently, no need to handle it because tcc does not |
||
6389 | track unused objects */ |
||
6390 | break; |
||
6391 | case TOK_CDECL1: |
||
6392 | case TOK_CDECL2: |
||
6393 | case TOK_CDECL3: |
||
6394 | ad->func_call = FUNC_CDECL; |
||
6395 | break; |
||
6396 | case TOK_STDCALL1: |
||
6397 | case TOK_STDCALL2: |
||
6398 | case TOK_STDCALL3: |
||
6399 | ad->func_call = FUNC_STDCALL; |
||
6400 | break; |
||
6401 | #ifdef TCC_TARGET_I386 |
||
6402 | case TOK_REGPARM1: |
||
6403 | case TOK_REGPARM2: |
||
6404 | skip('('); |
||
6405 | n = expr_const(); |
||
6406 | if (n > 3) |
||
6407 | n = 3; |
||
6408 | else if (n < 0) |
||
6409 | n = 0; |
||
6410 | if (n > 0) |
||
6411 | ad->func_call = FUNC_FASTCALL1 + n - 1; |
||
6412 | skip(')'); |
||
6413 | break; |
||
6414 | #endif |
||
6415 | case TOK_DLLEXPORT: |
||
6416 | ad->dllexport = 1; |
||
6417 | break; |
||
6418 | default: |
||
6419 | if (tcc_state->warn_unsupported) |
||
6420 | warning("'%s' attribute ignored", get_tok_str(t, NULL)); |
||
6421 | /* skip parameters */ |
||
6422 | /* XXX: skip parenthesis too */ |
||
6423 | if (tok == '(') { |
||
6424 | next(); |
||
6425 | while (tok != ')' && tok != -1) |
||
6426 | next(); |
||
6427 | next(); |
||
6428 | } |
||
6429 | break; |
||
6430 | } |
||
6431 | if (tok != ',') |
||
6432 | break; |
||
6433 | next(); |
||
6434 | } |
||
6435 | skip(')'); |
||
6436 | skip(')'); |
||
6437 | } |
||
6438 | } |
||
6439 | |||
6440 | /* enum/struct/union declaration. u is either VT_ENUM or VT_STRUCT */ |
||
6441 | static void struct_decl(CType *type, int u) |
||
6442 | { |
||
6443 | int a, v, size, align, maxalign, c, offset; |
||
6444 | int bit_size, bit_pos, bsize, bt, lbit_pos; |
||
6445 | Sym *s, *ss, **ps; |
||
6446 | AttributeDef ad; |
||
6447 | CType type1, btype; |
||
6448 | |||
6449 | a = tok; /* save decl type */ |
||
6450 | next(); |
||
6451 | if (tok != '{') { |
||
6452 | v = tok; |
||
6453 | next(); |
||
6454 | /* struct already defined ? return it */ |
||
6455 | if (v < TOK_IDENT) |
||
6456 | expect("struct/union/enum name"); |
||
6457 | s = struct_find(v); |
||
6458 | if (s) { |
||
6459 | if (s->type.t != a) |
||
6460 | error("invalid type"); |
||
6461 | goto do_decl; |
||
6462 | } |
||
6463 | } else { |
||
6464 | v = anon_sym++; |
||
6465 | } |
||
6466 | type1.t = a; |
||
6467 | /* we put an undefined size for struct/union */ |
||
6468 | s = sym_push(v | SYM_STRUCT, &type1, 0, -1); |
||
6469 | s->r = 0; /* default alignment is zero as gcc */ |
||
6470 | /* put struct/union/enum name in type */ |
||
6471 | do_decl: |
||
6472 | type->t = u; |
||
6473 | type->ref = s; |
||
6474 | |||
6475 | if (tok == '{') { |
||
6476 | next(); |
||
6477 | if (s->c != -1) |
||
6478 | error("struct/union/enum already defined"); |
||
6479 | /* cannot be empty */ |
||
6480 | c = 0; |
||
6481 | /* non empty enums are not allowed */ |
||
6482 | if (a == TOK_ENUM) { |
||
6483 | for(;;) { |
||
6484 | v = tok; |
||
6485 | if (v < TOK_UIDENT) |
||
6486 | expect("identifier"); |
||
6487 | next(); |
||
6488 | if (tok == '=') { |
||
6489 | next(); |
||
6490 | c = expr_const(); |
||
6491 | } |
||
6492 | /* enum symbols have static storage */ |
||
6493 | ss = sym_push(v, &int_type, VT_CONST, c); |
||
6494 | ss->type.t |= VT_STATIC; |
||
6495 | if (tok != ',') |
||
6496 | break; |
||
6497 | next(); |
||
6498 | c++; |
||
6499 | /* NOTE: we accept a trailing comma */ |
||
6500 | if (tok == '}') |
||
6501 | break; |
||
6502 | } |
||
6503 | skip('}'); |
||
6504 | } else { |
||
6505 | maxalign = 1; |
||
6506 | ps = &s->next; |
||
6507 | bit_pos = 0; |
||
6508 | offset = 0; |
||
6509 | while (tok != '}') { |
||
6510 | parse_btype(&btype, &ad); |
||
6511 | while (1) { |
||
6512 | bit_size = -1; |
||
6513 | v = 0; |
||
6514 | type1 = btype; |
||
6515 | if (tok != ':') { |
||
6516 | type_decl(&type1, &ad, &v, TYPE_DIRECT); |
||
6517 | if ((type1.t & VT_BTYPE) == VT_FUNC || |
||
6518 | (type1.t & (VT_TYPEDEF | VT_STATIC | VT_EXTERN | VT_INLINE))) |
||
6519 | error("invalid type for '%s'", |
||
6520 | get_tok_str(v, NULL)); |
||
6521 | } |
||
6522 | if (tok == ':') { |
||
6523 | next(); |
||
6524 | bit_size = expr_const(); |
||
6525 | /* XXX: handle v = 0 case for messages */ |
||
6526 | if (bit_size < 0) |
||
6527 | error("negative width in bit-field '%s'", |
||
6528 | get_tok_str(v, NULL)); |
||
6529 | if (v && bit_size == 0) |
||
6530 | error("zero width for bit-field '%s'", |
||
6531 | get_tok_str(v, NULL)); |
||
6532 | } |
||
6533 | size = type_size(&type1, &align); |
||
6534 | if (ad.aligned) { |
||
6535 | if (align < ad.aligned) |
||
6536 | align = ad.aligned; |
||
6537 | } else if (ad.packed) { |
||
6538 | align = 1; |
||
6539 | } else if (*tcc_state->pack_stack_ptr) { |
||
6540 | if (align > *tcc_state->pack_stack_ptr) |
||
6541 | align = *tcc_state->pack_stack_ptr; |
||
6542 | } |
||
6543 | lbit_pos = 0; |
||
6544 | if (bit_size >= 0) { |
||
6545 | bt = type1.t & VT_BTYPE; |
||
6546 | if (bt != VT_INT && |
||
6547 | bt != VT_BYTE && |
||
6548 | bt != VT_SHORT && |
||
6549 | bt != VT_BOOL && |
||
6550 | bt != VT_ENUM) |
||
6551 | error("bitfields must have scalar type"); |
||
6552 | bsize = size * 8; |
||
6553 | if (bit_size > bsize) { |
||
6554 | error("width of '%s' exceeds its type", |
||
6555 | get_tok_str(v, NULL)); |
||
6556 | } else if (bit_size == bsize) { |
||
6557 | /* no need for bit fields */ |
||
6558 | bit_pos = 0; |
||
6559 | } else if (bit_size == 0) { |
||
6560 | /* XXX: what to do if only padding in a |
||
6561 | structure ? */ |
||
6562 | /* zero size: means to pad */ |
||
6563 | if (bit_pos > 0) |
||
6564 | bit_pos = bsize; |
||
6565 | } else { |
||
6566 | /* we do not have enough room ? */ |
||
6567 | if ((bit_pos + bit_size) > bsize) |
||
6568 | bit_pos = 0; |
||
6569 | lbit_pos = bit_pos; |
||
6570 | /* XXX: handle LSB first */ |
||
6571 | type1.t |= VT_BITFIELD | |
||
6572 | (bit_pos << VT_STRUCT_SHIFT) | |
||
6573 | (bit_size << (VT_STRUCT_SHIFT + 6)); |
||
6574 | bit_pos += bit_size; |
||
6575 | } |
||
6576 | } else { |
||
6577 | bit_pos = 0; |
||
6578 | } |
||
6579 | if (v) { |
||
6580 | /* add new memory data only if starting |
||
6581 | bit field */ |
||
6582 | if (lbit_pos == 0) { |
||
6583 | if (a == TOK_STRUCT) { |
||
6584 | c = (c + align - 1) & -align; |
||
6585 | offset = c; |
||
6586 | c += size; |
||
6587 | } else { |
||
6588 | offset = 0; |
||
6589 | if (size > c) |
||
6590 | c = size; |
||
6591 | } |
||
6592 | if (align > maxalign) |
||
6593 | maxalign = align; |
||
6594 | } |
||
6595 | #if 0 |
||
6596 | printf("add field %s offset=%d", |
||
6597 | get_tok_str(v, NULL), offset); |
||
6598 | if (type1.t & VT_BITFIELD) { |
||
6599 | printf(" pos=%d size=%d", |
||
6600 | (type1.t >> VT_STRUCT_SHIFT) & 0x3f, |
||
6601 | (type1.t >> (VT_STRUCT_SHIFT + 6)) & 0x3f); |
||
6602 | } |
||
6603 | printf("\n"); |
||
6604 | #endif |
||
6605 | ss = sym_push(v | SYM_FIELD, &type1, 0, offset); |
||
6606 | *ps = ss; |
||
6607 | ps = &ss->next; |
||
6608 | } |
||
6609 | if (tok == ';' || tok == TOK_EOF) |
||
6610 | break; |
||
6611 | skip(','); |
||
6612 | } |
||
6613 | skip(';'); |
||
6614 | } |
||
6615 | skip('}'); |
||
6616 | /* store size and alignment */ |
||
6617 | s->c = (c + maxalign - 1) & -maxalign; |
||
6618 | s->r = maxalign; |
||
6619 | } |
||
6620 | } |
||
6621 | } |
||
6622 | |||
6623 | /* return 0 if no type declaration. otherwise, return the basic type |
||
6624 | and skip it. |
||
6625 | */ |
||
6626 | static int parse_btype(CType *type, AttributeDef *ad) |
||
6627 | { |
||
6628 | int t, u, type_found, typespec_found; |
||
6629 | Sym *s; |
||
6630 | CType type1; |
||
6631 | |||
6632 | memset(ad, 0, sizeof(AttributeDef)); |
||
6633 | type_found = 0; |
||
6634 | typespec_found = 0; |
||
6635 | t = 0; |
||
6636 | while(1) { |
||
6637 | switch(tok) { |
||
6638 | case TOK_EXTENSION: |
||
6639 | /* currently, we really ignore extension */ |
||
6640 | next(); |
||
6641 | continue; |
||
6642 | |||
6643 | /* basic types */ |
||
6644 | case TOK_CHAR: |
||
6645 | u = VT_BYTE; |
||
6646 | basic_type: |
||
6647 | next(); |
||
6648 | basic_type1: |
||
6649 | if ((t & VT_BTYPE) != 0) |
||
6650 | error("too many basic types"); |
||
6651 | t |= u; |
||
6652 | typespec_found = 1; |
||
6653 | break; |
||
6654 | case TOK_VOID: |
||
6655 | u = VT_VOID; |
||
6656 | goto basic_type; |
||
6657 | case TOK_SHORT: |
||
6658 | u = VT_SHORT; |
||
6659 | goto basic_type; |
||
6660 | case TOK_INT: |
||
6661 | next(); |
||
6662 | typespec_found = 1; |
||
6663 | break; |
||
6664 | case TOK_LONG: |
||
6665 | next(); |
||
6666 | if ((t & VT_BTYPE) == VT_DOUBLE) { |
||
6667 | t = (t & ~VT_BTYPE) | VT_LDOUBLE; |
||
6668 | } else if ((t & VT_BTYPE) == VT_LONG) { |
||
6669 | t = (t & ~VT_BTYPE) | VT_LLONG; |
||
6670 | } else { |
||
6671 | u = VT_LONG; |
||
6672 | goto basic_type1; |
||
6673 | } |
||
6674 | break; |
||
6675 | case TOK_BOOL: |
||
6676 | u = VT_BOOL; |
||
6677 | goto basic_type; |
||
6678 | case TOK_FLOAT: |
||
6679 | u = VT_FLOAT; |
||
6680 | goto basic_type; |
||
6681 | case TOK_DOUBLE: |
||
6682 | next(); |
||
6683 | if ((t & VT_BTYPE) == VT_LONG) { |
||
6684 | t = (t & ~VT_BTYPE) | VT_LDOUBLE; |
||
6685 | } else { |
||
6686 | u = VT_DOUBLE; |
||
6687 | goto basic_type1; |
||
6688 | } |
||
6689 | break; |
||
6690 | case TOK_ENUM: |
||
6691 | struct_decl(&type1, VT_ENUM); |
||
6692 | basic_type2: |
||
6693 | u = type1.t; |
||
6694 | type->ref = type1.ref; |
||
6695 | goto basic_type1; |
||
6696 | case TOK_STRUCT: |
||
6697 | case TOK_UNION: |
||
6698 | struct_decl(&type1, VT_STRUCT); |
||
6699 | goto basic_type2; |
||
6700 | |||
6701 | /* type modifiers */ |
||
6702 | case TOK_CONST1: |
||
6703 | case TOK_CONST2: |
||
6704 | case TOK_CONST3: |
||
6705 | t |= VT_CONSTANT; |
||
6706 | next(); |
||
6707 | break; |
||
6708 | case TOK_VOLATILE1: |
||
6709 | case TOK_VOLATILE2: |
||
6710 | case TOK_VOLATILE3: |
||
6711 | t |= VT_VOLATILE; |
||
6712 | next(); |
||
6713 | break; |
||
6714 | case TOK_SIGNED1: |
||
6715 | case TOK_SIGNED2: |
||
6716 | case TOK_SIGNED3: |
||
6717 | typespec_found = 1; |
||
6718 | t |= VT_SIGNED; |
||
6719 | next(); |
||
6720 | break; |
||
6721 | case TOK_REGISTER: |
||
6722 | case TOK_AUTO: |
||
6723 | case TOK_RESTRICT1: |
||
6724 | case TOK_RESTRICT2: |
||
6725 | case TOK_RESTRICT3: |
||
6726 | next(); |
||
6727 | break; |
||
6728 | case TOK_UNSIGNED: |
||
6729 | t |= VT_UNSIGNED; |
||
6730 | next(); |
||
6731 | typespec_found = 1; |
||
6732 | break; |
||
6733 | |||
6734 | /* storage */ |
||
6735 | case TOK_EXTERN: |
||
6736 | t |= VT_EXTERN; |
||
6737 | next(); |
||
6738 | break; |
||
6739 | case TOK_STATIC: |
||
6740 | t |= VT_STATIC; |
||
6741 | next(); |
||
6742 | break; |
||
6743 | case TOK_TYPEDEF: |
||
6744 | t |= VT_TYPEDEF; |
||
6745 | next(); |
||
6746 | break; |
||
6747 | case TOK_INLINE1: |
||
6748 | case TOK_INLINE2: |
||
6749 | case TOK_INLINE3: |
||
6750 | t |= VT_INLINE; |
||
6751 | next(); |
||
6752 | break; |
||
6753 | |||
6754 | /* GNUC attribute */ |
||
6755 | case TOK_ATTRIBUTE1: |
||
6756 | case TOK_ATTRIBUTE2: |
||
6757 | parse_attribute(ad); |
||
6758 | break; |
||
6759 | /* GNUC typeof */ |
||
6760 | case TOK_TYPEOF1: |
||
6761 | case TOK_TYPEOF2: |
||
6762 | case TOK_TYPEOF3: |
||
6763 | next(); |
||
6764 | parse_expr_type(&type1); |
||
6765 | goto basic_type2; |
||
6766 | default: |
||
6767 | if (typespec_found) |
||
6768 | goto the_end; |
||
6769 | s = sym_find(tok); |
||
6770 | if (!s || !(s->type.t & VT_TYPEDEF)) |
||
6771 | goto the_end; |
||
6772 | t |= (s->type.t & ~VT_TYPEDEF); |
||
6773 | type->ref = s->type.ref; |
||
6774 | next(); |
||
6775 | break; |
||
6776 | } |
||
6777 | type_found = 1; |
||
6778 | } |
||
6779 | the_end: |
||
6780 | if ((t & (VT_SIGNED|VT_UNSIGNED)) == (VT_SIGNED|VT_UNSIGNED)) |
||
6781 | error("signed and unsigned modifier"); |
||
6782 | if (tcc_state->char_is_unsigned) { |
||
6783 | if ((t & (VT_SIGNED|VT_UNSIGNED|VT_BTYPE)) == VT_BYTE) |
||
6784 | t |= VT_UNSIGNED; |
||
6785 | } |
||
6786 | t &= ~VT_SIGNED; |
||
6787 | |||
6788 | /* long is never used as type */ |
||
6789 | if ((t & VT_BTYPE) == VT_LONG) |
||
6790 | t = (t & ~VT_BTYPE) | VT_INT; |
||
6791 | type->t = t; |
||
6792 | return type_found; |
||
6793 | } |
||
6794 | |||
6795 | /* convert a function parameter type (array to pointer and function to |
||
6796 | function pointer) */ |
||
6797 | static inline void convert_parameter_type(CType *pt) |
||
6798 | { |
||
6799 | /* remove const and volatile qualifiers (XXX: const could be used |
||
6800 | to indicate a const function parameter */ |
||
6801 | pt->t &= ~(VT_CONSTANT | VT_VOLATILE); |
||
6802 | /* array must be transformed to pointer according to ANSI C */ |
||
6803 | pt->t &= ~VT_ARRAY; |
||
6804 | if ((pt->t & VT_BTYPE) == VT_FUNC) { |
||
6805 | mk_pointer(pt); |
||
6806 | } |
||
6807 | } |
||
6808 | |||
6809 | static void post_type(CType *type, AttributeDef *ad) |
||
6810 | { |
||
6811 | int n, l, t1; |
||
6812 | Sym **plast, *s, *first; |
||
6813 | AttributeDef ad1; |
||
6814 | CType pt; |
||
6815 | |||
6816 | if (tok == '(') { |
||
6817 | /* function declaration */ |
||
6818 | next(); |
||
6819 | l = 0; |
||
6820 | first = NULL; |
||
6821 | plast = &first; |
||
6822 | while (tok != ')') { |
||
6823 | /* read param name and compute offset */ |
||
6824 | if (l != FUNC_OLD) { |
||
6825 | if (!parse_btype(&pt, &ad1)) { |
||
6826 | if (l) { |
||
6827 | error("invalid type"); |
||
6828 | } else { |
||
6829 | l = FUNC_OLD; |
||
6830 | goto old_proto; |
||
6831 | } |
||
6832 | } |
||
6833 | l = FUNC_NEW; |
||
6834 | if ((pt.t & VT_BTYPE) == VT_VOID && tok == ')') |
||
6835 | break; |
||
6836 | type_decl(&pt, &ad1, &n, TYPE_DIRECT | TYPE_ABSTRACT); |
||
6837 | if ((pt.t & VT_BTYPE) == VT_VOID) |
||
6838 | error("parameter declared as void"); |
||
6839 | } else { |
||
6840 | old_proto: |
||
6841 | n = tok; |
||
6842 | pt.t = VT_INT; |
||
6843 | next(); |
||
6844 | } |
||
6845 | convert_parameter_type(&pt); |
||
6846 | s = sym_push(n | SYM_FIELD, &pt, 0, 0); |
||
6847 | *plast = s; |
||
6848 | plast = &s->next; |
||
6849 | if (tok == ',') { |
||
6850 | next(); |
||
6851 | if (l == FUNC_NEW && tok == TOK_DOTS) { |
||
6852 | l = FUNC_ELLIPSIS; |
||
6853 | next(); |
||
6854 | break; |
||
6855 | } |
||
6856 | } |
||
6857 | } |
||
6858 | /* if no parameters, then old type prototype */ |
||
6859 | if (l == 0) |
||
6860 | l = FUNC_OLD; |
||
6861 | skip(')'); |
||
6862 | t1 = type->t & VT_STORAGE; |
||
6863 | /* NOTE: const is ignored in returned type as it has a special |
||
6864 | meaning in gcc / C++ */ |
||
6865 | type->t &= ~(VT_STORAGE | VT_CONSTANT); |
||
6866 | post_type(type, ad); |
||
6867 | /* we push a anonymous symbol which will contain the function prototype */ |
||
6868 | s = sym_push(SYM_FIELD, type, ad->func_call, l); |
||
6869 | s->next = first; |
||
6870 | type->t = t1 | VT_FUNC; |
||
6871 | type->ref = s; |
||
6872 | } else if (tok == '[') { |
||
6873 | /* array definition */ |
||
6874 | next(); |
||
6875 | n = -1; |
||
6876 | if (tok != ']') { |
||
6877 | n = expr_const(); |
||
6878 | if (n < 0) |
||
6879 | error("invalid array size"); |
||
6880 | } |
||
6881 | skip(']'); |
||
6882 | /* parse next post type */ |
||
6883 | t1 = type->t & VT_STORAGE; |
||
6884 | type->t &= ~VT_STORAGE; |
||
6885 | post_type(type, ad); |
||
6886 | |||
6887 | /* we push a anonymous symbol which will contain the array |
||
6888 | element type */ |
||
6889 | s = sym_push(SYM_FIELD, type, 0, n); |
||
6890 | type->t = t1 | VT_ARRAY | VT_PTR; |
||
6891 | type->ref = s; |
||
6892 | } |
||
6893 | } |
||
6894 | |||
6895 | /* Parse a type declaration (except basic type), and return the type |
||
6896 | in 'type'. 'td' is a bitmask indicating which kind of type decl is |
||
6897 | expected. 'type' should contain the basic type. 'ad' is the |
||
6898 | attribute definition of the basic type. It can be modified by |
||
6899 | type_decl(). |
||
6900 | */ |
||
6901 | static void type_decl(CType *type, AttributeDef *ad, int *v, int td) |
||
6902 | { |
||
6903 | Sym *s; |
||
6904 | CType type1, *type2; |
||
6905 | int qualifiers; |
||
6906 | |||
6907 | while (tok == '*') { |
||
6908 | qualifiers = 0; |
||
6909 | redo: |
||
6910 | next(); |
||
6911 | switch(tok) { |
||
6912 | case TOK_CONST1: |
||
6913 | case TOK_CONST2: |
||
6914 | case TOK_CONST3: |
||
6915 | qualifiers |= VT_CONSTANT; |
||
6916 | goto redo; |
||
6917 | case TOK_VOLATILE1: |
||
6918 | case TOK_VOLATILE2: |
||
6919 | case TOK_VOLATILE3: |
||
6920 | qualifiers |= VT_VOLATILE; |
||
6921 | goto redo; |
||
6922 | case TOK_RESTRICT1: |
||
6923 | case TOK_RESTRICT2: |
||
6924 | case TOK_RESTRICT3: |
||
6925 | goto redo; |
||
6926 | } |
||
6927 | mk_pointer(type); |
||
6928 | type->t |= qualifiers; |
||
6929 | } |
||
6930 | |||
6931 | /* XXX: clarify attribute handling */ |
||
6932 | if (tok == TOK_ATTRIBUTE1 || tok == TOK_ATTRIBUTE2) |
||
6933 | parse_attribute(ad); |
||
6934 | |||
6935 | /* recursive type */ |
||
6936 | /* XXX: incorrect if abstract type for functions (e.g. 'int ()') */ |
||
6937 | type1.t = 0; /* XXX: same as int */ |
||
6938 | if (tok == '(') { |
||
6939 | next(); |
||
6940 | /* XXX: this is not correct to modify 'ad' at this point, but |
||
6941 | the syntax is not clear */ |
||
6942 | if (tok == TOK_ATTRIBUTE1 || tok == TOK_ATTRIBUTE2) |
||
6943 | parse_attribute(ad); |
||
6944 | type_decl(&type1, ad, v, td); |
||
6945 | skip(')'); |
||
6946 | } else { |
||
6947 | /* type identifier */ |
||
6948 | if (tok >= TOK_IDENT && (td & TYPE_DIRECT)) { |
||
6949 | *v = tok; |
||
6950 | next(); |
||
6951 | } else { |
||
6952 | if (!(td & TYPE_ABSTRACT)) |
||
6953 | expect("identifier"); |
||
6954 | *v = 0; |
||
6955 | } |
||
6956 | } |
||
6957 | post_type(type, ad); |
||
6958 | if (tok == TOK_ATTRIBUTE1 || tok == TOK_ATTRIBUTE2) |
||
6959 | parse_attribute(ad); |
||
6960 | if (!type1.t) |
||
6961 | return; |
||
6962 | /* append type at the end of type1 */ |
||
6963 | type2 = &type1; |
||
6964 | for(;;) { |
||
6965 | s = type2->ref; |
||
6966 | type2 = &s->type; |
||
6967 | if (!type2->t) { |
||
6968 | *type2 = *type; |
||
6969 | break; |
||
6970 | } |
||
6971 | } |
||
6972 | *type = type1; |
||
6973 | } |
||
6974 | |||
6975 | /* compute the lvalue VT_LVAL_xxx needed to match type t. */ |
||
6976 | static int lvalue_type(int t) |
||
6977 | { |
||
6978 | int bt, r; |
||
6979 | r = VT_LVAL; |
||
6980 | bt = t & VT_BTYPE; |
||
6981 | if (bt == VT_BYTE || bt == VT_BOOL) |
||
6982 | r |= VT_LVAL_BYTE; |
||
6983 | else if (bt == VT_SHORT) |
||
6984 | r |= VT_LVAL_SHORT; |
||
6985 | else |
||
6986 | return r; |
||
6987 | if (t & VT_UNSIGNED) |
||
6988 | r |= VT_LVAL_UNSIGNED; |
||
6989 | return r; |
||
6990 | } |
||
6991 | |||
6992 | /* indirection with full error checking and bound check */ |
||
6993 | static void indir(void) |
||
6994 | { |
||
6995 | if ((vtop->type.t & VT_BTYPE) != VT_PTR) |
||
6996 | expect("pointer"); |
||
6997 | if ((vtop->r & VT_LVAL) && !nocode_wanted) |
||
6998 | gv(RC_INT); |
||
6999 | vtop->type = *pointed_type(&vtop->type); |
||
7000 | /* an array is never an lvalue */ |
||
7001 | if (!(vtop->type.t & VT_ARRAY)) { |
||
7002 | vtop->r |= lvalue_type(vtop->type.t); |
||
7003 | /* if bound checking, the referenced pointer must be checked */ |
||
7004 | if (do_bounds_check) |
||
7005 | vtop->r |= VT_MUSTBOUND; |
||
7006 | } |
||
7007 | } |
||
7008 | |||
7009 | /* pass a parameter to a function and do type checking and casting */ |
||
7010 | static void gfunc_param_typed(Sym *func, Sym *arg) |
||
7011 | { |
||
7012 | int func_type; |
||
7013 | CType type; |
||
7014 | |||
7015 | func_type = func->c; |
||
7016 | if (func_type == FUNC_OLD || |
||
7017 | (func_type == FUNC_ELLIPSIS && arg == NULL)) { |
||
7018 | /* default casting : only need to convert float to double */ |
||
7019 | if ((vtop->type.t & VT_BTYPE) == VT_FLOAT) { |
||
7020 | type.t = VT_DOUBLE; |
||
7021 | gen_cast(&type); |
||
7022 | } |
||
7023 | } else if (arg == NULL) { |
||
7024 | error("too many arguments to function"); |
||
7025 | } else { |
||
7026 | type = arg->type; |
||
7027 | type.t &= ~VT_CONSTANT; /* need to do that to avoid false warning */ |
||
7028 | gen_assign_cast(&type); |
||
7029 | } |
||
7030 | } |
||
7031 | |||
7032 | /* parse an expression of the form '(type)' or '(expr)' and return its |
||
7033 | type */ |
||
7034 | static void parse_expr_type(CType *type) |
||
7035 | { |
||
7036 | int n; |
||
7037 | AttributeDef ad; |
||
7038 | |||
7039 | skip('('); |
||
7040 | if (parse_btype(type, &ad)) { |
||
7041 | type_decl(type, &ad, &n, TYPE_ABSTRACT); |
||
7042 | } else { |
||
7043 | expr_type(type); |
||
7044 | } |
||
7045 | skip(')'); |
||
7046 | } |
||
7047 | |||
7048 | static void parse_type(CType *type) |
||
7049 | { |
||
7050 | AttributeDef ad; |
||
7051 | int n; |
||
7052 | |||
7053 | if (!parse_btype(type, &ad)) { |
||
7054 | expect("type"); |
||
7055 | } |
||
7056 | type_decl(type, &ad, &n, TYPE_ABSTRACT); |
||
7057 | } |
||
7058 | |||
7059 | static void vpush_tokc(int t) |
||
7060 | { |
||
7061 | CType type; |
||
7062 | type.t = t; |
||
7063 | vsetc(&type, VT_CONST, &tokc); |
||
7064 | } |
||
7065 | |||
7066 | static void unary(void) |
||
7067 | { |
||
7068 | int n, t, align, size, r; |
||
7069 | CType type; |
||
7070 | Sym *s; |
||
7071 | AttributeDef ad; |
||
7072 | |||
7073 | /* XXX: GCC 2.95.3 does not generate a table although it should be |
||
7074 | better here */ |
||
7075 | tok_next: |
||
7076 | switch(tok) { |
||
7077 | case TOK_EXTENSION: |
||
7078 | next(); |
||
7079 | goto tok_next; |
||
7080 | case TOK_CINT: |
||
7081 | case TOK_CCHAR: |
||
7082 | case TOK_LCHAR: |
||
7083 | vpushi(tokc.i); |
||
7084 | next(); |
||
7085 | break; |
||
7086 | case TOK_CUINT: |
||
7087 | vpush_tokc(VT_INT | VT_UNSIGNED); |
||
7088 | next(); |
||
7089 | break; |
||
7090 | case TOK_CLLONG: |
||
7091 | vpush_tokc(VT_LLONG); |
||
7092 | next(); |
||
7093 | break; |
||
7094 | case TOK_CULLONG: |
||
7095 | vpush_tokc(VT_LLONG | VT_UNSIGNED); |
||
7096 | next(); |
||
7097 | break; |
||
7098 | case TOK_CFLOAT: |
||
7099 | vpush_tokc(VT_FLOAT); |
||
7100 | next(); |
||
7101 | break; |
||
7102 | case TOK_CDOUBLE: |
||
7103 | vpush_tokc(VT_DOUBLE); |
||
7104 | next(); |
||
7105 | break; |
||
7106 | case TOK_CLDOUBLE: |
||
7107 | vpush_tokc(VT_LDOUBLE); |
||
7108 | next(); |
||
7109 | break; |
||
7110 | case TOK___FUNCTION__: |
||
7111 | if (!gnu_ext) |
||
7112 | goto tok_identifier; |
||
7113 | /* fall thru */ |
||
7114 | case TOK___FUNC__: |
||
7115 | { |
||
7116 | void *ptr; |
||
7117 | int len; |
||
7118 | /* special function name identifier */ |
||
7119 | len = strlen(funcname) + 1; |
||
7120 | /* generate char[len] type */ |
||
7121 | type.t = VT_BYTE; |
||
7122 | mk_pointer(&type); |
||
7123 | type.t |= VT_ARRAY; |
||
7124 | type.ref->c = len; |
||
7125 | vpush_ref(&type, data_section, data_section->data_offset, len); |
||
7126 | ptr = section_ptr_add(data_section, len); |
||
7127 | memcpy(ptr, funcname, len); |
||
7128 | next(); |
||
7129 | } |
||
7130 | break; |
||
7131 | case TOK_LSTR: |
||
7132 | t = VT_INT; |
||
7133 | goto str_init; |
||
7134 | case TOK_STR: |
||
7135 | /* string parsing */ |
||
7136 | t = VT_BYTE; |
||
7137 | str_init: |
||
7138 | if (tcc_state->warn_write_strings) |
||
7139 | t |= VT_CONSTANT; |
||
7140 | type.t = t; |
||
7141 | mk_pointer(&type); |
||
7142 | type.t |= VT_ARRAY; |
||
7143 | memset(&ad, 0, sizeof(AttributeDef)); |
||
7144 | decl_initializer_alloc(&type, &ad, VT_CONST, 2, 0, 0); |
||
7145 | break; |
||
7146 | case '(': |
||
7147 | next(); |
||
7148 | /* cast ? */ |
||
7149 | if (parse_btype(&type, &ad)) { |
||
7150 | type_decl(&type, &ad, &n, TYPE_ABSTRACT); |
||
7151 | skip(')'); |
||
7152 | /* check ISOC99 compound literal */ |
||
7153 | if (tok == '{') { |
||
7154 | /* data is allocated locally by default */ |
||
7155 | if (global_expr) |
||
7156 | r = VT_CONST; |
||
7157 | else |
||
7158 | r = VT_LOCAL; |
||
7159 | /* all except arrays are lvalues */ |
||
7160 | if (!(type.t & VT_ARRAY)) |
||
7161 | r |= lvalue_type(type.t); |
||
7162 | memset(&ad, 0, sizeof(AttributeDef)); |
||
7163 | decl_initializer_alloc(&type, &ad, r, 1, 0, 0); |
||
7164 | } else { |
||
7165 | unary(); |
||
7166 | gen_cast(&type); |
||
7167 | } |
||
7168 | } else if (tok == '{') { |
||
7169 | /* save all registers */ |
||
7170 | save_regs(0); |
||
7171 | /* statement expression : we do not accept break/continue |
||
7172 | inside as GCC does */ |
||
7173 | block(NULL, NULL, NULL, NULL, 0, 1); |
||
7174 | skip(')'); |
||
7175 | } else { |
||
7176 | gexpr(); |
||
7177 | skip(')'); |
||
7178 | } |
||
7179 | break; |
||
7180 | case '*': |
||
7181 | next(); |
||
7182 | unary(); |
||
7183 | indir(); |
||
7184 | break; |
||
7185 | case '&': |
||
7186 | next(); |
||
7187 | unary(); |
||
7188 | /* functions names must be treated as function pointers, |
||
7189 | except for unary '&' and sizeof. Since we consider that |
||
7190 | functions are not lvalues, we only have to handle it |
||
7191 | there and in function calls. */ |
||
7192 | /* arrays can also be used although they are not lvalues */ |
||
7193 | if ((vtop->type.t & VT_BTYPE) != VT_FUNC && |
||
7194 | !(vtop->type.t & VT_ARRAY)) |
||
7195 | test_lvalue(); |
||
7196 | mk_pointer(&vtop->type); |
||
7197 | gaddrof(); |
||
7198 | break; |
||
7199 | case '!': |
||
7200 | next(); |
||
7201 | unary(); |
||
7202 | if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) |
||
7203 | vtop->c.i = !vtop->c.i; |
||
7204 | else if ((vtop->r & VT_VALMASK) == VT_CMP) |
||
7205 | vtop->c.i = vtop->c.i ^ 1; |
||
7206 | else |
||
7207 | vseti(VT_JMP, gtst(1, 0)); |
||
7208 | break; |
||
7209 | case '~': |
||
7210 | next(); |
||
7211 | unary(); |
||
7212 | vpushi(-1); |
||
7213 | gen_op('^'); |
||
7214 | break; |
||
7215 | case '+': |
||
7216 | next(); |
||
7217 | /* in order to force cast, we add zero */ |
||
7218 | unary(); |
||
7219 | if ((vtop->type.t & VT_BTYPE) == VT_PTR) |
||
7220 | error("pointer not accepted for unary plus"); |
||
7221 | vpushi(0); |
||
7222 | gen_op('+'); |
||
7223 | break; |
||
7224 | case TOK_SIZEOF: |
||
7225 | case TOK_ALIGNOF1: |
||
7226 | case TOK_ALIGNOF2: |
||
7227 | t = tok; |
||
7228 | next(); |
||
7229 | if (tok == '(') { |
||
7230 | parse_expr_type(&type); |
||
7231 | } else { |
||
7232 | unary_type(&type); |
||
7233 | } |
||
7234 | size = type_size(&type, &align); |
||
7235 | if (t == TOK_SIZEOF) { |
||
7236 | if (size < 0) |
||
7237 | error("sizeof applied to an incomplete type"); |
||
7238 | vpushi(size); |
||
7239 | } else { |
||
7240 | vpushi(align); |
||
7241 | } |
||
7242 | break; |
||
7243 | |||
7244 | case TOK_builtin_types_compatible_p: |
||
7245 | { |
||
7246 | CType type1, type2; |
||
7247 | next(); |
||
7248 | skip('('); |
||
7249 | parse_type(&type1); |
||
7250 | skip(','); |
||
7251 | parse_type(&type2); |
||
7252 | skip(')'); |
||
7253 | type1.t &= ~(VT_CONSTANT | VT_VOLATILE); |
||
7254 | type2.t &= ~(VT_CONSTANT | VT_VOLATILE); |
||
7255 | vpushi(is_compatible_types(&type1, &type2)); |
||
7256 | } |
||
7257 | break; |
||
7258 | case TOK_builtin_constant_p: |
||
7259 | { |
||
7260 | int saved_nocode_wanted, res; |
||
7261 | next(); |
||
7262 | skip('('); |
||
7263 | saved_nocode_wanted = nocode_wanted; |
||
7264 | nocode_wanted = 1; |
||
7265 | gexpr(); |
||
7266 | res = (vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; |
||
7267 | vpop(); |
||
7268 | nocode_wanted = saved_nocode_wanted; |
||
7269 | skip(')'); |
||
7270 | vpushi(res); |
||
7271 | } |
||
7272 | break; |
||
7273 | case TOK_INC: |
||
7274 | case TOK_DEC: |
||
7275 | t = tok; |
||
7276 | next(); |
||
7277 | unary(); |
||
7278 | inc(0, t); |
||
7279 | break; |
||
7280 | case '-': |
||
7281 | next(); |
||
7282 | vpushi(0); |
||
7283 | unary(); |
||
7284 | gen_op('-'); |
||
7285 | break; |
||
7286 | case TOK_LAND: |
||
7287 | if (!gnu_ext) |
||
7288 | goto tok_identifier; |
||
7289 | next(); |
||
7290 | /* allow to take the address of a label */ |
||
7291 | if (tok < TOK_UIDENT) |
||
7292 | expect("label identifier"); |
||
7293 | s = label_find(tok); |
||
7294 | if (!s) { |
||
7295 | s = label_push(&global_label_stack, tok, LABEL_FORWARD); |
||
7296 | } else { |
||
7297 | if (s->r == LABEL_DECLARED) |
||
7298 | s->r = LABEL_FORWARD; |
||
7299 | } |
||
7300 | if (!s->type.t) { |
||
7301 | s->type.t = VT_VOID; |
||
7302 | mk_pointer(&s->type); |
||
7303 | s->type.t |= VT_STATIC; |
||
7304 | } |
||
7305 | vset(&s->type, VT_CONST | VT_SYM, 0); |
||
7306 | vtop->sym = s; |
||
7307 | next(); |
||
7308 | break; |
||
7309 | default: |
||
7310 | tok_identifier: |
||
7311 | t = tok; |
||
7312 | next(); |
||
7313 | if (t < TOK_UIDENT) |
||
7314 | expect("identifier"); |
||
7315 | s = sym_find(t); |
||
7316 | if (!s) { |
||
7317 | if (tok != '(') |
||
7318 | error("'%s' undeclared", get_tok_str(t, NULL)); |
||
7319 | /* for simple function calls, we tolerate undeclared |
||
7320 | external reference to int() function */ |
||
7321 | if (tcc_state->warn_implicit_function_declaration) |
||
7322 | warning("implicit declaration of function '%s'", |
||
7323 | get_tok_str(t, NULL)); |
||
7324 | s = external_global_sym(t, &func_old_type, 0); |
||
7325 | } |
||
7326 | if ((s->type.t & (VT_STATIC | VT_INLINE | VT_BTYPE)) == |
||
7327 | (VT_STATIC | VT_INLINE | VT_FUNC)) { |
||
7328 | /* if referencing an inline function, then we generate a |
||
7329 | symbol to it if not already done. It will have the |
||
7330 | effect to generate code for it at the end of the |
||
7331 | compilation unit. Inline function as always |
||
7332 | generated in the text section. */ |
||
7333 | if (!s->c) |
||
7334 | put_extern_sym(s, text_section, 0, 0); |
||
7335 | r = VT_SYM | VT_CONST; |
||
7336 | } else { |
||
7337 | r = s->r; |
||
7338 | } |
||
7339 | vset(&s->type, r, s->c); |
||
7340 | /* if forward reference, we must point to s */ |
||
7341 | if (vtop->r & VT_SYM) { |
||
7342 | vtop->sym = s; |
||
7343 | vtop->c.ul = 0; |
||
7344 | } |
||
7345 | break; |
||
7346 | } |
||
7347 | |||
7348 | /* post operations */ |
||
7349 | while (1) { |
||
7350 | if (tok == TOK_INC || tok == TOK_DEC) { |
||
7351 | inc(1, tok); |
||
7352 | next(); |
||
7353 | } else if (tok == '.' || tok == TOK_ARROW) { |
||
7354 | /* field */ |
||
7355 | if (tok == TOK_ARROW) |
||
7356 | indir(); |
||
7357 | test_lvalue(); |
||
7358 | gaddrof(); |
||
7359 | next(); |
||
7360 | /* expect pointer on structure */ |
||
7361 | if ((vtop->type.t & VT_BTYPE) != VT_STRUCT) |
||
7362 | expect("struct or union"); |
||
7363 | s = vtop->type.ref; |
||
7364 | /* find field */ |
||
7365 | tok |= SYM_FIELD; |
||
7366 | while ((s = s->next) != NULL) { |
||
7367 | if (s->v == tok) |
||
7368 | break; |
||
7369 | } |
||
7370 | if (!s) |
||
7371 | error("field not found"); |
||
7372 | /* add field offset to pointer */ |
||
7373 | vtop->type = char_pointer_type; /* change type to 'char *' */ |
||
7374 | vpushi(s->c); |
||
7375 | gen_op('+'); |
||
7376 | /* change type to field type, and set to lvalue */ |
||
7377 | vtop->type = s->type; |
||
7378 | /* an array is never an lvalue */ |
||
7379 | if (!(vtop->type.t & VT_ARRAY)) { |
||
7380 | vtop->r |= lvalue_type(vtop->type.t); |
||
7381 | /* if bound checking, the referenced pointer must be checked */ |
||
7382 | if (do_bounds_check) |
||
7383 | vtop->r |= VT_MUSTBOUND; |
||
7384 | } |
||
7385 | next(); |
||
7386 | } else if (tok == '[') { |
||
7387 | next(); |
||
7388 | gexpr(); |
||
7389 | gen_op('+'); |
||
7390 | indir(); |
||
7391 | skip(']'); |
||
7392 | } else if (tok == '(') { |
||
7393 | SValue ret; |
||
7394 | Sym *sa; |
||
7395 | int nb_args; |
||
7396 | |||
7397 | /* function call */ |
||
7398 | if ((vtop->type.t & VT_BTYPE) != VT_FUNC) { |
||
7399 | /* pointer test (no array accepted) */ |
||
7400 | if ((vtop->type.t & (VT_BTYPE | VT_ARRAY)) == VT_PTR) { |
||
7401 | vtop->type = *pointed_type(&vtop->type); |
||
7402 | if ((vtop->type.t & VT_BTYPE) != VT_FUNC) |
||
7403 | goto error_func; |
||
7404 | } else { |
||
7405 | error_func: |
||
7406 | expect("function pointer"); |
||
7407 | } |
||
7408 | } else { |
||
7409 | vtop->r &= ~VT_LVAL; /* no lvalue */ |
||
7410 | } |
||
7411 | /* get return type */ |
||
7412 | s = vtop->type.ref; |
||
7413 | next(); |
||
7414 | sa = s->next; /* first parameter */ |
||
7415 | nb_args = 0; |
||
7416 | /* compute first implicit argument if a structure is returned */ |
||
7417 | if ((s->type.t & VT_BTYPE) == VT_STRUCT) { |
||
7418 | /* get some space for the returned structure */ |
||
7419 | size = type_size(&s->type, &align); |
||
7420 | loc = (loc - size) & -align; |
||
7421 | ret.type = s->type; |
||
7422 | ret.r = VT_LOCAL | VT_LVAL; |
||
7423 | /* pass it as 'int' to avoid structure arg passing |
||
7424 | problems */ |
||
7425 | vseti(VT_LOCAL, loc); |
||
7426 | ret.c = vtop->c; |
||
7427 | nb_args++; |
||
7428 | } else { |
||
7429 | ret.type = s->type; |
||
7430 | ret.r2 = VT_CONST; |
||
7431 | /* return in register */ |
||
7432 | if (is_float(ret.type.t)) { |
||
7433 | ret.r = REG_FRET; |
||
7434 | } else { |
||
7435 | if ((ret.type.t & VT_BTYPE) == VT_LLONG) |
||
7436 | ret.r2 = REG_LRET; |
||
7437 | ret.r = REG_IRET; |
||
7438 | } |
||
7439 | ret.c.i = 0; |
||
7440 | } |
||
7441 | if (tok != ')') { |
||
7442 | for(;;) { |
||
7443 | expr_eq(); |
||
7444 | gfunc_param_typed(s, sa); |
||
7445 | nb_args++; |
||
7446 | if (sa) |
||
7447 | sa = sa->next; |
||
7448 | if (tok == ')') |
||
7449 | break; |
||
7450 | skip(','); |
||
7451 | } |
||
7452 | } |
||
7453 | if (sa) |
||
7454 | error("too few arguments to function"); |
||
7455 | skip(')'); |
||
7456 | if (!nocode_wanted) { |
||
7457 | gfunc_call(nb_args); |
||
7458 | } else { |
||
7459 | vtop -= (nb_args + 1); |
||
7460 | } |
||
7461 | /* return value */ |
||
7462 | vsetc(&ret.type, ret.r, &ret.c); |
||
7463 | vtop->r2 = ret.r2; |
||
7464 | } else { |
||
7465 | break; |
||
7466 | } |
||
7467 | } |
||
7468 | } |
||
7469 | |||
7470 | static void uneq(void) |
||
7471 | { |
||
7472 | int t; |
||
7473 | |||
7474 | unary(); |
||
7475 | if (tok == '=' || |
||
7476 | (tok >= TOK_A_MOD && tok <= TOK_A_DIV) || |
||
7477 | tok == TOK_A_XOR || tok == TOK_A_OR || |
||
7478 | tok == TOK_A_SHL || tok == TOK_A_SAR) { |
||
7479 | test_lvalue(); |
||
7480 | t = tok; |
||
7481 | next(); |
||
7482 | if (t == '=') { |
||
7483 | expr_eq(); |
||
7484 | } else { |
||
7485 | vdup(); |
||
7486 | expr_eq(); |
||
7487 | gen_op(t & 0x7f); |
||
7488 | } |
||
7489 | vstore(); |
||
7490 | } |
||
7491 | } |
||
7492 | |||
7493 | static void expr_prod(void) |
||
7494 | { |
||
7495 | int t; |
||
7496 | |||
7497 | uneq(); |
||
7498 | while (tok == '*' || tok == '/' || tok == '%') { |
||
7499 | t = tok; |
||
7500 | next(); |
||
7501 | uneq(); |
||
7502 | gen_op(t); |
||
7503 | } |
||
7504 | } |
||
7505 | |||
7506 | static void expr_sum(void) |
||
7507 | { |
||
7508 | int t; |
||
7509 | |||
7510 | expr_prod(); |
||
7511 | while (tok == '+' || tok == '-') { |
||
7512 | t = tok; |
||
7513 | next(); |
||
7514 | expr_prod(); |
||
7515 | gen_op(t); |
||
7516 | } |
||
7517 | } |
||
7518 | |||
7519 | static void expr_shift(void) |
||
7520 | { |
||
7521 | int t; |
||
7522 | |||
7523 | expr_sum(); |
||
7524 | while (tok == TOK_SHL || tok == TOK_SAR) { |
||
7525 | t = tok; |
||
7526 | next(); |
||
7527 | expr_sum(); |
||
7528 | gen_op(t); |
||
7529 | } |
||
7530 | } |
||
7531 | |||
7532 | static void expr_cmp(void) |
||
7533 | { |
||
7534 | int t; |
||
7535 | |||
7536 | expr_shift(); |
||
7537 | while ((tok >= TOK_ULE && tok <= TOK_GT) || |
||
7538 | tok == TOK_ULT || tok == TOK_UGE) { |
||
7539 | t = tok; |
||
7540 | next(); |
||
7541 | expr_shift(); |
||
7542 | gen_op(t); |
||
7543 | } |
||
7544 | } |
||
7545 | |||
7546 | static void expr_cmpeq(void) |
||
7547 | { |
||
7548 | int t; |
||
7549 | |||
7550 | expr_cmp(); |
||
7551 | while (tok == TOK_EQ || tok == TOK_NE) { |
||
7552 | t = tok; |
||
7553 | next(); |
||
7554 | expr_cmp(); |
||
7555 | gen_op(t); |
||
7556 | } |
||
7557 | } |
||
7558 | |||
7559 | static void expr_and(void) |
||
7560 | { |
||
7561 | expr_cmpeq(); |
||
7562 | while (tok == '&') { |
||
7563 | next(); |
||
7564 | expr_cmpeq(); |
||
7565 | gen_op('&'); |
||
7566 | } |
||
7567 | } |
||
7568 | |||
7569 | static void expr_xor(void) |
||
7570 | { |
||
7571 | expr_and(); |
||
7572 | while (tok == '^') { |
||
7573 | next(); |
||
7574 | expr_and(); |
||
7575 | gen_op('^'); |
||
7576 | } |
||
7577 | } |
||
7578 | |||
7579 | static void expr_or(void) |
||
7580 | { |
||
7581 | expr_xor(); |
||
7582 | while (tok == '|') { |
||
7583 | next(); |
||
7584 | expr_xor(); |
||
7585 | gen_op('|'); |
||
7586 | } |
||
7587 | } |
||
7588 | |||
7589 | /* XXX: fix this mess */ |
||
7590 | static void expr_land_const(void) |
||
7591 | { |
||
7592 | expr_or(); |
||
7593 | while (tok == TOK_LAND) { |
||
7594 | next(); |
||
7595 | expr_or(); |
||
7596 | gen_op(TOK_LAND); |
||
7597 | } |
||
7598 | } |
||
7599 | |||
7600 | /* XXX: fix this mess */ |
||
7601 | static void expr_lor_const(void) |
||
7602 | { |
||
7603 | expr_land_const(); |
||
7604 | while (tok == TOK_LOR) { |
||
7605 | next(); |
||
7606 | expr_land_const(); |
||
7607 | gen_op(TOK_LOR); |
||
7608 | } |
||
7609 | } |
||
7610 | |||
7611 | /* only used if non constant */ |
||
7612 | static void expr_land(void) |
||
7613 | { |
||
7614 | int t; |
||
7615 | |||
7616 | expr_or(); |
||
7617 | if (tok == TOK_LAND) { |
||
7618 | t = 0; |
||
7619 | for(;;) { |
||
7620 | t = gtst(1, t); |
||
7621 | if (tok != TOK_LAND) { |
||
7622 | vseti(VT_JMPI, t); |
||
7623 | break; |
||
7624 | } |
||
7625 | next(); |
||
7626 | expr_or(); |
||
7627 | } |
||
7628 | } |
||
7629 | } |
||
7630 | |||
7631 | static void expr_lor(void) |
||
7632 | { |
||
7633 | int t; |
||
7634 | |||
7635 | expr_land(); |
||
7636 | if (tok == TOK_LOR) { |
||
7637 | t = 0; |
||
7638 | for(;;) { |
||
7639 | t = gtst(0, t); |
||
7640 | if (tok != TOK_LOR) { |
||
7641 | vseti(VT_JMP, t); |
||
7642 | break; |
||
7643 | } |
||
7644 | next(); |
||
7645 | expr_land(); |
||
7646 | } |
||
7647 | } |
||
7648 | } |
||
7649 | |||
7650 | /* XXX: better constant handling */ |
||
7651 | static void expr_eq(void) |
||
7652 | { |
||
7653 | int tt, u, r1, r2, rc, t1, t2, bt1, bt2; |
||
7654 | SValue sv; |
||
7655 | CType type, type1, type2; |
||
7656 | |||
7657 | if (const_wanted) { |
||
7658 | int c1, c; |
||
7659 | expr_lor_const(); |
||
7660 | if (tok == '?') { |
||
7661 | c = vtop->c.i; |
||
7662 | vpop(); |
||
7663 | next(); |
||
7664 | if (tok == ':' && gnu_ext) { |
||
7665 | c1 = c; |
||
7666 | } else { |
||
7667 | gexpr(); |
||
7668 | c1 = vtop->c.i; |
||
7669 | vpop(); |
||
7670 | } |
||
7671 | skip(':'); |
||
7672 | expr_eq(); |
||
7673 | if (c) |
||
7674 | vtop->c.i = c1; |
||
7675 | } |
||
7676 | } else { |
||
7677 | expr_lor(); |
||
7678 | if (tok == '?') { |
||
7679 | next(); |
||
7680 | if (vtop != vstack) { |
||
7681 | /* needed to avoid having different registers saved in |
||
7682 | each branch */ |
||
7683 | if (is_float(vtop->type.t)) |
||
7684 | rc = RC_FLOAT; |
||
7685 | else |
||
7686 | rc = RC_INT; |
||
7687 | gv(rc); |
||
7688 | save_regs(1); |
||
7689 | } |
||
7690 | if (tok == ':' && gnu_ext) { |
||
7691 | gv_dup(); |
||
7692 | tt = gtst(1, 0); |
||
7693 | } else { |
||
7694 | tt = gtst(1, 0); |
||
7695 | gexpr(); |
||
7696 | } |
||
7697 | type1 = vtop->type; |
||
7698 | sv = *vtop; /* save value to handle it later */ |
||
7699 | vtop--; /* no vpop so that FP stack is not flushed */ |
||
7700 | skip(':'); |
||
7701 | u = gjmp(0); |
||
7702 | gsym(tt); |
||
7703 | expr_eq(); |
||
7704 | type2 = vtop->type; |
||
7705 | |||
7706 | t1 = type1.t; |
||
7707 | bt1 = t1 & VT_BTYPE; |
||
7708 | t2 = type2.t; |
||
7709 | bt2 = t2 & VT_BTYPE; |
||
7710 | /* cast operands to correct type according to ISOC rules */ |
||
7711 | if (is_float(bt1) || is_float(bt2)) { |
||
7712 | if (bt1 == VT_LDOUBLE || bt2 == VT_LDOUBLE) { |
||
7713 | type.t = VT_LDOUBLE; |
||
7714 | } else if (bt1 == VT_DOUBLE || bt2 == VT_DOUBLE) { |
||
7715 | type.t = VT_DOUBLE; |
||
7716 | } else { |
||
7717 | type.t = VT_FLOAT; |
||
7718 | } |
||
7719 | } else if (bt1 == VT_LLONG || bt2 == VT_LLONG) { |
||
7720 | /* cast to biggest op */ |
||
7721 | type.t = VT_LLONG; |
||
7722 | /* convert to unsigned if it does not fit in a long long */ |
||
7723 | if ((t1 & (VT_BTYPE | VT_UNSIGNED)) == (VT_LLONG | VT_UNSIGNED) || |
||
7724 | (t2 & (VT_BTYPE | VT_UNSIGNED)) == (VT_LLONG | VT_UNSIGNED)) |
||
7725 | type.t |= VT_UNSIGNED; |
||
7726 | } else if (bt1 == VT_PTR || bt2 == VT_PTR) { |
||
7727 | /* XXX: test pointer compatibility */ |
||
7728 | type = type1; |
||
7729 | } else if (bt1 == VT_STRUCT || bt2 == VT_STRUCT) { |
||
7730 | /* XXX: test structure compatibility */ |
||
7731 | type = type1; |
||
7732 | } else if (bt1 == VT_VOID || bt2 == VT_VOID) { |
||
7733 | /* NOTE: as an extension, we accept void on only one side */ |
||
7734 | type.t = VT_VOID; |
||
7735 | } else { |
||
7736 | /* integer operations */ |
||
7737 | type.t = VT_INT; |
||
7738 | /* convert to unsigned if it does not fit in an integer */ |
||
7739 | if ((t1 & (VT_BTYPE | VT_UNSIGNED)) == (VT_INT | VT_UNSIGNED) || |
||
7740 | (t2 & (VT_BTYPE | VT_UNSIGNED)) == (VT_INT | VT_UNSIGNED)) |
||
7741 | type.t |= VT_UNSIGNED; |
||
7742 | } |
||
7743 | |||
7744 | /* now we convert second operand */ |
||
7745 | gen_cast(&type); |
||
7746 | rc = RC_INT; |
||
7747 | if (is_float(type.t)) { |
||
7748 | rc = RC_FLOAT; |
||
7749 | } else if ((type.t & VT_BTYPE) == VT_LLONG) { |
||
7750 | /* for long longs, we use fixed registers to avoid having |
||
7751 | to handle a complicated move */ |
||
7752 | rc = RC_IRET; |
||
7753 | } |
||
7754 | |||
7755 | r2 = gv(rc); |
||
7756 | /* this is horrible, but we must also convert first |
||
7757 | operand */ |
||
7758 | tt = gjmp(0); |
||
7759 | gsym(u); |
||
7760 | /* put again first value and cast it */ |
||
7761 | *vtop = sv; |
||
7762 | gen_cast(&type); |
||
7763 | r1 = gv(rc); |
||
7764 | move_reg(r2, r1); |
||
7765 | vtop->r = r2; |
||
7766 | gsym(tt); |
||
7767 | } |
||
7768 | } |
||
7769 | } |
||
7770 | |||
7771 | static void gexpr(void) |
||
7772 | { |
||
7773 | while (1) { |
||
7774 | expr_eq(); |
||
7775 | if (tok != ',') |
||
7776 | break; |
||
7777 | vpop(); |
||
7778 | next(); |
||
7779 | } |
||
7780 | } |
||
7781 | |||
7782 | /* parse an expression and return its type without any side effect. */ |
||
7783 | static void expr_type(CType *type) |
||
7784 | { |
||
7785 | int saved_nocode_wanted; |
||
7786 | |||
7787 | saved_nocode_wanted = nocode_wanted; |
||
7788 | nocode_wanted = 1; |
||
7789 | gexpr(); |
||
7790 | *type = vtop->type; |
||
7791 | vpop(); |
||
7792 | nocode_wanted = saved_nocode_wanted; |
||
7793 | } |
||
7794 | |||
7795 | /* parse a unary expression and return its type without any side |
||
7796 | effect. */ |
||
7797 | static void unary_type(CType *type) |
||
7798 | { |
||
7799 | int a; |
||
7800 | |||
7801 | a = nocode_wanted; |
||
7802 | nocode_wanted = 1; |
||
7803 | unary(); |
||
7804 | *type = vtop->type; |
||
7805 | vpop(); |
||
7806 | nocode_wanted = a; |
||
7807 | } |
||
7808 | |||
7809 | /* parse a constant expression and return value in vtop. */ |
||
7810 | static void expr_const1(void) |
||
7811 | { |
||
7812 | int a; |
||
7813 | a = const_wanted; |
||
7814 | const_wanted = 1; |
||
7815 | expr_eq(); |
||
7816 | const_wanted = a; |
||
7817 | } |
||
7818 | |||
7819 | /* parse an integer constant and return its value. */ |
||
7820 | static int expr_const(void) |
||
7821 | { |
||
7822 | int c; |
||
7823 | expr_const1(); |
||
7824 | if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) != VT_CONST) |
||
7825 | expect("constant expression"); |
||
7826 | c = vtop->c.i; |
||
7827 | vpop(); |
||
7828 | return c; |
||
7829 | } |
||
7830 | |||
7831 | /* return the label token if current token is a label, otherwise |
||
7832 | return zero */ |
||
7833 | static int is_label(void) |
||
7834 | { |
||
7835 | int last_tok; |
||
7836 | |||
7837 | /* fast test first */ |
||
7838 | if (tok < TOK_UIDENT) |
||
7839 | return 0; |
||
7840 | /* no need to save tokc because tok is an identifier */ |
||
7841 | last_tok = tok; |
||
7842 | next(); |
||
7843 | if (tok == ':') { |
||
7844 | next(); |
||
7845 | return last_tok; |
||
7846 | } else { |
||
7847 | unget_tok(last_tok); |
||
7848 | return 0; |
||
7849 | } |
||
7850 | } |
||
7851 | |||
7852 | static void block(int *bsym, int *csym, int *case_sym, int *def_sym, |
||
7853 | int case_reg, int is_expr) |
||
7854 | { |
||
7855 | int a, b, c, d; |
||
7856 | Sym *s; |
||
7857 | |||
7858 | /* generate line number info */ |
||
7859 | if (do_debug && |
||
7860 | (last_line_num != file->line_num || last_ind != ind)) { |
||
7861 | put_stabn(N_SLINE, 0, file->line_num, ind - func_ind); |
||
7862 | last_ind = ind; |
||
7863 | last_line_num = file->line_num; |
||
7864 | } |
||
7865 | |||
7866 | if (is_expr) { |
||
7867 | /* default return value is (void) */ |
||
7868 | vpushi(0); |
||
7869 | vtop->type.t = VT_VOID; |
||
7870 | } |
||
7871 | |||
7872 | if (tok == TOK_IF) { |
||
7873 | /* if test */ |
||
7874 | next(); |
||
7875 | skip('('); |
||
7876 | gexpr(); |
||
7877 | skip(')'); |
||
7878 | a = gtst(1, 0); |
||
7879 | block(bsym, csym, case_sym, def_sym, case_reg, 0); |
||
7880 | c = tok; |
||
7881 | if (c == TOK_ELSE) { |
||
7882 | next(); |
||
7883 | d = gjmp(0); |
||
7884 | gsym(a); |
||
7885 | block(bsym, csym, case_sym, def_sym, case_reg, 0); |
||
7886 | gsym(d); /* patch else jmp */ |
||
7887 | } else |
||
7888 | gsym(a); |
||
7889 | } else if (tok == TOK_WHILE) { |
||
7890 | next(); |
||
7891 | d = ind; |
||
7892 | skip('('); |
||
7893 | gexpr(); |
||
7894 | skip(')'); |
||
7895 | a = gtst(1, 0); |
||
7896 | b = 0; |
||
7897 | block(&a, &b, case_sym, def_sym, case_reg, 0); |
||
7898 | gjmp_addr(d); |
||
7899 | gsym(a); |
||
7900 | gsym_addr(b, d); |
||
7901 | } else if (tok == '{') { |
||
7902 | Sym *llabel; |
||
7903 | |||
7904 | next(); |
||
7905 | /* record local declaration stack position */ |
||
7906 | s = local_stack; |
||
7907 | llabel = local_label_stack; |
||
7908 | /* handle local labels declarations */ |
||
7909 | if (tok == TOK_LABEL) { |
||
7910 | next(); |
||
7911 | for(;;) { |
||
7912 | if (tok < TOK_UIDENT) |
||
7913 | expect("label identifier"); |
||
7914 | label_push(&local_label_stack, tok, LABEL_DECLARED); |
||
7915 | next(); |
||
7916 | if (tok == ',') { |
||
7917 | next(); |
||
7918 | } else { |
||
7919 | skip(';'); |
||
7920 | break; |
||
7921 | } |
||
7922 | } |
||
7923 | } |
||
7924 | while (tok != '}') { |
||
7925 | decl(VT_LOCAL); |
||
7926 | if (tok != '}') { |
||
7927 | if (is_expr) |
||
7928 | vpop(); |
||
7929 | block(bsym, csym, case_sym, def_sym, case_reg, is_expr); |
||
7930 | } |
||
7931 | } |
||
7932 | /* pop locally defined labels */ |
||
7933 | label_pop(&local_label_stack, llabel); |
||
7934 | /* pop locally defined symbols */ |
||
7935 | sym_pop(&local_stack, s); |
||
7936 | next(); |
||
7937 | } else if (tok == TOK_RETURN) { |
||
7938 | next(); |
||
7939 | if (tok != ';') { |
||
7940 | gexpr(); |
||
7941 | gen_assign_cast(&func_vt); |
||
7942 | if ((func_vt.t & VT_BTYPE) == VT_STRUCT) { |
||
7943 | CType type; |
||
7944 | /* if returning structure, must copy it to implicit |
||
7945 | first pointer arg location */ |
||
7946 | type = func_vt; |
||
7947 | mk_pointer(&type); |
||
7948 | vset(&type, VT_LOCAL | VT_LVAL, func_vc); |
||
7949 | indir(); |
||
7950 | vswap(); |
||
7951 | /* copy structure value to pointer */ |
||
7952 | vstore(); |
||
7953 | } else if (is_float(func_vt.t)) { |
||
7954 | gv(RC_FRET); |
||
7955 | } else { |
||
7956 | gv(RC_IRET); |
||
7957 | } |
||
7958 | vtop--; /* NOT vpop() because on x86 it would flush the fp stack */ |
||
7959 | } |
||
7960 | skip(';'); |
||
7961 | rsym = gjmp(rsym); /* jmp */ |
||
7962 | } else if (tok == TOK_BREAK) { |
||
7963 | /* compute jump */ |
||
7964 | if (!bsym) |
||
7965 | error("cannot break"); |
||
7966 | *bsym = gjmp(*bsym); |
||
7967 | next(); |
||
7968 | skip(';'); |
||
7969 | } else if (tok == TOK_CONTINUE) { |
||
7970 | /* compute jump */ |
||
7971 | if (!csym) |
||
7972 | error("cannot continue"); |
||
7973 | *csym = gjmp(*csym); |
||
7974 | next(); |
||
7975 | skip(';'); |
||
7976 | } else if (tok == TOK_FOR) { |
||
7977 | int e; |
||
7978 | next(); |
||
7979 | skip('('); |
||
7980 | if (tok != ';') { |
||
7981 | gexpr(); |
||
7982 | vpop(); |
||
7983 | } |
||
7984 | skip(';'); |
||
7985 | d = ind; |
||
7986 | c = ind; |
||
7987 | a = 0; |
||
7988 | b = 0; |
||
7989 | if (tok != ';') { |
||
7990 | gexpr(); |
||
7991 | a = gtst(1, 0); |
||
7992 | } |
||
7993 | skip(';'); |
||
7994 | if (tok != ')') { |
||
7995 | e = gjmp(0); |
||
7996 | c = ind; |
||
7997 | gexpr(); |
||
7998 | vpop(); |
||
7999 | gjmp_addr(d); |
||
8000 | gsym(e); |
||
8001 | } |
||
8002 | skip(')'); |
||
8003 | block(&a, &b, case_sym, def_sym, case_reg, 0); |
||
8004 | gjmp_addr(c); |
||
8005 | gsym(a); |
||
8006 | gsym_addr(b, c); |
||
8007 | } else |
||
8008 | if (tok == TOK_DO) { |
||
8009 | next(); |
||
8010 | a = 0; |
||
8011 | b = 0; |
||
8012 | d = ind; |
||
8013 | block(&a, &b, case_sym, def_sym, case_reg, 0); |
||
8014 | skip(TOK_WHILE); |
||
8015 | skip('('); |
||
8016 | gsym(b); |
||
8017 | gexpr(); |
||
8018 | c = gtst(0, 0); |
||
8019 | gsym_addr(c, d); |
||
8020 | skip(')'); |
||
8021 | gsym(a); |
||
8022 | skip(';'); |
||
8023 | } else |
||
8024 | if (tok == TOK_SWITCH) { |
||
8025 | next(); |
||
8026 | skip('('); |
||
8027 | gexpr(); |
||
8028 | /* XXX: other types than integer */ |
||
8029 | case_reg = gv(RC_INT); |
||
8030 | vpop(); |
||
8031 | skip(')'); |
||
8032 | a = 0; |
||
8033 | b = gjmp(0); /* jump to first case */ |
||
8034 | c = 0; |
||
8035 | block(&a, csym, &b, &c, case_reg, 0); |
||
8036 | /* if no default, jmp after switch */ |
||
8037 | if (c == 0) |
||
8038 | c = ind; |
||
8039 | /* default label */ |
||
8040 | gsym_addr(b, c); |
||
8041 | /* break label */ |
||
8042 | gsym(a); |
||
8043 | } else |
||
8044 | if (tok == TOK_CASE) { |
||
8045 | int v1, v2; |
||
8046 | if (!case_sym) |
||
8047 | expect("switch"); |
||
8048 | next(); |
||
8049 | v1 = expr_const(); |
||
8050 | v2 = v1; |
||
8051 | if (gnu_ext && tok == TOK_DOTS) { |
||
8052 | next(); |
||
8053 | v2 = expr_const(); |
||
8054 | if (v2 < v1) |
||
8055 | warning("empty case range"); |
||
8056 | } |
||
8057 | /* since a case is like a label, we must skip it with a jmp */ |
||
8058 | b = gjmp(0); |
||
8059 | gsym(*case_sym); |
||
8060 | vseti(case_reg, 0); |
||
8061 | vpushi(v1); |
||
8062 | if (v1 == v2) { |
||
8063 | gen_op(TOK_EQ); |
||
8064 | *case_sym = gtst(1, 0); |
||
8065 | } else { |
||
8066 | gen_op(TOK_GE); |
||
8067 | *case_sym = gtst(1, 0); |
||
8068 | vseti(case_reg, 0); |
||
8069 | vpushi(v2); |
||
8070 | gen_op(TOK_LE); |
||
8071 | *case_sym = gtst(1, *case_sym); |
||
8072 | } |
||
8073 | gsym(b); |
||
8074 | skip(':'); |
||
8075 | is_expr = 0; |
||
8076 | goto block_after_label; |
||
8077 | } else |
||
8078 | if (tok == TOK_DEFAULT) { |
||
8079 | next(); |
||
8080 | skip(':'); |
||
8081 | if (!def_sym) |
||
8082 | expect("switch"); |
||
8083 | if (*def_sym) |
||
8084 | error("too many 'default'"); |
||
8085 | *def_sym = ind; |
||
8086 | is_expr = 0; |
||
8087 | goto block_after_label; |
||
8088 | } else |
||
8089 | if (tok == TOK_GOTO) { |
||
8090 | next(); |
||
8091 | if (tok == '*' && gnu_ext) { |
||
8092 | /* computed goto */ |
||
8093 | next(); |
||
8094 | gexpr(); |
||
8095 | if ((vtop->type.t & VT_BTYPE) != VT_PTR) |
||
8096 | expect("pointer"); |
||
8097 | ggoto(); |
||
8098 | } else if (tok >= TOK_UIDENT) { |
||
8099 | s = label_find(tok); |
||
8100 | /* put forward definition if needed */ |
||
8101 | if (!s) { |
||
8102 | s = label_push(&global_label_stack, tok, LABEL_FORWARD); |
||
8103 | } else { |
||
8104 | if (s->r == LABEL_DECLARED) |
||
8105 | s->r = LABEL_FORWARD; |
||
8106 | } |
||
8107 | /* label already defined */ |
||
8108 | if (s->r & LABEL_FORWARD) |
||
8109 | s->next = (void *)gjmp((long)s->next); |
||
8110 | else |
||
8111 | gjmp_addr((long)s->next); |
||
8112 | next(); |
||
8113 | } else { |
||
8114 | expect("label identifier"); |
||
8115 | } |
||
8116 | skip(';'); |
||
8117 | } else if (tok == TOK_ASM1 || tok == TOK_ASM2 || tok == TOK_ASM3) { |
||
8118 | asm_instr(); |
||
8119 | } else { |
||
8120 | b = is_label(); |
||
8121 | if (b) { |
||
8122 | /* label case */ |
||
8123 | s = label_find(b); |
||
8124 | if (s) { |
||
8125 | if (s->r == LABEL_DEFINED) |
||
8126 | error("duplicate label '%s'", get_tok_str(s->v, NULL)); |
||
8127 | gsym((long)s->next); |
||
8128 | s->r = LABEL_DEFINED; |
||
8129 | } else { |
||
8130 | s = label_push(&global_label_stack, b, LABEL_DEFINED); |
||
8131 | } |
||
8132 | s->next = (void *)ind; |
||
8133 | /* we accept this, but it is a mistake */ |
||
8134 | block_after_label: |
||
8135 | if (tok == '}') { |
||
8136 | warning("deprecated use of label at end of compound statement"); |
||
8137 | } else { |
||
8138 | if (is_expr) |
||
8139 | vpop(); |
||
8140 | block(bsym, csym, case_sym, def_sym, case_reg, is_expr); |
||
8141 | } |
||
8142 | } else { |
||
8143 | /* expression case */ |
||
8144 | if (tok != ';') { |
||
8145 | if (is_expr) { |
||
8146 | vpop(); |
||
8147 | gexpr(); |
||
8148 | } else { |
||
8149 | gexpr(); |
||
8150 | vpop(); |
||
8151 | } |
||
8152 | } |
||
8153 | skip(';'); |
||
8154 | } |
||
8155 | } |
||
8156 | } |
||
8157 | |||
8158 | /* t is the array or struct type. c is the array or struct |
||
8159 | address. cur_index/cur_field is the pointer to the current |
||
8160 | value. 'size_only' is true if only size info is needed (only used |
||
8161 | in arrays) */ |
||
8162 | static void decl_designator(CType *type, Section *sec, unsigned long c, |
||
8163 | int *cur_index, Sym **cur_field, |
||
8164 | int size_only) |
||
8165 | { |
||
8166 | Sym *s, *f; |
||
8167 | int notfirst, index, index_last, align, l, nb_elems, elem_size; |
||
8168 | CType type1; |
||
8169 | |||
8170 | notfirst = 0; |
||
8171 | elem_size = 0; |
||
8172 | nb_elems = 1; |
||
8173 | if (gnu_ext && (l = is_label()) != 0) |
||
8174 | goto struct_field; |
||
8175 | while (tok == '[' || tok == '.') { |
||
8176 | if (tok == '[') { |
||
8177 | if (!(type->t & VT_ARRAY)) |
||
8178 | expect("array type"); |
||
8179 | s = type->ref; |
||
8180 | next(); |
||
8181 | index = expr_const(); |
||
8182 | if (index < 0 || (s->c >= 0 && index >= s->c)) |
||
8183 | expect("invalid index"); |
||
8184 | if (tok == TOK_DOTS && gnu_ext) { |
||
8185 | next(); |
||
8186 | index_last = expr_const(); |
||
8187 | if (index_last < 0 || |
||
8188 | (s->c >= 0 && index_last >= s->c) || |
||
8189 | index_last < index) |
||
8190 | expect("invalid index"); |
||
8191 | } else { |
||
8192 | index_last = index; |
||
8193 | } |
||
8194 | skip(']'); |
||
8195 | if (!notfirst) |
||
8196 | *cur_index = index_last; |
||
8197 | type = pointed_type(type); |
||
8198 | elem_size = type_size(type, &align); |
||
8199 | c += index * elem_size; |
||
8200 | /* NOTE: we only support ranges for last designator */ |
||
8201 | nb_elems = index_last - index + 1; |
||
8202 | if (nb_elems != 1) { |
||
8203 | notfirst = 1; |
||
8204 | break; |
||
8205 | } |
||
8206 | } else { |
||
8207 | next(); |
||
8208 | l = tok; |
||
8209 | next(); |
||
8210 | struct_field: |
||
8211 | if ((type->t & VT_BTYPE) != VT_STRUCT) |
||
8212 | expect("struct/union type"); |
||
8213 | s = type->ref; |
||
8214 | l |= SYM_FIELD; |
||
8215 | f = s->next; |
||
8216 | while (f) { |
||
8217 | if (f->v == l) |
||
8218 | break; |
||
8219 | f = f->next; |
||
8220 | } |
||
8221 | if (!f) |
||
8222 | expect("field"); |
||
8223 | if (!notfirst) |
||
8224 | *cur_field = f; |
||
8225 | /* XXX: fix this mess by using explicit storage field */ |
||
8226 | type1 = f->type; |
||
8227 | type1.t |= (type->t & ~VT_TYPE); |
||
8228 | type = &type1; |
||
8229 | c += f->c; |
||
8230 | } |
||
8231 | notfirst = 1; |
||
8232 | } |
||
8233 | if (notfirst) { |
||
8234 | if (tok == '=') { |
||
8235 | next(); |
||
8236 | } else { |
||
8237 | if (!gnu_ext) |
||
8238 | expect("="); |
||
8239 | } |
||
8240 | } else { |
||
8241 | if (type->t & VT_ARRAY) { |
||
8242 | index = *cur_index; |
||
8243 | type = pointed_type(type); |
||
8244 | c += index * type_size(type, &align); |
||
8245 | } else { |
||
8246 | f = *cur_field; |
||
8247 | if (!f) |
||
8248 | error("too many field init"); |
||
8249 | /* XXX: fix this mess by using explicit storage field */ |
||
8250 | type1 = f->type; |
||
8251 | type1.t |= (type->t & ~VT_TYPE); |
||
8252 | type = &type1; |
||
8253 | c += f->c; |
||
8254 | } |
||
8255 | } |
||
8256 | decl_initializer(type, sec, c, 0, size_only); |
||
8257 | |||
8258 | /* XXX: make it more general */ |
||
8259 | if (!size_only && nb_elems > 1) { |
||
8260 | unsigned long c_end; |
||
8261 | uint8_t *src, *dst; |
||
8262 | int i; |
||
8263 | |||
8264 | if (!sec) |
||
8265 | error("range init not supported yet for dynamic storage"); |
||
8266 | c_end = c + nb_elems * elem_size; |
||
8267 | if (c_end > sec->data_allocated) |
||
8268 | section_realloc(sec, c_end); |
||
8269 | src = sec->data + c; |
||
8270 | dst = src; |
||
8271 | for(i = 1; i < nb_elems; i++) { |
||
8272 | dst += elem_size; |
||
8273 | memcpy(dst, src, elem_size); |
||
8274 | } |
||
8275 | } |
||
8276 | } |
||
8277 | |||
8278 | #define EXPR_VAL 0 |
||
8279 | #define EXPR_CONST 1 |
||
8280 | #define EXPR_ANY 2 |
||
8281 | |||
8282 | /* store a value or an expression directly in global data or in local array */ |
||
8283 | static void init_putv(CType *type, Section *sec, unsigned long c, |
||
8284 | int v, int expr_type) |
||
8285 | { |
||
8286 | int saved_global_expr, bt, bit_pos, bit_size; |
||
8287 | void *ptr; |
||
8288 | unsigned long long bit_mask; |
||
8289 | CType dtype; |
||
8290 | |||
8291 | switch(expr_type) { |
||
8292 | case EXPR_VAL: |
||
8293 | vpushi(v); |
||
8294 | break; |
||
8295 | case EXPR_CONST: |
||
8296 | /* compound literals must be allocated globally in this case */ |
||
8297 | saved_global_expr = global_expr; |
||
8298 | global_expr = 1; |
||
8299 | expr_const1(); |
||
8300 | global_expr = saved_global_expr; |
||
8301 | /* NOTE: symbols are accepted */ |
||
8302 | if ((vtop->r & (VT_VALMASK | VT_LVAL)) != VT_CONST) |
||
8303 | error("initializer element is not constant"); |
||
8304 | break; |
||
8305 | case EXPR_ANY: |
||
8306 | expr_eq(); |
||
8307 | break; |
||
8308 | } |
||
8309 | |||
8310 | dtype = *type; |
||
8311 | dtype.t &= ~VT_CONSTANT; /* need to do that to avoid false warning */ |
||
8312 | |||
8313 | if (sec) { |
||
8314 | /* XXX: not portable */ |
||
8315 | /* XXX: generate error if incorrect relocation */ |
||
8316 | gen_assign_cast(&dtype); |
||
8317 | bt = type->t & VT_BTYPE; |
||
8318 | ptr = sec->data + c; |
||
8319 | /* XXX: make code faster ? */ |
||
8320 | if (!(type->t & VT_BITFIELD)) { |
||
8321 | bit_pos = 0; |
||
8322 | bit_size = 32; |
||
8323 | bit_mask = -1LL; |
||
8324 | } else { |
||
8325 | bit_pos = (vtop->type.t >> VT_STRUCT_SHIFT) & 0x3f; |
||
8326 | bit_size = (vtop->type.t >> (VT_STRUCT_SHIFT + 6)) & 0x3f; |
||
8327 | bit_mask = (1LL << bit_size) - 1; |
||
8328 | } |
||
8329 | if ((vtop->r & VT_SYM) && |
||
8330 | (bt == VT_BYTE || |
||
8331 | bt == VT_SHORT || |
||
8332 | bt == VT_DOUBLE || |
||
8333 | bt == VT_LDOUBLE || |
||
8334 | bt == VT_LLONG || |
||
8335 | (bt == VT_INT && bit_size != 32))) |
||
8336 | error("initializer element is not computable at load time"); |
||
8337 | switch(bt) { |
||
8338 | case VT_BYTE: |
||
8339 | *(char *)ptr |= (vtop->c.i & bit_mask) << bit_pos; |
||
8340 | break; |
||
8341 | case VT_SHORT: |
||
8342 | *(short *)ptr |= (vtop->c.i & bit_mask) << bit_pos; |
||
8343 | break; |
||
8344 | case VT_DOUBLE: |
||
8345 | *(double *)ptr = vtop->c.d; |
||
8346 | break; |
||
8347 | case VT_LDOUBLE: |
||
8348 | *(long double *)ptr = vtop->c.ld; |
||
8349 | break; |
||
8350 | case VT_LLONG: |
||
8351 | *(long long *)ptr |= (vtop->c.ll & bit_mask) << bit_pos; |
||
8352 | break; |
||
8353 | default: |
||
8354 | if (vtop->r & VT_SYM) { |
||
8355 | greloc(sec, vtop->sym, c, R_DATA_32); |
||
8356 | } |
||
8357 | *(int *)ptr |= (vtop->c.i & bit_mask) << bit_pos; |
||
8358 | break; |
||
8359 | } |
||
8360 | vtop--; |
||
8361 | } else { |
||
8362 | vset(&dtype, VT_LOCAL, c); |
||
8363 | vswap(); |
||
8364 | vstore(); |
||
8365 | vpop(); |
||
8366 | } |
||
8367 | } |
||
8368 | |||
8369 | /* put zeros for variable based init */ |
||
8370 | static void init_putz(CType *t, Section *sec, unsigned long c, int size) |
||
8371 | { |
||
8372 | if (sec) { |
||
8373 | /* nothing to do because globals are already set to zero */ |
||
8374 | } else { |
||
8375 | vpush_global_sym(&func_old_type, TOK_memset); |
||
8376 | vseti(VT_LOCAL, c); |
||
8377 | vpushi(0); |
||
8378 | vpushi(size); |
||
8379 | gfunc_call(3); |
||
8380 | } |
||
8381 | } |
||
8382 | |||
8383 | /* 't' contains the type and storage info. 'c' is the offset of the |
||
8384 | object in section 'sec'. If 'sec' is NULL, it means stack based |
||
8385 | allocation. 'first' is true if array '{' must be read (multi |
||
8386 | dimension implicit array init handling). 'size_only' is true if |
||
8387 | size only evaluation is wanted (only for arrays). */ |
||
8388 | static void decl_initializer(CType *type, Section *sec, unsigned long c, |
||
8389 | int first, int size_only) |
||
8390 | { |
||
8391 | int index, array_length, n, no_oblock, nb, parlevel, i; |
||
8392 | int size1, align1, expr_type; |
||
8393 | Sym *s, *f; |
||
8394 | CType *t1; |
||
8395 | |||
8396 | if (type->t & VT_ARRAY) { |
||
8397 | s = type->ref; |
||
8398 | n = s->c; |
||
8399 | array_length = 0; |
||
8400 | t1 = pointed_type(type); |
||
8401 | size1 = type_size(t1, &align1); |
||
8402 | |||
8403 | no_oblock = 1; |
||
8404 | if ((first && tok != TOK_LSTR && tok != TOK_STR) || |
||
8405 | tok == '{') { |
||
8406 | skip('{'); |
||
8407 | no_oblock = 0; |
||
8408 | } |
||
8409 | |||
8410 | /* only parse strings here if correct type (otherwise: handle |
||
8411 | them as ((w)char *) expressions */ |
||
8412 | if ((tok == TOK_LSTR && |
||
8413 | (t1->t & VT_BTYPE) == VT_INT) || |
||
8414 | (tok == TOK_STR && |
||
8415 | (t1->t & VT_BTYPE) == VT_BYTE)) { |
||
8416 | while (tok == TOK_STR || tok == TOK_LSTR) { |
||
8417 | int cstr_len, ch; |
||
8418 | CString *cstr; |
||
8419 | |||
8420 | cstr = tokc.cstr; |
||
8421 | /* compute maximum number of chars wanted */ |
||
8422 | if (tok == TOK_STR) |
||
8423 | cstr_len = cstr->size; |
||
8424 | else |
||
8425 | cstr_len = cstr->size / sizeof(int); |
||
8426 | cstr_len--; |
||
8427 | nb = cstr_len; |
||
8428 | if (n >= 0 && nb > (n - array_length)) |
||
8429 | nb = n - array_length; |
||
8430 | if (!size_only) { |
||
8431 | if (cstr_len > nb) |
||
8432 | warning("initializer-string for array is too long"); |
||
8433 | /* in order to go faster for common case (char |
||
8434 | string in global variable, we handle it |
||
8435 | specifically */ |
||
8436 | if (sec && tok == TOK_STR && size1 == 1) { |
||
8437 | memcpy(sec->data + c + array_length, cstr->data, nb); |
||
8438 | } else { |
||
8439 | for(i=0;i |
||
8440 | if (tok == TOK_STR) |
||
8441 | ch = ((unsigned char *)cstr->data)[i]; |
||
8442 | else |
||
8443 | ch = ((int *)cstr->data)[i]; |
||
8444 | init_putv(t1, sec, c + (array_length + i) * size1, |
||
8445 | ch, EXPR_VAL); |
||
8446 | } |
||
8447 | } |
||
8448 | } |
||
8449 | array_length += nb; |
||
8450 | next(); |
||
8451 | } |
||
8452 | /* only add trailing zero if enough storage (no |
||
8453 | warning in this case since it is standard) */ |
||
8454 | if (n < 0 || array_length < n) { |
||
8455 | if (!size_only) { |
||
8456 | init_putv(t1, sec, c + (array_length * size1), 0, EXPR_VAL); |
||
8457 | } |
||
8458 | array_length++; |
||
8459 | } |
||
8460 | } else { |
||
8461 | index = 0; |
||
8462 | while (tok != '}') { |
||
8463 | decl_designator(type, sec, c, &index, NULL, size_only); |
||
8464 | if (n >= 0 && index >= n) |
||
8465 | error("index too large"); |
||
8466 | /* must put zero in holes (note that doing it that way |
||
8467 | ensures that it even works with designators) */ |
||
8468 | if (!size_only && array_length < index) { |
||
8469 | init_putz(t1, sec, c + array_length * size1, |
||
8470 | (index - array_length) * size1); |
||
8471 | } |
||
8472 | index++; |
||
8473 | if (index > array_length) |
||
8474 | array_length = index; |
||
8475 | /* special test for multi dimensional arrays (may not |
||
8476 | be strictly correct if designators are used at the |
||
8477 | same time) */ |
||
8478 | if (index >= n && no_oblock) |
||
8479 | break; |
||
8480 | if (tok == '}') |
||
8481 | break; |
||
8482 | skip(','); |
||
8483 | } |
||
8484 | } |
||
8485 | if (!no_oblock) |
||
8486 | skip('}'); |
||
8487 | /* put zeros at the end */ |
||
8488 | if (!size_only && n >= 0 && array_length < n) { |
||
8489 | init_putz(t1, sec, c + array_length * size1, |
||
8490 | (n - array_length) * size1); |
||
8491 | } |
||
8492 | /* patch type size if needed */ |
||
8493 | if (n < 0) |
||
8494 | s->c = array_length; |
||
8495 | } else if ((type->t & VT_BTYPE) == VT_STRUCT && |
||
8496 | (sec || !first || tok == '{')) { |
||
8497 | int par_count; |
||
8498 | |||
8499 | /* NOTE: the previous test is a specific case for automatic |
||
8500 | struct/union init */ |
||
8501 | /* XXX: union needs only one init */ |
||
8502 | |||
8503 | /* XXX: this test is incorrect for local initializers |
||
8504 | beginning with ( without {. It would be much more difficult |
||
8505 | to do it correctly (ideally, the expression parser should |
||
8506 | be used in all cases) */ |
||
8507 | par_count = 0; |
||
8508 | if (tok == '(') { |
||
8509 | AttributeDef ad1; |
||
8510 | CType type1; |
||
8511 | next(); |
||
8512 | while (tok == '(') { |
||
8513 | par_count++; |
||
8514 | next(); |
||
8515 | } |
||
8516 | if (!parse_btype(&type1, &ad1)) |
||
8517 | expect("cast"); |
||
8518 | type_decl(&type1, &ad1, &n, TYPE_ABSTRACT); |
||
8519 | #if 0 |
||
8520 | if (!is_assignable_types(type, &type1)) |
||
8521 | error("invalid type for cast"); |
||
8522 | #endif |
||
8523 | skip(')'); |
||
8524 | } |
||
8525 | no_oblock = 1; |
||
8526 | if (first || tok == '{') { |
||
8527 | skip('{'); |
||
8528 | no_oblock = 0; |
||
8529 | } |
||
8530 | s = type->ref; |
||
8531 | f = s->next; |
||
8532 | array_length = 0; |
||
8533 | index = 0; |
||
8534 | n = s->c; |
||
8535 | while (tok != '}') { |
||
8536 | decl_designator(type, sec, c, NULL, &f, size_only); |
||
8537 | index = f->c; |
||
8538 | if (!size_only && array_length < index) { |
||
8539 | init_putz(type, sec, c + array_length, |
||
8540 | index - array_length); |
||
8541 | } |
||
8542 | index = index + type_size(&f->type, &align1); |
||
8543 | if (index > array_length) |
||
8544 | array_length = index; |
||
8545 | f = f->next; |
||
8546 | if (no_oblock && f == NULL) |
||
8547 | break; |
||
8548 | if (tok == '}') |
||
8549 | break; |
||
8550 | skip(','); |
||
8551 | } |
||
8552 | /* put zeros at the end */ |
||
8553 | if (!size_only && array_length < n) { |
||
8554 | init_putz(type, sec, c + array_length, |
||
8555 | n - array_length); |
||
8556 | } |
||
8557 | if (!no_oblock) |
||
8558 | skip('}'); |
||
8559 | while (par_count) { |
||
8560 | skip(')'); |
||
8561 | par_count--; |
||
8562 | } |
||
8563 | } else if (tok == '{') { |
||
8564 | next(); |
||
8565 | decl_initializer(type, sec, c, first, size_only); |
||
8566 | skip('}'); |
||
8567 | } else if (size_only) { |
||
8568 | /* just skip expression */ |
||
8569 | parlevel = 0; |
||
8570 | while ((parlevel > 0 || (tok != '}' && tok != ',')) && |
||
8571 | tok != -1) { |
||
8572 | if (tok == '(') |
||
8573 | parlevel++; |
||
8574 | else if (tok == ')') |
||
8575 | parlevel--; |
||
8576 | next(); |
||
8577 | } |
||
8578 | } else { |
||
8579 | /* currently, we always use constant expression for globals |
||
8580 | (may change for scripting case) */ |
||
8581 | expr_type = EXPR_CONST; |
||
8582 | if (!sec) |
||
8583 | expr_type = EXPR_ANY; |
||
8584 | init_putv(type, sec, c, 0, expr_type); |
||
8585 | } |
||
8586 | } |
||
8587 | |||
8588 | /* parse an initializer for type 't' if 'has_init' is non zero, and |
||
8589 | allocate space in local or global data space ('r' is either |
||
8590 | VT_LOCAL or VT_CONST). If 'v' is non zero, then an associated |
||
8591 | variable 'v' of scope 'scope' is declared before initializers are |
||
8592 | parsed. If 'v' is zero, then a reference to the new object is put |
||
8593 | in the value stack. If 'has_init' is 2, a special parsing is done |
||
8594 | to handle string constants. */ |
||
8595 | static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, |
||
8596 | int has_init, int v, int scope) |
||
8597 | { |
||
8598 | int size, align, addr, data_offset; |
||
8599 | int level; |
||
8600 | ParseState saved_parse_state; |
||
8601 | TokenString init_str; |
||
8602 | Section *sec; |
||
8603 | |||
8604 | size = type_size(type, &align); |
||
8605 | /* If unknown size, we must evaluate it before |
||
8606 | evaluating initializers because |
||
8607 | initializers can generate global data too |
||
8608 | (e.g. string pointers or ISOC99 compound |
||
8609 | literals). It also simplifies local |
||
8610 | initializers handling */ |
||
8611 | tok_str_new(&init_str); |
||
8612 | if (size < 0) { |
||
8613 | if (!has_init) |
||
8614 | error("unknown type size"); |
||
8615 | /* get all init string */ |
||
8616 | if (has_init == 2) { |
||
8617 | /* only get strings */ |
||
8618 | while (tok == TOK_STR || tok == TOK_LSTR) { |
||
8619 | tok_str_add_tok(&init_str); |
||
8620 | next(); |
||
8621 | } |
||
8622 | } else { |
||
8623 | level = 0; |
||
8624 | while (level > 0 || (tok != ',' && tok != ';')) { |
||
8625 | if (tok < 0) |
||
8626 | error("unexpected end of file in initializer"); |
||
8627 | tok_str_add_tok(&init_str); |
||
8628 | if (tok == '{') |
||
8629 | level++; |
||
8630 | else if (tok == '}') { |
||
8631 | if (level == 0) |
||
8632 | break; |
||
8633 | level--; |
||
8634 | } |
||
8635 | next(); |
||
8636 | } |
||
8637 | } |
||
8638 | tok_str_add(&init_str, -1); |
||
8639 | tok_str_add(&init_str, 0); |
||
8640 | |||
8641 | /* compute size */ |
||
8642 | save_parse_state(&saved_parse_state); |
||
8643 | |||
8644 | macro_ptr = init_str.str; |
||
8645 | next(); |
||
8646 | decl_initializer(type, NULL, 0, 1, 1); |
||
8647 | /* prepare second initializer parsing */ |
||
8648 | macro_ptr = init_str.str; |
||
8649 | next(); |
||
8650 | |||
8651 | /* if still unknown size, error */ |
||
8652 | size = type_size(type, &align); |
||
8653 | if (size < 0) |
||
8654 | error("unknown type size"); |
||
8655 | } |
||
8656 | /* take into account specified alignment if bigger */ |
||
8657 | if (ad->aligned) { |
||
8658 | if (ad->aligned > align) |
||
8659 | align = ad->aligned; |
||
8660 | } else if (ad->packed) { |
||
8661 | align = 1; |
||
8662 | } |
||
8663 | if ((r & VT_VALMASK) == VT_LOCAL) { |
||
8664 | sec = NULL; |
||
8665 | if (do_bounds_check && (type->t & VT_ARRAY)) |
||
8666 | loc--; |
||
8667 | loc = (loc - size) & -align; |
||
8668 | addr = loc; |
||
8669 | /* handles bounds */ |
||
8670 | /* XXX: currently, since we do only one pass, we cannot track |
||
8671 | '&' operators, so we add only arrays */ |
||
8672 | if (do_bounds_check && (type->t & VT_ARRAY)) { |
||
8673 | unsigned long *bounds_ptr; |
||
8674 | /* add padding between regions */ |
||
8675 | loc--; |
||
8676 | /* then add local bound info */ |
||
8677 | bounds_ptr = section_ptr_add(lbounds_section, 2 * sizeof(unsigned long)); |
||
8678 | bounds_ptr[0] = addr; |
||
8679 | bounds_ptr[1] = size; |
||
8680 | } |
||
8681 | if (v) { |
||
8682 | /* local variable */ |
||
8683 | sym_push(v, type, r, addr); |
||
8684 | } else { |
||
8685 | /* push local reference */ |
||
8686 | vset(type, r, addr); |
||
8687 | } |
||
8688 | } else { |
||
8689 | Sym *sym; |
||
8690 | |||
8691 | sym = NULL; |
||
8692 | if (v && scope == VT_CONST) { |
||
8693 | /* see if the symbol was already defined */ |
||
8694 | sym = sym_find(v); |
||
8695 | if (sym) { |
||
8696 | if (!is_compatible_types(&sym->type, type)) |
||
8697 | error("incompatible types for redefinition of '%s'", |
||
8698 | get_tok_str(v, NULL)); |
||
8699 | if (sym->type.t & VT_EXTERN) { |
||
8700 | /* if the variable is extern, it was not allocated */ |
||
8701 | sym->type.t &= ~VT_EXTERN; |
||
8702 | /* set array size if it was ommited in extern |
||
8703 | declaration */ |
||
8704 | if ((sym->type.t & VT_ARRAY) && |
||
8705 | sym->type.ref->c < 0 && |
||
8706 | type->ref->c >= 0) |
||
8707 | sym->type.ref->c = type->ref->c; |
||
8708 | } else { |
||
8709 | /* we accept several definitions of the same |
||
8710 | global variable. this is tricky, because we |
||
8711 | must play with the SHN_COMMON type of the symbol */ |
||
8712 | /* XXX: should check if the variable was already |
||
8713 | initialized. It is incorrect to initialized it |
||
8714 | twice */ |
||
8715 | /* no init data, we won't add more to the symbol */ |
||
8716 | if (!has_init) |
||
8717 | goto no_alloc; |
||
8718 | } |
||
8719 | } |
||
8720 | } |
||
8721 | |||
8722 | /* allocate symbol in corresponding section */ |
||
8723 | sec = ad->section; |
||
8724 | if (!sec) { |
||
8725 | if (has_init) |
||
8726 | sec = data_section; |
||
8727 | else if (tcc_state->nocommon) |
||
8728 | sec = bss_section; |
||
8729 | } |
||
8730 | if (sec) { |
||
8731 | data_offset = sec->data_offset; |
||
8732 | data_offset = (data_offset + align - 1) & -align; |
||
8733 | addr = data_offset; |
||
8734 | /* very important to increment global pointer at this time |
||
8735 | because initializers themselves can create new initializers */ |
||
8736 | data_offset += size; |
||
8737 | /* add padding if bound check */ |
||
8738 | if (do_bounds_check) |
||
8739 | data_offset++; |
||
8740 | sec->data_offset = data_offset; |
||
8741 | /* allocate section space to put the data */ |
||
8742 | if (sec->sh_type != SHT_NOBITS && |
||
8743 | data_offset > sec->data_allocated) |
||
8744 | section_realloc(sec, data_offset); |
||
8745 | /* align section if needed */ |
||
8746 | if (align > sec->sh_addralign) |
||
8747 | sec->sh_addralign = align; |
||
8748 | } else { |
||
8749 | addr = 0; /* avoid warning */ |
||
8750 | } |
||
8751 | |||
8752 | if (v) { |
||
8753 | if (scope == VT_CONST) { |
||
8754 | if (!sym) |
||
8755 | goto do_def; |
||
8756 | } else { |
||
8757 | do_def: |
||
8758 | sym = sym_push(v, type, r | VT_SYM, 0); |
||
8759 | } |
||
8760 | /* update symbol definition */ |
||
8761 | if (sec) { |
||
8762 | put_extern_sym(sym, sec, addr, size); |
||
8763 | } else { |
||
8764 | Elf32_Sym *esym; |
||
8765 | /* put a common area */ |
||
8766 | put_extern_sym(sym, NULL, align, size); |
||
8767 | /* XXX: find a nicer way */ |
||
8768 | esym = &((Elf32_Sym *)symtab_section->data)[sym->c]; |
||
8769 | esym->st_shndx = SHN_COMMON; |
||
8770 | } |
||
8771 | } else { |
||
8772 | CValue cval; |
||
8773 | |||
8774 | /* push global reference */ |
||
8775 | sym = get_sym_ref(type, sec, addr, size); |
||
8776 | cval.ul = 0; |
||
8777 | vsetc(type, VT_CONST | VT_SYM, &cval); |
||
8778 | vtop->sym = sym; |
||
8779 | } |
||
8780 | |||
8781 | /* handles bounds now because the symbol must be defined |
||
8782 | before for the relocation */ |
||
8783 | if (do_bounds_check) { |
||
8784 | unsigned long *bounds_ptr; |
||
8785 | |||
8786 | greloc(bounds_section, sym, bounds_section->data_offset, R_DATA_32); |
||
8787 | /* then add global bound info */ |
||
8788 | bounds_ptr = section_ptr_add(bounds_section, 2 * sizeof(long)); |
||
8789 | bounds_ptr[0] = 0; /* relocated */ |
||
8790 | bounds_ptr[1] = size; |
||
8791 | } |
||
8792 | } |
||
8793 | if (has_init) { |
||
8794 | decl_initializer(type, sec, addr, 1, 0); |
||
8795 | /* restore parse state if needed */ |
||
8796 | if (init_str.str) { |
||
8797 | tok_str_free(init_str.str); |
||
8798 | restore_parse_state(&saved_parse_state); |
||
8799 | } |
||
8800 | } |
||
8801 | no_alloc: ; |
||
8802 | } |
||
8803 | |||
8804 | void put_func_debug(Sym *sym) |
||
8805 | { |
||
8806 | char buf[512]; |
||
8807 | |||
8808 | /* stabs info */ |
||
8809 | /* XXX: we put here a dummy type */ |
||
8810 | snprintf(buf, sizeof(buf), "%s:%c1", |
||
8811 | funcname, sym->type.t & VT_STATIC ? 'f' : 'F'); |
||
8812 | put_stabs_r(buf, N_FUN, 0, file->line_num, 0, |
||
8813 | cur_text_section, sym->c); |
||
8814 | last_ind = 0; |
||
8815 | last_line_num = 0; |
||
8816 | } |
||
8817 | |||
8818 | /* parse an old style function declaration list */ |
||
8819 | /* XXX: check multiple parameter */ |
||
8820 | static void func_decl_list(Sym *func_sym) |
||
8821 | { |
||
8822 | AttributeDef ad; |
||
8823 | int v; |
||
8824 | Sym *s; |
||
8825 | CType btype, type; |
||
8826 | |||
8827 | /* parse each declaration */ |
||
8828 | while (tok != '{' && tok != ';' && tok != ',' && tok != TOK_EOF) { |
||
8829 | if (!parse_btype(&btype, &ad)) |
||
8830 | expect("declaration list"); |
||
8831 | if (((btype.t & VT_BTYPE) == VT_ENUM || |
||
8832 | (btype.t & VT_BTYPE) == VT_STRUCT) && |
||
8833 | tok == ';') { |
||
8834 | /* we accept no variable after */ |
||
8835 | } else { |
||
8836 | for(;;) { |
||
8837 | type = btype; |
||
8838 | type_decl(&type, &ad, &v, TYPE_DIRECT); |
||
8839 | /* find parameter in function parameter list */ |
||
8840 | s = func_sym->next; |
||
8841 | while (s != NULL) { |
||
8842 | if ((s->v & ~SYM_FIELD) == v) |
||
8843 | goto found; |
||
8844 | s = s->next; |
||
8845 | } |
||
8846 | error("declaration for parameter '%s' but no such parameter", |
||
8847 | get_tok_str(v, NULL)); |
||
8848 | found: |
||
8849 | /* check that no storage specifier except 'register' was given */ |
||
8850 | if (type.t & VT_STORAGE) |
||
8851 | error("storage class specified for '%s'", get_tok_str(v, NULL)); |
||
8852 | convert_parameter_type(&type); |
||
8853 | /* we can add the type (NOTE: it could be local to the function) */ |
||
8854 | s->type = type; |
||
8855 | /* accept other parameters */ |
||
8856 | if (tok == ',') |
||
8857 | next(); |
||
8858 | else |
||
8859 | break; |
||
8860 | } |
||
8861 | } |
||
8862 | skip(';'); |
||
8863 | } |
||
8864 | } |
||
8865 | |||
8866 | /* parse a function defined by symbol 'sym' and generate its code in |
||
8867 | 'cur_text_section' */ |
||
8868 | static void gen_function(Sym *sym) |
||
8869 | { |
||
8870 | ind = cur_text_section->data_offset; |
||
8871 | /* NOTE: we patch the symbol size later */ |
||
8872 | put_extern_sym(sym, cur_text_section, ind, 0); |
||
8873 | funcname = get_tok_str(sym->v, NULL); |
||
8874 | func_ind = ind; |
||
8875 | /* put debug symbol */ |
||
8876 | if (do_debug) |
||
8877 | put_func_debug(sym); |
||
8878 | /* push a dummy symbol to enable local sym storage */ |
||
8879 | sym_push2(&local_stack, SYM_FIELD, 0, 0); |
||
8880 | gfunc_prolog(&sym->type); |
||
8881 | rsym = 0; |
||
8882 | block(NULL, NULL, NULL, NULL, 0, 0); |
||
8883 | gsym(rsym); |
||
8884 | gfunc_epilog(); |
||
8885 | cur_text_section->data_offset = ind; |
||
8886 | label_pop(&global_label_stack, NULL); |
||
8887 | sym_pop(&local_stack, NULL); /* reset local stack */ |
||
8888 | /* end of function */ |
||
8889 | /* patch symbol size */ |
||
8890 | ((Elf32_Sym *)symtab_section->data)[sym->c].st_size = |
||
8891 | ind - func_ind; |
||
8892 | if (do_debug) { |
||
8893 | put_stabn(N_FUN, 0, 0, ind - func_ind); |
||
8894 | } |
||
8895 | funcname = ""; /* for safety */ |
||
8896 | func_vt.t = VT_VOID; /* for safety */ |
||
8897 | ind = 0; /* for safety */ |
||
8898 | } |
||
8899 | |||
8900 | static void gen_inline_functions(void) |
||
8901 | { |
||
8902 | Sym *sym; |
||
8903 | CType *type; |
||
8904 | int *str, inline_generated; |
||
8905 | |||
8906 | /* iterate while inline function are referenced */ |
||
8907 | for(;;) { |
||
8908 | inline_generated = 0; |
||
8909 | for(sym = global_stack; sym != NULL; sym = sym->prev) { |
||
8910 | type = &sym->type; |
||
8911 | if (((type->t & VT_BTYPE) == VT_FUNC) && |
||
8912 | (type->t & (VT_STATIC | VT_INLINE)) == |
||
8913 | (VT_STATIC | VT_INLINE) && |
||
8914 | sym->c != 0) { |
||
8915 | /* the function was used: generate its code and |
||
8916 | convert it to a normal function */ |
||
8917 | str = (int *)sym->r; |
||
8918 | sym->r = VT_SYM | VT_CONST; |
||
8919 | type->t &= ~VT_INLINE; |
||
8920 | |||
8921 | macro_ptr = str; |
||
8922 | next(); |
||
8923 | cur_text_section = text_section; |
||
8924 | gen_function(sym); |
||
8925 | macro_ptr = NULL; /* fail safe */ |
||
8926 | |||
8927 | tok_str_free(str); |
||
8928 | inline_generated = 1; |
||
8929 | } |
||
8930 | } |
||
8931 | if (!inline_generated) |
||
8932 | break; |
||
8933 | } |
||
8934 | |||
8935 | /* free all remaining inline function tokens */ |
||
8936 | for(sym = global_stack; sym != NULL; sym = sym->prev) { |
||
8937 | type = &sym->type; |
||
8938 | if (((type->t & VT_BTYPE) == VT_FUNC) && |
||
8939 | (type->t & (VT_STATIC | VT_INLINE)) == |
||
8940 | (VT_STATIC | VT_INLINE)) { |
||
8941 | str = (int *)sym->r; |
||
8942 | tok_str_free(str); |
||
8943 | sym->r = 0; /* fail safe */ |
||
8944 | } |
||
8945 | } |
||
8946 | } |
||
8947 | |||
8948 | /* 'l' is VT_LOCAL or VT_CONST to define default storage type */ |
||
8949 | static void decl(int l) |
||
8950 | { |
||
8951 | int v, has_init, r; |
||
8952 | CType type, btype; |
||
8953 | Sym *sym; |
||
8954 | AttributeDef ad; |
||
8955 | |||
8956 | while (1) { |
||
8957 | if (!parse_btype(&btype, &ad)) { |
||
8958 | /* skip redundant ';' */ |
||
8959 | /* XXX: find more elegant solution */ |
||
8960 | if (tok == ';') { |
||
8961 | next(); |
||
8962 | continue; |
||
8963 | } |
||
8964 | if (l == VT_CONST && |
||
8965 | (tok == TOK_ASM1 || tok == TOK_ASM2 || tok == TOK_ASM3)) { |
||
8966 | /* global asm block */ |
||
8967 | asm_global_instr(); |
||
8968 | continue; |
||
8969 | } |
||
8970 | /* special test for old K&R protos without explicit int |
||
8971 | type. Only accepted when defining global data */ |
||
8972 | if (l == VT_LOCAL || tok < TOK_DEFINE) |
||
8973 | break; |
||
8974 | btype.t = VT_INT; |
||
8975 | } |
||
8976 | if (((btype.t & VT_BTYPE) == VT_ENUM || |
||
8977 | (btype.t & VT_BTYPE) == VT_STRUCT) && |
||
8978 | tok == ';') { |
||
8979 | /* we accept no variable after */ |
||
8980 | next(); |
||
8981 | continue; |
||
8982 | } |
||
8983 | while (1) { /* iterate thru each declaration */ |
||
8984 | type = btype; |
||
8985 | type_decl(&type, &ad, &v, TYPE_DIRECT); |
||
8986 | #if 0 |
||
8987 | { |
||
8988 | char buf[500]; |
||
8989 | type_to_str(buf, sizeof(buf), t, get_tok_str(v, NULL)); |
||
8990 | printf("type = '%s'\n", buf); |
||
8991 | } |
||
8992 | #endif |
||
8993 | if ((type.t & VT_BTYPE) == VT_FUNC) { |
||
8994 | /* if old style function prototype, we accept a |
||
8995 | declaration list */ |
||
8996 | sym = type.ref; |
||
8997 | if (sym->c == FUNC_OLD) |
||
8998 | func_decl_list(sym); |
||
8999 | } |
||
9000 | |||
9001 | if (tok == '{') { |
||
9002 | if (l == VT_LOCAL) |
||
9003 | error("cannot use local functions"); |
||
9004 | if (!(type.t & VT_FUNC)) |
||
9005 | expect("function definition"); |
||
9006 | |||
9007 | /* reject abstract declarators in function definition */ |
||
9008 | sym = type.ref; |
||
9009 | while ((sym = sym->next) != NULL) |
||
9010 | if (!(sym->v & ~SYM_FIELD)) |
||
9011 | expect("identifier"); |
||
9012 | |||
9013 | /* XXX: cannot do better now: convert extern line to static inline */ |
||
9014 | if ((type.t & (VT_EXTERN | VT_INLINE)) == (VT_EXTERN | VT_INLINE)) |
||
9015 | type.t = (type.t & ~VT_EXTERN) | VT_STATIC; |
||
9016 | |||
9017 | sym = sym_find(v); |
||
9018 | if (sym) { |
||
9019 | if ((sym->type.t & VT_BTYPE) != VT_FUNC) |
||
9020 | goto func_error1; |
||
9021 | /* specific case: if not func_call defined, we put |
||
9022 | the one of the prototype */ |
||
9023 | /* XXX: should have default value */ |
||
9024 | if (sym->type.ref->r != FUNC_CDECL && |
||
9025 | type.ref->r == FUNC_CDECL) |
||
9026 | type.ref->r = sym->type.ref->r; |
||
9027 | if (!is_compatible_types(&sym->type, &type)) { |
||
9028 | func_error1: |
||
9029 | error("incompatible types for redefinition of '%s'", |
||
9030 | get_tok_str(v, NULL)); |
||
9031 | } |
||
9032 | /* if symbol is already defined, then put complete type */ |
||
9033 | sym->type = type; |
||
9034 | } else { |
||
9035 | /* put function symbol */ |
||
9036 | sym = global_identifier_push(v, type.t, 0); |
||
9037 | sym->type.ref = type.ref; |
||
9038 | } |
||
9039 | |||
9040 | /* static inline functions are just recorded as a kind |
||
9041 | of macro. Their code will be emitted at the end of |
||
9042 | the compilation unit only if they are used */ |
||
9043 | if ((type.t & (VT_INLINE | VT_STATIC)) == |
||
9044 | (VT_INLINE | VT_STATIC)) { |
||
9045 | TokenString func_str; |
||
9046 | int block_level; |
||
9047 | |||
9048 | tok_str_new(&func_str); |
||
9049 | |||
9050 | block_level = 0; |
||
9051 | for(;;) { |
||
9052 | int t; |
||
9053 | if (tok == TOK_EOF) |
||
9054 | error("unexpected end of file"); |
||
9055 | tok_str_add_tok(&func_str); |
||
9056 | t = tok; |
||
9057 | next(); |
||
9058 | if (t == '{') { |
||
9059 | block_level++; |
||
9060 | } else if (t == '}') { |
||
9061 | block_level--; |
||
9062 | if (block_level == 0) |
||
9063 | break; |
||
9064 | } |
||
9065 | } |
||
9066 | tok_str_add(&func_str, -1); |
||
9067 | tok_str_add(&func_str, 0); |
||
9068 | sym->r = (int)func_str.str; |
||
9069 | } else { |
||
9070 | /* compute text section */ |
||
9071 | cur_text_section = ad.section; |
||
9072 | if (!cur_text_section) |
||
9073 | cur_text_section = text_section; |
||
9074 | sym->r = VT_SYM | VT_CONST; |
||
9075 | gen_function(sym); |
||
9076 | #ifdef TCC_TARGET_PE |
||
9077 | if (ad.dllexport) { |
||
9078 | ((Elf32_Sym *)symtab_section->data)[sym->c].st_other |= 1; |
||
9079 | } |
||
9080 | #endif |
||
9081 | } |
||
9082 | break; |
||
9083 | } else { |
||
9084 | if (btype.t & VT_TYPEDEF) { |
||
9085 | /* save typedefed type */ |
||
9086 | /* XXX: test storage specifiers ? */ |
||
9087 | sym = sym_push(v, &type, 0, 0); |
||
9088 | sym->type.t |= VT_TYPEDEF; |
||
9089 | } else if ((type.t & VT_BTYPE) == VT_FUNC) { |
||
9090 | /* external function definition */ |
||
9091 | /* specific case for func_call attribute */ |
||
9092 | if (ad.func_call) |
||
9093 | type.ref->r = ad.func_call; |
||
9094 | external_sym(v, &type, 0); |
||
9095 | } else { |
||
9096 | /* not lvalue if array */ |
||
9097 | r = 0; |
||
9098 | if (!(type.t & VT_ARRAY)) |
||
9099 | r |= lvalue_type(type.t); |
||
9100 | has_init = (tok == '='); |
||
9101 | if ((btype.t & VT_EXTERN) || |
||
9102 | ((type.t & VT_ARRAY) && (type.t & VT_STATIC) && |
||
9103 | !has_init && l == VT_CONST && type.ref->c < 0)) { |
||
9104 | /* external variable */ |
||
9105 | /* NOTE: as GCC, uninitialized global static |
||
9106 | arrays of null size are considered as |
||
9107 | extern */ |
||
9108 | external_sym(v, &type, r); |
||
9109 | } else { |
||
9110 | if (type.t & VT_STATIC) |
||
9111 | r |= VT_CONST; |
||
9112 | else |
||
9113 | r |= l; |
||
9114 | if (has_init) |
||
9115 | next(); |
||
9116 | decl_initializer_alloc(&type, &ad, r, |
||
9117 | has_init, v, l); |
||
9118 | } |
||
9119 | } |
||
9120 | if (tok != ',') { |
||
9121 | skip(';'); |
||
9122 | break; |
||
9123 | } |
||
9124 | next(); |
||
9125 | } |
||
9126 | } |
||
9127 | } |
||
9128 | } |
||
9129 | |||
9130 | /* better than nothing, but needs extension to handle '-E' option |
||
9131 | correctly too */ |
||
9132 | static void preprocess_init(TCCState *s1) |
||
9133 | { |
||
9134 | s1->include_stack_ptr = s1->include_stack; |
||
9135 | /* XXX: move that before to avoid having to initialize |
||
9136 | file->ifdef_stack_ptr ? */ |
||
9137 | s1->ifdef_stack_ptr = s1->ifdef_stack; |
||
9138 | file->ifdef_stack_ptr = s1->ifdef_stack_ptr; |
||
9139 | |||
9140 | /* XXX: not ANSI compliant: bound checking says error */ |
||
9141 | vtop = vstack - 1; |
||
9142 | s1->pack_stack[0] = 0; |
||
9143 | s1->pack_stack_ptr = s1->pack_stack; |
||
9144 | } |
||
9145 | |||
9146 | /* compile the C file opened in 'file'. Return non zero if errors. */ |
||
9147 | static int tcc_compile(TCCState *s1) |
||
9148 | { |
||
9149 | Sym *define_start; |
||
9150 | char buf[512]; |
||
9151 | volatile int section_sym; |
||
9152 | |||
9153 | #ifdef INC_DEBUG |
||
9154 | printf("%s: **** new file\n", file->filename); |
||
9155 | #endif |
||
9156 | preprocess_init(s1); |
||
9157 | |||
9158 | funcname = ""; |
||
9159 | anon_sym = SYM_FIRST_ANOM; |
||
9160 | |||
9161 | /* file info: full path + filename */ |
||
9162 | section_sym = 0; /* avoid warning */ |
||
9163 | if (do_debug) { |
||
9164 | section_sym = put_elf_sym(symtab_section, 0, 0, |
||
9165 | ELF32_ST_INFO(STB_LOCAL, STT_SECTION), 0, |
||
9166 | text_section->sh_num, NULL); |
||
9167 | getcwd(buf, sizeof(buf)); |
||
9168 | pstrcat(buf, sizeof(buf), "/"); |
||
9169 | put_stabs_r(buf, N_SO, 0, 0, |
||
9170 | text_section->data_offset, text_section, section_sym); |
||
9171 | put_stabs_r(file->filename, N_SO, 0, 0, |
||
9172 | text_section->data_offset, text_section, section_sym); |
||
9173 | } |
||
9174 | /* an elf symbol of type STT_FILE must be put so that STB_LOCAL |
||
9175 | symbols can be safely used */ |
||
9176 | put_elf_sym(symtab_section, 0, 0, |
||
9177 | ELF32_ST_INFO(STB_LOCAL, STT_FILE), 0, |
||
9178 | SHN_ABS, file->filename); |
||
9179 | |||
9180 | /* define some often used types */ |
||
9181 | int_type.t = VT_INT; |
||
9182 | |||
9183 | char_pointer_type.t = VT_BYTE; |
||
9184 | mk_pointer(&char_pointer_type); |
||
9185 | |||
9186 | func_old_type.t = VT_FUNC; |
||
9187 | func_old_type.ref = sym_push(SYM_FIELD, &int_type, FUNC_CDECL, FUNC_OLD); |
||
9188 | |||
9189 | #if 0 |
||
9190 | /* define 'void *alloca(unsigned int)' builtin function */ |
||
9191 | { |
||
9192 | Sym *s1; |
||
9193 | |||
9194 | p = anon_sym++; |
||
9195 | sym = sym_push(p, mk_pointer(VT_VOID), FUNC_CDECL, FUNC_NEW); |
||
9196 | s1 = sym_push(SYM_FIELD, VT_UNSIGNED | VT_INT, 0, 0); |
||
9197 | s1->next = NULL; |
||
9198 | sym->next = s1; |
||
9199 | sym_push(TOK_alloca, VT_FUNC | (p << VT_STRUCT_SHIFT), VT_CONST, 0); |
||
9200 | } |
||
9201 | #endif |
||
9202 | |||
9203 | define_start = define_stack; |
||
9204 | |||
9205 | if (setjmp(s1->error_jmp_buf) == 0) { |
||
9206 | s1->nb_errors = 0; |
||
9207 | s1->error_set_jmp_enabled = 1; |
||
9208 | |||
9209 | ch = file->buf_ptr[0]; |
||
9210 | tok_flags = TOK_FLAG_BOL | TOK_FLAG_BOF; |
||
9211 | parse_flags = PARSE_FLAG_PREPROCESS | PARSE_FLAG_TOK_NUM; |
||
9212 | next(); |
||
9213 | decl(VT_CONST); |
||
9214 | if (tok != TOK_EOF) |
||
9215 | expect("declaration"); |
||
9216 | |||
9217 | /* end of translation unit info */ |
||
9218 | if (do_debug) { |
||
9219 | put_stabs_r(NULL, N_SO, 0, 0, |
||
9220 | text_section->data_offset, text_section, section_sym); |
||
9221 | } |
||
9222 | } |
||
9223 | s1->error_set_jmp_enabled = 0; |
||
9224 | |||
9225 | /* reset define stack, but leave -Dsymbols (may be incorrect if |
||
9226 | they are undefined) */ |
||
9227 | free_defines(define_start); |
||
9228 | |||
9229 | gen_inline_functions(); |
||
9230 | |||
9231 | sym_pop(&global_stack, NULL); |
||
9232 | |||
9233 | return s1->nb_errors != 0 ? -1 : 0; |
||
9234 | } |
||
9235 | |||
9236 | #ifdef LIBTCC |
||
9237 | int tcc_compile_string(TCCState *s, const char *str) |
||
9238 | { |
||
9239 | BufferedFile bf1, *bf = &bf1; |
||
9240 | int ret, len; |
||
9241 | char *buf; |
||
9242 | |||
9243 | /* init file structure */ |
||
9244 | bf->fd = -1; |
||
9245 | /* XXX: avoid copying */ |
||
9246 | len = strlen(str); |
||
9247 | buf = tcc_malloc(len + 1); |
||
9248 | if (!buf) |
||
9249 | return -1; |
||
9250 | memcpy(buf, str, len); |
||
9251 | buf[len] = CH_EOB; |
||
9252 | bf->buf_ptr = buf; |
||
9253 | bf->buf_end = buf + len; |
||
9254 | pstrcpy(bf->filename, sizeof(bf->filename), " |
||
9255 | bf->line_num = 1; |
||
9256 | file = bf; |
||
9257 | |||
9258 | ret = tcc_compile(s); |
||
9259 | |||
9260 | tcc_free(buf); |
||
9261 | |||
9262 | /* currently, no need to close */ |
||
9263 | return ret; |
||
9264 | } |
||
9265 | #endif |
||
9266 | |||
9267 | /* define a preprocessor symbol. A value can also be provided with the '=' operator */ |
||
9268 | void tcc_define_symbol(TCCState *s1, const char *sym, const char *value) |
||
9269 | { |
||
9270 | BufferedFile bf1, *bf = &bf1; |
||
9271 | |||
9272 | pstrcpy(bf->buffer, IO_BUF_SIZE, sym); |
||
9273 | pstrcat(bf->buffer, IO_BUF_SIZE, " "); |
||
9274 | /* default value */ |
||
9275 | if (!value) |
||
9276 | value = "1"; |
||
9277 | pstrcat(bf->buffer, IO_BUF_SIZE, value); |
||
9278 | |||
9279 | /* init file structure */ |
||
9280 | bf->fd = -1; |
||
9281 | bf->buf_ptr = bf->buffer; |
||
9282 | bf->buf_end = bf->buffer + strlen(bf->buffer); |
||
9283 | *bf->buf_end = CH_EOB; |
||
9284 | bf->filename[0] = '\0'; |
||
9285 | bf->line_num = 1; |
||
9286 | file = bf; |
||
9287 | |||
9288 | s1->include_stack_ptr = s1->include_stack; |
||
9289 | |||
9290 | /* parse with define parser */ |
||
9291 | ch = file->buf_ptr[0]; |
||
9292 | next_nomacro(); |
||
9293 | parse_define(); |
||
9294 | file = NULL; |
||
9295 | } |
||
9296 | |||
9297 | /* undefine a preprocessor symbol */ |
||
9298 | void tcc_undefine_symbol(TCCState *s1, const char *sym) |
||
9299 | { |
||
9300 | TokenSym *ts; |
||
9301 | Sym *s; |
||
9302 | ts = tok_alloc(sym, strlen(sym)); |
||
9303 | s = define_find(ts->tok); |
||
9304 | /* undefine symbol by putting an invalid name */ |
||
9305 | if (s) |
||
9306 | define_undef(s); |
||
9307 | } |
||
9308 | |||
9309 | #ifdef CONFIG_TCC_ASM |
||
9310 | |||
9311 | #ifdef TCC_TARGET_I386 |
||
9312 | #include "i386-asm.c" |
||
9313 | #endif |
||
9314 | #include "tccasm.c" |
||
9315 | |||
9316 | #else |
||
9317 | static void asm_instr(void) |
||
9318 | { |
||
9319 | error("inline asm() not supported"); |
||
9320 | } |
||
9321 | static void asm_global_instr(void) |
||
9322 | { |
||
9323 | error("inline asm() not supported"); |
||
9324 | } |
||
9325 | #endif |
||
9326 | |||
9327 | #include "tccelf.c" |
||
9328 | |||
9329 | #ifdef TCC_TARGET_COFF |
||
9330 | #include "tcccoff.c" |
||
9331 | #endif |
||
9332 | |||
9333 | #if defined(TCC_TARGET_PE) || defined(TCC_TARGET_MEOS) |
||
9334 | #include "tccpe.c" |
||
9335 | #endif |
||
9336 | |||
9337 | #ifdef TCC_TARGET_MEOS |
||
9338 | #include "tccmeos.c" |
||
9339 | #endif |
||
9340 | |||
9341 | /* print the position in the source file of PC value 'pc' by reading |
||
9342 | the stabs debug information */ |
||
9343 | static void rt_printline(unsigned long wanted_pc) |
||
9344 | { |
||
9345 | Stab_Sym *sym, *sym_end; |
||
9346 | char func_name[128], last_func_name[128]; |
||
9347 | unsigned long func_addr, last_pc, pc; |
||
9348 | const char *incl_files[INCLUDE_STACK_SIZE]; |
||
9349 | int incl_index, len, last_line_num, i; |
||
9350 | const char *str, *p; |
||
9351 | |||
9352 | fprintf(stderr, "0x%08lx:", wanted_pc); |
||
9353 | |||
9354 | func_name[0] = '\0'; |
||
9355 | func_addr = 0; |
||
9356 | incl_index = 0; |
||
9357 | last_func_name[0] = '\0'; |
||
9358 | last_pc = 0xffffffff; |
||
9359 | last_line_num = 1; |
||
9360 | sym = (Stab_Sym *)stab_section->data + 1; |
||
9361 | sym_end = (Stab_Sym *)(stab_section->data + stab_section->data_offset); |
||
9362 | while (sym < sym_end) { |
||
9363 | switch(sym->n_type) { |
||
9364 | /* function start or end */ |
||
9365 | case N_FUN: |
||
9366 | if (sym->n_strx == 0) { |
||
9367 | /* we test if between last line and end of function */ |
||
9368 | pc = sym->n_value + func_addr; |
||
9369 | if (wanted_pc >= last_pc && wanted_pc < pc) |
||
9370 | goto found; |
||
9371 | func_name[0] = '\0'; |
||
9372 | func_addr = 0; |
||
9373 | } else { |
||
9374 | str = stabstr_section->data + sym->n_strx; |
||
9375 | p = strchr(str, ':'); |
||
9376 | if (!p) { |
||
9377 | pstrcpy(func_name, sizeof(func_name), str); |
||
9378 | } else { |
||
9379 | len = p - str; |
||
9380 | if (len > sizeof(func_name) - 1) |
||
9381 | len = sizeof(func_name) - 1; |
||
9382 | memcpy(func_name, str, len); |
||
9383 | func_name[len] = '\0'; |
||
9384 | } |
||
9385 | func_addr = sym->n_value; |
||
9386 | } |
||
9387 | break; |
||
9388 | /* line number info */ |
||
9389 | case N_SLINE: |
||
9390 | pc = sym->n_value + func_addr; |
||
9391 | if (wanted_pc >= last_pc && wanted_pc < pc) |
||
9392 | goto found; |
||
9393 | last_pc = pc; |
||
9394 | last_line_num = sym->n_desc; |
||
9395 | /* XXX: slow! */ |
||
9396 | strcpy(last_func_name, func_name); |
||
9397 | break; |
||
9398 | /* include files */ |
||
9399 | case N_BINCL: |
||
9400 | str = stabstr_section->data + sym->n_strx; |
||
9401 | add_incl: |
||
9402 | if (incl_index < INCLUDE_STACK_SIZE) { |
||
9403 | incl_files[incl_index++] = str; |
||
9404 | } |
||
9405 | break; |
||
9406 | case N_EINCL: |
||
9407 | if (incl_index > 1) |
||
9408 | incl_index--; |
||
9409 | break; |
||
9410 | case N_SO: |
||
9411 | if (sym->n_strx == 0) { |
||
9412 | incl_index = 0; /* end of translation unit */ |
||
9413 | } else { |
||
9414 | str = stabstr_section->data + sym->n_strx; |
||
9415 | /* do not add path */ |
||
9416 | len = strlen(str); |
||
9417 | if (len > 0 && str[len - 1] != '/') |
||
9418 | goto add_incl; |
||
9419 | } |
||
9420 | break; |
||
9421 | } |
||
9422 | sym++; |
||
9423 | } |
||
9424 | |||
9425 | /* second pass: we try symtab symbols (no line number info) */ |
||
9426 | incl_index = 0; |
||
9427 | { |
||
9428 | Elf32_Sym *sym, *sym_end; |
||
9429 | int type; |
||
9430 | |||
9431 | sym_end = (Elf32_Sym *)(symtab_section->data + symtab_section->data_offset); |
||
9432 | for(sym = (Elf32_Sym *)symtab_section->data + 1; |
||
9433 | sym < sym_end; |
||
9434 | sym++) { |
||
9435 | type = ELF32_ST_TYPE(sym->st_info); |
||
9436 | if (type == STT_FUNC) { |
||
9437 | if (wanted_pc >= sym->st_value && |
||
9438 | wanted_pc < sym->st_value + sym->st_size) { |
||
9439 | pstrcpy(last_func_name, sizeof(last_func_name), |
||
9440 | strtab_section->data + sym->st_name); |
||
9441 | goto found; |
||
9442 | } |
||
9443 | } |
||
9444 | } |
||
9445 | } |
||
9446 | /* did not find any info: */ |
||
9447 | fprintf(stderr, " ???\n"); |
||
9448 | return; |
||
9449 | found: |
||
9450 | if (last_func_name[0] != '\0') { |
||
9451 | fprintf(stderr, " %s()", last_func_name); |
||
9452 | } |
||
9453 | if (incl_index > 0) { |
||
9454 | fprintf(stderr, " (%s:%d", |
||
9455 | incl_files[incl_index - 1], last_line_num); |
||
9456 | for(i = incl_index - 2; i >= 0; i--) |
||
9457 | fprintf(stderr, ", included from %s", incl_files[i]); |
||
9458 | fprintf(stderr, ")"); |
||
9459 | } |
||
9460 | fprintf(stderr, "\n"); |
||
9461 | } |
||
9462 | |||
9463 | #if !defined(WIN32) && !defined(CONFIG_TCCBOOT) |
||
9464 | |||
9465 | #ifdef __i386__ |
||
9466 | |||
9467 | /* fix for glibc 2.1 */ |
||
9468 | #ifndef REG_EIP |
||
9469 | #define REG_EIP EIP |
||
9470 | #define REG_EBP EBP |
||
9471 | #endif |
||
9472 | |||
9473 | /* return the PC at frame level 'level'. Return non zero if not found */ |
||
9474 | static int rt_get_caller_pc(unsigned long *paddr, |
||
9475 | ucontext_t *uc, int level) |
||
9476 | { |
||
9477 | unsigned long fp; |
||
9478 | int i; |
||
9479 | |||
9480 | if (level == 0) { |
||
9481 | #if defined(__FreeBSD__) |
||
9482 | *paddr = uc->uc_mcontext.mc_eip; |
||
9483 | #elif defined(__dietlibc__) |
||
9484 | *paddr = uc->uc_mcontext.eip; |
||
9485 | #else |
||
9486 | *paddr = uc->uc_mcontext.gregs[REG_EIP]; |
||
9487 | #endif |
||
9488 | return 0; |
||
9489 | } else { |
||
9490 | #if defined(__FreeBSD__) |
||
9491 | fp = uc->uc_mcontext.mc_ebp; |
||
9492 | #elif defined(__dietlibc__) |
||
9493 | fp = uc->uc_mcontext.ebp; |
||
9494 | #else |
||
9495 | fp = uc->uc_mcontext.gregs[REG_EBP]; |
||
9496 | #endif |
||
9497 | for(i=1;i |
||
9498 | /* XXX: check address validity with program info */ |
||
9499 | if (fp <= 0x1000 || fp >= 0xc0000000) |
||
9500 | return -1; |
||
9501 | fp = ((unsigned long *)fp)[0]; |
||
9502 | } |
||
9503 | *paddr = ((unsigned long *)fp)[1]; |
||
9504 | return 0; |
||
9505 | } |
||
9506 | } |
||
9507 | #else |
||
9508 | |||
9509 | #warning add arch specific rt_get_caller_pc() |
||
9510 | |||
9511 | static int rt_get_caller_pc(unsigned long *paddr, |
||
9512 | ucontext_t *uc, int level) |
||
9513 | { |
||
9514 | return -1; |
||
9515 | } |
||
9516 | #endif |
||
9517 | |||
9518 | /* emit a run time error at position 'pc' */ |
||
9519 | void rt_error(ucontext_t *uc, const char *fmt, ...) |
||
9520 | { |
||
9521 | va_list ap; |
||
9522 | unsigned long pc; |
||
9523 | int i; |
||
9524 | |||
9525 | va_start(ap, fmt); |
||
9526 | fprintf(stderr, "Runtime error: "); |
||
9527 | vfprintf(stderr, fmt, ap); |
||
9528 | fprintf(stderr, "\n"); |
||
9529 | for(i=0;i |
||
9530 | if (rt_get_caller_pc(&pc, uc, i) < 0) |
||
9531 | break; |
||
9532 | if (i == 0) |
||
9533 | fprintf(stderr, "at "); |
||
9534 | else |
||
9535 | fprintf(stderr, "by "); |
||
9536 | rt_printline(pc); |
||
9537 | } |
||
9538 | exit(255); |
||
9539 | va_end(ap); |
||
9540 | } |
||
9541 | |||
9542 | /* signal handler for fatal errors */ |
||
9543 | static void sig_error(int signum, siginfo_t *siginf, void *puc) |
||
9544 | { |
||
9545 | ucontext_t *uc = puc; |
||
9546 | |||
9547 | switch(signum) { |
||
9548 | case SIGFPE: |
||
9549 | switch(siginf->si_code) { |
||
9550 | case FPE_INTDIV: |
||
9551 | case FPE_FLTDIV: |
||
9552 | rt_error(uc, "division by zero"); |
||
9553 | break; |
||
9554 | default: |
||
9555 | rt_error(uc, "floating point exception"); |
||
9556 | break; |
||
9557 | } |
||
9558 | break; |
||
9559 | case SIGBUS: |
||
9560 | case SIGSEGV: |
||
9561 | if (rt_bound_error_msg && *rt_bound_error_msg) |
||
9562 | rt_error(uc, *rt_bound_error_msg); |
||
9563 | else |
||
9564 | rt_error(uc, "dereferencing invalid pointer"); |
||
9565 | break; |
||
9566 | case SIGILL: |
||
9567 | rt_error(uc, "illegal instruction"); |
||
9568 | break; |
||
9569 | case SIGABRT: |
||
9570 | rt_error(uc, "abort() called"); |
||
9571 | break; |
||
9572 | default: |
||
9573 | rt_error(uc, "caught signal %d", signum); |
||
9574 | break; |
||
9575 | } |
||
9576 | exit(255); |
||
9577 | } |
||
9578 | #endif |
||
9579 | |||
9580 | /* do all relocations (needed before using tcc_get_symbol()) */ |
||
9581 | int tcc_relocate(TCCState *s1) |
||
9582 | { |
||
9583 | Section *s; |
||
9584 | int i; |
||
9585 | |||
9586 | s1->nb_errors = 0; |
||
9587 | |||
9588 | #if defined(TCC_TARGET_PE) || defined(TCC_TARGET_MEOS) |
||
9589 | pe_add_runtime(s1); |
||
9590 | #else |
||
9591 | tcc_add_runtime(s1); |
||
9592 | #endif |
||
9593 | |||
9594 | relocate_common_syms(); |
||
9595 | |||
9596 | tcc_add_linker_symbols(s1); |
||
9597 | |||
9598 | build_got_entries(s1); |
||
9599 | |||
9600 | /* compute relocation address : section are relocated in place. We |
||
9601 | also alloc the bss space */ |
||
9602 | for(i = 1; i < s1->nb_sections; i++) { |
||
9603 | s = s1->sections[i]; |
||
9604 | if (s->sh_flags & SHF_ALLOC) { |
||
9605 | if (s->sh_type == SHT_NOBITS) |
||
9606 | s->data = tcc_mallocz(s->data_offset); |
||
9607 | s->sh_addr = (unsigned long)s->data; |
||
9608 | } |
||
9609 | } |
||
9610 | |||
9611 | relocate_syms(s1, 1); |
||
9612 | |||
9613 | if (s1->nb_errors != 0) |
||
9614 | return -1; |
||
9615 | |||
9616 | /* relocate each section */ |
||
9617 | for(i = 1; i < s1->nb_sections; i++) { |
||
9618 | s = s1->sections[i]; |
||
9619 | if (s->reloc) |
||
9620 | relocate_section(s1, s); |
||
9621 | } |
||
9622 | return 0; |
||
9623 | } |
||
9624 | |||
9625 | /* launch the compiled program with the given arguments */ |
||
9626 | int tcc_run(TCCState *s1, int argc, char **argv) |
||
9627 | { |
||
9628 | int (*prog_main)(int, char **); |
||
9629 | |||
9630 | if (tcc_relocate(s1) < 0) |
||
9631 | return -1; |
||
9632 | |||
9633 | prog_main = tcc_get_symbol_err(s1, "main"); |
||
9634 | |||
9635 | if (do_debug) { |
||
9636 | #if defined(WIN32) || defined(CONFIG_TCCBOOT) |
||
9637 | error("debug mode currently not available for Windows"); |
||
9638 | #else |
||
9639 | struct sigaction sigact; |
||
9640 | /* install TCC signal handlers to print debug info on fatal |
||
9641 | runtime errors */ |
||
9642 | sigact.sa_flags = SA_SIGINFO | SA_RESETHAND; |
||
9643 | sigact.sa_sigaction = sig_error; |
||
9644 | sigemptyset(&sigact.sa_mask); |
||
9645 | sigaction(SIGFPE, &sigact, NULL); |
||
9646 | sigaction(SIGILL, &sigact, NULL); |
||
9647 | sigaction(SIGSEGV, &sigact, NULL); |
||
9648 | sigaction(SIGBUS, &sigact, NULL); |
||
9649 | sigaction(SIGABRT, &sigact, NULL); |
||
9650 | #endif |
||
9651 | } |
||
9652 | |||
9653 | #ifdef CONFIG_TCC_BCHECK |
||
9654 | if (do_bounds_check) { |
||
9655 | void (*bound_init)(void); |
||
9656 | |||
9657 | /* set error function */ |
||
9658 | rt_bound_error_msg = (void *)tcc_get_symbol_err(s1, |
||
9659 | "__bound_error_msg"); |
||
9660 | |||
9661 | /* XXX: use .init section so that it also work in binary ? */ |
||
9662 | bound_init = (void *)tcc_get_symbol_err(s1, "__bound_init"); |
||
9663 | bound_init(); |
||
9664 | } |
||
9665 | #endif |
||
9666 | return (*prog_main)(argc, argv); |
||
9667 | } |
||
9668 | |||
9669 | TCCState *tcc_new(void) |
||
9670 | { |
||
9671 | const char *p, *r; |
||
9672 | TCCState *s; |
||
9673 | TokenSym *ts; |
||
9674 | int i, c; |
||
9675 | |||
9676 | s = tcc_mallocz(sizeof(TCCState)); |
||
9677 | if (!s) |
||
9678 | return NULL; |
||
9679 | tcc_state = s; |
||
9680 | s->output_type = TCC_OUTPUT_MEMORY; |
||
9681 | |||
9682 | /* init isid table */ |
||
9683 | for(i=0;i<256;i++) |
||
9684 | isidnum_table[i] = isid(i) || isnum(i); |
||
9685 | |||
9686 | /* add all tokens */ |
||
9687 | table_ident = NULL; |
||
9688 | memset(hash_ident, 0, TOK_HASH_SIZE * sizeof(TokenSym *)); |
||
9689 | |||
9690 | tok_ident = TOK_IDENT; |
||
9691 | p = tcc_keywords; |
||
9692 | while (*p) { |
||
9693 | r = p; |
||
9694 | for(;;) { |
||
9695 | c = *r++; |
||
9696 | if (c == '\0') |
||
9697 | break; |
||
9698 | } |
||
9699 | ts = tok_alloc(p, r - p - 1); |
||
9700 | p = r; |
||
9701 | } |
||
9702 | |||
9703 | /* we add dummy defines for some special macros to speed up tests |
||
9704 | and to have working defined() */ |
||
9705 | define_push(TOK___LINE__, MACRO_OBJ, NULL, NULL); |
||
9706 | define_push(TOK___FILE__, MACRO_OBJ, NULL, NULL); |
||
9707 | define_push(TOK___DATE__, MACRO_OBJ, NULL, NULL); |
||
9708 | define_push(TOK___TIME__, MACRO_OBJ, NULL, NULL); |
||
9709 | |||
9710 | /* standard defines */ |
||
9711 | tcc_define_symbol(s, "__STDC__", NULL); |
||
9712 | #if defined(TCC_TARGET_I386) |
||
9713 | tcc_define_symbol(s, "__i386__", NULL); |
||
9714 | #endif |
||
9715 | #if defined(TCC_TARGET_ARM) |
||
9716 | tcc_define_symbol(s, "__ARM_ARCH_4__", NULL); |
||
9717 | tcc_define_symbol(s, "__arm_elf__", NULL); |
||
9718 | tcc_define_symbol(s, "__arm_elf", NULL); |
||
9719 | tcc_define_symbol(s, "arm_elf", NULL); |
||
9720 | tcc_define_symbol(s, "__arm__", NULL); |
||
9721 | tcc_define_symbol(s, "__arm", NULL); |
||
9722 | tcc_define_symbol(s, "arm", NULL); |
||
9723 | tcc_define_symbol(s, "__APCS_32__", NULL); |
||
9724 | #endif |
||
9725 | #if defined(linux) |
||
9726 | tcc_define_symbol(s, "__linux__", NULL); |
||
9727 | tcc_define_symbol(s, "linux", NULL); |
||
9728 | #endif |
||
9729 | /* tiny C specific defines */ |
||
9730 | tcc_define_symbol(s, "__TINYC__", NULL); |
||
9731 | |||
9732 | /* tiny C & gcc defines */ |
||
9733 | tcc_define_symbol(s, "__SIZE_TYPE__", "unsigned int"); |
||
9734 | tcc_define_symbol(s, "__PTRDIFF_TYPE__", "int"); |
||
9735 | tcc_define_symbol(s, "__WCHAR_TYPE__", "int"); |
||
9736 | |||
9737 | /* default library paths */ |
||
9738 | #ifdef TCC_TARGET_PE |
||
9739 | { |
||
9740 | char buf[1024]; |
||
9741 | snprintf(buf, sizeof(buf), "%s/lib", tcc_lib_path); |
||
9742 | tcc_add_library_path(s, buf); |
||
9743 | } |
||
9744 | #else |
||
9745 | #ifdef TCC_TARGET_MEOS |
||
9746 | #else |
||
9747 | tcc_add_library_path(s, "/usr/local/lib"); |
||
9748 | tcc_add_library_path(s, "/usr/lib"); |
||
9749 | tcc_add_library_path(s, "/lib"); |
||
9750 | #endif |
||
9751 | #endif |
||
9752 | |||
9753 | /* no section zero */ |
||
9754 | dynarray_add((void ***)&s->sections, &s->nb_sections, NULL); |
||
9755 | |||
9756 | /* create standard sections */ |
||
9757 | text_section = new_section(s, ".text", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR); |
||
9758 | data_section = new_section(s, ".data", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE); |
||
9759 | bss_section = new_section(s, ".bss", SHT_NOBITS, SHF_ALLOC | SHF_WRITE); |
||
9760 | |||
9761 | /* symbols are always generated for linking stage */ |
||
9762 | symtab_section = new_symtab(s, ".symtab", SHT_SYMTAB, 0, |
||
9763 | ".strtab", |
||
9764 | ".hashtab", SHF_PRIVATE); |
||
9765 | strtab_section = symtab_section->link; |
||
9766 | |||
9767 | /* private symbol table for dynamic symbols */ |
||
9768 | s->dynsymtab_section = new_symtab(s, ".dynsymtab", SHT_SYMTAB, SHF_PRIVATE, |
||
9769 | ".dynstrtab", |
||
9770 | ".dynhashtab", SHF_PRIVATE); |
||
9771 | s->alacarte_link = 1; |
||
9772 | |||
9773 | #ifdef CHAR_IS_UNSIGNED |
||
9774 | s->char_is_unsigned = 1; |
||
9775 | #endif |
||
9776 | #if defined(TCC_TARGET_PE) && 0 |
||
9777 | /* XXX: currently the PE linker is not ready to support that */ |
||
9778 | s->leading_underscore = 1; |
||
9779 | #endif |
||
9780 | return s; |
||
9781 | } |
||
9782 | |||
9783 | void tcc_delete(TCCState *s1) |
||
9784 | { |
||
9785 | int i, n; |
||
9786 | |||
9787 | /* free -D defines */ |
||
9788 | free_defines(NULL); |
||
9789 | |||
9790 | /* free tokens */ |
||
9791 | n = tok_ident - TOK_IDENT; |
||
9792 | for(i = 0; i < n; i++) |
||
9793 | tcc_free(table_ident[i]); |
||
9794 | tcc_free(table_ident); |
||
9795 | |||
9796 | /* free all sections */ |
||
9797 | |||
9798 | free_section(symtab_section->hash); |
||
9799 | |||
9800 | free_section(s1->dynsymtab_section->hash); |
||
9801 | free_section(s1->dynsymtab_section->link); |
||
9802 | free_section(s1->dynsymtab_section); |
||
9803 | |||
9804 | for(i = 1; i < s1->nb_sections; i++) |
||
9805 | free_section(s1->sections[i]); |
||
9806 | tcc_free(s1->sections); |
||
9807 | |||
9808 | /* free loaded dlls array */ |
||
9809 | for(i = 0; i < s1->nb_loaded_dlls; i++) |
||
9810 | tcc_free(s1->loaded_dlls[i]); |
||
9811 | tcc_free(s1->loaded_dlls); |
||
9812 | |||
9813 | /* library paths */ |
||
9814 | for(i = 0; i < s1->nb_library_paths; i++) |
||
9815 | tcc_free(s1->library_paths[i]); |
||
9816 | tcc_free(s1->library_paths); |
||
9817 | |||
9818 | /* cached includes */ |
||
9819 | for(i = 0; i < s1->nb_cached_includes; i++) |
||
9820 | tcc_free(s1->cached_includes[i]); |
||
9821 | tcc_free(s1->cached_includes); |
||
9822 | |||
9823 | for(i = 0; i < s1->nb_include_paths; i++) |
||
9824 | tcc_free(s1->include_paths[i]); |
||
9825 | tcc_free(s1->include_paths); |
||
9826 | |||
9827 | for(i = 0; i < s1->nb_sysinclude_paths; i++) |
||
9828 | tcc_free(s1->sysinclude_paths[i]); |
||
9829 | tcc_free(s1->sysinclude_paths); |
||
9830 | |||
9831 | tcc_free(s1); |
||
9832 | } |
||
9833 | |||
9834 | int tcc_add_include_path(TCCState *s1, const char *pathname) |
||
9835 | { |
||
9836 | char *pathname1; |
||
9837 | |||
9838 | pathname1 = tcc_strdup(pathname); |
||
9839 | dynarray_add((void ***)&s1->include_paths, &s1->nb_include_paths, pathname1); |
||
9840 | return 0; |
||
9841 | } |
||
9842 | |||
9843 | int tcc_add_sysinclude_path(TCCState *s1, const char *pathname) |
||
9844 | { |
||
9845 | char *pathname1; |
||
9846 | |||
9847 | pathname1 = tcc_strdup(pathname); |
||
9848 | dynarray_add((void ***)&s1->sysinclude_paths, &s1->nb_sysinclude_paths, pathname1); |
||
9849 | return 0; |
||
9850 | } |
||
9851 | |||
9852 | static int tcc_add_file_internal(TCCState *s1, const char *filename, int flags) |
||
9853 | { |
||
9854 | const char *ext, *filename1; |
||
9855 | Elf32_Ehdr ehdr; |
||
9856 | int fd, ret; |
||
9857 | BufferedFile *saved_file; |
||
9858 | |||
9859 | /* find source file type with extension */ |
||
9860 | filename1 = strrchr(filename, '/'); |
||
9861 | if (filename1) |
||
9862 | filename1++; |
||
9863 | else |
||
9864 | filename1 = filename; |
||
9865 | ext = strrchr(filename1, '.'); |
||
9866 | if (ext) |
||
9867 | ext++; |
||
9868 | |||
9869 | /* open the file */ |
||
9870 | saved_file = file; |
||
9871 | file = tcc_open(s1, filename); |
||
9872 | if (!file) { |
||
9873 | if (flags & AFF_PRINT_ERROR) { |
||
9874 | error_noabort("file '%s' not found", filename); |
||
9875 | } |
||
9876 | ret = -1; |
||
9877 | goto fail1; |
||
9878 | } |
||
9879 | |||
9880 | if (!ext || !strcmp(ext, "c")) { |
||
9881 | /* C file assumed */ |
||
9882 | ret = tcc_compile(s1); |
||
9883 | } else |
||
9884 | #ifdef CONFIG_TCC_ASM |
||
9885 | if (!strcmp(ext, "S")) { |
||
9886 | /* preprocessed assembler */ |
||
9887 | ret = tcc_assemble(s1, 1); |
||
9888 | } else if (!strcmp(ext, "s")) { |
||
9889 | /* non preprocessed assembler */ |
||
9890 | ret = tcc_assemble(s1, 0); |
||
9891 | } else |
||
9892 | #endif |
||
9893 | #ifdef TCC_TARGET_PE |
||
9894 | if (!strcmp(ext, "def")) { |
||
9895 | ret = pe_load_def_file(s1, fdopen(file->fd, "rb")); |
||
9896 | } else |
||
9897 | #endif |
||
9898 | { |
||
9899 | fd = file->fd; |
||
9900 | /* assume executable format: auto guess file type */ |
||
9901 | ret = read(fd, &ehdr, sizeof(ehdr)); |
||
9902 | lseek(fd, 0, SEEK_SET); |
||
9903 | if (ret <= 0) { |
||
9904 | error_noabort("could not read header"); |
||
9905 | goto fail; |
||
9906 | } else if (ret != sizeof(ehdr)) { |
||
9907 | goto try_load_script; |
||
9908 | } |
||
9909 | |||
9910 | if (ehdr.e_ident[0] == ELFMAG0 && |
||
9911 | ehdr.e_ident[1] == ELFMAG1 && |
||
9912 | ehdr.e_ident[2] == ELFMAG2 && |
||
9913 | ehdr.e_ident[3] == ELFMAG3) { |
||
9914 | file->line_num = 0; /* do not display line number if error */ |
||
9915 | if (ehdr.e_type == ET_REL) { |
||
9916 | ret = tcc_load_object_file(s1, fd, 0); |
||
9917 | } else if (ehdr.e_type == ET_DYN) { |
||
9918 | if (s1->output_type == TCC_OUTPUT_MEMORY) { |
||
9919 | #if defined(TCC_TARGET_PE) || defined(TCC_TARGET_MEOS) |
||
9920 | ret = -1; |
||
9921 | #else |
||
9922 | void *h; |
||
9923 | h = dlopen(filename, RTLD_GLOBAL | RTLD_LAZY); |
||
9924 | if (h) |
||
9925 | ret = 0; |
||
9926 | else |
||
9927 | ret = -1; |
||
9928 | #endif |
||
9929 | } else { |
||
9930 | ret = tcc_load_dll(s1, fd, filename, |
||
9931 | (flags & AFF_REFERENCED_DLL) != 0); |
||
9932 | } |
||
9933 | } else { |
||
9934 | error_noabort("unrecognized ELF file"); |
||
9935 | goto fail; |
||
9936 | } |
||
9937 | } else if (memcmp((char *)&ehdr, ARMAG, 8) == 0) { |
||
9938 | file->line_num = 0; /* do not display line number if error */ |
||
9939 | ret = tcc_load_archive(s1, fd); |
||
9940 | } else |
||
9941 | #ifdef TCC_TARGET_COFF |
||
9942 | if (*(uint16_t *)(&ehdr) == COFF_C67_MAGIC) { |
||
9943 | ret = tcc_load_coff(s1, fd); |
||
9944 | } else |
||
9945 | #endif |
||
9946 | { |
||
9947 | /* as GNU ld, consider it is an ld script if not recognized */ |
||
9948 | try_load_script: |
||
9949 | ret = tcc_load_ldscript(s1); |
||
9950 | if (ret < 0) { |
||
9951 | error_noabort("unrecognized file type"); |
||
9952 | goto fail; |
||
9953 | } |
||
9954 | } |
||
9955 | } |
||
9956 | the_end: |
||
9957 | tcc_close(file); |
||
9958 | fail1: |
||
9959 | file = saved_file; |
||
9960 | return ret; |
||
9961 | fail: |
||
9962 | ret = -1; |
||
9963 | goto the_end; |
||
9964 | } |
||
9965 | |||
9966 | int tcc_add_file(TCCState *s, const char *filename) |
||
9967 | { |
||
9968 | return tcc_add_file_internal(s, filename, AFF_PRINT_ERROR); |
||
9969 | } |
||
9970 | |||
9971 | int tcc_add_library_path(TCCState *s, const char *pathname) |
||
9972 | { |
||
9973 | char *pathname1; |
||
9974 | |||
9975 | pathname1 = tcc_strdup(pathname); |
||
9976 | dynarray_add((void ***)&s->library_paths, &s->nb_library_paths, pathname1); |
||
9977 | return 0; |
||
9978 | } |
||
9979 | |||
9980 | /* find and load a dll. Return non zero if not found */ |
||
9981 | /* XXX: add '-rpath' option support ? */ |
||
9982 | static int tcc_add_dll(TCCState *s, const char *filename, int flags) |
||
9983 | { |
||
9984 | char buf[1024]; |
||
9985 | int i; |
||
9986 | |||
9987 | for(i = 0; i < s->nb_library_paths; i++) { |
||
9988 | snprintf(buf, sizeof(buf), "%s/%s", |
||
9989 | s->library_paths[i], filename); |
||
9990 | if (tcc_add_file_internal(s, buf, flags) == 0) |
||
9991 | return 0; |
||
9992 | } |
||
9993 | return -1; |
||
9994 | } |
||
9995 | |||
9996 | /* the library name is the same as the argument of the '-l' option */ |
||
9997 | int tcc_add_library(TCCState *s, const char *libraryname) |
||
9998 | { |
||
9999 | char buf[1024]; |
||
10000 | int i; |
||
10001 | |||
10002 | /* first we look for the dynamic library if not static linking */ |
||
10003 | if (!s->static_link) { |
||
10004 | #ifdef TCC_TARGET_PE |
||
10005 | snprintf(buf, sizeof(buf), "%s.def", libraryname); |
||
10006 | #else |
||
10007 | snprintf(buf, sizeof(buf), "lib%s.so", libraryname); |
||
10008 | #endif |
||
10009 | if (tcc_add_dll(s, buf, 0) == 0) |
||
10010 | return 0; |
||
10011 | } |
||
10012 | |||
10013 | /* then we look for the static library */ |
||
10014 | for(i = 0; i < s->nb_library_paths; i++) { |
||
10015 | snprintf(buf, sizeof(buf), "%s/lib%s.a", |
||
10016 | s->library_paths[i], libraryname); |
||
10017 | if (tcc_add_file_internal(s, buf, 0) == 0) |
||
10018 | return 0; |
||
10019 | } |
||
10020 | return -1; |
||
10021 | } |
||
10022 | |||
10023 | int tcc_add_symbol(TCCState *s, const char *name, unsigned long val) |
||
10024 | { |
||
10025 | add_elf_sym(symtab_section, val, 0, |
||
10026 | ELF32_ST_INFO(STB_GLOBAL, STT_NOTYPE), 0, |
||
10027 | SHN_ABS, name); |
||
10028 | return 0; |
||
10029 | } |
||
10030 | |||
10031 | int tcc_set_output_type(TCCState *s, int output_type) |
||
10032 | { |
||
10033 | s->output_type = output_type; |
||
10034 | |||
10035 | if (!s->nostdinc) { |
||
10036 | char buf[1024]; |
||
10037 | |||
10038 | /* default include paths */ |
||
10039 | /* XXX: reverse order needed if -isystem support */ |
||
10040 | #if !defined(TCC_TARGET_PE) && !defined(TCC_TARGET_MEOS) |
||
10041 | tcc_add_sysinclude_path(s, "/usr/local/include"); |
||
10042 | tcc_add_sysinclude_path(s, "/usr/include"); |
||
10043 | #endif |
||
10044 | snprintf(buf, sizeof(buf), "%s/include", tcc_lib_path); |
||
10045 | tcc_add_sysinclude_path(s, buf); |
||
10046 | #ifdef TCC_TARGET_PE |
||
10047 | snprintf(buf, sizeof(buf), "%s/include/winapi", tcc_lib_path); |
||
10048 | tcc_add_sysinclude_path(s, buf); |
||
10049 | #endif |
||
10050 | } |
||
10051 | |||
10052 | /* if bound checking, then add corresponding sections */ |
||
10053 | #ifdef CONFIG_TCC_BCHECK |
||
10054 | if (do_bounds_check) { |
||
10055 | /* define symbol */ |
||
10056 | tcc_define_symbol(s, "__BOUNDS_CHECKING_ON", NULL); |
||
10057 | /* create bounds sections */ |
||
10058 | bounds_section = new_section(s, ".bounds", |
||
10059 | SHT_PROGBITS, SHF_ALLOC); |
||
10060 | lbounds_section = new_section(s, ".lbounds", |
||
10061 | SHT_PROGBITS, SHF_ALLOC); |
||
10062 | } |
||
10063 | #endif |
||
10064 | |||
10065 | if (s->char_is_unsigned) { |
||
10066 | tcc_define_symbol(s, "__CHAR_UNSIGNED__", NULL); |
||
10067 | } |
||
10068 | |||
10069 | /* add debug sections */ |
||
10070 | if (do_debug) { |
||
10071 | /* stab symbols */ |
||
10072 | stab_section = new_section(s, ".stab", SHT_PROGBITS, 0); |
||
10073 | stab_section->sh_entsize = sizeof(Stab_Sym); |
||
10074 | stabstr_section = new_section(s, ".stabstr", SHT_STRTAB, 0); |
||
10075 | put_elf_str(stabstr_section, ""); |
||
10076 | stab_section->link = stabstr_section; |
||
10077 | /* put first entry */ |
||
10078 | put_stabs("", 0, 0, 0, 0); |
||
10079 | } |
||
10080 | |||
10081 | /* add libc crt1/crti objects */ |
||
10082 | #if !defined(TCC_TARGET_PE) && !defined(TCC_TARGET_MEOS) |
||
10083 | if ((output_type == TCC_OUTPUT_EXE || output_type == TCC_OUTPUT_DLL) && |
||
10084 | !s->nostdlib) { |
||
10085 | if (output_type != TCC_OUTPUT_DLL) |
||
10086 | tcc_add_file(s, CONFIG_TCC_CRT_PREFIX "/crt1.o"); |
||
10087 | tcc_add_file(s, CONFIG_TCC_CRT_PREFIX "/crti.o"); |
||
10088 | } |
||
10089 | #endif |
||
10090 | #if defined(TCC_TARGET_MEOS) |
||
10091 | if (s->output_type != TCC_OUTPUT_OBJ) |
||
10092 | tcc_add_file(s,".\\start.o"); |
||
10093 | #endif |
||
10094 | return 0; |
||
10095 | } |
||
10096 | |||
10097 | #define WD_ALL 0x0001 /* warning is activated when using -Wall */ |
||
10098 | #define FD_INVERT 0x0002 /* invert value before storing */ |
||
10099 | |||
10100 | typedef struct FlagDef { |
||
10101 | uint16_t offset; |
||
10102 | uint16_t flags; |
||
10103 | const char *name; |
||
10104 | } FlagDef; |
||
10105 | |||
10106 | static const FlagDef warning_defs[] = { |
||
10107 | { offsetof(TCCState, warn_unsupported), 0, "unsupported" }, |
||
10108 | { offsetof(TCCState, warn_write_strings), 0, "write-strings" }, |
||
10109 | { offsetof(TCCState, warn_error), 0, "error" }, |
||
10110 | { offsetof(TCCState, warn_implicit_function_declaration), WD_ALL, |
||
10111 | "implicit-function-declaration" }, |
||
10112 | }; |
||
10113 | |||
10114 | static int set_flag(TCCState *s, const FlagDef *flags, int nb_flags, |
||
10115 | const char *name, int value) |
||
10116 | { |
||
10117 | int i; |
||
10118 | const FlagDef *p; |
||
10119 | const char *r; |
||
10120 | |||
10121 | r = name; |
||
10122 | if (r[0] == 'n' && r[1] == 'o' && r[2] == '-') { |
||
10123 | r += 3; |
||
10124 | value = !value; |
||
10125 | } |
||
10126 | for(i = 0, p = flags; i < nb_flags; i++, p++) { |
||
10127 | if (!strcmp(r, p->name)) |
||
10128 | goto found; |
||
10129 | } |
||
10130 | return -1; |
||
10131 | found: |
||
10132 | if (p->flags & FD_INVERT) |
||
10133 | value = !value; |
||
10134 | *(int *)((uint8_t *)s + p->offset) = value; |
||
10135 | return 0; |
||
10136 | } |
||
10137 | |||
10138 | |||
10139 | /* set/reset a warning */ |
||
10140 | int tcc_set_warning(TCCState *s, const char *warning_name, int value) |
||
10141 | { |
||
10142 | int i; |
||
10143 | const FlagDef *p; |
||
10144 | |||
10145 | if (!strcmp(warning_name, "all")) { |
||
10146 | for(i = 0, p = warning_defs; i < countof(warning_defs); i++, p++) { |
||
10147 | if (p->flags & WD_ALL) |
||
10148 | *(int *)((uint8_t *)s + p->offset) = 1; |
||
10149 | } |
||
10150 | return 0; |
||
10151 | } else { |
||
10152 | return set_flag(s, warning_defs, countof(warning_defs), |
||
10153 | warning_name, value); |
||
10154 | } |
||
10155 | } |
||
10156 | |||
10157 | static const FlagDef flag_defs[] = { |
||
10158 | { offsetof(TCCState, char_is_unsigned), 0, "unsigned-char" }, |
||
10159 | { offsetof(TCCState, char_is_unsigned), FD_INVERT, "signed-char" }, |
||
10160 | { offsetof(TCCState, nocommon), FD_INVERT, "common" }, |
||
10161 | { offsetof(TCCState, leading_underscore), 0, "leading-underscore" }, |
||
10162 | }; |
||
10163 | |||
10164 | /* set/reset a flag */ |
||
10165 | int tcc_set_flag(TCCState *s, const char *flag_name, int value) |
||
10166 | { |
||
10167 | return set_flag(s, flag_defs, countof(flag_defs), |
||
10168 | flag_name, value); |
||
10169 | } |
||
10170 | |||
10171 | #if !defined(LIBTCC) |
||
10172 | |||
10173 | /* extract the basename of a file */ |
||
10174 | static const char *tcc_basename(const char *name) |
||
10175 | { |
||
10176 | const char *p; |
||
10177 | p = strrchr(name, '/'); |
||
10178 | #ifdef WIN32 |
||
10179 | if (!p) |
||
10180 | p = strrchr(name, '\\'); |
||
10181 | #endif |
||
10182 | if (!p) |
||
10183 | p = name; |
||
10184 | else |
||
10185 | p++; |
||
10186 | return p; |
||
10187 | } |
||
10188 | |||
10189 | static int64_t getclock_us(void) |
||
10190 | { |
||
10191 | #ifdef WIN32 |
||
10192 | struct _timeb tb; |
||
10193 | _ftime(&tb); |
||
10194 | return (tb.time * 1000LL + tb.millitm) * 1000LL; |
||
10195 | #else |
||
10196 | struct timeval tv; |
||
10197 | gettimeofday(&tv, NULL); |
||
10198 | return tv.tv_sec * 1000000LL + tv.tv_usec; |
||
10199 | #endif |
||
10200 | } |
||
10201 | |||
10202 | void help(void) |
||
10203 | { |
||
10204 | printf("tcc version " TCC_VERSION " - Tiny C Compiler - Copyright (C) 2001-2005 Fabrice Bellard\n" |
||
10205 | "usage: tcc [-v] [-c] [-o outfile] [-Bdir] [-bench] [-Idir] [-Dsym[=val]] [-Usym]\n" |
||
10206 | " [-Wwarn] [-g] [-b] [-bt N] [-Ldir] [-llib] [-shared] [-static]\n" |
||
10207 | " [infile1 infile2...] [-run infile args...]\n" |
||
10208 | "\n" |
||
10209 | "General options:\n" |
||
10210 | " -v display current version\n" |
||
10211 | " -c compile only - generate an object file\n" |
||
10212 | " -o outfile set output filename\n" |
||
10213 | " -Bdir set tcc internal library path\n" |
||
10214 | " -bench output compilation statistics\n" |
||
10215 | " -run run compiled source\n" |
||
10216 | " -fflag set or reset (with 'no-' prefix) 'flag' (see man page)\n" |
||
10217 | " -Wwarning set or reset (with 'no-' prefix) 'warning' (see man page)\n" |
||
10218 | " -w disable all warnings\n" |
||
10219 | "Preprocessor options:\n" |
||
10220 | " -Idir add include path 'dir'\n" |
||
10221 | " -Dsym[=val] define 'sym' with value 'val'\n" |
||
10222 | " -Usym undefine 'sym'\n" |
||
10223 | "Linker options:\n" |
||
10224 | " -Ldir add library path 'dir'\n" |
||
10225 | " -llib link with dynamic or static library 'lib'\n" |
||
10226 | " -shared generate a shared library\n" |
||
10227 | " -static static linking\n" |
||
10228 | " -rdynamic export all global symbols to dynamic linker\n" |
||
10229 | " -r relocatable output\n" |
||
10230 | "Debugger options:\n" |
||
10231 | " -g generate runtime debug info\n" |
||
10232 | #ifdef CONFIG_TCC_BCHECK |
||
10233 | " -b compile with built-in memory and bounds checker (implies -g)\n" |
||
10234 | #endif |
||
10235 | " -bt N show N callers in stack traces\n" |
||
10236 | ); |
||
10237 | } |
||
10238 | |||
10239 | #define TCC_OPTION_HAS_ARG 0x0001 |
||
10240 | #define TCC_OPTION_NOSEP 0x0002 /* cannot have space before option and arg */ |
||
10241 | |||
10242 | typedef struct TCCOption { |
||
10243 | const char *name; |
||
10244 | uint16_t index; |
||
10245 | uint16_t flags; |
||
10246 | } TCCOption; |
||
10247 | |||
10248 | enum { |
||
10249 | TCC_OPTION_HELP, |
||
10250 | TCC_OPTION_I, |
||
10251 | TCC_OPTION_D, |
||
10252 | TCC_OPTION_U, |
||
10253 | TCC_OPTION_L, |
||
10254 | TCC_OPTION_B, |
||
10255 | TCC_OPTION_l, |
||
10256 | TCC_OPTION_bench, |
||
10257 | TCC_OPTION_bt, |
||
10258 | TCC_OPTION_b, |
||
10259 | TCC_OPTION_g, |
||
10260 | TCC_OPTION_c, |
||
10261 | TCC_OPTION_static, |
||
10262 | TCC_OPTION_shared, |
||
10263 | TCC_OPTION_o, |
||
10264 | TCC_OPTION_r, |
||
10265 | TCC_OPTION_Wl, |
||
10266 | TCC_OPTION_W, |
||
10267 | TCC_OPTION_O, |
||
10268 | TCC_OPTION_m, |
||
10269 | TCC_OPTION_f, |
||
10270 | TCC_OPTION_nostdinc, |
||
10271 | TCC_OPTION_nostdlib, |
||
10272 | TCC_OPTION_print_search_dirs, |
||
10273 | TCC_OPTION_rdynamic, |
||
10274 | TCC_OPTION_run, |
||
10275 | TCC_OPTION_v, |
||
10276 | TCC_OPTION_w, |
||
10277 | TCC_OPTION_pipe, |
||
10278 | }; |
||
10279 | |||
10280 | static const TCCOption tcc_options[] = { |
||
10281 | { "h", TCC_OPTION_HELP, 0 }, |
||
10282 | { "?", TCC_OPTION_HELP, 0 }, |
||
10283 | { "I", TCC_OPTION_I, TCC_OPTION_HAS_ARG }, |
||
10284 | { "D", TCC_OPTION_D, TCC_OPTION_HAS_ARG }, |
||
10285 | { "U", TCC_OPTION_U, TCC_OPTION_HAS_ARG }, |
||
10286 | { "L", TCC_OPTION_L, TCC_OPTION_HAS_ARG }, |
||
10287 | { "B", TCC_OPTION_B, TCC_OPTION_HAS_ARG }, |
||
10288 | { "l", TCC_OPTION_l, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, |
||
10289 | { "bench", TCC_OPTION_bench, 0 }, |
||
10290 | { "bt", TCC_OPTION_bt, TCC_OPTION_HAS_ARG }, |
||
10291 | #ifdef CONFIG_TCC_BCHECK |
||
10292 | { "b", TCC_OPTION_b, 0 }, |
||
10293 | #endif |
||
10294 | { "g", TCC_OPTION_g, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, |
||
10295 | { "c", TCC_OPTION_c, 0 }, |
||
10296 | { "static", TCC_OPTION_static, 0 }, |
||
10297 | { "shared", TCC_OPTION_shared, 0 }, |
||
10298 | { "o", TCC_OPTION_o, TCC_OPTION_HAS_ARG }, |
||
10299 | { "run", TCC_OPTION_run, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, |
||
10300 | { "rdynamic", TCC_OPTION_rdynamic, 0 }, |
||
10301 | { "r", TCC_OPTION_r, 0 }, |
||
10302 | { "Wl,", TCC_OPTION_Wl, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, |
||
10303 | { "W", TCC_OPTION_W, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, |
||
10304 | { "O", TCC_OPTION_O, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, |
||
10305 | { "m", TCC_OPTION_m, TCC_OPTION_HAS_ARG }, |
||
10306 | { "f", TCC_OPTION_f, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, |
||
10307 | { "nostdinc", TCC_OPTION_nostdinc, 0 }, |
||
10308 | { "nostdlib", TCC_OPTION_nostdlib, 0 }, |
||
10309 | { "print-search-dirs", TCC_OPTION_print_search_dirs, 0 }, |
||
10310 | { "v", TCC_OPTION_v, 0 }, |
||
10311 | { "w", TCC_OPTION_w, 0 }, |
||
10312 | { "pipe", TCC_OPTION_pipe, 0}, |
||
10313 | { NULL }, |
||
10314 | }; |
||
10315 | |||
10316 | /* convert 'str' into an array of space separated strings */ |
||
10317 | static int expand_args(char ***pargv, const char *str) |
||
10318 | { |
||
10319 | const char *s1; |
||
10320 | char **argv, *arg; |
||
10321 | int argc, len; |
||
10322 | |||
10323 | argc = 0; |
||
10324 | argv = NULL; |
||
10325 | for(;;) { |
||
10326 | while (is_space(*str)) |
||
10327 | str++; |
||
10328 | if (*str == '\0') |
||
10329 | break; |
||
10330 | s1 = str; |
||
10331 | while (*str != '\0' && !is_space(*str)) |
||
10332 | str++; |
||
10333 | len = str - s1; |
||
10334 | arg = tcc_malloc(len + 1); |
||
10335 | memcpy(arg, s1, len); |
||
10336 | arg[len] = '\0'; |
||
10337 | dynarray_add((void ***)&argv, &argc, arg); |
||
10338 | } |
||
10339 | *pargv = argv; |
||
10340 | return argc; |
||
10341 | } |
||
10342 | |||
10343 | static char **files; |
||
10344 | static int nb_files, nb_libraries; |
||
10345 | static int multiple_files; |
||
10346 | static int print_search_dirs; |
||
10347 | static int output_type; |
||
10348 | static int reloc_output; |
||
10349 | static const char *outfile; |
||
10350 | |||
10351 | int parse_args(TCCState *s, int argc, char **argv) |
||
10352 | { |
||
10353 | int optind; |
||
10354 | const TCCOption *popt; |
||
10355 | const char *optarg, *p1, *r1; |
||
10356 | char *r; |
||
10357 | |||
10358 | optind = 0; |
||
10359 | while (1) { |
||
10360 | if (optind >= argc) { |
||
10361 | if (nb_files == 0 && !print_search_dirs) |
||
10362 | goto show_help; |
||
10363 | else |
||
10364 | break; |
||
10365 | } |
||
10366 | r = argv[optind++]; |
||
10367 | if (r[0] != '-') { |
||
10368 | /* add a new file */ |
||
10369 | dynarray_add((void ***)&files, &nb_files, r); |
||
10370 | if (!multiple_files) { |
||
10371 | optind--; |
||
10372 | /* argv[0] will be this file */ |
||
10373 | break; |
||
10374 | } |
||
10375 | } else { |
||
10376 | /* find option in table (match only the first chars */ |
||
10377 | popt = tcc_options; |
||
10378 | for(;;) { |
||
10379 | p1 = popt->name; |
||
10380 | if (p1 == NULL) |
||
10381 | error("invalid option -- '%s'", r); |
||
10382 | r1 = r + 1; |
||
10383 | for(;;) { |
||
10384 | if (*p1 == '\0') |
||
10385 | goto option_found; |
||
10386 | if (*r1 != *p1) |
||
10387 | break; |
||
10388 | p1++; |
||
10389 | r1++; |
||
10390 | } |
||
10391 | popt++; |
||
10392 | } |
||
10393 | option_found: |
||
10394 | if (popt->flags & TCC_OPTION_HAS_ARG) { |
||
10395 | if (*r1 != '\0' || (popt->flags & TCC_OPTION_NOSEP)) { |
||
10396 | optarg = r1; |
||
10397 | } else { |
||
10398 | if (optind >= argc) |
||
10399 | error("argument to '%s' is missing", r); |
||
10400 | optarg = argv[optind++]; |
||
10401 | } |
||
10402 | } else { |
||
10403 | if (*r1 != '\0') |
||
10404 | goto show_help; |
||
10405 | optarg = NULL; |
||
10406 | } |
||
10407 | |||
10408 | switch(popt->index) { |
||
10409 | case TCC_OPTION_HELP: |
||
10410 | show_help: |
||
10411 | help(); |
||
10412 | exit(1); |
||
10413 | case TCC_OPTION_I: |
||
10414 | if (tcc_add_include_path(s, optarg) < 0) |
||
10415 | error("too many include paths"); |
||
10416 | break; |
||
10417 | case TCC_OPTION_D: |
||
10418 | { |
||
10419 | char *sym, *value; |
||
10420 | sym = (char *)optarg; |
||
10421 | value = strchr(sym, '='); |
||
10422 | if (value) { |
||
10423 | *value = '\0'; |
||
10424 | value++; |
||
10425 | } |
||
10426 | tcc_define_symbol(s, sym, value); |
||
10427 | } |
||
10428 | break; |
||
10429 | case TCC_OPTION_U: |
||
10430 | tcc_undefine_symbol(s, optarg); |
||
10431 | break; |
||
10432 | case TCC_OPTION_L: |
||
10433 | tcc_add_library_path(s, optarg); |
||
10434 | break; |
||
10435 | case TCC_OPTION_B: |
||
10436 | /* set tcc utilities path (mainly for tcc development) */ |
||
10437 | tcc_lib_path = optarg; |
||
10438 | break; |
||
10439 | case TCC_OPTION_l: |
||
10440 | dynarray_add((void ***)&files, &nb_files, r); |
||
10441 | nb_libraries++; |
||
10442 | break; |
||
10443 | case TCC_OPTION_bench: |
||
10444 | do_bench = 1; |
||
10445 | break; |
||
10446 | case TCC_OPTION_bt: |
||
10447 | num_callers = atoi(optarg); |
||
10448 | break; |
||
10449 | #ifdef CONFIG_TCC_BCHECK |
||
10450 | case TCC_OPTION_b: |
||
10451 | do_bounds_check = 1; |
||
10452 | do_debug = 1; |
||
10453 | break; |
||
10454 | #endif |
||
10455 | case TCC_OPTION_g: |
||
10456 | do_debug = 1; |
||
10457 | break; |
||
10458 | case TCC_OPTION_c: |
||
10459 | multiple_files = 1; |
||
10460 | output_type = TCC_OUTPUT_OBJ; |
||
10461 | break; |
||
10462 | case TCC_OPTION_static: |
||
10463 | s->static_link = 1; |
||
10464 | break; |
||
10465 | case TCC_OPTION_shared: |
||
10466 | output_type = TCC_OUTPUT_DLL; |
||
10467 | break; |
||
10468 | case TCC_OPTION_o: |
||
10469 | multiple_files = 1; |
||
10470 | outfile = optarg; |
||
10471 | break; |
||
10472 | case TCC_OPTION_r: |
||
10473 | /* generate a .o merging several output files */ |
||
10474 | reloc_output = 1; |
||
10475 | output_type = TCC_OUTPUT_OBJ; |
||
10476 | break; |
||
10477 | case TCC_OPTION_nostdinc: |
||
10478 | s->nostdinc = 1; |
||
10479 | break; |
||
10480 | case TCC_OPTION_nostdlib: |
||
10481 | s->nostdlib = 1; |
||
10482 | break; |
||
10483 | case TCC_OPTION_print_search_dirs: |
||
10484 | print_search_dirs = 1; |
||
10485 | break; |
||
10486 | case TCC_OPTION_run: |
||
10487 | { |
||
10488 | int argc1; |
||
10489 | char **argv1; |
||
10490 | argc1 = expand_args(&argv1, optarg); |
||
10491 | if (argc1 > 0) { |
||
10492 | parse_args(s, argc1, argv1); |
||
10493 | } |
||
10494 | multiple_files = 0; |
||
10495 | output_type = TCC_OUTPUT_MEMORY; |
||
10496 | } |
||
10497 | break; |
||
10498 | case TCC_OPTION_v: |
||
10499 | printf("tcc version %s\n", TCC_VERSION); |
||
10500 | exit(0); |
||
10501 | case TCC_OPTION_f: |
||
10502 | if (tcc_set_flag(s, optarg, 1) < 0 && s->warn_unsupported) |
||
10503 | goto unsupported_option; |
||
10504 | break; |
||
10505 | case TCC_OPTION_W: |
||
10506 | if (tcc_set_warning(s, optarg, 1) < 0 && |
||
10507 | s->warn_unsupported) |
||
10508 | goto unsupported_option; |
||
10509 | break; |
||
10510 | case TCC_OPTION_w: |
||
10511 | s->warn_none = 1; |
||
10512 | break; |
||
10513 | case TCC_OPTION_rdynamic: |
||
10514 | s->rdynamic = 1; |
||
10515 | break; |
||
10516 | case TCC_OPTION_Wl: |
||
10517 | { |
||
10518 | const char *p; |
||
10519 | if (strstart(optarg, "-Ttext,", &p)) { |
||
10520 | s->text_addr = strtoul(p, NULL, 16); |
||
10521 | s->has_text_addr = 1; |
||
10522 | } else if (strstart(optarg, "--oformat,", &p)) { |
||
10523 | if (strstart(p, "elf32-", NULL)) { |
||
10524 | s->output_format = TCC_OUTPUT_FORMAT_ELF; |
||
10525 | } else if (!strcmp(p, "binary")) { |
||
10526 | s->output_format = TCC_OUTPUT_FORMAT_BINARY; |
||
10527 | } else |
||
10528 | #ifdef TCC_TARGET_COFF |
||
10529 | if (!strcmp(p, "coff")) { |
||
10530 | s->output_format = TCC_OUTPUT_FORMAT_COFF; |
||
10531 | } else |
||
10532 | #endif |
||
10533 | { |
||
10534 | error("target %s not found", p); |
||
10535 | } |
||
10536 | } else { |
||
10537 | error("unsupported linker option '%s'", optarg); |
||
10538 | } |
||
10539 | } |
||
10540 | break; |
||
10541 | default: |
||
10542 | if (s->warn_unsupported) { |
||
10543 | unsupported_option: |
||
10544 | warning("unsupported option '%s'", r); |
||
10545 | } |
||
10546 | break; |
||
10547 | } |
||
10548 | } |
||
10549 | } |
||
10550 | return optind; |
||
10551 | } |
||
10552 | |||
10553 | int main(int argc, char **argv) |
||
10554 | { |
||
10555 | int i; |
||
10556 | TCCState *s; |
||
10557 | int nb_objfiles, ret, optind; |
||
10558 | char objfilename[1024]; |
||
10559 | int64_t start_time = 0; |
||
10560 | |||
10561 | #ifdef WIN32 |
||
10562 | /* on win32, we suppose the lib and includes are at the location |
||
10563 | of 'tcc.exe' */ |
||
10564 | { |
||
10565 | static char path[1024]; |
||
10566 | char *p, *d; |
||
10567 | |||
10568 | GetModuleFileNameA(NULL, path, sizeof path); |
||
10569 | p = d = strlwr(path); |
||
10570 | while (*d) |
||
10571 | { |
||
10572 | if (*d == '\\') *d = '/', p = d; |
||
10573 | ++d; |
||
10574 | } |
||
10575 | *p = '\0'; |
||
10576 | tcc_lib_path = path; |
||
10577 | } |
||
10578 | #endif |
||
10579 | |||
10580 | s = tcc_new(); |
||
10581 | output_type = TCC_OUTPUT_EXE; |
||
10582 | outfile = NULL; |
||
10583 | multiple_files = 1; |
||
10584 | files = NULL; |
||
10585 | nb_files = 0; |
||
10586 | nb_libraries = 0; |
||
10587 | reloc_output = 0; |
||
10588 | print_search_dirs = 0; |
||
10589 | |||
10590 | optind = parse_args(s, argc - 1, argv + 1) + 1; |
||
10591 | |||
10592 | if (print_search_dirs) { |
||
10593 | /* enough for Linux kernel */ |
||
10594 | printf("install: %s/\n", tcc_lib_path); |
||
10595 | return 0; |
||
10596 | } |
||
10597 | |||
10598 | nb_objfiles = nb_files - nb_libraries; |
||
10599 | |||
10600 | /* if outfile provided without other options, we output an |
||
10601 | executable */ |
||
10602 | if (outfile && output_type == TCC_OUTPUT_MEMORY) |
||
10603 | output_type = TCC_OUTPUT_EXE; |
||
10604 | |||
10605 | /* check -c consistency : only single file handled. XXX: checks file type */ |
||
10606 | if (output_type == TCC_OUTPUT_OBJ && !reloc_output) { |
||
10607 | /* accepts only a single input file */ |
||
10608 | if (nb_objfiles != 1) |
||
10609 | error("cannot specify multiple files with -c"); |
||
10610 | if (nb_libraries != 0) |
||
10611 | error("cannot specify libraries with -c"); |
||
10612 | } |
||
10613 | |||
10614 | if (output_type != TCC_OUTPUT_MEMORY) { |
||
10615 | if (!outfile) { |
||
10616 | /* compute default outfile name */ |
||
10617 | pstrcpy(objfilename, sizeof(objfilename) - 1, |
||
10618 | /* strip path */ |
||
10619 | tcc_basename(files[0])); |
||
10620 | #ifdef TCC_TARGET_PE |
||
10621 | pe_guess_outfile(objfilename, output_type); |
||
10622 | #else |
||
10623 | if (output_type == TCC_OUTPUT_OBJ && !reloc_output) { |
||
10624 | char *ext = strrchr(objfilename, '.'); |
||
10625 | if (!ext) |
||
10626 | goto default_outfile; |
||
10627 | /* add .o extension */ |
||
10628 | strcpy(ext + 1, "o"); |
||
10629 | } else { |
||
10630 | default_outfile: |
||
10631 | pstrcpy(objfilename, sizeof(objfilename), "a.out"); |
||
10632 | } |
||
10633 | #endif |
||
10634 | outfile = objfilename; |
||
10635 | } |
||
10636 | } |
||
10637 | |||
10638 | if (do_bench) { |
||
10639 | start_time = getclock_us(); |
||
10640 | } |
||
10641 | |||
10642 | tcc_set_output_type(s, output_type); |
||
10643 | |||
10644 | /* compile or add each files or library */ |
||
10645 | for(i = 0;i < nb_files; i++) { |
||
10646 | const char *filename; |
||
10647 | |||
10648 | filename = files[i]; |
||
10649 | if (filename[0] == '-') { |
||
10650 | if (tcc_add_library(s, filename + 2) < 0) |
||
10651 | error("cannot find %s", filename); |
||
10652 | } else { |
||
10653 | if (tcc_add_file(s, filename) < 0) { |
||
10654 | ret = 1; |
||
10655 | goto the_end; |
||
10656 | } |
||
10657 | } |
||
10658 | } |
||
10659 | |||
10660 | /* free all files */ |
||
10661 | tcc_free(files); |
||
10662 | |||
10663 | if (do_bench) { |
||
10664 | double total_time; |
||
10665 | total_time = (double)(getclock_us() - start_time) / 1000000.0; |
||
10666 | if (total_time < 0.001) |
||
10667 | total_time = 0.001; |
||
10668 | if (total_bytes < 1) |
||
10669 | total_bytes = 1; |
||
10670 | printf("%d idents, %d lines, %d bytes, %0.3f s, %d lines/s, %0.1f MB/s\n", |
||
10671 | tok_ident - TOK_IDENT, total_lines, total_bytes, |
||
10672 | total_time, (int)(total_lines / total_time), |
||
10673 | total_bytes / total_time / 1000000.0); |
||
10674 | } |
||
10675 | |||
10676 | if (s->output_type == TCC_OUTPUT_MEMORY) { |
||
10677 | ret = tcc_run(s, argc - optind, argv + optind); |
||
10678 | } else |
||
10679 | #ifdef TCC_TARGET_PE |
||
10680 | if (s->output_type != TCC_OUTPUT_OBJ) { |
||
10681 | ret = tcc_output_pe(s, outfile); |
||
10682 | } else |
||
10683 | #else |
||
10684 | #ifdef TCC_TARGET_MEOS |
||
10685 | if (s->output_type != TCC_OUTPUT_OBJ) { |
||
10686 | ret = tcc_output_me(s, outfile); |
||
10687 | } else |
||
10688 | #endif |
||
10689 | #endif |
||
10690 | |||
10691 | { |
||
10692 | tcc_output_file(s, outfile); |
||
10693 | ret = 0; |
||
10694 | } |
||
10695 | the_end: |
||
10696 | /* XXX: cannot do it with bound checking because of the malloc hooks */ |
||
10697 | if (!do_bounds_check) |
||
10698 | tcc_delete(s); |
||
10699 | |||
10700 | #ifdef MEM_DEBUG |
||
10701 | if (do_bench) { |
||
10702 | printf("memory: %d bytes, max = %d bytes\n", mem_cur_size, mem_max_size); |
||
10703 | } |
||
10704 | #endif |
||
10705 | return ret; |
||
10706 | } |
||
10707 | |||
10708 | #endif>>>>>>>>>>>>>=>>>>>>>>256;i++) |