Rev 145 | Go to most recent revision | Details | Compare with Previous | 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 |
||
609 | andrew_pro | 34 | //#include |
145 | halyavin | 35 | #include |
36 | #include |
||
609 | andrew_pro | 37 | //#include |
145 | halyavin | 38 | #include |
39 | #include |
||
40 | #include |
||
41 | #ifdef WIN32 |
||
42 | #include |
||
43 | #endif |
||
609 | andrew_pro | 44 | //#ifndef WIN32 |
45 | |||
145 | halyavin | 46 | #include |
609 | andrew_pro | 47 | //#include |
48 | //#endif |
||
145 | halyavin | 49 | |
50 | #endif /* !CONFIG_TCCBOOT */ |
||
51 | |||
52 | #include "elf.h" |
||
53 | #include "stab.h" |
||
54 | |||
55 | #ifndef O_BINARY |
||
56 | #define O_BINARY 0 |
||
57 | #endif |
||
58 | |||
59 | #include "libtcc.h" |
||
60 | |||
61 | /* parser debug */ |
||
62 | //#define PARSE_DEBUG |
||
63 | /* preprocessor debug */ |
||
64 | //#define PP_DEBUG |
||
65 | /* include file debug */ |
||
66 | //#define INC_DEBUG |
||
67 | |||
68 | //#define MEM_DEBUG |
||
69 | |||
70 | /* assembler debug */ |
||
71 | //#define ASM_DEBUG |
||
72 | |||
73 | /* target selection */ |
||
74 | //#define TCC_TARGET_I386 /* i386 code generator */ |
||
75 | //#define TCC_TARGET_ARM /* ARMv4 code generator */ |
||
76 | //#define TCC_TARGET_C67 /* TMS320C67xx code generator */ |
||
609 | andrew_pro | 77 | //---------------------------------------------------------------- |
78 | #define TCC_TARGET_MEOS |
||
145 | halyavin | 79 | |
80 | /* default target is I386 */ |
||
81 | #if !defined(TCC_TARGET_I386) && !defined(TCC_TARGET_ARM) && \ |
||
82 | !defined(TCC_TARGET_C67) |
||
83 | #define TCC_TARGET_I386 |
||
84 | #endif |
||
85 | |||
86 | #if !defined(WIN32) && !defined(TCC_UCLIBC) && !defined(TCC_TARGET_ARM) && \ |
||
87 | !defined(TCC_TARGET_C67) |
||
88 | #define CONFIG_TCC_BCHECK /* enable bound checking code */ |
||
89 | #endif |
||
90 | |||
91 | #if defined(WIN32) && !defined(TCC_TARGET_PE) && !defined(TCC_TARGET_MEOS) |
||
92 | #define CONFIG_TCC_STATIC |
||
93 | #endif |
||
94 | |||
95 | /* define it to include assembler support */ |
||
96 | #if !defined(TCC_TARGET_ARM) && !defined(TCC_TARGET_C67) |
||
97 | #define CONFIG_TCC_ASM |
||
98 | #endif |
||
99 | |||
100 | /* object format selection */ |
||
101 | #if defined(TCC_TARGET_C67) |
||
102 | #define TCC_TARGET_COFF |
||
103 | #endif |
||
104 | |||
105 | #define FALSE 0 |
||
106 | #define false 0 |
||
107 | #define TRUE 1 |
||
108 | #define true 1 |
||
109 | typedef int BOOL; |
||
110 | |||
111 | /* path to find crt1.o, crti.o and crtn.o. Only needed when generating |
||
112 | executables or dlls */ |
||
113 | #define CONFIG_TCC_CRT_PREFIX "/usr/lib" |
||
114 | |||
115 | #define INCLUDE_STACK_SIZE 32 |
||
116 | #define IFDEF_STACK_SIZE 64 |
||
117 | #define VSTACK_SIZE 256 |
||
118 | #define STRING_MAX_SIZE 1024 |
||
119 | #define PACK_STACK_SIZE 8 |
||
120 | |||
121 | #define TOK_HASH_SIZE 8192 /* must be a power of two */ |
||
122 | #define TOK_ALLOC_INCR 512 /* must be a power of two */ |
||
123 | #define TOK_MAX_SIZE 4 /* token max size in int unit when stored in string */ |
||
124 | |||
125 | /* token symbol management */ |
||
126 | typedef struct TokenSym { |
||
127 | struct TokenSym *hash_next; |
||
128 | struct Sym *sym_define; /* direct pointer to define */ |
||
129 | struct Sym *sym_label; /* direct pointer to label */ |
||
130 | struct Sym *sym_struct; /* direct pointer to structure */ |
||
131 | struct Sym *sym_identifier; /* direct pointer to identifier */ |
||
132 | int tok; /* token number */ |
||
133 | int len; |
||
134 | char str[1]; |
||
135 | } TokenSym; |
||
136 | |||
137 | typedef struct CString { |
||
138 | int size; /* size in bytes */ |
||
139 | void *data; /* either 'char *' or 'int *' */ |
||
140 | int size_allocated; |
||
141 | void *data_allocated; /* if non NULL, data has been malloced */ |
||
142 | } CString; |
||
143 | |||
144 | /* type definition */ |
||
145 | typedef struct CType { |
||
146 | int t; |
||
147 | struct Sym *ref; |
||
148 | } CType; |
||
149 | |||
150 | /* constant value */ |
||
151 | typedef union CValue { |
||
152 | long double ld; |
||
153 | double d; |
||
154 | float f; |
||
155 | int i; |
||
156 | unsigned int ui; |
||
157 | unsigned int ul; /* address (should be unsigned long on 64 bit cpu) */ |
||
158 | long long ll; |
||
159 | unsigned long long ull; |
||
160 | struct CString *cstr; |
||
161 | void *ptr; |
||
162 | int tab[1]; |
||
163 | } CValue; |
||
164 | |||
165 | /* value on stack */ |
||
166 | typedef struct SValue { |
||
167 | CType type; /* type */ |
||
168 | unsigned short r; /* register + flags */ |
||
169 | unsigned short r2; /* second register, used for 'long long' |
||
170 | type. If not used, set to VT_CONST */ |
||
171 | CValue c; /* constant, if VT_CONST */ |
||
172 | struct Sym *sym; /* symbol, if (VT_SYM | VT_CONST) */ |
||
173 | } SValue; |
||
174 | |||
175 | /* symbol management */ |
||
176 | typedef struct Sym { |
||
177 | int v; /* symbol token */ |
||
178 | int r; /* associated register */ |
||
179 | int c; /* associated number */ |
||
180 | CType type; /* associated type */ |
||
181 | struct Sym *next; /* next related symbol */ |
||
182 | struct Sym *prev; /* prev symbol in stack */ |
||
183 | struct Sym *prev_tok; /* previous symbol for this token */ |
||
184 | } Sym; |
||
185 | |||
186 | /* section definition */ |
||
187 | /* XXX: use directly ELF structure for parameters ? */ |
||
188 | /* special flag to indicate that the section should not be linked to |
||
189 | the other ones */ |
||
190 | #define SHF_PRIVATE 0x80000000 |
||
191 | |||
192 | typedef struct Section { |
||
193 | unsigned long data_offset; /* current data offset */ |
||
194 | unsigned char *data; /* section data */ |
||
195 | unsigned long data_allocated; /* used for realloc() handling */ |
||
196 | int sh_name; /* elf section name (only used during output) */ |
||
197 | int sh_num; /* elf section number */ |
||
198 | int sh_type; /* elf section type */ |
||
199 | int sh_flags; /* elf section flags */ |
||
200 | int sh_info; /* elf section info */ |
||
201 | int sh_addralign; /* elf section alignment */ |
||
202 | int sh_entsize; /* elf entry size */ |
||
203 | unsigned long sh_size; /* section size (only used during output) */ |
||
204 | unsigned long sh_addr; /* address at which the section is relocated */ |
||
205 | unsigned long sh_offset; /* address at which the section is relocated */ |
||
206 | int nb_hashed_syms; /* used to resize the hash table */ |
||
207 | struct Section *link; /* link to another section */ |
||
208 | struct Section *reloc; /* corresponding section for relocation, if any */ |
||
209 | struct Section *hash; /* hash table for symbols */ |
||
210 | struct Section *next; |
||
211 | char name[1]; /* section name */ |
||
212 | } Section; |
||
213 | |||
214 | typedef struct DLLReference { |
||
215 | int level; |
||
216 | char name[1]; |
||
217 | } DLLReference; |
||
218 | |||
219 | /* GNUC attribute definition */ |
||
220 | typedef struct AttributeDef { |
||
221 | int aligned; |
||
222 | int packed; |
||
223 | Section *section; |
||
224 | unsigned char func_call; /* FUNC_CDECL, FUNC_STDCALL, FUNC_FASTCALLx */ |
||
225 | unsigned char dllexport; |
||
226 | } AttributeDef; |
||
227 | |||
228 | #define SYM_STRUCT 0x40000000 /* struct/union/enum symbol space */ |
||
229 | #define SYM_FIELD 0x20000000 /* struct/union field symbol space */ |
||
230 | #define SYM_FIRST_ANOM 0x10000000 /* first anonymous sym */ |
||
231 | |||
232 | /* stored in 'Sym.c' field */ |
||
233 | #define FUNC_NEW 1 /* ansi function prototype */ |
||
234 | #define FUNC_OLD 2 /* old function prototype */ |
||
235 | #define FUNC_ELLIPSIS 3 /* ansi function prototype with ... */ |
||
236 | |||
237 | /* stored in 'Sym.r' field */ |
||
238 | #define FUNC_CDECL 0 /* standard c call */ |
||
239 | #define FUNC_STDCALL 1 /* pascal c call */ |
||
240 | #define FUNC_FASTCALL1 2 /* first param in %eax */ |
||
241 | #define FUNC_FASTCALL2 3 /* first parameters in %eax, %edx */ |
||
242 | #define FUNC_FASTCALL3 4 /* first parameter in %eax, %edx, %ecx */ |
||
243 | |||
244 | /* field 'Sym.t' for macros */ |
||
245 | #define MACRO_OBJ 0 /* object like macro */ |
||
246 | #define MACRO_FUNC 1 /* function like macro */ |
||
247 | |||
248 | /* field 'Sym.r' for C labels */ |
||
249 | #define LABEL_DEFINED 0 /* label is defined */ |
||
250 | #define LABEL_FORWARD 1 /* label is forward defined */ |
||
251 | #define LABEL_DECLARED 2 /* label is declared but never used */ |
||
252 | |||
253 | /* type_decl() types */ |
||
254 | #define TYPE_ABSTRACT 1 /* type without variable */ |
||
255 | #define TYPE_DIRECT 2 /* type with variable */ |
||
256 | |||
257 | #define IO_BUF_SIZE 8192 |
||
258 | |||
259 | typedef struct BufferedFile { |
||
260 | uint8_t *buf_ptr; |
||
261 | uint8_t *buf_end; |
||
262 | int fd; |
||
263 | int line_num; /* current line number - here to simplify code */ |
||
264 | int ifndef_macro; /* #ifndef macro / #endif search */ |
||
265 | int ifndef_macro_saved; /* saved ifndef_macro */ |
||
266 | int *ifdef_stack_ptr; /* ifdef_stack value at the start of the file */ |
||
267 | char inc_type; /* type of include */ |
||
268 | char inc_filename[512]; /* filename specified by the user */ |
||
269 | char filename[1024]; /* current filename - here to simplify code */ |
||
270 | unsigned char buffer[IO_BUF_SIZE + 1]; /* extra size for CH_EOB char */ |
||
271 | } BufferedFile; |
||
272 | |||
273 | #define CH_EOB '\\' /* end of buffer or '\0' char in file */ |
||
274 | #define CH_EOF (-1) /* end of file */ |
||
275 | |||
276 | /* parsing state (used to save parser state to reparse part of the |
||
277 | source several times) */ |
||
278 | typedef struct ParseState { |
||
279 | int *macro_ptr; |
||
280 | int line_num; |
||
281 | int tok; |
||
282 | CValue tokc; |
||
283 | } ParseState; |
||
284 | |||
285 | /* used to record tokens */ |
||
286 | typedef struct TokenString { |
||
287 | int *str; |
||
288 | int len; |
||
289 | int allocated_len; |
||
290 | int last_line_num; |
||
291 | } TokenString; |
||
292 | |||
293 | /* include file cache, used to find files faster and also to eliminate |
||
294 | inclusion if the include file is protected by #ifndef ... #endif */ |
||
295 | typedef struct CachedInclude { |
||
296 | int ifndef_macro; |
||
297 | int hash_next; /* -1 if none */ |
||
298 | char type; /* '"' or '>' to give include type */ |
||
299 | char filename[1]; /* path specified in #include */ |
||
300 | } CachedInclude; |
||
301 | |||
302 | #define CACHED_INCLUDES_HASH_SIZE 512 |
||
303 | |||
304 | /* parser */ |
||
305 | static struct BufferedFile *file; |
||
306 | static int ch, tok; |
||
307 | static CValue tokc; |
||
308 | static CString tokcstr; /* current parsed string, if any */ |
||
309 | /* additional informations about token */ |
||
310 | static int tok_flags; |
||
311 | #define TOK_FLAG_BOL 0x0001 /* beginning of line before */ |
||
312 | #define TOK_FLAG_BOF 0x0002 /* beginning of file before */ |
||
313 | #define TOK_FLAG_ENDIF 0x0004 /* a endif was found matching starting #ifdef */ |
||
314 | |||
315 | static int *macro_ptr, *macro_ptr_allocated; |
||
316 | static int *unget_saved_macro_ptr; |
||
317 | static int unget_saved_buffer[TOK_MAX_SIZE + 1]; |
||
318 | static int unget_buffer_enabled; |
||
319 | static int parse_flags; |
||
320 | #define PARSE_FLAG_PREPROCESS 0x0001 /* activate preprocessing */ |
||
321 | #define PARSE_FLAG_TOK_NUM 0x0002 /* return numbers instead of TOK_PPNUM */ |
||
322 | #define PARSE_FLAG_LINEFEED 0x0004 /* line feed is returned as a |
||
323 | token. line feed is also |
||
324 | returned at eof */ |
||
325 | #define PARSE_FLAG_ASM_COMMENTS 0x0008 /* '#' can be used for line comment */ |
||
326 | |||
327 | static Section *text_section, *data_section, *bss_section; /* predefined sections */ |
||
328 | static Section *cur_text_section; /* current section where function code is |
||
329 | generated */ |
||
330 | #ifdef CONFIG_TCC_ASM |
||
331 | static Section *last_text_section; /* to handle .previous asm directive */ |
||
332 | #endif |
||
333 | /* bound check related sections */ |
||
334 | static Section *bounds_section; /* contains global data bound description */ |
||
335 | static Section *lbounds_section; /* contains local data bound description */ |
||
336 | /* symbol sections */ |
||
337 | static Section *symtab_section, *strtab_section; |
||
338 | |||
339 | /* debug sections */ |
||
340 | static Section *stab_section, *stabstr_section; |
||
341 | |||
342 | /* loc : local variable index |
||
343 | ind : output code index |
||
344 | rsym: return symbol |
||
345 | anon_sym: anonymous symbol index |
||
346 | */ |
||
347 | static int rsym, anon_sym, ind, loc; |
||
348 | /* expression generation modifiers */ |
||
349 | static int const_wanted; /* true if constant wanted */ |
||
350 | static int nocode_wanted; /* true if no code generation wanted for an expression */ |
||
351 | static int global_expr; /* true if compound literals must be allocated |
||
352 | globally (used during initializers parsing */ |
||
353 | static CType func_vt; /* current function return type (used by return |
||
354 | instruction) */ |
||
355 | static int func_vc; |
||
356 | static int last_line_num, last_ind, func_ind; /* debug last line number and pc */ |
||
357 | static int tok_ident; |
||
358 | static TokenSym **table_ident; |
||
359 | static TokenSym *hash_ident[TOK_HASH_SIZE]; |
||
360 | static char token_buf[STRING_MAX_SIZE + 1]; |
||
361 | static char *funcname; |
||
362 | static Sym *global_stack, *local_stack; |
||
363 | static Sym *define_stack; |
||
364 | static Sym *global_label_stack, *local_label_stack; |
||
365 | /* symbol allocator */ |
||
366 | #define SYM_POOL_NB (8192 / sizeof(Sym)) |
||
367 | static Sym *sym_free_first; |
||
368 | |||
369 | static SValue vstack[VSTACK_SIZE], *vtop; |
||
370 | /* some predefined types */ |
||
371 | static CType char_pointer_type, func_old_type, int_type; |
||
372 | /* true if isid(c) || isnum(c) */ |
||
373 | static unsigned char isidnum_table[256]; |
||
374 | |||
375 | /* compile with debug symbol (and use them if error during execution) */ |
||
376 | static int do_debug = 0; |
||
377 | |||
378 | /* compile with built-in memory and bounds checker */ |
||
379 | static int do_bounds_check = 0; |
||
380 | |||
381 | /* display benchmark infos */ |
||
382 | #if !defined(LIBTCC) |
||
383 | static int do_bench = 0; |
||
384 | #endif |
||
385 | static int total_lines; |
||
386 | static int total_bytes; |
||
387 | |||
388 | /* use GNU C extensions */ |
||
389 | static int gnu_ext = 1; |
||
390 | |||
391 | /* use Tiny C extensions */ |
||
392 | static int tcc_ext = 1; |
||
393 | |||
394 | /* max number of callers shown if error */ |
||
395 | static int num_callers = 6; |
||
396 | static const char **rt_bound_error_msg; |
||
397 | |||
398 | /* XXX: get rid of this ASAP */ |
||
399 | static struct TCCState *tcc_state; |
||
400 | |||
401 | /* give the path of the tcc libraries */ |
||
402 | static const char *tcc_lib_path = CONFIG_TCCDIR; |
||
403 | |||
404 | struct TCCState { |
||
405 | int output_type; |
||
406 | |||
407 | BufferedFile **include_stack_ptr; |
||
408 | int *ifdef_stack_ptr; |
||
409 | |||
410 | /* include file handling */ |
||
411 | char **include_paths; |
||
412 | int nb_include_paths; |
||
413 | char **sysinclude_paths; |
||
414 | int nb_sysinclude_paths; |
||
415 | CachedInclude **cached_includes; |
||
416 | int nb_cached_includes; |
||
417 | |||
418 | char **library_paths; |
||
419 | int nb_library_paths; |
||
420 | |||
421 | /* array of all loaded dlls (including those referenced by loaded |
||
422 | dlls) */ |
||
423 | DLLReference **loaded_dlls; |
||
424 | int nb_loaded_dlls; |
||
425 | |||
426 | /* sections */ |
||
427 | Section **sections; |
||
428 | int nb_sections; /* number of sections, including first dummy section */ |
||
429 | |||
430 | /* got handling */ |
||
431 | Section *got; |
||
432 | Section *plt; |
||
433 | unsigned long *got_offsets; |
||
434 | int nb_got_offsets; |
||
435 | /* give the correspondance from symtab indexes to dynsym indexes */ |
||
436 | int *symtab_to_dynsym; |
||
437 | |||
438 | /* temporary dynamic symbol sections (for dll loading) */ |
||
439 | Section *dynsymtab_section; |
||
440 | /* exported dynamic symbol section */ |
||
441 | Section *dynsym; |
||
442 | |||
443 | int nostdinc; /* if true, no standard headers are added */ |
||
444 | int nostdlib; /* if true, no standard libraries are added */ |
||
445 | |||
446 | int nocommon; /* if true, do not use common symbols for .bss data */ |
||
447 | |||
448 | /* if true, static linking is performed */ |
||
449 | int static_link; |
||
450 | |||
451 | /* if true, all symbols are exported */ |
||
452 | int rdynamic; |
||
453 | |||
454 | /* if true, only link in referenced objects from archive */ |
||
455 | int alacarte_link; |
||
456 | |||
457 | /* address of text section */ |
||
458 | unsigned long text_addr; |
||
459 | int has_text_addr; |
||
460 | |||
461 | /* output format, see TCC_OUTPUT_FORMAT_xxx */ |
||
462 | int output_format; |
||
463 | |||
464 | /* C language options */ |
||
465 | int char_is_unsigned; |
||
466 | int leading_underscore; |
||
467 | |||
468 | /* warning switches */ |
||
469 | int warn_write_strings; |
||
470 | int warn_unsupported; |
||
471 | int warn_error; |
||
472 | int warn_none; |
||
473 | int warn_implicit_function_declaration; |
||
474 | |||
475 | /* error handling */ |
||
476 | void *error_opaque; |
||
477 | void (*error_func)(void *opaque, const char *msg); |
||
478 | int error_set_jmp_enabled; |
||
479 | jmp_buf error_jmp_buf; |
||
480 | int nb_errors; |
||
481 | |||
482 | /* tiny assembler state */ |
||
483 | Sym *asm_labels; |
||
484 | |||
485 | /* see include_stack_ptr */ |
||
486 | BufferedFile *include_stack[INCLUDE_STACK_SIZE]; |
||
487 | |||
488 | /* see ifdef_stack_ptr */ |
||
489 | int ifdef_stack[IFDEF_STACK_SIZE]; |
||
490 | |||
491 | /* see cached_includes */ |
||
492 | int cached_includes_hash[CACHED_INCLUDES_HASH_SIZE]; |
||
493 | |||
494 | /* pack stack */ |
||
495 | int pack_stack[PACK_STACK_SIZE]; |
||
496 | int *pack_stack_ptr; |
||
497 | }; |
||
498 | |||
499 | /* The current value can be: */ |
||
500 | #define VT_VALMASK 0x00ff |
||
501 | #define VT_CONST 0x00f0 /* constant in vc |
||
502 | (must be first non register value) */ |
||
503 | #define VT_LLOCAL 0x00f1 /* lvalue, offset on stack */ |
||
504 | #define VT_LOCAL 0x00f2 /* offset on stack */ |
||
505 | #define VT_CMP 0x00f3 /* the value is stored in processor flags (in vc) */ |
||
506 | #define VT_JMP 0x00f4 /* value is the consequence of jmp true (even) */ |
||
507 | #define VT_JMPI 0x00f5 /* value is the consequence of jmp false (odd) */ |
||
508 | #define VT_LVAL 0x0100 /* var is an lvalue */ |
||
509 | #define VT_SYM 0x0200 /* a symbol value is added */ |
||
510 | #define VT_MUSTCAST 0x0400 /* value must be casted to be correct (used for |
||
511 | char/short stored in integer registers) */ |
||
512 | #define VT_MUSTBOUND 0x0800 /* bound checking must be done before |
||
513 | dereferencing value */ |
||
514 | #define VT_BOUNDED 0x8000 /* value is bounded. The address of the |
||
515 | bounding function call point is in vc */ |
||
516 | #define VT_LVAL_BYTE 0x1000 /* lvalue is a byte */ |
||
517 | #define VT_LVAL_SHORT 0x2000 /* lvalue is a short */ |
||
518 | #define VT_LVAL_UNSIGNED 0x4000 /* lvalue is unsigned */ |
||
519 | #define VT_LVAL_TYPE (VT_LVAL_BYTE | VT_LVAL_SHORT | VT_LVAL_UNSIGNED) |
||
520 | |||
521 | /* types */ |
||
522 | #define VT_INT 0 /* integer type */ |
||
523 | #define VT_BYTE 1 /* signed byte type */ |
||
524 | #define VT_SHORT 2 /* short type */ |
||
525 | #define VT_VOID 3 /* void type */ |
||
526 | #define VT_PTR 4 /* pointer */ |
||
527 | #define VT_ENUM 5 /* enum definition */ |
||
528 | #define VT_FUNC 6 /* function type */ |
||
529 | #define VT_STRUCT 7 /* struct/union definition */ |
||
530 | #define VT_FLOAT 8 /* IEEE float */ |
||
531 | #define VT_DOUBLE 9 /* IEEE double */ |
||
532 | #define VT_LDOUBLE 10 /* IEEE long double */ |
||
533 | #define VT_BOOL 11 /* ISOC99 boolean type */ |
||
534 | #define VT_LLONG 12 /* 64 bit integer */ |
||
535 | #define VT_LONG 13 /* long integer (NEVER USED as type, only |
||
536 | during parsing) */ |
||
537 | #define VT_BTYPE 0x000f /* mask for basic type */ |
||
538 | #define VT_UNSIGNED 0x0010 /* unsigned type */ |
||
539 | #define VT_ARRAY 0x0020 /* array type (also has VT_PTR) */ |
||
540 | #define VT_BITFIELD 0x0040 /* bitfield modifier */ |
||
541 | #define VT_CONSTANT 0x0800 /* const modifier */ |
||
542 | #define VT_VOLATILE 0x1000 /* volatile modifier */ |
||
543 | #define VT_SIGNED 0x2000 /* signed type */ |
||
544 | |||
545 | /* storage */ |
||
546 | #define VT_EXTERN 0x00000080 /* extern definition */ |
||
547 | #define VT_STATIC 0x00000100 /* static variable */ |
||
548 | #define VT_TYPEDEF 0x00000200 /* typedef definition */ |
||
549 | #define VT_INLINE 0x00000400 /* inline definition */ |
||
550 | |||
551 | #define VT_STRUCT_SHIFT 16 /* shift for bitfield shift values */ |
||
552 | |||
553 | /* type mask (except storage) */ |
||
554 | #define VT_STORAGE (VT_EXTERN | VT_STATIC | VT_TYPEDEF | VT_INLINE) |
||
555 | #define VT_TYPE (~(VT_STORAGE)) |
||
556 | |||
557 | /* token values */ |
||
558 | |||
559 | /* warning: the following compare tokens depend on i386 asm code */ |
||
560 | #define TOK_ULT 0x92 |
||
561 | #define TOK_UGE 0x93 |
||
562 | #define TOK_EQ 0x94 |
||
563 | #define TOK_NE 0x95 |
||
564 | #define TOK_ULE 0x96 |
||
565 | #define TOK_UGT 0x97 |
||
566 | #define TOK_LT 0x9c |
||
567 | #define TOK_GE 0x9d |
||
568 | #define TOK_LE 0x9e |
||
569 | #define TOK_GT 0x9f |
||
570 | |||
571 | #define TOK_LAND 0xa0 |
||
572 | #define TOK_LOR 0xa1 |
||
573 | |||
574 | #define TOK_DEC 0xa2 |
||
575 | #define TOK_MID 0xa3 /* inc/dec, to void constant */ |
||
576 | #define TOK_INC 0xa4 |
||
577 | #define TOK_UDIV 0xb0 /* unsigned division */ |
||
578 | #define TOK_UMOD 0xb1 /* unsigned modulo */ |
||
579 | #define TOK_PDIV 0xb2 /* fast division with undefined rounding for pointers */ |
||
580 | #define TOK_CINT 0xb3 /* number in tokc */ |
||
581 | #define TOK_CCHAR 0xb4 /* char constant in tokc */ |
||
582 | #define TOK_STR 0xb5 /* pointer to string in tokc */ |
||
583 | #define TOK_TWOSHARPS 0xb6 /* ## preprocessing token */ |
||
584 | #define TOK_LCHAR 0xb7 |
||
585 | #define TOK_LSTR 0xb8 |
||
586 | #define TOK_CFLOAT 0xb9 /* float constant */ |
||
587 | #define TOK_LINENUM 0xba /* line number info */ |
||
588 | #define TOK_CDOUBLE 0xc0 /* double constant */ |
||
589 | #define TOK_CLDOUBLE 0xc1 /* long double constant */ |
||
590 | #define TOK_UMULL 0xc2 /* unsigned 32x32 -> 64 mul */ |
||
591 | #define TOK_ADDC1 0xc3 /* add with carry generation */ |
||
592 | #define TOK_ADDC2 0xc4 /* add with carry use */ |
||
593 | #define TOK_SUBC1 0xc5 /* add with carry generation */ |
||
594 | #define TOK_SUBC2 0xc6 /* add with carry use */ |
||
595 | #define TOK_CUINT 0xc8 /* unsigned int constant */ |
||
596 | #define TOK_CLLONG 0xc9 /* long long constant */ |
||
597 | #define TOK_CULLONG 0xca /* unsigned long long constant */ |
||
598 | #define TOK_ARROW 0xcb |
||
599 | #define TOK_DOTS 0xcc /* three dots */ |
||
600 | #define TOK_SHR 0xcd /* unsigned shift right */ |
||
601 | #define TOK_PPNUM 0xce /* preprocessor number */ |
||
602 | |||
603 | #define TOK_SHL 0x01 /* shift left */ |
||
604 | #define TOK_SAR 0x02 /* signed shift right */ |
||
605 | |||
606 | /* assignement operators : normal operator or 0x80 */ |
||
607 | #define TOK_A_MOD 0xa5 |
||
608 | #define TOK_A_AND 0xa6 |
||
609 | #define TOK_A_MUL 0xaa |
||
610 | #define TOK_A_ADD 0xab |
||
611 | #define TOK_A_SUB 0xad |
||
612 | #define TOK_A_DIV 0xaf |
||
613 | #define TOK_A_XOR 0xde |
||
614 | #define TOK_A_OR 0xfc |
||
615 | #define TOK_A_SHL 0x81 |
||
616 | #define TOK_A_SAR 0x82 |
||
617 | |||
618 | #ifndef offsetof |
||
619 | #define offsetof(type, field) ((size_t) &((type *)0)->field) |
||
620 | #endif |
||
621 | |||
622 | #ifndef countof |
||
623 | #define countof(tab) (sizeof(tab) / sizeof((tab)[0])) |
||
624 | #endif |
||
625 | |||
626 | /* WARNING: the content of this string encodes token numbers */ |
||
627 | static char tok_two_chars[] = "<=\236>=\235!=\225&&\240||\241++\244--\242==\224<<\1>>\2+=\253-=\255*=\252/=\257%=\245&=\246^=\336|=\374->\313..\250##\266"; |
||
628 | |||
629 | #define TOK_EOF (-1) /* end of file */ |
||
630 | #define TOK_LINEFEED 10 /* line feed */ |
||
631 | |||
632 | /* all identificators and strings have token above that */ |
||
633 | #define TOK_IDENT 256 |
||
634 | |||
635 | /* only used for i386 asm opcodes definitions */ |
||
636 | #define DEF_ASM(x) DEF(TOK_ASM_ ## x, #x) |
||
637 | |||
638 | #define DEF_BWL(x) \ |
||
639 | DEF(TOK_ASM_ ## x ## b, #x "b") \ |
||
640 | DEF(TOK_ASM_ ## x ## w, #x "w") \ |
||
641 | DEF(TOK_ASM_ ## x ## l, #x "l") \ |
||
642 | DEF(TOK_ASM_ ## x, #x) |
||
643 | |||
644 | #define DEF_WL(x) \ |
||
645 | DEF(TOK_ASM_ ## x ## w, #x "w") \ |
||
646 | DEF(TOK_ASM_ ## x ## l, #x "l") \ |
||
647 | DEF(TOK_ASM_ ## x, #x) |
||
648 | |||
649 | #define DEF_FP1(x) \ |
||
650 | DEF(TOK_ASM_ ## f ## x ## s, "f" #x "s") \ |
||
651 | DEF(TOK_ASM_ ## fi ## x ## l, "fi" #x "l") \ |
||
652 | DEF(TOK_ASM_ ## f ## x ## l, "f" #x "l") \ |
||
653 | DEF(TOK_ASM_ ## fi ## x ## s, "fi" #x "s") |
||
654 | |||
655 | #define DEF_FP(x) \ |
||
656 | DEF(TOK_ASM_ ## f ## x, "f" #x ) \ |
||
657 | DEF(TOK_ASM_ ## f ## x ## p, "f" #x "p") \ |
||
658 | DEF_FP1(x) |
||
659 | |||
660 | #define DEF_ASMTEST(x) \ |
||
661 | DEF_ASM(x ## o) \ |
||
662 | DEF_ASM(x ## no) \ |
||
663 | DEF_ASM(x ## b) \ |
||
664 | DEF_ASM(x ## c) \ |
||
665 | DEF_ASM(x ## nae) \ |
||
666 | DEF_ASM(x ## nb) \ |
||
667 | DEF_ASM(x ## nc) \ |
||
668 | DEF_ASM(x ## ae) \ |
||
669 | DEF_ASM(x ## e) \ |
||
670 | DEF_ASM(x ## z) \ |
||
671 | DEF_ASM(x ## ne) \ |
||
672 | DEF_ASM(x ## nz) \ |
||
673 | DEF_ASM(x ## be) \ |
||
674 | DEF_ASM(x ## na) \ |
||
675 | DEF_ASM(x ## nbe) \ |
||
676 | DEF_ASM(x ## a) \ |
||
677 | DEF_ASM(x ## s) \ |
||
678 | DEF_ASM(x ## ns) \ |
||
679 | DEF_ASM(x ## p) \ |
||
680 | DEF_ASM(x ## pe) \ |
||
681 | DEF_ASM(x ## np) \ |
||
682 | DEF_ASM(x ## po) \ |
||
683 | DEF_ASM(x ## l) \ |
||
684 | DEF_ASM(x ## nge) \ |
||
685 | DEF_ASM(x ## nl) \ |
||
686 | DEF_ASM(x ## ge) \ |
||
687 | DEF_ASM(x ## le) \ |
||
688 | DEF_ASM(x ## ng) \ |
||
689 | DEF_ASM(x ## nle) \ |
||
690 | DEF_ASM(x ## g) |
||
691 | |||
692 | #define TOK_ASM_int TOK_INT |
||
693 | |||
694 | enum tcc_token { |
||
695 | TOK_LAST = TOK_IDENT - 1, |
||
696 | #define DEF(id, str) id, |
||
697 | #include "tcctok.h" |
||
698 | #undef DEF |
||
699 | }; |
||
700 | |||
701 | static const char tcc_keywords[] = |
||
702 | #define DEF(id, str) str "\0" |
||
703 | #include "tcctok.h" |
||
704 | #undef DEF |
||
705 | ; |
||
706 | |||
707 | #define TOK_UIDENT TOK_DEFINE |
||
708 | |||
709 | #ifdef WIN32 |
||
710 | int __stdcall GetModuleFileNameA(void *, char *, int); |
||
711 | void *__stdcall GetProcAddress(void *, const char *); |
||
712 | void *__stdcall GetModuleHandleA(const char *); |
||
713 | void *__stdcall LoadLibraryA(const char *); |
||
714 | int __stdcall FreeConsole(void); |
||
715 | |||
716 | #define snprintf _snprintf |
||
717 | #define vsnprintf _vsnprintf |
||
718 | #ifndef __GNUC__ |
||
719 | #define strtold (long double)strtod |
||
720 | #define strtof (float)strtod |
||
721 | #define strtoll (long long)strtol |
||
722 | #endif |
||
723 | #elif defined(TCC_UCLIBC) || defined(__FreeBSD__) |
||
609 | andrew_pro | 724 | |
145 | halyavin | 725 | long double strtold(const char *nptr, char **endptr) |
726 | { |
||
727 | return (long double)strtod(nptr, endptr); |
||
728 | } |
||
729 | float strtof(const char *nptr, char **endptr) |
||
730 | { |
||
731 | return (float)strtod(nptr, endptr); |
||
732 | } |
||
609 | andrew_pro | 733 | |
145 | halyavin | 734 | #else |
609 | andrew_pro | 735 | |
145 | halyavin | 736 | /* XXX: need to define this to use them in non ISOC99 context */ |
737 | extern float strtof (const char *__nptr, char **__endptr); |
||
738 | extern long double strtold (const char *__nptr, char **__endptr); |
||
609 | andrew_pro | 739 | //extern long long strtoll(const char *__nptr, char **__endptr, int __base) |
145 | halyavin | 740 | #endif |
741 | |||
609 | andrew_pro | 742 | #define strtold (long double)strtod |
743 | #define strtof (float)strtod |
||
744 | #define strtoll (long long)strtol |
||
745 | |||
746 | |||
145 | halyavin | 747 | static char *pstrcpy(char *buf, int buf_size, const char *s); |
748 | static char *pstrcat(char *buf, int buf_size, const char *s); |
||
749 | static const char *tcc_basename(const char *name); |
||
750 | |||
751 | static void next(void); |
||
752 | static void next_nomacro(void); |
||
753 | static void parse_expr_type(CType *type); |
||
754 | static void expr_type(CType *type); |
||
755 | static void unary_type(CType *type); |
||
756 | static void block(int *bsym, int *csym, int *case_sym, int *def_sym, |
||
757 | int case_reg, int is_expr); |
||
758 | static int expr_const(void); |
||
759 | static void expr_eq(void); |
||
760 | static void gexpr(void); |
||
761 | static void gen_inline_functions(void); |
||
762 | static void decl(int l); |
||
763 | static void decl_initializer(CType *type, Section *sec, unsigned long c, |
||
764 | int first, int size_only); |
||
765 | static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, |
||
766 | int has_init, int v, int scope); |
||
767 | int gv(int rc); |
||
768 | void gv2(int rc1, int rc2); |
||
769 | void move_reg(int r, int s); |
||
770 | void save_regs(int n); |
||
771 | void save_reg(int r); |
||
772 | void vpop(void); |
||
773 | void vswap(void); |
||
774 | void vdup(void); |
||
775 | int get_reg(int rc); |
||
776 | int get_reg_ex(int rc,int rc2); |
||
777 | |||
778 | struct macro_level { |
||
779 | struct macro_level *prev; |
||
780 | int *p; |
||
781 | }; |
||
782 | |||
783 | static void macro_subst(TokenString *tok_str, Sym **nested_list, |
||
784 | const int *macro_str, struct macro_level **can_read_stream); |
||
785 | void gen_op(int op); |
||
786 | void force_charshort_cast(int t); |
||
787 | static void gen_cast(CType *type); |
||
788 | void vstore(void); |
||
789 | static Sym *sym_find(int v); |
||
790 | static Sym *sym_push(int v, CType *type, int r, int c); |
||
791 | |||
792 | /* type handling */ |
||
793 | static int type_size(CType *type, int *a); |
||
794 | static inline CType *pointed_type(CType *type); |
||
795 | static int pointed_size(CType *type); |
||
796 | static int lvalue_type(int t); |
||
797 | static int parse_btype(CType *type, AttributeDef *ad); |
||
798 | static void type_decl(CType *type, AttributeDef *ad, int *v, int td); |
||
799 | static int is_compatible_types(CType *type1, CType *type2); |
||
800 | |||
801 | int ieee_finite(double d); |
||
802 | void error(const char *fmt, ...); |
||
803 | void vpushi(int v); |
||
804 | void vrott(int n); |
||
805 | void vnrott(int n); |
||
806 | void lexpand_nr(void); |
||
807 | static void vpush_global_sym(CType *type, int v); |
||
808 | void vset(CType *type, int r, int v); |
||
809 | void type_to_str(char *buf, int buf_size, |
||
810 | CType *type, const char *varstr); |
||
811 | char *get_tok_str(int v, CValue *cv); |
||
812 | static Sym *get_sym_ref(CType *type, Section *sec, |
||
813 | unsigned long offset, unsigned long size); |
||
814 | static Sym *external_global_sym(int v, CType *type, int r); |
||
815 | |||
816 | /* section generation */ |
||
817 | static void section_realloc(Section *sec, unsigned long new_size); |
||
818 | static void *section_ptr_add(Section *sec, unsigned long size); |
||
819 | static void put_extern_sym(Sym *sym, Section *section, |
||
820 | unsigned long value, unsigned long size); |
||
821 | static void greloc(Section *s, Sym *sym, unsigned long addr, int type); |
||
822 | static int put_elf_str(Section *s, const char *sym); |
||
823 | static int put_elf_sym(Section *s, |
||
824 | unsigned long value, unsigned long size, |
||
825 | int info, int other, int shndx, const char *name); |
||
826 | static int add_elf_sym(Section *s, unsigned long value, unsigned long size, |
||
827 | int info, int other, int sh_num, const char *name); |
||
828 | static void put_elf_reloc(Section *symtab, Section *s, unsigned long offset, |
||
829 | int type, int symbol); |
||
830 | static void put_stabs(const char *str, int type, int other, int desc, |
||
831 | unsigned long value); |
||
832 | static void put_stabs_r(const char *str, int type, int other, int desc, |
||
833 | unsigned long value, Section *sec, int sym_index); |
||
834 | static void put_stabn(int type, int other, int desc, int value); |
||
835 | static void put_stabd(int type, int other, int desc); |
||
836 | static int tcc_add_dll(TCCState *s, const char *filename, int flags); |
||
837 | |||
838 | #define AFF_PRINT_ERROR 0x0001 /* print error if file not found */ |
||
839 | #define AFF_REFERENCED_DLL 0x0002 /* load a referenced dll from another dll */ |
||
840 | static int tcc_add_file_internal(TCCState *s, const char *filename, int flags); |
||
841 | |||
842 | /* tcccoff.c */ |
||
843 | int tcc_output_coff(TCCState *s1, FILE *f); |
||
844 | |||
845 | /* tccpe.c */ |
||
846 | void *resolve_sym(TCCState *s1, const char *sym, int type); |
||
847 | int pe_load_def_file(struct TCCState *s1, FILE *fp); |
||
848 | void pe_setup_paths(struct TCCState *s1, int *p_output_type, const char **p_outfile, char *first_file); |
||
849 | unsigned long pe_add_runtime(struct TCCState *s1); |
||
850 | int tcc_output_pe(struct TCCState *s1, const char *filename); |
||
851 | |||
852 | /* tccasm.c */ |
||
853 | |||
854 | #ifdef CONFIG_TCC_ASM |
||
855 | |||
856 | typedef struct ExprValue { |
||
857 | uint32_t v; |
||
858 | Sym *sym; |
||
859 | } ExprValue; |
||
860 | |||
861 | #define MAX_ASM_OPERANDS 30 |
||
862 | |||
863 | typedef struct ASMOperand { |
||
864 | int id; /* GCC 3 optionnal identifier (0 if number only supported */ |
||
865 | char *constraint; |
||
866 | char asm_str[16]; /* computed asm string for operand */ |
||
867 | SValue *vt; /* C value of the expression */ |
||
868 | int ref_index; /* if >= 0, gives reference to a output constraint */ |
||
869 | int input_index; /* if >= 0, gives reference to an input constraint */ |
||
870 | int priority; /* priority, used to assign registers */ |
||
871 | int reg; /* if >= 0, register number used for this operand */ |
||
872 | int is_llong; /* true if double register value */ |
||
873 | int is_memory; /* true if memory operand */ |
||
874 | int is_rw; /* for '+' modifier */ |
||
875 | } ASMOperand; |
||
876 | |||
877 | static void asm_expr(TCCState *s1, ExprValue *pe); |
||
878 | static int asm_int_expr(TCCState *s1); |
||
879 | static int find_constraint(ASMOperand *operands, int nb_operands, |
||
880 | const char *name, const char **pp); |
||
881 | |||
882 | static int tcc_assemble(TCCState *s1, int do_preprocess); |
||
883 | |||
884 | #endif |
||
885 | |||
886 | static void asm_instr(void); |
||
887 | static void asm_global_instr(void); |
||
888 | |||
889 | /* true if float/double/long double type */ |
||
890 | static inline int is_float(int t) |
||
891 | { |
||
892 | int bt; |
||
893 | bt = t & VT_BTYPE; |
||
894 | return bt == VT_LDOUBLE || bt == VT_DOUBLE || bt == VT_FLOAT; |
||
895 | } |
||
896 | |||
897 | #ifdef TCC_TARGET_I386 |
||
898 | #include "i386-gen.c" |
||
899 | #endif |
||
900 | |||
901 | #ifdef TCC_TARGET_ARM |
||
902 | #include "arm-gen.c" |
||
903 | #endif |
||
904 | |||
905 | #ifdef TCC_TARGET_C67 |
||
906 | #include "c67-gen.c" |
||
907 | #endif |
||
908 | |||
909 | #ifdef CONFIG_TCC_STATIC |
||
910 | |||
911 | #define RTLD_LAZY 0x001 |
||
912 | #define RTLD_NOW 0x002 |
||
913 | #define RTLD_GLOBAL 0x100 |
||
914 | #define RTLD_DEFAULT NULL |
||
915 | |||
916 | /* dummy function for profiling */ |
||
917 | void *dlopen(const char *filename, int flag) |
||
918 | { |
||
919 | return NULL; |
||
920 | } |
||
921 | |||
922 | const char *dlerror(void) |
||
923 | { |
||
924 | return "error"; |
||
925 | } |
||
926 | |||
927 | typedef struct TCCSyms { |
||
928 | char *str; |
||
929 | void *ptr; |
||
930 | } TCCSyms; |
||
931 | |||
932 | #define TCCSYM(a) { #a, &a, }, |
||
933 | |||
934 | /* add the symbol you want here if no dynamic linking is done */ |
||
935 | static TCCSyms tcc_syms[] = { |
||
936 | #if !defined(CONFIG_TCCBOOT) |
||
937 | TCCSYM(printf) |
||
609 | andrew_pro | 938 | TCCSYM(printf) |
145 | halyavin | 939 | TCCSYM(fopen) |
940 | TCCSYM(fclose) |
||
941 | #endif |
||
942 | { NULL, NULL }, |
||
943 | }; |
||
944 | |||
945 | void *resolve_sym(TCCState *s1, const char *symbol, int type) |
||
946 | { |
||
947 | TCCSyms *p; |
||
948 | p = tcc_syms; |
||
949 | while (p->str != NULL) { |
||
950 | if (!strcmp(p->str, symbol)) |
||
951 | return p->ptr; |
||
952 | p++; |
||
953 | } |
||
954 | return NULL; |
||
955 | } |
||
956 | |||
957 | #elif !defined(WIN32) |
||
609 | andrew_pro | 958 | //------------------------------------------------------------------------- |
959 | //#include |
||
145 | halyavin | 960 | |
961 | void *resolve_sym(TCCState *s1, const char *sym, int type) |
||
962 | { |
||
609 | andrew_pro | 963 | return(0); |
964 | //return dlsym(RTLD_DEFAULT, sym); |
||
145 | halyavin | 965 | } |
609 | andrew_pro | 966 | //------------------------------------------------------------------------- |
145 | halyavin | 967 | #endif |
968 | |||
969 | /********************************************************/ |
||
970 | |||
971 | /* we use our own 'finite' function to avoid potential problems with |
||
972 | non standard math libs */ |
||
973 | /* XXX: endianness dependent */ |
||
974 | int ieee_finite(double d) |
||
975 | { |
||
976 | int *p = (int *)&d; |
||
977 | return ((unsigned)((p[1] | 0x800fffff) + 1)) >> 31; |
||
978 | } |
||
979 | |||
980 | /* copy a string and truncate it. */ |
||
981 | static char *pstrcpy(char *buf, int buf_size, const char *s) |
||
982 | { |
||
983 | char *q, *q_end; |
||
984 | int c; |
||
985 | |||
986 | if (buf_size > 0) { |
||
987 | q = buf; |
||
988 | q_end = buf + buf_size - 1; |
||
989 | while (q < q_end) { |
||
990 | c = *s++; |
||
991 | if (c == '\0') |
||
992 | break; |
||
993 | *q++ = c; |
||
994 | } |
||
995 | *q = '\0'; |
||
996 | } |
||
997 | return buf; |
||
998 | } |
||
999 | |||
1000 | /* strcat and truncate. */ |
||
1001 | static char *pstrcat(char *buf, int buf_size, const char *s) |
||
1002 | { |
||
1003 | int len; |
||
1004 | len = strlen(buf); |
||
1005 | if (len < buf_size) |
||
1006 | pstrcpy(buf + len, buf_size - len, s); |
||
1007 | return buf; |
||
1008 | } |
||
1009 | |||
1010 | static int strstart(const char *str, const char *val, const char **ptr) |
||
1011 | { |
||
1012 | const char *p, *q; |
||
1013 | p = str; |
||
1014 | q = val; |
||
1015 | while (*q != '\0') { |
||
1016 | if (*p != *q) |
||
1017 | return 0; |
||
1018 | p++; |
||
1019 | q++; |
||
1020 | } |
||
1021 | if (ptr) |
||
1022 | *ptr = p; |
||
1023 | return 1; |
||
1024 | } |
||
1025 | |||
1026 | /* memory management */ |
||
1027 | #ifdef MEM_DEBUG |
||
1028 | int mem_cur_size; |
||
1029 | int mem_max_size; |
||
1030 | #endif |
||
1031 | |||
1032 | static inline void tcc_free(void *ptr) |
||
1033 | { |
||
1034 | #ifdef MEM_DEBUG |
||
1035 | mem_cur_size -= malloc_usable_size(ptr); |
||
1036 | #endif |
||
1037 | free(ptr); |
||
1038 | } |
||
1039 | |||
1040 | static void *tcc_malloc(unsigned long size) |
||
1041 | { |
||
1042 | void *ptr; |
||
1043 | ptr = malloc(size); |
||
1044 | if (!ptr && size) |
||
1045 | error("memory full"); |
||
1046 | #ifdef MEM_DEBUG |
||
1047 | mem_cur_size += malloc_usable_size(ptr); |
||
1048 | if (mem_cur_size > mem_max_size) |
||
1049 | mem_max_size = mem_cur_size; |
||
1050 | #endif |
||
1051 | return ptr; |
||
1052 | } |
||
1053 | |||
1054 | static void *tcc_mallocz(unsigned long size) |
||
1055 | { |
||
1056 | void *ptr; |
||
1057 | ptr = tcc_malloc(size); |
||
1058 | memset(ptr, 0, size); |
||
1059 | return ptr; |
||
1060 | } |
||
1061 | |||
1062 | static inline void *tcc_realloc(void *ptr, unsigned long size) |
||
1063 | { |
||
1064 | void *ptr1; |
||
1065 | #ifdef MEM_DEBUG |
||
1066 | mem_cur_size -= malloc_usable_size(ptr); |
||
1067 | #endif |
||
1068 | ptr1 = realloc(ptr, size); |
||
1069 | #ifdef MEM_DEBUG |
||
1070 | /* NOTE: count not correct if alloc error, but not critical */ |
||
1071 | mem_cur_size += malloc_usable_size(ptr1); |
||
1072 | if (mem_cur_size > mem_max_size) |
||
1073 | mem_max_size = mem_cur_size; |
||
1074 | #endif |
||
1075 | return ptr1; |
||
1076 | } |
||
1077 | |||
1078 | static char *tcc_strdup(const char *str) |
||
1079 | { |
||
1080 | char *ptr; |
||
1081 | ptr = tcc_malloc(strlen(str) + 1); |
||
1082 | strcpy(ptr, str); |
||
1083 | return ptr; |
||
1084 | } |
||
1085 | |||
1086 | #define free(p) use_tcc_free(p) |
||
1087 | #define malloc(s) use_tcc_malloc(s) |
||
1088 | #define realloc(p, s) use_tcc_realloc(p, s) |
||
1089 | |||
1090 | static void dynarray_add(void ***ptab, int *nb_ptr, void *data) |
||
1091 | { |
||
1092 | int nb, nb_alloc; |
||
1093 | void **pp; |
||
1094 | |||
1095 | nb = *nb_ptr; |
||
1096 | pp = *ptab; |
||
1097 | /* every power of two we double array size */ |
||
1098 | if ((nb & (nb - 1)) == 0) { |
||
1099 | if (!nb) |
||
1100 | nb_alloc = 1; |
||
1101 | else |
||
1102 | nb_alloc = nb * 2; |
||
1103 | pp = tcc_realloc(pp, nb_alloc * sizeof(void *)); |
||
1104 | if (!pp) |
||
1105 | error("memory full"); |
||
1106 | *ptab = pp; |
||
1107 | } |
||
1108 | pp[nb++] = data; |
||
1109 | *nb_ptr = nb; |
||
1110 | } |
||
1111 | |||
1112 | /* symbol allocator */ |
||
1113 | static Sym *__sym_malloc(void) |
||
1114 | { |
||
1115 | Sym *sym_pool, *sym, *last_sym; |
||
1116 | int i; |
||
1117 | |||
1118 | sym_pool = tcc_malloc(SYM_POOL_NB * sizeof(Sym)); |
||
1119 | |||
1120 | last_sym = sym_free_first; |
||
1121 | sym = sym_pool; |
||
1122 | for(i = 0; i < SYM_POOL_NB; i++) { |
||
1123 | sym->next = last_sym; |
||
1124 | last_sym = sym; |
||
1125 | sym++; |
||
1126 | } |
||
1127 | sym_free_first = last_sym; |
||
1128 | return last_sym; |
||
1129 | } |
||
1130 | |||
1131 | static inline Sym *sym_malloc(void) |
||
1132 | { |
||
1133 | Sym *sym; |
||
1134 | sym = sym_free_first; |
||
1135 | if (!sym) |
||
1136 | sym = __sym_malloc(); |
||
1137 | sym_free_first = sym->next; |
||
1138 | return sym; |
||
1139 | } |
||
1140 | |||
1141 | static inline void sym_free(Sym *sym) |
||
1142 | { |
||
1143 | sym->next = sym_free_first; |
||
1144 | sym_free_first = sym; |
||
1145 | } |
||
1146 | |||
1147 | Section *new_section(TCCState *s1, const char *name, int sh_type, int sh_flags) |
||
1148 | { |
||
1149 | Section *sec; |
||
1150 | |||
1151 | sec = tcc_mallocz(sizeof(Section) + strlen(name)); |
||
1152 | strcpy(sec->name, name); |
||
1153 | sec->sh_type = sh_type; |
||
1154 | sec->sh_flags = sh_flags; |
||
1155 | switch(sh_type) { |
||
1156 | case SHT_HASH: |
||
1157 | case SHT_REL: |
||
1158 | case SHT_DYNSYM: |
||
1159 | case SHT_SYMTAB: |
||
1160 | case SHT_DYNAMIC: |
||
1161 | sec->sh_addralign = 4; |
||
1162 | break; |
||
1163 | case SHT_STRTAB: |
||
1164 | sec->sh_addralign = 1; |
||
1165 | break; |
||
1166 | default: |
||
1167 | sec->sh_addralign = 32; /* default conservative alignment */ |
||
1168 | break; |
||
1169 | } |
||
1170 | |||
1171 | /* only add section if not private */ |
||
1172 | if (!(sh_flags & SHF_PRIVATE)) { |
||
1173 | sec->sh_num = s1->nb_sections; |
||
1174 | dynarray_add((void ***)&s1->sections, &s1->nb_sections, sec); |
||
1175 | } |
||
1176 | return sec; |
||
1177 | } |
||
1178 | |||
1179 | static void free_section(Section *s) |
||
1180 | { |
||
1181 | tcc_free(s->data); |
||
1182 | tcc_free(s); |
||
1183 | } |
||
1184 | |||
1185 | /* realloc section and set its content to zero */ |
||
1186 | static void section_realloc(Section *sec, unsigned long new_size) |
||
1187 | { |
||
1188 | unsigned long size; |
||
1189 | unsigned char *data; |
||
1190 | |||
1191 | size = sec->data_allocated; |
||
1192 | if (size == 0) |
||
1193 | size = 1; |
||
1194 | while (size < new_size) |
||
1195 | size = size * 2; |
||
1196 | data = tcc_realloc(sec->data, size); |
||
1197 | if (!data) |
||
1198 | error("memory full"); |
||
1199 | memset(data + sec->data_allocated, 0, size - sec->data_allocated); |
||
1200 | sec->data = data; |
||
1201 | sec->data_allocated = size; |
||
1202 | } |
||
1203 | |||
1204 | /* reserve at least 'size' bytes in section 'sec' from |
||
1205 | sec->data_offset. */ |
||
1206 | static void *section_ptr_add(Section *sec, unsigned long size) |
||
1207 | { |
||
1208 | unsigned long offset, offset1; |
||
1209 | |||
1210 | offset = sec->data_offset; |
||
1211 | offset1 = offset + size; |
||
1212 | if (offset1 > sec->data_allocated) |
||
1213 | section_realloc(sec, offset1); |
||
1214 | sec->data_offset = offset1; |
||
1215 | return sec->data + offset; |
||
1216 | } |
||
1217 | |||
1218 | /* return a reference to a section, and create it if it does not |
||
1219 | exists */ |
||
1220 | Section *find_section(TCCState *s1, const char *name) |
||
1221 | { |
||
1222 | Section *sec; |
||
1223 | int i; |
||
1224 | for(i = 1; i < s1->nb_sections; i++) { |
||
1225 | sec = s1->sections[i]; |
||
1226 | if (!strcmp(name, sec->name)) |
||
1227 | return sec; |
||
1228 | } |
||
1229 | /* sections are created as PROGBITS */ |
||
1230 | return new_section(s1, name, SHT_PROGBITS, SHF_ALLOC); |
||
1231 | } |
||
1232 | |||
1233 | #define SECTION_ABS ((void *)1) |
||
1234 | |||
1235 | /* update sym->c so that it points to an external symbol in section |
||
1236 | 'section' with value 'value' */ |
||
1237 | static void put_extern_sym2(Sym *sym, Section *section, |
||
1238 | unsigned long value, unsigned long size, |
||
1239 | int can_add_underscore) |
||
1240 | { |
||
1241 | int sym_type, sym_bind, sh_num, info; |
||
1242 | Elf32_Sym *esym; |
||
1243 | const char *name; |
||
1244 | char buf1[256]; |
||
1245 | |||
1246 | if (section == NULL) |
||
1247 | sh_num = SHN_UNDEF; |
||
1248 | else if (section == SECTION_ABS) |
||
1249 | sh_num = SHN_ABS; |
||
1250 | else |
||
1251 | sh_num = section->sh_num; |
||
1252 | if (!sym->c) { |
||
1253 | if ((sym->type.t & VT_BTYPE) == VT_FUNC) |
||
1254 | sym_type = STT_FUNC; |
||
1255 | else |
||
1256 | sym_type = STT_OBJECT; |
||
1257 | if (sym->type.t & VT_STATIC) |
||
1258 | sym_bind = STB_LOCAL; |
||
1259 | else |
||
1260 | sym_bind = STB_GLOBAL; |
||
1261 | |||
1262 | name = get_tok_str(sym->v, NULL); |
||
1263 | #ifdef CONFIG_TCC_BCHECK |
||
1264 | if (do_bounds_check) { |
||
1265 | char buf[32]; |
||
1266 | |||
1267 | /* XXX: avoid doing that for statics ? */ |
||
1268 | /* if bound checking is activated, we change some function |
||
1269 | names by adding the "__bound" prefix */ |
||
1270 | switch(sym->v) { |
||
1271 | #if 0 |
||
1272 | /* XXX: we rely only on malloc hooks */ |
||
1273 | case TOK_malloc: |
||
1274 | case TOK_free: |
||
1275 | case TOK_realloc: |
||
1276 | case TOK_memalign: |
||
1277 | case TOK_calloc: |
||
1278 | #endif |
||
1279 | case TOK_memcpy: |
||
1280 | case TOK_memmove: |
||
1281 | case TOK_memset: |
||
1282 | case TOK_strlen: |
||
1283 | case TOK_strcpy: |
||
1284 | strcpy(buf, "__bound_"); |
||
1285 | strcat(buf, name); |
||
1286 | name = buf; |
||
1287 | break; |
||
1288 | } |
||
1289 | } |
||
1290 | #endif |
||
1291 | if (tcc_state->leading_underscore && can_add_underscore) { |
||
1292 | buf1[0] = '_'; |
||
1293 | pstrcpy(buf1 + 1, sizeof(buf1) - 1, name); |
||
1294 | name = buf1; |
||
1295 | } |
||
1296 | info = ELF32_ST_INFO(sym_bind, sym_type); |
||
1297 | sym->c = add_elf_sym(symtab_section, value, size, info, 0, sh_num, name); |
||
1298 | } else { |
||
1299 | esym = &((Elf32_Sym *)symtab_section->data)[sym->c]; |
||
1300 | esym->st_value = value; |
||
1301 | esym->st_size = size; |
||
1302 | esym->st_shndx = sh_num; |
||
1303 | } |
||
1304 | } |
||
1305 | |||
1306 | static void put_extern_sym(Sym *sym, Section *section, |
||
1307 | unsigned long value, unsigned long size) |
||
1308 | { |
||
1309 | put_extern_sym2(sym, section, value, size, 1); |
||
1310 | } |
||
1311 | |||
1312 | /* add a new relocation entry to symbol 'sym' in section 's' */ |
||
1313 | static void greloc(Section *s, Sym *sym, unsigned long offset, int type) |
||
1314 | { |
||
1315 | if (!sym->c) |
||
1316 | put_extern_sym(sym, NULL, 0, 0); |
||
1317 | /* now we can add ELF relocation info */ |
||
1318 | put_elf_reloc(symtab_section, s, offset, type, sym->c); |
||
1319 | } |
||
1320 | |||
1321 | static inline int isid(int c) |
||
1322 | { |
||
1323 | return (c >= 'a' && c <= 'z') || |
||
1324 | (c >= 'A' && c <= 'Z') || |
||
1325 | c == '_'; |
||
1326 | } |
||
1327 | |||
1328 | static inline int isnum(int c) |
||
1329 | { |
||
1330 | return c >= '0' && c <= '9'; |
||
1331 | } |
||
1332 | |||
1333 | static inline int isoct(int c) |
||
1334 | { |
||
1335 | return c >= '0' && c <= '7'; |
||
1336 | } |
||
1337 | |||
1338 | static inline int toup(int c) |
||
1339 | { |
||
1340 | if (c >= 'a' && c <= 'z') |
||
1341 | return c - 'a' + 'A'; |
||
1342 | else |
||
1343 | return c; |
||
1344 | } |
||
1345 | |||
1346 | static void strcat_vprintf(char *buf, int buf_size, const char *fmt, va_list ap) |
||
1347 | { |
||
1348 | int len; |
||
1349 | len = strlen(buf); |
||
1350 | vsnprintf(buf + len, buf_size - len, fmt, ap); |
||
1351 | } |
||
1352 | |||
1353 | static void strcat_printf(char *buf, int buf_size, const char *fmt, ...) |
||
1354 | { |
||
1355 | va_list ap; |
||
1356 | va_start(ap, fmt); |
||
1357 | strcat_vprintf(buf, buf_size, fmt, ap); |
||
1358 | va_end(ap); |
||
1359 | } |
||
1360 | |||
1361 | void error1(TCCState *s1, int is_warning, const char *fmt, va_list ap) |
||
1362 | { |
||
1363 | char buf[2048]; |
||
1364 | BufferedFile **f; |
||
1365 | |||
1366 | buf[0] = '\0'; |
||
1367 | if (file) { |
||
1368 | for(f = s1->include_stack; f < s1->include_stack_ptr; f++) |
||
1369 | strcat_printf(buf, sizeof(buf), "In file included from %s:%d:\n", |
||
1370 | (*f)->filename, (*f)->line_num); |
||
1371 | if (file->line_num > 0) { |
||
1372 | strcat_printf(buf, sizeof(buf), |
||
1373 | "%s:%d: ", file->filename, file->line_num); |
||
1374 | } else { |
||
1375 | strcat_printf(buf, sizeof(buf), |
||
1376 | "%s: ", file->filename); |
||
1377 | } |
||
1378 | } else { |
||
1379 | strcat_printf(buf, sizeof(buf), |
||
1380 | "tcc: "); |
||
1381 | } |
||
1382 | if (is_warning) |
||
1383 | strcat_printf(buf, sizeof(buf), "warning: "); |
||
1384 | strcat_vprintf(buf, sizeof(buf), fmt, ap); |
||
1385 | |||
1386 | if (!s1->error_func) { |
||
1387 | /* default case: stderr */ |
||
609 | andrew_pro | 1388 | printf("%s\n", buf); |
145 | halyavin | 1389 | } else { |
1390 | s1->error_func(s1->error_opaque, buf); |
||
1391 | } |
||
1392 | if (!is_warning || s1->warn_error) |
||
1393 | s1->nb_errors++; |
||
1394 | } |
||
1395 | |||
1396 | #ifdef LIBTCC |
||
1397 | void tcc_set_error_func(TCCState *s, void *error_opaque, |
||
1398 | void (*error_func)(void *opaque, const char *msg)) |
||
1399 | { |
||
1400 | s->error_opaque = error_opaque; |
||
1401 | s->error_func = error_func; |
||
1402 | } |
||
1403 | #endif |
||
1404 | |||
1405 | /* error without aborting current compilation */ |
||
1406 | void error_noabort(const char *fmt, ...) |
||
1407 | { |
||
1408 | TCCState *s1 = tcc_state; |
||
1409 | va_list ap; |
||
1410 | |||
1411 | va_start(ap, fmt); |
||
1412 | error1(s1, 0, fmt, ap); |
||
1413 | va_end(ap); |
||
1414 | } |
||
1415 | |||
1416 | void error(const char *fmt, ...) |
||
1417 | { |
||
1418 | TCCState *s1 = tcc_state; |
||
1419 | va_list ap; |
||
1420 | |||
1421 | va_start(ap, fmt); |
||
1422 | error1(s1, 0, fmt, ap); |
||
1423 | va_end(ap); |
||
1424 | /* better than nothing: in some cases, we accept to handle errors */ |
||
1425 | if (s1->error_set_jmp_enabled) { |
||
1426 | longjmp(s1->error_jmp_buf, 1); |
||
1427 | } else { |
||
1428 | /* XXX: eliminate this someday */ |
||
1429 | exit(1); |
||
1430 | } |
||
1431 | } |
||
1432 | |||
1433 | void expect(const char *msg) |
||
1434 | { |
||
1435 | error("%s expected", msg); |
||
1436 | } |
||
1437 | |||
1438 | void warning(const char *fmt, ...) |
||
1439 | { |
||
1440 | TCCState *s1 = tcc_state; |
||
1441 | va_list ap; |
||
1442 | |||
1443 | if (s1->warn_none) |
||
1444 | return; |
||
1445 | |||
1446 | va_start(ap, fmt); |
||
1447 | error1(s1, 1, fmt, ap); |
||
1448 | va_end(ap); |
||
1449 | } |
||
1450 | |||
1451 | void skip(int c) |
||
1452 | { |
||
1453 | if (tok != c) |
||
1454 | error("'%c' expected", c); |
||
1455 | next(); |
||
1456 | } |
||
1457 | |||
1458 | static void test_lvalue(void) |
||
1459 | { |
||
1460 | if (!(vtop->r & VT_LVAL)) |
||
1461 | expect("lvalue"); |
||
1462 | } |
||
1463 | |||
1464 | /* allocate a new token */ |
||
1465 | static TokenSym *tok_alloc_new(TokenSym **pts, const char *str, int len) |
||
1466 | { |
||
1467 | TokenSym *ts, **ptable; |
||
1468 | int i; |
||
1469 | |||
1470 | if (tok_ident >= SYM_FIRST_ANOM) |
||
1471 | error("memory full"); |
||
1472 | |||
1473 | /* expand token table if needed */ |
||
1474 | i = tok_ident - TOK_IDENT; |
||
1475 | if ((i % TOK_ALLOC_INCR) == 0) { |
||
1476 | ptable = tcc_realloc(table_ident, (i + TOK_ALLOC_INCR) * sizeof(TokenSym *)); |
||
1477 | if (!ptable) |
||
1478 | error("memory full"); |
||
1479 | table_ident = ptable; |
||
1480 | } |
||
1481 | |||
1482 | ts = tcc_malloc(sizeof(TokenSym) + len); |
||
1483 | table_ident[i] = ts; |
||
1484 | ts->tok = tok_ident++; |
||
1485 | ts->sym_define = NULL; |
||
1486 | ts->sym_label = NULL; |
||
1487 | ts->sym_struct = NULL; |
||
1488 | ts->sym_identifier = NULL; |
||
1489 | ts->len = len; |
||
1490 | ts->hash_next = NULL; |
||
1491 | memcpy(ts->str, str, len); |
||
1492 | ts->str[len] = '\0'; |
||
1493 | *pts = ts; |
||
1494 | return ts; |
||
1495 | } |
||
1496 | |||
1497 | #define TOK_HASH_INIT 1 |
||
1498 | #define TOK_HASH_FUNC(h, c) ((h) * 263 + (c)) |
||
1499 | |||
1500 | /* find a token and add it if not found */ |
||
1501 | static TokenSym *tok_alloc(const char *str, int len) |
||
1502 | { |
||
1503 | TokenSym *ts, **pts; |
||
1504 | int i; |
||
1505 | unsigned int h; |
||
1506 | |||
1507 | h = TOK_HASH_INIT; |
||
1508 | for(i=0;i |
||
1509 | h = TOK_HASH_FUNC(h, ((unsigned char *)str)[i]); |
||
1510 | h &= (TOK_HASH_SIZE - 1); |
||
1511 | |||
1512 | pts = &hash_ident[h]; |
||
1513 | for(;;) { |
||
1514 | ts = *pts; |
||
1515 | if (!ts) |
||
1516 | break; |
||
1517 | if (ts->len == len && !memcmp(ts->str, str, len)) |
||
1518 | return ts; |
||
1519 | pts = &(ts->hash_next); |
||
1520 | } |
||
1521 | return tok_alloc_new(pts, str, len); |
||
1522 | } |
||
1523 | |||
1524 | /* CString handling */ |
||
1525 | |||
1526 | static void cstr_realloc(CString *cstr, int new_size) |
||
1527 | { |
||
1528 | int size; |
||
1529 | void *data; |
||
1530 | |||
1531 | size = cstr->size_allocated; |
||
1532 | if (size == 0) |
||
1533 | size = 8; /* no need to allocate a too small first string */ |
||
1534 | while (size < new_size) |
||
1535 | size = size * 2; |
||
1536 | data = tcc_realloc(cstr->data_allocated, size); |
||
1537 | if (!data) |
||
1538 | error("memory full"); |
||
1539 | cstr->data_allocated = data; |
||
1540 | cstr->size_allocated = size; |
||
1541 | cstr->data = data; |
||
1542 | } |
||
1543 | |||
1544 | /* add a byte */ |
||
1545 | static inline void cstr_ccat(CString *cstr, int ch) |
||
1546 | { |
||
1547 | int size; |
||
1548 | size = cstr->size + 1; |
||
1549 | if (size > cstr->size_allocated) |
||
1550 | cstr_realloc(cstr, size); |
||
1551 | ((unsigned char *)cstr->data)[size - 1] = ch; |
||
1552 | cstr->size = size; |
||
1553 | } |
||
1554 | |||
1555 | static void cstr_cat(CString *cstr, const char *str) |
||
1556 | { |
||
1557 | int c; |
||
1558 | for(;;) { |
||
1559 | c = *str; |
||
1560 | if (c == '\0') |
||
1561 | break; |
||
1562 | cstr_ccat(cstr, c); |
||
1563 | str++; |
||
1564 | } |
||
1565 | } |
||
1566 | |||
1567 | /* add a wide char */ |
||
1568 | static void cstr_wccat(CString *cstr, int ch) |
||
1569 | { |
||
1570 | int size; |
||
1571 | size = cstr->size + sizeof(int); |
||
1572 | if (size > cstr->size_allocated) |
||
1573 | cstr_realloc(cstr, size); |
||
1574 | *(int *)(((unsigned char *)cstr->data) + size - sizeof(int)) = ch; |
||
1575 | cstr->size = size; |
||
1576 | } |
||
1577 | |||
1578 | static void cstr_new(CString *cstr) |
||
1579 | { |
||
1580 | memset(cstr, 0, sizeof(CString)); |
||
1581 | } |
||
1582 | |||
1583 | /* free string and reset it to NULL */ |
||
1584 | static void cstr_free(CString *cstr) |
||
1585 | { |
||
1586 | tcc_free(cstr->data_allocated); |
||
1587 | cstr_new(cstr); |
||
1588 | } |
||
1589 | |||
1590 | #define cstr_reset(cstr) cstr_free(cstr) |
||
1591 | |||
1592 | /* XXX: unicode ? */ |
||
1593 | static void add_char(CString *cstr, int c) |
||
1594 | { |
||
1595 | if (c == '\'' || c == '\"' || c == '\\') { |
||
1596 | /* XXX: could be more precise if char or string */ |
||
1597 | cstr_ccat(cstr, '\\'); |
||
1598 | } |
||
1599 | if (c >= 32 && c <= 126) { |
||
1600 | cstr_ccat(cstr, c); |
||
1601 | } else { |
||
1602 | cstr_ccat(cstr, '\\'); |
||
1603 | if (c == '\n') { |
||
1604 | cstr_ccat(cstr, 'n'); |
||
1605 | } else { |
||
1606 | cstr_ccat(cstr, '0' + ((c >> 6) & 7)); |
||
1607 | cstr_ccat(cstr, '0' + ((c >> 3) & 7)); |
||
1608 | cstr_ccat(cstr, '0' + (c & 7)); |
||
1609 | } |
||
1610 | } |
||
1611 | } |
||
1612 | |||
1613 | /* XXX: buffer overflow */ |
||
1614 | /* XXX: float tokens */ |
||
1615 | char *get_tok_str(int v, CValue *cv) |
||
1616 | { |
||
1617 | static char buf[STRING_MAX_SIZE + 1]; |
||
1618 | static CString cstr_buf; |
||
1619 | CString *cstr; |
||
1620 | unsigned char *q; |
||
1621 | char *p; |
||
1622 | int i, len; |
||
1623 | |||
1624 | /* NOTE: to go faster, we give a fixed buffer for small strings */ |
||
1625 | cstr_reset(&cstr_buf); |
||
1626 | cstr_buf.data = buf; |
||
1627 | cstr_buf.size_allocated = sizeof(buf); |
||
1628 | p = buf; |
||
1629 | |||
1630 | switch(v) { |
||
1631 | case TOK_CINT: |
||
1632 | case TOK_CUINT: |
||
1633 | /* XXX: not quite exact, but only useful for testing */ |
||
1634 | sprintf(p, "%u", cv->ui); |
||
1635 | break; |
||
1636 | case TOK_CLLONG: |
||
1637 | case TOK_CULLONG: |
||
1638 | /* XXX: not quite exact, but only useful for testing */ |
||
1639 | sprintf(p, "%Lu", cv->ull); |
||
1640 | break; |
||
1641 | case TOK_CCHAR: |
||
1642 | case TOK_LCHAR: |
||
1643 | cstr_ccat(&cstr_buf, '\''); |
||
1644 | add_char(&cstr_buf, cv->i); |
||
1645 | cstr_ccat(&cstr_buf, '\''); |
||
1646 | cstr_ccat(&cstr_buf, '\0'); |
||
1647 | break; |
||
1648 | case TOK_PPNUM: |
||
1649 | cstr = cv->cstr; |
||
1650 | len = cstr->size - 1; |
||
1651 | for(i=0;i |
||
1652 | add_char(&cstr_buf, ((unsigned char *)cstr->data)[i]); |
||
1653 | cstr_ccat(&cstr_buf, '\0'); |
||
1654 | break; |
||
1655 | case TOK_STR: |
||
1656 | case TOK_LSTR: |
||
1657 | cstr = cv->cstr; |
||
1658 | cstr_ccat(&cstr_buf, '\"'); |
||
1659 | if (v == TOK_STR) { |
||
1660 | len = cstr->size - 1; |
||
1661 | for(i=0;i |
||
1662 | add_char(&cstr_buf, ((unsigned char *)cstr->data)[i]); |
||
1663 | } else { |
||
1664 | len = (cstr->size / sizeof(int)) - 1; |
||
1665 | for(i=0;i |
||
1666 | add_char(&cstr_buf, ((int *)cstr->data)[i]); |
||
1667 | } |
||
1668 | cstr_ccat(&cstr_buf, '\"'); |
||
1669 | cstr_ccat(&cstr_buf, '\0'); |
||
1670 | break; |
||
1671 | case TOK_LT: |
||
1672 | v = '<'; |
||
1673 | goto addv; |
||
1674 | case TOK_GT: |
||
1675 | v = '>'; |
||
1676 | goto addv; |
||
1677 | case TOK_A_SHL: |
||
1678 | return strcpy(p, "<<="); |
||
1679 | case TOK_A_SAR: |
||
1680 | return strcpy(p, ">>="); |
||
1681 | default: |
||
1682 | if (v < TOK_IDENT) { |
||
1683 | /* search in two bytes table */ |
||
1684 | q = tok_two_chars; |
||
1685 | while (*q) { |
||
1686 | if (q[2] == v) { |
||
1687 | *p++ = q[0]; |
||
1688 | *p++ = q[1]; |
||
1689 | *p = '\0'; |
||
1690 | return buf; |
||
1691 | } |
||
1692 | q += 3; |
||
1693 | } |
||
1694 | addv: |
||
1695 | *p++ = v; |
||
1696 | *p = '\0'; |
||
1697 | } else if (v < tok_ident) { |
||
1698 | return table_ident[v - TOK_IDENT]->str; |
||
1699 | } else if (v >= SYM_FIRST_ANOM) { |
||
1700 | /* special name for anonymous symbol */ |
||
1701 | sprintf(p, "L.%u", v - SYM_FIRST_ANOM); |
||
1702 | } else { |
||
1703 | /* should never happen */ |
||
1704 | return NULL; |
||
1705 | } |
||
1706 | break; |
||
1707 | } |
||
1708 | return cstr_buf.data; |
||
1709 | } |
||
1710 | |||
1711 | /* push, without hashing */ |
||
1712 | static Sym *sym_push2(Sym **ps, int v, int t, int c) |
||
1713 | { |
||
1714 | Sym *s; |
||
1715 | s = sym_malloc(); |
||
1716 | s->v = v; |
||
1717 | s->type.t = t; |
||
1718 | s->c = c; |
||
1719 | s->next = NULL; |
||
1720 | /* add in stack */ |
||
1721 | s->prev = *ps; |
||
1722 | *ps = s; |
||
1723 | return s; |
||
1724 | } |
||
1725 | |||
1726 | /* find a symbol and return its associated structure. 's' is the top |
||
1727 | of the symbol stack */ |
||
1728 | static Sym *sym_find2(Sym *s, int v) |
||
1729 | { |
||
1730 | while (s) { |
||
1731 | if (s->v == v) |
||
1732 | return s; |
||
1733 | s = s->prev; |
||
1734 | } |
||
1735 | return NULL; |
||
1736 | } |
||
1737 | |||
1738 | /* structure lookup */ |
||
1739 | static inline Sym *struct_find(int v) |
||
1740 | { |
||
1741 | v -= TOK_IDENT; |
||
1742 | if ((unsigned)v >= (unsigned)(tok_ident - TOK_IDENT)) |
||
1743 | return NULL; |
||
1744 | return table_ident[v]->sym_struct; |
||
1745 | } |
||
1746 | |||
1747 | /* find an identifier */ |
||
1748 | static inline Sym *sym_find(int v) |
||
1749 | { |
||
1750 | v -= TOK_IDENT; |
||
1751 | if ((unsigned)v >= (unsigned)(tok_ident - TOK_IDENT)) |
||
1752 | return NULL; |
||
1753 | return table_ident[v]->sym_identifier; |
||
1754 | } |
||
1755 | |||
1756 | /* push a given symbol on the symbol stack */ |
||
1757 | static Sym *sym_push(int v, CType *type, int r, int c) |
||
1758 | { |
||
1759 | Sym *s, **ps; |
||
1760 | TokenSym *ts; |
||
1761 | |||
1762 | if (local_stack) |
||
1763 | ps = &local_stack; |
||
1764 | else |
||
1765 | ps = &global_stack; |
||
1766 | s = sym_push2(ps, v, type->t, c); |
||
1767 | s->type.ref = type->ref; |
||
1768 | s->r = r; |
||
1769 | /* don't record fields or anonymous symbols */ |
||
1770 | /* XXX: simplify */ |
||
1771 | if (!(v & SYM_FIELD) && (v & ~SYM_STRUCT) < SYM_FIRST_ANOM) { |
||
1772 | /* record symbol in token array */ |
||
1773 | ts = table_ident[(v & ~SYM_STRUCT) - TOK_IDENT]; |
||
1774 | if (v & SYM_STRUCT) |
||
1775 | ps = &ts->sym_struct; |
||
1776 | else |
||
1777 | ps = &ts->sym_identifier; |
||
1778 | s->prev_tok = *ps; |
||
1779 | *ps = s; |
||
1780 | } |
||
1781 | return s; |
||
1782 | } |
||
1783 | |||
1784 | /* push a global identifier */ |
||
1785 | static Sym *global_identifier_push(int v, int t, int c) |
||
1786 | { |
||
1787 | Sym *s, **ps; |
||
1788 | s = sym_push2(&global_stack, v, t, c); |
||
1789 | /* don't record anonymous symbol */ |
||
1790 | if (v < SYM_FIRST_ANOM) { |
||
1791 | ps = &table_ident[v - TOK_IDENT]->sym_identifier; |
||
1792 | /* modify the top most local identifier, so that |
||
1793 | sym_identifier will point to 's' when popped */ |
||
1794 | while (*ps != NULL) |
||
1795 | ps = &(*ps)->prev_tok; |
||
1796 | s->prev_tok = NULL; |
||
1797 | *ps = s; |
||
1798 | } |
||
1799 | return s; |
||
1800 | } |
||
1801 | |||
1802 | /* pop symbols until top reaches 'b' */ |
||
1803 | static void sym_pop(Sym **ptop, Sym *b) |
||
1804 | { |
||
1805 | Sym *s, *ss, **ps; |
||
1806 | TokenSym *ts; |
||
1807 | int v; |
||
1808 | |||
1809 | s = *ptop; |
||
1810 | while(s != b) { |
||
1811 | ss = s->prev; |
||
1812 | v = s->v; |
||
1813 | /* remove symbol in token array */ |
||
1814 | /* XXX: simplify */ |
||
1815 | if (!(v & SYM_FIELD) && (v & ~SYM_STRUCT) < SYM_FIRST_ANOM) { |
||
1816 | ts = table_ident[(v & ~SYM_STRUCT) - TOK_IDENT]; |
||
1817 | if (v & SYM_STRUCT) |
||
1818 | ps = &ts->sym_struct; |
||
1819 | else |
||
1820 | ps = &ts->sym_identifier; |
||
1821 | *ps = s->prev_tok; |
||
1822 | } |
||
1823 | sym_free(s); |
||
1824 | s = ss; |
||
1825 | } |
||
1826 | *ptop = b; |
||
1827 | } |
||
1828 | |||
1829 | /* I/O layer */ |
||
1830 | |||
1831 | BufferedFile *tcc_open(TCCState *s1, const char *filename) |
||
1832 | { |
||
1833 | int fd; |
||
1834 | BufferedFile *bf; |
||
1835 | |||
1836 | fd = open(filename, O_RDONLY | O_BINARY); |
||
1837 | if (fd < 0) |
||
1838 | return NULL; |
||
1839 | bf = tcc_malloc(sizeof(BufferedFile)); |
||
1840 | if (!bf) { |
||
1841 | close(fd); |
||
1842 | return NULL; |
||
1843 | } |
||
1844 | bf->fd = fd; |
||
1845 | bf->buf_ptr = bf->buffer; |
||
1846 | bf->buf_end = bf->buffer; |
||
1847 | bf->buffer[0] = CH_EOB; /* put eob symbol */ |
||
1848 | pstrcpy(bf->filename, sizeof(bf->filename), filename); |
||
1849 | bf->line_num = 1; |
||
1850 | bf->ifndef_macro = 0; |
||
1851 | bf->ifdef_stack_ptr = s1->ifdef_stack_ptr; |
||
1852 | // printf("opening '%s'\n", filename); |
||
1853 | return bf; |
||
1854 | } |
||
1855 | |||
1856 | void tcc_close(BufferedFile *bf) |
||
1857 | { |
||
1858 | total_lines += bf->line_num; |
||
1859 | close(bf->fd); |
||
1860 | tcc_free(bf); |
||
1861 | } |
||
1862 | |||
1863 | /* fill input buffer and peek next char */ |
||
1864 | static int tcc_peekc_slow(BufferedFile *bf) |
||
1865 | { |
||
1866 | int len; |
||
1867 | /* only tries to read if really end of buffer */ |
||
1868 | if (bf->buf_ptr >= bf->buf_end) { |
||
1869 | if (bf->fd != -1) { |
||
1870 | #if defined(PARSE_DEBUG) |
||
1871 | len = 8; |
||
1872 | #else |
||
1873 | len = IO_BUF_SIZE; |
||
1874 | #endif |
||
1875 | len = read(bf->fd, bf->buffer, len); |
||
1876 | if (len < 0) |
||
1877 | len = 0; |
||
1878 | } else { |
||
1879 | len = 0; |
||
1880 | } |
||
1881 | total_bytes += len; |
||
1882 | bf->buf_ptr = bf->buffer; |
||
1883 | bf->buf_end = bf->buffer + len; |
||
1884 | *bf->buf_end = CH_EOB; |
||
1885 | } |
||
1886 | if (bf->buf_ptr < bf->buf_end) { |
||
1887 | return bf->buf_ptr[0]; |
||
1888 | } else { |
||
1889 | bf->buf_ptr = bf->buf_end; |
||
1890 | return CH_EOF; |
||
1891 | } |
||
1892 | } |
||
1893 | |||
1894 | /* return the current character, handling end of block if necessary |
||
1895 | (but not stray) */ |
||
1896 | static int handle_eob(void) |
||
1897 | { |
||
1898 | return tcc_peekc_slow(file); |
||
1899 | } |
||
1900 | |||
1901 | /* read next char from current input file and handle end of input buffer */ |
||
609 | andrew_pro | 1902 | static inline void input(void) |
145 | halyavin | 1903 | { |
1904 | ch = *(++(file->buf_ptr)); |
||
1905 | /* end of buffer/file handling */ |
||
1906 | if (ch == CH_EOB) |
||
1907 | ch = handle_eob(); |
||
1908 | } |
||
1909 | |||
1910 | /* handle '\[\r]\n' */ |
||
1911 | static void handle_stray(void) |
||
1912 | { |
||
1913 | while (ch == '\\') { |
||
609 | andrew_pro | 1914 | input(); |
145 | halyavin | 1915 | if (ch == '\n') { |
1916 | file->line_num++; |
||
609 | andrew_pro | 1917 | input(); |
145 | halyavin | 1918 | } else if (ch == '\r') { |
609 | andrew_pro | 1919 | input(); |
145 | halyavin | 1920 | if (ch != '\n') |
1921 | goto fail; |
||
1922 | file->line_num++; |
||
609 | andrew_pro | 1923 | input(); |
145 | halyavin | 1924 | } else { |
1925 | fail: |
||
1926 | error("stray '\\' in program"); |
||
1927 | } |
||
1928 | } |
||
1929 | } |
||
1930 | |||
1931 | /* skip the stray and handle the \\n case. Output an error if |
||
1932 | incorrect char after the stray */ |
||
1933 | static int handle_stray1(uint8_t *p) |
||
1934 | { |
||
1935 | int c; |
||
1936 | |||
1937 | if (p >= file->buf_end) { |
||
1938 | file->buf_ptr = p; |
||
1939 | c = handle_eob(); |
||
1940 | p = file->buf_ptr; |
||
1941 | if (c == '\\') |
||
1942 | goto parse_stray; |
||
1943 | } else { |
||
1944 | parse_stray: |
||
1945 | file->buf_ptr = p; |
||
1946 | ch = *p; |
||
1947 | handle_stray(); |
||
1948 | p = file->buf_ptr; |
||
1949 | c = *p; |
||
1950 | } |
||
1951 | return c; |
||
1952 | } |
||
1953 | |||
1954 | /* handle just the EOB case, but not stray */ |
||
1955 | #define PEEKC_EOB(c, p)\ |
||
1956 | {\ |
||
1957 | p++;\ |
||
1958 | c = *p;\ |
||
1959 | if (c == '\\') {\ |
||
1960 | file->buf_ptr = p;\ |
||
1961 | c = handle_eob();\ |
||
1962 | p = file->buf_ptr;\ |
||
1963 | }\ |
||
1964 | } |
||
1965 | |||
1966 | /* handle the complicated stray case */ |
||
1967 | #define PEEKC(c, p)\ |
||
1968 | {\ |
||
1969 | p++;\ |
||
1970 | c = *p;\ |
||
1971 | if (c == '\\') {\ |
||
1972 | c = handle_stray1(p);\ |
||
1973 | p = file->buf_ptr;\ |
||
1974 | }\ |
||
1975 | } |
||
1976 | |||
1977 | /* input with '\[\r]\n' handling. Note that this function cannot |
||
1978 | handle other characters after '\', so you cannot call it inside |
||
1979 | strings or comments */ |
||
1980 | static void minp(void) |
||
1981 | { |
||
609 | andrew_pro | 1982 | input(); |
145 | halyavin | 1983 | if (ch == '\\') |
1984 | handle_stray(); |
||
1985 | } |
||
1986 | |||
1987 | |||
1988 | /* single line C++ comments */ |
||
1989 | static uint8_t *parse_line_comment(uint8_t *p) |
||
1990 | { |
||
1991 | int c; |
||
1992 | |||
1993 | p++; |
||
1994 | for(;;) { |
||
1995 | c = *p; |
||
1996 | redo: |
||
1997 | if (c == '\n' || c == CH_EOF) { |
||
1998 | break; |
||
1999 | } else if (c == '\\') { |
||
2000 | file->buf_ptr = p; |
||
2001 | c = handle_eob(); |
||
2002 | p = file->buf_ptr; |
||
2003 | if (c == '\\') { |
||
2004 | PEEKC_EOB(c, p); |
||
2005 | if (c == '\n') { |
||
2006 | file->line_num++; |
||
2007 | PEEKC_EOB(c, p); |
||
2008 | } else if (c == '\r') { |
||
2009 | PEEKC_EOB(c, p); |
||
2010 | if (c == '\n') { |
||
2011 | file->line_num++; |
||
2012 | PEEKC_EOB(c, p); |
||
2013 | } |
||
2014 | } |
||
2015 | } else { |
||
2016 | goto redo; |
||
2017 | } |
||
2018 | } else { |
||
2019 | p++; |
||
2020 | } |
||
2021 | } |
||
2022 | return p; |
||
2023 | } |
||
2024 | |||
2025 | /* C comments */ |
||
2026 | static uint8_t *parse_comment(uint8_t *p) |
||
2027 | { |
||
2028 | int c; |
||
2029 | |||
2030 | p++; |
||
2031 | for(;;) { |
||
2032 | /* fast skip loop */ |
||
2033 | for(;;) { |
||
2034 | c = *p; |
||
2035 | if (c == '\n' || c == '*' || c == '\\') |
||
2036 | break; |
||
2037 | p++; |
||
2038 | c = *p; |
||
2039 | if (c == '\n' || c == '*' || c == '\\') |
||
2040 | break; |
||
2041 | p++; |
||
2042 | } |
||
2043 | /* now we can handle all the cases */ |
||
2044 | if (c == '\n') { |
||
2045 | file->line_num++; |
||
2046 | p++; |
||
2047 | } else if (c == '*') { |
||
2048 | p++; |
||
2049 | for(;;) { |
||
2050 | c = *p; |
||
2051 | if (c == '*') { |
||
2052 | p++; |
||
2053 | } else if (c == '/') { |
||
2054 | goto end_of_comment; |
||
2055 | } else if (c == '\\') { |
||
2056 | file->buf_ptr = p; |
||
2057 | c = handle_eob(); |
||
2058 | p = file->buf_ptr; |
||
2059 | if (c == '\\') { |
||
2060 | /* skip '\[\r]\n', otherwise just skip the stray */ |
||
2061 | while (c == '\\') { |
||
2062 | PEEKC_EOB(c, p); |
||
2063 | if (c == '\n') { |
||
2064 | file->line_num++; |
||
2065 | PEEKC_EOB(c, p); |
||
2066 | } else if (c == '\r') { |
||
2067 | PEEKC_EOB(c, p); |
||
2068 | if (c == '\n') { |
||
2069 | file->line_num++; |
||
2070 | PEEKC_EOB(c, p); |
||
2071 | } |
||
2072 | } else { |
||
2073 | goto after_star; |
||
2074 | } |
||
2075 | } |
||
2076 | } |
||
2077 | } else { |
||
2078 | break; |
||
2079 | } |
||
2080 | } |
||
2081 | after_star: ; |
||
2082 | } else { |
||
2083 | /* stray, eob or eof */ |
||
2084 | file->buf_ptr = p; |
||
2085 | c = handle_eob(); |
||
2086 | p = file->buf_ptr; |
||
2087 | if (c == CH_EOF) { |
||
2088 | error("unexpected end of file in comment"); |
||
2089 | } else if (c == '\\') { |
||
2090 | p++; |
||
2091 | } |
||
2092 | } |
||
2093 | } |
||
2094 | end_of_comment: |
||
2095 | p++; |
||
2096 | return p; |
||
2097 | } |
||
2098 | |||
2099 | #define cinp minp |
||
2100 | |||
2101 | /* space excluding newline */ |
||
2102 | static inline int is_space(int ch) |
||
2103 | { |
||
2104 | return ch == ' ' || ch == '\t' || ch == '\v' || ch == '\f' || ch == '\r'; |
||
2105 | } |
||
2106 | |||
2107 | static inline void skip_spaces(void) |
||
2108 | { |
||
2109 | while (is_space(ch)) |
||
2110 | cinp(); |
||
2111 | } |
||
2112 | |||
2113 | /* parse a string without interpreting escapes */ |
||
2114 | static uint8_t *parse_pp_string(uint8_t *p, |
||
2115 | int sep, CString *str) |
||
2116 | { |
||
2117 | int c; |
||
2118 | p++; |
||
2119 | for(;;) { |
||
2120 | c = *p; |
||
2121 | if (c == sep) { |
||
2122 | break; |
||
2123 | } else if (c == '\\') { |
||
2124 | file->buf_ptr = p; |
||
2125 | c = handle_eob(); |
||
2126 | p = file->buf_ptr; |
||
2127 | if (c == CH_EOF) { |
||
2128 | unterminated_string: |
||
2129 | /* XXX: indicate line number of start of string */ |
||
2130 | error("missing terminating %c character", sep); |
||
2131 | } else if (c == '\\') { |
||
2132 | /* escape : just skip \[\r]\n */ |
||
2133 | PEEKC_EOB(c, p); |
||
2134 | if (c == '\n') { |
||
2135 | file->line_num++; |
||
2136 | p++; |
||
2137 | } else if (c == '\r') { |
||
2138 | PEEKC_EOB(c, p); |
||
2139 | if (c != '\n') |
||
2140 | expect("'\n' after '\r'"); |
||
2141 | file->line_num++; |
||
2142 | p++; |
||
2143 | } else if (c == CH_EOF) { |
||
2144 | goto unterminated_string; |
||
2145 | } else { |
||
2146 | if (str) { |
||
2147 | cstr_ccat(str, '\\'); |
||
2148 | cstr_ccat(str, c); |
||
2149 | } |
||
2150 | p++; |
||
2151 | } |
||
2152 | } |
||
2153 | } else if (c == '\n') { |
||
2154 | file->line_num++; |
||
2155 | goto add_char; |
||
2156 | } else if (c == '\r') { |
||
2157 | PEEKC_EOB(c, p); |
||
2158 | if (c != '\n') { |
||
2159 | if (str) |
||
2160 | cstr_ccat(str, '\r'); |
||
2161 | } else { |
||
2162 | file->line_num++; |
||
2163 | goto add_char; |
||
2164 | } |
||
2165 | } else { |
||
2166 | add_char: |
||
2167 | if (str) |
||
2168 | cstr_ccat(str, c); |
||
2169 | p++; |
||
2170 | } |
||
2171 | } |
||
2172 | p++; |
||
2173 | return p; |
||
2174 | } |
||
2175 | |||
2176 | /* skip block of text until #else, #elif or #endif. skip also pairs of |
||
2177 | #if/#endif */ |
||
2178 | void preprocess_skip(void) |
||
2179 | { |
||
2180 | int a, start_of_line, c; |
||
2181 | uint8_t *p; |
||
2182 | |||
2183 | p = file->buf_ptr; |
||
2184 | start_of_line = 1; |
||
2185 | a = 0; |
||
2186 | for(;;) { |
||
2187 | redo_no_start: |
||
2188 | c = *p; |
||
2189 | switch(c) { |
||
2190 | case ' ': |
||
2191 | case '\t': |
||
2192 | case '\f': |
||
2193 | case '\v': |
||
2194 | case '\r': |
||
2195 | p++; |
||
2196 | goto redo_no_start; |
||
2197 | case '\n': |
||
2198 | start_of_line = 1; |
||
2199 | file->line_num++; |
||
2200 | p++; |
||
2201 | goto redo_no_start; |
||
2202 | case '\\': |
||
2203 | file->buf_ptr = p; |
||
2204 | c = handle_eob(); |
||
2205 | if (c == CH_EOF) { |
||
2206 | expect("#endif"); |
||
2207 | } else if (c == '\\') { |
||
2208 | /* XXX: incorrect: should not give an error */ |
||
2209 | ch = file->buf_ptr[0]; |
||
2210 | handle_stray(); |
||
2211 | } |
||
2212 | p = file->buf_ptr; |
||
2213 | goto redo_no_start; |
||
2214 | /* skip strings */ |
||
2215 | case '\"': |
||
2216 | case '\'': |
||
2217 | p = parse_pp_string(p, c, NULL); |
||
2218 | break; |
||
2219 | /* skip comments */ |
||
2220 | case '/': |
||
2221 | file->buf_ptr = p; |
||
2222 | ch = *p; |
||
2223 | minp(); |
||
2224 | p = file->buf_ptr; |
||
2225 | if (ch == '*') { |
||
2226 | p = parse_comment(p); |
||
2227 | } else if (ch == '/') { |
||
2228 | p = parse_line_comment(p); |
||
2229 | } |
||
2230 | break; |
||
2231 | |||
2232 | case '#': |
||
2233 | p++; |
||
2234 | if (start_of_line) { |
||
2235 | file->buf_ptr = p; |
||
2236 | next_nomacro(); |
||
2237 | p = file->buf_ptr; |
||
2238 | if (a == 0 && |
||
2239 | (tok == TOK_ELSE || tok == TOK_ELIF || tok == TOK_ENDIF)) |
||
2240 | goto the_end; |
||
2241 | if (tok == TOK_IF || tok == TOK_IFDEF || tok == TOK_IFNDEF) |
||
2242 | a++; |
||
2243 | else if (tok == TOK_ENDIF) |
||
2244 | a--; |
||
2245 | } |
||
2246 | break; |
||
2247 | default: |
||
2248 | p++; |
||
2249 | break; |
||
2250 | } |
||
2251 | start_of_line = 0; |
||
2252 | } |
||
2253 | the_end: ; |
||
2254 | file->buf_ptr = p; |
||
2255 | } |
||
2256 | |||
2257 | /* ParseState handling */ |
||
2258 | |||
2259 | /* XXX: currently, no include file info is stored. Thus, we cannot display |
||
2260 | accurate messages if the function or data definition spans multiple |
||
2261 | files */ |
||
2262 | |||
2263 | /* save current parse state in 's' */ |
||
2264 | void save_parse_state(ParseState *s) |
||
2265 | { |
||
2266 | s->line_num = file->line_num; |
||
2267 | s->macro_ptr = macro_ptr; |
||
2268 | s->tok = tok; |
||
2269 | s->tokc = tokc; |
||
2270 | } |
||
2271 | |||
2272 | /* restore parse state from 's' */ |
||
2273 | void restore_parse_state(ParseState *s) |
||
2274 | { |
||
2275 | file->line_num = s->line_num; |
||
2276 | macro_ptr = s->macro_ptr; |
||
2277 | tok = s->tok; |
||
2278 | tokc = s->tokc; |
||
2279 | } |
||
2280 | |||
2281 | /* return the number of additional 'ints' necessary to store the |
||
2282 | token */ |
||
2283 | static inline int tok_ext_size(int t) |
||
2284 | { |
||
2285 | switch(t) { |
||
2286 | /* 4 bytes */ |
||
2287 | case TOK_CINT: |
||
2288 | case TOK_CUINT: |
||
2289 | case TOK_CCHAR: |
||
2290 | case TOK_LCHAR: |
||
2291 | case TOK_CFLOAT: |
||
2292 | case TOK_LINENUM: |
||
2293 | return 1; |
||
2294 | case TOK_STR: |
||
2295 | case TOK_LSTR: |
||
2296 | case TOK_PPNUM: |
||
2297 | error("unsupported token"); |
||
2298 | return 1; |
||
2299 | case TOK_CDOUBLE: |
||
2300 | case TOK_CLLONG: |
||
2301 | case TOK_CULLONG: |
||
2302 | return 2; |
||
2303 | case TOK_CLDOUBLE: |
||
2304 | return LDOUBLE_SIZE / 4; |
||
2305 | default: |
||
2306 | return 0; |
||
2307 | } |
||
2308 | } |
||
2309 | |||
2310 | /* token string handling */ |
||
2311 | |||
2312 | static inline void tok_str_new(TokenString *s) |
||
2313 | { |
||
2314 | s->str = NULL; |
||
2315 | s->len = 0; |
||
2316 | s->allocated_len = 0; |
||
2317 | s->last_line_num = -1; |
||
2318 | } |
||
2319 | |||
2320 | static void tok_str_free(int *str) |
||
2321 | { |
||
2322 | tcc_free(str); |
||
2323 | } |
||
2324 | |||
2325 | static int *tok_str_realloc(TokenString *s) |
||
2326 | { |
||
2327 | int *str, len; |
||
2328 | |||
2329 | if (s->allocated_len == 0) { |
||
2330 | len = 8; |
||
2331 | } else { |
||
2332 | len = s->allocated_len * 2; |
||
2333 | } |
||
2334 | str = tcc_realloc(s->str, len * sizeof(int)); |
||
2335 | if (!str) |
||
2336 | error("memory full"); |
||
2337 | s->allocated_len = len; |
||
2338 | s->str = str; |
||
2339 | return str; |
||
2340 | } |
||
2341 | |||
2342 | static void tok_str_add(TokenString *s, int t) |
||
2343 | { |
||
2344 | int len, *str; |
||
2345 | |||
2346 | len = s->len; |
||
2347 | str = s->str; |
||
2348 | if (len >= s->allocated_len) |
||
2349 | str = tok_str_realloc(s); |
||
2350 | str[len++] = t; |
||
2351 | s->len = len; |
||
2352 | } |
||
2353 | |||
2354 | static void tok_str_add2(TokenString *s, int t, CValue *cv) |
||
2355 | { |
||
2356 | int len, *str; |
||
2357 | |||
2358 | len = s->len; |
||
2359 | str = s->str; |
||
2360 | |||
2361 | /* allocate space for worst case */ |
||
2362 | if (len + TOK_MAX_SIZE > s->allocated_len) |
||
2363 | str = tok_str_realloc(s); |
||
2364 | str[len++] = t; |
||
2365 | switch(t) { |
||
2366 | case TOK_CINT: |
||
2367 | case TOK_CUINT: |
||
2368 | case TOK_CCHAR: |
||
2369 | case TOK_LCHAR: |
||
2370 | case TOK_CFLOAT: |
||
2371 | case TOK_LINENUM: |
||
2372 | str[len++] = cv->tab[0]; |
||
2373 | break; |
||
2374 | case TOK_PPNUM: |
||
2375 | case TOK_STR: |
||
2376 | case TOK_LSTR: |
||
2377 | { |
||
2378 | int nb_words; |
||
2379 | CString *cstr; |
||
2380 | |||
2381 | nb_words = (sizeof(CString) + cv->cstr->size + 3) >> 2; |
||
2382 | while ((len + nb_words) > s->allocated_len) |
||
2383 | str = tok_str_realloc(s); |
||
2384 | cstr = (CString *)(str + len); |
||
2385 | cstr->data = NULL; |
||
2386 | cstr->size = cv->cstr->size; |
||
2387 | cstr->data_allocated = NULL; |
||
2388 | cstr->size_allocated = cstr->size; |
||
2389 | memcpy((char *)cstr + sizeof(CString), |
||
2390 | cv->cstr->data, cstr->size); |
||
2391 | len += nb_words; |
||
2392 | } |
||
2393 | break; |
||
2394 | case TOK_CDOUBLE: |
||
2395 | case TOK_CLLONG: |
||
2396 | case TOK_CULLONG: |
||
2397 | #if LDOUBLE_SIZE == 8 |
||
2398 | case TOK_CLDOUBLE: |
||
2399 | #endif |
||
2400 | str[len++] = cv->tab[0]; |
||
2401 | str[len++] = cv->tab[1]; |
||
2402 | break; |
||
2403 | #if LDOUBLE_SIZE == 12 |
||
2404 | case TOK_CLDOUBLE: |
||
2405 | str[len++] = cv->tab[0]; |
||
2406 | str[len++] = cv->tab[1]; |
||
2407 | str[len++] = cv->tab[2]; |
||
2408 | #elif LDOUBLE_SIZE != 8 |
||
2409 | #error add long double size support |
||
2410 | #endif |
||
2411 | break; |
||
2412 | default: |
||
2413 | break; |
||
2414 | } |
||
2415 | s->len = len; |
||
2416 | } |
||
2417 | |||
2418 | /* add the current parse token in token string 's' */ |
||
2419 | static void tok_str_add_tok(TokenString *s) |
||
2420 | { |
||
2421 | CValue cval; |
||
2422 | |||
2423 | /* save line number info */ |
||
2424 | if (file->line_num != s->last_line_num) { |
||
2425 | s->last_line_num = file->line_num; |
||
2426 | cval.i = s->last_line_num; |
||
2427 | tok_str_add2(s, TOK_LINENUM, &cval); |
||
2428 | } |
||
2429 | tok_str_add2(s, tok, &tokc); |
||
2430 | } |
||
2431 | |||
2432 | #if LDOUBLE_SIZE == 12 |
||
2433 | #define LDOUBLE_GET(p, cv) \ |
||
2434 | cv.tab[0] = p[0]; \ |
||
2435 | cv.tab[1] = p[1]; \ |
||
2436 | cv.tab[2] = p[2]; |
||
2437 | #elif LDOUBLE_SIZE == 8 |
||
2438 | #define LDOUBLE_GET(p, cv) \ |
||
2439 | cv.tab[0] = p[0]; \ |
||
2440 | cv.tab[1] = p[1]; |
||
2441 | #else |
||
2442 | #error add long double size support |
||
2443 | #endif |
||
2444 | |||
2445 | |||
2446 | /* get a token from an integer array and increment pointer |
||
2447 | accordingly. we code it as a macro to avoid pointer aliasing. */ |
||
2448 | #define TOK_GET(t, p, cv) \ |
||
2449 | { \ |
||
2450 | t = *p++; \ |
||
2451 | switch(t) { \ |
||
2452 | case TOK_CINT: \ |
||
2453 | case TOK_CUINT: \ |
||
2454 | case TOK_CCHAR: \ |
||
2455 | case TOK_LCHAR: \ |
||
2456 | case TOK_CFLOAT: \ |
||
2457 | case TOK_LINENUM: \ |
||
2458 | cv.tab[0] = *p++; \ |
||
2459 | break; \ |
||
2460 | case TOK_STR: \ |
||
2461 | case TOK_LSTR: \ |
||
2462 | case TOK_PPNUM: \ |
||
2463 | cv.cstr = (CString *)p; \ |
||
2464 | cv.cstr->data = (char *)p + sizeof(CString);\ |
||
2465 | p += (sizeof(CString) + cv.cstr->size + 3) >> 2;\ |
||
2466 | break; \ |
||
2467 | case TOK_CDOUBLE: \ |
||
2468 | case TOK_CLLONG: \ |
||
2469 | case TOK_CULLONG: \ |
||
2470 | cv.tab[0] = p[0]; \ |
||
2471 | cv.tab[1] = p[1]; \ |
||
2472 | p += 2; \ |
||
2473 | break; \ |
||
2474 | case TOK_CLDOUBLE: \ |
||
2475 | LDOUBLE_GET(p, cv); \ |
||
2476 | p += LDOUBLE_SIZE / 4; \ |
||
2477 | break; \ |
||
2478 | default: \ |
||
2479 | break; \ |
||
2480 | } \ |
||
2481 | } |
||
2482 | |||
2483 | /* defines handling */ |
||
2484 | static inline void define_push(int v, int macro_type, int *str, Sym *first_arg) |
||
2485 | { |
||
2486 | Sym *s; |
||
2487 | |||
2488 | s = sym_push2(&define_stack, v, macro_type, (int)str); |
||
2489 | s->next = first_arg; |
||
2490 | table_ident[v - TOK_IDENT]->sym_define = s; |
||
2491 | } |
||
2492 | |||
2493 | /* undefined a define symbol. Its name is just set to zero */ |
||
2494 | static void define_undef(Sym *s) |
||
2495 | { |
||
2496 | int v; |
||
2497 | v = s->v; |
||
2498 | if (v >= TOK_IDENT && v < tok_ident) |
||
2499 | table_ident[v - TOK_IDENT]->sym_define = NULL; |
||
2500 | s->v = 0; |
||
2501 | } |
||
2502 | |||
2503 | static inline Sym *define_find(int v) |
||
2504 | { |
||
2505 | v -= TOK_IDENT; |
||
2506 | if ((unsigned)v >= (unsigned)(tok_ident - TOK_IDENT)) |
||
2507 | return NULL; |
||
2508 | return table_ident[v]->sym_define; |
||
2509 | } |
||
2510 | |||
2511 | /* free define stack until top reaches 'b' */ |
||
2512 | static void free_defines(Sym *b) |
||
2513 | { |
||
2514 | Sym *top, *top1; |
||
2515 | int v; |
||
2516 | |||
2517 | top = define_stack; |
||
2518 | while (top != b) { |
||
2519 | top1 = top->prev; |
||
2520 | /* do not free args or predefined defines */ |
||
2521 | if (top->c) |
||
2522 | tok_str_free((int *)top->c); |
||
2523 | v = top->v; |
||
2524 | if (v >= TOK_IDENT && v < tok_ident) |
||
2525 | table_ident[v - TOK_IDENT]->sym_define = NULL; |
||
2526 | sym_free(top); |
||
2527 | top = top1; |
||
2528 | } |
||
2529 | define_stack = b; |
||
2530 | } |
||
2531 | |||
2532 | /* label lookup */ |
||
2533 | static Sym *label_find(int v) |
||
2534 | { |
||
2535 | v -= TOK_IDENT; |
||
2536 | if ((unsigned)v >= (unsigned)(tok_ident - TOK_IDENT)) |
||
2537 | return NULL; |
||
2538 | return table_ident[v]->sym_label; |
||
2539 | } |
||
2540 | |||
2541 | static Sym *label_push(Sym **ptop, int v, int flags) |
||
2542 | { |
||
2543 | Sym *s, **ps; |
||
2544 | s = sym_push2(ptop, v, 0, 0); |
||
2545 | s->r = flags; |
||
2546 | ps = &table_ident[v - TOK_IDENT]->sym_label; |
||
2547 | if (ptop == &global_label_stack) { |
||
2548 | /* modify the top most local identifier, so that |
||
2549 | sym_identifier will point to 's' when popped */ |
||
2550 | while (*ps != NULL) |
||
2551 | ps = &(*ps)->prev_tok; |
||
2552 | } |
||
2553 | s->prev_tok = *ps; |
||
2554 | *ps = s; |
||
2555 | return s; |
||
2556 | } |
||
2557 | |||
2558 | /* pop labels until element last is reached. Look if any labels are |
||
2559 | undefined. Define symbols if '&&label' was used. */ |
||
2560 | static void label_pop(Sym **ptop, Sym *slast) |
||
2561 | { |
||
2562 | Sym *s, *s1; |
||
2563 | for(s = *ptop; s != slast; s = s1) { |
||
2564 | s1 = s->prev; |
||
2565 | if (s->r == LABEL_DECLARED) { |
||
2566 | warning("label '%s' declared but not used", get_tok_str(s->v, NULL)); |
||
2567 | } else if (s->r == LABEL_FORWARD) { |
||
2568 | error("label '%s' used but not defined", |
||
2569 | get_tok_str(s->v, NULL)); |
||
2570 | } else { |
||
2571 | if (s->c) { |
||
2572 | /* define corresponding symbol. A size of |
||
2573 | 1 is put. */ |
||
2574 | put_extern_sym(s, cur_text_section, (long)s->next, 1); |
||
2575 | } |
||
2576 | } |
||
2577 | /* remove label */ |
||
2578 | table_ident[s->v - TOK_IDENT]->sym_label = s->prev_tok; |
||
2579 | sym_free(s); |
||
2580 | } |
||
2581 | *ptop = slast; |
||
2582 | } |
||
2583 | |||
2584 | /* eval an expression for #if/#elif */ |
||
2585 | static int expr_preprocess(void) |
||
2586 | { |
||
2587 | int c, t; |
||
2588 | TokenString str; |
||
2589 | |||
2590 | tok_str_new(&str); |
||
2591 | while (tok != TOK_LINEFEED && tok != TOK_EOF) { |
||
2592 | next(); /* do macro subst */ |
||
2593 | if (tok == TOK_DEFINED) { |
||
2594 | next_nomacro(); |
||
2595 | t = tok; |
||
2596 | if (t == '(') |
||
2597 | next_nomacro(); |
||
2598 | c = define_find(tok) != 0; |
||
2599 | if (t == '(') |
||
2600 | next_nomacro(); |
||
2601 | tok = TOK_CINT; |
||
2602 | tokc.i = c; |
||
2603 | } else if (tok >= TOK_IDENT) { |
||
2604 | /* if undefined macro */ |
||
2605 | tok = TOK_CINT; |
||
2606 | tokc.i = 0; |
||
2607 | } |
||
2608 | tok_str_add_tok(&str); |
||
2609 | } |
||
2610 | tok_str_add(&str, -1); /* simulate end of file */ |
||
2611 | tok_str_add(&str, 0); |
||
2612 | /* now evaluate C constant expression */ |
||
2613 | macro_ptr = str.str; |
||
2614 | next(); |
||
2615 | c = expr_const(); |
||
2616 | macro_ptr = NULL; |
||
2617 | tok_str_free(str.str); |
||
2618 | return c != 0; |
||
2619 | } |
||
2620 | |||
2621 | #if defined(PARSE_DEBUG) || defined(PP_DEBUG) |
||
2622 | static void tok_print(int *str) |
||
2623 | { |
||
2624 | int t; |
||
2625 | CValue cval; |
||
2626 | |||
2627 | while (1) { |
||
2628 | TOK_GET(t, str, cval); |
||
2629 | if (!t) |
||
2630 | break; |
||
2631 | printf(" %s", get_tok_str(t, &cval)); |
||
2632 | } |
||
2633 | printf("\n"); |
||
2634 | } |
||
2635 | #endif |
||
2636 | |||
2637 | /* parse after #define */ |
||
2638 | static void parse_define(void) |
||
2639 | { |
||
2640 | Sym *s, *first, **ps; |
||
2641 | int v, t, varg, is_vaargs, c; |
||
2642 | TokenString str; |
||
2643 | |||
2644 | v = tok; |
||
2645 | if (v < TOK_IDENT) |
||
2646 | error("invalid macro name '%s'", get_tok_str(tok, &tokc)); |
||
2647 | /* XXX: should check if same macro (ANSI) */ |
||
2648 | first = NULL; |
||
2649 | t = MACRO_OBJ; |
||
2650 | /* '(' must be just after macro definition for MACRO_FUNC */ |
||
2651 | c = file->buf_ptr[0]; |
||
2652 | if (c == '\\') |
||
2653 | c = handle_stray1(file->buf_ptr); |
||
2654 | if (c == '(') { |
||
2655 | next_nomacro(); |
||
2656 | next_nomacro(); |
||
2657 | ps = &first; |
||
2658 | while (tok != ')') { |
||
2659 | varg = tok; |
||
2660 | next_nomacro(); |
||
2661 | is_vaargs = 0; |
||
2662 | if (varg == TOK_DOTS) { |
||
2663 | varg = TOK___VA_ARGS__; |
||
2664 | is_vaargs = 1; |
||
2665 | } else if (tok == TOK_DOTS && gnu_ext) { |
||
2666 | is_vaargs = 1; |
||
2667 | next_nomacro(); |
||
2668 | } |
||
2669 | if (varg < TOK_IDENT) |
||
2670 | error("badly punctuated parameter list"); |
||
2671 | s = sym_push2(&define_stack, varg | SYM_FIELD, is_vaargs, 0); |
||
2672 | *ps = s; |
||
2673 | ps = &s->next; |
||
2674 | if (tok != ',') |
||
2675 | break; |
||
2676 | next_nomacro(); |
||
2677 | } |
||
2678 | t = MACRO_FUNC; |
||
2679 | } |
||
2680 | tok_str_new(&str); |
||
2681 | next_nomacro(); |
||
2682 | /* EOF testing necessary for '-D' handling */ |
||
2683 | while (tok != TOK_LINEFEED && tok != TOK_EOF) { |
||
2684 | tok_str_add2(&str, tok, &tokc); |
||
2685 | next_nomacro(); |
||
2686 | } |
||
2687 | tok_str_add(&str, 0); |
||
2688 | #ifdef PP_DEBUG |
||
2689 | printf("define %s %d: ", get_tok_str(v, NULL), t); |
||
2690 | tok_print(str.str); |
||
2691 | #endif |
||
2692 | define_push(v, t, str.str, first); |
||
2693 | } |
||
2694 | |||
2695 | static inline int hash_cached_include(int type, const char *filename) |
||
2696 | { |
||
2697 | const unsigned char *s; |
||
2698 | unsigned int h; |
||
2699 | |||
2700 | h = TOK_HASH_INIT; |
||
2701 | h = TOK_HASH_FUNC(h, type); |
||
2702 | s = filename; |
||
2703 | while (*s) { |
||
2704 | h = TOK_HASH_FUNC(h, *s); |
||
2705 | s++; |
||
2706 | } |
||
2707 | h &= (CACHED_INCLUDES_HASH_SIZE - 1); |
||
2708 | return h; |
||
2709 | } |
||
2710 | |||
2711 | /* XXX: use a token or a hash table to accelerate matching ? */ |
||
2712 | static CachedInclude *search_cached_include(TCCState *s1, |
||
2713 | int type, const char *filename) |
||
2714 | { |
||
2715 | CachedInclude *e; |
||
2716 | int i, h; |
||
2717 | h = hash_cached_include(type, filename); |
||
2718 | i = s1->cached_includes_hash[h]; |
||
2719 | for(;;) { |
||
2720 | if (i == 0) |
||
2721 | break; |
||
2722 | e = s1->cached_includes[i - 1]; |
||
2723 | if (e->type == type && !strcmp(e->filename, filename)) |
||
2724 | return e; |
||
2725 | i = e->hash_next; |
||
2726 | } |
||
2727 | return NULL; |
||
2728 | } |
||
2729 | |||
2730 | static inline void add_cached_include(TCCState *s1, int type, |
||
2731 | const char *filename, int ifndef_macro) |
||
2732 | { |
||
2733 | CachedInclude *e; |
||
2734 | int h; |
||
2735 | |||
2736 | if (search_cached_include(s1, type, filename)) |
||
2737 | return; |
||
2738 | #ifdef INC_DEBUG |
||
2739 | printf("adding cached '%s' %s\n", filename, get_tok_str(ifndef_macro, NULL)); |
||
2740 | #endif |
||
2741 | e = tcc_malloc(sizeof(CachedInclude) + strlen(filename)); |
||
2742 | if (!e) |
||
2743 | return; |
||
2744 | e->type = type; |
||
2745 | strcpy(e->filename, filename); |
||
2746 | e->ifndef_macro = ifndef_macro; |
||
2747 | dynarray_add((void ***)&s1->cached_includes, &s1->nb_cached_includes, e); |
||
2748 | /* add in hash table */ |
||
2749 | h = hash_cached_include(type, filename); |
||
2750 | e->hash_next = s1->cached_includes_hash[h]; |
||
2751 | s1->cached_includes_hash[h] = s1->nb_cached_includes; |
||
2752 | } |
||
2753 | |||
2754 | static void pragma_parse(TCCState *s1) |
||
2755 | { |
||
2756 | int val; |
||
2757 | |||
2758 | next(); |
||
2759 | if (tok == TOK_pack) { |
||
2760 | /* |
||
2761 | This may be: |
||
2762 | #pragma pack(1) // set |
||
2763 | #pragma pack() // reset to default |
||
2764 | #pragma pack(push,1) // push & set |
||
2765 | #pragma pack(pop) // restore previous |
||
2766 | */ |
||
2767 | next(); |
||
2768 | skip('('); |
||
2769 | if (tok == TOK_ASM_pop) { |
||
2770 | next(); |
||
2771 | if (s1->pack_stack_ptr <= s1->pack_stack) { |
||
2772 | stk_error: |
||
2773 | error("out of pack stack"); |
||
2774 | } |
||
2775 | s1->pack_stack_ptr--; |
||
2776 | } else { |
||
2777 | val = 0; |
||
2778 | if (tok != ')') { |
||
2779 | if (tok == TOK_ASM_push) { |
||
2780 | next(); |
||
2781 | if (s1->pack_stack_ptr >= s1->pack_stack + PACK_STACK_SIZE - 1) |
||
2782 | goto stk_error; |
||
2783 | s1->pack_stack_ptr++; |
||
2784 | skip(','); |
||
2785 | } |
||
2786 | if (tok != TOK_CINT) { |
||
2787 | pack_error: |
||
2788 | error("invalid pack pragma"); |
||
2789 | } |
||
2790 | val = tokc.i; |
||
2791 | if (val < 1 || val > 16 || (val & (val - 1)) != 0) |
||
2792 | goto pack_error; |
||
2793 | next(); |
||
2794 | } |
||
2795 | *s1->pack_stack_ptr = val; |
||
2796 | skip(')'); |
||
2797 | } |
||
2798 | } |
||
2799 | } |
||
2800 | |||
2801 | /* is_bof is true if first non space token at beginning of file */ |
||
2802 | static void preprocess(int is_bof) |
||
2803 | { |
||
2804 | TCCState *s1 = tcc_state; |
||
2805 | int size, i, c, n, saved_parse_flags; |
||
2806 | char buf[1024], *q, *p; |
||
2807 | char buf1[1024]; |
||
2808 | BufferedFile *f; |
||
2809 | Sym *s; |
||
2810 | CachedInclude *e; |
||
2811 | |||
2812 | saved_parse_flags = parse_flags; |
||
2813 | parse_flags = PARSE_FLAG_PREPROCESS | PARSE_FLAG_TOK_NUM | |
||
2814 | PARSE_FLAG_LINEFEED; |
||
2815 | next_nomacro(); |
||
2816 | redo: |
||
2817 | switch(tok) { |
||
2818 | case TOK_DEFINE: |
||
2819 | next_nomacro(); |
||
2820 | parse_define(); |
||
2821 | break; |
||
2822 | case TOK_UNDEF: |
||
2823 | next_nomacro(); |
||
2824 | s = define_find(tok); |
||
2825 | /* undefine symbol by putting an invalid name */ |
||
2826 | if (s) |
||
2827 | define_undef(s); |
||
2828 | break; |
||
2829 | case TOK_INCLUDE: |
||
2830 | case TOK_INCLUDE_NEXT: |
||
2831 | ch = file->buf_ptr[0]; |
||
2832 | /* XXX: incorrect if comments : use next_nomacro with a special mode */ |
||
2833 | skip_spaces(); |
||
2834 | if (ch == '<') { |
||
2835 | c = '>'; |
||
2836 | goto read_name; |
||
2837 | } else if (ch == '\"') { |
||
2838 | c = ch; |
||
2839 | read_name: |
||
2840 | /* XXX: better stray handling */ |
||
2841 | minp(); |
||
2842 | q = buf; |
||
2843 | while (ch != c && ch != '\n' && ch != CH_EOF) { |
||
2844 | if ((q - buf) < sizeof(buf) - 1) |
||
2845 | *q++ = ch; |
||
2846 | minp(); |
||
2847 | } |
||
2848 | *q = '\0'; |
||
2849 | minp(); |
||
2850 | #if 0 |
||
2851 | /* eat all spaces and comments after include */ |
||
2852 | /* XXX: slightly incorrect */ |
||
2853 | while (ch1 != '\n' && ch1 != CH_EOF) |
||
609 | andrew_pro | 2854 | input(); |
145 | halyavin | 2855 | #endif |
2856 | } else { |
||
2857 | /* computed #include : either we have only strings or |
||
2858 | we have anything enclosed in '<>' */ |
||
2859 | next(); |
||
2860 | buf[0] = '\0'; |
||
2861 | if (tok == TOK_STR) { |
||
2862 | while (tok != TOK_LINEFEED) { |
||
2863 | if (tok != TOK_STR) { |
||
2864 | include_syntax: |
||
2865 | error("'#include' expects \"FILENAME\" or |
||
2866 | } |
||
2867 | pstrcat(buf, sizeof(buf), (char *)tokc.cstr->data); |
||
2868 | next(); |
||
2869 | } |
||
2870 | c = '\"'; |
||
2871 | } else { |
||
2872 | int len; |
||
2873 | while (tok != TOK_LINEFEED) { |
||
2874 | pstrcat(buf, sizeof(buf), get_tok_str(tok, &tokc)); |
||
2875 | next(); |
||
2876 | } |
||
2877 | len = strlen(buf); |
||
2878 | /* check syntax and remove '<>' */ |
||
2879 | if (len < 2 || buf[0] != '<' || buf[len - 1] != '>') |
||
2880 | goto include_syntax; |
||
2881 | memmove(buf, buf + 1, len - 2); |
||
2882 | buf[len - 2] = '\0'; |
||
2883 | c = '>'; |
||
2884 | } |
||
2885 | } |
||
2886 | |||
2887 | e = search_cached_include(s1, c, buf); |
||
2888 | if (e && define_find(e->ifndef_macro)) { |
||
2889 | /* no need to parse the include because the 'ifndef macro' |
||
2890 | is defined */ |
||
2891 | #ifdef INC_DEBUG |
||
2892 | printf("%s: skipping %s\n", file->filename, buf); |
||
2893 | #endif |
||
2894 | } else { |
||
2895 | if (c == '\"') { |
||
2896 | /* first search in current dir if "header.h" */ |
||
2897 | size = 0; |
||
2898 | p = strrchr(file->filename, '/'); |
||
2899 | if (p) |
||
2900 | size = p + 1 - file->filename; |
||
2901 | if (size > sizeof(buf1) - 1) |
||
2902 | size = sizeof(buf1) - 1; |
||
2903 | memcpy(buf1, file->filename, size); |
||
2904 | buf1[size] = '\0'; |
||
2905 | pstrcat(buf1, sizeof(buf1), buf); |
||
2906 | f = tcc_open(s1, buf1); |
||
2907 | if (f) { |
||
2908 | if (tok == TOK_INCLUDE_NEXT) |
||
2909 | tok = TOK_INCLUDE; |
||
2910 | else |
||
2911 | goto found; |
||
2912 | } |
||
2913 | } |
||
2914 | if (s1->include_stack_ptr >= s1->include_stack + INCLUDE_STACK_SIZE) |
||
2915 | error("#include recursion too deep"); |
||
2916 | /* now search in all the include paths */ |
||
2917 | n = s1->nb_include_paths + s1->nb_sysinclude_paths; |
||
2918 | for(i = 0; i < n; i++) { |
||
2919 | const char *path; |
||
2920 | if (i < s1->nb_include_paths) |
||
2921 | path = s1->include_paths[i]; |
||
2922 | else |
||
2923 | path = s1->sysinclude_paths[i - s1->nb_include_paths]; |
||
2924 | pstrcpy(buf1, sizeof(buf1), path); |
||
2925 | pstrcat(buf1, sizeof(buf1), "/"); |
||
2926 | pstrcat(buf1, sizeof(buf1), buf); |
||
2927 | f = tcc_open(s1, buf1); |
||
2928 | if (f) { |
||
2929 | if (tok == TOK_INCLUDE_NEXT) |
||
2930 | tok = TOK_INCLUDE; |
||
2931 | else |
||
2932 | goto found; |
||
2933 | } |
||
2934 | } |
||
2935 | error("include file '%s' not found", buf); |
||
2936 | f = NULL; |
||
2937 | found: |
||
2938 | #ifdef INC_DEBUG |
||
2939 | printf("%s: including %s\n", file->filename, buf1); |
||
2940 | #endif |
||
2941 | f->inc_type = c; |
||
2942 | pstrcpy(f->inc_filename, sizeof(f->inc_filename), buf); |
||
2943 | /* push current file in stack */ |
||
2944 | /* XXX: fix current line init */ |
||
2945 | *s1->include_stack_ptr++ = file; |
||
2946 | file = f; |
||
2947 | /* add include file debug info */ |
||
2948 | if (do_debug) { |
||
2949 | put_stabs(file->filename, N_BINCL, 0, 0, 0); |
||
2950 | } |
||
2951 | tok_flags |= TOK_FLAG_BOF | TOK_FLAG_BOL; |
||
2952 | ch = file->buf_ptr[0]; |
||
2953 | goto the_end; |
||
2954 | } |
||
2955 | break; |
||
2956 | case TOK_IFNDEF: |
||
2957 | c = 1; |
||
2958 | goto do_ifdef; |
||
2959 | case TOK_IF: |
||
2960 | c = expr_preprocess(); |
||
2961 | goto do_if; |
||
2962 | case TOK_IFDEF: |
||
2963 | c = 0; |
||
2964 | do_ifdef: |
||
2965 | next_nomacro(); |
||
2966 | if (tok < TOK_IDENT) |
||
2967 | error("invalid argument for '#if%sdef'", c ? "n" : ""); |
||
2968 | if (is_bof) { |
||
2969 | if (c) { |
||
2970 | #ifdef INC_DEBUG |
||
2971 | printf("#ifndef %s\n", get_tok_str(tok, NULL)); |
||
2972 | #endif |
||
2973 | file->ifndef_macro = tok; |
||
2974 | } |
||
2975 | } |
||
2976 | c = (define_find(tok) != 0) ^ c; |
||
2977 | do_if: |
||
2978 | if (s1->ifdef_stack_ptr >= s1->ifdef_stack + IFDEF_STACK_SIZE) |
||
2979 | error("memory full"); |
||
2980 | *s1->ifdef_stack_ptr++ = c; |
||
2981 | goto test_skip; |
||
2982 | case TOK_ELSE: |
||
2983 | if (s1->ifdef_stack_ptr == s1->ifdef_stack) |
||
2984 | error("#else without matching #if"); |
||
2985 | if (s1->ifdef_stack_ptr[-1] & 2) |
||
2986 | error("#else after #else"); |
||
2987 | c = (s1->ifdef_stack_ptr[-1] ^= 3); |
||
2988 | goto test_skip; |
||
2989 | case TOK_ELIF: |
||
2990 | if (s1->ifdef_stack_ptr == s1->ifdef_stack) |
||
2991 | error("#elif without matching #if"); |
||
2992 | c = s1->ifdef_stack_ptr[-1]; |
||
2993 | if (c > 1) |
||
2994 | error("#elif after #else"); |
||
2995 | /* last #if/#elif expression was true: we skip */ |
||
2996 | if (c == 1) |
||
2997 | goto skip; |
||
2998 | c = expr_preprocess(); |
||
2999 | s1->ifdef_stack_ptr[-1] = c; |
||
3000 | test_skip: |
||
3001 | if (!(c & 1)) { |
||
3002 | skip: |
||
3003 | preprocess_skip(); |
||
3004 | is_bof = 0; |
||
3005 | goto redo; |
||
3006 | } |
||
3007 | break; |
||
3008 | case TOK_ENDIF: |
||
3009 | if (s1->ifdef_stack_ptr <= file->ifdef_stack_ptr) |
||
3010 | error("#endif without matching #if"); |
||
3011 | s1->ifdef_stack_ptr--; |
||
3012 | /* '#ifndef macro' was at the start of file. Now we check if |
||
3013 | an '#endif' is exactly at the end of file */ |
||
3014 | if (file->ifndef_macro && |
||
3015 | s1->ifdef_stack_ptr == file->ifdef_stack_ptr) { |
||
3016 | file->ifndef_macro_saved = file->ifndef_macro; |
||
3017 | /* need to set to zero to avoid false matches if another |
||
3018 | #ifndef at middle of file */ |
||
3019 | file->ifndef_macro = 0; |
||
3020 | while (tok != TOK_LINEFEED) |
||
3021 | next_nomacro(); |
||
3022 | tok_flags |= TOK_FLAG_ENDIF; |
||
3023 | goto the_end; |
||
3024 | } |
||
3025 | break; |
||
3026 | case TOK_LINE: |
||
3027 | next(); |
||
3028 | if (tok != TOK_CINT) |
||
3029 | error("#line"); |
||
3030 | file->line_num = tokc.i - 1; /* the line number will be incremented after */ |
||
3031 | next(); |
||
3032 | if (tok != TOK_LINEFEED) { |
||
3033 | if (tok != TOK_STR) |
||
3034 | error("#line"); |
||
3035 | pstrcpy(file->filename, sizeof(file->filename), |
||
3036 | (char *)tokc.cstr->data); |
||
3037 | } |
||
3038 | break; |
||
3039 | case TOK_ERROR: |
||
3040 | case TOK_WARNING: |
||
3041 | c = tok; |
||
3042 | ch = file->buf_ptr[0]; |
||
3043 | skip_spaces(); |
||
3044 | q = buf; |
||
3045 | while (ch != '\n' && ch != CH_EOF) { |
||
3046 | if ((q - buf) < sizeof(buf) - 1) |
||
3047 | *q++ = ch; |
||
3048 | minp(); |
||
3049 | } |
||
3050 | *q = '\0'; |
||
3051 | if (c == TOK_ERROR) |
||
3052 | error("#error %s", buf); |
||
3053 | else |
||
3054 | warning("#warning %s", buf); |
||
3055 | break; |
||
3056 | case TOK_PRAGMA: |
||
3057 | pragma_parse(s1); |
||
3058 | break; |
||
3059 | default: |
||
3060 | if (tok == TOK_LINEFEED || tok == '!' || tok == TOK_CINT) { |
||
3061 | /* '!' is ignored to allow C scripts. numbers are ignored |
||
3062 | to emulate cpp behaviour */ |
||
3063 | } else { |
||
3064 | if (!(saved_parse_flags & PARSE_FLAG_ASM_COMMENTS)) |
||
3065 | error("invalid preprocessing directive #%s", get_tok_str(tok, &tokc)); |
||
3066 | } |
||
3067 | break; |
||
3068 | } |
||
3069 | /* ignore other preprocess commands or #! for C scripts */ |
||
3070 | while (tok != TOK_LINEFEED) |
||
3071 | next_nomacro(); |
||
3072 | the_end: |
||
3073 | parse_flags = saved_parse_flags; |
||
3074 | } |
||
3075 | |||
3076 | /* evaluate escape codes in a string. */ |
||
3077 | static void parse_escape_string(CString *outstr, const uint8_t *buf, int is_long) |
||
3078 | { |
||
3079 | int c, n; |
||
3080 | const uint8_t *p; |
||
3081 | |||
3082 | p = buf; |
||
3083 | for(;;) { |
||
3084 | c = *p; |
||
3085 | if (c == '\0') |
||
3086 | break; |
||
3087 | if (c == '\\') { |
||
3088 | p++; |
||
3089 | /* escape */ |
||
3090 | c = *p; |
||
3091 | switch(c) { |
||
3092 | case '0': case '1': case '2': case '3': |
||
3093 | case '4': case '5': case '6': case '7': |
||
3094 | /* at most three octal digits */ |
||
3095 | n = c - '0'; |
||
3096 | p++; |
||
3097 | c = *p; |
||
3098 | if (isoct(c)) { |
||
3099 | n = n * 8 + c - '0'; |
||
3100 | p++; |
||
3101 | c = *p; |
||
3102 | if (isoct(c)) { |
||
3103 | n = n * 8 + c - '0'; |
||
3104 | p++; |
||
3105 | } |
||
3106 | } |
||
3107 | c = n; |
||
3108 | goto add_char_nonext; |
||
3109 | case 'x': |
||
3110 | p++; |
||
3111 | n = 0; |
||
3112 | for(;;) { |
||
3113 | c = *p; |
||
3114 | if (c >= 'a' && c <= 'f') |
||
3115 | c = c - 'a' + 10; |
||
3116 | else if (c >= 'A' && c <= 'F') |
||
3117 | c = c - 'A' + 10; |
||
3118 | else if (isnum(c)) |
||
3119 | c = c - '0'; |
||
3120 | else |
||
3121 | break; |
||
3122 | n = n * 16 + c; |
||
3123 | p++; |
||
3124 | } |
||
3125 | c = n; |
||
3126 | goto add_char_nonext; |
||
3127 | case 'a': |
||
3128 | c = '\a'; |
||
3129 | break; |
||
3130 | case 'b': |
||
3131 | c = '\b'; |
||
3132 | break; |
||
3133 | case 'f': |
||
3134 | c = '\f'; |
||
3135 | break; |
||
3136 | case 'n': |
||
3137 | c = '\n'; |
||
3138 | break; |
||
3139 | case 'r': |
||
3140 | c = '\r'; |
||
3141 | break; |
||
3142 | case 't': |
||
3143 | c = '\t'; |
||
3144 | break; |
||
3145 | case 'v': |
||
3146 | c = '\v'; |
||
3147 | break; |
||
3148 | case 'e': |
||
3149 | if (!gnu_ext) |
||
3150 | goto invalid_escape; |
||
3151 | c = 27; |
||
3152 | break; |
||
3153 | case '\'': |
||
3154 | case '\"': |
||
3155 | case '\\': |
||
3156 | case '?': |
||
3157 | break; |
||
3158 | default: |
||
3159 | invalid_escape: |
||
3160 | if (c >= '!' && c <= '~') |
||
3161 | warning("unknown escape sequence: \'\\%c\'", c); |
||
3162 | else |
||
3163 | warning("unknown escape sequence: \'\\x%x\'", c); |
||
3164 | break; |
||
3165 | } |
||
3166 | } |
||
3167 | p++; |
||
3168 | add_char_nonext: |
||
3169 | if (!is_long) |
||
3170 | cstr_ccat(outstr, c); |
||
3171 | else |
||
3172 | cstr_wccat(outstr, c); |
||
3173 | } |
||
3174 | /* add a trailing '\0' */ |
||
3175 | if (!is_long) |
||
3176 | cstr_ccat(outstr, '\0'); |
||
3177 | else |
||
3178 | cstr_wccat(outstr, '\0'); |
||
3179 | } |
||
3180 | |||
3181 | /* we use 64 bit numbers */ |
||
3182 | #define BN_SIZE 2 |
||
3183 | |||
3184 | /* bn = (bn << shift) | or_val */ |
||
3185 | void bn_lshift(unsigned int *bn, int shift, int or_val) |
||
3186 | { |
||
3187 | int i; |
||
3188 | unsigned int v; |
||
3189 | for(i=0;i |
||
3190 | v = bn[i]; |
||
3191 | bn[i] = (v << shift) | or_val; |
||
3192 | or_val = v >> (32 - shift); |
||
3193 | } |
||
3194 | } |
||
3195 | |||
3196 | void bn_zero(unsigned int *bn) |
||
3197 | { |
||
3198 | int i; |
||
3199 | for(i=0;i |
||
3200 | bn[i] = 0; |
||
3201 | } |
||
3202 | } |
||
3203 | |||
3204 | /* parse number in null terminated string 'p' and return it in the |
||
3205 | current token */ |
||
3206 | void parse_number(const char *p) |
||
3207 | { |
||
3208 | int b, t, shift, frac_bits, s, exp_val, ch; |
||
3209 | char *q; |
||
3210 | unsigned int bn[BN_SIZE]; |
||
3211 | double d; |
||
3212 | |||
3213 | /* number */ |
||
3214 | q = token_buf; |
||
3215 | ch = *p++; |
||
3216 | t = ch; |
||
3217 | ch = *p++; |
||
3218 | *q++ = t; |
||
3219 | b = 10; |
||
3220 | if (t == '.') { |
||
3221 | goto float_frac_parse; |
||
3222 | } else if (t == '0') { |
||
3223 | if (ch == 'x' || ch == 'X') { |
||
3224 | q--; |
||
3225 | ch = *p++; |
||
3226 | b = 16; |
||
3227 | } else if (tcc_ext && (ch == 'b' || ch == 'B')) { |
||
3228 | q--; |
||
3229 | ch = *p++; |
||
3230 | b = 2; |
||
3231 | } |
||
3232 | } |
||
3233 | /* parse all digits. cannot check octal numbers at this stage |
||
3234 | because of floating point constants */ |
||
3235 | while (1) { |
||
3236 | if (ch >= 'a' && ch <= 'f') |
||
3237 | t = ch - 'a' + 10; |
||
3238 | else if (ch >= 'A' && ch <= 'F') |
||
3239 | t = ch - 'A' + 10; |
||
3240 | else if (isnum(ch)) |
||
3241 | t = ch - '0'; |
||
3242 | else |
||
3243 | break; |
||
3244 | if (t >= b) |
||
3245 | break; |
||
3246 | if (q >= token_buf + STRING_MAX_SIZE) { |
||
3247 | num_too_long: |
||
3248 | error("number too long"); |
||
3249 | } |
||
3250 | *q++ = ch; |
||
3251 | ch = *p++; |
||
3252 | } |
||
3253 | if (ch == '.' || |
||
3254 | ((ch == 'e' || ch == 'E') && b == 10) || |
||
3255 | ((ch == 'p' || ch == 'P') && (b == 16 || b == 2))) { |
||
3256 | if (b != 10) { |
||
3257 | /* NOTE: strtox should support that for hexa numbers, but |
||
3258 | non ISOC99 libcs do not support it, so we prefer to do |
||
3259 | it by hand */ |
||
3260 | /* hexadecimal or binary floats */ |
||
3261 | /* XXX: handle overflows */ |
||
3262 | *q = '\0'; |
||
3263 | if (b == 16) |
||
3264 | shift = 4; |
||
3265 | else |
||
3266 | shift = 2; |
||
3267 | bn_zero(bn); |
||
3268 | q = token_buf; |
||
3269 | while (1) { |
||
3270 | t = *q++; |
||
3271 | if (t == '\0') { |
||
3272 | break; |
||
3273 | } else if (t >= 'a') { |
||
3274 | t = t - 'a' + 10; |
||
3275 | } else if (t >= 'A') { |
||
3276 | t = t - 'A' + 10; |
||
3277 | } else { |
||
3278 | t = t - '0'; |
||
3279 | } |
||
3280 | bn_lshift(bn, shift, t); |
||
3281 | } |
||
3282 | frac_bits = 0; |
||
3283 | if (ch == '.') { |
||
3284 | ch = *p++; |
||
3285 | while (1) { |
||
3286 | t = ch; |
||
3287 | if (t >= 'a' && t <= 'f') { |
||
3288 | t = t - 'a' + 10; |
||
3289 | } else if (t >= 'A' && t <= 'F') { |
||
3290 | t = t - 'A' + 10; |
||
3291 | } else if (t >= '0' && t <= '9') { |
||
3292 | t = t - '0'; |
||
3293 | } else { |
||
3294 | break; |
||
3295 | } |
||
3296 | if (t >= b) |
||
3297 | error("invalid digit"); |
||
3298 | bn_lshift(bn, shift, t); |
||
3299 | frac_bits += shift; |
||
3300 | ch = *p++; |
||
3301 | } |
||
3302 | } |
||
3303 | if (ch != 'p' && ch != 'P') |
||
3304 | expect("exponent"); |
||
3305 | ch = *p++; |
||
3306 | s = 1; |
||
3307 | exp_val = 0; |
||
3308 | if (ch == '+') { |
||
3309 | ch = *p++; |
||
3310 | } else if (ch == '-') { |
||
3311 | s = -1; |
||
3312 | ch = *p++; |
||
3313 | } |
||
3314 | if (ch < '0' || ch > '9') |
||
3315 | expect("exponent digits"); |
||
3316 | while (ch >= '0' && ch <= '9') { |
||
3317 | exp_val = exp_val * 10 + ch - '0'; |
||
3318 | ch = *p++; |
||
3319 | } |
||
3320 | exp_val = exp_val * s; |
||
3321 | |||
3322 | /* now we can generate the number */ |
||
3323 | /* XXX: should patch directly float number */ |
||
3324 | d = (double)bn[1] * 4294967296.0 + (double)bn[0]; |
||
3325 | d = ldexp(d, exp_val - frac_bits); |
||
3326 | t = toup(ch); |
||
3327 | if (t == 'F') { |
||
3328 | ch = *p++; |
||
3329 | tok = TOK_CFLOAT; |
||
3330 | /* float : should handle overflow */ |
||
3331 | tokc.f = (float)d; |
||
3332 | } else if (t == 'L') { |
||
3333 | ch = *p++; |
||
3334 | tok = TOK_CLDOUBLE; |
||
3335 | /* XXX: not large enough */ |
||
3336 | tokc.ld = (long double)d; |
||
3337 | } else { |
||
3338 | tok = TOK_CDOUBLE; |
||
3339 | tokc.d = d; |
||
3340 | } |
||
3341 | } else { |
||
3342 | /* decimal floats */ |
||
3343 | if (ch == '.') { |
||
3344 | if (q >= token_buf + STRING_MAX_SIZE) |
||
3345 | goto num_too_long; |
||
3346 | *q++ = ch; |
||
3347 | ch = *p++; |
||
3348 | float_frac_parse: |
||
3349 | while (ch >= '0' && ch <= '9') { |
||
3350 | if (q >= token_buf + STRING_MAX_SIZE) |
||
3351 | goto num_too_long; |
||
3352 | *q++ = ch; |
||
3353 | ch = *p++; |
||
3354 | } |
||
3355 | } |
||
3356 | if (ch == 'e' || ch == 'E') { |
||
3357 | if (q >= token_buf + STRING_MAX_SIZE) |
||
3358 | goto num_too_long; |
||
3359 | *q++ = ch; |
||
3360 | ch = *p++; |
||
3361 | if (ch == '-' || ch == '+') { |
||
3362 | if (q >= token_buf + STRING_MAX_SIZE) |
||
3363 | goto num_too_long; |
||
3364 | *q++ = ch; |
||
3365 | ch = *p++; |
||
3366 | } |
||
3367 | if (ch < '0' || ch > '9') |
||
3368 | expect("exponent digits"); |
||
3369 | while (ch >= '0' && ch <= '9') { |
||
3370 | if (q >= token_buf + STRING_MAX_SIZE) |
||
3371 | goto num_too_long; |
||
3372 | *q++ = ch; |
||
3373 | ch = *p++; |
||
3374 | } |
||
3375 | } |
||
3376 | *q = '\0'; |
||
3377 | t = toup(ch); |
||
609 | andrew_pro | 3378 | //errno = 0; |
145 | halyavin | 3379 | if (t == 'F') { |
3380 | ch = *p++; |
||
3381 | tok = TOK_CFLOAT; |
||
3382 | tokc.f = strtof(token_buf, NULL); |
||
3383 | } else if (t == 'L') { |
||
3384 | ch = *p++; |
||
3385 | tok = TOK_CLDOUBLE; |
||
3386 | tokc.ld = strtold(token_buf, NULL); |
||
3387 | } else { |
||
3388 | tok = TOK_CDOUBLE; |
||
3389 | tokc.d = strtod(token_buf, NULL); |
||
3390 | } |
||
3391 | } |
||
3392 | } else { |
||
3393 | unsigned long long n, n1; |
||
3394 | int lcount, ucount; |
||
3395 | |||
3396 | /* integer number */ |
||
3397 | *q = '\0'; |
||
3398 | q = token_buf; |
||
3399 | if (b == 10 && *q == '0') { |
||
3400 | b = 8; |
||
3401 | q++; |
||
3402 | } |
||
3403 | n = 0; |
||
3404 | while(1) { |
||
3405 | t = *q++; |
||
3406 | /* no need for checks except for base 10 / 8 errors */ |
||
3407 | if (t == '\0') { |
||
3408 | break; |
||
3409 | } else if (t >= 'a') { |
||
3410 | t = t - 'a' + 10; |
||
3411 | } else if (t >= 'A') { |
||
3412 | t = t - 'A' + 10; |
||
3413 | } else { |
||
3414 | t = t - '0'; |
||
3415 | if (t >= b) |
||
3416 | error("invalid digit"); |
||
3417 | } |
||
3418 | n1 = n; |
||
3419 | n = n * b + t; |
||
3420 | /* detect overflow */ |
||
3421 | /* XXX: this test is not reliable */ |
||
3422 | if (n < n1) |
||
3423 | error("integer constant overflow"); |
||
3424 | } |
||
3425 | |||
3426 | /* XXX: not exactly ANSI compliant */ |
||
3427 | if ((n & 0xffffffff00000000LL) != 0) { |
||
3428 | if ((n >> 63) != 0) |
||
3429 | tok = TOK_CULLONG; |
||
3430 | else |
||
3431 | tok = TOK_CLLONG; |
||
3432 | } else if (n > 0x7fffffff) { |
||
3433 | tok = TOK_CUINT; |
||
3434 | } else { |
||
3435 | tok = TOK_CINT; |
||
3436 | } |
||
3437 | lcount = 0; |
||
3438 | ucount = 0; |
||
3439 | for(;;) { |
||
3440 | t = toup(ch); |
||
3441 | if (t == 'L') { |
||
3442 | if (lcount >= 2) |
||
3443 | error("three 'l's in integer constant"); |
||
3444 | lcount++; |
||
3445 | if (lcount == 2) { |
||
3446 | if (tok == TOK_CINT) |
||
3447 | tok = TOK_CLLONG; |
||
3448 | else if (tok == TOK_CUINT) |
||
3449 | tok = TOK_CULLONG; |
||
3450 | } |
||
3451 | ch = *p++; |
||
3452 | } else if (t == 'U') { |
||
3453 | if (ucount >= 1) |
||
3454 | error("two 'u's in integer constant"); |
||
3455 | ucount++; |
||
3456 | if (tok == TOK_CINT) |
||
3457 | tok = TOK_CUINT; |
||
3458 | else if (tok == TOK_CLLONG) |
||
3459 | tok = TOK_CULLONG; |
||
3460 | ch = *p++; |
||
3461 | } else { |
||
3462 | break; |
||
3463 | } |
||
3464 | } |
||
3465 | if (tok == TOK_CINT || tok == TOK_CUINT) |
||
3466 | tokc.ui = n; |
||
3467 | else |
||
3468 | tokc.ull = n; |
||
3469 | } |
||
3470 | } |
||
3471 | |||
3472 | |||
3473 | #define PARSE2(c1, tok1, c2, tok2) \ |
||
3474 | case c1: \ |
||
3475 | PEEKC(c, p); \ |
||
3476 | if (c == c2) { \ |
||
3477 | p++; \ |
||
3478 | tok = tok2; \ |
||
3479 | } else { \ |
||
3480 | tok = tok1; \ |
||
3481 | } \ |
||
3482 | break; |
||
3483 | |||
3484 | /* return next token without macro substitution */ |
||
3485 | static inline void next_nomacro1(void) |
||
3486 | { |
||
3487 | int t, c, is_long; |
||
3488 | TokenSym *ts; |
||
3489 | uint8_t *p, *p1; |
||
3490 | unsigned int h; |
||
3491 | |||
3492 | p = file->buf_ptr; |
||
3493 | redo_no_start: |
||
3494 | c = *p; |
||
3495 | switch(c) { |
||
3496 | case ' ': |
||
3497 | case '\t': |
||
3498 | case '\f': |
||
3499 | case '\v': |
||
3500 | case '\r': |
||
3501 | p++; |
||
3502 | goto redo_no_start; |
||
3503 | |||
3504 | case '\\': |
||
3505 | /* first look if it is in fact an end of buffer */ |
||
3506 | if (p >= file->buf_end) { |
||
3507 | file->buf_ptr = p; |
||
3508 | handle_eob(); |
||
3509 | p = file->buf_ptr; |
||
3510 | if (p >= file->buf_end) |
||
3511 | goto parse_eof; |
||
3512 | else |
||
3513 | goto redo_no_start; |
||
3514 | } else { |
||
3515 | file->buf_ptr = p; |
||
3516 | ch = *p; |
||
3517 | handle_stray(); |
||
3518 | p = file->buf_ptr; |
||
3519 | goto redo_no_start; |
||
3520 | } |
||
3521 | parse_eof: |
||
3522 | { |
||
3523 | TCCState *s1 = tcc_state; |
||
3524 | if (parse_flags & PARSE_FLAG_LINEFEED) { |
||
3525 | tok = TOK_LINEFEED; |
||
3526 | } else if (s1->include_stack_ptr == s1->include_stack || |
||
3527 | !(parse_flags & PARSE_FLAG_PREPROCESS)) { |
||
3528 | /* no include left : end of file. */ |
||
3529 | tok = TOK_EOF; |
||
3530 | } else { |
||
3531 | /* pop include file */ |
||
3532 | |||
3533 | /* test if previous '#endif' was after a #ifdef at |
||
3534 | start of file */ |
||
3535 | if (tok_flags & TOK_FLAG_ENDIF) { |
||
3536 | #ifdef INC_DEBUG |
||
3537 | printf("#endif %s\n", get_tok_str(file->ifndef_macro_saved, NULL)); |
||
3538 | #endif |
||
3539 | add_cached_include(s1, file->inc_type, file->inc_filename, |
||
3540 | file->ifndef_macro_saved); |
||
3541 | } |
||
3542 | |||
3543 | /* add end of include file debug info */ |
||
3544 | if (do_debug) { |
||
3545 | put_stabd(N_EINCL, 0, 0); |
||
3546 | } |
||
3547 | /* pop include stack */ |
||
3548 | tcc_close(file); |
||
3549 | s1->include_stack_ptr--; |
||
3550 | file = *s1->include_stack_ptr; |
||
3551 | p = file->buf_ptr; |
||
3552 | goto redo_no_start; |
||
3553 | } |
||
3554 | } |
||
3555 | break; |
||
3556 | |||
3557 | case '\n': |
||
3558 | if (parse_flags & PARSE_FLAG_LINEFEED) { |
||
3559 | tok = TOK_LINEFEED; |
||
3560 | } else { |
||
3561 | file->line_num++; |
||
3562 | tok_flags |= TOK_FLAG_BOL; |
||
3563 | p++; |
||
3564 | goto redo_no_start; |
||
3565 | } |
||
3566 | break; |
||
3567 | |||
3568 | case '#': |
||
3569 | /* XXX: simplify */ |
||
3570 | PEEKC(c, p); |
||
3571 | if ((tok_flags & TOK_FLAG_BOL) && |
||
3572 | (parse_flags & PARSE_FLAG_PREPROCESS)) { |
||
3573 | file->buf_ptr = p; |
||
3574 | preprocess(tok_flags & TOK_FLAG_BOF); |
||
3575 | p = file->buf_ptr; |
||
3576 | goto redo_no_start; |
||
3577 | } else { |
||
3578 | if (c == '#') { |
||
3579 | p++; |
||
3580 | tok = TOK_TWOSHARPS; |
||
3581 | } else { |
||
3582 | if (parse_flags & PARSE_FLAG_ASM_COMMENTS) { |
||
3583 | p = parse_line_comment(p - 1); |
||
3584 | goto redo_no_start; |
||
3585 | } else { |
||
3586 | tok = '#'; |
||
3587 | } |
||
3588 | } |
||
3589 | } |
||
3590 | break; |
||
3591 | |||
3592 | case 'a': case 'b': case 'c': case 'd': |
||
3593 | case 'e': case 'f': case 'g': case 'h': |
||
3594 | case 'i': case 'j': case 'k': case 'l': |
||
3595 | case 'm': case 'n': case 'o': case 'p': |
||
3596 | case 'q': case 'r': case 's': case 't': |
||
3597 | case 'u': case 'v': case 'w': case 'x': |
||
3598 | case 'y': case 'z': |
||
3599 | case 'A': case 'B': case 'C': case 'D': |
||
3600 | case 'E': case 'F': case 'G': case 'H': |
||
3601 | case 'I': case 'J': case 'K': |
||
3602 | case 'M': case 'N': case 'O': case 'P': |
||
3603 | case 'Q': case 'R': case 'S': case 'T': |
||
3604 | case 'U': case 'V': case 'W': case 'X': |
||
3605 | case 'Y': case 'Z': |
||
3606 | case '_': |
||
3607 | parse_ident_fast: |
||
3608 | p1 = p; |
||
3609 | h = TOK_HASH_INIT; |
||
3610 | h = TOK_HASH_FUNC(h, c); |
||
3611 | p++; |
||
3612 | for(;;) { |
||
3613 | c = *p; |
||
3614 | if (!isidnum_table[c]) |
||
3615 | break; |
||
3616 | h = TOK_HASH_FUNC(h, c); |
||
3617 | p++; |
||
3618 | } |
||
3619 | if (c != '\\') { |
||
3620 | TokenSym **pts; |
||
3621 | int len; |
||
3622 | |||
3623 | /* fast case : no stray found, so we have the full token |
||
3624 | and we have already hashed it */ |
||
3625 | len = p - p1; |
||
3626 | h &= (TOK_HASH_SIZE - 1); |
||
3627 | pts = &hash_ident[h]; |
||
3628 | for(;;) { |
||
3629 | ts = *pts; |
||
3630 | if (!ts) |
||
3631 | break; |
||
3632 | if (ts->len == len && !memcmp(ts->str, p1, len)) |
||
3633 | goto token_found; |
||
3634 | pts = &(ts->hash_next); |
||
3635 | } |
||
3636 | ts = tok_alloc_new(pts, p1, len); |
||
3637 | token_found: ; |
||
3638 | } else { |
||
3639 | /* slower case */ |
||
3640 | cstr_reset(&tokcstr); |
||
3641 | |||
3642 | while (p1 < p) { |
||
3643 | cstr_ccat(&tokcstr, *p1); |
||
3644 | p1++; |
||
3645 | } |
||
3646 | p--; |
||
3647 | PEEKC(c, p); |
||
3648 | parse_ident_slow: |
||
3649 | while (isidnum_table[c]) { |
||
3650 | cstr_ccat(&tokcstr, c); |
||
3651 | PEEKC(c, p); |
||
3652 | } |
||
3653 | ts = tok_alloc(tokcstr.data, tokcstr.size); |
||
3654 | } |
||
3655 | tok = ts->tok; |
||
3656 | break; |
||
3657 | case 'L': |
||
3658 | t = p[1]; |
||
3659 | if (t != '\\' && t != '\'' && t != '\"') { |
||
3660 | /* fast case */ |
||
3661 | goto parse_ident_fast; |
||
3662 | } else { |
||
3663 | PEEKC(c, p); |
||
3664 | if (c == '\'' || c == '\"') { |
||
3665 | is_long = 1; |
||
3666 | goto str_const; |
||
3667 | } else { |
||
3668 | cstr_reset(&tokcstr); |
||
3669 | cstr_ccat(&tokcstr, 'L'); |
||
3670 | goto parse_ident_slow; |
||
3671 | } |
||
3672 | } |
||
3673 | break; |
||
3674 | case '0': case '1': case '2': case '3': |
||
3675 | case '4': case '5': case '6': case '7': |
||
3676 | case '8': case '9': |
||
3677 | |||
3678 | cstr_reset(&tokcstr); |
||
3679 | /* after the first digit, accept digits, alpha, '.' or sign if |
||
3680 | prefixed by 'eEpP' */ |
||
3681 | parse_num: |
||
3682 | for(;;) { |
||
3683 | t = c; |
||
3684 | cstr_ccat(&tokcstr, c); |
||
3685 | PEEKC(c, p); |
||
3686 | if (!(isnum(c) || isid(c) || c == '.' || |
||
3687 | ((c == '+' || c == '-') && |
||
3688 | (t == 'e' || t == 'E' || t == 'p' || t == 'P')))) |
||
3689 | break; |
||
3690 | } |
||
3691 | /* We add a trailing '\0' to ease parsing */ |
||
3692 | cstr_ccat(&tokcstr, '\0'); |
||
3693 | tokc.cstr = &tokcstr; |
||
3694 | tok = TOK_PPNUM; |
||
3695 | break; |
||
3696 | case '.': |
||
3697 | /* special dot handling because it can also start a number */ |
||
3698 | PEEKC(c, p); |
||
3699 | if (isnum(c)) { |
||
3700 | cstr_reset(&tokcstr); |
||
3701 | cstr_ccat(&tokcstr, '.'); |
||
3702 | goto parse_num; |
||
3703 | } else if (c == '.') { |
||
3704 | PEEKC(c, p); |
||
3705 | if (c != '.') |
||
3706 | expect("'.'"); |
||
3707 | PEEKC(c, p); |
||
3708 | tok = TOK_DOTS; |
||
3709 | } else { |
||
3710 | tok = '.'; |
||
3711 | } |
||
3712 | break; |
||
3713 | case '\'': |
||
3714 | case '\"': |
||
3715 | is_long = 0; |
||
3716 | str_const: |
||
3717 | { |
||
3718 | CString str; |
||
3719 | int sep; |
||
3720 | |||
3721 | sep = c; |
||
3722 | |||
3723 | /* parse the string */ |
||
3724 | cstr_new(&str); |
||
3725 | p = parse_pp_string(p, sep, &str); |
||
3726 | cstr_ccat(&str, '\0'); |
||
3727 | |||
3728 | /* eval the escape (should be done as TOK_PPNUM) */ |
||
3729 | cstr_reset(&tokcstr); |
||
3730 | parse_escape_string(&tokcstr, str.data, is_long); |
||
3731 | cstr_free(&str); |
||
3732 | |||
3733 | if (sep == '\'') { |
||
3734 | int char_size; |
||
3735 | /* XXX: make it portable */ |
||
3736 | if (!is_long) |
||
3737 | char_size = 1; |
||
3738 | else |
||
3739 | char_size = sizeof(int); |
||
3740 | if (tokcstr.size <= char_size) |
||
3741 | error("empty character constant"); |
||
3742 | if (tokcstr.size > 2 * char_size) |
||
3743 | warning("multi-character character constant"); |
||
3744 | if (!is_long) { |
||
3745 | tokc.i = *(int8_t *)tokcstr.data; |
||
3746 | tok = TOK_CCHAR; |
||
3747 | } else { |
||
3748 | tokc.i = *(int *)tokcstr.data; |
||
3749 | tok = TOK_LCHAR; |
||
3750 | } |
||
3751 | } else { |
||
3752 | tokc.cstr = &tokcstr; |
||
3753 | if (!is_long) |
||
3754 | tok = TOK_STR; |
||
3755 | else |
||
3756 | tok = TOK_LSTR; |
||
3757 | } |
||
3758 | } |
||
3759 | break; |
||
3760 | |||
3761 | case '<': |
||
3762 | PEEKC(c, p); |
||
3763 | if (c == '=') { |
||
3764 | p++; |
||
3765 | tok = TOK_LE; |
||
3766 | } else if (c == '<') { |
||
3767 | PEEKC(c, p); |
||
3768 | if (c == '=') { |
||
3769 | p++; |
||
3770 | tok = TOK_A_SHL; |
||
3771 | } else { |
||
3772 | tok = TOK_SHL; |
||
3773 | } |
||
3774 | } else { |
||
3775 | tok = TOK_LT; |
||
3776 | } |
||
3777 | break; |
||
3778 | |||
3779 | case '>': |
||
3780 | PEEKC(c, p); |
||
3781 | if (c == '=') { |
||
3782 | p++; |
||
3783 | tok = TOK_GE; |
||
3784 | } else if (c == '>') { |
||
3785 | PEEKC(c, p); |
||
3786 | if (c == '=') { |
||
3787 | p++; |
||
3788 | tok = TOK_A_SAR; |
||
3789 | } else { |
||
3790 | tok = TOK_SAR; |
||
3791 | } |
||
3792 | } else { |
||
3793 | tok = TOK_GT; |
||
3794 | } |
||
3795 | break; |
||
3796 | |||
3797 | case '&': |
||
3798 | PEEKC(c, p); |
||
3799 | if (c == '&') { |
||
3800 | p++; |
||
3801 | tok = TOK_LAND; |
||
3802 | } else if (c == '=') { |
||
3803 | p++; |
||
3804 | tok = TOK_A_AND; |
||
3805 | } else { |
||
3806 | tok = '&'; |
||
3807 | } |
||
3808 | break; |
||
3809 | |||
3810 | case '|': |
||
3811 | PEEKC(c, p); |
||
3812 | if (c == '|') { |
||
3813 | p++; |
||
3814 | tok = TOK_LOR; |
||
3815 | } else if (c == '=') { |
||
3816 | p++; |
||
3817 | tok = TOK_A_OR; |
||
3818 | } else { |
||
3819 | tok = '|'; |
||
3820 | } |
||
3821 | break; |
||
3822 | |||
3823 | case '+': |
||
3824 | PEEKC(c, p); |
||
3825 | if (c == '+') { |
||
3826 | p++; |
||
3827 | tok = TOK_INC; |
||
3828 | } else if (c == '=') { |
||
3829 | p++; |
||
3830 | tok = TOK_A_ADD; |
||
3831 | } else { |
||
3832 | tok = '+'; |
||
3833 | } |
||
3834 | break; |
||
3835 | |||
3836 | case '-': |
||
3837 | PEEKC(c, p); |
||
3838 | if (c == '-') { |
||
3839 | p++; |
||
3840 | tok = TOK_DEC; |
||
3841 | } else if (c == '=') { |
||
3842 | p++; |
||
3843 | tok = TOK_A_SUB; |
||
3844 | } else if (c == '>') { |
||
3845 | p++; |
||
3846 | tok = TOK_ARROW; |
||
3847 | } else { |
||
3848 | tok = '-'; |
||
3849 | } |
||
3850 | break; |
||
3851 | |||
3852 | PARSE2('!', '!', '=', TOK_NE) |
||
3853 | PARSE2('=', '=', '=', TOK_EQ) |
||
3854 | PARSE2('*', '*', '=', TOK_A_MUL) |
||
3855 | PARSE2('%', '%', '=', TOK_A_MOD) |
||
3856 | PARSE2('^', '^', '=', TOK_A_XOR) |
||
3857 | |||
3858 | /* comments or operator */ |
||
3859 | case '/': |
||
3860 | PEEKC(c, p); |
||
3861 | if (c == '*') { |
||
3862 | p = parse_comment(p); |
||
3863 | goto redo_no_start; |
||
3864 | } else if (c == '/') { |
||
3865 | p = parse_line_comment(p); |
||
3866 | goto redo_no_start; |
||
3867 | } else if (c == '=') { |
||
3868 | p++; |
||
3869 | tok = TOK_A_DIV; |
||
3870 | } else { |
||
3871 | tok = '/'; |
||
3872 | } |
||
3873 | break; |
||
3874 | |||
3875 | /* simple tokens */ |
||
3876 | case '(': |
||
3877 | case ')': |
||
3878 | case '[': |
||
3879 | case ']': |
||
3880 | case '{': |
||
3881 | case '}': |
||
3882 | case ',': |
||
3883 | case ';': |
||
3884 | case ':': |
||
3885 | case '?': |
||
3886 | case '~': |
||
3887 | case '$': /* only used in assembler */ |
||
3888 | case '@': /* dito */ |
||
3889 | tok = c; |
||
3890 | p++; |
||
3891 | break; |
||
3892 | default: |
||
3893 | error("unrecognized character \\x%02x", c); |
||
3894 | break; |
||
3895 | } |
||
3896 | file->buf_ptr = p; |
||
3897 | tok_flags = 0; |
||
3898 | #if defined(PARSE_DEBUG) |
||
3899 | printf("token = %s\n", get_tok_str(tok, &tokc)); |
||
3900 | #endif |
||
3901 | } |
||
3902 | |||
3903 | /* return next token without macro substitution. Can read input from |
||
3904 | macro_ptr buffer */ |
||
3905 | static void next_nomacro(void) |
||
3906 | { |
||
3907 | if (macro_ptr) { |
||
3908 | redo: |
||
3909 | tok = *macro_ptr; |
||
3910 | if (tok) { |
||
3911 | TOK_GET(tok, macro_ptr, tokc); |
||
3912 | if (tok == TOK_LINENUM) { |
||
3913 | file->line_num = tokc.i; |
||
3914 | goto redo; |
||
3915 | } |
||
3916 | } |
||
3917 | } else { |
||
3918 | next_nomacro1(); |
||
3919 | } |
||
3920 | } |
||
3921 | |||
3922 | /* substitute args in macro_str and return allocated string */ |
||
3923 | static int *macro_arg_subst(Sym **nested_list, int *macro_str, Sym *args) |
||
3924 | { |
||
3925 | int *st, last_tok, t, notfirst; |
||
3926 | Sym *s; |
||
3927 | CValue cval; |
||
3928 | TokenString str; |
||
3929 | CString cstr; |
||
3930 | |||
3931 | tok_str_new(&str); |
||
3932 | last_tok = 0; |
||
3933 | while(1) { |
||
3934 | TOK_GET(t, macro_str, cval); |
||
3935 | if (!t) |
||
3936 | break; |
||
3937 | if (t == '#') { |
||
3938 | /* stringize */ |
||
3939 | TOK_GET(t, macro_str, cval); |
||
3940 | if (!t) |
||
3941 | break; |
||
3942 | s = sym_find2(args, t); |
||
3943 | if (s) { |
||
3944 | cstr_new(&cstr); |
||
3945 | st = (int *)s->c; |
||
3946 | notfirst = 0; |
||
3947 | while (*st) { |
||
3948 | if (notfirst) |
||
3949 | cstr_ccat(&cstr, ' '); |
||
3950 | TOK_GET(t, st, cval); |
||
3951 | cstr_cat(&cstr, get_tok_str(t, &cval)); |
||
3952 | notfirst = 1; |
||
3953 | } |
||
3954 | cstr_ccat(&cstr, '\0'); |
||
3955 | #ifdef PP_DEBUG |
||
3956 | printf("stringize: %s\n", (char *)cstr.data); |
||
3957 | #endif |
||
3958 | /* add string */ |
||
3959 | cval.cstr = &cstr; |
||
3960 | tok_str_add2(&str, TOK_STR, &cval); |
||
3961 | cstr_free(&cstr); |
||
3962 | } else { |
||
3963 | tok_str_add2(&str, t, &cval); |
||
3964 | } |
||
3965 | } else if (t >= TOK_IDENT) { |
||
3966 | s = sym_find2(args, t); |
||
3967 | if (s) { |
||
3968 | st = (int *)s->c; |
||
3969 | /* if '##' is present before or after, no arg substitution */ |
||
3970 | if (*macro_str == TOK_TWOSHARPS || last_tok == TOK_TWOSHARPS) { |
||
3971 | /* special case for var arg macros : ## eats the |
||
3972 | ',' if empty VA_ARGS variable. */ |
||
3973 | /* XXX: test of the ',' is not 100% |
||
3974 | reliable. should fix it to avoid security |
||
3975 | problems */ |
||
3976 | if (gnu_ext && s->type.t && |
||
3977 | last_tok == TOK_TWOSHARPS && |
||
3978 | str.len >= 2 && str.str[str.len - 2] == ',') { |
||
3979 | if (*st == 0) { |
||
3980 | /* suppress ',' '##' */ |
||
3981 | str.len -= 2; |
||
3982 | } else { |
||
3983 | /* suppress '##' and add variable */ |
||
3984 | str.len--; |
||
3985 | goto add_var; |
||
3986 | } |
||
3987 | } else { |
||
3988 | int t1; |
||
3989 | add_var: |
||
3990 | for(;;) { |
||
3991 | TOK_GET(t1, st, cval); |
||
3992 | if (!t1) |
||
3993 | break; |
||
3994 | tok_str_add2(&str, t1, &cval); |
||
3995 | } |
||
3996 | } |
||
3997 | } else { |
||
3998 | /* NOTE: the stream cannot be read when macro |
||
3999 | substituing an argument */ |
||
4000 | macro_subst(&str, nested_list, st, NULL); |
||
4001 | } |
||
4002 | } else { |
||
4003 | tok_str_add(&str, t); |
||
4004 | } |
||
4005 | } else { |
||
4006 | tok_str_add2(&str, t, &cval); |
||
4007 | } |
||
4008 | last_tok = t; |
||
4009 | } |
||
4010 | tok_str_add(&str, 0); |
||
4011 | return str.str; |
||
4012 | } |
||
4013 | |||
4014 | static char const ab_month_name[12][4] = |
||
4015 | { |
||
4016 | "Jan", "Feb", "Mar", "Apr", "May", "Jun", |
||
4017 | "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" |
||
4018 | }; |
||
4019 | |||
4020 | /* do macro substitution of current token with macro 's' and add |
||
4021 | result to (tok_str,tok_len). 'nested_list' is the list of all |
||
4022 | macros we got inside to avoid recursing. Return non zero if no |
||
4023 | substitution needs to be done */ |
||
4024 | static int macro_subst_tok(TokenString *tok_str, |
||
4025 | Sym **nested_list, Sym *s, struct macro_level **can_read_stream) |
||
4026 | { |
||
4027 | Sym *args, *sa, *sa1; |
||
4028 | int mstr_allocated, parlevel, *mstr, t, t1; |
||
4029 | TokenString str; |
||
4030 | char *cstrval; |
||
4031 | CValue cval; |
||
4032 | CString cstr; |
||
4033 | char buf[32]; |
||
4034 | |||
4035 | /* if symbol is a macro, prepare substitution */ |
||
4036 | /* special macros */ |
||
4037 | if (tok == TOK___LINE__) { |
||
4038 | snprintf(buf, sizeof(buf), "%d", file->line_num); |
||
4039 | cstrval = buf; |
||
4040 | t1 = TOK_PPNUM; |
||
4041 | goto add_cstr1; |
||
4042 | } else if (tok == TOK___FILE__) { |
||
4043 | cstrval = file->filename; |
||
4044 | goto add_cstr; |
||
4045 | } else if (tok == TOK___DATE__ || tok == TOK___TIME__) { |
||
4046 | time_t ti; |
||
4047 | struct tm *tm; |
||
4048 | |||
4049 | time(&ti); |
||
4050 | tm = localtime(&ti); |
||
4051 | if (tok == TOK___DATE__) { |
||
4052 | snprintf(buf, sizeof(buf), "%s %2d %d", |
||
4053 | ab_month_name[tm->tm_mon], tm->tm_mday, tm->tm_year + 1900); |
||
4054 | } else { |
||
4055 | snprintf(buf, sizeof(buf), "%02d:%02d:%02d", |
||
4056 | tm->tm_hour, tm->tm_min, tm->tm_sec); |
||
4057 | } |
||
4058 | cstrval = buf; |
||
4059 | add_cstr: |
||
4060 | t1 = TOK_STR; |
||
4061 | add_cstr1: |
||
4062 | cstr_new(&cstr); |
||
4063 | cstr_cat(&cstr, cstrval); |
||
4064 | cstr_ccat(&cstr, '\0'); |
||
4065 | cval.cstr = &cstr; |
||
4066 | tok_str_add2(tok_str, t1, &cval); |
||
4067 | cstr_free(&cstr); |
||
4068 | } else { |
||
4069 | mstr = (int *)s->c; |
||
4070 | mstr_allocated = 0; |
||
4071 | if (s->type.t == MACRO_FUNC) { |
||
4072 | /* NOTE: we do not use next_nomacro to avoid eating the |
||
4073 | next token. XXX: find better solution */ |
||
4074 | redo: |
||
4075 | if (macro_ptr) { |
||
4076 | t = *macro_ptr; |
||
4077 | if (t == 0 && can_read_stream) { |
||
4078 | /* end of macro stream: we must look at the token |
||
4079 | after in the file */ |
||
4080 | struct macro_level *ml = *can_read_stream; |
||
4081 | macro_ptr = NULL; |
||
4082 | if (ml) |
||
4083 | { |
||
4084 | macro_ptr = ml->p; |
||
4085 | ml->p = NULL; |
||
4086 | *can_read_stream = ml -> prev; |
||
4087 | } |
||
4088 | goto redo; |
||
4089 | } |
||
4090 | } else { |
||
4091 | /* XXX: incorrect with comments */ |
||
4092 | ch = file->buf_ptr[0]; |
||
4093 | while (is_space(ch) || ch == '\n') |
||
4094 | cinp(); |
||
4095 | t = ch; |
||
4096 | } |
||
4097 | if (t != '(') /* no macro subst */ |
||
4098 | return -1; |
||
4099 | |||
4100 | /* argument macro */ |
||
4101 | next_nomacro(); |
||
4102 | next_nomacro(); |
||
4103 | args = NULL; |
||
4104 | sa = s->next; |
||
4105 | /* NOTE: empty args are allowed, except if no args */ |
||
4106 | for(;;) { |
||
4107 | /* handle '()' case */ |
||
4108 | if (!args && !sa && tok == ')') |
||
4109 | break; |
||
4110 | if (!sa) |
||
4111 | error("macro '%s' used with too many args", |
||
4112 | get_tok_str(s->v, 0)); |
||
4113 | tok_str_new(&str); |
||
4114 | parlevel = 0; |
||
4115 | /* NOTE: non zero sa->t indicates VA_ARGS */ |
||
4116 | while ((parlevel > 0 || |
||
4117 | (tok != ')' && |
||
4118 | (tok != ',' || sa->type.t))) && |
||
4119 | tok != -1) { |
||
4120 | if (tok == '(') |
||
4121 | parlevel++; |
||
4122 | else if (tok == ')') |
||
4123 | parlevel--; |
||
4124 | tok_str_add2(&str, tok, &tokc); |
||
4125 | next_nomacro(); |
||
4126 | } |
||
4127 | tok_str_add(&str, 0); |
||
4128 | sym_push2(&args, sa->v & ~SYM_FIELD, sa->type.t, (int)str.str); |
||
4129 | sa = sa->next; |
||
4130 | if (tok == ')') { |
||
4131 | /* special case for gcc var args: add an empty |
||
4132 | var arg argument if it is omitted */ |
||
4133 | if (sa && sa->type.t && gnu_ext) |
||
4134 | continue; |
||
4135 | else |
||
4136 | break; |
||
4137 | } |
||
4138 | if (tok != ',') |
||
4139 | expect(","); |
||
4140 | next_nomacro(); |
||
4141 | } |
||
4142 | if (sa) { |
||
4143 | error("macro '%s' used with too few args", |
||
4144 | get_tok_str(s->v, 0)); |
||
4145 | } |
||
4146 | |||
4147 | /* now subst each arg */ |
||
4148 | mstr = macro_arg_subst(nested_list, mstr, args); |
||
4149 | /* free memory */ |
||
4150 | sa = args; |
||
4151 | while (sa) { |
||
4152 | sa1 = sa->prev; |
||
4153 | tok_str_free((int *)sa->c); |
||
4154 | sym_free(sa); |
||
4155 | sa = sa1; |
||
4156 | } |
||
4157 | mstr_allocated = 1; |
||
4158 | } |
||
4159 | sym_push2(nested_list, s->v, 0, 0); |
||
4160 | macro_subst(tok_str, nested_list, mstr, can_read_stream); |
||
4161 | /* pop nested defined symbol */ |
||
4162 | sa1 = *nested_list; |
||
4163 | *nested_list = sa1->prev; |
||
4164 | sym_free(sa1); |
||
4165 | if (mstr_allocated) |
||
4166 | tok_str_free(mstr); |
||
4167 | } |
||
4168 | return 0; |
||
4169 | } |
||
4170 | |||
4171 | /* handle the '##' operator. Return NULL if no '##' seen. Otherwise |
||
4172 | return the resulting string (which must be freed). */ |
||
4173 | static inline int *macro_twosharps(const int *macro_str) |
||
4174 | { |
||
4175 | TokenSym *ts; |
||
4176 | const int *macro_ptr1, *start_macro_ptr, *ptr, *saved_macro_ptr; |
||
4177 | int t; |
||
4178 | const char *p1, *p2; |
||
4179 | CValue cval; |
||
4180 | TokenString macro_str1; |
||
4181 | CString cstr; |
||
4182 | |||
4183 | start_macro_ptr = macro_str; |
||
4184 | /* we search the first '##' */ |
||
4185 | for(;;) { |
||
4186 | macro_ptr1 = macro_str; |
||
4187 | TOK_GET(t, macro_str, cval); |
||
4188 | /* nothing more to do if end of string */ |
||
4189 | if (t == 0) |
||
4190 | return NULL; |
||
4191 | if (*macro_str == TOK_TWOSHARPS) |
||
4192 | break; |
||
4193 | } |
||
4194 | |||
4195 | /* we saw '##', so we need more processing to handle it */ |
||
4196 | cstr_new(&cstr); |
||
4197 | tok_str_new(¯o_str1); |
||
4198 | tok = t; |
||
4199 | tokc = cval; |
||
4200 | |||
4201 | /* add all tokens seen so far */ |
||
4202 | for(ptr = start_macro_ptr; ptr < macro_ptr1;) { |
||
4203 | TOK_GET(t, ptr, cval); |
||
4204 | tok_str_add2(¯o_str1, t, &cval); |
||
4205 | } |
||
4206 | saved_macro_ptr = macro_ptr; |
||
4207 | /* XXX: get rid of the use of macro_ptr here */ |
||
4208 | macro_ptr = (int *)macro_str; |
||
4209 | for(;;) { |
||
4210 | while (*macro_ptr == TOK_TWOSHARPS) { |
||
4211 | macro_ptr++; |
||
4212 | macro_ptr1 = macro_ptr; |
||
4213 | t = *macro_ptr; |
||
4214 | if (t) { |
||
4215 | TOK_GET(t, macro_ptr, cval); |
||
4216 | /* We concatenate the two tokens if we have an |
||
4217 | identifier or a preprocessing number */ |
||
4218 | cstr_reset(&cstr); |
||
4219 | p1 = get_tok_str(tok, &tokc); |
||
4220 | cstr_cat(&cstr, p1); |
||
4221 | p2 = get_tok_str(t, &cval); |
||
4222 | cstr_cat(&cstr, p2); |
||
4223 | cstr_ccat(&cstr, '\0'); |
||
4224 | |||
4225 | if ((tok >= TOK_IDENT || tok == TOK_PPNUM) && |
||
4226 | (t >= TOK_IDENT || t == TOK_PPNUM)) { |
||
4227 | if (tok == TOK_PPNUM) { |
||
4228 | /* if number, then create a number token */ |
||
4229 | /* NOTE: no need to allocate because |
||
4230 | tok_str_add2() does it */ |
||
4231 | tokc.cstr = &cstr; |
||
4232 | } else { |
||
4233 | /* if identifier, we must do a test to |
||
4234 | validate we have a correct identifier */ |
||
4235 | if (t == TOK_PPNUM) { |
||
4236 | const char *p; |
||
4237 | int c; |
||
4238 | |||
4239 | p = p2; |
||
4240 | for(;;) { |
||
4241 | c = *p; |
||
4242 | if (c == '\0') |
||
4243 | break; |
||
4244 | p++; |
||
4245 | if (!isnum(c) && !isid(c)) |
||
4246 | goto error_pasting; |
||
4247 | } |
||
4248 | } |
||
4249 | ts = tok_alloc(cstr.data, strlen(cstr.data)); |
||
4250 | tok = ts->tok; /* modify current token */ |
||
4251 | } |
||
4252 | } else { |
||
4253 | const char *str = cstr.data; |
||
4254 | const unsigned char *q; |
||
4255 | |||
4256 | /* we look for a valid token */ |
||
4257 | /* XXX: do more extensive checks */ |
||
4258 | if (!strcmp(str, ">>=")) { |
||
4259 | tok = TOK_A_SAR; |
||
4260 | } else if (!strcmp(str, "<<=")) { |
||
4261 | tok = TOK_A_SHL; |
||
4262 | } else if (strlen(str) == 2) { |
||
4263 | /* search in two bytes table */ |
||
4264 | q = tok_two_chars; |
||
4265 | for(;;) { |
||
4266 | if (!*q) |
||
4267 | goto error_pasting; |
||
4268 | if (q[0] == str[0] && q[1] == str[1]) |
||
4269 | break; |
||
4270 | q += 3; |
||
4271 | } |
||
4272 | tok = q[2]; |
||
4273 | } else { |
||
4274 | error_pasting: |
||
4275 | /* NOTE: because get_tok_str use a static buffer, |
||
4276 | we must save it */ |
||
4277 | cstr_reset(&cstr); |
||
4278 | p1 = get_tok_str(tok, &tokc); |
||
4279 | cstr_cat(&cstr, p1); |
||
4280 | cstr_ccat(&cstr, '\0'); |
||
4281 | p2 = get_tok_str(t, &cval); |
||
4282 | warning("pasting \"%s\" and \"%s\" does not give a valid preprocessing token", cstr.data, p2); |
||
4283 | /* cannot merge tokens: just add them separately */ |
||
4284 | tok_str_add2(¯o_str1, tok, &tokc); |
||
4285 | /* XXX: free associated memory ? */ |
||
4286 | tok = t; |
||
4287 | tokc = cval; |
||
4288 | } |
||
4289 | } |
||
4290 | } |
||
4291 | } |
||
4292 | tok_str_add2(¯o_str1, tok, &tokc); |
||
4293 | next_nomacro(); |
||
4294 | if (tok == 0) |
||
4295 | break; |
||
4296 | } |
||
4297 | macro_ptr = (int *)saved_macro_ptr; |
||
4298 | cstr_free(&cstr); |
||
4299 | tok_str_add(¯o_str1, 0); |
||
4300 | return macro_str1.str; |
||
4301 | } |
||
4302 | |||
4303 | |||
4304 | /* do macro substitution of macro_str and add result to |
||
4305 | (tok_str,tok_len). 'nested_list' is the list of all macros we got |
||
4306 | inside to avoid recursing. */ |
||
4307 | static void macro_subst(TokenString *tok_str, Sym **nested_list, |
||
4308 | const int *macro_str, struct macro_level ** can_read_stream) |
||
4309 | { |
||
4310 | Sym *s; |
||
4311 | int *macro_str1; |
||
4312 | const int *ptr; |
||
4313 | int t, ret; |
||
4314 | CValue cval; |
||
4315 | struct macro_level ml; |
||
4316 | |||
4317 | /* first scan for '##' operator handling */ |
||
4318 | ptr = macro_str; |
||
4319 | macro_str1 = macro_twosharps(ptr); |
||
4320 | if (macro_str1) |
||
4321 | ptr = macro_str1; |
||
4322 | while (1) { |
||
4323 | /* NOTE: ptr == NULL can only happen if tokens are read from |
||
4324 | file stream due to a macro function call */ |
||
4325 | if (ptr == NULL) |
||
4326 | break; |
||
4327 | TOK_GET(t, ptr, cval); |
||
4328 | if (t == 0) |
||
4329 | break; |
||
4330 | s = define_find(t); |
||
4331 | if (s != NULL) { |
||
4332 | /* if nested substitution, do nothing */ |
||
4333 | if (sym_find2(*nested_list, t)) |
||
4334 | goto no_subst; |
||
4335 | ml.p = macro_ptr; |
||
4336 | if (can_read_stream) |
||
4337 | ml.prev = *can_read_stream, *can_read_stream = &ml; |
||
4338 | macro_ptr = (int *)ptr; |
||
4339 | tok = t; |
||
4340 | ret = macro_subst_tok(tok_str, nested_list, s, can_read_stream); |
||
4341 | ptr = (int *)macro_ptr; |
||
4342 | macro_ptr = ml.p; |
||
4343 | if (can_read_stream && *can_read_stream == &ml) |
||
4344 | *can_read_stream = ml.prev; |
||
4345 | if (ret != 0) |
||
4346 | goto no_subst; |
||
4347 | } else { |
||
4348 | no_subst: |
||
4349 | tok_str_add2(tok_str, t, &cval); |
||
4350 | } |
||
4351 | } |
||
4352 | if (macro_str1) |
||
4353 | tok_str_free(macro_str1); |
||
4354 | } |
||
4355 | |||
4356 | /* return next token with macro substitution */ |
||
4357 | static void next(void) |
||
4358 | { |
||
4359 | Sym *nested_list, *s; |
||
4360 | TokenString str; |
||
4361 | struct macro_level *ml; |
||
4362 | |||
4363 | redo: |
||
4364 | next_nomacro(); |
||
4365 | if (!macro_ptr) { |
||
4366 | /* if not reading from macro substituted string, then try |
||
4367 | to substitute macros */ |
||
4368 | if (tok >= TOK_IDENT && |
||
4369 | (parse_flags & PARSE_FLAG_PREPROCESS)) { |
||
4370 | s = define_find(tok); |
||
4371 | if (s) { |
||
4372 | /* we have a macro: we try to substitute */ |
||
4373 | tok_str_new(&str); |
||
4374 | nested_list = NULL; |
||
4375 | ml = NULL; |
||
4376 | if (macro_subst_tok(&str, &nested_list, s, &ml) == 0) { |
||
4377 | /* substitution done, NOTE: maybe empty */ |
||
4378 | tok_str_add(&str, 0); |
||
4379 | macro_ptr = str.str; |
||
4380 | macro_ptr_allocated = str.str; |
||
4381 | goto redo; |
||
4382 | } |
||
4383 | } |
||
4384 | } |
||
4385 | } else { |
||
4386 | if (tok == 0) { |
||
4387 | /* end of macro or end of unget buffer */ |
||
4388 | if (unget_buffer_enabled) { |
||
4389 | macro_ptr = unget_saved_macro_ptr; |
||
4390 | unget_buffer_enabled = 0; |
||
4391 | } else { |
||
4392 | /* end of macro string: free it */ |
||
4393 | tok_str_free(macro_ptr_allocated); |
||
4394 | macro_ptr = NULL; |
||
4395 | } |
||
4396 | goto redo; |
||
4397 | } |
||
4398 | } |
||
4399 | |||
4400 | /* convert preprocessor tokens into C tokens */ |
||
4401 | if (tok == TOK_PPNUM && |
||
4402 | (parse_flags & PARSE_FLAG_TOK_NUM)) { |
||
4403 | parse_number((char *)tokc.cstr->data); |
||
4404 | } |
||
4405 | } |
||
4406 | |||
4407 | /* push back current token and set current token to 'last_tok'. Only |
||
4408 | identifier case handled for labels. */ |
||
4409 | static inline void unget_tok(int last_tok) |
||
4410 | { |
||
4411 | int i, n; |
||
4412 | int *q; |
||
4413 | unget_saved_macro_ptr = macro_ptr; |
||
4414 | unget_buffer_enabled = 1; |
||
4415 | q = unget_saved_buffer; |
||
4416 | macro_ptr = q; |
||
4417 | *q++ = tok; |
||
4418 | n = tok_ext_size(tok) - 1; |
||
4419 | for(i=0;i |
||
4420 | *q++ = tokc.tab[i]; |
||
4421 | *q = 0; /* end of token string */ |
||
4422 | tok = last_tok; |
||
4423 | } |
||
4424 | |||
4425 | |||
4426 | void swap(int *p, int *q) |
||
4427 | { |
||
4428 | int t; |
||
4429 | t = *p; |
||
4430 | *p = *q; |
||
4431 | *q = t; |
||
4432 | } |
||
4433 | |||
4434 | void vsetc(CType *type, int r, CValue *vc) |
||
4435 | { |
||
4436 | int v; |
||
4437 | |||
4438 | if (vtop >= vstack + (VSTACK_SIZE - 1)) |
||
4439 | error("memory full"); |
||
4440 | /* cannot let cpu flags if other instruction are generated. Also |
||
4441 | avoid leaving VT_JMP anywhere except on the top of the stack |
||
4442 | because it would complicate the code generator. */ |
||
4443 | if (vtop >= vstack) { |
||
4444 | v = vtop->r & VT_VALMASK; |
||
4445 | if (v == VT_CMP || (v & ~1) == VT_JMP) |
||
4446 | gv(RC_INT); |
||
4447 | } |
||
4448 | vtop++; |
||
4449 | vtop->type = *type; |
||
4450 | vtop->r = r; |
||
4451 | vtop->r2 = VT_CONST; |
||
4452 | vtop->c = *vc; |
||
4453 | } |
||
4454 | |||
4455 | /* push integer constant */ |
||
4456 | void vpushi(int v) |
||
4457 | { |
||
4458 | CValue cval; |
||
4459 | cval.i = v; |
||
4460 | vsetc(&int_type, VT_CONST, &cval); |
||
4461 | } |
||
4462 | |||
4463 | /* Return a static symbol pointing to a section */ |
||
4464 | static Sym *get_sym_ref(CType *type, Section *sec, |
||
4465 | unsigned long offset, unsigned long size) |
||
4466 | { |
||
4467 | int v; |
||
4468 | Sym *sym; |
||
4469 | |||
4470 | v = anon_sym++; |
||
4471 | sym = global_identifier_push(v, type->t | VT_STATIC, 0); |
||
4472 | sym->type.ref = type->ref; |
||
4473 | sym->r = VT_CONST | VT_SYM; |
||
4474 | put_extern_sym(sym, sec, offset, size); |
||
4475 | return sym; |
||
4476 | } |
||
4477 | |||
4478 | /* push a reference to a section offset by adding a dummy symbol */ |
||
4479 | static void vpush_ref(CType *type, Section *sec, unsigned long offset, unsigned long size) |
||
4480 | { |
||
4481 | CValue cval; |
||
4482 | |||
4483 | cval.ul = 0; |
||
4484 | vsetc(type, VT_CONST | VT_SYM, &cval); |
||
4485 | vtop->sym = get_sym_ref(type, sec, offset, size); |
||
4486 | } |
||
4487 | |||
4488 | /* define a new external reference to a symbol 'v' of type 'u' */ |
||
4489 | static Sym *external_global_sym(int v, CType *type, int r) |
||
4490 | { |
||
4491 | Sym *s; |
||
4492 | |||
4493 | s = sym_find(v); |
||
4494 | if (!s) { |
||
4495 | /* push forward reference */ |
||
4496 | s = global_identifier_push(v, type->t | VT_EXTERN, 0); |
||
4497 | s->type.ref = type->ref; |
||
4498 | s->r = r | VT_CONST | VT_SYM; |
||
4499 | } |
||
4500 | return s; |
||
4501 | } |
||
4502 | |||
4503 | /* define a new external reference to a symbol 'v' of type 'u' */ |
||
4504 | static Sym *external_sym(int v, CType *type, int r) |
||
4505 | { |
||
4506 | Sym *s; |
||
4507 | |||
4508 | s = sym_find(v); |
||
4509 | if (!s) { |
||
4510 | /* push forward reference */ |
||
4511 | s = sym_push(v, type, r | VT_CONST | VT_SYM, 0); |
||
4512 | s->type.t |= VT_EXTERN; |
||
4513 | } else { |
||
4514 | if (!is_compatible_types(&s->type, type)) |
||
4515 | error("incompatible types for redefinition of '%s'", |
||
4516 | get_tok_str(v, NULL)); |
||
4517 | } |
||
4518 | return s; |
||
4519 | } |
||
4520 | |||
4521 | /* push a reference to global symbol v */ |
||
4522 | static void vpush_global_sym(CType *type, int v) |
||
4523 | { |
||
4524 | Sym *sym; |
||
4525 | CValue cval; |
||
4526 | |||
4527 | sym = external_global_sym(v, type, 0); |
||
4528 | cval.ul = 0; |
||
4529 | vsetc(type, VT_CONST | VT_SYM, &cval); |
||
4530 | vtop->sym = sym; |
||
4531 | } |
||
4532 | |||
4533 | void vset(CType *type, int r, int v) |
||
4534 | { |
||
4535 | CValue cval; |
||
4536 | |||
4537 | cval.i = v; |
||
4538 | vsetc(type, r, &cval); |
||
4539 | } |
||
4540 | |||
4541 | void vseti(int r, int v) |
||
4542 | { |
||
4543 | CType type; |
||
4544 | type.t = VT_INT; |
||
4545 | vset(&type, r, v); |
||
4546 | } |
||
4547 | |||
4548 | void vswap(void) |
||
4549 | { |
||
4550 | SValue tmp; |
||
4551 | |||
4552 | tmp = vtop[0]; |
||
4553 | vtop[0] = vtop[-1]; |
||
4554 | vtop[-1] = tmp; |
||
4555 | } |
||
4556 | |||
4557 | void vpushv(SValue *v) |
||
4558 | { |
||
4559 | if (vtop >= vstack + (VSTACK_SIZE - 1)) |
||
4560 | error("memory full"); |
||
4561 | vtop++; |
||
4562 | *vtop = *v; |
||
4563 | } |
||
4564 | |||
4565 | void vdup(void) |
||
4566 | { |
||
4567 | vpushv(vtop); |
||
4568 | } |
||
4569 | |||
4570 | /* save r to the memory stack, and mark it as being free */ |
||
4571 | void save_reg(int r) |
||
4572 | { |
||
4573 | int l, saved, size, align; |
||
4574 | SValue *p, sv; |
||
4575 | CType *type; |
||
4576 | |||
4577 | /* modify all stack values */ |
||
4578 | saved = 0; |
||
4579 | l = 0; |
||
4580 | for(p=vstack;p<=vtop;p++) { |
||
4581 | if ((p->r & VT_VALMASK) == r || |
||
4582 | (p->r2 & VT_VALMASK) == r) { |
||
4583 | /* must save value on stack if not already done */ |
||
4584 | if (!saved) { |
||
4585 | /* NOTE: must reload 'r' because r might be equal to r2 */ |
||
4586 | r = p->r & VT_VALMASK; |
||
4587 | /* store register in the stack */ |
||
4588 | type = &p->type; |
||
4589 | if ((p->r & VT_LVAL) || |
||
4590 | (!is_float(type->t) && (type->t & VT_BTYPE) != VT_LLONG)) |
||
4591 | type = &int_type; |
||
4592 | size = type_size(type, &align); |
||
4593 | loc = (loc - size) & -align; |
||
4594 | sv.type.t = type->t; |
||
4595 | sv.r = VT_LOCAL | VT_LVAL; |
||
4596 | sv.c.ul = loc; |
||
4597 | store(r, &sv); |
||
4598 | #ifdef TCC_TARGET_I386 |
||
4599 | /* x86 specific: need to pop fp register ST0 if saved */ |
||
4600 | if (r == TREG_ST0) { |
||
4601 | o(0xd9dd); /* fstp %st(1) */ |
||
4602 | } |
||
4603 | #endif |
||
4604 | /* special long long case */ |
||
4605 | if ((type->t & VT_BTYPE) == VT_LLONG) { |
||
4606 | sv.c.ul += 4; |
||
4607 | store(p->r2, &sv); |
||
4608 | } |
||
4609 | l = loc; |
||
4610 | saved = 1; |
||
4611 | } |
||
4612 | /* mark that stack entry as being saved on the stack */ |
||
4613 | if (p->r & VT_LVAL) { |
||
4614 | /* also clear the bounded flag because the |
||
4615 | relocation address of the function was stored in |
||
4616 | p->c.ul */ |
||
4617 | p->r = (p->r & ~(VT_VALMASK | VT_BOUNDED)) | VT_LLOCAL; |
||
4618 | } else { |
||
4619 | p->r = lvalue_type(p->type.t) | VT_LOCAL; |
||
4620 | } |
||
4621 | p->r2 = VT_CONST; |
||
4622 | p->c.ul = l; |
||
4623 | } |
||
4624 | } |
||
4625 | } |
||
4626 | |||
4627 | /* find a register of class 'rc2' with at most one reference on stack. |
||
4628 | * If none, call get_reg(rc) */ |
||
4629 | int get_reg_ex(int rc, int rc2) |
||
4630 | { |
||
4631 | int r; |
||
4632 | SValue *p; |
||
4633 | |||
4634 | for(r=0;r |
||
4635 | if (reg_classes[r] & rc2) { |
||
4636 | int n; |
||
4637 | n=0; |
||
4638 | for(p = vstack; p <= vtop; p++) { |
||
4639 | if ((p->r & VT_VALMASK) == r || |
||
4640 | (p->r2 & VT_VALMASK) == r) |
||
4641 | n++; |
||
4642 | } |
||
4643 | if (n <= 1) |
||
4644 | return r; |
||
4645 | } |
||
4646 | } |
||
4647 | return get_reg(rc); |
||
4648 | } |
||
4649 | |||
4650 | /* find a free register of class 'rc'. If none, save one register */ |
||
4651 | int get_reg(int rc) |
||
4652 | { |
||
4653 | int r; |
||
4654 | SValue *p; |
||
4655 | |||
4656 | /* find a free register */ |
||
4657 | for(r=0;r |
||
4658 | if (reg_classes[r] & rc) { |
||
4659 | for(p=vstack;p<=vtop;p++) { |
||
4660 | if ((p->r & VT_VALMASK) == r || |
||
4661 | (p->r2 & VT_VALMASK) == r) |
||
4662 | goto notfound; |
||
4663 | } |
||
4664 | return r; |
||
4665 | } |
||
4666 | notfound: ; |
||
4667 | } |
||
4668 | |||
4669 | /* no register left : free the first one on the stack (VERY |
||
4670 | IMPORTANT to start from the bottom to ensure that we don't |
||
4671 | spill registers used in gen_opi()) */ |
||
4672 | for(p=vstack;p<=vtop;p++) { |
||
4673 | r = p->r & VT_VALMASK; |
||
4674 | if (r < VT_CONST && (reg_classes[r] & rc)) |
||
4675 | goto save_found; |
||
4676 | /* also look at second register (if long long) */ |
||
4677 | r = p->r2 & VT_VALMASK; |
||
4678 | if (r < VT_CONST && (reg_classes[r] & rc)) { |
||
4679 | save_found: |
||
4680 | save_reg(r); |
||
4681 | return r; |
||
4682 | } |
||
4683 | } |
||
4684 | /* Should never comes here */ |
||
4685 | return -1; |
||
4686 | } |
||
4687 | |||
4688 | /* save registers up to (vtop - n) stack entry */ |
||
4689 | void save_regs(int n) |
||
4690 | { |
||
4691 | int r; |
||
4692 | SValue *p, *p1; |
||
4693 | p1 = vtop - n; |
||
4694 | for(p = vstack;p <= p1; p++) { |
||
4695 | r = p->r & VT_VALMASK; |
||
4696 | if (r < VT_CONST) { |
||
4697 | save_reg(r); |
||
4698 | } |
||
4699 | } |
||
4700 | } |
||
4701 | |||
4702 | /* move register 's' to 'r', and flush previous value of r to memory |
||
4703 | if needed */ |
||
4704 | void move_reg(int r, int s) |
||
4705 | { |
||
4706 | SValue sv; |
||
4707 | |||
4708 | if (r != s) { |
||
4709 | save_reg(r); |
||
4710 | sv.type.t = VT_INT; |
||
4711 | sv.r = s; |
||
4712 | sv.c.ul = 0; |
||
4713 | load(r, &sv); |
||
4714 | } |
||
4715 | } |
||
4716 | |||
4717 | /* get address of vtop (vtop MUST BE an lvalue) */ |
||
4718 | void gaddrof(void) |
||
4719 | { |
||
4720 | vtop->r &= ~VT_LVAL; |
||
4721 | /* tricky: if saved lvalue, then we can go back to lvalue */ |
||
4722 | if ((vtop->r & VT_VALMASK) == VT_LLOCAL) |
||
4723 | vtop->r = (vtop->r & ~(VT_VALMASK | VT_LVAL_TYPE)) | VT_LOCAL | VT_LVAL; |
||
4724 | } |
||
4725 | |||
4726 | #ifdef CONFIG_TCC_BCHECK |
||
4727 | /* generate lvalue bound code */ |
||
4728 | void gbound(void) |
||
4729 | { |
||
4730 | int lval_type; |
||
4731 | CType type1; |
||
4732 | |||
4733 | vtop->r &= ~VT_MUSTBOUND; |
||
4734 | /* if lvalue, then use checking code before dereferencing */ |
||
4735 | if (vtop->r & VT_LVAL) { |
||
4736 | /* if not VT_BOUNDED value, then make one */ |
||
4737 | if (!(vtop->r & VT_BOUNDED)) { |
||
4738 | lval_type = vtop->r & (VT_LVAL_TYPE | VT_LVAL); |
||
4739 | /* must save type because we must set it to int to get pointer */ |
||
4740 | type1 = vtop->type; |
||
4741 | vtop->type.t = VT_INT; |
||
4742 | gaddrof(); |
||
4743 | vpushi(0); |
||
4744 | gen_bounded_ptr_add(); |
||
4745 | vtop->r |= lval_type; |
||
4746 | vtop->type = type1; |
||
4747 | } |
||
4748 | /* then check for dereferencing */ |
||
4749 | gen_bounded_ptr_deref(); |
||
4750 | } |
||
4751 | } |
||
4752 | #endif |
||
4753 | |||
4754 | /* store vtop a register belonging to class 'rc'. lvalues are |
||
4755 | converted to values. Cannot be used if cannot be converted to |
||
4756 | register value (such as structures). */ |
||
4757 | int gv(int rc) |
||
4758 | { |
||
4759 | int r, r2, rc2, bit_pos, bit_size, size, align, i; |
||
4760 | unsigned long long ll; |
||
4761 | |||
4762 | /* NOTE: get_reg can modify vstack[] */ |
||
4763 | if (vtop->type.t & VT_BITFIELD) { |
||
4764 | bit_pos = (vtop->type.t >> VT_STRUCT_SHIFT) & 0x3f; |
||
4765 | bit_size = (vtop->type.t >> (VT_STRUCT_SHIFT + 6)) & 0x3f; |
||
4766 | /* remove bit field info to avoid loops */ |
||
4767 | vtop->type.t &= ~(VT_BITFIELD | (-1 << VT_STRUCT_SHIFT)); |
||
4768 | /* generate shifts */ |
||
4769 | vpushi(32 - (bit_pos + bit_size)); |
||
4770 | gen_op(TOK_SHL); |
||
4771 | vpushi(32 - bit_size); |
||
4772 | /* NOTE: transformed to SHR if unsigned */ |
||
4773 | gen_op(TOK_SAR); |
||
4774 | r = gv(rc); |
||
4775 | } else { |
||
4776 | if (is_float(vtop->type.t) && |
||
4777 | (vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) { |
||
4778 | Sym *sym; |
||
4779 | int *ptr; |
||
4780 | unsigned long offset; |
||
4781 | |||
4782 | /* XXX: unify with initializers handling ? */ |
||
4783 | /* CPUs usually cannot use float constants, so we store them |
||
4784 | generically in data segment */ |
||
4785 | size = type_size(&vtop->type, &align); |
||
4786 | offset = (data_section->data_offset + align - 1) & -align; |
||
4787 | data_section->data_offset = offset; |
||
4788 | /* XXX: not portable yet */ |
||
4789 | ptr = section_ptr_add(data_section, size); |
||
4790 | size = size >> 2; |
||
4791 | for(i=0;i |
||
4792 | ptr[i] = vtop->c.tab[i]; |
||
4793 | sym = get_sym_ref(&vtop->type, data_section, offset, size << 2); |
||
4794 | vtop->r |= VT_LVAL | VT_SYM; |
||
4795 | vtop->sym = sym; |
||
4796 | vtop->c.ul = 0; |
||
4797 | } |
||
4798 | #ifdef CONFIG_TCC_BCHECK |
||
4799 | if (vtop->r & VT_MUSTBOUND) |
||
4800 | gbound(); |
||
4801 | #endif |
||
4802 | |||
4803 | r = vtop->r & VT_VALMASK; |
||
4804 | /* need to reload if: |
||
4805 | - constant |
||
4806 | - lvalue (need to dereference pointer) |
||
4807 | - already a register, but not in the right class */ |
||
4808 | if (r >= VT_CONST || |
||
4809 | (vtop->r & VT_LVAL) || |
||
4810 | !(reg_classes[r] & rc) || |
||
4811 | ((vtop->type.t & VT_BTYPE) == VT_LLONG && |
||
4812 | !(reg_classes[vtop->r2] & rc))) { |
||
4813 | r = get_reg(rc); |
||
4814 | if ((vtop->type.t & VT_BTYPE) == VT_LLONG) { |
||
4815 | /* two register type load : expand to two words |
||
4816 | temporarily */ |
||
4817 | if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) { |
||
4818 | /* load constant */ |
||
4819 | ll = vtop->c.ull; |
||
4820 | vtop->c.ui = ll; /* first word */ |
||
4821 | load(r, vtop); |
||
4822 | vtop->r = r; /* save register value */ |
||
4823 | vpushi(ll >> 32); /* second word */ |
||
4824 | } else if (r >= VT_CONST || /* XXX: test to VT_CONST incorrect ? */ |
||
4825 | (vtop->r & VT_LVAL)) { |
||
4826 | /* We do not want to modifier the long long |
||
4827 | pointer here, so the safest (and less |
||
4828 | efficient) is to save all the other registers |
||
4829 | in the stack. XXX: totally inefficient. */ |
||
4830 | save_regs(1); |
||
4831 | /* load from memory */ |
||
4832 | load(r, vtop); |
||
4833 | vdup(); |
||
4834 | vtop[-1].r = r; /* save register value */ |
||
4835 | /* increment pointer to get second word */ |
||
4836 | vtop->type.t = VT_INT; |
||
4837 | gaddrof(); |
||
4838 | vpushi(4); |
||
4839 | gen_op('+'); |
||
4840 | vtop->r |= VT_LVAL; |
||
4841 | } else { |
||
4842 | /* move registers */ |
||
4843 | load(r, vtop); |
||
4844 | vdup(); |
||
4845 | vtop[-1].r = r; /* save register value */ |
||
4846 | vtop->r = vtop[-1].r2; |
||
4847 | } |
||
4848 | /* allocate second register */ |
||
4849 | rc2 = RC_INT; |
||
4850 | if (rc == RC_IRET) |
||
4851 | rc2 = RC_LRET; |
||
4852 | r2 = get_reg(rc2); |
||
4853 | load(r2, vtop); |
||
4854 | vpop(); |
||
4855 | /* write second register */ |
||
4856 | vtop->r2 = r2; |
||
4857 | } else if ((vtop->r & VT_LVAL) && !is_float(vtop->type.t)) { |
||
4858 | int t1, t; |
||
4859 | /* lvalue of scalar type : need to use lvalue type |
||
4860 | because of possible cast */ |
||
4861 | t = vtop->type.t; |
||
4862 | t1 = t; |
||
4863 | /* compute memory access type */ |
||
4864 | if (vtop->r & VT_LVAL_BYTE) |
||
4865 | t = VT_BYTE; |
||
4866 | else if (vtop->r & VT_LVAL_SHORT) |
||
4867 | t = VT_SHORT; |
||
4868 | if (vtop->r & VT_LVAL_UNSIGNED) |
||
4869 | t |= VT_UNSIGNED; |
||
4870 | vtop->type.t = t; |
||
4871 | load(r, vtop); |
||
4872 | /* restore wanted type */ |
||
4873 | vtop->type.t = t1; |
||
4874 | } else { |
||
4875 | /* one register type load */ |
||
4876 | load(r, vtop); |
||
4877 | } |
||
4878 | } |
||
4879 | vtop->r = r; |
||
4880 | #ifdef TCC_TARGET_C67 |
||
4881 | /* uses register pairs for doubles */ |
||
4882 | if ((vtop->type.t & VT_BTYPE) == VT_DOUBLE) |
||
4883 | vtop->r2 = r+1; |
||
4884 | #endif |
||
4885 | } |
||
4886 | return r; |
||
4887 | } |
||
4888 | |||
4889 | /* generate vtop[-1] and vtop[0] in resp. classes rc1 and rc2 */ |
||
4890 | void gv2(int rc1, int rc2) |
||
4891 | { |
||
4892 | int v; |
||
4893 | |||
4894 | /* generate more generic register first. But VT_JMP or VT_CMP |
||
4895 | values must be generated first in all cases to avoid possible |
||
4896 | reload errors */ |
||
4897 | v = vtop[0].r & VT_VALMASK; |
||
4898 | if (v != VT_CMP && (v & ~1) != VT_JMP && rc1 <= rc2) { |
||
4899 | vswap(); |
||
4900 | gv(rc1); |
||
4901 | vswap(); |
||
4902 | gv(rc2); |
||
4903 | /* test if reload is needed for first register */ |
||
4904 | if ((vtop[-1].r & VT_VALMASK) >= VT_CONST) { |
||
4905 | vswap(); |
||
4906 | gv(rc1); |
||
4907 | vswap(); |
||
4908 | } |
||
4909 | } else { |
||
4910 | gv(rc2); |
||
4911 | vswap(); |
||
4912 | gv(rc1); |
||
4913 | vswap(); |
||
4914 | /* test if reload is needed for first register */ |
||
4915 | if ((vtop[0].r & VT_VALMASK) >= VT_CONST) { |
||
4916 | gv(rc2); |
||
4917 | } |
||
4918 | } |
||
4919 | } |
||
4920 | |||
4921 | /* expand long long on stack in two int registers */ |
||
4922 | void lexpand(void) |
||
4923 | { |
||
4924 | int u; |
||
4925 | |||
4926 | u = vtop->type.t & VT_UNSIGNED; |
||
4927 | gv(RC_INT); |
||
4928 | vdup(); |
||
4929 | vtop[0].r = vtop[-1].r2; |
||
4930 | vtop[0].r2 = VT_CONST; |
||
4931 | vtop[-1].r2 = VT_CONST; |
||
4932 | vtop[0].type.t = VT_INT | u; |
||
4933 | vtop[-1].type.t = VT_INT | u; |
||
4934 | } |
||
4935 | |||
4936 | #ifdef TCC_TARGET_ARM |
||
4937 | /* expand long long on stack */ |
||
4938 | void lexpand_nr(void) |
||
4939 | { |
||
4940 | int u,v; |
||
4941 | |||
4942 | u = vtop->type.t & VT_UNSIGNED; |
||
4943 | vdup(); |
||
4944 | vtop->r2 = VT_CONST; |
||
4945 | vtop->type.t = VT_INT | u; |
||
4946 | v=vtop[-1].r & (VT_VALMASK | VT_LVAL); |
||
4947 | if (v == VT_CONST) { |
||
4948 | vtop[-1].c.ui = vtop->c.ull; |
||
4949 | vtop->c.ui = vtop->c.ull >> 32; |
||
4950 | vtop->r = VT_CONST; |
||
4951 | } else if (v == (VT_LVAL|VT_CONST) || v == (VT_LVAL|VT_LOCAL)) { |
||
4952 | vtop->c.ui += 4; |
||
4953 | vtop->r = vtop[-1].r; |
||
4954 | } else if (v > VT_CONST) { |
||
4955 | vtop--; |
||
4956 | lexpand(); |
||
4957 | } else |
||
4958 | vtop->r = vtop[-1].r2; |
||
4959 | vtop[-1].r2 = VT_CONST; |
||
4960 | vtop[-1].type.t = VT_INT | u; |
||
4961 | } |
||
4962 | #endif |
||
4963 | |||
4964 | /* build a long long from two ints */ |
||
4965 | void lbuild(int t) |
||
4966 | { |
||
4967 | gv2(RC_INT, RC_INT); |
||
4968 | vtop[-1].r2 = vtop[0].r; |
||
4969 | vtop[-1].type.t = t; |
||
4970 | vpop(); |
||
4971 | } |
||
4972 | |||
4973 | /* rotate n first stack elements to the bottom |
||
4974 | I1 ... In -> I2 ... In I1 [top is right] |
||
4975 | */ |
||
4976 | void vrotb(int n) |
||
4977 | { |
||
4978 | int i; |
||
4979 | SValue tmp; |
||
4980 | |||
4981 | tmp = vtop[-n + 1]; |
||
4982 | for(i=-n+1;i!=0;i++) |
||
4983 | vtop[i] = vtop[i+1]; |
||
4984 | vtop[0] = tmp; |
||
4985 | } |
||
4986 | |||
4987 | /* rotate n first stack elements to the top |
||
4988 | I1 ... In -> In I1 ... I(n-1) [top is right] |
||
4989 | */ |
||
4990 | void vrott(int n) |
||
4991 | { |
||
4992 | int i; |
||
4993 | SValue tmp; |
||
4994 | |||
4995 | tmp = vtop[0]; |
||
4996 | for(i = 0;i < n - 1; i++) |
||
4997 | vtop[-i] = vtop[-i - 1]; |
||
4998 | vtop[-n + 1] = tmp; |
||
4999 | } |
||
5000 | |||
5001 | #ifdef TCC_TARGET_ARM |
||
5002 | /* like vrott but in other direction |
||
5003 | In ... I1 -> I(n-1) ... I1 In [top is right] |
||
5004 | */ |
||
5005 | void vnrott(int n) |
||
5006 | { |
||
5007 | int i; |
||
5008 | SValue tmp; |
||
5009 | |||
5010 | tmp = vtop[-n + 1]; |
||
5011 | for(i = n - 1; i > 0; i--) |
||
5012 | vtop[-i] = vtop[-i + 1]; |
||
5013 | vtop[0] = tmp; |
||
5014 | } |
||
5015 | #endif |
||
5016 | |||
5017 | /* pop stack value */ |
||
5018 | void vpop(void) |
||
5019 | { |
||
5020 | int v; |
||
5021 | v = vtop->r & VT_VALMASK; |
||
5022 | #ifdef TCC_TARGET_I386 |
||
5023 | /* for x86, we need to pop the FP stack */ |
||
5024 | if (v == TREG_ST0 && !nocode_wanted) { |
||
5025 | o(0xd9dd); /* fstp %st(1) */ |
||
5026 | } else |
||
5027 | #endif |
||
5028 | if (v == VT_JMP || v == VT_JMPI) { |
||
5029 | /* need to put correct jump if && or || without test */ |
||
5030 | gsym(vtop->c.ul); |
||
5031 | } |
||
5032 | vtop--; |
||
5033 | } |
||
5034 | |||
5035 | /* convert stack entry to register and duplicate its value in another |
||
5036 | register */ |
||
5037 | void gv_dup(void) |
||
5038 | { |
||
5039 | int rc, t, r, r1; |
||
5040 | SValue sv; |
||
5041 | |||
5042 | t = vtop->type.t; |
||
5043 | if ((t & VT_BTYPE) == VT_LLONG) { |
||
5044 | lexpand(); |
||
5045 | gv_dup(); |
||
5046 | vswap(); |
||
5047 | vrotb(3); |
||
5048 | gv_dup(); |
||
5049 | vrotb(4); |
||
5050 | /* stack: H L L1 H1 */ |
||
5051 | lbuild(t); |
||
5052 | vrotb(3); |
||
5053 | vrotb(3); |
||
5054 | vswap(); |
||
5055 | lbuild(t); |
||
5056 | vswap(); |
||
5057 | } else { |
||
5058 | /* duplicate value */ |
||
5059 | rc = RC_INT; |
||
5060 | sv.type.t = VT_INT; |
||
5061 | if (is_float(t)) { |
||
5062 | rc = RC_FLOAT; |
||
5063 | sv.type.t = t; |
||
5064 | } |
||
5065 | r = gv(rc); |
||
5066 | r1 = get_reg(rc); |
||
5067 | sv.r = r; |
||
5068 | sv.c.ul = 0; |
||
5069 | load(r1, &sv); /* move r to r1 */ |
||
5070 | vdup(); |
||
5071 | /* duplicates value */ |
||
5072 | vtop->r = r1; |
||
5073 | } |
||
5074 | } |
||
5075 | |||
5076 | /* generate CPU independent (unsigned) long long operations */ |
||
5077 | void gen_opl(int op) |
||
5078 | { |
||
5079 | int t, a, b, op1, c, i; |
||
5080 | int func; |
||
5081 | SValue tmp; |
||
5082 | |||
5083 | switch(op) { |
||
5084 | case '/': |
||
5085 | case TOK_PDIV: |
||
5086 | func = TOK___divdi3; |
||
5087 | goto gen_func; |
||
5088 | case TOK_UDIV: |
||
5089 | func = TOK___udivdi3; |
||
5090 | goto gen_func; |
||
5091 | case '%': |
||
5092 | func = TOK___moddi3; |
||
5093 | goto gen_func; |
||
5094 | case TOK_UMOD: |
||
5095 | func = TOK___umoddi3; |
||
5096 | gen_func: |
||
5097 | /* call generic long long function */ |
||
5098 | vpush_global_sym(&func_old_type, func); |
||
5099 | vrott(3); |
||
5100 | gfunc_call(2); |
||
5101 | vpushi(0); |
||
5102 | vtop->r = REG_IRET; |
||
5103 | vtop->r2 = REG_LRET; |
||
5104 | break; |
||
5105 | case '^': |
||
5106 | case '&': |
||
5107 | case '|': |
||
5108 | case '*': |
||
5109 | case '+': |
||
5110 | case '-': |
||
5111 | t = vtop->type.t; |
||
5112 | vswap(); |
||
5113 | lexpand(); |
||
5114 | vrotb(3); |
||
5115 | lexpand(); |
||
5116 | /* stack: L1 H1 L2 H2 */ |
||
5117 | tmp = vtop[0]; |
||
5118 | vtop[0] = vtop[-3]; |
||
5119 | vtop[-3] = tmp; |
||
5120 | tmp = vtop[-2]; |
||
5121 | vtop[-2] = vtop[-3]; |
||
5122 | vtop[-3] = tmp; |
||
5123 | vswap(); |
||
5124 | /* stack: H1 H2 L1 L2 */ |
||
5125 | if (op == '*') { |
||
5126 | vpushv(vtop - 1); |
||
5127 | vpushv(vtop - 1); |
||
5128 | gen_op(TOK_UMULL); |
||
5129 | lexpand(); |
||
5130 | /* stack: H1 H2 L1 L2 ML MH */ |
||
5131 | for(i=0;i<4;i++) |
||
5132 | vrotb(6); |
||
5133 | /* stack: ML MH H1 H2 L1 L2 */ |
||
5134 | tmp = vtop[0]; |
||
5135 | vtop[0] = vtop[-2]; |
||
5136 | vtop[-2] = tmp; |
||
5137 | /* stack: ML MH H1 L2 H2 L1 */ |
||
5138 | gen_op('*'); |
||
5139 | vrotb(3); |
||
5140 | vrotb(3); |
||
5141 | gen_op('*'); |
||
5142 | /* stack: ML MH M1 M2 */ |
||
5143 | gen_op('+'); |
||
5144 | gen_op('+'); |
||
5145 | } else if (op == '+' || op == '-') { |
||
5146 | /* XXX: add non carry method too (for MIPS or alpha) */ |
||
5147 | if (op == '+') |
||
5148 | op1 = TOK_ADDC1; |
||
5149 | else |
||
5150 | op1 = TOK_SUBC1; |
||
5151 | gen_op(op1); |
||
5152 | /* stack: H1 H2 (L1 op L2) */ |
||
5153 | vrotb(3); |
||
5154 | vrotb(3); |
||
5155 | gen_op(op1 + 1); /* TOK_xxxC2 */ |
||
5156 | } else { |
||
5157 | gen_op(op); |
||
5158 | /* stack: H1 H2 (L1 op L2) */ |
||
5159 | vrotb(3); |
||
5160 | vrotb(3); |
||
5161 | /* stack: (L1 op L2) H1 H2 */ |
||
5162 | gen_op(op); |
||
5163 | /* stack: (L1 op L2) (H1 op H2) */ |
||
5164 | } |
||
5165 | /* stack: L H */ |
||
5166 | lbuild(t); |
||
5167 | break; |
||
5168 | case TOK_SAR: |
||
5169 | case TOK_SHR: |
||
5170 | case TOK_SHL: |
||
5171 | if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) { |
||
5172 | t = vtop[-1].type.t; |
||
5173 | vswap(); |
||
5174 | lexpand(); |
||
5175 | vrotb(3); |
||
5176 | /* stack: L H shift */ |
||
5177 | c = (int)vtop->c.i; |
||
5178 | /* constant: simpler */ |
||
5179 | /* NOTE: all comments are for SHL. the other cases are |
||
5180 | done by swaping words */ |
||
5181 | vpop(); |
||
5182 | if (op != TOK_SHL) |
||
5183 | vswap(); |
||
5184 | if (c >= 32) { |
||
5185 | /* stack: L H */ |
||
5186 | vpop(); |
||
5187 | if (c > 32) { |
||
5188 | vpushi(c - 32); |
||
5189 | gen_op(op); |
||
5190 | } |
||
5191 | if (op != TOK_SAR) { |
||
5192 | vpushi(0); |
||
5193 | } else { |
||
5194 | gv_dup(); |
||
5195 | vpushi(31); |
||
5196 | gen_op(TOK_SAR); |
||
5197 | } |
||
5198 | vswap(); |
||
5199 | } else { |
||
5200 | vswap(); |
||
5201 | gv_dup(); |
||
5202 | /* stack: H L L */ |
||
5203 | vpushi(c); |
||
5204 | gen_op(op); |
||
5205 | vswap(); |
||
5206 | vpushi(32 - c); |
||
5207 | if (op == TOK_SHL) |
||
5208 | gen_op(TOK_SHR); |
||
5209 | else |
||
5210 | gen_op(TOK_SHL); |
||
5211 | vrotb(3); |
||
5212 | /* stack: L L H */ |
||
5213 | vpushi(c); |
||
5214 | if (op == TOK_SHL) |
||
5215 | gen_op(TOK_SHL); |
||
5216 | else |
||
5217 | gen_op(TOK_SHR); |
||
5218 | gen_op('|'); |
||
5219 | } |
||
5220 | if (op != TOK_SHL) |
||
5221 | vswap(); |
||
5222 | lbuild(t); |
||
5223 | } else { |
||
5224 | /* XXX: should provide a faster fallback on x86 ? */ |
||
5225 | switch(op) { |
||
5226 | case TOK_SAR: |
||
5227 | func = TOK___sardi3; |
||
5228 | goto gen_func; |
||
5229 | case TOK_SHR: |
||
5230 | func = TOK___shrdi3; |
||
5231 | goto gen_func; |
||
5232 | case TOK_SHL: |
||
5233 | func = TOK___shldi3; |
||
5234 | goto gen_func; |
||
5235 | } |
||
5236 | } |
||
5237 | break; |
||
5238 | default: |
||
5239 | /* compare operations */ |
||
5240 | t = vtop->type.t; |
||
5241 | vswap(); |
||
5242 | lexpand(); |
||
5243 | vrotb(3); |
||
5244 | lexpand(); |
||
5245 | /* stack: L1 H1 L2 H2 */ |
||
5246 | tmp = vtop[-1]; |
||
5247 | vtop[-1] = vtop[-2]; |
||
5248 | vtop[-2] = tmp; |
||
5249 | /* stack: L1 L2 H1 H2 */ |
||
5250 | /* compare high */ |
||
5251 | op1 = op; |
||
5252 | /* when values are equal, we need to compare low words. since |
||
5253 | the jump is inverted, we invert the test too. */ |
||
5254 | if (op1 == TOK_LT) |
||
5255 | op1 = TOK_LE; |
||
5256 | else if (op1 == TOK_GT) |
||
5257 | op1 = TOK_GE; |
||
5258 | else if (op1 == TOK_ULT) |
||
5259 | op1 = TOK_ULE; |
||
5260 | else if (op1 == TOK_UGT) |
||
5261 | op1 = TOK_UGE; |
||
5262 | a = 0; |
||
5263 | b = 0; |
||
5264 | gen_op(op1); |
||
5265 | if (op1 != TOK_NE) { |
||
5266 | a = gtst(1, 0); |
||
5267 | } |
||
5268 | if (op != TOK_EQ) { |
||
5269 | /* generate non equal test */ |
||
5270 | /* XXX: NOT PORTABLE yet */ |
||
5271 | if (a == 0) { |
||
5272 | b = gtst(0, 0); |
||
5273 | } else { |
||
5274 | #if defined(TCC_TARGET_I386) |
||
5275 | b = psym(0x850f, 0); |
||
5276 | #elif defined(TCC_TARGET_ARM) |
||
5277 | b = ind; |
||
5278 | o(0x1A000000 | encbranch(ind, 0, 1)); |
||
5279 | #elif defined(TCC_TARGET_C67) |
||
5280 | error("not implemented"); |
||
5281 | #else |
||
5282 | #error not supported |
||
5283 | #endif |
||
5284 | } |
||
5285 | } |
||
5286 | /* compare low. Always unsigned */ |
||
5287 | op1 = op; |
||
5288 | if (op1 == TOK_LT) |
||
5289 | op1 = TOK_ULT; |
||
5290 | else if (op1 == TOK_LE) |
||
5291 | op1 = TOK_ULE; |
||
5292 | else if (op1 == TOK_GT) |
||
5293 | op1 = TOK_UGT; |
||
5294 | else if (op1 == TOK_GE) |
||
5295 | op1 = TOK_UGE; |
||
5296 | gen_op(op1); |
||
5297 | a = gtst(1, a); |
||
5298 | gsym(b); |
||
5299 | vseti(VT_JMPI, a); |
||
5300 | break; |
||
5301 | } |
||
5302 | } |
||
5303 | |||
5304 | /* handle integer constant optimizations and various machine |
||
5305 | independent opt */ |
||
5306 | void gen_opic(int op) |
||
5307 | { |
||
5308 | int fc, c1, c2, n; |
||
5309 | SValue *v1, *v2; |
||
5310 | |||
5311 | v1 = vtop - 1; |
||
5312 | v2 = vtop; |
||
5313 | /* currently, we cannot do computations with forward symbols */ |
||
5314 | c1 = (v1->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; |
||
5315 | c2 = (v2->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; |
||
5316 | if (c1 && c2) { |
||
5317 | fc = v2->c.i; |
||
5318 | switch(op) { |
||
5319 | case '+': v1->c.i += fc; break; |
||
5320 | case '-': v1->c.i -= fc; break; |
||
5321 | case '&': v1->c.i &= fc; break; |
||
5322 | case '^': v1->c.i ^= fc; break; |
||
5323 | case '|': v1->c.i |= fc; break; |
||
5324 | case '*': v1->c.i *= fc; break; |
||
5325 | |||
5326 | case TOK_PDIV: |
||
5327 | case '/': |
||
5328 | case '%': |
||
5329 | case TOK_UDIV: |
||
5330 | case TOK_UMOD: |
||
5331 | /* if division by zero, generate explicit division */ |
||
5332 | if (fc == 0) { |
||
5333 | if (const_wanted) |
||
5334 | error("division by zero in constant"); |
||
5335 | goto general_case; |
||
5336 | } |
||
5337 | switch(op) { |
||
5338 | default: v1->c.i /= fc; break; |
||
5339 | case '%': v1->c.i %= fc; break; |
||
5340 | case TOK_UDIV: v1->c.i = (unsigned)v1->c.i / fc; break; |
||
5341 | case TOK_UMOD: v1->c.i = (unsigned)v1->c.i % fc; break; |
||
5342 | } |
||
5343 | break; |
||
5344 | case TOK_SHL: v1->c.i <<= fc; break; |
||
5345 | case TOK_SHR: v1->c.i = (unsigned)v1->c.i >> fc; break; |
||
5346 | case TOK_SAR: v1->c.i >>= fc; break; |
||
5347 | /* tests */ |
||
5348 | case TOK_ULT: v1->c.i = (unsigned)v1->c.i < (unsigned)fc; break; |
||
5349 | case TOK_UGE: v1->c.i = (unsigned)v1->c.i >= (unsigned)fc; break; |
||
5350 | case TOK_EQ: v1->c.i = v1->c.i == fc; break; |
||
5351 | case TOK_NE: v1->c.i = v1->c.i != fc; break; |
||
5352 | case TOK_ULE: v1->c.i = (unsigned)v1->c.i <= (unsigned)fc; break; |
||
5353 | case TOK_UGT: v1->c.i = (unsigned)v1->c.i > (unsigned)fc; break; |
||
5354 | case TOK_LT: v1->c.i = v1->c.i < fc; break; |
||
5355 | case TOK_GE: v1->c.i = v1->c.i >= fc; break; |
||
5356 | case TOK_LE: v1->c.i = v1->c.i <= fc; break; |
||
5357 | case TOK_GT: v1->c.i = v1->c.i > fc; break; |
||
5358 | /* logical */ |
||
5359 | case TOK_LAND: v1->c.i = v1->c.i && fc; break; |
||
5360 | case TOK_LOR: v1->c.i = v1->c.i || fc; break; |
||
5361 | default: |
||
5362 | goto general_case; |
||
5363 | } |
||
5364 | vtop--; |
||
5365 | } else { |
||
5366 | /* if commutative ops, put c2 as constant */ |
||
5367 | if (c1 && (op == '+' || op == '&' || op == '^' || |
||
5368 | op == '|' || op == '*')) { |
||
5369 | vswap(); |
||
5370 | swap(&c1, &c2); |
||
5371 | } |
||
5372 | fc = vtop->c.i; |
||
5373 | if (c2 && (((op == '*' || op == '/' || op == TOK_UDIV || |
||
5374 | op == TOK_PDIV) && |
||
5375 | fc == 1) || |
||
5376 | ((op == '+' || op == '-' || op == '|' || op == '^' || |
||
5377 | op == TOK_SHL || op == TOK_SHR || op == TOK_SAR) && |
||
5378 | fc == 0) || |
||
5379 | (op == '&' && |
||
5380 | fc == -1))) { |
||
5381 | /* nothing to do */ |
||
5382 | vtop--; |
||
5383 | } else if (c2 && (op == '*' || op == TOK_PDIV || op == TOK_UDIV)) { |
||
5384 | /* try to use shifts instead of muls or divs */ |
||
5385 | if (fc > 0 && (fc & (fc - 1)) == 0) { |
||
5386 | n = -1; |
||
5387 | while (fc) { |
||
5388 | fc >>= 1; |
||
5389 | n++; |
||
5390 | } |
||
5391 | vtop->c.i = n; |
||
5392 | if (op == '*') |
||
5393 | op = TOK_SHL; |
||
5394 | else if (op == TOK_PDIV) |
||
5395 | op = TOK_SAR; |
||
5396 | else |
||
5397 | op = TOK_SHR; |
||
5398 | } |
||
5399 | goto general_case; |
||
5400 | } else if (c2 && (op == '+' || op == '-') && |
||
5401 | (vtop[-1].r & (VT_VALMASK | VT_LVAL | VT_SYM)) == |
||
5402 | (VT_CONST | VT_SYM)) { |
||
5403 | /* symbol + constant case */ |
||
5404 | if (op == '-') |
||
5405 | fc = -fc; |
||
5406 | vtop--; |
||
5407 | vtop->c.i += fc; |
||
5408 | } else { |
||
5409 | general_case: |
||
5410 | if (!nocode_wanted) { |
||
5411 | /* call low level op generator */ |
||
5412 | gen_opi(op); |
||
5413 | } else { |
||
5414 | vtop--; |
||
5415 | } |
||
5416 | } |
||
5417 | } |
||
5418 | } |
||
5419 | |||
5420 | /* generate a floating point operation with constant propagation */ |
||
5421 | void gen_opif(int op) |
||
5422 | { |
||
5423 | int c1, c2; |
||
5424 | SValue *v1, *v2; |
||
5425 | long double f1, f2; |
||
5426 | |||
5427 | v1 = vtop - 1; |
||
5428 | v2 = vtop; |
||
5429 | /* currently, we cannot do computations with forward symbols */ |
||
5430 | c1 = (v1->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; |
||
5431 | c2 = (v2->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; |
||
5432 | if (c1 && c2) { |
||
5433 | if (v1->type.t == VT_FLOAT) { |
||
5434 | f1 = v1->c.f; |
||
5435 | f2 = v2->c.f; |
||
5436 | } else if (v1->type.t == VT_DOUBLE) { |
||
5437 | f1 = v1->c.d; |
||
5438 | f2 = v2->c.d; |
||
5439 | } else { |
||
5440 | f1 = v1->c.ld; |
||
5441 | f2 = v2->c.ld; |
||
5442 | } |
||
5443 | |||
5444 | /* NOTE: we only do constant propagation if finite number (not |
||
5445 | NaN or infinity) (ANSI spec) */ |
||
5446 | if (!ieee_finite(f1) || !ieee_finite(f2)) |
||
5447 | goto general_case; |
||
5448 | |||
5449 | switch(op) { |
||
5450 | case '+': f1 += f2; break; |
||
5451 | case '-': f1 -= f2; break; |
||
5452 | case '*': f1 *= f2; break; |
||
5453 | case '/': |
||
5454 | if (f2 == 0.0) { |
||
5455 | if (const_wanted) |
||
5456 | error("division by zero in constant"); |
||
5457 | goto general_case; |
||
5458 | } |
||
5459 | f1 /= f2; |
||
5460 | break; |
||
5461 | /* XXX: also handles tests ? */ |
||
5462 | default: |
||
5463 | goto general_case; |
||
5464 | } |
||
5465 | /* XXX: overflow test ? */ |
||
5466 | if (v1->type.t == VT_FLOAT) { |
||
5467 | v1->c.f = f1; |
||
5468 | } else if (v1->type.t == VT_DOUBLE) { |
||
5469 | v1->c.d = f1; |
||
5470 | } else { |
||
5471 | v1->c.ld = f1; |
||
5472 | } |
||
5473 | vtop--; |
||
5474 | } else { |
||
5475 | general_case: |
||
5476 | if (!nocode_wanted) { |
||
5477 | gen_opf(op); |
||
5478 | } else { |
||
5479 | vtop--; |
||
5480 | } |
||
5481 | } |
||
5482 | } |
||
5483 | |||
5484 | static int pointed_size(CType *type) |
||
5485 | { |
||
5486 | int align; |
||
5487 | return type_size(pointed_type(type), &align); |
||
5488 | } |
||
5489 | |||
5490 | static inline int is_null_pointer(SValue *p) |
||
5491 | { |
||
5492 | if ((p->r & (VT_VALMASK | VT_LVAL | VT_SYM)) != VT_CONST) |
||
5493 | return 0; |
||
5494 | return ((p->type.t & VT_BTYPE) == VT_INT && p->c.i == 0) || |
||
5495 | ((p->type.t & VT_BTYPE) == VT_LLONG && p->c.ll == 0); |
||
5496 | } |
||
5497 | |||
5498 | static inline int is_integer_btype(int bt) |
||
5499 | { |
||
5500 | return (bt == VT_BYTE || bt == VT_SHORT || |
||
5501 | bt == VT_INT || bt == VT_LLONG); |
||
5502 | } |
||
5503 | |||
5504 | /* check types for comparison or substraction of pointers */ |
||
5505 | static void check_comparison_pointer_types(SValue *p1, SValue *p2, int op) |
||
5506 | { |
||
5507 | CType *type1, *type2, tmp_type1, tmp_type2; |
||
5508 | int bt1, bt2; |
||
5509 | |||
5510 | /* null pointers are accepted for all comparisons as gcc */ |
||
5511 | if (is_null_pointer(p1) || is_null_pointer(p2)) |
||
5512 | return; |
||
5513 | type1 = &p1->type; |
||
5514 | type2 = &p2->type; |
||
5515 | bt1 = type1->t & VT_BTYPE; |
||
5516 | bt2 = type2->t & VT_BTYPE; |
||
5517 | /* accept comparison between pointer and integer with a warning */ |
||
5518 | if ((is_integer_btype(bt1) || is_integer_btype(bt2)) && op != '-') { |
||
5519 | warning("comparison between pointer and integer"); |
||
5520 | return; |
||
5521 | } |
||
5522 | |||
5523 | /* both must be pointers or implicit function pointers */ |
||
5524 | if (bt1 == VT_PTR) { |
||
5525 | type1 = pointed_type(type1); |
||
5526 | } else if (bt1 != VT_FUNC) |
||
5527 | goto invalid_operands; |
||
5528 | |||
5529 | if (bt2 == VT_PTR) { |
||
5530 | type2 = pointed_type(type2); |
||
5531 | } else if (bt2 != VT_FUNC) { |
||
5532 | invalid_operands: |
||
5533 | error("invalid operands to binary %s", get_tok_str(op, NULL)); |
||
5534 | } |
||
5535 | if ((type1->t & VT_BTYPE) == VT_VOID || |
||
5536 | (type2->t & VT_BTYPE) == VT_VOID) |
||
5537 | return; |
||
5538 | tmp_type1 = *type1; |
||
5539 | tmp_type2 = *type2; |
||
5540 | tmp_type1.t &= ~(VT_UNSIGNED | VT_CONSTANT | VT_VOLATILE); |
||
5541 | tmp_type2.t &= ~(VT_UNSIGNED | VT_CONSTANT | VT_VOLATILE); |
||
5542 | if (!is_compatible_types(&tmp_type1, &tmp_type2)) { |
||
5543 | /* gcc-like error if '-' is used */ |
||
5544 | if (op == '-') |
||
5545 | goto invalid_operands; |
||
5546 | else |
||
5547 | warning("comparison of distinct pointer types lacks a cast"); |
||
5548 | } |
||
5549 | } |
||
5550 | |||
5551 | /* generic gen_op: handles types problems */ |
||
5552 | void gen_op(int op) |
||
5553 | { |
||
5554 | int u, t1, t2, bt1, bt2, t; |
||
5555 | CType type1; |
||
5556 | |||
5557 | t1 = vtop[-1].type.t; |
||
5558 | t2 = vtop[0].type.t; |
||
5559 | bt1 = t1 & VT_BTYPE; |
||
5560 | bt2 = t2 & VT_BTYPE; |
||
5561 | |||
5562 | if (bt1 == VT_PTR || bt2 == VT_PTR) { |
||
5563 | /* at least one operand is a pointer */ |
||
5564 | /* relationnal op: must be both pointers */ |
||
5565 | if (op >= TOK_ULT && op <= TOK_GT) { |
||
5566 | check_comparison_pointer_types(vtop - 1, vtop, op); |
||
5567 | /* pointers are handled are unsigned */ |
||
5568 | t = VT_INT | VT_UNSIGNED; |
||
5569 | goto std_op; |
||
5570 | } |
||
5571 | /* if both pointers, then it must be the '-' op */ |
||
5572 | if (bt1 == VT_PTR && bt2 == VT_PTR) { |
||
5573 | if (op != '-') |
||
5574 | error("cannot use pointers here"); |
||
5575 | check_comparison_pointer_types(vtop - 1, vtop, op); |
||
5576 | /* XXX: check that types are compatible */ |
||
5577 | u = pointed_size(&vtop[-1].type); |
||
5578 | gen_opic(op); |
||
5579 | /* set to integer type */ |
||
5580 | vtop->type.t = VT_INT; |
||
5581 | vpushi(u); |
||
5582 | gen_op(TOK_PDIV); |
||
5583 | } else { |
||
5584 | /* exactly one pointer : must be '+' or '-'. */ |
||
5585 | if (op != '-' && op != '+') |
||
5586 | error("cannot use pointers here"); |
||
5587 | /* Put pointer as first operand */ |
||
5588 | if (bt2 == VT_PTR) { |
||
5589 | vswap(); |
||
5590 | swap(&t1, &t2); |
||
5591 | } |
||
5592 | type1 = vtop[-1].type; |
||
5593 | /* XXX: cast to int ? (long long case) */ |
||
5594 | vpushi(pointed_size(&vtop[-1].type)); |
||
5595 | gen_op('*'); |
||
5596 | #ifdef CONFIG_TCC_BCHECK |
||
5597 | /* if evaluating constant expression, no code should be |
||
5598 | generated, so no bound check */ |
||
5599 | if (do_bounds_check && !const_wanted) { |
||
5600 | /* if bounded pointers, we generate a special code to |
||
5601 | test bounds */ |
||
5602 | if (op == '-') { |
||
5603 | vpushi(0); |
||
5604 | vswap(); |
||
5605 | gen_op('-'); |
||
5606 | } |
||
5607 | gen_bounded_ptr_add(); |
||
5608 | } else |
||
5609 | #endif |
||
5610 | { |
||
5611 | gen_opic(op); |
||
5612 | } |
||
5613 | /* put again type if gen_opic() swaped operands */ |
||
5614 | vtop->type = type1; |
||
5615 | } |
||
5616 | } else if (is_float(bt1) || is_float(bt2)) { |
||
5617 | /* compute bigger type and do implicit casts */ |
||
5618 | if (bt1 == VT_LDOUBLE || bt2 == VT_LDOUBLE) { |
||
5619 | t = VT_LDOUBLE; |
||
5620 | } else if (bt1 == VT_DOUBLE || bt2 == VT_DOUBLE) { |
||
5621 | t = VT_DOUBLE; |
||
5622 | } else { |
||
5623 | t = VT_FLOAT; |
||
5624 | } |
||
5625 | /* floats can only be used for a few operations */ |
||
5626 | if (op != '+' && op != '-' && op != '*' && op != '/' && |
||
5627 | (op < TOK_ULT || op > TOK_GT)) |
||
5628 | error("invalid operands for binary operation"); |
||
5629 | goto std_op; |
||
5630 | } else if (bt1 == VT_LLONG || bt2 == VT_LLONG) { |
||
5631 | /* cast to biggest op */ |
||
5632 | t = VT_LLONG; |
||
5633 | /* convert to unsigned if it does not fit in a long long */ |
||
5634 | if ((t1 & (VT_BTYPE | VT_UNSIGNED)) == (VT_LLONG | VT_UNSIGNED) || |
||
5635 | (t2 & (VT_BTYPE | VT_UNSIGNED)) == (VT_LLONG | VT_UNSIGNED)) |
||
5636 | t |= VT_UNSIGNED; |
||
5637 | goto std_op; |
||
5638 | } else { |
||
5639 | /* integer operations */ |
||
5640 | t = VT_INT; |
||
5641 | /* convert to unsigned if it does not fit in an integer */ |
||
5642 | if ((t1 & (VT_BTYPE | VT_UNSIGNED)) == (VT_INT | VT_UNSIGNED) || |
||
5643 | (t2 & (VT_BTYPE | VT_UNSIGNED)) == (VT_INT | VT_UNSIGNED)) |
||
5644 | t |= VT_UNSIGNED; |
||
5645 | std_op: |
||
5646 | /* XXX: currently, some unsigned operations are explicit, so |
||
5647 | we modify them here */ |
||
5648 | if (t & VT_UNSIGNED) { |
||
5649 | if (op == TOK_SAR) |
||
5650 | op = TOK_SHR; |
||
5651 | else if (op == '/') |
||
5652 | op = TOK_UDIV; |
||
5653 | else if (op == '%') |
||
5654 | op = TOK_UMOD; |
||
5655 | else if (op == TOK_LT) |
||
5656 | op = TOK_ULT; |
||
5657 | else if (op == TOK_GT) |
||
5658 | op = TOK_UGT; |
||
5659 | else if (op == TOK_LE) |
||
5660 | op = TOK_ULE; |
||
5661 | else if (op == TOK_GE) |
||
5662 | op = TOK_UGE; |
||
5663 | } |
||
5664 | vswap(); |
||
5665 | type1.t = t; |
||
5666 | gen_cast(&type1); |
||
5667 | vswap(); |
||
5668 | /* special case for shifts and long long: we keep the shift as |
||
5669 | an integer */ |
||
5670 | if (op == TOK_SHR || op == TOK_SAR || op == TOK_SHL) |
||
5671 | type1.t = VT_INT; |
||
5672 | gen_cast(&type1); |
||
5673 | if (is_float(t)) |
||
5674 | gen_opif(op); |
||
5675 | else if ((t & VT_BTYPE) == VT_LLONG) |
||
5676 | gen_opl(op); |
||
5677 | else |
||
5678 | gen_opic(op); |
||
5679 | if (op >= TOK_ULT && op <= TOK_GT) { |
||
5680 | /* relationnal op: the result is an int */ |
||
5681 | vtop->type.t = VT_INT; |
||
5682 | } else { |
||
5683 | vtop->type.t = t; |
||
5684 | } |
||
5685 | } |
||
5686 | } |
||
5687 | |||
5688 | /* generic itof for unsigned long long case */ |
||
5689 | void gen_cvt_itof1(int t) |
||
5690 | { |
||
5691 | if ((vtop->type.t & (VT_BTYPE | VT_UNSIGNED)) == |
||
5692 | (VT_LLONG | VT_UNSIGNED)) { |
||
5693 | |||
5694 | if (t == VT_FLOAT) |
||
5695 | vpush_global_sym(&func_old_type, TOK___ulltof); |
||
5696 | else if (t == VT_DOUBLE) |
||
5697 | vpush_global_sym(&func_old_type, TOK___ulltod); |
||
5698 | else |
||
5699 | vpush_global_sym(&func_old_type, TOK___ulltold); |
||
5700 | vrott(2); |
||
5701 | gfunc_call(1); |
||
5702 | vpushi(0); |
||
5703 | vtop->r = REG_FRET; |
||
5704 | } else { |
||
5705 | gen_cvt_itof(t); |
||
5706 | } |
||
5707 | } |
||
5708 | |||
5709 | /* generic ftoi for unsigned long long case */ |
||
5710 | void gen_cvt_ftoi1(int t) |
||
5711 | { |
||
5712 | int st; |
||
5713 | |||
5714 | if (t == (VT_LLONG | VT_UNSIGNED)) { |
||
5715 | /* not handled natively */ |
||
5716 | st = vtop->type.t & VT_BTYPE; |
||
5717 | if (st == VT_FLOAT) |
||
5718 | vpush_global_sym(&func_old_type, TOK___fixunssfdi); |
||
5719 | else if (st == VT_DOUBLE) |
||
5720 | vpush_global_sym(&func_old_type, TOK___fixunsdfdi); |
||
5721 | else |
||
5722 | vpush_global_sym(&func_old_type, TOK___fixunsxfdi); |
||
5723 | vrott(2); |
||
5724 | gfunc_call(1); |
||
5725 | vpushi(0); |
||
5726 | vtop->r = REG_IRET; |
||
5727 | vtop->r2 = REG_LRET; |
||
5728 | } else { |
||
5729 | gen_cvt_ftoi(t); |
||
5730 | } |
||
5731 | } |
||
5732 | |||
5733 | /* force char or short cast */ |
||
5734 | void force_charshort_cast(int t) |
||
5735 | { |
||
5736 | int bits, dbt; |
||
5737 | dbt = t & VT_BTYPE; |
||
5738 | /* XXX: add optimization if lvalue : just change type and offset */ |
||
5739 | if (dbt == VT_BYTE) |
||
5740 | bits = 8; |
||
5741 | else |
||
5742 | bits = 16; |
||
5743 | if (t & VT_UNSIGNED) { |
||
5744 | vpushi((1 << bits) - 1); |
||
5745 | gen_op('&'); |
||
5746 | } else { |
||
5747 | bits = 32 - bits; |
||
5748 | vpushi(bits); |
||
5749 | gen_op(TOK_SHL); |
||
5750 | vpushi(bits); |
||
5751 | gen_op(TOK_SAR); |
||
5752 | } |
||
5753 | } |
||
5754 | |||
5755 | /* cast 'vtop' to 'type'. Casting to bitfields is forbidden. */ |
||
5756 | static void gen_cast(CType *type) |
||
5757 | { |
||
5758 | int sbt, dbt, sf, df, c; |
||
5759 | |||
5760 | /* special delayed cast for char/short */ |
||
5761 | /* XXX: in some cases (multiple cascaded casts), it may still |
||
5762 | be incorrect */ |
||
5763 | if (vtop->r & VT_MUSTCAST) { |
||
5764 | vtop->r &= ~VT_MUSTCAST; |
||
5765 | force_charshort_cast(vtop->type.t); |
||
5766 | } |
||
5767 | |||
5768 | /* bitfields first get cast to ints */ |
||
5769 | if (vtop->type.t & VT_BITFIELD) { |
||
5770 | gv(RC_INT); |
||
5771 | } |
||
5772 | |||
5773 | dbt = type->t & (VT_BTYPE | VT_UNSIGNED); |
||
5774 | sbt = vtop->type.t & (VT_BTYPE | VT_UNSIGNED); |
||
5775 | |||
5776 | if (sbt != dbt && !nocode_wanted) { |
||
5777 | sf = is_float(sbt); |
||
5778 | df = is_float(dbt); |
||
5779 | c = (vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; |
||
5780 | if (sf && df) { |
||
5781 | /* convert from fp to fp */ |
||
5782 | if (c) { |
||
5783 | /* constant case: we can do it now */ |
||
5784 | /* XXX: in ISOC, cannot do it if error in convert */ |
||
5785 | if (dbt == VT_FLOAT && sbt == VT_DOUBLE) |
||
5786 | vtop->c.f = (float)vtop->c.d; |
||
5787 | else if (dbt == VT_FLOAT && sbt == VT_LDOUBLE) |
||
5788 | vtop->c.f = (float)vtop->c.ld; |
||
5789 | else if (dbt == VT_DOUBLE && sbt == VT_FLOAT) |
||
5790 | vtop->c.d = (double)vtop->c.f; |
||
5791 | else if (dbt == VT_DOUBLE && sbt == VT_LDOUBLE) |
||
5792 | vtop->c.d = (double)vtop->c.ld; |
||
5793 | else if (dbt == VT_LDOUBLE && sbt == VT_FLOAT) |
||
5794 | vtop->c.ld = (long double)vtop->c.f; |
||
5795 | else if (dbt == VT_LDOUBLE && sbt == VT_DOUBLE) |
||
5796 | vtop->c.ld = (long double)vtop->c.d; |
||
5797 | } else { |
||
5798 | /* non constant case: generate code */ |
||
5799 | gen_cvt_ftof(dbt); |
||
5800 | } |
||
5801 | } else if (df) { |
||
5802 | /* convert int to fp */ |
||
5803 | if (c) { |
||
5804 | switch(sbt) { |
||
5805 | case VT_LLONG | VT_UNSIGNED: |
||
5806 | case VT_LLONG: |
||
5807 | /* XXX: add const cases for long long */ |
||
5808 | goto do_itof; |
||
5809 | case VT_INT | VT_UNSIGNED: |
||
5810 | switch(dbt) { |
||
5811 | case VT_FLOAT: vtop->c.f = (float)vtop->c.ui; break; |
||
5812 | case VT_DOUBLE: vtop->c.d = (double)vtop->c.ui; break; |
||
5813 | case VT_LDOUBLE: vtop->c.ld = (long double)vtop->c.ui; break; |
||
5814 | } |
||
5815 | break; |
||
5816 | default: |
||
5817 | switch(dbt) { |
||
5818 | case VT_FLOAT: vtop->c.f = (float)vtop->c.i; break; |
||
5819 | case VT_DOUBLE: vtop->c.d = (double)vtop->c.i; break; |
||
5820 | case VT_LDOUBLE: vtop->c.ld = (long double)vtop->c.i; break; |
||
5821 | } |
||
5822 | break; |
||
5823 | } |
||
5824 | } else { |
||
5825 | do_itof: |
||
5826 | #if !defined(TCC_TARGET_ARM) |
||
5827 | gen_cvt_itof1(dbt); |
||
5828 | #else |
||
5829 | gen_cvt_itof(dbt); |
||
5830 | #endif |
||
5831 | } |
||
5832 | } else if (sf) { |
||
5833 | /* convert fp to int */ |
||
5834 | /* we handle char/short/etc... with generic code */ |
||
5835 | if (dbt != (VT_INT | VT_UNSIGNED) && |
||
5836 | dbt != (VT_LLONG | VT_UNSIGNED) && |
||
5837 | dbt != VT_LLONG) |
||
5838 | dbt = VT_INT; |
||
5839 | if (c) { |
||
5840 | switch(dbt) { |
||
5841 | case VT_LLONG | VT_UNSIGNED: |
||
5842 | case VT_LLONG: |
||
5843 | /* XXX: add const cases for long long */ |
||
5844 | goto do_ftoi; |
||
5845 | case VT_INT | VT_UNSIGNED: |
||
5846 | switch(sbt) { |
||
5847 | case VT_FLOAT: vtop->c.ui = (unsigned int)vtop->c.d; break; |
||
5848 | case VT_DOUBLE: vtop->c.ui = (unsigned int)vtop->c.d; break; |
||
5849 | case VT_LDOUBLE: vtop->c.ui = (unsigned int)vtop->c.d; break; |
||
5850 | } |
||
5851 | break; |
||
5852 | default: |
||
5853 | /* int case */ |
||
5854 | switch(sbt) { |
||
5855 | case VT_FLOAT: vtop->c.i = (int)vtop->c.d; break; |
||
5856 | case VT_DOUBLE: vtop->c.i = (int)vtop->c.d; break; |
||
5857 | case VT_LDOUBLE: vtop->c.i = (int)vtop->c.d; break; |
||
5858 | } |
||
5859 | break; |
||
5860 | } |
||
5861 | } else { |
||
5862 | do_ftoi: |
||
5863 | gen_cvt_ftoi1(dbt); |
||
5864 | } |
||
5865 | if (dbt == VT_INT && (type->t & (VT_BTYPE | VT_UNSIGNED)) != dbt) { |
||
5866 | /* additional cast for char/short/bool... */ |
||
5867 | vtop->type.t = dbt; |
||
5868 | gen_cast(type); |
||
5869 | } |
||
5870 | } else if ((dbt & VT_BTYPE) == VT_LLONG) { |
||
5871 | if ((sbt & VT_BTYPE) != VT_LLONG) { |
||
5872 | /* scalar to long long */ |
||
5873 | if (c) { |
||
5874 | if (sbt == (VT_INT | VT_UNSIGNED)) |
||
5875 | vtop->c.ll = vtop->c.ui; |
||
5876 | else |
||
5877 | vtop->c.ll = vtop->c.i; |
||
5878 | } else { |
||
5879 | /* machine independent conversion */ |
||
5880 | gv(RC_INT); |
||
5881 | /* generate high word */ |
||
5882 | if (sbt == (VT_INT | VT_UNSIGNED)) { |
||
5883 | vpushi(0); |
||
5884 | gv(RC_INT); |
||
5885 | } else { |
||
5886 | gv_dup(); |
||
5887 | vpushi(31); |
||
5888 | gen_op(TOK_SAR); |
||
5889 | } |
||
5890 | /* patch second register */ |
||
5891 | vtop[-1].r2 = vtop->r; |
||
5892 | vpop(); |
||
5893 | } |
||
5894 | } |
||
5895 | } else if (dbt == VT_BOOL) { |
||
5896 | /* scalar to bool */ |
||
5897 | vpushi(0); |
||
5898 | gen_op(TOK_NE); |
||
5899 | } else if ((dbt & VT_BTYPE) == VT_BYTE || |
||
5900 | (dbt & VT_BTYPE) == VT_SHORT) { |
||
5901 | force_charshort_cast(dbt); |
||
5902 | } else if ((dbt & VT_BTYPE) == VT_INT) { |
||
5903 | /* scalar to int */ |
||
5904 | if (sbt == VT_LLONG) { |
||
5905 | /* from long long: just take low order word */ |
||
5906 | lexpand(); |
||
5907 | vpop(); |
||
5908 | } |
||
5909 | /* if lvalue and single word type, nothing to do because |
||
5910 | the lvalue already contains the real type size (see |
||
5911 | VT_LVAL_xxx constants) */ |
||
5912 | } |
||
5913 | } |
||
5914 | vtop->type = *type; |
||
5915 | } |
||
5916 | |||
5917 | /* return type size. Put alignment at 'a' */ |
||
5918 | static int type_size(CType *type, int *a) |
||
5919 | { |
||
5920 | Sym *s; |
||
5921 | int bt; |
||
609 | andrew_pro | 5922 | int size; |
145 | halyavin | 5923 | |
5924 | bt = type->t & VT_BTYPE; |
||
5925 | if (bt == VT_STRUCT) { |
||
5926 | /* struct/union */ |
||
5927 | s = type->ref; |
||
5928 | *a = s->r; |
||
609 | andrew_pro | 5929 | |
145 | halyavin | 5930 | return s->c; |
5931 | } else if (bt == VT_PTR) { |
||
609 | andrew_pro | 5932 | |
145 | halyavin | 5933 | if (type->t & VT_ARRAY) { |
5934 | s = type->ref; |
||
609 | andrew_pro | 5935 | size=type_size(&s->type, a) * s->c; |
5936 | return size;//type_size(&s->type, a) * s->c; |
||
145 | halyavin | 5937 | } else { |
5938 | *a = PTR_SIZE; |
||
5939 | return PTR_SIZE; |
||
5940 | } |
||
5941 | } else if (bt == VT_LDOUBLE) { |
||
5942 | *a = LDOUBLE_ALIGN; |
||
5943 | return LDOUBLE_SIZE; |
||
5944 | } else if (bt == VT_DOUBLE || bt == VT_LLONG) { |
||
5945 | #ifdef TCC_TARGET_I386 |
||
5946 | *a = 4; |
||
5947 | #else |
||
5948 | *a = 8; |
||
5949 | #endif |
||
5950 | return 8; |
||
5951 | } else if (bt == VT_INT || bt == VT_ENUM || bt == VT_FLOAT) { |
||
5952 | *a = 4; |
||
5953 | return 4; |
||
5954 | } else if (bt == VT_SHORT) { |
||
5955 | *a = 2; |
||
5956 | return 2; |
||
5957 | } else { |
||
5958 | /* char, void, function, _Bool */ |
||
5959 | *a = 1; |
||
5960 | return 1; |
||
5961 | } |
||
5962 | } |
||
5963 | |||
5964 | /* return the pointed type of t */ |
||
5965 | static inline CType *pointed_type(CType *type) |
||
5966 | { |
||
5967 | return &type->ref->type; |
||
5968 | } |
||
5969 | |||
5970 | /* modify type so that its it is a pointer to type. */ |
||
5971 | static void mk_pointer(CType *type) |
||
5972 | { |
||
5973 | Sym *s; |
||
5974 | s = sym_push(SYM_FIELD, type, 0, -1); |
||
5975 | type->t = VT_PTR | (type->t & ~VT_TYPE); |
||
5976 | type->ref = s; |
||
5977 | } |
||
5978 | |||
5979 | /* compare function types. OLD functions match any new functions */ |
||
5980 | static int is_compatible_func(CType *type1, CType *type2) |
||
5981 | { |
||
5982 | Sym *s1, *s2; |
||
5983 | |||
5984 | s1 = type1->ref; |
||
5985 | s2 = type2->ref; |
||
5986 | if (!is_compatible_types(&s1->type, &s2->type)) |
||
5987 | return 0; |
||
5988 | /* check func_call */ |
||
5989 | if (s1->r != s2->r) |
||
5990 | return 0; |
||
5991 | /* XXX: not complete */ |
||
5992 | if (s1->c == FUNC_OLD || s2->c == FUNC_OLD) |
||
5993 | return 1; |
||
5994 | if (s1->c != s2->c) |
||
5995 | return 0; |
||
5996 | while (s1 != NULL) { |
||
5997 | if (s2 == NULL) |
||
5998 | return 0; |
||
5999 | if (!is_compatible_types(&s1->type, &s2->type)) |
||
6000 | return 0; |
||
6001 | s1 = s1->next; |
||
6002 | s2 = s2->next; |
||
6003 | } |
||
6004 | if (s2) |
||
6005 | return 0; |
||
6006 | return 1; |
||
6007 | } |
||
6008 | |||
6009 | /* return true if type1 and type2 are exactly the same (including |
||
6010 | qualifiers). |
||
6011 | |||
6012 | - enums are not checked as gcc __builtin_types_compatible_p () |
||
6013 | */ |
||
6014 | static int is_compatible_types(CType *type1, CType *type2) |
||
6015 | { |
||
6016 | int bt1, t1, t2; |
||
6017 | |||
6018 | t1 = type1->t & VT_TYPE; |
||
6019 | t2 = type2->t & VT_TYPE; |
||
6020 | /* XXX: bitfields ? */ |
||
6021 | if (t1 != t2) |
||
6022 | return 0; |
||
6023 | /* test more complicated cases */ |
||
6024 | bt1 = t1 & VT_BTYPE; |
||
6025 | if (bt1 == VT_PTR) { |
||
6026 | type1 = pointed_type(type1); |
||
6027 | type2 = pointed_type(type2); |
||
6028 | return is_compatible_types(type1, type2); |
||
6029 | } else if (bt1 == VT_STRUCT) { |
||
6030 | return (type1->ref == type2->ref); |
||
6031 | } else if (bt1 == VT_FUNC) { |
||
6032 | return is_compatible_func(type1, type2); |
||
6033 | } else { |
||
6034 | return 1; |
||
6035 | } |
||
6036 | } |
||
6037 | |||
6038 | /* print a type. If 'varstr' is not NULL, then the variable is also |
||
6039 | printed in the type */ |
||
6040 | /* XXX: union */ |
||
6041 | /* XXX: add array and function pointers */ |
||
6042 | void type_to_str(char *buf, int buf_size, |
||
6043 | CType *type, const char *varstr) |
||
6044 | { |
||
6045 | int bt, v, t; |
||
6046 | Sym *s, *sa; |
||
6047 | char buf1[256]; |
||
6048 | const char *tstr; |
||
6049 | |||
6050 | t = type->t & VT_TYPE; |
||
6051 | bt = t & VT_BTYPE; |
||
6052 | buf[0] = '\0'; |
||
6053 | if (t & VT_CONSTANT) |
||
6054 | pstrcat(buf, buf_size, "const "); |
||
6055 | if (t & VT_VOLATILE) |
||
6056 | pstrcat(buf, buf_size, "volatile "); |
||
6057 | if (t & VT_UNSIGNED) |
||
6058 | pstrcat(buf, buf_size, "unsigned "); |
||
6059 | switch(bt) { |
||
6060 | case VT_VOID: |
||
6061 | tstr = "void"; |
||
6062 | goto add_tstr; |
||
6063 | case VT_BOOL: |
||
6064 | tstr = "_Bool"; |
||
6065 | goto add_tstr; |
||
6066 | case VT_BYTE: |
||
6067 | tstr = "char"; |
||
6068 | goto add_tstr; |
||
6069 | case VT_SHORT: |
||
6070 | tstr = "short"; |
||
6071 | goto add_tstr; |
||
6072 | case VT_INT: |
||
6073 | tstr = "int"; |
||
6074 | goto add_tstr; |
||
6075 | case VT_LONG: |
||
6076 | tstr = "long"; |
||
6077 | goto add_tstr; |
||
6078 | case VT_LLONG: |
||
6079 | tstr = "long long"; |
||
6080 | goto add_tstr; |
||
6081 | case VT_FLOAT: |
||
6082 | tstr = "float"; |
||
6083 | goto add_tstr; |
||
6084 | case VT_DOUBLE: |
||
6085 | tstr = "double"; |
||
6086 | goto add_tstr; |
||
6087 | case VT_LDOUBLE: |
||
6088 | tstr = "long double"; |
||
6089 | add_tstr: |
||
6090 | pstrcat(buf, buf_size, tstr); |
||
6091 | break; |
||
6092 | case VT_ENUM: |
||
6093 | case VT_STRUCT: |
||
6094 | if (bt == VT_STRUCT) |
||
6095 | tstr = "struct "; |
||
6096 | else |
||
6097 | tstr = "enum "; |
||
6098 | pstrcat(buf, buf_size, tstr); |
||
6099 | v = type->ref->v & ~SYM_STRUCT; |
||
6100 | if (v >= SYM_FIRST_ANOM) |
||
6101 | pstrcat(buf, buf_size, " |
||
6102 | else |
||
6103 | pstrcat(buf, buf_size, get_tok_str(v, NULL)); |
||
6104 | break; |
||
6105 | case VT_FUNC: |
||
6106 | s = type->ref; |
||
6107 | type_to_str(buf, buf_size, &s->type, varstr); |
||
6108 | pstrcat(buf, buf_size, "("); |
||
6109 | sa = s->next; |
||
6110 | while (sa != NULL) { |
||
6111 | type_to_str(buf1, sizeof(buf1), &sa->type, NULL); |
||
6112 | pstrcat(buf, buf_size, buf1); |
||
6113 | sa = sa->next; |
||
6114 | if (sa) |
||
6115 | pstrcat(buf, buf_size, ", "); |
||
6116 | } |
||
6117 | pstrcat(buf, buf_size, ")"); |
||
6118 | goto no_var; |
||
6119 | case VT_PTR: |
||
6120 | s = type->ref; |
||
6121 | pstrcpy(buf1, sizeof(buf1), "*"); |
||
6122 | if (varstr) |
||
6123 | pstrcat(buf1, sizeof(buf1), varstr); |
||
6124 | type_to_str(buf, buf_size, &s->type, buf1); |
||
6125 | goto no_var; |
||
6126 | } |
||
6127 | if (varstr) { |
||
6128 | pstrcat(buf, buf_size, " "); |
||
6129 | pstrcat(buf, buf_size, varstr); |
||
6130 | } |
||
6131 | no_var: ; |
||
6132 | } |
||
6133 | |||
6134 | /* verify type compatibility to store vtop in 'dt' type, and generate |
||
6135 | casts if needed. */ |
||
6136 | static void gen_assign_cast(CType *dt) |
||
6137 | { |
||
6138 | CType *st, *type1, *type2, tmp_type1, tmp_type2; |
||
6139 | char buf1[256], buf2[256]; |
||
6140 | int dbt, sbt; |
||
6141 | |||
6142 | st = &vtop->type; /* source type */ |
||
6143 | dbt = dt->t & VT_BTYPE; |
||
6144 | sbt = st->t & VT_BTYPE; |
||
6145 | if (dt->t & VT_CONSTANT) |
||
6146 | warning("assignment of read-only location"); |
||
6147 | switch(dbt) { |
||
6148 | case VT_PTR: |
||
6149 | /* special cases for pointers */ |
||
6150 | /* '0' can also be a pointer */ |
||
6151 | if (is_null_pointer(vtop)) |
||
6152 | goto type_ok; |
||
6153 | /* accept implicit pointer to integer cast with warning */ |
||
6154 | if (is_integer_btype(sbt)) { |
||
6155 | warning("assignment makes pointer from integer without a cast"); |
||
6156 | goto type_ok; |
||
6157 | } |
||
6158 | type1 = pointed_type(dt); |
||
6159 | /* a function is implicitely a function pointer */ |
||
6160 | if (sbt == VT_FUNC) { |
||
6161 | if ((type1->t & VT_BTYPE) != VT_VOID && |
||
6162 | !is_compatible_types(pointed_type(dt), st)) |
||
6163 | goto error; |
||
6164 | else |
||
6165 | goto type_ok; |
||
6166 | } |
||
6167 | if (sbt != VT_PTR) |
||
6168 | goto error; |
||
6169 | type2 = pointed_type(st); |
||
6170 | if ((type1->t & VT_BTYPE) == VT_VOID || |
||
6171 | (type2->t & VT_BTYPE) == VT_VOID) { |
||
6172 | /* void * can match anything */ |
||
6173 | } else { |
||
6174 | /* exact type match, except for unsigned */ |
||
6175 | tmp_type1 = *type1; |
||
6176 | tmp_type2 = *type2; |
||
6177 | tmp_type1.t &= ~(VT_UNSIGNED | VT_CONSTANT | VT_VOLATILE); |
||
6178 | tmp_type2.t &= ~(VT_UNSIGNED | VT_CONSTANT | VT_VOLATILE); |
||
6179 | if (!is_compatible_types(&tmp_type1, &tmp_type2)) |
||
6180 | goto error; |
||
6181 | } |
||
6182 | /* check const and volatile */ |
||
6183 | if ((!(type1->t & VT_CONSTANT) && (type2->t & VT_CONSTANT)) || |
||
6184 | (!(type1->t & VT_VOLATILE) && (type2->t & VT_VOLATILE))) |
||
6185 | warning("assignment discards qualifiers from pointer target type"); |
||
6186 | break; |
||
6187 | case VT_BYTE: |
||
6188 | case VT_SHORT: |
||
6189 | case VT_INT: |
||
6190 | case VT_LLONG: |
||
6191 | if (sbt == VT_PTR || sbt == VT_FUNC) { |
||
6192 | warning("assignment makes integer from pointer without a cast"); |
||
6193 | } |
||
6194 | /* XXX: more tests */ |
||
6195 | break; |
||
6196 | case VT_STRUCT: |
||
6197 | tmp_type1 = *dt; |
||
6198 | tmp_type2 = *st; |
||
6199 | tmp_type1.t &= ~(VT_CONSTANT | VT_VOLATILE); |
||
6200 | tmp_type2.t &= ~(VT_CONSTANT | VT_VOLATILE); |
||
6201 | if (!is_compatible_types(&tmp_type1, &tmp_type2)) { |
||
6202 | error: |
||
6203 | type_to_str(buf1, sizeof(buf1), st, NULL); |
||
6204 | type_to_str(buf2, sizeof(buf2), dt, NULL); |
||
6205 | error("cannot cast '%s' to '%s'", buf1, buf2); |
||
6206 | } |
||
6207 | break; |
||
6208 | } |
||
6209 | type_ok: |
||
6210 | gen_cast(dt); |
||
6211 | } |
||
6212 | |||
6213 | /* store vtop in lvalue pushed on stack */ |
||
6214 | void vstore(void) |
||
6215 | { |
||
6216 | int sbt, dbt, ft, r, t, size, align, bit_size, bit_pos, rc, delayed_cast; |
||
6217 | |||
6218 | ft = vtop[-1].type.t; |
||
6219 | sbt = vtop->type.t & VT_BTYPE; |
||
6220 | dbt = ft & VT_BTYPE; |
||
6221 | if (((sbt == VT_INT || sbt == VT_SHORT) && dbt == VT_BYTE) || |
||
6222 | (sbt == VT_INT && dbt == VT_SHORT)) { |
||
6223 | /* optimize char/short casts */ |
||
6224 | delayed_cast = VT_MUSTCAST; |
||
6225 | vtop->type.t = ft & VT_TYPE; |
||
6226 | /* XXX: factorize */ |
||
6227 | if (ft & VT_CONSTANT) |
||
6228 | warning("assignment of read-only location"); |
||
6229 | } else { |
||
6230 | delayed_cast = 0; |
||
6231 | if (!(ft & VT_BITFIELD)) |
||
6232 | gen_assign_cast(&vtop[-1].type); |
||
6233 | } |
||
6234 | |||
6235 | if (sbt == VT_STRUCT) { |
||
6236 | /* if structure, only generate pointer */ |
||
6237 | /* structure assignment : generate memcpy */ |
||
6238 | /* XXX: optimize if small size */ |
||
6239 | if (!nocode_wanted) { |
||
6240 | size = type_size(&vtop->type, &align); |
||
6241 | |||
6242 | vpush_global_sym(&func_old_type, TOK_memcpy); |
||
6243 | |||
6244 | /* destination */ |
||
6245 | vpushv(vtop - 2); |
||
6246 | vtop->type.t = VT_INT; |
||
6247 | gaddrof(); |
||
6248 | /* source */ |
||
6249 | vpushv(vtop - 2); |
||
6250 | vtop->type.t = VT_INT; |
||
6251 | gaddrof(); |
||
6252 | /* type size */ |
||
6253 | vpushi(size); |
||
6254 | gfunc_call(3); |
||
6255 | |||
6256 | vswap(); |
||
6257 | vpop(); |
||
6258 | } else { |
||
6259 | vswap(); |
||
6260 | vpop(); |
||
6261 | } |
||
6262 | /* leave source on stack */ |
||
6263 | } else if (ft & VT_BITFIELD) { |
||
6264 | /* bitfield store handling */ |
||
6265 | bit_pos = (ft >> VT_STRUCT_SHIFT) & 0x3f; |
||
6266 | bit_size = (ft >> (VT_STRUCT_SHIFT + 6)) & 0x3f; |
||
6267 | /* remove bit field info to avoid loops */ |
||
6268 | vtop[-1].type.t = ft & ~(VT_BITFIELD | (-1 << VT_STRUCT_SHIFT)); |
||
6269 | |||
6270 | /* duplicate destination */ |
||
6271 | vdup(); |
||
6272 | vtop[-1] = vtop[-2]; |
||
6273 | |||
6274 | /* mask and shift source */ |
||
6275 | vpushi((1 << bit_size) - 1); |
||
6276 | gen_op('&'); |
||
6277 | vpushi(bit_pos); |
||
6278 | gen_op(TOK_SHL); |
||
6279 | /* load destination, mask and or with source */ |
||
6280 | vswap(); |
||
6281 | vpushi(~(((1 << bit_size) - 1) << bit_pos)); |
||
6282 | gen_op('&'); |
||
6283 | gen_op('|'); |
||
6284 | /* store result */ |
||
6285 | vstore(); |
||
6286 | } else { |
||
6287 | #ifdef CONFIG_TCC_BCHECK |
||
6288 | /* bound check case */ |
||
6289 | if (vtop[-1].r & VT_MUSTBOUND) { |
||
6290 | vswap(); |
||
6291 | gbound(); |
||
6292 | vswap(); |
||
6293 | } |
||
6294 | #endif |
||
6295 | if (!nocode_wanted) { |
||
6296 | rc = RC_INT; |
||
6297 | if (is_float(ft)) |
||
6298 | rc = RC_FLOAT; |
||
6299 | r = gv(rc); /* generate value */ |
||
6300 | /* if lvalue was saved on stack, must read it */ |
||
6301 | if ((vtop[-1].r & VT_VALMASK) == VT_LLOCAL) { |
||
6302 | SValue sv; |
||
6303 | t = get_reg(RC_INT); |
||
6304 | sv.type.t = VT_INT; |
||
6305 | sv.r = VT_LOCAL | VT_LVAL; |
||
6306 | sv.c.ul = vtop[-1].c.ul; |
||
6307 | load(t, &sv); |
||
6308 | vtop[-1].r = t | VT_LVAL; |
||
6309 | } |
||
6310 | store(r, vtop - 1); |
||
6311 | /* two word case handling : store second register at word + 4 */ |
||
6312 | if ((ft & VT_BTYPE) == VT_LLONG) { |
||
6313 | vswap(); |
||
6314 | /* convert to int to increment easily */ |
||
6315 | vtop->type.t = VT_INT; |
||
6316 | gaddrof(); |
||
6317 | vpushi(4); |
||
6318 | gen_op('+'); |
||
6319 | vtop->r |= VT_LVAL; |
||
6320 | vswap(); |
||
6321 | /* XXX: it works because r2 is spilled last ! */ |
||
6322 | store(vtop->r2, vtop - 1); |
||
6323 | } |
||
6324 | } |
||
6325 | vswap(); |
||
6326 | vtop--; /* NOT vpop() because on x86 it would flush the fp stack */ |
||
6327 | vtop->r |= delayed_cast; |
||
6328 | } |
||
6329 | } |
||
6330 | |||
6331 | /* post defines POST/PRE add. c is the token ++ or -- */ |
||
6332 | void inc(int post, int c) |
||
6333 | { |
||
6334 | test_lvalue(); |
||
6335 | vdup(); /* save lvalue */ |
||
6336 | if (post) { |
||
6337 | gv_dup(); /* duplicate value */ |
||
6338 | vrotb(3); |
||
6339 | vrotb(3); |
||
6340 | } |
||
6341 | /* add constant */ |
||
6342 | vpushi(c - TOK_MID); |
||
6343 | gen_op('+'); |
||
6344 | vstore(); /* store value */ |
||
6345 | if (post) |
||
6346 | vpop(); /* if post op, return saved value */ |
||
6347 | } |
||
6348 | |||
6349 | /* Parse GNUC __attribute__ extension. Currently, the following |
||
6350 | extensions are recognized: |
||
6351 | - aligned(n) : set data/function alignment. |
||
6352 | - packed : force data alignment to 1 |
||
6353 | - section(x) : generate data/code in this section. |
||
6354 | - unused : currently ignored, but may be used someday. |
||
6355 | - regparm(n) : pass function parameters in registers (i386 only) |
||
6356 | */ |
||
6357 | static void parse_attribute(AttributeDef *ad) |
||
6358 | { |
||
6359 | int t, n; |
||
6360 | |||
6361 | while (tok == TOK_ATTRIBUTE1 || tok == TOK_ATTRIBUTE2) { |
||
6362 | next(); |
||
6363 | skip('('); |
||
6364 | skip('('); |
||
6365 | while (tok != ')') { |
||
6366 | if (tok < TOK_IDENT) |
||
6367 | expect("attribute name"); |
||
6368 | t = tok; |
||
6369 | next(); |
||
6370 | switch(t) { |
||
6371 | case TOK_SECTION1: |
||
6372 | case TOK_SECTION2: |
||
6373 | skip('('); |
||
6374 | if (tok != TOK_STR) |
||
6375 | expect("section name"); |
||
6376 | ad->section = find_section(tcc_state, (char *)tokc.cstr->data); |
||
6377 | next(); |
||
6378 | skip(')'); |
||
6379 | break; |
||
6380 | case TOK_ALIGNED1: |
||
6381 | case TOK_ALIGNED2: |
||
6382 | if (tok == '(') { |
||
6383 | next(); |
||
6384 | n = expr_const(); |
||
6385 | if (n <= 0 || (n & (n - 1)) != 0) |
||
6386 | error("alignment must be a positive power of two"); |
||
6387 | skip(')'); |
||
6388 | } else { |
||
6389 | n = MAX_ALIGN; |
||
6390 | } |
||
6391 | ad->aligned = n; |
||
6392 | break; |
||
6393 | case TOK_PACKED1: |
||
6394 | case TOK_PACKED2: |
||
6395 | ad->packed = 1; |
||
6396 | break; |
||
6397 | case TOK_UNUSED1: |
||
6398 | case TOK_UNUSED2: |
||
6399 | /* currently, no need to handle it because tcc does not |
||
6400 | track unused objects */ |
||
6401 | break; |
||
6402 | case TOK_NORETURN1: |
||
6403 | case TOK_NORETURN2: |
||
6404 | /* currently, no need to handle it because tcc does not |
||
6405 | track unused objects */ |
||
6406 | break; |
||
6407 | case TOK_CDECL1: |
||
6408 | case TOK_CDECL2: |
||
6409 | case TOK_CDECL3: |
||
6410 | ad->func_call = FUNC_CDECL; |
||
6411 | break; |
||
6412 | case TOK_STDCALL1: |
||
6413 | case TOK_STDCALL2: |
||
6414 | case TOK_STDCALL3: |
||
6415 | ad->func_call = FUNC_STDCALL; |
||
6416 | break; |
||
6417 | #ifdef TCC_TARGET_I386 |
||
6418 | case TOK_REGPARM1: |
||
6419 | case TOK_REGPARM2: |
||
6420 | skip('('); |
||
6421 | n = expr_const(); |
||
6422 | if (n > 3) |
||
6423 | n = 3; |
||
6424 | else if (n < 0) |
||
6425 | n = 0; |
||
6426 | if (n > 0) |
||
6427 | ad->func_call = FUNC_FASTCALL1 + n - 1; |
||
6428 | skip(')'); |
||
6429 | break; |
||
6430 | #endif |
||
6431 | case TOK_DLLEXPORT: |
||
6432 | ad->dllexport = 1; |
||
6433 | break; |
||
6434 | default: |
||
6435 | if (tcc_state->warn_unsupported) |
||
6436 | warning("'%s' attribute ignored", get_tok_str(t, NULL)); |
||
6437 | /* skip parameters */ |
||
6438 | /* XXX: skip parenthesis too */ |
||
6439 | if (tok == '(') { |
||
6440 | next(); |
||
6441 | while (tok != ')' && tok != -1) |
||
6442 | next(); |
||
6443 | next(); |
||
6444 | } |
||
6445 | break; |
||
6446 | } |
||
6447 | if (tok != ',') |
||
6448 | break; |
||
6449 | next(); |
||
6450 | } |
||
6451 | skip(')'); |
||
6452 | skip(')'); |
||
6453 | } |
||
6454 | } |
||
6455 | |||
6456 | /* enum/struct/union declaration. u is either VT_ENUM or VT_STRUCT */ |
||
6457 | static void struct_decl(CType *type, int u) |
||
6458 | { |
||
6459 | int a, v, size, align, maxalign, c, offset; |
||
6460 | int bit_size, bit_pos, bsize, bt, lbit_pos; |
||
6461 | Sym *s, *ss, **ps; |
||
6462 | AttributeDef ad; |
||
6463 | CType type1, btype; |
||
6464 | |||
6465 | a = tok; /* save decl type */ |
||
6466 | next(); |
||
6467 | if (tok != '{') { |
||
6468 | v = tok; |
||
6469 | next(); |
||
6470 | /* struct already defined ? return it */ |
||
6471 | if (v < TOK_IDENT) |
||
6472 | expect("struct/union/enum name"); |
||
6473 | s = struct_find(v); |
||
6474 | if (s) { |
||
6475 | if (s->type.t != a) |
||
6476 | error("invalid type"); |
||
6477 | goto do_decl; |
||
6478 | } |
||
6479 | } else { |
||
6480 | v = anon_sym++; |
||
6481 | } |
||
6482 | type1.t = a; |
||
6483 | /* we put an undefined size for struct/union */ |
||
6484 | s = sym_push(v | SYM_STRUCT, &type1, 0, -1); |
||
6485 | s->r = 0; /* default alignment is zero as gcc */ |
||
6486 | /* put struct/union/enum name in type */ |
||
6487 | do_decl: |
||
6488 | type->t = u; |
||
6489 | type->ref = s; |
||
6490 | |||
6491 | if (tok == '{') { |
||
6492 | next(); |
||
6493 | if (s->c != -1) |
||
6494 | error("struct/union/enum already defined"); |
||
6495 | /* cannot be empty */ |
||
6496 | c = 0; |
||
6497 | /* non empty enums are not allowed */ |
||
6498 | if (a == TOK_ENUM) { |
||
6499 | for(;;) { |
||
6500 | v = tok; |
||
6501 | if (v < TOK_UIDENT) |
||
6502 | expect("identifier"); |
||
6503 | next(); |
||
6504 | if (tok == '=') { |
||
6505 | next(); |
||
6506 | c = expr_const(); |
||
6507 | } |
||
6508 | /* enum symbols have static storage */ |
||
6509 | ss = sym_push(v, &int_type, VT_CONST, c); |
||
6510 | ss->type.t |= VT_STATIC; |
||
6511 | if (tok != ',') |
||
6512 | break; |
||
6513 | next(); |
||
6514 | c++; |
||
6515 | /* NOTE: we accept a trailing comma */ |
||
6516 | if (tok == '}') |
||
6517 | break; |
||
6518 | } |
||
6519 | skip('}'); |
||
6520 | } else { |
||
6521 | maxalign = 1; |
||
6522 | ps = &s->next; |
||
6523 | bit_pos = 0; |
||
6524 | offset = 0; |
||
6525 | while (tok != '}') { |
||
6526 | parse_btype(&btype, &ad); |
||
6527 | while (1) { |
||
6528 | bit_size = -1; |
||
6529 | v = 0; |
||
6530 | type1 = btype; |
||
6531 | if (tok != ':') { |
||
6532 | type_decl(&type1, &ad, &v, TYPE_DIRECT); |
||
6533 | if ((type1.t & VT_BTYPE) == VT_FUNC || |
||
6534 | (type1.t & (VT_TYPEDEF | VT_STATIC | VT_EXTERN | VT_INLINE))) |
||
6535 | error("invalid type for '%s'", |
||
6536 | get_tok_str(v, NULL)); |
||
6537 | } |
||
6538 | if (tok == ':') { |
||
6539 | next(); |
||
6540 | bit_size = expr_const(); |
||
6541 | /* XXX: handle v = 0 case for messages */ |
||
6542 | if (bit_size < 0) |
||
6543 | error("negative width in bit-field '%s'", |
||
6544 | get_tok_str(v, NULL)); |
||
6545 | if (v && bit_size == 0) |
||
6546 | error("zero width for bit-field '%s'", |
||
6547 | get_tok_str(v, NULL)); |
||
6548 | } |
||
6549 | size = type_size(&type1, &align); |
||
6550 | if (ad.aligned) { |
||
6551 | if (align < ad.aligned) |
||
6552 | align = ad.aligned; |
||
6553 | } else if (ad.packed) { |
||
6554 | align = 1; |
||
6555 | } else if (*tcc_state->pack_stack_ptr) { |
||
6556 | if (align > *tcc_state->pack_stack_ptr) |
||
6557 | align = *tcc_state->pack_stack_ptr; |
||
6558 | } |
||
6559 | lbit_pos = 0; |
||
6560 | if (bit_size >= 0) { |
||
6561 | bt = type1.t & VT_BTYPE; |
||
6562 | if (bt != VT_INT && |
||
6563 | bt != VT_BYTE && |
||
6564 | bt != VT_SHORT && |
||
6565 | bt != VT_BOOL && |
||
6566 | bt != VT_ENUM) |
||
6567 | error("bitfields must have scalar type"); |
||
6568 | bsize = size * 8; |
||
6569 | if (bit_size > bsize) { |
||
6570 | error("width of '%s' exceeds its type", |
||
6571 | get_tok_str(v, NULL)); |
||
6572 | } else if (bit_size == bsize) { |
||
6573 | /* no need for bit fields */ |
||
6574 | bit_pos = 0; |
||
6575 | } else if (bit_size == 0) { |
||
6576 | /* XXX: what to do if only padding in a |
||
6577 | structure ? */ |
||
6578 | /* zero size: means to pad */ |
||
6579 | if (bit_pos > 0) |
||
6580 | bit_pos = bsize; |
||
6581 | } else { |
||
6582 | /* we do not have enough room ? */ |
||
6583 | if ((bit_pos + bit_size) > bsize) |
||
6584 | bit_pos = 0; |
||
6585 | lbit_pos = bit_pos; |
||
6586 | /* XXX: handle LSB first */ |
||
6587 | type1.t |= VT_BITFIELD | |
||
6588 | (bit_pos << VT_STRUCT_SHIFT) | |
||
6589 | (bit_size << (VT_STRUCT_SHIFT + 6)); |
||
6590 | bit_pos += bit_size; |
||
6591 | } |
||
6592 | } else { |
||
6593 | bit_pos = 0; |
||
6594 | } |
||
6595 | if (v) { |
||
6596 | /* add new memory data only if starting |
||
6597 | bit field */ |
||
6598 | if (lbit_pos == 0) { |
||
6599 | if (a == TOK_STRUCT) { |
||
609 | andrew_pro | 6600 | //17.09.2007 |
6601 | //c = (c + align - 1) & -align; |
||
145 | halyavin | 6602 | offset = c; |
609 | andrew_pro | 6603 | //c += size; |
6604 | if (size<=4) {c=c+size;} |
||
6605 | else |
||
6606 | {c=c+align;} |
||
145 | halyavin | 6607 | } else { |
6608 | offset = 0; |
||
6609 | if (size > c) |
||
6610 | c = size; |
||
6611 | } |
||
6612 | if (align > maxalign) |
||
6613 | maxalign = align; |
||
6614 | } |
||
6615 | #if 0 |
||
6616 | printf("add field %s offset=%d", |
||
6617 | get_tok_str(v, NULL), offset); |
||
6618 | if (type1.t & VT_BITFIELD) { |
||
6619 | printf(" pos=%d size=%d", |
||
6620 | (type1.t >> VT_STRUCT_SHIFT) & 0x3f, |
||
6621 | (type1.t >> (VT_STRUCT_SHIFT + 6)) & 0x3f); |
||
6622 | } |
||
6623 | printf("\n"); |
||
6624 | #endif |
||
6625 | ss = sym_push(v | SYM_FIELD, &type1, 0, offset); |
||
6626 | *ps = ss; |
||
6627 | ps = &ss->next; |
||
6628 | } |
||
6629 | if (tok == ';' || tok == TOK_EOF) |
||
6630 | break; |
||
6631 | skip(','); |
||
6632 | } |
||
6633 | skip(';'); |
||
6634 | } |
||
6635 | skip('}'); |
||
6636 | /* store size and alignment */ |
||
6637 | s->c = (c + maxalign - 1) & -maxalign; |
||
6638 | s->r = maxalign; |
||
6639 | } |
||
6640 | } |
||
6641 | } |
||
6642 | |||
6643 | /* return 0 if no type declaration. otherwise, return the basic type |
||
6644 | and skip it. |
||
6645 | */ |
||
6646 | static int parse_btype(CType *type, AttributeDef *ad) |
||
6647 | { |
||
6648 | int t, u, type_found, typespec_found; |
||
6649 | Sym *s; |
||
6650 | CType type1; |
||
6651 | |||
6652 | memset(ad, 0, sizeof(AttributeDef)); |
||
6653 | type_found = 0; |
||
6654 | typespec_found = 0; |
||
6655 | t = 0; |
||
6656 | while(1) { |
||
6657 | switch(tok) { |
||
6658 | case TOK_EXTENSION: |
||
6659 | /* currently, we really ignore extension */ |
||
6660 | next(); |
||
6661 | continue; |
||
6662 | |||
6663 | /* basic types */ |
||
6664 | case TOK_CHAR: |
||
6665 | u = VT_BYTE; |
||
6666 | basic_type: |
||
6667 | next(); |
||
6668 | basic_type1: |
||
6669 | if ((t & VT_BTYPE) != 0) |
||
6670 | error("too many basic types"); |
||
6671 | t |= u; |
||
6672 | typespec_found = 1; |
||
6673 | break; |
||
6674 | case TOK_VOID: |
||
6675 | u = VT_VOID; |
||
6676 | goto basic_type; |
||
6677 | case TOK_SHORT: |
||
6678 | u = VT_SHORT; |
||
6679 | goto basic_type; |
||
6680 | case TOK_INT: |
||
6681 | next(); |
||
6682 | typespec_found = 1; |
||
6683 | break; |
||
6684 | case TOK_LONG: |
||
6685 | next(); |
||
6686 | if ((t & VT_BTYPE) == VT_DOUBLE) { |
||
6687 | t = (t & ~VT_BTYPE) | VT_LDOUBLE; |
||
6688 | } else if ((t & VT_BTYPE) == VT_LONG) { |
||
6689 | t = (t & ~VT_BTYPE) | VT_LLONG; |
||
6690 | } else { |
||
6691 | u = VT_LONG; |
||
6692 | goto basic_type1; |
||
6693 | } |
||
6694 | break; |
||
6695 | case TOK_BOOL: |
||
6696 | u = VT_BOOL; |
||
6697 | goto basic_type; |
||
6698 | case TOK_FLOAT: |
||
6699 | u = VT_FLOAT; |
||
6700 | goto basic_type; |
||
6701 | case TOK_DOUBLE: |
||
6702 | next(); |
||
6703 | if ((t & VT_BTYPE) == VT_LONG) { |
||
6704 | t = (t & ~VT_BTYPE) | VT_LDOUBLE; |
||
6705 | } else { |
||
6706 | u = VT_DOUBLE; |
||
6707 | goto basic_type1; |
||
6708 | } |
||
6709 | break; |
||
6710 | case TOK_ENUM: |
||
6711 | struct_decl(&type1, VT_ENUM); |
||
6712 | basic_type2: |
||
6713 | u = type1.t; |
||
6714 | type->ref = type1.ref; |
||
6715 | goto basic_type1; |
||
6716 | case TOK_STRUCT: |
||
6717 | case TOK_UNION: |
||
6718 | struct_decl(&type1, VT_STRUCT); |
||
6719 | goto basic_type2; |
||
6720 | |||
6721 | /* type modifiers */ |
||
6722 | case TOK_CONST1: |
||
6723 | case TOK_CONST2: |
||
6724 | case TOK_CONST3: |
||
6725 | t |= VT_CONSTANT; |
||
6726 | next(); |
||
6727 | break; |
||
6728 | case TOK_VOLATILE1: |
||
6729 | case TOK_VOLATILE2: |
||
6730 | case TOK_VOLATILE3: |
||
6731 | t |= VT_VOLATILE; |
||
6732 | next(); |
||
6733 | break; |
||
6734 | case TOK_SIGNED1: |
||
6735 | case TOK_SIGNED2: |
||
6736 | case TOK_SIGNED3: |
||
6737 | typespec_found = 1; |
||
6738 | t |= VT_SIGNED; |
||
6739 | next(); |
||
6740 | break; |
||
6741 | case TOK_REGISTER: |
||
6742 | case TOK_AUTO: |
||
6743 | case TOK_RESTRICT1: |
||
6744 | case TOK_RESTRICT2: |
||
6745 | case TOK_RESTRICT3: |
||
6746 | next(); |
||
6747 | break; |
||
6748 | case TOK_UNSIGNED: |
||
6749 | t |= VT_UNSIGNED; |
||
6750 | next(); |
||
6751 | typespec_found = 1; |
||
6752 | break; |
||
6753 | |||
6754 | /* storage */ |
||
6755 | case TOK_EXTERN: |
||
6756 | t |= VT_EXTERN; |
||
6757 | next(); |
||
6758 | break; |
||
6759 | case TOK_STATIC: |
||
6760 | t |= VT_STATIC; |
||
6761 | next(); |
||
6762 | break; |
||
6763 | case TOK_TYPEDEF: |
||
6764 | t |= VT_TYPEDEF; |
||
6765 | next(); |
||
6766 | break; |
||
6767 | case TOK_INLINE1: |
||
6768 | case TOK_INLINE2: |
||
6769 | case TOK_INLINE3: |
||
6770 | t |= VT_INLINE; |
||
6771 | next(); |
||
6772 | break; |
||
6773 | |||
6774 | /* GNUC attribute */ |
||
6775 | case TOK_ATTRIBUTE1: |
||
6776 | case TOK_ATTRIBUTE2: |
||
6777 | parse_attribute(ad); |
||
6778 | break; |
||
6779 | /* GNUC typeof */ |
||
6780 | case TOK_TYPEOF1: |
||
6781 | case TOK_TYPEOF2: |
||
6782 | case TOK_TYPEOF3: |
||
6783 | next(); |
||
6784 | parse_expr_type(&type1); |
||
6785 | goto basic_type2; |
||
6786 | default: |
||
6787 | if (typespec_found) |
||
6788 | goto the_end; |
||
6789 | s = sym_find(tok); |
||
6790 | if (!s || !(s->type.t & VT_TYPEDEF)) |
||
6791 | goto the_end; |
||
6792 | t |= (s->type.t & ~VT_TYPEDEF); |
||
6793 | type->ref = s->type.ref; |
||
6794 | next(); |
||
6795 | break; |
||
6796 | } |
||
6797 | type_found = 1; |
||
6798 | } |
||
6799 | the_end: |
||
6800 | if ((t & (VT_SIGNED|VT_UNSIGNED)) == (VT_SIGNED|VT_UNSIGNED)) |
||
6801 | error("signed and unsigned modifier"); |
||
6802 | if (tcc_state->char_is_unsigned) { |
||
6803 | if ((t & (VT_SIGNED|VT_UNSIGNED|VT_BTYPE)) == VT_BYTE) |
||
6804 | t |= VT_UNSIGNED; |
||
6805 | } |
||
6806 | t &= ~VT_SIGNED; |
||
6807 | |||
6808 | /* long is never used as type */ |
||
6809 | if ((t & VT_BTYPE) == VT_LONG) |
||
6810 | t = (t & ~VT_BTYPE) | VT_INT; |
||
6811 | type->t = t; |
||
6812 | return type_found; |
||
6813 | } |
||
6814 | |||
6815 | /* convert a function parameter type (array to pointer and function to |
||
6816 | function pointer) */ |
||
6817 | static inline void convert_parameter_type(CType *pt) |
||
6818 | { |
||
6819 | /* remove const and volatile qualifiers (XXX: const could be used |
||
6820 | to indicate a const function parameter */ |
||
6821 | pt->t &= ~(VT_CONSTANT | VT_VOLATILE); |
||
6822 | /* array must be transformed to pointer according to ANSI C */ |
||
6823 | pt->t &= ~VT_ARRAY; |
||
6824 | if ((pt->t & VT_BTYPE) == VT_FUNC) { |
||
6825 | mk_pointer(pt); |
||
6826 | } |
||
6827 | } |
||
6828 | |||
6829 | static void post_type(CType *type, AttributeDef *ad) |
||
6830 | { |
||
6831 | int n, l, t1; |
||
6832 | Sym **plast, *s, *first; |
||
6833 | AttributeDef ad1; |
||
6834 | CType pt; |
||
6835 | |||
6836 | if (tok == '(') { |
||
6837 | /* function declaration */ |
||
6838 | next(); |
||
6839 | l = 0; |
||
6840 | first = NULL; |
||
6841 | plast = &first; |
||
6842 | while (tok != ')') { |
||
6843 | /* read param name and compute offset */ |
||
6844 | if (l != FUNC_OLD) { |
||
6845 | if (!parse_btype(&pt, &ad1)) { |
||
6846 | if (l) { |
||
6847 | error("invalid type"); |
||
6848 | } else { |
||
6849 | l = FUNC_OLD; |
||
6850 | goto old_proto; |
||
6851 | } |
||
6852 | } |
||
6853 | l = FUNC_NEW; |
||
6854 | if ((pt.t & VT_BTYPE) == VT_VOID && tok == ')') |
||
6855 | break; |
||
6856 | type_decl(&pt, &ad1, &n, TYPE_DIRECT | TYPE_ABSTRACT); |
||
6857 | if ((pt.t & VT_BTYPE) == VT_VOID) |
||
6858 | error("parameter declared as void"); |
||
6859 | } else { |
||
6860 | old_proto: |
||
6861 | n = tok; |
||
6862 | pt.t = VT_INT; |
||
6863 | next(); |
||
6864 | } |
||
6865 | convert_parameter_type(&pt); |
||
6866 | s = sym_push(n | SYM_FIELD, &pt, 0, 0); |
||
6867 | *plast = s; |
||
6868 | plast = &s->next; |
||
6869 | if (tok == ',') { |
||
6870 | next(); |
||
6871 | if (l == FUNC_NEW && tok == TOK_DOTS) { |
||
6872 | l = FUNC_ELLIPSIS; |
||
6873 | next(); |
||
6874 | break; |
||
6875 | } |
||
6876 | } |
||
6877 | } |
||
6878 | /* if no parameters, then old type prototype */ |
||
6879 | if (l == 0) |
||
6880 | l = FUNC_OLD; |
||
6881 | skip(')'); |
||
6882 | t1 = type->t & VT_STORAGE; |
||
6883 | /* NOTE: const is ignored in returned type as it has a special |
||
6884 | meaning in gcc / C++ */ |
||
6885 | type->t &= ~(VT_STORAGE | VT_CONSTANT); |
||
6886 | post_type(type, ad); |
||
6887 | /* we push a anonymous symbol which will contain the function prototype */ |
||
6888 | s = sym_push(SYM_FIELD, type, ad->func_call, l); |
||
6889 | s->next = first; |
||
6890 | type->t = t1 | VT_FUNC; |
||
6891 | type->ref = s; |
||
6892 | } else if (tok == '[') { |
||
6893 | /* array definition */ |
||
6894 | next(); |
||
6895 | n = -1; |
||
6896 | if (tok != ']') { |
||
6897 | n = expr_const(); |
||
6898 | if (n < 0) |
||
6899 | error("invalid array size"); |
||
6900 | } |
||
6901 | skip(']'); |
||
6902 | /* parse next post type */ |
||
6903 | t1 = type->t & VT_STORAGE; |
||
6904 | type->t &= ~VT_STORAGE; |
||
6905 | post_type(type, ad); |
||
6906 | |||
6907 | /* we push a anonymous symbol which will contain the array |
||
6908 | element type */ |
||
6909 | s = sym_push(SYM_FIELD, type, 0, n); |
||
6910 | type->t = t1 | VT_ARRAY | VT_PTR; |
||
6911 | type->ref = s; |
||
6912 | } |
||
6913 | } |
||
6914 | |||
6915 | /* Parse a type declaration (except basic type), and return the type |
||
6916 | in 'type'. 'td' is a bitmask indicating which kind of type decl is |
||
6917 | expected. 'type' should contain the basic type. 'ad' is the |
||
6918 | attribute definition of the basic type. It can be modified by |
||
6919 | type_decl(). |
||
6920 | */ |
||
6921 | static void type_decl(CType *type, AttributeDef *ad, int *v, int td) |
||
6922 | { |
||
6923 | Sym *s; |
||
6924 | CType type1, *type2; |
||
6925 | int qualifiers; |
||
6926 | |||
6927 | while (tok == '*') { |
||
6928 | qualifiers = 0; |
||
6929 | redo: |
||
6930 | next(); |
||
6931 | switch(tok) { |
||
6932 | case TOK_CONST1: |
||
6933 | case TOK_CONST2: |
||
6934 | case TOK_CONST3: |
||
6935 | qualifiers |= VT_CONSTANT; |
||
6936 | goto redo; |
||
6937 | case TOK_VOLATILE1: |
||
6938 | case TOK_VOLATILE2: |
||
6939 | case TOK_VOLATILE3: |
||
6940 | qualifiers |= VT_VOLATILE; |
||
6941 | goto redo; |
||
6942 | case TOK_RESTRICT1: |
||
6943 | case TOK_RESTRICT2: |
||
6944 | case TOK_RESTRICT3: |
||
6945 | goto redo; |
||
6946 | } |
||
6947 | mk_pointer(type); |
||
6948 | type->t |= qualifiers; |
||
6949 | } |
||
6950 | |||
6951 | /* XXX: clarify attribute handling */ |
||
6952 | if (tok == TOK_ATTRIBUTE1 || tok == TOK_ATTRIBUTE2) |
||
6953 | parse_attribute(ad); |
||
6954 | |||
6955 | /* recursive type */ |
||
6956 | /* XXX: incorrect if abstract type for functions (e.g. 'int ()') */ |
||
6957 | type1.t = 0; /* XXX: same as int */ |
||
6958 | if (tok == '(') { |
||
6959 | next(); |
||
6960 | /* XXX: this is not correct to modify 'ad' at this point, but |
||
6961 | the syntax is not clear */ |
||
6962 | if (tok == TOK_ATTRIBUTE1 || tok == TOK_ATTRIBUTE2) |
||
6963 | parse_attribute(ad); |
||
6964 | type_decl(&type1, ad, v, td); |
||
6965 | skip(')'); |
||
6966 | } else { |
||
6967 | /* type identifier */ |
||
6968 | if (tok >= TOK_IDENT && (td & TYPE_DIRECT)) { |
||
6969 | *v = tok; |
||
6970 | next(); |
||
6971 | } else { |
||
6972 | if (!(td & TYPE_ABSTRACT)) |
||
6973 | expect("identifier"); |
||
6974 | *v = 0; |
||
6975 | } |
||
6976 | } |
||
6977 | post_type(type, ad); |
||
6978 | if (tok == TOK_ATTRIBUTE1 || tok == TOK_ATTRIBUTE2) |
||
6979 | parse_attribute(ad); |
||
6980 | if (!type1.t) |
||
6981 | return; |
||
6982 | /* append type at the end of type1 */ |
||
6983 | type2 = &type1; |
||
6984 | for(;;) { |
||
6985 | s = type2->ref; |
||
6986 | type2 = &s->type; |
||
6987 | if (!type2->t) { |
||
6988 | *type2 = *type; |
||
6989 | break; |
||
6990 | } |
||
6991 | } |
||
6992 | *type = type1; |
||
6993 | } |
||
6994 | |||
6995 | /* compute the lvalue VT_LVAL_xxx needed to match type t. */ |
||
6996 | static int lvalue_type(int t) |
||
6997 | { |
||
6998 | int bt, r; |
||
6999 | r = VT_LVAL; |
||
7000 | bt = t & VT_BTYPE; |
||
7001 | if (bt == VT_BYTE || bt == VT_BOOL) |
||
7002 | r |= VT_LVAL_BYTE; |
||
7003 | else if (bt == VT_SHORT) |
||
7004 | r |= VT_LVAL_SHORT; |
||
7005 | else |
||
7006 | return r; |
||
7007 | if (t & VT_UNSIGNED) |
||
7008 | r |= VT_LVAL_UNSIGNED; |
||
7009 | return r; |
||
7010 | } |
||
7011 | |||
7012 | /* indirection with full error checking and bound check */ |
||
7013 | static void indir(void) |
||
7014 | { |
||
7015 | if ((vtop->type.t & VT_BTYPE) != VT_PTR) |
||
7016 | expect("pointer"); |
||
7017 | if ((vtop->r & VT_LVAL) && !nocode_wanted) |
||
7018 | gv(RC_INT); |
||
7019 | vtop->type = *pointed_type(&vtop->type); |
||
7020 | /* an array is never an lvalue */ |
||
7021 | if (!(vtop->type.t & VT_ARRAY)) { |
||
7022 | vtop->r |= lvalue_type(vtop->type.t); |
||
7023 | /* if bound checking, the referenced pointer must be checked */ |
||
7024 | if (do_bounds_check) |
||
7025 | vtop->r |= VT_MUSTBOUND; |
||
7026 | } |
||
7027 | } |
||
7028 | |||
7029 | /* pass a parameter to a function and do type checking and casting */ |
||
7030 | static void gfunc_param_typed(Sym *func, Sym *arg) |
||
7031 | { |
||
7032 | int func_type; |
||
7033 | CType type; |
||
7034 | |||
7035 | func_type = func->c; |
||
7036 | if (func_type == FUNC_OLD || |
||
7037 | (func_type == FUNC_ELLIPSIS && arg == NULL)) { |
||
7038 | /* default casting : only need to convert float to double */ |
||
7039 | if ((vtop->type.t & VT_BTYPE) == VT_FLOAT) { |
||
7040 | type.t = VT_DOUBLE; |
||
7041 | gen_cast(&type); |
||
7042 | } |
||
7043 | } else if (arg == NULL) { |
||
7044 | error("too many arguments to function"); |
||
7045 | } else { |
||
7046 | type = arg->type; |
||
7047 | type.t &= ~VT_CONSTANT; /* need to do that to avoid false warning */ |
||
7048 | gen_assign_cast(&type); |
||
7049 | } |
||
7050 | } |
||
7051 | |||
7052 | /* parse an expression of the form '(type)' or '(expr)' and return its |
||
7053 | type */ |
||
7054 | static void parse_expr_type(CType *type) |
||
7055 | { |
||
7056 | int n; |
||
7057 | AttributeDef ad; |
||
7058 | |||
7059 | skip('('); |
||
7060 | if (parse_btype(type, &ad)) { |
||
7061 | type_decl(type, &ad, &n, TYPE_ABSTRACT); |
||
7062 | } else { |
||
7063 | expr_type(type); |
||
7064 | } |
||
7065 | skip(')'); |
||
7066 | } |
||
7067 | |||
7068 | static void parse_type(CType *type) |
||
7069 | { |
||
7070 | AttributeDef ad; |
||
7071 | int n; |
||
7072 | |||
7073 | if (!parse_btype(type, &ad)) { |
||
7074 | expect("type"); |
||
7075 | } |
||
7076 | type_decl(type, &ad, &n, TYPE_ABSTRACT); |
||
7077 | } |
||
7078 | |||
7079 | static void vpush_tokc(int t) |
||
7080 | { |
||
7081 | CType type; |
||
7082 | type.t = t; |
||
7083 | vsetc(&type, VT_CONST, &tokc); |
||
7084 | } |
||
7085 | |||
7086 | static void unary(void) |
||
7087 | { |
||
7088 | int n, t, align, size, r; |
||
7089 | CType type; |
||
7090 | Sym *s; |
||
7091 | AttributeDef ad; |
||
7092 | |||
7093 | /* XXX: GCC 2.95.3 does not generate a table although it should be |
||
7094 | better here */ |
||
7095 | tok_next: |
||
7096 | switch(tok) { |
||
7097 | case TOK_EXTENSION: |
||
7098 | next(); |
||
7099 | goto tok_next; |
||
7100 | case TOK_CINT: |
||
7101 | case TOK_CCHAR: |
||
7102 | case TOK_LCHAR: |
||
7103 | vpushi(tokc.i); |
||
7104 | next(); |
||
7105 | break; |
||
7106 | case TOK_CUINT: |
||
7107 | vpush_tokc(VT_INT | VT_UNSIGNED); |
||
7108 | next(); |
||
7109 | break; |
||
7110 | case TOK_CLLONG: |
||
7111 | vpush_tokc(VT_LLONG); |
||
7112 | next(); |
||
7113 | break; |
||
7114 | case TOK_CULLONG: |
||
7115 | vpush_tokc(VT_LLONG | VT_UNSIGNED); |
||
7116 | next(); |
||
7117 | break; |
||
7118 | case TOK_CFLOAT: |
||
7119 | vpush_tokc(VT_FLOAT); |
||
7120 | next(); |
||
7121 | break; |
||
7122 | case TOK_CDOUBLE: |
||
7123 | vpush_tokc(VT_DOUBLE); |
||
7124 | next(); |
||
7125 | break; |
||
7126 | case TOK_CLDOUBLE: |
||
7127 | vpush_tokc(VT_LDOUBLE); |
||
7128 | next(); |
||
7129 | break; |
||
7130 | case TOK___FUNCTION__: |
||
7131 | if (!gnu_ext) |
||
7132 | goto tok_identifier; |
||
7133 | /* fall thru */ |
||
7134 | case TOK___FUNC__: |
||
7135 | { |
||
7136 | void *ptr; |
||
7137 | int len; |
||
7138 | /* special function name identifier */ |
||
7139 | len = strlen(funcname) + 1; |
||
7140 | /* generate char[len] type */ |
||
7141 | type.t = VT_BYTE; |
||
7142 | mk_pointer(&type); |
||
7143 | type.t |= VT_ARRAY; |
||
7144 | type.ref->c = len; |
||
7145 | vpush_ref(&type, data_section, data_section->data_offset, len); |
||
7146 | ptr = section_ptr_add(data_section, len); |
||
7147 | memcpy(ptr, funcname, len); |
||
7148 | next(); |
||
7149 | } |
||
7150 | break; |
||
7151 | case TOK_LSTR: |
||
7152 | t = VT_INT; |
||
7153 | goto str_init; |
||
7154 | case TOK_STR: |
||
7155 | /* string parsing */ |
||
7156 | t = VT_BYTE; |
||
7157 | str_init: |
||
7158 | if (tcc_state->warn_write_strings) |
||
7159 | t |= VT_CONSTANT; |
||
7160 | type.t = t; |
||
7161 | mk_pointer(&type); |
||
7162 | type.t |= VT_ARRAY; |
||
7163 | memset(&ad, 0, sizeof(AttributeDef)); |
||
7164 | decl_initializer_alloc(&type, &ad, VT_CONST, 2, 0, 0); |
||
7165 | break; |
||
7166 | case '(': |
||
7167 | next(); |
||
7168 | /* cast ? */ |
||
7169 | if (parse_btype(&type, &ad)) { |
||
7170 | type_decl(&type, &ad, &n, TYPE_ABSTRACT); |
||
7171 | skip(')'); |
||
7172 | /* check ISOC99 compound literal */ |
||
7173 | if (tok == '{') { |
||
7174 | /* data is allocated locally by default */ |
||
7175 | if (global_expr) |
||
7176 | r = VT_CONST; |
||
7177 | else |
||
7178 | r = VT_LOCAL; |
||
7179 | /* all except arrays are lvalues */ |
||
7180 | if (!(type.t & VT_ARRAY)) |
||
7181 | r |= lvalue_type(type.t); |
||
7182 | memset(&ad, 0, sizeof(AttributeDef)); |
||
7183 | decl_initializer_alloc(&type, &ad, r, 1, 0, 0); |
||
7184 | } else { |
||
7185 | unary(); |
||
7186 | gen_cast(&type); |
||
7187 | } |
||
7188 | } else if (tok == '{') { |
||
7189 | /* save all registers */ |
||
7190 | save_regs(0); |
||
7191 | /* statement expression : we do not accept break/continue |
||
7192 | inside as GCC does */ |
||
7193 | block(NULL, NULL, NULL, NULL, 0, 1); |
||
7194 | skip(')'); |
||
7195 | } else { |
||
7196 | gexpr(); |
||
7197 | skip(')'); |
||
7198 | } |
||
7199 | break; |
||
7200 | case '*': |
||
7201 | next(); |
||
7202 | unary(); |
||
7203 | indir(); |
||
7204 | break; |
||
7205 | case '&': |
||
7206 | next(); |
||
7207 | unary(); |
||
7208 | /* functions names must be treated as function pointers, |
||
7209 | except for unary '&' and sizeof. Since we consider that |
||
7210 | functions are not lvalues, we only have to handle it |
||
7211 | there and in function calls. */ |
||
7212 | /* arrays can also be used although they are not lvalues */ |
||
7213 | if ((vtop->type.t & VT_BTYPE) != VT_FUNC && |
||
7214 | !(vtop->type.t & VT_ARRAY)) |
||
7215 | test_lvalue(); |
||
7216 | mk_pointer(&vtop->type); |
||
7217 | gaddrof(); |
||
7218 | break; |
||
7219 | case '!': |
||
7220 | next(); |
||
7221 | unary(); |
||
7222 | if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) |
||
7223 | vtop->c.i = !vtop->c.i; |
||
7224 | else if ((vtop->r & VT_VALMASK) == VT_CMP) |
||
7225 | vtop->c.i = vtop->c.i ^ 1; |
||
7226 | else |
||
7227 | vseti(VT_JMP, gtst(1, 0)); |
||
7228 | break; |
||
7229 | case '~': |
||
7230 | next(); |
||
7231 | unary(); |
||
7232 | vpushi(-1); |
||
7233 | gen_op('^'); |
||
7234 | break; |
||
7235 | case '+': |
||
7236 | next(); |
||
7237 | /* in order to force cast, we add zero */ |
||
7238 | unary(); |
||
7239 | if ((vtop->type.t & VT_BTYPE) == VT_PTR) |
||
7240 | error("pointer not accepted for unary plus"); |
||
7241 | vpushi(0); |
||
7242 | gen_op('+'); |
||
7243 | break; |
||
7244 | case TOK_SIZEOF: |
||
7245 | case TOK_ALIGNOF1: |
||
7246 | case TOK_ALIGNOF2: |
||
7247 | t = tok; |
||
7248 | next(); |
||
7249 | if (tok == '(') { |
||
7250 | parse_expr_type(&type); |
||
7251 | } else { |
||
7252 | unary_type(&type); |
||
7253 | } |
||
7254 | size = type_size(&type, &align); |
||
7255 | if (t == TOK_SIZEOF) { |
||
7256 | if (size < 0) |
||
7257 | error("sizeof applied to an incomplete type"); |
||
7258 | vpushi(size); |
||
7259 | } else { |
||
7260 | vpushi(align); |
||
7261 | } |
||
7262 | break; |
||
7263 | |||
7264 | case TOK_builtin_types_compatible_p: |
||
7265 | { |
||
7266 | CType type1, type2; |
||
7267 | next(); |
||
7268 | skip('('); |
||
7269 | parse_type(&type1); |
||
7270 | skip(','); |
||
7271 | parse_type(&type2); |
||
7272 | skip(')'); |
||
7273 | type1.t &= ~(VT_CONSTANT | VT_VOLATILE); |
||
7274 | type2.t &= ~(VT_CONSTANT | VT_VOLATILE); |
||
7275 | vpushi(is_compatible_types(&type1, &type2)); |
||
7276 | } |
||
7277 | break; |
||
7278 | case TOK_builtin_constant_p: |
||
7279 | { |
||
7280 | int saved_nocode_wanted, res; |
||
7281 | next(); |
||
7282 | skip('('); |
||
7283 | saved_nocode_wanted = nocode_wanted; |
||
7284 | nocode_wanted = 1; |
||
7285 | gexpr(); |
||
7286 | res = (vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; |
||
7287 | vpop(); |
||
7288 | nocode_wanted = saved_nocode_wanted; |
||
7289 | skip(')'); |
||
7290 | vpushi(res); |
||
7291 | } |
||
7292 | break; |
||
7293 | case TOK_INC: |
||
7294 | case TOK_DEC: |
||
7295 | t = tok; |
||
7296 | next(); |
||
7297 | unary(); |
||
7298 | inc(0, t); |
||
7299 | break; |
||
7300 | case '-': |
||
7301 | next(); |
||
7302 | vpushi(0); |
||
7303 | unary(); |
||
7304 | gen_op('-'); |
||
7305 | break; |
||
7306 | case TOK_LAND: |
||
7307 | if (!gnu_ext) |
||
7308 | goto tok_identifier; |
||
7309 | next(); |
||
7310 | /* allow to take the address of a label */ |
||
7311 | if (tok < TOK_UIDENT) |
||
7312 | expect("label identifier"); |
||
7313 | s = label_find(tok); |
||
7314 | if (!s) { |
||
7315 | s = label_push(&global_label_stack, tok, LABEL_FORWARD); |
||
7316 | } else { |
||
7317 | if (s->r == LABEL_DECLARED) |
||
7318 | s->r = LABEL_FORWARD; |
||
7319 | } |
||
7320 | if (!s->type.t) { |
||
7321 | s->type.t = VT_VOID; |
||
7322 | mk_pointer(&s->type); |
||
7323 | s->type.t |= VT_STATIC; |
||
7324 | } |
||
7325 | vset(&s->type, VT_CONST | VT_SYM, 0); |
||
7326 | vtop->sym = s; |
||
7327 | next(); |
||
7328 | break; |
||
7329 | default: |
||
7330 | tok_identifier: |
||
7331 | t = tok; |
||
7332 | next(); |
||
7333 | if (t < TOK_UIDENT) |
||
7334 | expect("identifier"); |
||
7335 | s = sym_find(t); |
||
7336 | if (!s) { |
||
7337 | if (tok != '(') |
||
7338 | error("'%s' undeclared", get_tok_str(t, NULL)); |
||
7339 | /* for simple function calls, we tolerate undeclared |
||
7340 | external reference to int() function */ |
||
7341 | if (tcc_state->warn_implicit_function_declaration) |
||
7342 | warning("implicit declaration of function '%s'", |
||
7343 | get_tok_str(t, NULL)); |
||
7344 | s = external_global_sym(t, &func_old_type, 0); |
||
7345 | } |
||
7346 | if ((s->type.t & (VT_STATIC | VT_INLINE | VT_BTYPE)) == |
||
7347 | (VT_STATIC | VT_INLINE | VT_FUNC)) { |
||
7348 | /* if referencing an inline function, then we generate a |
||
7349 | symbol to it if not already done. It will have the |
||
7350 | effect to generate code for it at the end of the |
||
7351 | compilation unit. Inline function as always |
||
7352 | generated in the text section. */ |
||
7353 | if (!s->c) |
||
7354 | put_extern_sym(s, text_section, 0, 0); |
||
7355 | r = VT_SYM | VT_CONST; |
||
7356 | } else { |
||
7357 | r = s->r; |
||
7358 | } |
||
7359 | vset(&s->type, r, s->c); |
||
7360 | /* if forward reference, we must point to s */ |
||
7361 | if (vtop->r & VT_SYM) { |
||
7362 | vtop->sym = s; |
||
7363 | vtop->c.ul = 0; |
||
7364 | } |
||
7365 | break; |
||
7366 | } |
||
7367 | |||
7368 | /* post operations */ |
||
7369 | while (1) { |
||
7370 | if (tok == TOK_INC || tok == TOK_DEC) { |
||
7371 | inc(1, tok); |
||
7372 | next(); |
||
7373 | } else if (tok == '.' || tok == TOK_ARROW) { |
||
7374 | /* field */ |
||
7375 | if (tok == TOK_ARROW) |
||
7376 | indir(); |
||
7377 | test_lvalue(); |
||
7378 | gaddrof(); |
||
7379 | next(); |
||
7380 | /* expect pointer on structure */ |
||
7381 | if ((vtop->type.t & VT_BTYPE) != VT_STRUCT) |
||
7382 | expect("struct or union"); |
||
7383 | s = vtop->type.ref; |
||
7384 | /* find field */ |
||
7385 | tok |= SYM_FIELD; |
||
7386 | while ((s = s->next) != NULL) { |
||
7387 | if (s->v == tok) |
||
7388 | break; |
||
7389 | } |
||
7390 | if (!s) |
||
7391 | error("field not found"); |
||
7392 | /* add field offset to pointer */ |
||
7393 | vtop->type = char_pointer_type; /* change type to 'char *' */ |
||
7394 | vpushi(s->c); |
||
7395 | gen_op('+'); |
||
7396 | /* change type to field type, and set to lvalue */ |
||
7397 | vtop->type = s->type; |
||
7398 | /* an array is never an lvalue */ |
||
7399 | if (!(vtop->type.t & VT_ARRAY)) { |
||
7400 | vtop->r |= lvalue_type(vtop->type.t); |
||
7401 | /* if bound checking, the referenced pointer must be checked */ |
||
7402 | if (do_bounds_check) |
||
7403 | vtop->r |= VT_MUSTBOUND; |
||
7404 | } |
||
7405 | next(); |
||
7406 | } else if (tok == '[') { |
||
7407 | next(); |
||
7408 | gexpr(); |
||
7409 | gen_op('+'); |
||
7410 | indir(); |
||
7411 | skip(']'); |
||
7412 | } else if (tok == '(') { |
||
7413 | SValue ret; |
||
7414 | Sym *sa; |
||
7415 | int nb_args; |
||
7416 | |||
7417 | /* function call */ |
||
7418 | if ((vtop->type.t & VT_BTYPE) != VT_FUNC) { |
||
7419 | /* pointer test (no array accepted) */ |
||
7420 | if ((vtop->type.t & (VT_BTYPE | VT_ARRAY)) == VT_PTR) { |
||
7421 | vtop->type = *pointed_type(&vtop->type); |
||
7422 | if ((vtop->type.t & VT_BTYPE) != VT_FUNC) |
||
7423 | goto error_func; |
||
7424 | } else { |
||
7425 | error_func: |
||
7426 | expect("function pointer"); |
||
7427 | } |
||
7428 | } else { |
||
7429 | vtop->r &= ~VT_LVAL; /* no lvalue */ |
||
7430 | } |
||
7431 | /* get return type */ |
||
7432 | s = vtop->type.ref; |
||
7433 | next(); |
||
7434 | sa = s->next; /* first parameter */ |
||
7435 | nb_args = 0; |
||
7436 | /* compute first implicit argument if a structure is returned */ |
||
7437 | if ((s->type.t & VT_BTYPE) == VT_STRUCT) { |
||
7438 | /* get some space for the returned structure */ |
||
7439 | size = type_size(&s->type, &align); |
||
7440 | loc = (loc - size) & -align; |
||
7441 | ret.type = s->type; |
||
7442 | ret.r = VT_LOCAL | VT_LVAL; |
||
7443 | /* pass it as 'int' to avoid structure arg passing |
||
7444 | problems */ |
||
7445 | vseti(VT_LOCAL, loc); |
||
7446 | ret.c = vtop->c; |
||
7447 | nb_args++; |
||
7448 | } else { |
||
7449 | ret.type = s->type; |
||
7450 | ret.r2 = VT_CONST; |
||
7451 | /* return in register */ |
||
7452 | if (is_float(ret.type.t)) { |
||
7453 | ret.r = REG_FRET; |
||
7454 | } else { |
||
7455 | if ((ret.type.t & VT_BTYPE) == VT_LLONG) |
||
7456 | ret.r2 = REG_LRET; |
||
7457 | ret.r = REG_IRET; |
||
7458 | } |
||
7459 | ret.c.i = 0; |
||
7460 | } |
||
7461 | if (tok != ')') { |
||
7462 | for(;;) { |
||
7463 | expr_eq(); |
||
7464 | gfunc_param_typed(s, sa); |
||
7465 | nb_args++; |
||
7466 | if (sa) |
||
7467 | sa = sa->next; |
||
7468 | if (tok == ')') |
||
7469 | break; |
||
7470 | skip(','); |
||
7471 | } |
||
7472 | } |
||
7473 | if (sa) |
||
7474 | error("too few arguments to function"); |
||
7475 | skip(')'); |
||
7476 | if (!nocode_wanted) { |
||
7477 | gfunc_call(nb_args); |
||
7478 | } else { |
||
7479 | vtop -= (nb_args + 1); |
||
7480 | } |
||
7481 | /* return value */ |
||
7482 | vsetc(&ret.type, ret.r, &ret.c); |
||
7483 | vtop->r2 = ret.r2; |
||
7484 | } else { |
||
7485 | break; |
||
7486 | } |
||
7487 | } |
||
7488 | } |
||
7489 | |||
7490 | static void uneq(void) |
||
7491 | { |
||
7492 | int t; |
||
7493 | |||
7494 | unary(); |
||
7495 | if (tok == '=' || |
||
7496 | (tok >= TOK_A_MOD && tok <= TOK_A_DIV) || |
||
7497 | tok == TOK_A_XOR || tok == TOK_A_OR || |
||
7498 | tok == TOK_A_SHL || tok == TOK_A_SAR) { |
||
7499 | test_lvalue(); |
||
7500 | t = tok; |
||
7501 | next(); |
||
7502 | if (t == '=') { |
||
7503 | expr_eq(); |
||
7504 | } else { |
||
7505 | vdup(); |
||
7506 | expr_eq(); |
||
7507 | gen_op(t & 0x7f); |
||
7508 | } |
||
7509 | vstore(); |
||
7510 | } |
||
7511 | } |
||
7512 | |||
7513 | static void expr_prod(void) |
||
7514 | { |
||
7515 | int t; |
||
7516 | |||
7517 | uneq(); |
||
7518 | while (tok == '*' || tok == '/' || tok == '%') { |
||
7519 | t = tok; |
||
7520 | next(); |
||
7521 | uneq(); |
||
7522 | gen_op(t); |
||
7523 | } |
||
7524 | } |
||
7525 | |||
7526 | static void expr_sum(void) |
||
7527 | { |
||
7528 | int t; |
||
7529 | |||
7530 | expr_prod(); |
||
7531 | while (tok == '+' || tok == '-') { |
||
7532 | t = tok; |
||
7533 | next(); |
||
7534 | expr_prod(); |
||
7535 | gen_op(t); |
||
7536 | } |
||
7537 | } |
||
7538 | |||
7539 | static void expr_shift(void) |
||
7540 | { |
||
7541 | int t; |
||
7542 | |||
7543 | expr_sum(); |
||
7544 | while (tok == TOK_SHL || tok == TOK_SAR) { |
||
7545 | t = tok; |
||
7546 | next(); |
||
7547 | expr_sum(); |
||
7548 | gen_op(t); |
||
7549 | } |
||
7550 | } |
||
7551 | |||
7552 | static void expr_cmp(void) |
||
7553 | { |
||
7554 | int t; |
||
7555 | |||
7556 | expr_shift(); |
||
7557 | while ((tok >= TOK_ULE && tok <= TOK_GT) || |
||
7558 | tok == TOK_ULT || tok == TOK_UGE) { |
||
7559 | t = tok; |
||
7560 | next(); |
||
7561 | expr_shift(); |
||
7562 | gen_op(t); |
||
7563 | } |
||
7564 | } |
||
7565 | |||
7566 | static void expr_cmpeq(void) |
||
7567 | { |
||
7568 | int t; |
||
7569 | |||
7570 | expr_cmp(); |
||
7571 | while (tok == TOK_EQ || tok == TOK_NE) { |
||
7572 | t = tok; |
||
7573 | next(); |
||
7574 | expr_cmp(); |
||
7575 | gen_op(t); |
||
7576 | } |
||
7577 | } |
||
7578 | |||
7579 | static void expr_and(void) |
||
7580 | { |
||
7581 | expr_cmpeq(); |
||
7582 | while (tok == '&') { |
||
7583 | next(); |
||
7584 | expr_cmpeq(); |
||
7585 | gen_op('&'); |
||
7586 | } |
||
7587 | } |
||
7588 | |||
7589 | static void expr_xor(void) |
||
7590 | { |
||
7591 | expr_and(); |
||
7592 | while (tok == '^') { |
||
7593 | next(); |
||
7594 | expr_and(); |
||
7595 | gen_op('^'); |
||
7596 | } |
||
7597 | } |
||
7598 | |||
7599 | static void expr_or(void) |
||
7600 | { |
||
7601 | expr_xor(); |
||
7602 | while (tok == '|') { |
||
7603 | next(); |
||
7604 | expr_xor(); |
||
7605 | gen_op('|'); |
||
7606 | } |
||
7607 | } |
||
7608 | |||
7609 | /* XXX: fix this mess */ |
||
7610 | static void expr_land_const(void) |
||
7611 | { |
||
7612 | expr_or(); |
||
7613 | while (tok == TOK_LAND) { |
||
7614 | next(); |
||
7615 | expr_or(); |
||
7616 | gen_op(TOK_LAND); |
||
7617 | } |
||
7618 | } |
||
7619 | |||
7620 | /* XXX: fix this mess */ |
||
7621 | static void expr_lor_const(void) |
||
7622 | { |
||
7623 | expr_land_const(); |
||
7624 | while (tok == TOK_LOR) { |
||
7625 | next(); |
||
7626 | expr_land_const(); |
||
7627 | gen_op(TOK_LOR); |
||
7628 | } |
||
7629 | } |
||
7630 | |||
7631 | /* only used if non constant */ |
||
7632 | static void expr_land(void) |
||
7633 | { |
||
7634 | int t; |
||
7635 | |||
7636 | expr_or(); |
||
7637 | if (tok == TOK_LAND) { |
||
7638 | t = 0; |
||
7639 | for(;;) { |
||
7640 | t = gtst(1, t); |
||
7641 | if (tok != TOK_LAND) { |
||
7642 | vseti(VT_JMPI, t); |
||
7643 | break; |
||
7644 | } |
||
7645 | next(); |
||
7646 | expr_or(); |
||
7647 | } |
||
7648 | } |
||
7649 | } |
||
7650 | |||
7651 | static void expr_lor(void) |
||
7652 | { |
||
7653 | int t; |
||
7654 | |||
7655 | expr_land(); |
||
7656 | if (tok == TOK_LOR) { |
||
7657 | t = 0; |
||
7658 | for(;;) { |
||
7659 | t = gtst(0, t); |
||
7660 | if (tok != TOK_LOR) { |
||
7661 | vseti(VT_JMP, t); |
||
7662 | break; |
||
7663 | } |
||
7664 | next(); |
||
7665 | expr_land(); |
||
7666 | } |
||
7667 | } |
||
7668 | } |
||
7669 | |||
7670 | /* XXX: better constant handling */ |
||
7671 | static void expr_eq(void) |
||
7672 | { |
||
7673 | int tt, u, r1, r2, rc, t1, t2, bt1, bt2; |
||
7674 | SValue sv; |
||
7675 | CType type, type1, type2; |
||
7676 | |||
7677 | if (const_wanted) { |
||
7678 | int c1, c; |
||
7679 | expr_lor_const(); |
||
7680 | if (tok == '?') { |
||
7681 | c = vtop->c.i; |
||
7682 | vpop(); |
||
7683 | next(); |
||
7684 | if (tok == ':' && gnu_ext) { |
||
7685 | c1 = c; |
||
7686 | } else { |
||
7687 | gexpr(); |
||
7688 | c1 = vtop->c.i; |
||
7689 | vpop(); |
||
7690 | } |
||
7691 | skip(':'); |
||
7692 | expr_eq(); |
||
7693 | if (c) |
||
7694 | vtop->c.i = c1; |
||
7695 | } |
||
7696 | } else { |
||
7697 | expr_lor(); |
||
7698 | if (tok == '?') { |
||
7699 | next(); |
||
7700 | if (vtop != vstack) { |
||
7701 | /* needed to avoid having different registers saved in |
||
7702 | each branch */ |
||
7703 | if (is_float(vtop->type.t)) |
||
7704 | rc = RC_FLOAT; |
||
7705 | else |
||
7706 | rc = RC_INT; |
||
7707 | gv(rc); |
||
7708 | save_regs(1); |
||
7709 | } |
||
7710 | if (tok == ':' && gnu_ext) { |
||
7711 | gv_dup(); |
||
7712 | tt = gtst(1, 0); |
||
7713 | } else { |
||
7714 | tt = gtst(1, 0); |
||
7715 | gexpr(); |
||
7716 | } |
||
7717 | type1 = vtop->type; |
||
7718 | sv = *vtop; /* save value to handle it later */ |
||
7719 | vtop--; /* no vpop so that FP stack is not flushed */ |
||
7720 | skip(':'); |
||
7721 | u = gjmp(0); |
||
7722 | gsym(tt); |
||
7723 | expr_eq(); |
||
7724 | type2 = vtop->type; |
||
7725 | |||
7726 | t1 = type1.t; |
||
7727 | bt1 = t1 & VT_BTYPE; |
||
7728 | t2 = type2.t; |
||
7729 | bt2 = t2 & VT_BTYPE; |
||
7730 | /* cast operands to correct type according to ISOC rules */ |
||
7731 | if (is_float(bt1) || is_float(bt2)) { |
||
7732 | if (bt1 == VT_LDOUBLE || bt2 == VT_LDOUBLE) { |
||
7733 | type.t = VT_LDOUBLE; |
||
7734 | } else if (bt1 == VT_DOUBLE || bt2 == VT_DOUBLE) { |
||
7735 | type.t = VT_DOUBLE; |
||
7736 | } else { |
||
7737 | type.t = VT_FLOAT; |
||
7738 | } |
||
7739 | } else if (bt1 == VT_LLONG || bt2 == VT_LLONG) { |
||
7740 | /* cast to biggest op */ |
||
7741 | type.t = VT_LLONG; |
||
7742 | /* convert to unsigned if it does not fit in a long long */ |
||
7743 | if ((t1 & (VT_BTYPE | VT_UNSIGNED)) == (VT_LLONG | VT_UNSIGNED) || |
||
7744 | (t2 & (VT_BTYPE | VT_UNSIGNED)) == (VT_LLONG | VT_UNSIGNED)) |
||
7745 | type.t |= VT_UNSIGNED; |
||
7746 | } else if (bt1 == VT_PTR || bt2 == VT_PTR) { |
||
7747 | /* XXX: test pointer compatibility */ |
||
7748 | type = type1; |
||
7749 | } else if (bt1 == VT_STRUCT || bt2 == VT_STRUCT) { |
||
7750 | /* XXX: test structure compatibility */ |
||
7751 | type = type1; |
||
7752 | } else if (bt1 == VT_VOID || bt2 == VT_VOID) { |
||
7753 | /* NOTE: as an extension, we accept void on only one side */ |
||
7754 | type.t = VT_VOID; |
||
7755 | } else { |
||
7756 | /* integer operations */ |
||
7757 | type.t = VT_INT; |
||
7758 | /* convert to unsigned if it does not fit in an integer */ |
||
7759 | if ((t1 & (VT_BTYPE | VT_UNSIGNED)) == (VT_INT | VT_UNSIGNED) || |
||
7760 | (t2 & (VT_BTYPE | VT_UNSIGNED)) == (VT_INT | VT_UNSIGNED)) |
||
7761 | type.t |= VT_UNSIGNED; |
||
7762 | } |
||
7763 | |||
7764 | /* now we convert second operand */ |
||
7765 | gen_cast(&type); |
||
7766 | rc = RC_INT; |
||
7767 | if (is_float(type.t)) { |
||
7768 | rc = RC_FLOAT; |
||
7769 | } else if ((type.t & VT_BTYPE) == VT_LLONG) { |
||
7770 | /* for long longs, we use fixed registers to avoid having |
||
7771 | to handle a complicated move */ |
||
7772 | rc = RC_IRET; |
||
7773 | } |
||
7774 | |||
7775 | r2 = gv(rc); |
||
7776 | /* this is horrible, but we must also convert first |
||
7777 | operand */ |
||
7778 | tt = gjmp(0); |
||
7779 | gsym(u); |
||
7780 | /* put again first value and cast it */ |
||
7781 | *vtop = sv; |
||
7782 | gen_cast(&type); |
||
7783 | r1 = gv(rc); |
||
7784 | move_reg(r2, r1); |
||
7785 | vtop->r = r2; |
||
7786 | gsym(tt); |
||
7787 | } |
||
7788 | } |
||
7789 | } |
||
7790 | |||
7791 | static void gexpr(void) |
||
7792 | { |
||
7793 | while (1) { |
||
7794 | expr_eq(); |
||
7795 | if (tok != ',') |
||
7796 | break; |
||
7797 | vpop(); |
||
7798 | next(); |
||
7799 | } |
||
7800 | } |
||
7801 | |||
7802 | /* parse an expression and return its type without any side effect. */ |
||
7803 | static void expr_type(CType *type) |
||
7804 | { |
||
7805 | int saved_nocode_wanted; |
||
7806 | |||
7807 | saved_nocode_wanted = nocode_wanted; |
||
7808 | nocode_wanted = 1; |
||
7809 | gexpr(); |
||
7810 | *type = vtop->type; |
||
7811 | vpop(); |
||
7812 | nocode_wanted = saved_nocode_wanted; |
||
7813 | } |
||
7814 | |||
7815 | /* parse a unary expression and return its type without any side |
||
7816 | effect. */ |
||
7817 | static void unary_type(CType *type) |
||
7818 | { |
||
7819 | int a; |
||
7820 | |||
7821 | a = nocode_wanted; |
||
7822 | nocode_wanted = 1; |
||
7823 | unary(); |
||
7824 | *type = vtop->type; |
||
7825 | vpop(); |
||
7826 | nocode_wanted = a; |
||
7827 | } |
||
7828 | |||
7829 | /* parse a constant expression and return value in vtop. */ |
||
7830 | static void expr_const1(void) |
||
7831 | { |
||
7832 | int a; |
||
7833 | a = const_wanted; |
||
7834 | const_wanted = 1; |
||
7835 | expr_eq(); |
||
7836 | const_wanted = a; |
||
7837 | } |
||
7838 | |||
7839 | /* parse an integer constant and return its value. */ |
||
7840 | static int expr_const(void) |
||
7841 | { |
||
7842 | int c; |
||
7843 | expr_const1(); |
||
7844 | if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) != VT_CONST) |
||
7845 | expect("constant expression"); |
||
7846 | c = vtop->c.i; |
||
7847 | vpop(); |
||
7848 | return c; |
||
7849 | } |
||
7850 | |||
7851 | /* return the label token if current token is a label, otherwise |
||
7852 | return zero */ |
||
7853 | static int is_label(void) |
||
7854 | { |
||
7855 | int last_tok; |
||
7856 | |||
7857 | /* fast test first */ |
||
7858 | if (tok < TOK_UIDENT) |
||
7859 | return 0; |
||
7860 | /* no need to save tokc because tok is an identifier */ |
||
7861 | last_tok = tok; |
||
7862 | next(); |
||
7863 | if (tok == ':') { |
||
7864 | next(); |
||
7865 | return last_tok; |
||
7866 | } else { |
||
7867 | unget_tok(last_tok); |
||
7868 | return 0; |
||
7869 | } |
||
7870 | } |
||
7871 | |||
7872 | static void block(int *bsym, int *csym, int *case_sym, int *def_sym, |
||
7873 | int case_reg, int is_expr) |
||
7874 | { |
||
7875 | int a, b, c, d; |
||
7876 | Sym *s; |
||
7877 | |||
7878 | /* generate line number info */ |
||
7879 | if (do_debug && |
||
7880 | (last_line_num != file->line_num || last_ind != ind)) { |
||
7881 | put_stabn(N_SLINE, 0, file->line_num, ind - func_ind); |
||
7882 | last_ind = ind; |
||
7883 | last_line_num = file->line_num; |
||
7884 | } |
||
7885 | |||
7886 | if (is_expr) { |
||
7887 | /* default return value is (void) */ |
||
7888 | vpushi(0); |
||
7889 | vtop->type.t = VT_VOID; |
||
7890 | } |
||
7891 | |||
7892 | if (tok == TOK_IF) { |
||
7893 | /* if test */ |
||
7894 | next(); |
||
7895 | skip('('); |
||
7896 | gexpr(); |
||
7897 | skip(')'); |
||
7898 | a = gtst(1, 0); |
||
7899 | block(bsym, csym, case_sym, def_sym, case_reg, 0); |
||
7900 | c = tok; |
||
7901 | if (c == TOK_ELSE) { |
||
7902 | next(); |
||
7903 | d = gjmp(0); |
||
7904 | gsym(a); |
||
7905 | block(bsym, csym, case_sym, def_sym, case_reg, 0); |
||
7906 | gsym(d); /* patch else jmp */ |
||
7907 | } else |
||
7908 | gsym(a); |
||
7909 | } else if (tok == TOK_WHILE) { |
||
7910 | next(); |
||
7911 | d = ind; |
||
7912 | skip('('); |
||
7913 | gexpr(); |
||
7914 | skip(')'); |
||
7915 | a = gtst(1, 0); |
||
7916 | b = 0; |
||
7917 | block(&a, &b, case_sym, def_sym, case_reg, 0); |
||
7918 | gjmp_addr(d); |
||
7919 | gsym(a); |
||
7920 | gsym_addr(b, d); |
||
7921 | } else if (tok == '{') { |
||
7922 | Sym *llabel; |
||
7923 | |||
7924 | next(); |
||
7925 | /* record local declaration stack position */ |
||
7926 | s = local_stack; |
||
7927 | llabel = local_label_stack; |
||
7928 | /* handle local labels declarations */ |
||
7929 | if (tok == TOK_LABEL) { |
||
7930 | next(); |
||
7931 | for(;;) { |
||
7932 | if (tok < TOK_UIDENT) |
||
7933 | expect("label identifier"); |
||
7934 | label_push(&local_label_stack, tok, LABEL_DECLARED); |
||
7935 | next(); |
||
7936 | if (tok == ',') { |
||
7937 | next(); |
||
7938 | } else { |
||
7939 | skip(';'); |
||
7940 | break; |
||
7941 | } |
||
7942 | } |
||
7943 | } |
||
7944 | while (tok != '}') { |
||
7945 | decl(VT_LOCAL); |
||
7946 | if (tok != '}') { |
||
7947 | if (is_expr) |
||
7948 | vpop(); |
||
7949 | block(bsym, csym, case_sym, def_sym, case_reg, is_expr); |
||
7950 | } |
||
7951 | } |
||
7952 | /* pop locally defined labels */ |
||
7953 | label_pop(&local_label_stack, llabel); |
||
7954 | /* pop locally defined symbols */ |
||
7955 | sym_pop(&local_stack, s); |
||
7956 | next(); |
||
7957 | } else if (tok == TOK_RETURN) { |
||
7958 | next(); |
||
7959 | if (tok != ';') { |
||
7960 | gexpr(); |
||
7961 | gen_assign_cast(&func_vt); |
||
7962 | if ((func_vt.t & VT_BTYPE) == VT_STRUCT) { |
||
7963 | CType type; |
||
7964 | /* if returning structure, must copy it to implicit |
||
7965 | first pointer arg location */ |
||
7966 | type = func_vt; |
||
7967 | mk_pointer(&type); |
||
7968 | vset(&type, VT_LOCAL | VT_LVAL, func_vc); |
||
7969 | indir(); |
||
7970 | vswap(); |
||
7971 | /* copy structure value to pointer */ |
||
7972 | vstore(); |
||
7973 | } else if (is_float(func_vt.t)) { |
||
7974 | gv(RC_FRET); |
||
7975 | } else { |
||
7976 | gv(RC_IRET); |
||
7977 | } |
||
7978 | vtop--; /* NOT vpop() because on x86 it would flush the fp stack */ |
||
7979 | } |
||
7980 | skip(';'); |
||
7981 | rsym = gjmp(rsym); /* jmp */ |
||
7982 | } else if (tok == TOK_BREAK) { |
||
7983 | /* compute jump */ |
||
7984 | if (!bsym) |
||
7985 | error("cannot break"); |
||
7986 | *bsym = gjmp(*bsym); |
||
7987 | next(); |
||
7988 | skip(';'); |
||
7989 | } else if (tok == TOK_CONTINUE) { |
||
7990 | /* compute jump */ |
||
7991 | if (!csym) |
||
7992 | error("cannot continue"); |
||
7993 | *csym = gjmp(*csym); |
||
7994 | next(); |
||
7995 | skip(';'); |
||
7996 | } else if (tok == TOK_FOR) { |
||
7997 | int e; |
||
7998 | next(); |
||
7999 | skip('('); |
||
8000 | if (tok != ';') { |
||
8001 | gexpr(); |
||
8002 | vpop(); |
||
8003 | } |
||
8004 | skip(';'); |
||
8005 | d = ind; |
||
8006 | c = ind; |
||
8007 | a = 0; |
||
8008 | b = 0; |
||
8009 | if (tok != ';') { |
||
8010 | gexpr(); |
||
8011 | a = gtst(1, 0); |
||
8012 | } |
||
8013 | skip(';'); |
||
8014 | if (tok != ')') { |
||
8015 | e = gjmp(0); |
||
8016 | c = ind; |
||
8017 | gexpr(); |
||
8018 | vpop(); |
||
8019 | gjmp_addr(d); |
||
8020 | gsym(e); |
||
8021 | } |
||
8022 | skip(')'); |
||
8023 | block(&a, &b, case_sym, def_sym, case_reg, 0); |
||
8024 | gjmp_addr(c); |
||
8025 | gsym(a); |
||
8026 | gsym_addr(b, c); |
||
8027 | } else |
||
8028 | if (tok == TOK_DO) { |
||
8029 | next(); |
||
8030 | a = 0; |
||
8031 | b = 0; |
||
8032 | d = ind; |
||
8033 | block(&a, &b, case_sym, def_sym, case_reg, 0); |
||
8034 | skip(TOK_WHILE); |
||
8035 | skip('('); |
||
8036 | gsym(b); |
||
8037 | gexpr(); |
||
8038 | c = gtst(0, 0); |
||
8039 | gsym_addr(c, d); |
||
8040 | skip(')'); |
||
8041 | gsym(a); |
||
8042 | skip(';'); |
||
8043 | } else |
||
8044 | if (tok == TOK_SWITCH) { |
||
8045 | next(); |
||
8046 | skip('('); |
||
8047 | gexpr(); |
||
8048 | /* XXX: other types than integer */ |
||
8049 | case_reg = gv(RC_INT); |
||
8050 | vpop(); |
||
8051 | skip(')'); |
||
8052 | a = 0; |
||
8053 | b = gjmp(0); /* jump to first case */ |
||
8054 | c = 0; |
||
8055 | block(&a, csym, &b, &c, case_reg, 0); |
||
8056 | /* if no default, jmp after switch */ |
||
8057 | if (c == 0) |
||
8058 | c = ind; |
||
8059 | /* default label */ |
||
8060 | gsym_addr(b, c); |
||
8061 | /* break label */ |
||
8062 | gsym(a); |
||
8063 | } else |
||
8064 | if (tok == TOK_CASE) { |
||
8065 | int v1, v2; |
||
8066 | if (!case_sym) |
||
8067 | expect("switch"); |
||
8068 | next(); |
||
8069 | v1 = expr_const(); |
||
8070 | v2 = v1; |
||
8071 | if (gnu_ext && tok == TOK_DOTS) { |
||
8072 | next(); |
||
8073 | v2 = expr_const(); |
||
8074 | if (v2 < v1) |
||
8075 | warning("empty case range"); |
||
8076 | } |
||
8077 | /* since a case is like a label, we must skip it with a jmp */ |
||
8078 | b = gjmp(0); |
||
8079 | gsym(*case_sym); |
||
8080 | vseti(case_reg, 0); |
||
8081 | vpushi(v1); |
||
8082 | if (v1 == v2) { |
||
8083 | gen_op(TOK_EQ); |
||
8084 | *case_sym = gtst(1, 0); |
||
8085 | } else { |
||
8086 | gen_op(TOK_GE); |
||
8087 | *case_sym = gtst(1, 0); |
||
8088 | vseti(case_reg, 0); |
||
8089 | vpushi(v2); |
||
8090 | gen_op(TOK_LE); |
||
8091 | *case_sym = gtst(1, *case_sym); |
||
8092 | } |
||
8093 | gsym(b); |
||
8094 | skip(':'); |
||
8095 | is_expr = 0; |
||
8096 | goto block_after_label; |
||
8097 | } else |
||
8098 | if (tok == TOK_DEFAULT) { |
||
8099 | next(); |
||
8100 | skip(':'); |
||
8101 | if (!def_sym) |
||
8102 | expect("switch"); |
||
8103 | if (*def_sym) |
||
8104 | error("too many 'default'"); |
||
8105 | *def_sym = ind; |
||
8106 | is_expr = 0; |
||
8107 | goto block_after_label; |
||
8108 | } else |
||
8109 | if (tok == TOK_GOTO) { |
||
8110 | next(); |
||
8111 | if (tok == '*' && gnu_ext) { |
||
8112 | /* computed goto */ |
||
8113 | next(); |
||
8114 | gexpr(); |
||
8115 | if ((vtop->type.t & VT_BTYPE) != VT_PTR) |
||
8116 | expect("pointer"); |
||
8117 | ggoto(); |
||
8118 | } else if (tok >= TOK_UIDENT) { |
||
8119 | s = label_find(tok); |
||
8120 | /* put forward definition if needed */ |
||
8121 | if (!s) { |
||
8122 | s = label_push(&global_label_stack, tok, LABEL_FORWARD); |
||
8123 | } else { |
||
8124 | if (s->r == LABEL_DECLARED) |
||
8125 | s->r = LABEL_FORWARD; |
||
8126 | } |
||
8127 | /* label already defined */ |
||
8128 | if (s->r & LABEL_FORWARD) |
||
8129 | s->next = (void *)gjmp((long)s->next); |
||
8130 | else |
||
8131 | gjmp_addr((long)s->next); |
||
8132 | next(); |
||
8133 | } else { |
||
8134 | expect("label identifier"); |
||
8135 | } |
||
8136 | skip(';'); |
||
8137 | } else if (tok == TOK_ASM1 || tok == TOK_ASM2 || tok == TOK_ASM3) { |
||
8138 | asm_instr(); |
||
8139 | } else { |
||
8140 | b = is_label(); |
||
8141 | if (b) { |
||
8142 | /* label case */ |
||
8143 | s = label_find(b); |
||
8144 | if (s) { |
||
8145 | if (s->r == LABEL_DEFINED) |
||
8146 | error("duplicate label '%s'", get_tok_str(s->v, NULL)); |
||
8147 | gsym((long)s->next); |
||
8148 | s->r = LABEL_DEFINED; |
||
8149 | } else { |
||
8150 | s = label_push(&global_label_stack, b, LABEL_DEFINED); |
||
8151 | } |
||
8152 | s->next = (void *)ind; |
||
8153 | /* we accept this, but it is a mistake */ |
||
8154 | block_after_label: |
||
8155 | if (tok == '}') { |
||
8156 | warning("deprecated use of label at end of compound statement"); |
||
8157 | } else { |
||
8158 | if (is_expr) |
||
8159 | vpop(); |
||
8160 | block(bsym, csym, case_sym, def_sym, case_reg, is_expr); |
||
8161 | } |
||
8162 | } else { |
||
8163 | /* expression case */ |
||
8164 | if (tok != ';') { |
||
8165 | if (is_expr) { |
||
8166 | vpop(); |
||
8167 | gexpr(); |
||
8168 | } else { |
||
8169 | gexpr(); |
||
8170 | vpop(); |
||
8171 | } |
||
8172 | } |
||
8173 | skip(';'); |
||
8174 | } |
||
8175 | } |
||
8176 | } |
||
8177 | |||
8178 | /* t is the array or struct type. c is the array or struct |
||
8179 | address. cur_index/cur_field is the pointer to the current |
||
8180 | value. 'size_only' is true if only size info is needed (only used |
||
8181 | in arrays) */ |
||
8182 | static void decl_designator(CType *type, Section *sec, unsigned long c, |
||
8183 | int *cur_index, Sym **cur_field, |
||
8184 | int size_only) |
||
8185 | { |
||
8186 | Sym *s, *f; |
||
8187 | int notfirst, index, index_last, align, l, nb_elems, elem_size; |
||
8188 | CType type1; |
||
8189 | |||
8190 | notfirst = 0; |
||
8191 | elem_size = 0; |
||
8192 | nb_elems = 1; |
||
8193 | if (gnu_ext && (l = is_label()) != 0) |
||
8194 | goto struct_field; |
||
8195 | while (tok == '[' || tok == '.') { |
||
8196 | if (tok == '[') { |
||
8197 | if (!(type->t & VT_ARRAY)) |
||
8198 | expect("array type"); |
||
8199 | s = type->ref; |
||
8200 | next(); |
||
8201 | index = expr_const(); |
||
8202 | if (index < 0 || (s->c >= 0 && index >= s->c)) |
||
8203 | expect("invalid index"); |
||
8204 | if (tok == TOK_DOTS && gnu_ext) { |
||
8205 | next(); |
||
8206 | index_last = expr_const(); |
||
8207 | if (index_last < 0 || |
||
8208 | (s->c >= 0 && index_last >= s->c) || |
||
8209 | index_last < index) |
||
8210 | expect("invalid index"); |
||
8211 | } else { |
||
8212 | index_last = index; |
||
8213 | } |
||
8214 | skip(']'); |
||
8215 | if (!notfirst) |
||
8216 | *cur_index = index_last; |
||
8217 | type = pointed_type(type); |
||
8218 | elem_size = type_size(type, &align); |
||
8219 | c += index * elem_size; |
||
8220 | /* NOTE: we only support ranges for last designator */ |
||
8221 | nb_elems = index_last - index + 1; |
||
8222 | if (nb_elems != 1) { |
||
8223 | notfirst = 1; |
||
8224 | break; |
||
8225 | } |
||
8226 | } else { |
||
8227 | next(); |
||
8228 | l = tok; |
||
8229 | next(); |
||
8230 | struct_field: |
||
8231 | if ((type->t & VT_BTYPE) != VT_STRUCT) |
||
8232 | expect("struct/union type"); |
||
8233 | s = type->ref; |
||
8234 | l |= SYM_FIELD; |
||
8235 | f = s->next; |
||
8236 | while (f) { |
||
8237 | if (f->v == l) |
||
8238 | break; |
||
8239 | f = f->next; |
||
8240 | } |
||
8241 | if (!f) |
||
8242 | expect("field"); |
||
8243 | if (!notfirst) |
||
8244 | *cur_field = f; |
||
8245 | /* XXX: fix this mess by using explicit storage field */ |
||
8246 | type1 = f->type; |
||
8247 | type1.t |= (type->t & ~VT_TYPE); |
||
8248 | type = &type1; |
||
8249 | c += f->c; |
||
8250 | } |
||
8251 | notfirst = 1; |
||
8252 | } |
||
8253 | if (notfirst) { |
||
8254 | if (tok == '=') { |
||
8255 | next(); |
||
8256 | } else { |
||
8257 | if (!gnu_ext) |
||
8258 | expect("="); |
||
8259 | } |
||
8260 | } else { |
||
8261 | if (type->t & VT_ARRAY) { |
||
8262 | index = *cur_index; |
||
8263 | type = pointed_type(type); |
||
8264 | c += index * type_size(type, &align); |
||
8265 | } else { |
||
8266 | f = *cur_field; |
||
8267 | if (!f) |
||
8268 | error("too many field init"); |
||
8269 | /* XXX: fix this mess by using explicit storage field */ |
||
8270 | type1 = f->type; |
||
8271 | type1.t |= (type->t & ~VT_TYPE); |
||
8272 | type = &type1; |
||
8273 | c += f->c; |
||
8274 | } |
||
8275 | } |
||
8276 | decl_initializer(type, sec, c, 0, size_only); |
||
8277 | |||
8278 | /* XXX: make it more general */ |
||
8279 | if (!size_only && nb_elems > 1) { |
||
8280 | unsigned long c_end; |
||
8281 | uint8_t *src, *dst; |
||
8282 | int i; |
||
8283 | |||
8284 | if (!sec) |
||
8285 | error("range init not supported yet for dynamic storage"); |
||
8286 | c_end = c + nb_elems * elem_size; |
||
8287 | if (c_end > sec->data_allocated) |
||
8288 | section_realloc(sec, c_end); |
||
8289 | src = sec->data + c; |
||
8290 | dst = src; |
||
8291 | for(i = 1; i < nb_elems; i++) { |
||
8292 | dst += elem_size; |
||
8293 | memcpy(dst, src, elem_size); |
||
8294 | } |
||
8295 | } |
||
8296 | } |
||
8297 | |||
8298 | #define EXPR_VAL 0 |
||
8299 | #define EXPR_CONST 1 |
||
8300 | #define EXPR_ANY 2 |
||
8301 | |||
8302 | /* store a value or an expression directly in global data or in local array */ |
||
8303 | static void init_putv(CType *type, Section *sec, unsigned long c, |
||
8304 | int v, int expr_type) |
||
8305 | { |
||
8306 | int saved_global_expr, bt, bit_pos, bit_size; |
||
8307 | void *ptr; |
||
8308 | unsigned long long bit_mask; |
||
8309 | CType dtype; |
||
8310 | |||
8311 | switch(expr_type) { |
||
8312 | case EXPR_VAL: |
||
8313 | vpushi(v); |
||
8314 | break; |
||
8315 | case EXPR_CONST: |
||
8316 | /* compound literals must be allocated globally in this case */ |
||
8317 | saved_global_expr = global_expr; |
||
8318 | global_expr = 1; |
||
8319 | expr_const1(); |
||
8320 | global_expr = saved_global_expr; |
||
8321 | /* NOTE: symbols are accepted */ |
||
8322 | if ((vtop->r & (VT_VALMASK | VT_LVAL)) != VT_CONST) |
||
8323 | error("initializer element is not constant"); |
||
8324 | break; |
||
8325 | case EXPR_ANY: |
||
8326 | expr_eq(); |
||
8327 | break; |
||
8328 | } |
||
8329 | |||
8330 | dtype = *type; |
||
8331 | dtype.t &= ~VT_CONSTANT; /* need to do that to avoid false warning */ |
||
8332 | |||
8333 | if (sec) { |
||
8334 | /* XXX: not portable */ |
||
8335 | /* XXX: generate error if incorrect relocation */ |
||
8336 | gen_assign_cast(&dtype); |
||
8337 | bt = type->t & VT_BTYPE; |
||
8338 | ptr = sec->data + c; |
||
8339 | /* XXX: make code faster ? */ |
||
8340 | if (!(type->t & VT_BITFIELD)) { |
||
8341 | bit_pos = 0; |
||
8342 | bit_size = 32; |
||
8343 | bit_mask = -1LL; |
||
8344 | } else { |
||
8345 | bit_pos = (vtop->type.t >> VT_STRUCT_SHIFT) & 0x3f; |
||
8346 | bit_size = (vtop->type.t >> (VT_STRUCT_SHIFT + 6)) & 0x3f; |
||
8347 | bit_mask = (1LL << bit_size) - 1; |
||
8348 | } |
||
8349 | if ((vtop->r & VT_SYM) && |
||
8350 | (bt == VT_BYTE || |
||
8351 | bt == VT_SHORT || |
||
8352 | bt == VT_DOUBLE || |
||
8353 | bt == VT_LDOUBLE || |
||
8354 | bt == VT_LLONG || |
||
8355 | (bt == VT_INT && bit_size != 32))) |
||
8356 | error("initializer element is not computable at load time"); |
||
8357 | switch(bt) { |
||
8358 | case VT_BYTE: |
||
8359 | *(char *)ptr |= (vtop->c.i & bit_mask) << bit_pos; |
||
8360 | break; |
||
8361 | case VT_SHORT: |
||
8362 | *(short *)ptr |= (vtop->c.i & bit_mask) << bit_pos; |
||
8363 | break; |
||
8364 | case VT_DOUBLE: |
||
8365 | *(double *)ptr = vtop->c.d; |
||
8366 | break; |
||
8367 | case VT_LDOUBLE: |
||
8368 | *(long double *)ptr = vtop->c.ld; |
||
8369 | break; |
||
8370 | case VT_LLONG: |
||
8371 | *(long long *)ptr |= (vtop->c.ll & bit_mask) << bit_pos; |
||
8372 | break; |
||
8373 | default: |
||
8374 | if (vtop->r & VT_SYM) { |
||
8375 | greloc(sec, vtop->sym, c, R_DATA_32); |
||
8376 | } |
||
8377 | *(int *)ptr |= (vtop->c.i & bit_mask) << bit_pos; |
||
8378 | break; |
||
8379 | } |
||
8380 | vtop--; |
||
8381 | } else { |
||
8382 | vset(&dtype, VT_LOCAL, c); |
||
8383 | vswap(); |
||
8384 | vstore(); |
||
8385 | vpop(); |
||
8386 | } |
||
8387 | } |
||
8388 | |||
8389 | /* put zeros for variable based init */ |
||
8390 | static void init_putz(CType *t, Section *sec, unsigned long c, int size) |
||
8391 | { |
||
8392 | if (sec) { |
||
8393 | /* nothing to do because globals are already set to zero */ |
||
8394 | } else { |
||
8395 | vpush_global_sym(&func_old_type, TOK_memset); |
||
8396 | vseti(VT_LOCAL, c); |
||
8397 | vpushi(0); |
||
8398 | vpushi(size); |
||
8399 | gfunc_call(3); |
||
8400 | } |
||
8401 | } |
||
8402 | |||
8403 | /* 't' contains the type and storage info. 'c' is the offset of the |
||
8404 | object in section 'sec'. If 'sec' is NULL, it means stack based |
||
8405 | allocation. 'first' is true if array '{' must be read (multi |
||
8406 | dimension implicit array init handling). 'size_only' is true if |
||
8407 | size only evaluation is wanted (only for arrays). */ |
||
8408 | static void decl_initializer(CType *type, Section *sec, unsigned long c, |
||
8409 | int first, int size_only) |
||
8410 | { |
||
8411 | int index, array_length, n, no_oblock, nb, parlevel, i; |
||
8412 | int size1, align1, expr_type; |
||
8413 | Sym *s, *f; |
||
8414 | CType *t1; |
||
8415 | |||
8416 | if (type->t & VT_ARRAY) { |
||
8417 | s = type->ref; |
||
8418 | n = s->c; |
||
8419 | array_length = 0; |
||
8420 | t1 = pointed_type(type); |
||
8421 | size1 = type_size(t1, &align1); |
||
8422 | |||
8423 | no_oblock = 1; |
||
8424 | if ((first && tok != TOK_LSTR && tok != TOK_STR) || |
||
8425 | tok == '{') { |
||
8426 | skip('{'); |
||
8427 | no_oblock = 0; |
||
8428 | } |
||
8429 | |||
8430 | /* only parse strings here if correct type (otherwise: handle |
||
8431 | them as ((w)char *) expressions */ |
||
8432 | if ((tok == TOK_LSTR && |
||
8433 | (t1->t & VT_BTYPE) == VT_INT) || |
||
8434 | (tok == TOK_STR && |
||
8435 | (t1->t & VT_BTYPE) == VT_BYTE)) { |
||
8436 | while (tok == TOK_STR || tok == TOK_LSTR) { |
||
8437 | int cstr_len, ch; |
||
8438 | CString *cstr; |
||
8439 | |||
8440 | cstr = tokc.cstr; |
||
8441 | /* compute maximum number of chars wanted */ |
||
8442 | if (tok == TOK_STR) |
||
8443 | cstr_len = cstr->size; |
||
8444 | else |
||
8445 | cstr_len = cstr->size / sizeof(int); |
||
8446 | cstr_len--; |
||
8447 | nb = cstr_len; |
||
8448 | if (n >= 0 && nb > (n - array_length)) |
||
8449 | nb = n - array_length; |
||
8450 | if (!size_only) { |
||
8451 | if (cstr_len > nb) |
||
8452 | warning("initializer-string for array is too long"); |
||
8453 | /* in order to go faster for common case (char |
||
8454 | string in global variable, we handle it |
||
8455 | specifically */ |
||
8456 | if (sec && tok == TOK_STR && size1 == 1) { |
||
8457 | memcpy(sec->data + c + array_length, cstr->data, nb); |
||
8458 | } else { |
||
8459 | for(i=0;i |
||
8460 | if (tok == TOK_STR) |
||
8461 | ch = ((unsigned char *)cstr->data)[i]; |
||
8462 | else |
||
8463 | ch = ((int *)cstr->data)[i]; |
||
8464 | init_putv(t1, sec, c + (array_length + i) * size1, |
||
8465 | ch, EXPR_VAL); |
||
8466 | } |
||
8467 | } |
||
8468 | } |
||
8469 | array_length += nb; |
||
8470 | next(); |
||
8471 | } |
||
8472 | /* only add trailing zero if enough storage (no |
||
8473 | warning in this case since it is standard) */ |
||
8474 | if (n < 0 || array_length < n) { |
||
8475 | if (!size_only) { |
||
8476 | init_putv(t1, sec, c + (array_length * size1), 0, EXPR_VAL); |
||
8477 | } |
||
8478 | array_length++; |
||
8479 | } |
||
8480 | } else { |
||
8481 | index = 0; |
||
8482 | while (tok != '}') { |
||
8483 | decl_designator(type, sec, c, &index, NULL, size_only); |
||
8484 | if (n >= 0 && index >= n) |
||
8485 | error("index too large"); |
||
8486 | /* must put zero in holes (note that doing it that way |
||
8487 | ensures that it even works with designators) */ |
||
8488 | if (!size_only && array_length < index) { |
||
8489 | init_putz(t1, sec, c + array_length * size1, |
||
8490 | (index - array_length) * size1); |
||
8491 | } |
||
8492 | index++; |
||
8493 | if (index > array_length) |
||
8494 | array_length = index; |
||
8495 | /* special test for multi dimensional arrays (may not |
||
8496 | be strictly correct if designators are used at the |
||
8497 | same time) */ |
||
8498 | if (index >= n && no_oblock) |
||
8499 | break; |
||
8500 | if (tok == '}') |
||
8501 | break; |
||
8502 | skip(','); |
||
8503 | } |
||
8504 | } |
||
8505 | if (!no_oblock) |
||
8506 | skip('}'); |
||
8507 | /* put zeros at the end */ |
||
8508 | if (!size_only && n >= 0 && array_length < n) { |
||
8509 | init_putz(t1, sec, c + array_length * size1, |
||
8510 | (n - array_length) * size1); |
||
8511 | } |
||
8512 | /* patch type size if needed */ |
||
8513 | if (n < 0) |
||
8514 | s->c = array_length; |
||
8515 | } else if ((type->t & VT_BTYPE) == VT_STRUCT && |
||
8516 | (sec || !first || tok == '{')) { |
||
8517 | int par_count; |
||
8518 | |||
8519 | /* NOTE: the previous test is a specific case for automatic |
||
8520 | struct/union init */ |
||
8521 | /* XXX: union needs only one init */ |
||
8522 | |||
8523 | /* XXX: this test is incorrect for local initializers |
||
8524 | beginning with ( without {. It would be much more difficult |
||
8525 | to do it correctly (ideally, the expression parser should |
||
8526 | be used in all cases) */ |
||
8527 | par_count = 0; |
||
8528 | if (tok == '(') { |
||
8529 | AttributeDef ad1; |
||
8530 | CType type1; |
||
8531 | next(); |
||
8532 | while (tok == '(') { |
||
8533 | par_count++; |
||
8534 | next(); |
||
8535 | } |
||
8536 | if (!parse_btype(&type1, &ad1)) |
||
8537 | expect("cast"); |
||
8538 | type_decl(&type1, &ad1, &n, TYPE_ABSTRACT); |
||
8539 | #if 0 |
||
8540 | if (!is_assignable_types(type, &type1)) |
||
8541 | error("invalid type for cast"); |
||
8542 | #endif |
||
8543 | skip(')'); |
||
8544 | } |
||
8545 | no_oblock = 1; |
||
8546 | if (first || tok == '{') { |
||
8547 | skip('{'); |
||
8548 | no_oblock = 0; |
||
8549 | } |
||
8550 | s = type->ref; |
||
8551 | f = s->next; |
||
8552 | array_length = 0; |
||
8553 | index = 0; |
||
8554 | n = s->c; |
||
8555 | while (tok != '}') { |
||
8556 | decl_designator(type, sec, c, NULL, &f, size_only); |
||
8557 | index = f->c; |
||
8558 | if (!size_only && array_length < index) { |
||
8559 | init_putz(type, sec, c + array_length, |
||
8560 | index - array_length); |
||
8561 | } |
||
8562 | index = index + type_size(&f->type, &align1); |
||
8563 | if (index > array_length) |
||
8564 | array_length = index; |
||
8565 | f = f->next; |
||
8566 | if (no_oblock && f == NULL) |
||
8567 | break; |
||
8568 | if (tok == '}') |
||
8569 | break; |
||
8570 | skip(','); |
||
8571 | } |
||
8572 | /* put zeros at the end */ |
||
8573 | if (!size_only && array_length < n) { |
||
8574 | init_putz(type, sec, c + array_length, |
||
8575 | n - array_length); |
||
8576 | } |
||
8577 | if (!no_oblock) |
||
8578 | skip('}'); |
||
8579 | while (par_count) { |
||
8580 | skip(')'); |
||
8581 | par_count--; |
||
8582 | } |
||
8583 | } else if (tok == '{') { |
||
8584 | next(); |
||
8585 | decl_initializer(type, sec, c, first, size_only); |
||
8586 | skip('}'); |
||
8587 | } else if (size_only) { |
||
8588 | /* just skip expression */ |
||
8589 | parlevel = 0; |
||
8590 | while ((parlevel > 0 || (tok != '}' && tok != ',')) && |
||
8591 | tok != -1) { |
||
8592 | if (tok == '(') |
||
8593 | parlevel++; |
||
8594 | else if (tok == ')') |
||
8595 | parlevel--; |
||
8596 | next(); |
||
8597 | } |
||
8598 | } else { |
||
8599 | /* currently, we always use constant expression for globals |
||
8600 | (may change for scripting case) */ |
||
8601 | expr_type = EXPR_CONST; |
||
8602 | if (!sec) |
||
8603 | expr_type = EXPR_ANY; |
||
8604 | init_putv(type, sec, c, 0, expr_type); |
||
8605 | } |
||
8606 | } |
||
8607 | |||
8608 | /* parse an initializer for type 't' if 'has_init' is non zero, and |
||
8609 | allocate space in local or global data space ('r' is either |
||
8610 | VT_LOCAL or VT_CONST). If 'v' is non zero, then an associated |
||
8611 | variable 'v' of scope 'scope' is declared before initializers are |
||
8612 | parsed. If 'v' is zero, then a reference to the new object is put |
||
8613 | in the value stack. If 'has_init' is 2, a special parsing is done |
||
8614 | to handle string constants. */ |
||
8615 | static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, |
||
8616 | int has_init, int v, int scope) |
||
8617 | { |
||
8618 | int size, align, addr, data_offset; |
||
8619 | int level; |
||
8620 | ParseState saved_parse_state; |
||
8621 | TokenString init_str; |
||
8622 | Section *sec; |
||
8623 | |||
8624 | size = type_size(type, &align); |
||
8625 | /* If unknown size, we must evaluate it before |
||
8626 | evaluating initializers because |
||
8627 | initializers can generate global data too |
||
8628 | (e.g. string pointers or ISOC99 compound |
||
8629 | literals). It also simplifies local |
||
8630 | initializers handling */ |
||
8631 | tok_str_new(&init_str); |
||
8632 | if (size < 0) { |
||
8633 | if (!has_init) |
||
8634 | error("unknown type size"); |
||
8635 | /* get all init string */ |
||
8636 | if (has_init == 2) { |
||
8637 | /* only get strings */ |
||
8638 | while (tok == TOK_STR || tok == TOK_LSTR) { |
||
8639 | tok_str_add_tok(&init_str); |
||
8640 | next(); |
||
8641 | } |
||
8642 | } else { |
||
8643 | level = 0; |
||
8644 | while (level > 0 || (tok != ',' && tok != ';')) { |
||
8645 | if (tok < 0) |
||
8646 | error("unexpected end of file in initializer"); |
||
8647 | tok_str_add_tok(&init_str); |
||
8648 | if (tok == '{') |
||
8649 | level++; |
||
8650 | else if (tok == '}') { |
||
8651 | if (level == 0) |
||
8652 | break; |
||
8653 | level--; |
||
8654 | } |
||
8655 | next(); |
||
8656 | } |
||
8657 | } |
||
8658 | tok_str_add(&init_str, -1); |
||
8659 | tok_str_add(&init_str, 0); |
||
8660 | |||
8661 | /* compute size */ |
||
8662 | save_parse_state(&saved_parse_state); |
||
8663 | |||
8664 | macro_ptr = init_str.str; |
||
8665 | next(); |
||
8666 | decl_initializer(type, NULL, 0, 1, 1); |
||
8667 | /* prepare second initializer parsing */ |
||
8668 | macro_ptr = init_str.str; |
||
8669 | next(); |
||
8670 | |||
8671 | /* if still unknown size, error */ |
||
8672 | size = type_size(type, &align); |
||
8673 | if (size < 0) |
||
8674 | error("unknown type size"); |
||
8675 | } |
||
8676 | /* take into account specified alignment if bigger */ |
||
8677 | if (ad->aligned) { |
||
8678 | if (ad->aligned > align) |
||
8679 | align = ad->aligned; |
||
8680 | } else if (ad->packed) { |
||
8681 | align = 1; |
||
8682 | } |
||
8683 | if ((r & VT_VALMASK) == VT_LOCAL) { |
||
8684 | sec = NULL; |
||
8685 | if (do_bounds_check && (type->t & VT_ARRAY)) |
||
8686 | loc--; |
||
8687 | loc = (loc - size) & -align; |
||
8688 | addr = loc; |
||
8689 | /* handles bounds */ |
||
8690 | /* XXX: currently, since we do only one pass, we cannot track |
||
8691 | '&' operators, so we add only arrays */ |
||
8692 | if (do_bounds_check && (type->t & VT_ARRAY)) { |
||
8693 | unsigned long *bounds_ptr; |
||
8694 | /* add padding between regions */ |
||
8695 | loc--; |
||
8696 | /* then add local bound info */ |
||
8697 | bounds_ptr = section_ptr_add(lbounds_section, 2 * sizeof(unsigned long)); |
||
8698 | bounds_ptr[0] = addr; |
||
8699 | bounds_ptr[1] = size; |
||
8700 | } |
||
8701 | if (v) { |
||
8702 | /* local variable */ |
||
8703 | sym_push(v, type, r, addr); |
||
8704 | } else { |
||
8705 | /* push local reference */ |
||
8706 | vset(type, r, addr); |
||
8707 | } |
||
8708 | } else { |
||
8709 | Sym *sym; |
||
8710 | |||
8711 | sym = NULL; |
||
8712 | if (v && scope == VT_CONST) { |
||
8713 | /* see if the symbol was already defined */ |
||
8714 | sym = sym_find(v); |
||
8715 | if (sym) { |
||
8716 | if (!is_compatible_types(&sym->type, type)) |
||
8717 | error("incompatible types for redefinition of '%s'", |
||
8718 | get_tok_str(v, NULL)); |
||
8719 | if (sym->type.t & VT_EXTERN) { |
||
8720 | /* if the variable is extern, it was not allocated */ |
||
8721 | sym->type.t &= ~VT_EXTERN; |
||
8722 | /* set array size if it was ommited in extern |
||
8723 | declaration */ |
||
8724 | if ((sym->type.t & VT_ARRAY) && |
||
8725 | sym->type.ref->c < 0 && |
||
8726 | type->ref->c >= 0) |
||
8727 | sym->type.ref->c = type->ref->c; |
||
8728 | } else { |
||
8729 | /* we accept several definitions of the same |
||
8730 | global variable. this is tricky, because we |
||
8731 | must play with the SHN_COMMON type of the symbol */ |
||
8732 | /* XXX: should check if the variable was already |
||
8733 | initialized. It is incorrect to initialized it |
||
8734 | twice */ |
||
8735 | /* no init data, we won't add more to the symbol */ |
||
8736 | if (!has_init) |
||
8737 | goto no_alloc; |
||
8738 | } |
||
8739 | } |
||
8740 | } |
||
8741 | |||
8742 | /* allocate symbol in corresponding section */ |
||
8743 | sec = ad->section; |
||
8744 | if (!sec) { |
||
8745 | if (has_init) |
||
8746 | sec = data_section; |
||
8747 | else if (tcc_state->nocommon) |
||
8748 | sec = bss_section; |
||
8749 | } |
||
8750 | if (sec) { |
||
8751 | data_offset = sec->data_offset; |
||
8752 | data_offset = (data_offset + align - 1) & -align; |
||
8753 | addr = data_offset; |
||
8754 | /* very important to increment global pointer at this time |
||
8755 | because initializers themselves can create new initializers */ |
||
8756 | data_offset += size; |
||
8757 | /* add padding if bound check */ |
||
8758 | if (do_bounds_check) |
||
8759 | data_offset++; |
||
8760 | sec->data_offset = data_offset; |
||
8761 | /* allocate section space to put the data */ |
||
8762 | if (sec->sh_type != SHT_NOBITS && |
||
8763 | data_offset > sec->data_allocated) |
||
8764 | section_realloc(sec, data_offset); |
||
8765 | /* align section if needed */ |
||
8766 | if (align > sec->sh_addralign) |
||
8767 | sec->sh_addralign = align; |
||
8768 | } else { |
||
8769 | addr = 0; /* avoid warning */ |
||
8770 | } |
||
8771 | |||
8772 | if (v) { |
||
8773 | if (scope == VT_CONST) { |
||
8774 | if (!sym) |
||
8775 | goto do_def; |
||
8776 | } else { |
||
8777 | do_def: |
||
8778 | sym = sym_push(v, type, r | VT_SYM, 0); |
||
8779 | } |
||
8780 | /* update symbol definition */ |
||
8781 | if (sec) { |
||
8782 | put_extern_sym(sym, sec, addr, size); |
||
8783 | } else { |
||
8784 | Elf32_Sym *esym; |
||
8785 | /* put a common area */ |
||
8786 | put_extern_sym(sym, NULL, align, size); |
||
8787 | /* XXX: find a nicer way */ |
||
8788 | esym = &((Elf32_Sym *)symtab_section->data)[sym->c]; |
||
8789 | esym->st_shndx = SHN_COMMON; |
||
8790 | } |
||
8791 | } else { |
||
8792 | CValue cval; |
||
8793 | |||
8794 | /* push global reference */ |
||
8795 | sym = get_sym_ref(type, sec, addr, size); |
||
8796 | cval.ul = 0; |
||
8797 | vsetc(type, VT_CONST | VT_SYM, &cval); |
||
8798 | vtop->sym = sym; |
||
8799 | } |
||
8800 | |||
8801 | /* handles bounds now because the symbol must be defined |
||
8802 | before for the relocation */ |
||
8803 | if (do_bounds_check) { |
||
8804 | unsigned long *bounds_ptr; |
||
8805 | |||
8806 | greloc(bounds_section, sym, bounds_section->data_offset, R_DATA_32); |
||
8807 | /* then add global bound info */ |
||
8808 | bounds_ptr = section_ptr_add(bounds_section, 2 * sizeof(long)); |
||
8809 | bounds_ptr[0] = 0; /* relocated */ |
||
8810 | bounds_ptr[1] = size; |
||
8811 | } |
||
8812 | } |
||
8813 | if (has_init) { |
||
8814 | decl_initializer(type, sec, addr, 1, 0); |
||
8815 | /* restore parse state if needed */ |
||
8816 | if (init_str.str) { |
||
8817 | tok_str_free(init_str.str); |
||
8818 | restore_parse_state(&saved_parse_state); |
||
8819 | } |
||
8820 | } |
||
8821 | no_alloc: ; |
||
8822 | } |
||
8823 | |||
8824 | void put_func_debug(Sym *sym) |
||
8825 | { |
||
8826 | char buf[512]; |
||
8827 | |||
8828 | /* stabs info */ |
||
8829 | /* XXX: we put here a dummy type */ |
||
8830 | snprintf(buf, sizeof(buf), "%s:%c1", |
||
8831 | funcname, sym->type.t & VT_STATIC ? 'f' : 'F'); |
||
8832 | put_stabs_r(buf, N_FUN, 0, file->line_num, 0, |
||
8833 | cur_text_section, sym->c); |
||
8834 | last_ind = 0; |
||
8835 | last_line_num = 0; |
||
8836 | } |
||
8837 | |||
8838 | /* parse an old style function declaration list */ |
||
8839 | /* XXX: check multiple parameter */ |
||
8840 | static void func_decl_list(Sym *func_sym) |
||
8841 | { |
||
8842 | AttributeDef ad; |
||
8843 | int v; |
||
8844 | Sym *s; |
||
8845 | CType btype, type; |
||
8846 | |||
8847 | /* parse each declaration */ |
||
8848 | while (tok != '{' && tok != ';' && tok != ',' && tok != TOK_EOF) { |
||
8849 | if (!parse_btype(&btype, &ad)) |
||
8850 | expect("declaration list"); |
||
8851 | if (((btype.t & VT_BTYPE) == VT_ENUM || |
||
8852 | (btype.t & VT_BTYPE) == VT_STRUCT) && |
||
8853 | tok == ';') { |
||
8854 | /* we accept no variable after */ |
||
8855 | } else { |
||
8856 | for(;;) { |
||
8857 | type = btype; |
||
8858 | type_decl(&type, &ad, &v, TYPE_DIRECT); |
||
8859 | /* find parameter in function parameter list */ |
||
8860 | s = func_sym->next; |
||
8861 | while (s != NULL) { |
||
8862 | if ((s->v & ~SYM_FIELD) == v) |
||
8863 | goto found; |
||
8864 | s = s->next; |
||
8865 | } |
||
8866 | error("declaration for parameter '%s' but no such parameter", |
||
8867 | get_tok_str(v, NULL)); |
||
8868 | found: |
||
8869 | /* check that no storage specifier except 'register' was given */ |
||
8870 | if (type.t & VT_STORAGE) |
||
8871 | error("storage class specified for '%s'", get_tok_str(v, NULL)); |
||
8872 | convert_parameter_type(&type); |
||
8873 | /* we can add the type (NOTE: it could be local to the function) */ |
||
8874 | s->type = type; |
||
8875 | /* accept other parameters */ |
||
8876 | if (tok == ',') |
||
8877 | next(); |
||
8878 | else |
||
8879 | break; |
||
8880 | } |
||
8881 | } |
||
8882 | skip(';'); |
||
8883 | } |
||
8884 | } |
||
8885 | |||
8886 | /* parse a function defined by symbol 'sym' and generate its code in |
||
8887 | 'cur_text_section' */ |
||
8888 | static void gen_function(Sym *sym) |
||
8889 | { |
||
8890 | ind = cur_text_section->data_offset; |
||
8891 | /* NOTE: we patch the symbol size later */ |
||
8892 | put_extern_sym(sym, cur_text_section, ind, 0); |
||
8893 | funcname = get_tok_str(sym->v, NULL); |
||
8894 | func_ind = ind; |
||
8895 | /* put debug symbol */ |
||
8896 | if (do_debug) |
||
8897 | put_func_debug(sym); |
||
8898 | /* push a dummy symbol to enable local sym storage */ |
||
8899 | sym_push2(&local_stack, SYM_FIELD, 0, 0); |
||
8900 | gfunc_prolog(&sym->type); |
||
8901 | rsym = 0; |
||
8902 | block(NULL, NULL, NULL, NULL, 0, 0); |
||
8903 | gsym(rsym); |
||
8904 | gfunc_epilog(); |
||
8905 | cur_text_section->data_offset = ind; |
||
8906 | label_pop(&global_label_stack, NULL); |
||
8907 | sym_pop(&local_stack, NULL); /* reset local stack */ |
||
8908 | /* end of function */ |
||
8909 | /* patch symbol size */ |
||
8910 | ((Elf32_Sym *)symtab_section->data)[sym->c].st_size = |
||
8911 | ind - func_ind; |
||
8912 | if (do_debug) { |
||
8913 | put_stabn(N_FUN, 0, 0, ind - func_ind); |
||
8914 | } |
||
8915 | funcname = ""; /* for safety */ |
||
8916 | func_vt.t = VT_VOID; /* for safety */ |
||
8917 | ind = 0; /* for safety */ |
||
8918 | } |
||
8919 | |||
8920 | static void gen_inline_functions(void) |
||
8921 | { |
||
8922 | Sym *sym; |
||
8923 | CType *type; |
||
8924 | int *str, inline_generated; |
||
8925 | |||
8926 | /* iterate while inline function are referenced */ |
||
8927 | for(;;) { |
||
8928 | inline_generated = 0; |
||
8929 | for(sym = global_stack; sym != NULL; sym = sym->prev) { |
||
8930 | type = &sym->type; |
||
8931 | if (((type->t & VT_BTYPE) == VT_FUNC) && |
||
8932 | (type->t & (VT_STATIC | VT_INLINE)) == |
||
8933 | (VT_STATIC | VT_INLINE) && |
||
8934 | sym->c != 0) { |
||
8935 | /* the function was used: generate its code and |
||
8936 | convert it to a normal function */ |
||
8937 | str = (int *)sym->r; |
||
8938 | sym->r = VT_SYM | VT_CONST; |
||
8939 | type->t &= ~VT_INLINE; |
||
8940 | |||
8941 | macro_ptr = str; |
||
8942 | next(); |
||
8943 | cur_text_section = text_section; |
||
8944 | gen_function(sym); |
||
8945 | macro_ptr = NULL; /* fail safe */ |
||
8946 | |||
8947 | tok_str_free(str); |
||
8948 | inline_generated = 1; |
||
8949 | } |
||
8950 | } |
||
8951 | if (!inline_generated) |
||
8952 | break; |
||
8953 | } |
||
8954 | |||
8955 | /* free all remaining inline function tokens */ |
||
8956 | for(sym = global_stack; sym != NULL; sym = sym->prev) { |
||
8957 | type = &sym->type; |
||
8958 | if (((type->t & VT_BTYPE) == VT_FUNC) && |
||
8959 | (type->t & (VT_STATIC | VT_INLINE)) == |
||
8960 | (VT_STATIC | VT_INLINE)) { |
||
8961 | str = (int *)sym->r; |
||
8962 | tok_str_free(str); |
||
8963 | sym->r = 0; /* fail safe */ |
||
8964 | } |
||
8965 | } |
||
8966 | } |
||
8967 | |||
8968 | /* 'l' is VT_LOCAL or VT_CONST to define default storage type */ |
||
8969 | static void decl(int l) |
||
8970 | { |
||
8971 | int v, has_init, r; |
||
8972 | CType type, btype; |
||
8973 | Sym *sym; |
||
8974 | AttributeDef ad; |
||
8975 | |||
8976 | while (1) { |
||
8977 | if (!parse_btype(&btype, &ad)) { |
||
8978 | /* skip redundant ';' */ |
||
8979 | /* XXX: find more elegant solution */ |
||
8980 | if (tok == ';') { |
||
8981 | next(); |
||
8982 | continue; |
||
8983 | } |
||
8984 | if (l == VT_CONST && |
||
8985 | (tok == TOK_ASM1 || tok == TOK_ASM2 || tok == TOK_ASM3)) { |
||
8986 | /* global asm block */ |
||
8987 | asm_global_instr(); |
||
8988 | continue; |
||
8989 | } |
||
8990 | /* special test for old K&R protos without explicit int |
||
8991 | type. Only accepted when defining global data */ |
||
8992 | if (l == VT_LOCAL || tok < TOK_DEFINE) |
||
8993 | break; |
||
8994 | btype.t = VT_INT; |
||
8995 | } |
||
8996 | if (((btype.t & VT_BTYPE) == VT_ENUM || |
||
8997 | (btype.t & VT_BTYPE) == VT_STRUCT) && |
||
8998 | tok == ';') { |
||
8999 | /* we accept no variable after */ |
||
9000 | next(); |
||
9001 | continue; |
||
9002 | } |
||
9003 | while (1) { /* iterate thru each declaration */ |
||
9004 | type = btype; |
||
9005 | type_decl(&type, &ad, &v, TYPE_DIRECT); |
||
9006 | #if 0 |
||
9007 | { |
||
9008 | char buf[500]; |
||
9009 | type_to_str(buf, sizeof(buf), t, get_tok_str(v, NULL)); |
||
9010 | printf("type = '%s'\n", buf); |
||
9011 | } |
||
9012 | #endif |
||
9013 | if ((type.t & VT_BTYPE) == VT_FUNC) { |
||
9014 | /* if old style function prototype, we accept a |
||
9015 | declaration list */ |
||
9016 | sym = type.ref; |
||
9017 | if (sym->c == FUNC_OLD) |
||
9018 | func_decl_list(sym); |
||
9019 | } |
||
9020 | |||
9021 | if (tok == '{') { |
||
9022 | if (l == VT_LOCAL) |
||
9023 | error("cannot use local functions"); |
||
9024 | if (!(type.t & VT_FUNC)) |
||
9025 | expect("function definition"); |
||
9026 | |||
9027 | /* reject abstract declarators in function definition */ |
||
9028 | sym = type.ref; |
||
9029 | while ((sym = sym->next) != NULL) |
||
9030 | if (!(sym->v & ~SYM_FIELD)) |
||
9031 | expect("identifier"); |
||
9032 | |||
9033 | /* XXX: cannot do better now: convert extern line to static inline */ |
||
9034 | if ((type.t & (VT_EXTERN | VT_INLINE)) == (VT_EXTERN | VT_INLINE)) |
||
9035 | type.t = (type.t & ~VT_EXTERN) | VT_STATIC; |
||
9036 | |||
9037 | sym = sym_find(v); |
||
9038 | if (sym) { |
||
9039 | if ((sym->type.t & VT_BTYPE) != VT_FUNC) |
||
9040 | goto func_error1; |
||
9041 | /* specific case: if not func_call defined, we put |
||
9042 | the one of the prototype */ |
||
9043 | /* XXX: should have default value */ |
||
9044 | if (sym->type.ref->r != FUNC_CDECL && |
||
9045 | type.ref->r == FUNC_CDECL) |
||
9046 | type.ref->r = sym->type.ref->r; |
||
9047 | if (!is_compatible_types(&sym->type, &type)) { |
||
9048 | func_error1: |
||
9049 | error("incompatible types for redefinition of '%s'", |
||
9050 | get_tok_str(v, NULL)); |
||
9051 | } |
||
9052 | /* if symbol is already defined, then put complete type */ |
||
9053 | sym->type = type; |
||
9054 | } else { |
||
9055 | /* put function symbol */ |
||
9056 | sym = global_identifier_push(v, type.t, 0); |
||
9057 | sym->type.ref = type.ref; |
||
9058 | } |
||
9059 | |||
9060 | /* static inline functions are just recorded as a kind |
||
9061 | of macro. Their code will be emitted at the end of |
||
9062 | the compilation unit only if they are used */ |
||
9063 | if ((type.t & (VT_INLINE | VT_STATIC)) == |
||
9064 | (VT_INLINE | VT_STATIC)) { |
||
9065 | TokenString func_str; |
||
9066 | int block_level; |
||
9067 | |||
9068 | tok_str_new(&func_str); |
||
9069 | |||
9070 | block_level = 0; |
||
9071 | for(;;) { |
||
9072 | int t; |
||
9073 | if (tok == TOK_EOF) |
||
9074 | error("unexpected end of file"); |
||
9075 | tok_str_add_tok(&func_str); |
||
9076 | t = tok; |
||
9077 | next(); |
||
9078 | if (t == '{') { |
||
9079 | block_level++; |
||
9080 | } else if (t == '}') { |
||
9081 | block_level--; |
||
9082 | if (block_level == 0) |
||
9083 | break; |
||
9084 | } |
||
9085 | } |
||
9086 | tok_str_add(&func_str, -1); |
||
9087 | tok_str_add(&func_str, 0); |
||
9088 | sym->r = (int)func_str.str; |
||
9089 | } else { |
||
9090 | /* compute text section */ |
||
9091 | cur_text_section = ad.section; |
||
9092 | if (!cur_text_section) |
||
9093 | cur_text_section = text_section; |
||
9094 | sym->r = VT_SYM | VT_CONST; |
||
9095 | gen_function(sym); |
||
9096 | #ifdef TCC_TARGET_PE |
||
9097 | if (ad.dllexport) { |
||
9098 | ((Elf32_Sym *)symtab_section->data)[sym->c].st_other |= 1; |
||
9099 | } |
||
9100 | #endif |
||
9101 | } |
||
9102 | break; |
||
9103 | } else { |
||
9104 | if (btype.t & VT_TYPEDEF) { |
||
9105 | /* save typedefed type */ |
||
9106 | /* XXX: test storage specifiers ? */ |
||
9107 | sym = sym_push(v, &type, 0, 0); |
||
9108 | sym->type.t |= VT_TYPEDEF; |
||
9109 | } else if ((type.t & VT_BTYPE) == VT_FUNC) { |
||
9110 | /* external function definition */ |
||
9111 | /* specific case for func_call attribute */ |
||
9112 | if (ad.func_call) |
||
9113 | type.ref->r = ad.func_call; |
||
9114 | external_sym(v, &type, 0); |
||
9115 | } else { |
||
9116 | /* not lvalue if array */ |
||
9117 | r = 0; |
||
9118 | if (!(type.t & VT_ARRAY)) |
||
9119 | r |= lvalue_type(type.t); |
||
9120 | has_init = (tok == '='); |
||
9121 | if ((btype.t & VT_EXTERN) || |
||
9122 | ((type.t & VT_ARRAY) && (type.t & VT_STATIC) && |
||
9123 | !has_init && l == VT_CONST && type.ref->c < 0)) { |
||
9124 | /* external variable */ |
||
9125 | /* NOTE: as GCC, uninitialized global static |
||
9126 | arrays of null size are considered as |
||
9127 | extern */ |
||
9128 | external_sym(v, &type, r); |
||
9129 | } else { |
||
9130 | if (type.t & VT_STATIC) |
||
9131 | r |= VT_CONST; |
||
9132 | else |
||
9133 | r |= l; |
||
9134 | if (has_init) |
||
9135 | next(); |
||
9136 | decl_initializer_alloc(&type, &ad, r, |
||
9137 | has_init, v, l); |
||
9138 | } |
||
9139 | } |
||
9140 | if (tok != ',') { |
||
9141 | skip(';'); |
||
9142 | break; |
||
9143 | } |
||
9144 | next(); |
||
9145 | } |
||
9146 | } |
||
9147 | } |
||
9148 | } |
||
9149 | |||
9150 | /* better than nothing, but needs extension to handle '-E' option |
||
9151 | correctly too */ |
||
9152 | static void preprocess_init(TCCState *s1) |
||
9153 | { |
||
9154 | s1->include_stack_ptr = s1->include_stack; |
||
9155 | /* XXX: move that before to avoid having to initialize |
||
9156 | file->ifdef_stack_ptr ? */ |
||
9157 | s1->ifdef_stack_ptr = s1->ifdef_stack; |
||
9158 | file->ifdef_stack_ptr = s1->ifdef_stack_ptr; |
||
9159 | |||
9160 | /* XXX: not ANSI compliant: bound checking says error */ |
||
9161 | vtop = vstack - 1; |
||
9162 | s1->pack_stack[0] = 0; |
||
9163 | s1->pack_stack_ptr = s1->pack_stack; |
||
9164 | } |
||
9165 | |||
9166 | /* compile the C file opened in 'file'. Return non zero if errors. */ |
||
9167 | static int tcc_compile(TCCState *s1) |
||
9168 | { |
||
9169 | Sym *define_start; |
||
9170 | char buf[512]; |
||
9171 | volatile int section_sym; |
||
9172 | |||
9173 | #ifdef INC_DEBUG |
||
9174 | printf("%s: **** new file\n", file->filename); |
||
9175 | #endif |
||
9176 | preprocess_init(s1); |
||
9177 | |||
9178 | funcname = ""; |
||
9179 | anon_sym = SYM_FIRST_ANOM; |
||
9180 | |||
9181 | /* file info: full path + filename */ |
||
9182 | section_sym = 0; /* avoid warning */ |
||
9183 | if (do_debug) { |
||
9184 | section_sym = put_elf_sym(symtab_section, 0, 0, |
||
9185 | ELF32_ST_INFO(STB_LOCAL, STT_SECTION), 0, |
||
9186 | text_section->sh_num, NULL); |
||
9187 | getcwd(buf, sizeof(buf)); |
||
9188 | pstrcat(buf, sizeof(buf), "/"); |
||
9189 | put_stabs_r(buf, N_SO, 0, 0, |
||
9190 | text_section->data_offset, text_section, section_sym); |
||
9191 | put_stabs_r(file->filename, N_SO, 0, 0, |
||
9192 | text_section->data_offset, text_section, section_sym); |
||
9193 | } |
||
9194 | /* an elf symbol of type STT_FILE must be put so that STB_LOCAL |
||
9195 | symbols can be safely used */ |
||
9196 | put_elf_sym(symtab_section, 0, 0, |
||
9197 | ELF32_ST_INFO(STB_LOCAL, STT_FILE), 0, |
||
9198 | SHN_ABS, file->filename); |
||
9199 | |||
9200 | /* define some often used types */ |
||
9201 | int_type.t = VT_INT; |
||
9202 | |||
9203 | char_pointer_type.t = VT_BYTE; |
||
9204 | mk_pointer(&char_pointer_type); |
||
9205 | |||
9206 | func_old_type.t = VT_FUNC; |
||
9207 | func_old_type.ref = sym_push(SYM_FIELD, &int_type, FUNC_CDECL, FUNC_OLD); |
||
9208 | |||
9209 | #if 0 |
||
9210 | /* define 'void *alloca(unsigned int)' builtin function */ |
||
9211 | { |
||
9212 | Sym *s1; |
||
9213 | |||
9214 | p = anon_sym++; |
||
9215 | sym = sym_push(p, mk_pointer(VT_VOID), FUNC_CDECL, FUNC_NEW); |
||
9216 | s1 = sym_push(SYM_FIELD, VT_UNSIGNED | VT_INT, 0, 0); |
||
9217 | s1->next = NULL; |
||
9218 | sym->next = s1; |
||
9219 | sym_push(TOK_alloca, VT_FUNC | (p << VT_STRUCT_SHIFT), VT_CONST, 0); |
||
9220 | } |
||
9221 | #endif |
||
9222 | |||
9223 | define_start = define_stack; |
||
9224 | |||
9225 | if (setjmp(s1->error_jmp_buf) == 0) { |
||
9226 | s1->nb_errors = 0; |
||
9227 | s1->error_set_jmp_enabled = 1; |
||
9228 | |||
9229 | ch = file->buf_ptr[0]; |
||
9230 | tok_flags = TOK_FLAG_BOL | TOK_FLAG_BOF; |
||
9231 | parse_flags = PARSE_FLAG_PREPROCESS | PARSE_FLAG_TOK_NUM; |
||
9232 | next(); |
||
9233 | decl(VT_CONST); |
||
9234 | if (tok != TOK_EOF) |
||
9235 | expect("declaration"); |
||
9236 | |||
9237 | /* end of translation unit info */ |
||
9238 | if (do_debug) { |
||
9239 | put_stabs_r(NULL, N_SO, 0, 0, |
||
9240 | text_section->data_offset, text_section, section_sym); |
||
9241 | } |
||
9242 | } |
||
9243 | s1->error_set_jmp_enabled = 0; |
||
9244 | |||
9245 | /* reset define stack, but leave -Dsymbols (may be incorrect if |
||
9246 | they are undefined) */ |
||
9247 | free_defines(define_start); |
||
9248 | |||
9249 | gen_inline_functions(); |
||
9250 | |||
9251 | sym_pop(&global_stack, NULL); |
||
9252 | |||
9253 | return s1->nb_errors != 0 ? -1 : 0; |
||
9254 | } |
||
9255 | |||
9256 | #ifdef LIBTCC |
||
9257 | int tcc_compile_string(TCCState *s, const char *str) |
||
9258 | { |
||
9259 | BufferedFile bf1, *bf = &bf1; |
||
9260 | int ret, len; |
||
9261 | char *buf; |
||
9262 | |||
9263 | /* init file structure */ |
||
9264 | bf->fd = -1; |
||
9265 | /* XXX: avoid copying */ |
||
9266 | len = strlen(str); |
||
9267 | buf = tcc_malloc(len + 1); |
||
9268 | if (!buf) |
||
9269 | return -1; |
||
9270 | memcpy(buf, str, len); |
||
9271 | buf[len] = CH_EOB; |
||
9272 | bf->buf_ptr = buf; |
||
9273 | bf->buf_end = buf + len; |
||
9274 | pstrcpy(bf->filename, sizeof(bf->filename), " |
||
9275 | bf->line_num = 1; |
||
9276 | file = bf; |
||
9277 | |||
9278 | ret = tcc_compile(s); |
||
9279 | |||
9280 | tcc_free(buf); |
||
9281 | |||
9282 | /* currently, no need to close */ |
||
9283 | return ret; |
||
9284 | } |
||
9285 | #endif |
||
9286 | |||
9287 | /* define a preprocessor symbol. A value can also be provided with the '=' operator */ |
||
9288 | void tcc_define_symbol(TCCState *s1, const char *sym, const char *value) |
||
9289 | { |
||
9290 | BufferedFile bf1, *bf = &bf1; |
||
9291 | |||
9292 | pstrcpy(bf->buffer, IO_BUF_SIZE, sym); |
||
9293 | pstrcat(bf->buffer, IO_BUF_SIZE, " "); |
||
9294 | /* default value */ |
||
9295 | if (!value) |
||
9296 | value = "1"; |
||
9297 | pstrcat(bf->buffer, IO_BUF_SIZE, value); |
||
9298 | |||
9299 | /* init file structure */ |
||
9300 | bf->fd = -1; |
||
9301 | bf->buf_ptr = bf->buffer; |
||
9302 | bf->buf_end = bf->buffer + strlen(bf->buffer); |
||
9303 | *bf->buf_end = CH_EOB; |
||
9304 | bf->filename[0] = '\0'; |
||
9305 | bf->line_num = 1; |
||
9306 | file = bf; |
||
9307 | |||
9308 | s1->include_stack_ptr = s1->include_stack; |
||
9309 | |||
9310 | /* parse with define parser */ |
||
9311 | ch = file->buf_ptr[0]; |
||
9312 | next_nomacro(); |
||
9313 | parse_define(); |
||
9314 | file = NULL; |
||
9315 | } |
||
9316 | |||
9317 | /* undefine a preprocessor symbol */ |
||
9318 | void tcc_undefine_symbol(TCCState *s1, const char *sym) |
||
9319 | { |
||
9320 | TokenSym *ts; |
||
9321 | Sym *s; |
||
9322 | ts = tok_alloc(sym, strlen(sym)); |
||
9323 | s = define_find(ts->tok); |
||
9324 | /* undefine symbol by putting an invalid name */ |
||
9325 | if (s) |
||
9326 | define_undef(s); |
||
9327 | } |
||
9328 | |||
9329 | #ifdef CONFIG_TCC_ASM |
||
9330 | |||
9331 | #ifdef TCC_TARGET_I386 |
||
9332 | #include "i386-asm.c" |
||
9333 | #endif |
||
9334 | #include "tccasm.c" |
||
9335 | |||
9336 | #else |
||
9337 | static void asm_instr(void) |
||
9338 | { |
||
9339 | error("inline asm() not supported"); |
||
9340 | } |
||
9341 | static void asm_global_instr(void) |
||
9342 | { |
||
9343 | error("inline asm() not supported"); |
||
9344 | } |
||
9345 | #endif |
||
9346 | |||
9347 | #include "tccelf.c" |
||
9348 | |||
9349 | #ifdef TCC_TARGET_COFF |
||
9350 | #include "tcccoff.c" |
||
9351 | #endif |
||
9352 | |||
9353 | #if defined(TCC_TARGET_PE) || defined(TCC_TARGET_MEOS) |
||
9354 | #include "tccpe.c" |
||
9355 | #endif |
||
9356 | |||
609 | andrew_pro | 9357 | #ifdef TCC_TARGET_MEOS |
9358 | #include "tccmeos.c" |
||
9359 | #endif |
||
9360 | |||
145 | halyavin | 9361 | /* print the position in the source file of PC value 'pc' by reading |
9362 | the stabs debug information */ |
||
9363 | static void rt_printline(unsigned long wanted_pc) |
||
9364 | { |
||
9365 | Stab_Sym *sym, *sym_end; |
||
9366 | char func_name[128], last_func_name[128]; |
||
9367 | unsigned long func_addr, last_pc, pc; |
||
9368 | const char *incl_files[INCLUDE_STACK_SIZE]; |
||
9369 | int incl_index, len, last_line_num, i; |
||
9370 | const char *str, *p; |
||
9371 | |||
609 | andrew_pro | 9372 | printf("0x%08lx:", wanted_pc); |
145 | halyavin | 9373 | |
9374 | func_name[0] = '\0'; |
||
9375 | func_addr = 0; |
||
9376 | incl_index = 0; |
||
9377 | last_func_name[0] = '\0'; |
||
9378 | last_pc = 0xffffffff; |
||
9379 | last_line_num = 1; |
||
9380 | sym = (Stab_Sym *)stab_section->data + 1; |
||
9381 | sym_end = (Stab_Sym *)(stab_section->data + stab_section->data_offset); |
||
9382 | while (sym < sym_end) { |
||
9383 | switch(sym->n_type) { |
||
9384 | /* function start or end */ |
||
9385 | case N_FUN: |
||
9386 | if (sym->n_strx == 0) { |
||
9387 | /* we test if between last line and end of function */ |
||
9388 | pc = sym->n_value + func_addr; |
||
9389 | if (wanted_pc >= last_pc && wanted_pc < pc) |
||
9390 | goto found; |
||
9391 | func_name[0] = '\0'; |
||
9392 | func_addr = 0; |
||
9393 | } else { |
||
9394 | str = stabstr_section->data + sym->n_strx; |
||
9395 | p = strchr(str, ':'); |
||
9396 | if (!p) { |
||
9397 | pstrcpy(func_name, sizeof(func_name), str); |
||
9398 | } else { |
||
9399 | len = p - str; |
||
9400 | if (len > sizeof(func_name) - 1) |
||
9401 | len = sizeof(func_name) - 1; |
||
9402 | memcpy(func_name, str, len); |
||
9403 | func_name[len] = '\0'; |
||
9404 | } |
||
9405 | func_addr = sym->n_value; |
||
9406 | } |
||
9407 | break; |
||
9408 | /* line number info */ |
||
9409 | case N_SLINE: |
||
9410 | pc = sym->n_value + func_addr; |
||
9411 | if (wanted_pc >= last_pc && wanted_pc < pc) |
||
9412 | goto found; |
||
9413 | last_pc = pc; |
||
9414 | last_line_num = sym->n_desc; |
||
9415 | /* XXX: slow! */ |
||
9416 | strcpy(last_func_name, func_name); |
||
9417 | break; |
||
9418 | /* include files */ |
||
9419 | case N_BINCL: |
||
9420 | str = stabstr_section->data + sym->n_strx; |
||
9421 | add_incl: |
||
9422 | if (incl_index < INCLUDE_STACK_SIZE) { |
||
9423 | incl_files[incl_index++] = str; |
||
9424 | } |
||
9425 | break; |
||
9426 | case N_EINCL: |
||
9427 | if (incl_index > 1) |
||
9428 | incl_index--; |
||
9429 | break; |
||
9430 | case N_SO: |
||
9431 | if (sym->n_strx == 0) { |
||
9432 | incl_index = 0; /* end of translation unit */ |
||
9433 | } else { |
||
9434 | str = stabstr_section->data + sym->n_strx; |
||
9435 | /* do not add path */ |
||
9436 | len = strlen(str); |
||
9437 | if (len > 0 && str[len - 1] != '/') |
||
9438 | goto add_incl; |
||
9439 | } |
||
9440 | break; |
||
9441 | } |
||
9442 | sym++; |
||
9443 | } |
||
9444 | |||
9445 | /* second pass: we try symtab symbols (no line number info) */ |
||
9446 | incl_index = 0; |
||
9447 | { |
||
9448 | Elf32_Sym *sym, *sym_end; |
||
9449 | int type; |
||
9450 | |||
9451 | sym_end = (Elf32_Sym *)(symtab_section->data + symtab_section->data_offset); |
||
9452 | for(sym = (Elf32_Sym *)symtab_section->data + 1; |
||
9453 | sym < sym_end; |
||
9454 | sym++) { |
||
9455 | type = ELF32_ST_TYPE(sym->st_info); |
||
9456 | if (type == STT_FUNC) { |
||
9457 | if (wanted_pc >= sym->st_value && |
||
9458 | wanted_pc < sym->st_value + sym->st_size) { |
||
9459 | pstrcpy(last_func_name, sizeof(last_func_name), |
||
9460 | strtab_section->data + sym->st_name); |
||
9461 | goto found; |
||
9462 | } |
||
9463 | } |
||
9464 | } |
||
9465 | } |
||
9466 | /* did not find any info: */ |
||
609 | andrew_pro | 9467 | printf(" ???\n"); |
145 | halyavin | 9468 | return; |
9469 | found: |
||
9470 | if (last_func_name[0] != '\0') { |
||
609 | andrew_pro | 9471 | printf(" %s()", last_func_name); |
145 | halyavin | 9472 | } |
9473 | if (incl_index > 0) { |
||
609 | andrew_pro | 9474 | printf(" (%s:%d", |
145 | halyavin | 9475 | incl_files[incl_index - 1], last_line_num); |
9476 | for(i = incl_index - 2; i >= 0; i--) |
||
609 | andrew_pro | 9477 | printf(", included from %s", incl_files[i]); |
9478 | printf(")"); |
||
145 | halyavin | 9479 | } |
609 | andrew_pro | 9480 | printf("\n"); |
145 | halyavin | 9481 | } |
9482 | |||
9483 | #if !defined(WIN32) && !defined(CONFIG_TCCBOOT) |
||
9484 | |||
9485 | #ifdef __i386__ |
||
9486 | |||
9487 | /* fix for glibc 2.1 */ |
||
9488 | #ifndef REG_EIP |
||
9489 | #define REG_EIP EIP |
||
9490 | #define REG_EBP EBP |
||
9491 | #endif |
||
9492 | |||
9493 | /* return the PC at frame level 'level'. Return non zero if not found */ |
||
609 | andrew_pro | 9494 | /* |
145 | halyavin | 9495 | static int rt_get_caller_pc(unsigned long *paddr, |
9496 | ucontext_t *uc, int level) |
||
9497 | { |
||
9498 | unsigned long fp; |
||
9499 | int i; |
||
9500 | |||
9501 | if (level == 0) { |
||
9502 | #if defined(__FreeBSD__) |
||
9503 | *paddr = uc->uc_mcontext.mc_eip; |
||
9504 | #elif defined(__dietlibc__) |
||
9505 | *paddr = uc->uc_mcontext.eip; |
||
9506 | #else |
||
9507 | *paddr = uc->uc_mcontext.gregs[REG_EIP]; |
||
9508 | #endif |
||
9509 | return 0; |
||
9510 | } else { |
||
9511 | #if defined(__FreeBSD__) |
||
9512 | fp = uc->uc_mcontext.mc_ebp; |
||
9513 | #elif defined(__dietlibc__) |
||
9514 | fp = uc->uc_mcontext.ebp; |
||
9515 | #else |
||
9516 | fp = uc->uc_mcontext.gregs[REG_EBP]; |
||
9517 | #endif |
||
9518 | for(i=1;i |
||
609 | andrew_pro | 9519 | // XXX: check address validity with program info |
145 | halyavin | 9520 | if (fp <= 0x1000 || fp >= 0xc0000000) |
9521 | return -1; |
||
9522 | fp = ((unsigned long *)fp)[0]; |
||
9523 | } |
||
9524 | *paddr = ((unsigned long *)fp)[1]; |
||
9525 | return 0; |
||
9526 | } |
||
9527 | } |
||
609 | andrew_pro | 9528 | */ |
145 | halyavin | 9529 | #else |
9530 | |||
9531 | #warning add arch specific rt_get_caller_pc() |
||
609 | andrew_pro | 9532 | /* |
145 | halyavin | 9533 | static int rt_get_caller_pc(unsigned long *paddr, |
9534 | ucontext_t *uc, int level) |
||
9535 | { |
||
9536 | return -1; |
||
9537 | } |
||
609 | andrew_pro | 9538 | */ |
145 | halyavin | 9539 | #endif |
9540 | |||
9541 | /* emit a run time error at position 'pc' */ |
||
609 | andrew_pro | 9542 | /* |
145 | halyavin | 9543 | void rt_error(ucontext_t *uc, const char *fmt, ...) |
9544 | { |
||
9545 | va_list ap; |
||
9546 | unsigned long pc; |
||
9547 | int i; |
||
9548 | |||
9549 | va_start(ap, fmt); |
||
609 | andrew_pro | 9550 | printf("Runtime error: "); |
9551 | //vfprintf(stderr, fmt, ap); |
||
9552 | printf("\n"); |
||
145 | halyavin | 9553 | for(i=0;i |
9554 | if (rt_get_caller_pc(&pc, uc, i) < 0) |
||
9555 | break; |
||
9556 | if (i == 0) |
||
609 | andrew_pro | 9557 | printf("at "); |
145 | halyavin | 9558 | else |
609 | andrew_pro | 9559 | printf("by "); |
145 | halyavin | 9560 | rt_printline(pc); |
9561 | } |
||
9562 | exit(255); |
||
9563 | va_end(ap); |
||
9564 | } |
||
9565 | |||
609 | andrew_pro | 9566 | */ |
145 | halyavin | 9567 | /* signal handler for fatal errors */ |
609 | andrew_pro | 9568 | /* |
145 | halyavin | 9569 | static void sig_error(int signum, siginfo_t *siginf, void *puc) |
9570 | { |
||
9571 | ucontext_t *uc = puc; |
||
9572 | |||
9573 | switch(signum) { |
||
9574 | case SIGFPE: |
||
9575 | switch(siginf->si_code) { |
||
9576 | case FPE_INTDIV: |
||
9577 | case FPE_FLTDIV: |
||
9578 | rt_error(uc, "division by zero"); |
||
9579 | break; |
||
9580 | default: |
||
9581 | rt_error(uc, "floating point exception"); |
||
9582 | break; |
||
9583 | } |
||
9584 | break; |
||
9585 | case SIGBUS: |
||
9586 | case SIGSEGV: |
||
9587 | if (rt_bound_error_msg && *rt_bound_error_msg) |
||
9588 | rt_error(uc, *rt_bound_error_msg); |
||
9589 | else |
||
9590 | rt_error(uc, "dereferencing invalid pointer"); |
||
9591 | break; |
||
9592 | case SIGILL: |
||
9593 | rt_error(uc, "illegal instruction"); |
||
9594 | break; |
||
9595 | case SIGABRT: |
||
9596 | rt_error(uc, "abort() called"); |
||
9597 | break; |
||
9598 | default: |
||
9599 | rt_error(uc, "caught signal %d", signum); |
||
9600 | break; |
||
9601 | } |
||
9602 | exit(255); |
||
9603 | } |
||
609 | andrew_pro | 9604 | */ |
145 | halyavin | 9605 | #endif |
9606 | |||
609 | andrew_pro | 9607 | |
145 | halyavin | 9608 | /* do all relocations (needed before using tcc_get_symbol()) */ |
9609 | int tcc_relocate(TCCState *s1) |
||
9610 | { |
||
9611 | Section *s; |
||
9612 | int i; |
||
9613 | |||
9614 | s1->nb_errors = 0; |
||
9615 | |||
9616 | #if defined(TCC_TARGET_PE) || defined(TCC_TARGET_MEOS) |
||
9617 | pe_add_runtime(s1); |
||
9618 | #else |
||
9619 | tcc_add_runtime(s1); |
||
9620 | #endif |
||
9621 | |||
9622 | relocate_common_syms(); |
||
9623 | |||
9624 | tcc_add_linker_symbols(s1); |
||
9625 | |||
9626 | build_got_entries(s1); |
||
9627 | |||
9628 | /* compute relocation address : section are relocated in place. We |
||
9629 | also alloc the bss space */ |
||
9630 | for(i = 1; i < s1->nb_sections; i++) { |
||
9631 | s = s1->sections[i]; |
||
9632 | if (s->sh_flags & SHF_ALLOC) { |
||
9633 | if (s->sh_type == SHT_NOBITS) |
||
9634 | s->data = tcc_mallocz(s->data_offset); |
||
9635 | s->sh_addr = (unsigned long)s->data; |
||
9636 | } |
||
9637 | } |
||
9638 | |||
9639 | relocate_syms(s1, 1); |
||
9640 | |||
9641 | if (s1->nb_errors != 0) |
||
9642 | return -1; |
||
9643 | |||
9644 | /* relocate each section */ |
||
9645 | for(i = 1; i < s1->nb_sections; i++) { |
||
9646 | s = s1->sections[i]; |
||
9647 | if (s->reloc) |
||
9648 | relocate_section(s1, s); |
||
9649 | } |
||
9650 | return 0; |
||
9651 | } |
||
9652 | |||
9653 | /* launch the compiled program with the given arguments */ |
||
9654 | int tcc_run(TCCState *s1, int argc, char **argv) |
||
9655 | { |
||
9656 | int (*prog_main)(int, char **); |
||
9657 | |||
9658 | if (tcc_relocate(s1) < 0) |
||
9659 | return -1; |
||
9660 | |||
9661 | prog_main = tcc_get_symbol_err(s1, "main"); |
||
9662 | |||
9663 | if (do_debug) { |
||
9664 | #if defined(WIN32) || defined(CONFIG_TCCBOOT) |
||
9665 | error("debug mode currently not available for Windows"); |
||
9666 | #else |
||
609 | andrew_pro | 9667 | //struct sigaction sigact; |
145 | halyavin | 9668 | /* install TCC signal handlers to print debug info on fatal |
9669 | runtime errors */ |
||
609 | andrew_pro | 9670 | //sigact.sa_flags = SA_SIGINFO | SA_RESETHAND; |
9671 | //sigact.sa_sigaction = sig_error; |
||
9672 | //sigemptyset(&sigact.sa_mask); |
||
9673 | //sigaction(SIGFPE, &sigact, NULL); |
||
9674 | //sigaction(SIGILL, &sigact, NULL); |
||
9675 | //sigaction(SIGSEGV, &sigact, NULL); |
||
9676 | //sigaction(SIGBUS, &sigact, NULL); |
||
9677 | //sigaction(SIGABRT, &sigact, NULL); |
||
145 | halyavin | 9678 | #endif |
9679 | } |
||
9680 | |||
9681 | #ifdef CONFIG_TCC_BCHECK |
||
9682 | if (do_bounds_check) { |
||
9683 | void (*bound_init)(void); |
||
9684 | |||
9685 | /* set error function */ |
||
9686 | rt_bound_error_msg = (void *)tcc_get_symbol_err(s1, |
||
9687 | "__bound_error_msg"); |
||
9688 | |||
9689 | /* XXX: use .init section so that it also work in binary ? */ |
||
9690 | bound_init = (void *)tcc_get_symbol_err(s1, "__bound_init"); |
||
9691 | bound_init(); |
||
9692 | } |
||
9693 | #endif |
||
9694 | return (*prog_main)(argc, argv); |
||
9695 | } |
||
9696 | |||
9697 | TCCState *tcc_new(void) |
||
9698 | { |
||
9699 | const char *p, *r; |
||
9700 | TCCState *s; |
||
9701 | TokenSym *ts; |
||
9702 | int i, c; |
||
9703 | |||
9704 | s = tcc_mallocz(sizeof(TCCState)); |
||
9705 | if (!s) |
||
9706 | return NULL; |
||
9707 | tcc_state = s; |
||
9708 | s->output_type = TCC_OUTPUT_MEMORY; |
||
9709 | |||
9710 | /* init isid table */ |
||
9711 | for(i=0;i<256;i++) |
||
9712 | isidnum_table[i] = isid(i) || isnum(i); |
||
9713 | |||
9714 | /* add all tokens */ |
||
9715 | table_ident = NULL; |
||
9716 | memset(hash_ident, 0, TOK_HASH_SIZE * sizeof(TokenSym *)); |
||
9717 | |||
9718 | tok_ident = TOK_IDENT; |
||
9719 | p = tcc_keywords; |
||
9720 | while (*p) { |
||
9721 | r = p; |
||
9722 | for(;;) { |
||
9723 | c = *r++; |
||
9724 | if (c == '\0') |
||
9725 | break; |
||
9726 | } |
||
9727 | ts = tok_alloc(p, r - p - 1); |
||
9728 | p = r; |
||
9729 | } |
||
9730 | |||
9731 | /* we add dummy defines for some special macros to speed up tests |
||
9732 | and to have working defined() */ |
||
9733 | define_push(TOK___LINE__, MACRO_OBJ, NULL, NULL); |
||
9734 | define_push(TOK___FILE__, MACRO_OBJ, NULL, NULL); |
||
9735 | define_push(TOK___DATE__, MACRO_OBJ, NULL, NULL); |
||
9736 | define_push(TOK___TIME__, MACRO_OBJ, NULL, NULL); |
||
9737 | |||
9738 | /* standard defines */ |
||
9739 | tcc_define_symbol(s, "__STDC__", NULL); |
||
9740 | #if defined(TCC_TARGET_I386) |
||
9741 | tcc_define_symbol(s, "__i386__", NULL); |
||
9742 | #endif |
||
9743 | #if defined(TCC_TARGET_ARM) |
||
9744 | tcc_define_symbol(s, "__ARM_ARCH_4__", NULL); |
||
9745 | tcc_define_symbol(s, "__arm_elf__", NULL); |
||
9746 | tcc_define_symbol(s, "__arm_elf", NULL); |
||
9747 | tcc_define_symbol(s, "arm_elf", NULL); |
||
9748 | tcc_define_symbol(s, "__arm__", NULL); |
||
9749 | tcc_define_symbol(s, "__arm", NULL); |
||
9750 | tcc_define_symbol(s, "arm", NULL); |
||
9751 | tcc_define_symbol(s, "__APCS_32__", NULL); |
||
9752 | #endif |
||
9753 | #if defined(linux) |
||
9754 | tcc_define_symbol(s, "__linux__", NULL); |
||
9755 | tcc_define_symbol(s, "linux", NULL); |
||
9756 | #endif |
||
9757 | /* tiny C specific defines */ |
||
9758 | tcc_define_symbol(s, "__TINYC__", NULL); |
||
9759 | |||
9760 | /* tiny C & gcc defines */ |
||
9761 | tcc_define_symbol(s, "__SIZE_TYPE__", "unsigned int"); |
||
9762 | tcc_define_symbol(s, "__PTRDIFF_TYPE__", "int"); |
||
9763 | tcc_define_symbol(s, "__WCHAR_TYPE__", "int"); |
||
9764 | |||
9765 | /* default library paths */ |
||
9766 | #ifdef TCC_TARGET_PE |
||
9767 | { |
||
9768 | char buf[1024]; |
||
9769 | snprintf(buf, sizeof(buf), "%s/lib", tcc_lib_path); |
||
9770 | tcc_add_library_path(s, buf); |
||
9771 | } |
||
9772 | #else |
||
609 | andrew_pro | 9773 | #ifdef TCC_TARGET_MEOS |
9774 | tcc_add_library_path(s, ".//lib"); |
||
9775 | #else |
||
145 | halyavin | 9776 | tcc_add_library_path(s, "/usr/local/lib"); |
9777 | tcc_add_library_path(s, "/usr/lib"); |
||
609 | andrew_pro | 9778 | tcc_add_library_path(s, "/lib"); |
145 | halyavin | 9779 | #endif |
9780 | #endif |
||
9781 | |||
9782 | /* no section zero */ |
||
9783 | dynarray_add((void ***)&s->sections, &s->nb_sections, NULL); |
||
9784 | |||
9785 | /* create standard sections */ |
||
9786 | text_section = new_section(s, ".text", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR); |
||
9787 | data_section = new_section(s, ".data", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE); |
||
9788 | bss_section = new_section(s, ".bss", SHT_NOBITS, SHF_ALLOC | SHF_WRITE); |
||
9789 | |||
9790 | /* symbols are always generated for linking stage */ |
||
9791 | symtab_section = new_symtab(s, ".symtab", SHT_SYMTAB, 0, |
||
9792 | ".strtab", |
||
9793 | ".hashtab", SHF_PRIVATE); |
||
9794 | strtab_section = symtab_section->link; |
||
9795 | |||
9796 | /* private symbol table for dynamic symbols */ |
||
9797 | s->dynsymtab_section = new_symtab(s, ".dynsymtab", SHT_SYMTAB, SHF_PRIVATE, |
||
9798 | ".dynstrtab", |
||
9799 | ".dynhashtab", SHF_PRIVATE); |
||
9800 | s->alacarte_link = 1; |
||
9801 | |||
9802 | #ifdef CHAR_IS_UNSIGNED |
||
9803 | s->char_is_unsigned = 1; |
||
9804 | #endif |
||
9805 | #if defined(TCC_TARGET_PE) && 0 |
||
9806 | /* XXX: currently the PE linker is not ready to support that */ |
||
9807 | s->leading_underscore = 1; |
||
9808 | #endif |
||
9809 | return s; |
||
9810 | } |
||
9811 | |||
9812 | void tcc_delete(TCCState *s1) |
||
9813 | { |
||
9814 | int i, n; |
||
9815 | |||
9816 | /* free -D defines */ |
||
9817 | free_defines(NULL); |
||
9818 | |||
9819 | /* free tokens */ |
||
9820 | n = tok_ident - TOK_IDENT; |
||
9821 | for(i = 0; i < n; i++) |
||
9822 | tcc_free(table_ident[i]); |
||
9823 | tcc_free(table_ident); |
||
9824 | |||
9825 | /* free all sections */ |
||
9826 | |||
9827 | free_section(symtab_section->hash); |
||
9828 | |||
9829 | free_section(s1->dynsymtab_section->hash); |
||
9830 | free_section(s1->dynsymtab_section->link); |
||
9831 | free_section(s1->dynsymtab_section); |
||
9832 | |||
9833 | for(i = 1; i < s1->nb_sections; i++) |
||
9834 | free_section(s1->sections[i]); |
||
9835 | tcc_free(s1->sections); |
||
9836 | |||
9837 | /* free loaded dlls array */ |
||
9838 | for(i = 0; i < s1->nb_loaded_dlls; i++) |
||
9839 | tcc_free(s1->loaded_dlls[i]); |
||
9840 | tcc_free(s1->loaded_dlls); |
||
9841 | |||
9842 | /* library paths */ |
||
9843 | for(i = 0; i < s1->nb_library_paths; i++) |
||
9844 | tcc_free(s1->library_paths[i]); |
||
9845 | tcc_free(s1->library_paths); |
||
9846 | |||
9847 | /* cached includes */ |
||
9848 | for(i = 0; i < s1->nb_cached_includes; i++) |
||
9849 | tcc_free(s1->cached_includes[i]); |
||
9850 | tcc_free(s1->cached_includes); |
||
9851 | |||
9852 | for(i = 0; i < s1->nb_include_paths; i++) |
||
9853 | tcc_free(s1->include_paths[i]); |
||
9854 | tcc_free(s1->include_paths); |
||
9855 | |||
9856 | for(i = 0; i < s1->nb_sysinclude_paths; i++) |
||
9857 | tcc_free(s1->sysinclude_paths[i]); |
||
9858 | tcc_free(s1->sysinclude_paths); |
||
9859 | |||
9860 | tcc_free(s1); |
||
9861 | } |
||
9862 | |||
9863 | int tcc_add_include_path(TCCState *s1, const char *pathname) |
||
9864 | { |
||
9865 | char *pathname1; |
||
9866 | |||
9867 | pathname1 = tcc_strdup(pathname); |
||
9868 | dynarray_add((void ***)&s1->include_paths, &s1->nb_include_paths, pathname1); |
||
9869 | return 0; |
||
9870 | } |
||
9871 | |||
9872 | int tcc_add_sysinclude_path(TCCState *s1, const char *pathname) |
||
9873 | { |
||
9874 | char *pathname1; |
||
9875 | |||
9876 | pathname1 = tcc_strdup(pathname); |
||
9877 | dynarray_add((void ***)&s1->sysinclude_paths, &s1->nb_sysinclude_paths, pathname1); |
||
9878 | return 0; |
||
9879 | } |
||
9880 | |||
9881 | static int tcc_add_file_internal(TCCState *s1, const char *filename, int flags) |
||
9882 | { |
||
9883 | const char *ext, *filename1; |
||
9884 | Elf32_Ehdr ehdr; |
||
9885 | int fd, ret; |
||
9886 | BufferedFile *saved_file; |
||
9887 | |||
9888 | /* find source file type with extension */ |
||
9889 | filename1 = strrchr(filename, '/'); |
||
9890 | if (filename1) |
||
9891 | filename1++; |
||
9892 | else |
||
9893 | filename1 = filename; |
||
9894 | ext = strrchr(filename1, '.'); |
||
9895 | if (ext) |
||
9896 | ext++; |
||
9897 | |||
9898 | /* open the file */ |
||
9899 | saved_file = file; |
||
9900 | file = tcc_open(s1, filename); |
||
9901 | if (!file) { |
||
9902 | if (flags & AFF_PRINT_ERROR) { |
||
9903 | error_noabort("file '%s' not found", filename); |
||
9904 | } |
||
9905 | ret = -1; |
||
9906 | goto fail1; |
||
9907 | } |
||
9908 | |||
9909 | if (!ext || !strcmp(ext, "c")) { |
||
9910 | /* C file assumed */ |
||
9911 | ret = tcc_compile(s1); |
||
9912 | } else |
||
9913 | #ifdef CONFIG_TCC_ASM |
||
9914 | if (!strcmp(ext, "S")) { |
||
9915 | /* preprocessed assembler */ |
||
9916 | ret = tcc_assemble(s1, 1); |
||
9917 | } else if (!strcmp(ext, "s")) { |
||
9918 | /* non preprocessed assembler */ |
||
9919 | ret = tcc_assemble(s1, 0); |
||
9920 | } else |
||
9921 | #endif |
||
9922 | #ifdef TCC_TARGET_PE |
||
9923 | if (!strcmp(ext, "def")) { |
||
9924 | ret = pe_load_def_file(s1, fdopen(file->fd, "rb")); |
||
9925 | } else |
||
9926 | #endif |
||
9927 | { |
||
9928 | fd = file->fd; |
||
9929 | /* assume executable format: auto guess file type */ |
||
9930 | ret = read(fd, &ehdr, sizeof(ehdr)); |
||
9931 | lseek(fd, 0, SEEK_SET); |
||
9932 | if (ret <= 0) { |
||
9933 | error_noabort("could not read header"); |
||
9934 | goto fail; |
||
9935 | } else if (ret != sizeof(ehdr)) { |
||
9936 | goto try_load_script; |
||
9937 | } |
||
9938 | |||
9939 | if (ehdr.e_ident[0] == ELFMAG0 && |
||
9940 | ehdr.e_ident[1] == ELFMAG1 && |
||
9941 | ehdr.e_ident[2] == ELFMAG2 && |
||
9942 | ehdr.e_ident[3] == ELFMAG3) { |
||
9943 | file->line_num = 0; /* do not display line number if error */ |
||
9944 | if (ehdr.e_type == ET_REL) { |
||
9945 | ret = tcc_load_object_file(s1, fd, 0); |
||
9946 | } else if (ehdr.e_type == ET_DYN) { |
||
9947 | if (s1->output_type == TCC_OUTPUT_MEMORY) { |
||
9948 | #if defined(TCC_TARGET_PE) || defined(TCC_TARGET_MEOS) |
||
9949 | ret = -1; |
||
9950 | #else |
||
9951 | void *h; |
||
9952 | h = dlopen(filename, RTLD_GLOBAL | RTLD_LAZY); |
||
9953 | if (h) |
||
9954 | ret = 0; |
||
9955 | else |
||
9956 | ret = -1; |
||
9957 | #endif |
||
9958 | } else { |
||
9959 | ret = tcc_load_dll(s1, fd, filename, |
||
9960 | (flags & AFF_REFERENCED_DLL) != 0); |
||
9961 | } |
||
9962 | } else { |
||
9963 | error_noabort("unrecognized ELF file"); |
||
9964 | goto fail; |
||
9965 | } |
||
9966 | } else if (memcmp((char *)&ehdr, ARMAG, 8) == 0) { |
||
9967 | file->line_num = 0; /* do not display line number if error */ |
||
9968 | ret = tcc_load_archive(s1, fd); |
||
9969 | } else |
||
9970 | #ifdef TCC_TARGET_COFF |
||
9971 | if (*(uint16_t *)(&ehdr) == COFF_C67_MAGIC) { |
||
9972 | ret = tcc_load_coff(s1, fd); |
||
9973 | } else |
||
9974 | #endif |
||
9975 | { |
||
9976 | /* as GNU ld, consider it is an ld script if not recognized */ |
||
9977 | try_load_script: |
||
9978 | ret = tcc_load_ldscript(s1); |
||
9979 | if (ret < 0) { |
||
9980 | error_noabort("unrecognized file type"); |
||
9981 | goto fail; |
||
9982 | } |
||
9983 | } |
||
9984 | } |
||
9985 | the_end: |
||
9986 | tcc_close(file); |
||
9987 | fail1: |
||
9988 | file = saved_file; |
||
9989 | return ret; |
||
9990 | fail: |
||
9991 | ret = -1; |
||
9992 | goto the_end; |
||
9993 | } |
||
9994 | |||
9995 | int tcc_add_file(TCCState *s, const char *filename) |
||
9996 | { |
||
9997 | return tcc_add_file_internal(s, filename, AFF_PRINT_ERROR); |
||
9998 | } |
||
9999 | |||
10000 | int tcc_add_library_path(TCCState *s, const char *pathname) |
||
10001 | { |
||
10002 | char *pathname1; |
||
10003 | |||
10004 | pathname1 = tcc_strdup(pathname); |
||
10005 | dynarray_add((void ***)&s->library_paths, &s->nb_library_paths, pathname1); |
||
10006 | return 0; |
||
10007 | } |
||
10008 | |||
10009 | /* find and load a dll. Return non zero if not found */ |
||
10010 | /* XXX: add '-rpath' option support ? */ |
||
10011 | static int tcc_add_dll(TCCState *s, const char *filename, int flags) |
||
10012 | { |
||
10013 | char buf[1024]; |
||
10014 | int i; |
||
10015 | |||
10016 | for(i = 0; i < s->nb_library_paths; i++) { |
||
10017 | snprintf(buf, sizeof(buf), "%s/%s", |
||
10018 | s->library_paths[i], filename); |
||
10019 | if (tcc_add_file_internal(s, buf, flags) == 0) |
||
10020 | return 0; |
||
10021 | } |
||
10022 | return -1; |
||
10023 | } |
||
10024 | |||
10025 | /* the library name is the same as the argument of the '-l' option */ |
||
10026 | int tcc_add_library(TCCState *s, const char *libraryname) |
||
10027 | { |
||
10028 | char buf[1024]; |
||
10029 | int i; |
||
10030 | |||
10031 | /* first we look for the dynamic library if not static linking */ |
||
10032 | if (!s->static_link) { |
||
10033 | #ifdef TCC_TARGET_PE |
||
10034 | snprintf(buf, sizeof(buf), "%s.def", libraryname); |
||
10035 | #else |
||
10036 | snprintf(buf, sizeof(buf), "lib%s.so", libraryname); |
||
10037 | #endif |
||
10038 | if (tcc_add_dll(s, buf, 0) == 0) |
||
10039 | return 0; |
||
10040 | } |
||
10041 | |||
10042 | /* then we look for the static library */ |
||
10043 | for(i = 0; i < s->nb_library_paths; i++) { |
||
10044 | snprintf(buf, sizeof(buf), "%s/lib%s.a", |
||
10045 | s->library_paths[i], libraryname); |
||
10046 | if (tcc_add_file_internal(s, buf, 0) == 0) |
||
10047 | return 0; |
||
10048 | } |
||
10049 | return -1; |
||
10050 | } |
||
10051 | |||
10052 | int tcc_add_symbol(TCCState *s, const char *name, unsigned long val) |
||
10053 | { |
||
10054 | add_elf_sym(symtab_section, val, 0, |
||
10055 | ELF32_ST_INFO(STB_GLOBAL, STT_NOTYPE), 0, |
||
10056 | SHN_ABS, name); |
||
10057 | return 0; |
||
10058 | } |
||
10059 | |||
10060 | int tcc_set_output_type(TCCState *s, int output_type) |
||
10061 | { |
||
10062 | s->output_type = output_type; |
||
10063 | |||
10064 | if (!s->nostdinc) { |
||
10065 | char buf[1024]; |
||
10066 | |||
10067 | /* default include paths */ |
||
10068 | /* XXX: reverse order needed if -isystem support */ |
||
10069 | #if !defined(TCC_TARGET_PE) && !defined(TCC_TARGET_MEOS) |
||
10070 | tcc_add_sysinclude_path(s, "/usr/local/include"); |
||
10071 | tcc_add_sysinclude_path(s, "/usr/include"); |
||
10072 | #endif |
||
609 | andrew_pro | 10073 | |
10074 | #if defined(TCC_TARGET_MEOS) |
||
10075 | tcc_add_sysinclude_path(s, ".//include"); |
||
10076 | #endif |
||
145 | halyavin | 10077 | snprintf(buf, sizeof(buf), "%s/include", tcc_lib_path); |
10078 | tcc_add_sysinclude_path(s, buf); |
||
10079 | #ifdef TCC_TARGET_PE |
||
10080 | snprintf(buf, sizeof(buf), "%s/include/winapi", tcc_lib_path); |
||
10081 | tcc_add_sysinclude_path(s, buf); |
||
10082 | #endif |
||
10083 | } |
||
10084 | |||
10085 | /* if bound checking, then add corresponding sections */ |
||
10086 | #ifdef CONFIG_TCC_BCHECK |
||
10087 | if (do_bounds_check) { |
||
10088 | /* define symbol */ |
||
10089 | tcc_define_symbol(s, "__BOUNDS_CHECKING_ON", NULL); |
||
10090 | /* create bounds sections */ |
||
10091 | bounds_section = new_section(s, ".bounds", |
||
10092 | SHT_PROGBITS, SHF_ALLOC); |
||
10093 | lbounds_section = new_section(s, ".lbounds", |
||
10094 | SHT_PROGBITS, SHF_ALLOC); |
||
10095 | } |
||
10096 | #endif |
||
10097 | |||
10098 | if (s->char_is_unsigned) { |
||
10099 | tcc_define_symbol(s, "__CHAR_UNSIGNED__", NULL); |
||
10100 | } |
||
10101 | |||
10102 | /* add debug sections */ |
||
10103 | if (do_debug) { |
||
10104 | /* stab symbols */ |
||
10105 | stab_section = new_section(s, ".stab", SHT_PROGBITS, 0); |
||
10106 | stab_section->sh_entsize = sizeof(Stab_Sym); |
||
10107 | stabstr_section = new_section(s, ".stabstr", SHT_STRTAB, 0); |
||
10108 | put_elf_str(stabstr_section, ""); |
||
10109 | stab_section->link = stabstr_section; |
||
10110 | /* put first entry */ |
||
10111 | put_stabs("", 0, 0, 0, 0); |
||
10112 | } |
||
10113 | |||
10114 | /* add libc crt1/crti objects */ |
||
10115 | #if !defined(TCC_TARGET_PE) && !defined(TCC_TARGET_MEOS) |
||
10116 | if ((output_type == TCC_OUTPUT_EXE || output_type == TCC_OUTPUT_DLL) && |
||
10117 | !s->nostdlib) { |
||
10118 | if (output_type != TCC_OUTPUT_DLL) |
||
10119 | tcc_add_file(s, CONFIG_TCC_CRT_PREFIX "/crt1.o"); |
||
10120 | tcc_add_file(s, CONFIG_TCC_CRT_PREFIX "/crti.o"); |
||
10121 | } |
||
609 | andrew_pro | 10122 | #endif |
10123 | #if defined(TCC_TARGET_MEOS) |
||
10124 | if (s->output_type != TCC_OUTPUT_OBJ) |
||
10125 | tcc_add_file(s,".//start.o"); |
||
145 | halyavin | 10126 | #endif |
10127 | return 0; |
||
10128 | } |
||
10129 | |||
10130 | #define WD_ALL 0x0001 /* warning is activated when using -Wall */ |
||
10131 | #define FD_INVERT 0x0002 /* invert value before storing */ |
||
10132 | |||
10133 | typedef struct FlagDef { |
||
10134 | uint16_t offset; |
||
10135 | uint16_t flags; |
||
10136 | const char *name; |
||
10137 | } FlagDef; |
||
10138 | |||
10139 | static const FlagDef warning_defs[] = { |
||
10140 | { offsetof(TCCState, warn_unsupported), 0, "unsupported" }, |
||
10141 | { offsetof(TCCState, warn_write_strings), 0, "write-strings" }, |
||
10142 | { offsetof(TCCState, warn_error), 0, "error" }, |
||
10143 | { offsetof(TCCState, warn_implicit_function_declaration), WD_ALL, |
||
10144 | "implicit-function-declaration" }, |
||
10145 | }; |
||
10146 | |||
10147 | static int set_flag(TCCState *s, const FlagDef *flags, int nb_flags, |
||
10148 | const char *name, int value) |
||
10149 | { |
||
10150 | int i; |
||
10151 | const FlagDef *p; |
||
10152 | const char *r; |
||
10153 | |||
10154 | r = name; |
||
10155 | if (r[0] == 'n' && r[1] == 'o' && r[2] == '-') { |
||
10156 | r += 3; |
||
10157 | value = !value; |
||
10158 | } |
||
10159 | for(i = 0, p = flags; i < nb_flags; i++, p++) { |
||
10160 | if (!strcmp(r, p->name)) |
||
10161 | goto found; |
||
10162 | } |
||
10163 | return -1; |
||
10164 | found: |
||
10165 | if (p->flags & FD_INVERT) |
||
10166 | value = !value; |
||
10167 | *(int *)((uint8_t *)s + p->offset) = value; |
||
10168 | return 0; |
||
10169 | } |
||
10170 | |||
10171 | |||
10172 | /* set/reset a warning */ |
||
10173 | int tcc_set_warning(TCCState *s, const char *warning_name, int value) |
||
10174 | { |
||
10175 | int i; |
||
10176 | const FlagDef *p; |
||
10177 | |||
10178 | if (!strcmp(warning_name, "all")) { |
||
10179 | for(i = 0, p = warning_defs; i < countof(warning_defs); i++, p++) { |
||
10180 | if (p->flags & WD_ALL) |
||
10181 | *(int *)((uint8_t *)s + p->offset) = 1; |
||
10182 | } |
||
10183 | return 0; |
||
10184 | } else { |
||
10185 | return set_flag(s, warning_defs, countof(warning_defs), |
||
10186 | warning_name, value); |
||
10187 | } |
||
10188 | } |
||
10189 | |||
10190 | static const FlagDef flag_defs[] = { |
||
10191 | { offsetof(TCCState, char_is_unsigned), 0, "unsigned-char" }, |
||
10192 | { offsetof(TCCState, char_is_unsigned), FD_INVERT, "signed-char" }, |
||
10193 | { offsetof(TCCState, nocommon), FD_INVERT, "common" }, |
||
10194 | { offsetof(TCCState, leading_underscore), 0, "leading-underscore" }, |
||
10195 | }; |
||
10196 | |||
10197 | /* set/reset a flag */ |
||
10198 | int tcc_set_flag(TCCState *s, const char *flag_name, int value) |
||
10199 | { |
||
10200 | return set_flag(s, flag_defs, countof(flag_defs), |
||
10201 | flag_name, value); |
||
10202 | } |
||
10203 | |||
10204 | #if !defined(LIBTCC) |
||
10205 | |||
10206 | /* extract the basename of a file */ |
||
10207 | static const char *tcc_basename(const char *name) |
||
10208 | { |
||
10209 | const char *p; |
||
10210 | p = strrchr(name, '/'); |
||
10211 | #ifdef WIN32 |
||
10212 | if (!p) |
||
10213 | p = strrchr(name, '\\'); |
||
10214 | #endif |
||
10215 | if (!p) |
||
10216 | p = name; |
||
10217 | else |
||
10218 | p++; |
||
10219 | return p; |
||
10220 | } |
||
10221 | |||
10222 | static int64_t getclock_us(void) |
||
10223 | { |
||
10224 | #ifdef WIN32 |
||
10225 | struct _timeb tb; |
||
10226 | _ftime(&tb); |
||
10227 | return (tb.time * 1000LL + tb.millitm) * 1000LL; |
||
10228 | #else |
||
10229 | struct timeval tv; |
||
10230 | gettimeofday(&tv, NULL); |
||
10231 | return tv.tv_sec * 1000000LL + tv.tv_usec; |
||
10232 | #endif |
||
10233 | } |
||
10234 | |||
10235 | void help(void) |
||
10236 | { |
||
10237 | printf("tcc version " TCC_VERSION " - Tiny C Compiler - Copyright (C) 2001-2005 Fabrice Bellard\n" |
||
10238 | "usage: tcc [-v] [-c] [-o outfile] [-Bdir] [-bench] [-Idir] [-Dsym[=val]] [-Usym]\n" |
||
10239 | " [-Wwarn] [-g] [-b] [-bt N] [-Ldir] [-llib] [-shared] [-static]\n" |
||
10240 | " [infile1 infile2...] [-run infile args...]\n" |
||
10241 | "\n" |
||
10242 | "General options:\n" |
||
10243 | " -v display current version\n" |
||
10244 | " -c compile only - generate an object file\n" |
||
10245 | " -o outfile set output filename\n" |
||
10246 | " -Bdir set tcc internal library path\n" |
||
10247 | " -bench output compilation statistics\n" |
||
10248 | " -run run compiled source\n" |
||
10249 | " -fflag set or reset (with 'no-' prefix) 'flag' (see man page)\n" |
||
10250 | " -Wwarning set or reset (with 'no-' prefix) 'warning' (see man page)\n" |
||
10251 | " -w disable all warnings\n" |
||
10252 | "Preprocessor options:\n" |
||
10253 | " -Idir add include path 'dir'\n" |
||
10254 | " -Dsym[=val] define 'sym' with value 'val'\n" |
||
10255 | " -Usym undefine 'sym'\n" |
||
10256 | "Linker options:\n" |
||
10257 | " -Ldir add library path 'dir'\n" |
||
10258 | " -llib link with dynamic or static library 'lib'\n" |
||
10259 | " -shared generate a shared library\n" |
||
10260 | " -static static linking\n" |
||
10261 | " -rdynamic export all global symbols to dynamic linker\n" |
||
10262 | " -r relocatable output\n" |
||
10263 | "Debugger options:\n" |
||
10264 | " -g generate runtime debug info\n" |
||
10265 | " -bt N show N callers in stack traces\n" |
||
10266 | ); |
||
10267 | } |
||
10268 | |||
10269 | #define TCC_OPTION_HAS_ARG 0x0001 |
||
10270 | #define TCC_OPTION_NOSEP 0x0002 /* cannot have space before option and arg */ |
||
10271 | |||
10272 | typedef struct TCCOption { |
||
10273 | const char *name; |
||
10274 | uint16_t index; |
||
10275 | uint16_t flags; |
||
10276 | } TCCOption; |
||
10277 | |||
10278 | enum { |
||
10279 | TCC_OPTION_HELP, |
||
10280 | TCC_OPTION_I, |
||
10281 | TCC_OPTION_D, |
||
10282 | TCC_OPTION_U, |
||
10283 | TCC_OPTION_L, |
||
10284 | TCC_OPTION_B, |
||
10285 | TCC_OPTION_l, |
||
10286 | TCC_OPTION_bench, |
||
10287 | TCC_OPTION_bt, |
||
10288 | TCC_OPTION_b, |
||
10289 | TCC_OPTION_g, |
||
10290 | TCC_OPTION_c, |
||
10291 | TCC_OPTION_static, |
||
10292 | TCC_OPTION_shared, |
||
10293 | TCC_OPTION_o, |
||
10294 | TCC_OPTION_r, |
||
10295 | TCC_OPTION_Wl, |
||
10296 | TCC_OPTION_W, |
||
10297 | TCC_OPTION_O, |
||
10298 | TCC_OPTION_m, |
||
10299 | TCC_OPTION_f, |
||
10300 | TCC_OPTION_nostdinc, |
||
10301 | TCC_OPTION_nostdlib, |
||
10302 | TCC_OPTION_print_search_dirs, |
||
10303 | TCC_OPTION_rdynamic, |
||
10304 | TCC_OPTION_run, |
||
10305 | TCC_OPTION_v, |
||
10306 | TCC_OPTION_w, |
||
10307 | TCC_OPTION_pipe, |
||
10308 | }; |
||
10309 | |||
10310 | static const TCCOption tcc_options[] = { |
||
10311 | { "h", TCC_OPTION_HELP, 0 }, |
||
10312 | { "?", TCC_OPTION_HELP, 0 }, |
||
10313 | { "I", TCC_OPTION_I, TCC_OPTION_HAS_ARG }, |
||
10314 | { "D", TCC_OPTION_D, TCC_OPTION_HAS_ARG }, |
||
10315 | { "U", TCC_OPTION_U, TCC_OPTION_HAS_ARG }, |
||
10316 | { "L", TCC_OPTION_L, TCC_OPTION_HAS_ARG }, |
||
10317 | { "B", TCC_OPTION_B, TCC_OPTION_HAS_ARG }, |
||
10318 | { "l", TCC_OPTION_l, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, |
||
10319 | { "bench", TCC_OPTION_bench, 0 }, |
||
10320 | { "bt", TCC_OPTION_bt, TCC_OPTION_HAS_ARG }, |
||
10321 | #ifdef CONFIG_TCC_BCHECK |
||
10322 | { "b", TCC_OPTION_b, 0 }, |
||
10323 | #endif |
||
10324 | { "g", TCC_OPTION_g, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, |
||
10325 | { "c", TCC_OPTION_c, 0 }, |
||
10326 | { "static", TCC_OPTION_static, 0 }, |
||
10327 | { "shared", TCC_OPTION_shared, 0 }, |
||
10328 | { "o", TCC_OPTION_o, TCC_OPTION_HAS_ARG }, |
||
10329 | { "run", TCC_OPTION_run, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, |
||
10330 | { "rdynamic", TCC_OPTION_rdynamic, 0 }, |
||
10331 | { "r", TCC_OPTION_r, 0 }, |
||
10332 | { "Wl,", TCC_OPTION_Wl, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, |
||
10333 | { "W", TCC_OPTION_W, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, |
||
10334 | { "O", TCC_OPTION_O, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, |
||
10335 | { "m", TCC_OPTION_m, TCC_OPTION_HAS_ARG }, |
||
10336 | { "f", TCC_OPTION_f, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, |
||
10337 | { "nostdinc", TCC_OPTION_nostdinc, 0 }, |
||
10338 | { "nostdlib", TCC_OPTION_nostdlib, 0 }, |
||
10339 | { "print-search-dirs", TCC_OPTION_print_search_dirs, 0 }, |
||
10340 | { "v", TCC_OPTION_v, 0 }, |
||
10341 | { "w", TCC_OPTION_w, 0 }, |
||
10342 | { "pipe", TCC_OPTION_pipe, 0}, |
||
10343 | { NULL }, |
||
10344 | }; |
||
10345 | |||
10346 | /* convert 'str' into an array of space separated strings */ |
||
10347 | static int expand_args(char ***pargv, const char *str) |
||
10348 | { |
||
10349 | const char *s1; |
||
10350 | char **argv, *arg; |
||
10351 | int argc, len; |
||
10352 | |||
10353 | argc = 0; |
||
10354 | argv = NULL; |
||
10355 | for(;;) { |
||
10356 | while (is_space(*str)) |
||
10357 | str++; |
||
10358 | if (*str == '\0') |
||
10359 | break; |
||
10360 | s1 = str; |
||
10361 | while (*str != '\0' && !is_space(*str)) |
||
10362 | str++; |
||
10363 | len = str - s1; |
||
10364 | arg = tcc_malloc(len + 1); |
||
10365 | memcpy(arg, s1, len); |
||
10366 | arg[len] = '\0'; |
||
10367 | dynarray_add((void ***)&argv, &argc, arg); |
||
10368 | } |
||
10369 | *pargv = argv; |
||
10370 | return argc; |
||
10371 | } |
||
10372 | |||
10373 | static char **files; |
||
10374 | static int nb_files, nb_libraries; |
||
10375 | static int multiple_files; |
||
10376 | static int print_search_dirs; |
||
10377 | static int output_type; |
||
10378 | static int reloc_output; |
||
10379 | static const char *outfile; |
||
10380 | |||
10381 | int parse_args(TCCState *s, int argc, char **argv) |
||
10382 | { |
||
10383 | int optind; |
||
609 | andrew_pro | 10384 | int i; |
145 | halyavin | 10385 | const TCCOption *popt; |
10386 | const char *optarg, *p1, *r1; |
||
10387 | char *r; |
||
609 | andrew_pro | 10388 | /* |
10389 | printf("\n%d\n",argc); |
||
145 | halyavin | 10390 | |
609 | andrew_pro | 10391 | for(i=0;i |
10392 | { |
||
10393 | printf("\n parameter %d = %s",i+1,argv[i]); |
||
10394 | } |
||
10395 | printf("\n"); |
||
10396 | */ |
||
145 | halyavin | 10397 | optind = 0; |
10398 | while (1) { |
||
10399 | if (optind >= argc) { |
||
10400 | if (nb_files == 0 && !print_search_dirs) |
||
609 | andrew_pro | 10401 | goto show_help; |
145 | halyavin | 10402 | else |
10403 | break; |
||
10404 | } |
||
10405 | r = argv[optind++]; |
||
10406 | if (r[0] != '-') { |
||
609 | andrew_pro | 10407 | |
145 | halyavin | 10408 | /* add a new file */ |
10409 | dynarray_add((void ***)&files, &nb_files, r); |
||
10410 | if (!multiple_files) { |
||
10411 | optind--; |
||
10412 | /* argv[0] will be this file */ |
||
10413 | break; |
||
10414 | } |
||
10415 | } else { |
||
10416 | /* find option in table (match only the first chars */ |
||
10417 | popt = tcc_options; |
||
10418 | for(;;) { |
||
10419 | p1 = popt->name; |
||
10420 | if (p1 == NULL) |
||
609 | andrew_pro | 10421 | printf("\n invalid option -- '%s'", r); |
145 | halyavin | 10422 | r1 = r + 1; |
10423 | for(;;) { |
||
10424 | if (*p1 == '\0') |
||
10425 | goto option_found; |
||
10426 | if (*r1 != *p1) |
||
10427 | break; |
||
10428 | p1++; |
||
10429 | r1++; |
||
10430 | } |
||
10431 | popt++; |
||
10432 | } |
||
10433 | option_found: |
||
10434 | if (popt->flags & TCC_OPTION_HAS_ARG) { |
||
10435 | if (*r1 != '\0' || (popt->flags & TCC_OPTION_NOSEP)) { |
||
10436 | optarg = r1; |
||
10437 | } else { |
||
10438 | if (optind >= argc) |
||
609 | andrew_pro | 10439 | printf("\n argument to '%s' is missing", r); |
145 | halyavin | 10440 | optarg = argv[optind++]; |
10441 | } |
||
10442 | } else { |
||
10443 | if (*r1 != '\0') |
||
10444 | goto show_help; |
||
10445 | optarg = NULL; |
||
10446 | } |
||
10447 | |||
10448 | switch(popt->index) { |
||
10449 | case TCC_OPTION_HELP: |
||
10450 | show_help: |
||
10451 | help(); |
||
10452 | exit(1); |
||
10453 | case TCC_OPTION_I: |
||
10454 | if (tcc_add_include_path(s, optarg) < 0) |
||
609 | andrew_pro | 10455 | printf("\n too many include paths"); |
145 | halyavin | 10456 | break; |
10457 | case TCC_OPTION_D: |
||
10458 | { |
||
10459 | char *sym, *value; |
||
10460 | sym = (char *)optarg; |
||
10461 | value = strchr(sym, '='); |
||
10462 | if (value) { |
||
10463 | *value = '\0'; |
||
10464 | value++; |
||
10465 | } |
||
10466 | tcc_define_symbol(s, sym, value); |
||
10467 | } |
||
10468 | break; |
||
10469 | case TCC_OPTION_U: |
||
10470 | tcc_undefine_symbol(s, optarg); |
||
10471 | break; |
||
10472 | case TCC_OPTION_L: |
||
10473 | tcc_add_library_path(s, optarg); |
||
10474 | break; |
||
10475 | case TCC_OPTION_B: |
||
10476 | /* set tcc utilities path (mainly for tcc development) */ |
||
10477 | tcc_lib_path = optarg; |
||
10478 | break; |
||
10479 | case TCC_OPTION_l: |
||
10480 | dynarray_add((void ***)&files, &nb_files, r); |
||
10481 | nb_libraries++; |
||
10482 | break; |
||
10483 | case TCC_OPTION_bench: |
||
10484 | do_bench = 1; |
||
10485 | break; |
||
10486 | case TCC_OPTION_bt: |
||
10487 | num_callers = atoi(optarg); |
||
10488 | break; |
||
10489 | #ifdef CONFIG_TCC_BCHECK |
||
10490 | case TCC_OPTION_b: |
||
10491 | do_bounds_check = 1; |
||
10492 | do_debug = 1; |
||
10493 | break; |
||
10494 | #endif |
||
10495 | case TCC_OPTION_g: |
||
10496 | do_debug = 1; |
||
10497 | break; |
||
10498 | case TCC_OPTION_c: |
||
10499 | multiple_files = 1; |
||
10500 | output_type = TCC_OUTPUT_OBJ; |
||
10501 | break; |
||
10502 | case TCC_OPTION_static: |
||
10503 | s->static_link = 1; |
||
10504 | break; |
||
10505 | case TCC_OPTION_shared: |
||
10506 | output_type = TCC_OUTPUT_DLL; |
||
10507 | break; |
||
10508 | case TCC_OPTION_o: |
||
10509 | multiple_files = 1; |
||
10510 | outfile = optarg; |
||
10511 | break; |
||
10512 | case TCC_OPTION_r: |
||
10513 | /* generate a .o merging several output files */ |
||
10514 | reloc_output = 1; |
||
10515 | output_type = TCC_OUTPUT_OBJ; |
||
10516 | break; |
||
10517 | case TCC_OPTION_nostdinc: |
||
10518 | s->nostdinc = 1; |
||
10519 | break; |
||
10520 | case TCC_OPTION_nostdlib: |
||
10521 | s->nostdlib = 1; |
||
10522 | break; |
||
10523 | case TCC_OPTION_print_search_dirs: |
||
10524 | print_search_dirs = 1; |
||
10525 | break; |
||
10526 | case TCC_OPTION_run: |
||
10527 | { |
||
10528 | int argc1; |
||
10529 | char **argv1; |
||
10530 | argc1 = expand_args(&argv1, optarg); |
||
10531 | if (argc1 > 0) { |
||
10532 | parse_args(s, argc1, argv1); |
||
10533 | } |
||
10534 | multiple_files = 0; |
||
10535 | output_type = TCC_OUTPUT_MEMORY; |
||
10536 | } |
||
10537 | break; |
||
10538 | case TCC_OPTION_v: |
||
10539 | printf("tcc version %s\n", TCC_VERSION); |
||
10540 | exit(0); |
||
10541 | case TCC_OPTION_f: |
||
10542 | if (tcc_set_flag(s, optarg, 1) < 0 && s->warn_unsupported) |
||
10543 | goto unsupported_option; |
||
10544 | break; |
||
10545 | case TCC_OPTION_W: |
||
10546 | if (tcc_set_warning(s, optarg, 1) < 0 && |
||
10547 | s->warn_unsupported) |
||
10548 | goto unsupported_option; |
||
10549 | break; |
||
10550 | case TCC_OPTION_w: |
||
10551 | s->warn_none = 1; |
||
10552 | break; |
||
10553 | case TCC_OPTION_rdynamic: |
||
10554 | s->rdynamic = 1; |
||
10555 | break; |
||
10556 | case TCC_OPTION_Wl: |
||
10557 | { |
||
10558 | const char *p; |
||
10559 | if (strstart(optarg, "-Ttext,", &p)) { |
||
10560 | s->text_addr = strtoul(p, NULL, 16); |
||
10561 | s->has_text_addr = 1; |
||
10562 | } else if (strstart(optarg, "--oformat,", &p)) { |
||
10563 | if (strstart(p, "elf32-", NULL)) { |
||
10564 | s->output_format = TCC_OUTPUT_FORMAT_ELF; |
||
10565 | } else if (!strcmp(p, "binary")) { |
||
10566 | s->output_format = TCC_OUTPUT_FORMAT_BINARY; |
||
10567 | } else |
||
10568 | #ifdef TCC_TARGET_COFF |
||
10569 | if (!strcmp(p, "coff")) { |
||
10570 | s->output_format = TCC_OUTPUT_FORMAT_COFF; |
||
10571 | } else |
||
10572 | #endif |
||
10573 | { |
||
609 | andrew_pro | 10574 | printf("\n target %s not found", p); |
145 | halyavin | 10575 | } |
10576 | } else { |
||
609 | andrew_pro | 10577 | printf("\n unsupported linker option '%s'", optarg); |
145 | halyavin | 10578 | } |
10579 | } |
||
10580 | break; |
||
10581 | default: |
||
10582 | if (s->warn_unsupported) { |
||
10583 | unsupported_option: |
||
10584 | warning("unsupported option '%s'", r); |
||
609 | andrew_pro | 10585 | printf("\n unsupported option '%s'", r); |
145 | halyavin | 10586 | } |
10587 | break; |
||
10588 | } |
||
10589 | } |
||
10590 | } |
||
10591 | return optind; |
||
10592 | } |
||
10593 | |||
609 | andrew_pro | 10594 | int app_main(int argc, char **argv) |
145 | halyavin | 10595 | { |
10596 | int i; |
||
10597 | TCCState *s; |
||
10598 | int nb_objfiles, ret, optind; |
||
10599 | char objfilename[1024]; |
||
10600 | int64_t start_time = 0; |
||
609 | andrew_pro | 10601 | int bug; |
145 | halyavin | 10602 | |
609 | andrew_pro | 10603 | printf("\nTinyC compiler started.\n "); |
145 | halyavin | 10604 | #ifdef WIN32 |
10605 | /* on win32, we suppose the lib and includes are at the location |
||
10606 | of 'tcc.exe' */ |
||
10607 | { |
||
10608 | static char path[1024]; |
||
10609 | char *p, *d; |
||
10610 | |||
10611 | GetModuleFileNameA(NULL, path, sizeof path); |
||
10612 | p = d = strlwr(path); |
||
10613 | while (*d) |
||
10614 | { |
||
10615 | if (*d == '\\') *d = '/', p = d; |
||
10616 | ++d; |
||
10617 | } |
||
10618 | *p = '\0'; |
||
10619 | tcc_lib_path = path; |
||
10620 | } |
||
10621 | #endif |
||
10622 | |||
10623 | s = tcc_new(); |
||
10624 | output_type = TCC_OUTPUT_EXE; |
||
10625 | outfile = NULL; |
||
10626 | multiple_files = 1; |
||
10627 | files = NULL; |
||
10628 | nb_files = 0; |
||
10629 | nb_libraries = 0; |
||
10630 | reloc_output = 0; |
||
10631 | print_search_dirs = 0; |
||
609 | andrew_pro | 10632 | printf("TinyC initializated.\n"); |
10633 | bug=argc; |
||
10634 | if (bug==0) {bug==1;} |
||
10635 | optind = parse_args(s, bug - 1, argv + 1) + 1; |
||
10636 | printf("\n Arguments parsed.\n"); |
||
145 | halyavin | 10637 | |
10638 | if (print_search_dirs) { |
||
10639 | /* enough for Linux kernel */ |
||
10640 | printf("install: %s/\n", tcc_lib_path); |
||
10641 | return 0; |
||
10642 | } |
||
10643 | |||
10644 | nb_objfiles = nb_files - nb_libraries; |
||
10645 | |||
10646 | /* if outfile provided without other options, we output an |
||
10647 | executable */ |
||
10648 | if (outfile && output_type == TCC_OUTPUT_MEMORY) |
||
10649 | output_type = TCC_OUTPUT_EXE; |
||
10650 | |||
609 | andrew_pro | 10651 | /* check -c |
10652 | consistency : only single file handled. XXX: checks file type */ |
||
145 | halyavin | 10653 | if (output_type == TCC_OUTPUT_OBJ && !reloc_output) { |
10654 | /* accepts only a single input file */ |
||
10655 | if (nb_objfiles != 1) |
||
609 | andrew_pro | 10656 | printf("\n cannot specify multiple files with -c"); |
145 | halyavin | 10657 | if (nb_libraries != 0) |
609 | andrew_pro | 10658 | printf("\n cannot specify libraries with -c"); |
145 | halyavin | 10659 | } |
10660 | |||
10661 | if (output_type != TCC_OUTPUT_MEMORY) { |
||
10662 | if (!outfile) { |
||
10663 | /* compute default outfile name */ |
||
10664 | pstrcpy(objfilename, sizeof(objfilename) - 1, |
||
10665 | /* strip path */ |
||
10666 | tcc_basename(files[0])); |
||
10667 | #ifdef TCC_TARGET_PE |
||
10668 | pe_guess_outfile(objfilename, output_type); |
||
10669 | #else |
||
10670 | if (output_type == TCC_OUTPUT_OBJ && !reloc_output) { |
||
10671 | char *ext = strrchr(objfilename, '.'); |
||
10672 | if (!ext) |
||
10673 | goto default_outfile; |
||
10674 | /* add .o extension */ |
||
10675 | strcpy(ext + 1, "o"); |
||
10676 | } else { |
||
10677 | default_outfile: |
||
10678 | pstrcpy(objfilename, sizeof(objfilename), "a.out"); |
||
10679 | } |
||
10680 | #endif |
||
10681 | outfile = objfilename; |
||
10682 | } |
||
10683 | } |
||
10684 | |||
10685 | if (do_bench) { |
||
10686 | start_time = getclock_us(); |
||
10687 | } |
||
10688 | |||
10689 | tcc_set_output_type(s, output_type); |
||
10690 | |||
10691 | /* compile or add each files or library */ |
||
10692 | for(i = 0;i < nb_files; i++) { |
||
10693 | const char *filename; |
||
10694 | |||
10695 | filename = files[i]; |
||
10696 | if (filename[0] == '-') { |
||
10697 | if (tcc_add_library(s, filename + 2) < 0) |
||
10698 | error("cannot find %s", filename); |
||
10699 | } else { |
||
10700 | if (tcc_add_file(s, filename) < 0) { |
||
10701 | ret = 1; |
||
10702 | goto the_end; |
||
10703 | } |
||
10704 | } |
||
10705 | } |
||
10706 | |||
10707 | /* free all files */ |
||
10708 | tcc_free(files); |
||
10709 | |||
10710 | if (do_bench) { |
||
10711 | double total_time; |
||
10712 | total_time = (double)(getclock_us() - start_time) / 1000000.0; |
||
10713 | if (total_time < 0.001) |
||
10714 | total_time = 0.001; |
||
10715 | if (total_bytes < 1) |
||
10716 | total_bytes = 1; |
||
10717 | printf("%d idents, %d lines, %d bytes, %0.3f s, %d lines/s, %0.1f MB/s\n", |
||
10718 | tok_ident - TOK_IDENT, total_lines, total_bytes, |
||
10719 | total_time, (int)(total_lines / total_time), |
||
10720 | total_bytes / total_time / 1000000.0); |
||
10721 | } |
||
10722 | |||
10723 | if (s->output_type == TCC_OUTPUT_MEMORY) { |
||
10724 | ret = tcc_run(s, argc - optind, argv + optind); |
||
10725 | } else |
||
10726 | #ifdef TCC_TARGET_PE |
||
10727 | if (s->output_type != TCC_OUTPUT_OBJ) { |
||
10728 | ret = tcc_output_pe(s, outfile); |
||
609 | andrew_pro | 10729 | } else |
10730 | #else |
||
10731 | #ifdef TCC_TARGET_MEOS |
||
145 | halyavin | 10732 | if (s->output_type != TCC_OUTPUT_OBJ) { |
10733 | ret = tcc_output_me(s, outfile); |
||
609 | andrew_pro | 10734 | } else |
145 | halyavin | 10735 | #endif |
609 | andrew_pro | 10736 | #endif |
145 | halyavin | 10737 | |
10738 | { |
||
10739 | tcc_output_file(s, outfile); |
||
10740 | ret = 0; |
||
10741 | } |
||
10742 | the_end: |
||
10743 | /* XXX: cannot do it with bound checking because of the malloc hooks */ |
||
10744 | if (!do_bounds_check) |
||
10745 | tcc_delete(s); |
||
10746 | |||
10747 | #ifdef MEM_DEBUG |
||
10748 | if (do_bench) { |
||
10749 | printf("memory: %d bytes, max = %d bytes\n", mem_cur_size, mem_max_size); |
||
10750 | } |
||
10751 | #endif |
||
609 | andrew_pro | 10752 | printf("\n TinyC finished work\n"); |
145 | halyavin | 10753 | return ret; |
10754 | } |
||
10755 | |||
10756 | #endif>>>>>>>> |