Rev 647 | Rev 6429 | 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 |
||
6410 | siemargl | 1037 | //2016-04-27 siemargl commented to fix crash temporally. Need to fix |
1038 | // free(ptr); |
||
145 | halyavin | 1039 | } |
1040 | |||
1041 | static void *tcc_malloc(unsigned long size) |
||
1042 | { |
||
1043 | void *ptr; |
||
1044 | ptr = malloc(size); |
||
1045 | if (!ptr && size) |
||
1046 | error("memory full"); |
||
1047 | #ifdef MEM_DEBUG |
||
1048 | mem_cur_size += malloc_usable_size(ptr); |
||
1049 | if (mem_cur_size > mem_max_size) |
||
1050 | mem_max_size = mem_cur_size; |
||
1051 | #endif |
||
1052 | return ptr; |
||
1053 | } |
||
1054 | |||
1055 | static void *tcc_mallocz(unsigned long size) |
||
1056 | { |
||
1057 | void *ptr; |
||
1058 | ptr = tcc_malloc(size); |
||
1059 | memset(ptr, 0, size); |
||
1060 | return ptr; |
||
1061 | } |
||
1062 | |||
1063 | static inline void *tcc_realloc(void *ptr, unsigned long size) |
||
1064 | { |
||
1065 | void *ptr1; |
||
1066 | #ifdef MEM_DEBUG |
||
1067 | mem_cur_size -= malloc_usable_size(ptr); |
||
1068 | #endif |
||
1069 | ptr1 = realloc(ptr, size); |
||
1070 | #ifdef MEM_DEBUG |
||
1071 | /* NOTE: count not correct if alloc error, but not critical */ |
||
1072 | mem_cur_size += malloc_usable_size(ptr1); |
||
1073 | if (mem_cur_size > mem_max_size) |
||
1074 | mem_max_size = mem_cur_size; |
||
1075 | #endif |
||
1076 | return ptr1; |
||
1077 | } |
||
1078 | |||
1079 | static char *tcc_strdup(const char *str) |
||
1080 | { |
||
1081 | char *ptr; |
||
1082 | ptr = tcc_malloc(strlen(str) + 1); |
||
1083 | strcpy(ptr, str); |
||
1084 | return ptr; |
||
1085 | } |
||
1086 | |||
1087 | #define free(p) use_tcc_free(p) |
||
1088 | #define malloc(s) use_tcc_malloc(s) |
||
1089 | #define realloc(p, s) use_tcc_realloc(p, s) |
||
1090 | |||
1091 | static void dynarray_add(void ***ptab, int *nb_ptr, void *data) |
||
1092 | { |
||
1093 | int nb, nb_alloc; |
||
1094 | void **pp; |
||
1095 | |||
1096 | nb = *nb_ptr; |
||
1097 | pp = *ptab; |
||
1098 | /* every power of two we double array size */ |
||
1099 | if ((nb & (nb - 1)) == 0) { |
||
1100 | if (!nb) |
||
1101 | nb_alloc = 1; |
||
1102 | else |
||
1103 | nb_alloc = nb * 2; |
||
1104 | pp = tcc_realloc(pp, nb_alloc * sizeof(void *)); |
||
1105 | if (!pp) |
||
1106 | error("memory full"); |
||
1107 | *ptab = pp; |
||
1108 | } |
||
1109 | pp[nb++] = data; |
||
1110 | *nb_ptr = nb; |
||
1111 | } |
||
1112 | |||
1113 | /* symbol allocator */ |
||
1114 | static Sym *__sym_malloc(void) |
||
1115 | { |
||
1116 | Sym *sym_pool, *sym, *last_sym; |
||
1117 | int i; |
||
1118 | |||
1119 | sym_pool = tcc_malloc(SYM_POOL_NB * sizeof(Sym)); |
||
1120 | |||
1121 | last_sym = sym_free_first; |
||
1122 | sym = sym_pool; |
||
1123 | for(i = 0; i < SYM_POOL_NB; i++) { |
||
1124 | sym->next = last_sym; |
||
1125 | last_sym = sym; |
||
1126 | sym++; |
||
1127 | } |
||
1128 | sym_free_first = last_sym; |
||
1129 | return last_sym; |
||
1130 | } |
||
1131 | |||
1132 | static inline Sym *sym_malloc(void) |
||
1133 | { |
||
1134 | Sym *sym; |
||
1135 | sym = sym_free_first; |
||
1136 | if (!sym) |
||
1137 | sym = __sym_malloc(); |
||
1138 | sym_free_first = sym->next; |
||
1139 | return sym; |
||
1140 | } |
||
1141 | |||
1142 | static inline void sym_free(Sym *sym) |
||
1143 | { |
||
1144 | sym->next = sym_free_first; |
||
1145 | sym_free_first = sym; |
||
1146 | } |
||
1147 | |||
1148 | Section *new_section(TCCState *s1, const char *name, int sh_type, int sh_flags) |
||
1149 | { |
||
1150 | Section *sec; |
||
1151 | |||
1152 | sec = tcc_mallocz(sizeof(Section) + strlen(name)); |
||
1153 | strcpy(sec->name, name); |
||
1154 | sec->sh_type = sh_type; |
||
1155 | sec->sh_flags = sh_flags; |
||
1156 | switch(sh_type) { |
||
1157 | case SHT_HASH: |
||
1158 | case SHT_REL: |
||
1159 | case SHT_DYNSYM: |
||
1160 | case SHT_SYMTAB: |
||
1161 | case SHT_DYNAMIC: |
||
1162 | sec->sh_addralign = 4; |
||
1163 | break; |
||
1164 | case SHT_STRTAB: |
||
1165 | sec->sh_addralign = 1; |
||
1166 | break; |
||
1167 | default: |
||
1168 | sec->sh_addralign = 32; /* default conservative alignment */ |
||
1169 | break; |
||
1170 | } |
||
1171 | |||
1172 | /* only add section if not private */ |
||
1173 | if (!(sh_flags & SHF_PRIVATE)) { |
||
1174 | sec->sh_num = s1->nb_sections; |
||
1175 | dynarray_add((void ***)&s1->sections, &s1->nb_sections, sec); |
||
1176 | } |
||
1177 | return sec; |
||
1178 | } |
||
1179 | |||
1180 | static void free_section(Section *s) |
||
1181 | { |
||
1182 | tcc_free(s->data); |
||
1183 | tcc_free(s); |
||
1184 | } |
||
1185 | |||
1186 | /* realloc section and set its content to zero */ |
||
1187 | static void section_realloc(Section *sec, unsigned long new_size) |
||
1188 | { |
||
1189 | unsigned long size; |
||
1190 | unsigned char *data; |
||
1191 | |||
1192 | size = sec->data_allocated; |
||
1193 | if (size == 0) |
||
1194 | size = 1; |
||
1195 | while (size < new_size) |
||
1196 | size = size * 2; |
||
1197 | data = tcc_realloc(sec->data, size); |
||
1198 | if (!data) |
||
1199 | error("memory full"); |
||
1200 | memset(data + sec->data_allocated, 0, size - sec->data_allocated); |
||
1201 | sec->data = data; |
||
1202 | sec->data_allocated = size; |
||
1203 | } |
||
1204 | |||
1205 | /* reserve at least 'size' bytes in section 'sec' from |
||
1206 | sec->data_offset. */ |
||
1207 | static void *section_ptr_add(Section *sec, unsigned long size) |
||
1208 | { |
||
1209 | unsigned long offset, offset1; |
||
1210 | |||
1211 | offset = sec->data_offset; |
||
1212 | offset1 = offset + size; |
||
1213 | if (offset1 > sec->data_allocated) |
||
1214 | section_realloc(sec, offset1); |
||
1215 | sec->data_offset = offset1; |
||
1216 | return sec->data + offset; |
||
1217 | } |
||
1218 | |||
1219 | /* return a reference to a section, and create it if it does not |
||
1220 | exists */ |
||
1221 | Section *find_section(TCCState *s1, const char *name) |
||
1222 | { |
||
1223 | Section *sec; |
||
1224 | int i; |
||
1225 | for(i = 1; i < s1->nb_sections; i++) { |
||
1226 | sec = s1->sections[i]; |
||
1227 | if (!strcmp(name, sec->name)) |
||
1228 | return sec; |
||
1229 | } |
||
1230 | /* sections are created as PROGBITS */ |
||
1231 | return new_section(s1, name, SHT_PROGBITS, SHF_ALLOC); |
||
1232 | } |
||
1233 | |||
1234 | #define SECTION_ABS ((void *)1) |
||
1235 | |||
1236 | /* update sym->c so that it points to an external symbol in section |
||
1237 | 'section' with value 'value' */ |
||
1238 | static void put_extern_sym2(Sym *sym, Section *section, |
||
1239 | unsigned long value, unsigned long size, |
||
1240 | int can_add_underscore) |
||
1241 | { |
||
1242 | int sym_type, sym_bind, sh_num, info; |
||
1243 | Elf32_Sym *esym; |
||
1244 | const char *name; |
||
1245 | char buf1[256]; |
||
1246 | |||
1247 | if (section == NULL) |
||
1248 | sh_num = SHN_UNDEF; |
||
1249 | else if (section == SECTION_ABS) |
||
1250 | sh_num = SHN_ABS; |
||
1251 | else |
||
1252 | sh_num = section->sh_num; |
||
1253 | if (!sym->c) { |
||
1254 | if ((sym->type.t & VT_BTYPE) == VT_FUNC) |
||
1255 | sym_type = STT_FUNC; |
||
1256 | else |
||
1257 | sym_type = STT_OBJECT; |
||
1258 | if (sym->type.t & VT_STATIC) |
||
1259 | sym_bind = STB_LOCAL; |
||
1260 | else |
||
1261 | sym_bind = STB_GLOBAL; |
||
1262 | |||
1263 | name = get_tok_str(sym->v, NULL); |
||
1264 | #ifdef CONFIG_TCC_BCHECK |
||
1265 | if (do_bounds_check) { |
||
1266 | char buf[32]; |
||
1267 | |||
1268 | /* XXX: avoid doing that for statics ? */ |
||
1269 | /* if bound checking is activated, we change some function |
||
1270 | names by adding the "__bound" prefix */ |
||
1271 | switch(sym->v) { |
||
1272 | #if 0 |
||
1273 | /* XXX: we rely only on malloc hooks */ |
||
1274 | case TOK_malloc: |
||
1275 | case TOK_free: |
||
1276 | case TOK_realloc: |
||
1277 | case TOK_memalign: |
||
1278 | case TOK_calloc: |
||
1279 | #endif |
||
1280 | case TOK_memcpy: |
||
1281 | case TOK_memmove: |
||
1282 | case TOK_memset: |
||
1283 | case TOK_strlen: |
||
1284 | case TOK_strcpy: |
||
1285 | strcpy(buf, "__bound_"); |
||
1286 | strcat(buf, name); |
||
1287 | name = buf; |
||
1288 | break; |
||
1289 | } |
||
1290 | } |
||
1291 | #endif |
||
1292 | if (tcc_state->leading_underscore && can_add_underscore) { |
||
1293 | buf1[0] = '_'; |
||
1294 | pstrcpy(buf1 + 1, sizeof(buf1) - 1, name); |
||
1295 | name = buf1; |
||
1296 | } |
||
1297 | info = ELF32_ST_INFO(sym_bind, sym_type); |
||
1298 | sym->c = add_elf_sym(symtab_section, value, size, info, 0, sh_num, name); |
||
1299 | } else { |
||
1300 | esym = &((Elf32_Sym *)symtab_section->data)[sym->c]; |
||
1301 | esym->st_value = value; |
||
1302 | esym->st_size = size; |
||
1303 | esym->st_shndx = sh_num; |
||
1304 | } |
||
1305 | } |
||
1306 | |||
1307 | static void put_extern_sym(Sym *sym, Section *section, |
||
1308 | unsigned long value, unsigned long size) |
||
1309 | { |
||
1310 | put_extern_sym2(sym, section, value, size, 1); |
||
1311 | } |
||
1312 | |||
1313 | /* add a new relocation entry to symbol 'sym' in section 's' */ |
||
1314 | static void greloc(Section *s, Sym *sym, unsigned long offset, int type) |
||
1315 | { |
||
1316 | if (!sym->c) |
||
1317 | put_extern_sym(sym, NULL, 0, 0); |
||
1318 | /* now we can add ELF relocation info */ |
||
1319 | put_elf_reloc(symtab_section, s, offset, type, sym->c); |
||
1320 | } |
||
1321 | |||
1322 | static inline int isid(int c) |
||
1323 | { |
||
1324 | return (c >= 'a' && c <= 'z') || |
||
1325 | (c >= 'A' && c <= 'Z') || |
||
1326 | c == '_'; |
||
1327 | } |
||
1328 | |||
1329 | static inline int isnum(int c) |
||
1330 | { |
||
1331 | return c >= '0' && c <= '9'; |
||
1332 | } |
||
1333 | |||
1334 | static inline int isoct(int c) |
||
1335 | { |
||
1336 | return c >= '0' && c <= '7'; |
||
1337 | } |
||
1338 | |||
1339 | static inline int toup(int c) |
||
1340 | { |
||
1341 | if (c >= 'a' && c <= 'z') |
||
1342 | return c - 'a' + 'A'; |
||
1343 | else |
||
1344 | return c; |
||
1345 | } |
||
1346 | |||
1347 | static void strcat_vprintf(char *buf, int buf_size, const char *fmt, va_list ap) |
||
1348 | { |
||
1349 | int len; |
||
1350 | len = strlen(buf); |
||
1351 | vsnprintf(buf + len, buf_size - len, fmt, ap); |
||
1352 | } |
||
1353 | |||
1354 | static void strcat_printf(char *buf, int buf_size, const char *fmt, ...) |
||
1355 | { |
||
1356 | va_list ap; |
||
1357 | va_start(ap, fmt); |
||
1358 | strcat_vprintf(buf, buf_size, fmt, ap); |
||
1359 | va_end(ap); |
||
1360 | } |
||
1361 | |||
1362 | void error1(TCCState *s1, int is_warning, const char *fmt, va_list ap) |
||
1363 | { |
||
1364 | char buf[2048]; |
||
1365 | BufferedFile **f; |
||
1366 | |||
1367 | buf[0] = '\0'; |
||
1368 | if (file) { |
||
1369 | for(f = s1->include_stack; f < s1->include_stack_ptr; f++) |
||
1370 | strcat_printf(buf, sizeof(buf), "In file included from %s:%d:\n", |
||
1371 | (*f)->filename, (*f)->line_num); |
||
1372 | if (file->line_num > 0) { |
||
1373 | strcat_printf(buf, sizeof(buf), |
||
1374 | "%s:%d: ", file->filename, file->line_num); |
||
1375 | } else { |
||
1376 | strcat_printf(buf, sizeof(buf), |
||
1377 | "%s: ", file->filename); |
||
1378 | } |
||
1379 | } else { |
||
1380 | strcat_printf(buf, sizeof(buf), |
||
1381 | "tcc: "); |
||
1382 | } |
||
1383 | if (is_warning) |
||
1384 | strcat_printf(buf, sizeof(buf), "warning: "); |
||
1385 | strcat_vprintf(buf, sizeof(buf), fmt, ap); |
||
1386 | |||
1387 | if (!s1->error_func) { |
||
1388 | /* default case: stderr */ |
||
609 | andrew_pro | 1389 | printf("%s\n", buf); |
145 | halyavin | 1390 | } else { |
1391 | s1->error_func(s1->error_opaque, buf); |
||
1392 | } |
||
1393 | if (!is_warning || s1->warn_error) |
||
1394 | s1->nb_errors++; |
||
1395 | } |
||
1396 | |||
1397 | #ifdef LIBTCC |
||
1398 | void tcc_set_error_func(TCCState *s, void *error_opaque, |
||
1399 | void (*error_func)(void *opaque, const char *msg)) |
||
1400 | { |
||
1401 | s->error_opaque = error_opaque; |
||
1402 | s->error_func = error_func; |
||
1403 | } |
||
1404 | #endif |
||
1405 | |||
1406 | /* error without aborting current compilation */ |
||
1407 | void error_noabort(const char *fmt, ...) |
||
1408 | { |
||
1409 | TCCState *s1 = tcc_state; |
||
1410 | va_list ap; |
||
1411 | |||
1412 | va_start(ap, fmt); |
||
1413 | error1(s1, 0, fmt, ap); |
||
1414 | va_end(ap); |
||
1415 | } |
||
1416 | |||
1417 | void error(const char *fmt, ...) |
||
1418 | { |
||
1419 | TCCState *s1 = tcc_state; |
||
1420 | va_list ap; |
||
1421 | |||
1422 | va_start(ap, fmt); |
||
1423 | error1(s1, 0, fmt, ap); |
||
1424 | va_end(ap); |
||
1425 | /* better than nothing: in some cases, we accept to handle errors */ |
||
1426 | if (s1->error_set_jmp_enabled) { |
||
1427 | longjmp(s1->error_jmp_buf, 1); |
||
1428 | } else { |
||
1429 | /* XXX: eliminate this someday */ |
||
1430 | exit(1); |
||
1431 | } |
||
1432 | } |
||
1433 | |||
1434 | void expect(const char *msg) |
||
1435 | { |
||
1436 | error("%s expected", msg); |
||
1437 | } |
||
1438 | |||
1439 | void warning(const char *fmt, ...) |
||
1440 | { |
||
1441 | TCCState *s1 = tcc_state; |
||
1442 | va_list ap; |
||
1443 | |||
1444 | if (s1->warn_none) |
||
1445 | return; |
||
1446 | |||
1447 | va_start(ap, fmt); |
||
1448 | error1(s1, 1, fmt, ap); |
||
1449 | va_end(ap); |
||
1450 | } |
||
1451 | |||
1452 | void skip(int c) |
||
1453 | { |
||
1454 | if (tok != c) |
||
1455 | error("'%c' expected", c); |
||
1456 | next(); |
||
1457 | } |
||
1458 | |||
1459 | static void test_lvalue(void) |
||
1460 | { |
||
1461 | if (!(vtop->r & VT_LVAL)) |
||
1462 | expect("lvalue"); |
||
1463 | } |
||
1464 | |||
1465 | /* allocate a new token */ |
||
1466 | static TokenSym *tok_alloc_new(TokenSym **pts, const char *str, int len) |
||
1467 | { |
||
1468 | TokenSym *ts, **ptable; |
||
1469 | int i; |
||
1470 | |||
1471 | if (tok_ident >= SYM_FIRST_ANOM) |
||
1472 | error("memory full"); |
||
1473 | |||
1474 | /* expand token table if needed */ |
||
1475 | i = tok_ident - TOK_IDENT; |
||
1476 | if ((i % TOK_ALLOC_INCR) == 0) { |
||
1477 | ptable = tcc_realloc(table_ident, (i + TOK_ALLOC_INCR) * sizeof(TokenSym *)); |
||
1478 | if (!ptable) |
||
1479 | error("memory full"); |
||
1480 | table_ident = ptable; |
||
1481 | } |
||
1482 | |||
1483 | ts = tcc_malloc(sizeof(TokenSym) + len); |
||
1484 | table_ident[i] = ts; |
||
1485 | ts->tok = tok_ident++; |
||
1486 | ts->sym_define = NULL; |
||
1487 | ts->sym_label = NULL; |
||
1488 | ts->sym_struct = NULL; |
||
1489 | ts->sym_identifier = NULL; |
||
1490 | ts->len = len; |
||
1491 | ts->hash_next = NULL; |
||
1492 | memcpy(ts->str, str, len); |
||
1493 | ts->str[len] = '\0'; |
||
1494 | *pts = ts; |
||
1495 | return ts; |
||
1496 | } |
||
1497 | |||
1498 | #define TOK_HASH_INIT 1 |
||
1499 | #define TOK_HASH_FUNC(h, c) ((h) * 263 + (c)) |
||
1500 | |||
1501 | /* find a token and add it if not found */ |
||
1502 | static TokenSym *tok_alloc(const char *str, int len) |
||
1503 | { |
||
1504 | TokenSym *ts, **pts; |
||
1505 | int i; |
||
1506 | unsigned int h; |
||
1507 | |||
1508 | h = TOK_HASH_INIT; |
||
1509 | for(i=0;i |
||
1510 | h = TOK_HASH_FUNC(h, ((unsigned char *)str)[i]); |
||
1511 | h &= (TOK_HASH_SIZE - 1); |
||
1512 | |||
1513 | pts = &hash_ident[h]; |
||
1514 | for(;;) { |
||
1515 | ts = *pts; |
||
1516 | if (!ts) |
||
1517 | break; |
||
1518 | if (ts->len == len && !memcmp(ts->str, str, len)) |
||
1519 | return ts; |
||
1520 | pts = &(ts->hash_next); |
||
1521 | } |
||
1522 | return tok_alloc_new(pts, str, len); |
||
1523 | } |
||
1524 | |||
1525 | /* CString handling */ |
||
1526 | |||
1527 | static void cstr_realloc(CString *cstr, int new_size) |
||
1528 | { |
||
1529 | int size; |
||
1530 | void *data; |
||
1531 | |||
1532 | size = cstr->size_allocated; |
||
1533 | if (size == 0) |
||
1534 | size = 8; /* no need to allocate a too small first string */ |
||
1535 | while (size < new_size) |
||
1536 | size = size * 2; |
||
1537 | data = tcc_realloc(cstr->data_allocated, size); |
||
1538 | if (!data) |
||
1539 | error("memory full"); |
||
1540 | cstr->data_allocated = data; |
||
1541 | cstr->size_allocated = size; |
||
1542 | cstr->data = data; |
||
1543 | } |
||
1544 | |||
1545 | /* add a byte */ |
||
1546 | static inline void cstr_ccat(CString *cstr, int ch) |
||
1547 | { |
||
1548 | int size; |
||
1549 | size = cstr->size + 1; |
||
1550 | if (size > cstr->size_allocated) |
||
1551 | cstr_realloc(cstr, size); |
||
1552 | ((unsigned char *)cstr->data)[size - 1] = ch; |
||
1553 | cstr->size = size; |
||
1554 | } |
||
1555 | |||
1556 | static void cstr_cat(CString *cstr, const char *str) |
||
1557 | { |
||
1558 | int c; |
||
1559 | for(;;) { |
||
1560 | c = *str; |
||
1561 | if (c == '\0') |
||
1562 | break; |
||
1563 | cstr_ccat(cstr, c); |
||
1564 | str++; |
||
1565 | } |
||
1566 | } |
||
1567 | |||
1568 | /* add a wide char */ |
||
1569 | static void cstr_wccat(CString *cstr, int ch) |
||
1570 | { |
||
1571 | int size; |
||
1572 | size = cstr->size + sizeof(int); |
||
1573 | if (size > cstr->size_allocated) |
||
1574 | cstr_realloc(cstr, size); |
||
1575 | *(int *)(((unsigned char *)cstr->data) + size - sizeof(int)) = ch; |
||
1576 | cstr->size = size; |
||
1577 | } |
||
1578 | |||
1579 | static void cstr_new(CString *cstr) |
||
1580 | { |
||
1581 | memset(cstr, 0, sizeof(CString)); |
||
1582 | } |
||
1583 | |||
1584 | /* free string and reset it to NULL */ |
||
1585 | static void cstr_free(CString *cstr) |
||
1586 | { |
||
1587 | tcc_free(cstr->data_allocated); |
||
1588 | cstr_new(cstr); |
||
1589 | } |
||
1590 | |||
1591 | #define cstr_reset(cstr) cstr_free(cstr) |
||
1592 | |||
1593 | /* XXX: unicode ? */ |
||
1594 | static void add_char(CString *cstr, int c) |
||
1595 | { |
||
1596 | if (c == '\'' || c == '\"' || c == '\\') { |
||
1597 | /* XXX: could be more precise if char or string */ |
||
1598 | cstr_ccat(cstr, '\\'); |
||
1599 | } |
||
1600 | if (c >= 32 && c <= 126) { |
||
1601 | cstr_ccat(cstr, c); |
||
1602 | } else { |
||
1603 | cstr_ccat(cstr, '\\'); |
||
1604 | if (c == '\n') { |
||
1605 | cstr_ccat(cstr, 'n'); |
||
1606 | } else { |
||
1607 | cstr_ccat(cstr, '0' + ((c >> 6) & 7)); |
||
1608 | cstr_ccat(cstr, '0' + ((c >> 3) & 7)); |
||
1609 | cstr_ccat(cstr, '0' + (c & 7)); |
||
1610 | } |
||
1611 | } |
||
1612 | } |
||
1613 | |||
1614 | /* XXX: buffer overflow */ |
||
1615 | /* XXX: float tokens */ |
||
1616 | char *get_tok_str(int v, CValue *cv) |
||
1617 | { |
||
1618 | static char buf[STRING_MAX_SIZE + 1]; |
||
1619 | static CString cstr_buf; |
||
1620 | CString *cstr; |
||
1621 | unsigned char *q; |
||
1622 | char *p; |
||
1623 | int i, len; |
||
1624 | |||
1625 | /* NOTE: to go faster, we give a fixed buffer for small strings */ |
||
1626 | cstr_reset(&cstr_buf); |
||
1627 | cstr_buf.data = buf; |
||
1628 | cstr_buf.size_allocated = sizeof(buf); |
||
1629 | p = buf; |
||
1630 | |||
1631 | switch(v) { |
||
1632 | case TOK_CINT: |
||
1633 | case TOK_CUINT: |
||
1634 | /* XXX: not quite exact, but only useful for testing */ |
||
1635 | sprintf(p, "%u", cv->ui); |
||
1636 | break; |
||
1637 | case TOK_CLLONG: |
||
1638 | case TOK_CULLONG: |
||
1639 | /* XXX: not quite exact, but only useful for testing */ |
||
1640 | sprintf(p, "%Lu", cv->ull); |
||
1641 | break; |
||
1642 | case TOK_CCHAR: |
||
1643 | case TOK_LCHAR: |
||
1644 | cstr_ccat(&cstr_buf, '\''); |
||
1645 | add_char(&cstr_buf, cv->i); |
||
1646 | cstr_ccat(&cstr_buf, '\''); |
||
1647 | cstr_ccat(&cstr_buf, '\0'); |
||
1648 | break; |
||
1649 | case TOK_PPNUM: |
||
1650 | cstr = cv->cstr; |
||
1651 | len = cstr->size - 1; |
||
1652 | for(i=0;i |
||
1653 | add_char(&cstr_buf, ((unsigned char *)cstr->data)[i]); |
||
1654 | cstr_ccat(&cstr_buf, '\0'); |
||
1655 | break; |
||
1656 | case TOK_STR: |
||
1657 | case TOK_LSTR: |
||
1658 | cstr = cv->cstr; |
||
1659 | cstr_ccat(&cstr_buf, '\"'); |
||
1660 | if (v == TOK_STR) { |
||
1661 | len = cstr->size - 1; |
||
1662 | for(i=0;i |
||
1663 | add_char(&cstr_buf, ((unsigned char *)cstr->data)[i]); |
||
1664 | } else { |
||
1665 | len = (cstr->size / sizeof(int)) - 1; |
||
1666 | for(i=0;i |
||
1667 | add_char(&cstr_buf, ((int *)cstr->data)[i]); |
||
1668 | } |
||
1669 | cstr_ccat(&cstr_buf, '\"'); |
||
1670 | cstr_ccat(&cstr_buf, '\0'); |
||
1671 | break; |
||
1672 | case TOK_LT: |
||
1673 | v = '<'; |
||
1674 | goto addv; |
||
1675 | case TOK_GT: |
||
1676 | v = '>'; |
||
1677 | goto addv; |
||
1678 | case TOK_A_SHL: |
||
1679 | return strcpy(p, "<<="); |
||
1680 | case TOK_A_SAR: |
||
1681 | return strcpy(p, ">>="); |
||
1682 | default: |
||
1683 | if (v < TOK_IDENT) { |
||
1684 | /* search in two bytes table */ |
||
1685 | q = tok_two_chars; |
||
1686 | while (*q) { |
||
1687 | if (q[2] == v) { |
||
1688 | *p++ = q[0]; |
||
1689 | *p++ = q[1]; |
||
1690 | *p = '\0'; |
||
1691 | return buf; |
||
1692 | } |
||
1693 | q += 3; |
||
1694 | } |
||
1695 | addv: |
||
1696 | *p++ = v; |
||
1697 | *p = '\0'; |
||
1698 | } else if (v < tok_ident) { |
||
1699 | return table_ident[v - TOK_IDENT]->str; |
||
1700 | } else if (v >= SYM_FIRST_ANOM) { |
||
1701 | /* special name for anonymous symbol */ |
||
1702 | sprintf(p, "L.%u", v - SYM_FIRST_ANOM); |
||
1703 | } else { |
||
1704 | /* should never happen */ |
||
1705 | return NULL; |
||
1706 | } |
||
1707 | break; |
||
1708 | } |
||
1709 | return cstr_buf.data; |
||
1710 | } |
||
1711 | |||
1712 | /* push, without hashing */ |
||
1713 | static Sym *sym_push2(Sym **ps, int v, int t, int c) |
||
1714 | { |
||
1715 | Sym *s; |
||
1716 | s = sym_malloc(); |
||
1717 | s->v = v; |
||
1718 | s->type.t = t; |
||
1719 | s->c = c; |
||
1720 | s->next = NULL; |
||
1721 | /* add in stack */ |
||
1722 | s->prev = *ps; |
||
1723 | *ps = s; |
||
1724 | return s; |
||
1725 | } |
||
1726 | |||
1727 | /* find a symbol and return its associated structure. 's' is the top |
||
1728 | of the symbol stack */ |
||
1729 | static Sym *sym_find2(Sym *s, int v) |
||
1730 | { |
||
1731 | while (s) { |
||
1732 | if (s->v == v) |
||
1733 | return s; |
||
1734 | s = s->prev; |
||
1735 | } |
||
1736 | return NULL; |
||
1737 | } |
||
1738 | |||
1739 | /* structure lookup */ |
||
1740 | static inline Sym *struct_find(int v) |
||
1741 | { |
||
1742 | v -= TOK_IDENT; |
||
1743 | if ((unsigned)v >= (unsigned)(tok_ident - TOK_IDENT)) |
||
1744 | return NULL; |
||
1745 | return table_ident[v]->sym_struct; |
||
1746 | } |
||
1747 | |||
1748 | /* find an identifier */ |
||
1749 | static inline Sym *sym_find(int v) |
||
1750 | { |
||
1751 | v -= TOK_IDENT; |
||
1752 | if ((unsigned)v >= (unsigned)(tok_ident - TOK_IDENT)) |
||
1753 | return NULL; |
||
1754 | return table_ident[v]->sym_identifier; |
||
1755 | } |
||
1756 | |||
1757 | /* push a given symbol on the symbol stack */ |
||
1758 | static Sym *sym_push(int v, CType *type, int r, int c) |
||
1759 | { |
||
1760 | Sym *s, **ps; |
||
1761 | TokenSym *ts; |
||
1762 | |||
1763 | if (local_stack) |
||
1764 | ps = &local_stack; |
||
1765 | else |
||
1766 | ps = &global_stack; |
||
1767 | s = sym_push2(ps, v, type->t, c); |
||
1768 | s->type.ref = type->ref; |
||
1769 | s->r = r; |
||
1770 | /* don't record fields or anonymous symbols */ |
||
1771 | /* XXX: simplify */ |
||
1772 | if (!(v & SYM_FIELD) && (v & ~SYM_STRUCT) < SYM_FIRST_ANOM) { |
||
1773 | /* record symbol in token array */ |
||
1774 | ts = table_ident[(v & ~SYM_STRUCT) - TOK_IDENT]; |
||
1775 | if (v & SYM_STRUCT) |
||
1776 | ps = &ts->sym_struct; |
||
1777 | else |
||
1778 | ps = &ts->sym_identifier; |
||
1779 | s->prev_tok = *ps; |
||
1780 | *ps = s; |
||
1781 | } |
||
1782 | return s; |
||
1783 | } |
||
1784 | |||
1785 | /* push a global identifier */ |
||
1786 | static Sym *global_identifier_push(int v, int t, int c) |
||
1787 | { |
||
1788 | Sym *s, **ps; |
||
1789 | s = sym_push2(&global_stack, v, t, c); |
||
1790 | /* don't record anonymous symbol */ |
||
1791 | if (v < SYM_FIRST_ANOM) { |
||
1792 | ps = &table_ident[v - TOK_IDENT]->sym_identifier; |
||
1793 | /* modify the top most local identifier, so that |
||
1794 | sym_identifier will point to 's' when popped */ |
||
1795 | while (*ps != NULL) |
||
1796 | ps = &(*ps)->prev_tok; |
||
1797 | s->prev_tok = NULL; |
||
1798 | *ps = s; |
||
1799 | } |
||
1800 | return s; |
||
1801 | } |
||
1802 | |||
1803 | /* pop symbols until top reaches 'b' */ |
||
1804 | static void sym_pop(Sym **ptop, Sym *b) |
||
1805 | { |
||
1806 | Sym *s, *ss, **ps; |
||
1807 | TokenSym *ts; |
||
1808 | int v; |
||
1809 | |||
1810 | s = *ptop; |
||
1811 | while(s != b) { |
||
1812 | ss = s->prev; |
||
1813 | v = s->v; |
||
1814 | /* remove symbol in token array */ |
||
1815 | /* XXX: simplify */ |
||
1816 | if (!(v & SYM_FIELD) && (v & ~SYM_STRUCT) < SYM_FIRST_ANOM) { |
||
1817 | ts = table_ident[(v & ~SYM_STRUCT) - TOK_IDENT]; |
||
1818 | if (v & SYM_STRUCT) |
||
1819 | ps = &ts->sym_struct; |
||
1820 | else |
||
1821 | ps = &ts->sym_identifier; |
||
1822 | *ps = s->prev_tok; |
||
1823 | } |
||
1824 | sym_free(s); |
||
1825 | s = ss; |
||
1826 | } |
||
1827 | *ptop = b; |
||
1828 | } |
||
1829 | |||
1830 | /* I/O layer */ |
||
1831 | |||
1832 | BufferedFile *tcc_open(TCCState *s1, const char *filename) |
||
1833 | { |
||
1834 | int fd; |
||
1835 | BufferedFile *bf; |
||
1836 | |||
1837 | fd = open(filename, O_RDONLY | O_BINARY); |
||
1838 | if (fd < 0) |
||
1839 | return NULL; |
||
1840 | bf = tcc_malloc(sizeof(BufferedFile)); |
||
1841 | if (!bf) { |
||
1842 | close(fd); |
||
1843 | return NULL; |
||
1844 | } |
||
1845 | bf->fd = fd; |
||
1846 | bf->buf_ptr = bf->buffer; |
||
1847 | bf->buf_end = bf->buffer; |
||
1848 | bf->buffer[0] = CH_EOB; /* put eob symbol */ |
||
1849 | pstrcpy(bf->filename, sizeof(bf->filename), filename); |
||
1850 | bf->line_num = 1; |
||
1851 | bf->ifndef_macro = 0; |
||
1852 | bf->ifdef_stack_ptr = s1->ifdef_stack_ptr; |
||
1853 | // printf("opening '%s'\n", filename); |
||
1854 | return bf; |
||
1855 | } |
||
1856 | |||
1857 | void tcc_close(BufferedFile *bf) |
||
1858 | { |
||
1859 | total_lines += bf->line_num; |
||
1860 | close(bf->fd); |
||
1861 | tcc_free(bf); |
||
1862 | } |
||
1863 | |||
1864 | /* fill input buffer and peek next char */ |
||
1865 | static int tcc_peekc_slow(BufferedFile *bf) |
||
1866 | { |
||
1867 | int len; |
||
1868 | /* only tries to read if really end of buffer */ |
||
1869 | if (bf->buf_ptr >= bf->buf_end) { |
||
1870 | if (bf->fd != -1) { |
||
1871 | #if defined(PARSE_DEBUG) |
||
1872 | len = 8; |
||
1873 | #else |
||
1874 | len = IO_BUF_SIZE; |
||
1875 | #endif |
||
1876 | len = read(bf->fd, bf->buffer, len); |
||
1877 | if (len < 0) |
||
1878 | len = 0; |
||
1879 | } else { |
||
1880 | len = 0; |
||
1881 | } |
||
1882 | total_bytes += len; |
||
1883 | bf->buf_ptr = bf->buffer; |
||
1884 | bf->buf_end = bf->buffer + len; |
||
1885 | *bf->buf_end = CH_EOB; |
||
1886 | } |
||
1887 | if (bf->buf_ptr < bf->buf_end) { |
||
1888 | return bf->buf_ptr[0]; |
||
1889 | } else { |
||
1890 | bf->buf_ptr = bf->buf_end; |
||
1891 | return CH_EOF; |
||
1892 | } |
||
1893 | } |
||
1894 | |||
1895 | /* return the current character, handling end of block if necessary |
||
1896 | (but not stray) */ |
||
1897 | static int handle_eob(void) |
||
1898 | { |
||
1899 | return tcc_peekc_slow(file); |
||
1900 | } |
||
1901 | |||
1902 | /* read next char from current input file and handle end of input buffer */ |
||
609 | andrew_pro | 1903 | static inline void input(void) |
145 | halyavin | 1904 | { |
1905 | ch = *(++(file->buf_ptr)); |
||
1906 | /* end of buffer/file handling */ |
||
1907 | if (ch == CH_EOB) |
||
1908 | ch = handle_eob(); |
||
1909 | } |
||
1910 | |||
1911 | /* handle '\[\r]\n' */ |
||
1912 | static void handle_stray(void) |
||
1913 | { |
||
1914 | while (ch == '\\') { |
||
609 | andrew_pro | 1915 | input(); |
145 | halyavin | 1916 | if (ch == '\n') { |
1917 | file->line_num++; |
||
609 | andrew_pro | 1918 | input(); |
145 | halyavin | 1919 | } else if (ch == '\r') { |
609 | andrew_pro | 1920 | input(); |
145 | halyavin | 1921 | if (ch != '\n') |
1922 | goto fail; |
||
1923 | file->line_num++; |
||
609 | andrew_pro | 1924 | input(); |
145 | halyavin | 1925 | } else { |
1926 | fail: |
||
1927 | error("stray '\\' in program"); |
||
1928 | } |
||
1929 | } |
||
1930 | } |
||
1931 | |||
1932 | /* skip the stray and handle the \\n case. Output an error if |
||
1933 | incorrect char after the stray */ |
||
1934 | static int handle_stray1(uint8_t *p) |
||
1935 | { |
||
1936 | int c; |
||
1937 | |||
1938 | if (p >= file->buf_end) { |
||
1939 | file->buf_ptr = p; |
||
1940 | c = handle_eob(); |
||
1941 | p = file->buf_ptr; |
||
1942 | if (c == '\\') |
||
1943 | goto parse_stray; |
||
1944 | } else { |
||
1945 | parse_stray: |
||
1946 | file->buf_ptr = p; |
||
1947 | ch = *p; |
||
1948 | handle_stray(); |
||
1949 | p = file->buf_ptr; |
||
1950 | c = *p; |
||
1951 | } |
||
1952 | return c; |
||
1953 | } |
||
1954 | |||
1955 | /* handle just the EOB case, but not stray */ |
||
1956 | #define PEEKC_EOB(c, p)\ |
||
1957 | {\ |
||
1958 | p++;\ |
||
1959 | c = *p;\ |
||
1960 | if (c == '\\') {\ |
||
1961 | file->buf_ptr = p;\ |
||
1962 | c = handle_eob();\ |
||
1963 | p = file->buf_ptr;\ |
||
1964 | }\ |
||
1965 | } |
||
1966 | |||
1967 | /* handle the complicated stray case */ |
||
1968 | #define PEEKC(c, p)\ |
||
1969 | {\ |
||
1970 | p++;\ |
||
1971 | c = *p;\ |
||
1972 | if (c == '\\') {\ |
||
1973 | c = handle_stray1(p);\ |
||
1974 | p = file->buf_ptr;\ |
||
1975 | }\ |
||
1976 | } |
||
1977 | |||
1978 | /* input with '\[\r]\n' handling. Note that this function cannot |
||
1979 | handle other characters after '\', so you cannot call it inside |
||
1980 | strings or comments */ |
||
1981 | static void minp(void) |
||
1982 | { |
||
609 | andrew_pro | 1983 | input(); |
145 | halyavin | 1984 | if (ch == '\\') |
1985 | handle_stray(); |
||
1986 | } |
||
1987 | |||
1988 | |||
1989 | /* single line C++ comments */ |
||
1990 | static uint8_t *parse_line_comment(uint8_t *p) |
||
1991 | { |
||
1992 | int c; |
||
1993 | |||
1994 | p++; |
||
1995 | for(;;) { |
||
1996 | c = *p; |
||
1997 | redo: |
||
1998 | if (c == '\n' || c == CH_EOF) { |
||
1999 | break; |
||
2000 | } else if (c == '\\') { |
||
2001 | file->buf_ptr = p; |
||
2002 | c = handle_eob(); |
||
2003 | p = file->buf_ptr; |
||
2004 | if (c == '\\') { |
||
2005 | PEEKC_EOB(c, p); |
||
2006 | if (c == '\n') { |
||
2007 | file->line_num++; |
||
2008 | PEEKC_EOB(c, p); |
||
2009 | } else if (c == '\r') { |
||
2010 | PEEKC_EOB(c, p); |
||
2011 | if (c == '\n') { |
||
2012 | file->line_num++; |
||
2013 | PEEKC_EOB(c, p); |
||
2014 | } |
||
2015 | } |
||
2016 | } else { |
||
2017 | goto redo; |
||
2018 | } |
||
2019 | } else { |
||
2020 | p++; |
||
2021 | } |
||
2022 | } |
||
2023 | return p; |
||
2024 | } |
||
2025 | |||
2026 | /* C comments */ |
||
2027 | static uint8_t *parse_comment(uint8_t *p) |
||
2028 | { |
||
2029 | int c; |
||
2030 | |||
2031 | p++; |
||
2032 | for(;;) { |
||
2033 | /* fast skip loop */ |
||
2034 | for(;;) { |
||
2035 | c = *p; |
||
2036 | if (c == '\n' || c == '*' || c == '\\') |
||
2037 | break; |
||
2038 | p++; |
||
2039 | c = *p; |
||
2040 | if (c == '\n' || c == '*' || c == '\\') |
||
2041 | break; |
||
2042 | p++; |
||
2043 | } |
||
2044 | /* now we can handle all the cases */ |
||
2045 | if (c == '\n') { |
||
2046 | file->line_num++; |
||
2047 | p++; |
||
2048 | } else if (c == '*') { |
||
2049 | p++; |
||
2050 | for(;;) { |
||
2051 | c = *p; |
||
2052 | if (c == '*') { |
||
2053 | p++; |
||
2054 | } else if (c == '/') { |
||
2055 | goto end_of_comment; |
||
2056 | } else if (c == '\\') { |
||
2057 | file->buf_ptr = p; |
||
2058 | c = handle_eob(); |
||
2059 | p = file->buf_ptr; |
||
2060 | if (c == '\\') { |
||
2061 | /* skip '\[\r]\n', otherwise just skip the stray */ |
||
2062 | while (c == '\\') { |
||
2063 | PEEKC_EOB(c, p); |
||
2064 | if (c == '\n') { |
||
2065 | file->line_num++; |
||
2066 | PEEKC_EOB(c, p); |
||
2067 | } else if (c == '\r') { |
||
2068 | PEEKC_EOB(c, p); |
||
2069 | if (c == '\n') { |
||
2070 | file->line_num++; |
||
2071 | PEEKC_EOB(c, p); |
||
2072 | } |
||
2073 | } else { |
||
2074 | goto after_star; |
||
2075 | } |
||
2076 | } |
||
2077 | } |
||
2078 | } else { |
||
2079 | break; |
||
2080 | } |
||
2081 | } |
||
2082 | after_star: ; |
||
2083 | } else { |
||
2084 | /* stray, eob or eof */ |
||
2085 | file->buf_ptr = p; |
||
2086 | c = handle_eob(); |
||
2087 | p = file->buf_ptr; |
||
2088 | if (c == CH_EOF) { |
||
2089 | error("unexpected end of file in comment"); |
||
2090 | } else if (c == '\\') { |
||
2091 | p++; |
||
2092 | } |
||
2093 | } |
||
2094 | } |
||
2095 | end_of_comment: |
||
2096 | p++; |
||
2097 | return p; |
||
2098 | } |
||
2099 | |||
2100 | #define cinp minp |
||
2101 | |||
2102 | /* space excluding newline */ |
||
2103 | static inline int is_space(int ch) |
||
2104 | { |
||
2105 | return ch == ' ' || ch == '\t' || ch == '\v' || ch == '\f' || ch == '\r'; |
||
2106 | } |
||
2107 | |||
2108 | static inline void skip_spaces(void) |
||
2109 | { |
||
2110 | while (is_space(ch)) |
||
2111 | cinp(); |
||
2112 | } |
||
2113 | |||
2114 | /* parse a string without interpreting escapes */ |
||
2115 | static uint8_t *parse_pp_string(uint8_t *p, |
||
2116 | int sep, CString *str) |
||
2117 | { |
||
2118 | int c; |
||
2119 | p++; |
||
2120 | for(;;) { |
||
2121 | c = *p; |
||
2122 | if (c == sep) { |
||
2123 | break; |
||
2124 | } else if (c == '\\') { |
||
2125 | file->buf_ptr = p; |
||
2126 | c = handle_eob(); |
||
2127 | p = file->buf_ptr; |
||
2128 | if (c == CH_EOF) { |
||
2129 | unterminated_string: |
||
2130 | /* XXX: indicate line number of start of string */ |
||
2131 | error("missing terminating %c character", sep); |
||
2132 | } else if (c == '\\') { |
||
2133 | /* escape : just skip \[\r]\n */ |
||
2134 | PEEKC_EOB(c, p); |
||
2135 | if (c == '\n') { |
||
2136 | file->line_num++; |
||
2137 | p++; |
||
2138 | } else if (c == '\r') { |
||
2139 | PEEKC_EOB(c, p); |
||
2140 | if (c != '\n') |
||
2141 | expect("'\n' after '\r'"); |
||
2142 | file->line_num++; |
||
2143 | p++; |
||
2144 | } else if (c == CH_EOF) { |
||
2145 | goto unterminated_string; |
||
2146 | } else { |
||
2147 | if (str) { |
||
2148 | cstr_ccat(str, '\\'); |
||
2149 | cstr_ccat(str, c); |
||
2150 | } |
||
2151 | p++; |
||
2152 | } |
||
2153 | } |
||
2154 | } else if (c == '\n') { |
||
2155 | file->line_num++; |
||
2156 | goto add_char; |
||
2157 | } else if (c == '\r') { |
||
2158 | PEEKC_EOB(c, p); |
||
2159 | if (c != '\n') { |
||
2160 | if (str) |
||
2161 | cstr_ccat(str, '\r'); |
||
2162 | } else { |
||
2163 | file->line_num++; |
||
2164 | goto add_char; |
||
2165 | } |
||
2166 | } else { |
||
2167 | add_char: |
||
2168 | if (str) |
||
2169 | cstr_ccat(str, c); |
||
2170 | p++; |
||
2171 | } |
||
2172 | } |
||
2173 | p++; |
||
2174 | return p; |
||
2175 | } |
||
2176 | |||
2177 | /* skip block of text until #else, #elif or #endif. skip also pairs of |
||
2178 | #if/#endif */ |
||
2179 | void preprocess_skip(void) |
||
2180 | { |
||
2181 | int a, start_of_line, c; |
||
2182 | uint8_t *p; |
||
2183 | |||
2184 | p = file->buf_ptr; |
||
2185 | start_of_line = 1; |
||
2186 | a = 0; |
||
2187 | for(;;) { |
||
2188 | redo_no_start: |
||
2189 | c = *p; |
||
2190 | switch(c) { |
||
2191 | case ' ': |
||
2192 | case '\t': |
||
2193 | case '\f': |
||
2194 | case '\v': |
||
2195 | case '\r': |
||
2196 | p++; |
||
2197 | goto redo_no_start; |
||
2198 | case '\n': |
||
2199 | start_of_line = 1; |
||
2200 | file->line_num++; |
||
2201 | p++; |
||
2202 | goto redo_no_start; |
||
2203 | case '\\': |
||
2204 | file->buf_ptr = p; |
||
2205 | c = handle_eob(); |
||
2206 | if (c == CH_EOF) { |
||
2207 | expect("#endif"); |
||
2208 | } else if (c == '\\') { |
||
2209 | /* XXX: incorrect: should not give an error */ |
||
2210 | ch = file->buf_ptr[0]; |
||
2211 | handle_stray(); |
||
2212 | } |
||
2213 | p = file->buf_ptr; |
||
2214 | goto redo_no_start; |
||
2215 | /* skip strings */ |
||
2216 | case '\"': |
||
2217 | case '\'': |
||
2218 | p = parse_pp_string(p, c, NULL); |
||
2219 | break; |
||
2220 | /* skip comments */ |
||
2221 | case '/': |
||
2222 | file->buf_ptr = p; |
||
2223 | ch = *p; |
||
2224 | minp(); |
||
2225 | p = file->buf_ptr; |
||
2226 | if (ch == '*') { |
||
2227 | p = parse_comment(p); |
||
2228 | } else if (ch == '/') { |
||
2229 | p = parse_line_comment(p); |
||
2230 | } |
||
2231 | break; |
||
2232 | |||
2233 | case '#': |
||
2234 | p++; |
||
2235 | if (start_of_line) { |
||
2236 | file->buf_ptr = p; |
||
2237 | next_nomacro(); |
||
2238 | p = file->buf_ptr; |
||
2239 | if (a == 0 && |
||
2240 | (tok == TOK_ELSE || tok == TOK_ELIF || tok == TOK_ENDIF)) |
||
2241 | goto the_end; |
||
2242 | if (tok == TOK_IF || tok == TOK_IFDEF || tok == TOK_IFNDEF) |
||
2243 | a++; |
||
2244 | else if (tok == TOK_ENDIF) |
||
2245 | a--; |
||
2246 | } |
||
2247 | break; |
||
2248 | default: |
||
2249 | p++; |
||
2250 | break; |
||
2251 | } |
||
2252 | start_of_line = 0; |
||
2253 | } |
||
2254 | the_end: ; |
||
2255 | file->buf_ptr = p; |
||
2256 | } |
||
2257 | |||
2258 | /* ParseState handling */ |
||
2259 | |||
2260 | /* XXX: currently, no include file info is stored. Thus, we cannot display |
||
2261 | accurate messages if the function or data definition spans multiple |
||
2262 | files */ |
||
2263 | |||
2264 | /* save current parse state in 's' */ |
||
2265 | void save_parse_state(ParseState *s) |
||
2266 | { |
||
2267 | s->line_num = file->line_num; |
||
2268 | s->macro_ptr = macro_ptr; |
||
2269 | s->tok = tok; |
||
2270 | s->tokc = tokc; |
||
2271 | } |
||
2272 | |||
2273 | /* restore parse state from 's' */ |
||
2274 | void restore_parse_state(ParseState *s) |
||
2275 | { |
||
2276 | file->line_num = s->line_num; |
||
2277 | macro_ptr = s->macro_ptr; |
||
2278 | tok = s->tok; |
||
2279 | tokc = s->tokc; |
||
2280 | } |
||
2281 | |||
2282 | /* return the number of additional 'ints' necessary to store the |
||
2283 | token */ |
||
2284 | static inline int tok_ext_size(int t) |
||
2285 | { |
||
2286 | switch(t) { |
||
2287 | /* 4 bytes */ |
||
2288 | case TOK_CINT: |
||
2289 | case TOK_CUINT: |
||
2290 | case TOK_CCHAR: |
||
2291 | case TOK_LCHAR: |
||
2292 | case TOK_CFLOAT: |
||
2293 | case TOK_LINENUM: |
||
2294 | return 1; |
||
2295 | case TOK_STR: |
||
2296 | case TOK_LSTR: |
||
2297 | case TOK_PPNUM: |
||
2298 | error("unsupported token"); |
||
2299 | return 1; |
||
2300 | case TOK_CDOUBLE: |
||
2301 | case TOK_CLLONG: |
||
2302 | case TOK_CULLONG: |
||
2303 | return 2; |
||
2304 | case TOK_CLDOUBLE: |
||
2305 | return LDOUBLE_SIZE / 4; |
||
2306 | default: |
||
2307 | return 0; |
||
2308 | } |
||
2309 | } |
||
2310 | |||
2311 | /* token string handling */ |
||
2312 | |||
2313 | static inline void tok_str_new(TokenString *s) |
||
2314 | { |
||
2315 | s->str = NULL; |
||
2316 | s->len = 0; |
||
2317 | s->allocated_len = 0; |
||
2318 | s->last_line_num = -1; |
||
2319 | } |
||
2320 | |||
2321 | static void tok_str_free(int *str) |
||
2322 | { |
||
2323 | tcc_free(str); |
||
2324 | } |
||
2325 | |||
2326 | static int *tok_str_realloc(TokenString *s) |
||
2327 | { |
||
2328 | int *str, len; |
||
2329 | |||
2330 | if (s->allocated_len == 0) { |
||
2331 | len = 8; |
||
2332 | } else { |
||
2333 | len = s->allocated_len * 2; |
||
2334 | } |
||
2335 | str = tcc_realloc(s->str, len * sizeof(int)); |
||
2336 | if (!str) |
||
2337 | error("memory full"); |
||
2338 | s->allocated_len = len; |
||
2339 | s->str = str; |
||
2340 | return str; |
||
2341 | } |
||
2342 | |||
2343 | static void tok_str_add(TokenString *s, int t) |
||
2344 | { |
||
2345 | int len, *str; |
||
2346 | |||
2347 | len = s->len; |
||
2348 | str = s->str; |
||
2349 | if (len >= s->allocated_len) |
||
2350 | str = tok_str_realloc(s); |
||
2351 | str[len++] = t; |
||
2352 | s->len = len; |
||
2353 | } |
||
2354 | |||
2355 | static void tok_str_add2(TokenString *s, int t, CValue *cv) |
||
2356 | { |
||
2357 | int len, *str; |
||
2358 | |||
2359 | len = s->len; |
||
2360 | str = s->str; |
||
2361 | |||
2362 | /* allocate space for worst case */ |
||
2363 | if (len + TOK_MAX_SIZE > s->allocated_len) |
||
2364 | str = tok_str_realloc(s); |
||
2365 | str[len++] = t; |
||
2366 | switch(t) { |
||
2367 | case TOK_CINT: |
||
2368 | case TOK_CUINT: |
||
2369 | case TOK_CCHAR: |
||
2370 | case TOK_LCHAR: |
||
2371 | case TOK_CFLOAT: |
||
2372 | case TOK_LINENUM: |
||
2373 | str[len++] = cv->tab[0]; |
||
2374 | break; |
||
2375 | case TOK_PPNUM: |
||
2376 | case TOK_STR: |
||
2377 | case TOK_LSTR: |
||
2378 | { |
||
2379 | int nb_words; |
||
2380 | CString *cstr; |
||
2381 | |||
2382 | nb_words = (sizeof(CString) + cv->cstr->size + 3) >> 2; |
||
2383 | while ((len + nb_words) > s->allocated_len) |
||
2384 | str = tok_str_realloc(s); |
||
2385 | cstr = (CString *)(str + len); |
||
2386 | cstr->data = NULL; |
||
2387 | cstr->size = cv->cstr->size; |
||
2388 | cstr->data_allocated = NULL; |
||
2389 | cstr->size_allocated = cstr->size; |
||
2390 | memcpy((char *)cstr + sizeof(CString), |
||
2391 | cv->cstr->data, cstr->size); |
||
2392 | len += nb_words; |
||
2393 | } |
||
2394 | break; |
||
2395 | case TOK_CDOUBLE: |
||
2396 | case TOK_CLLONG: |
||
2397 | case TOK_CULLONG: |
||
2398 | #if LDOUBLE_SIZE == 8 |
||
2399 | case TOK_CLDOUBLE: |
||
2400 | #endif |
||
2401 | str[len++] = cv->tab[0]; |
||
2402 | str[len++] = cv->tab[1]; |
||
2403 | break; |
||
2404 | #if LDOUBLE_SIZE == 12 |
||
2405 | case TOK_CLDOUBLE: |
||
2406 | str[len++] = cv->tab[0]; |
||
2407 | str[len++] = cv->tab[1]; |
||
2408 | str[len++] = cv->tab[2]; |
||
2409 | #elif LDOUBLE_SIZE != 8 |
||
2410 | #error add long double size support |
||
2411 | #endif |
||
2412 | break; |
||
2413 | default: |
||
2414 | break; |
||
2415 | } |
||
2416 | s->len = len; |
||
2417 | } |
||
2418 | |||
2419 | /* add the current parse token in token string 's' */ |
||
2420 | static void tok_str_add_tok(TokenString *s) |
||
2421 | { |
||
2422 | CValue cval; |
||
2423 | |||
2424 | /* save line number info */ |
||
2425 | if (file->line_num != s->last_line_num) { |
||
2426 | s->last_line_num = file->line_num; |
||
2427 | cval.i = s->last_line_num; |
||
2428 | tok_str_add2(s, TOK_LINENUM, &cval); |
||
2429 | } |
||
2430 | tok_str_add2(s, tok, &tokc); |
||
2431 | } |
||
2432 | |||
2433 | #if LDOUBLE_SIZE == 12 |
||
2434 | #define LDOUBLE_GET(p, cv) \ |
||
2435 | cv.tab[0] = p[0]; \ |
||
2436 | cv.tab[1] = p[1]; \ |
||
2437 | cv.tab[2] = p[2]; |
||
2438 | #elif LDOUBLE_SIZE == 8 |
||
2439 | #define LDOUBLE_GET(p, cv) \ |
||
2440 | cv.tab[0] = p[0]; \ |
||
2441 | cv.tab[1] = p[1]; |
||
2442 | #else |
||
2443 | #error add long double size support |
||
2444 | #endif |
||
2445 | |||
2446 | |||
2447 | /* get a token from an integer array and increment pointer |
||
2448 | accordingly. we code it as a macro to avoid pointer aliasing. */ |
||
2449 | #define TOK_GET(t, p, cv) \ |
||
2450 | { \ |
||
2451 | t = *p++; \ |
||
2452 | switch(t) { \ |
||
2453 | case TOK_CINT: \ |
||
2454 | case TOK_CUINT: \ |
||
2455 | case TOK_CCHAR: \ |
||
2456 | case TOK_LCHAR: \ |
||
2457 | case TOK_CFLOAT: \ |
||
2458 | case TOK_LINENUM: \ |
||
2459 | cv.tab[0] = *p++; \ |
||
2460 | break; \ |
||
2461 | case TOK_STR: \ |
||
2462 | case TOK_LSTR: \ |
||
2463 | case TOK_PPNUM: \ |
||
2464 | cv.cstr = (CString *)p; \ |
||
2465 | cv.cstr->data = (char *)p + sizeof(CString);\ |
||
2466 | p += (sizeof(CString) + cv.cstr->size + 3) >> 2;\ |
||
2467 | break; \ |
||
2468 | case TOK_CDOUBLE: \ |
||
2469 | case TOK_CLLONG: \ |
||
2470 | case TOK_CULLONG: \ |
||
2471 | cv.tab[0] = p[0]; \ |
||
2472 | cv.tab[1] = p[1]; \ |
||
2473 | p += 2; \ |
||
2474 | break; \ |
||
2475 | case TOK_CLDOUBLE: \ |
||
2476 | LDOUBLE_GET(p, cv); \ |
||
2477 | p += LDOUBLE_SIZE / 4; \ |
||
2478 | break; \ |
||
2479 | default: \ |
||
2480 | break; \ |
||
2481 | } \ |
||
2482 | } |
||
2483 | |||
2484 | /* defines handling */ |
||
2485 | static inline void define_push(int v, int macro_type, int *str, Sym *first_arg) |
||
2486 | { |
||
2487 | Sym *s; |
||
2488 | |||
2489 | s = sym_push2(&define_stack, v, macro_type, (int)str); |
||
2490 | s->next = first_arg; |
||
2491 | table_ident[v - TOK_IDENT]->sym_define = s; |
||
2492 | } |
||
2493 | |||
2494 | /* undefined a define symbol. Its name is just set to zero */ |
||
2495 | static void define_undef(Sym *s) |
||
2496 | { |
||
2497 | int v; |
||
2498 | v = s->v; |
||
2499 | if (v >= TOK_IDENT && v < tok_ident) |
||
2500 | table_ident[v - TOK_IDENT]->sym_define = NULL; |
||
2501 | s->v = 0; |
||
2502 | } |
||
2503 | |||
2504 | static inline Sym *define_find(int v) |
||
2505 | { |
||
2506 | v -= TOK_IDENT; |
||
2507 | if ((unsigned)v >= (unsigned)(tok_ident - TOK_IDENT)) |
||
2508 | return NULL; |
||
2509 | return table_ident[v]->sym_define; |
||
2510 | } |
||
2511 | |||
2512 | /* free define stack until top reaches 'b' */ |
||
2513 | static void free_defines(Sym *b) |
||
2514 | { |
||
2515 | Sym *top, *top1; |
||
2516 | int v; |
||
2517 | |||
2518 | top = define_stack; |
||
2519 | while (top != b) { |
||
2520 | top1 = top->prev; |
||
2521 | /* do not free args or predefined defines */ |
||
2522 | if (top->c) |
||
2523 | tok_str_free((int *)top->c); |
||
2524 | v = top->v; |
||
2525 | if (v >= TOK_IDENT && v < tok_ident) |
||
2526 | table_ident[v - TOK_IDENT]->sym_define = NULL; |
||
2527 | sym_free(top); |
||
2528 | top = top1; |
||
2529 | } |
||
2530 | define_stack = b; |
||
2531 | } |
||
2532 | |||
2533 | /* label lookup */ |
||
2534 | static Sym *label_find(int v) |
||
2535 | { |
||
2536 | v -= TOK_IDENT; |
||
2537 | if ((unsigned)v >= (unsigned)(tok_ident - TOK_IDENT)) |
||
2538 | return NULL; |
||
2539 | return table_ident[v]->sym_label; |
||
2540 | } |
||
2541 | |||
2542 | static Sym *label_push(Sym **ptop, int v, int flags) |
||
2543 | { |
||
2544 | Sym *s, **ps; |
||
2545 | s = sym_push2(ptop, v, 0, 0); |
||
2546 | s->r = flags; |
||
2547 | ps = &table_ident[v - TOK_IDENT]->sym_label; |
||
2548 | if (ptop == &global_label_stack) { |
||
2549 | /* modify the top most local identifier, so that |
||
2550 | sym_identifier will point to 's' when popped */ |
||
2551 | while (*ps != NULL) |
||
2552 | ps = &(*ps)->prev_tok; |
||
2553 | } |
||
2554 | s->prev_tok = *ps; |
||
2555 | *ps = s; |
||
2556 | return s; |
||
2557 | } |
||
2558 | |||
2559 | /* pop labels until element last is reached. Look if any labels are |
||
2560 | undefined. Define symbols if '&&label' was used. */ |
||
2561 | static void label_pop(Sym **ptop, Sym *slast) |
||
2562 | { |
||
2563 | Sym *s, *s1; |
||
2564 | for(s = *ptop; s != slast; s = s1) { |
||
2565 | s1 = s->prev; |
||
2566 | if (s->r == LABEL_DECLARED) { |
||
2567 | warning("label '%s' declared but not used", get_tok_str(s->v, NULL)); |
||
2568 | } else if (s->r == LABEL_FORWARD) { |
||
2569 | error("label '%s' used but not defined", |
||
2570 | get_tok_str(s->v, NULL)); |
||
2571 | } else { |
||
2572 | if (s->c) { |
||
2573 | /* define corresponding symbol. A size of |
||
2574 | 1 is put. */ |
||
2575 | put_extern_sym(s, cur_text_section, (long)s->next, 1); |
||
2576 | } |
||
2577 | } |
||
2578 | /* remove label */ |
||
2579 | table_ident[s->v - TOK_IDENT]->sym_label = s->prev_tok; |
||
2580 | sym_free(s); |
||
2581 | } |
||
2582 | *ptop = slast; |
||
2583 | } |
||
2584 | |||
2585 | /* eval an expression for #if/#elif */ |
||
2586 | static int expr_preprocess(void) |
||
2587 | { |
||
2588 | int c, t; |
||
2589 | TokenString str; |
||
2590 | |||
2591 | tok_str_new(&str); |
||
2592 | while (tok != TOK_LINEFEED && tok != TOK_EOF) { |
||
2593 | next(); /* do macro subst */ |
||
2594 | if (tok == TOK_DEFINED) { |
||
2595 | next_nomacro(); |
||
2596 | t = tok; |
||
2597 | if (t == '(') |
||
2598 | next_nomacro(); |
||
2599 | c = define_find(tok) != 0; |
||
2600 | if (t == '(') |
||
2601 | next_nomacro(); |
||
2602 | tok = TOK_CINT; |
||
2603 | tokc.i = c; |
||
2604 | } else if (tok >= TOK_IDENT) { |
||
2605 | /* if undefined macro */ |
||
2606 | tok = TOK_CINT; |
||
2607 | tokc.i = 0; |
||
2608 | } |
||
2609 | tok_str_add_tok(&str); |
||
2610 | } |
||
2611 | tok_str_add(&str, -1); /* simulate end of file */ |
||
2612 | tok_str_add(&str, 0); |
||
2613 | /* now evaluate C constant expression */ |
||
2614 | macro_ptr = str.str; |
||
2615 | next(); |
||
2616 | c = expr_const(); |
||
2617 | macro_ptr = NULL; |
||
2618 | tok_str_free(str.str); |
||
2619 | return c != 0; |
||
2620 | } |
||
2621 | |||
2622 | #if defined(PARSE_DEBUG) || defined(PP_DEBUG) |
||
2623 | static void tok_print(int *str) |
||
2624 | { |
||
2625 | int t; |
||
2626 | CValue cval; |
||
2627 | |||
2628 | while (1) { |
||
2629 | TOK_GET(t, str, cval); |
||
2630 | if (!t) |
||
2631 | break; |
||
2632 | printf(" %s", get_tok_str(t, &cval)); |
||
2633 | } |
||
2634 | printf("\n"); |
||
2635 | } |
||
2636 | #endif |
||
2637 | |||
2638 | /* parse after #define */ |
||
2639 | static void parse_define(void) |
||
2640 | { |
||
2641 | Sym *s, *first, **ps; |
||
2642 | int v, t, varg, is_vaargs, c; |
||
2643 | TokenString str; |
||
2644 | |||
2645 | v = tok; |
||
2646 | if (v < TOK_IDENT) |
||
2647 | error("invalid macro name '%s'", get_tok_str(tok, &tokc)); |
||
2648 | /* XXX: should check if same macro (ANSI) */ |
||
2649 | first = NULL; |
||
2650 | t = MACRO_OBJ; |
||
2651 | /* '(' must be just after macro definition for MACRO_FUNC */ |
||
2652 | c = file->buf_ptr[0]; |
||
2653 | if (c == '\\') |
||
2654 | c = handle_stray1(file->buf_ptr); |
||
2655 | if (c == '(') { |
||
2656 | next_nomacro(); |
||
2657 | next_nomacro(); |
||
2658 | ps = &first; |
||
2659 | while (tok != ')') { |
||
2660 | varg = tok; |
||
2661 | next_nomacro(); |
||
2662 | is_vaargs = 0; |
||
2663 | if (varg == TOK_DOTS) { |
||
2664 | varg = TOK___VA_ARGS__; |
||
2665 | is_vaargs = 1; |
||
2666 | } else if (tok == TOK_DOTS && gnu_ext) { |
||
2667 | is_vaargs = 1; |
||
2668 | next_nomacro(); |
||
2669 | } |
||
2670 | if (varg < TOK_IDENT) |
||
2671 | error("badly punctuated parameter list"); |
||
2672 | s = sym_push2(&define_stack, varg | SYM_FIELD, is_vaargs, 0); |
||
2673 | *ps = s; |
||
2674 | ps = &s->next; |
||
2675 | if (tok != ',') |
||
2676 | break; |
||
2677 | next_nomacro(); |
||
2678 | } |
||
2679 | t = MACRO_FUNC; |
||
2680 | } |
||
2681 | tok_str_new(&str); |
||
2682 | next_nomacro(); |
||
2683 | /* EOF testing necessary for '-D' handling */ |
||
2684 | while (tok != TOK_LINEFEED && tok != TOK_EOF) { |
||
2685 | tok_str_add2(&str, tok, &tokc); |
||
2686 | next_nomacro(); |
||
2687 | } |
||
2688 | tok_str_add(&str, 0); |
||
2689 | #ifdef PP_DEBUG |
||
2690 | printf("define %s %d: ", get_tok_str(v, NULL), t); |
||
2691 | tok_print(str.str); |
||
2692 | #endif |
||
2693 | define_push(v, t, str.str, first); |
||
2694 | } |
||
2695 | |||
2696 | static inline int hash_cached_include(int type, const char *filename) |
||
2697 | { |
||
2698 | const unsigned char *s; |
||
2699 | unsigned int h; |
||
2700 | |||
2701 | h = TOK_HASH_INIT; |
||
2702 | h = TOK_HASH_FUNC(h, type); |
||
2703 | s = filename; |
||
2704 | while (*s) { |
||
2705 | h = TOK_HASH_FUNC(h, *s); |
||
2706 | s++; |
||
2707 | } |
||
2708 | h &= (CACHED_INCLUDES_HASH_SIZE - 1); |
||
2709 | return h; |
||
2710 | } |
||
2711 | |||
2712 | /* XXX: use a token or a hash table to accelerate matching ? */ |
||
2713 | static CachedInclude *search_cached_include(TCCState *s1, |
||
2714 | int type, const char *filename) |
||
2715 | { |
||
2716 | CachedInclude *e; |
||
2717 | int i, h; |
||
2718 | h = hash_cached_include(type, filename); |
||
2719 | i = s1->cached_includes_hash[h]; |
||
2720 | for(;;) { |
||
2721 | if (i == 0) |
||
2722 | break; |
||
2723 | e = s1->cached_includes[i - 1]; |
||
2724 | if (e->type == type && !strcmp(e->filename, filename)) |
||
2725 | return e; |
||
2726 | i = e->hash_next; |
||
2727 | } |
||
2728 | return NULL; |
||
2729 | } |
||
2730 | |||
2731 | static inline void add_cached_include(TCCState *s1, int type, |
||
2732 | const char *filename, int ifndef_macro) |
||
2733 | { |
||
2734 | CachedInclude *e; |
||
2735 | int h; |
||
2736 | |||
2737 | if (search_cached_include(s1, type, filename)) |
||
2738 | return; |
||
2739 | #ifdef INC_DEBUG |
||
2740 | printf("adding cached '%s' %s\n", filename, get_tok_str(ifndef_macro, NULL)); |
||
2741 | #endif |
||
2742 | e = tcc_malloc(sizeof(CachedInclude) + strlen(filename)); |
||
2743 | if (!e) |
||
2744 | return; |
||
2745 | e->type = type; |
||
2746 | strcpy(e->filename, filename); |
||
2747 | e->ifndef_macro = ifndef_macro; |
||
2748 | dynarray_add((void ***)&s1->cached_includes, &s1->nb_cached_includes, e); |
||
2749 | /* add in hash table */ |
||
2750 | h = hash_cached_include(type, filename); |
||
2751 | e->hash_next = s1->cached_includes_hash[h]; |
||
2752 | s1->cached_includes_hash[h] = s1->nb_cached_includes; |
||
2753 | } |
||
2754 | |||
2755 | static void pragma_parse(TCCState *s1) |
||
2756 | { |
||
2757 | int val; |
||
2758 | |||
2759 | next(); |
||
2760 | if (tok == TOK_pack) { |
||
2761 | /* |
||
2762 | This may be: |
||
2763 | #pragma pack(1) // set |
||
2764 | #pragma pack() // reset to default |
||
2765 | #pragma pack(push,1) // push & set |
||
2766 | #pragma pack(pop) // restore previous |
||
2767 | */ |
||
2768 | next(); |
||
2769 | skip('('); |
||
2770 | if (tok == TOK_ASM_pop) { |
||
2771 | next(); |
||
2772 | if (s1->pack_stack_ptr <= s1->pack_stack) { |
||
2773 | stk_error: |
||
2774 | error("out of pack stack"); |
||
2775 | } |
||
2776 | s1->pack_stack_ptr--; |
||
2777 | } else { |
||
2778 | val = 0; |
||
2779 | if (tok != ')') { |
||
2780 | if (tok == TOK_ASM_push) { |
||
2781 | next(); |
||
2782 | if (s1->pack_stack_ptr >= s1->pack_stack + PACK_STACK_SIZE - 1) |
||
2783 | goto stk_error; |
||
2784 | s1->pack_stack_ptr++; |
||
2785 | skip(','); |
||
2786 | } |
||
2787 | if (tok != TOK_CINT) { |
||
2788 | pack_error: |
||
2789 | error("invalid pack pragma"); |
||
2790 | } |
||
2791 | val = tokc.i; |
||
2792 | if (val < 1 || val > 16 || (val & (val - 1)) != 0) |
||
2793 | goto pack_error; |
||
2794 | next(); |
||
2795 | } |
||
2796 | *s1->pack_stack_ptr = val; |
||
2797 | skip(')'); |
||
2798 | } |
||
2799 | } |
||
2800 | } |
||
2801 | |||
2802 | /* is_bof is true if first non space token at beginning of file */ |
||
2803 | static void preprocess(int is_bof) |
||
2804 | { |
||
2805 | TCCState *s1 = tcc_state; |
||
2806 | int size, i, c, n, saved_parse_flags; |
||
2807 | char buf[1024], *q, *p; |
||
2808 | char buf1[1024]; |
||
2809 | BufferedFile *f; |
||
2810 | Sym *s; |
||
2811 | CachedInclude *e; |
||
2812 | |||
2813 | saved_parse_flags = parse_flags; |
||
2814 | parse_flags = PARSE_FLAG_PREPROCESS | PARSE_FLAG_TOK_NUM | |
||
2815 | PARSE_FLAG_LINEFEED; |
||
2816 | next_nomacro(); |
||
2817 | redo: |
||
2818 | switch(tok) { |
||
2819 | case TOK_DEFINE: |
||
2820 | next_nomacro(); |
||
2821 | parse_define(); |
||
2822 | break; |
||
2823 | case TOK_UNDEF: |
||
2824 | next_nomacro(); |
||
2825 | s = define_find(tok); |
||
2826 | /* undefine symbol by putting an invalid name */ |
||
2827 | if (s) |
||
2828 | define_undef(s); |
||
2829 | break; |
||
2830 | case TOK_INCLUDE: |
||
2831 | case TOK_INCLUDE_NEXT: |
||
2832 | ch = file->buf_ptr[0]; |
||
2833 | /* XXX: incorrect if comments : use next_nomacro with a special mode */ |
||
2834 | skip_spaces(); |
||
2835 | if (ch == '<') { |
||
2836 | c = '>'; |
||
2837 | goto read_name; |
||
2838 | } else if (ch == '\"') { |
||
2839 | c = ch; |
||
2840 | read_name: |
||
2841 | /* XXX: better stray handling */ |
||
2842 | minp(); |
||
2843 | q = buf; |
||
2844 | while (ch != c && ch != '\n' && ch != CH_EOF) { |
||
2845 | if ((q - buf) < sizeof(buf) - 1) |
||
2846 | *q++ = ch; |
||
2847 | minp(); |
||
2848 | } |
||
2849 | *q = '\0'; |
||
2850 | minp(); |
||
2851 | #if 0 |
||
2852 | /* eat all spaces and comments after include */ |
||
2853 | /* XXX: slightly incorrect */ |
||
2854 | while (ch1 != '\n' && ch1 != CH_EOF) |
||
609 | andrew_pro | 2855 | input(); |
145 | halyavin | 2856 | #endif |
2857 | } else { |
||
2858 | /* computed #include : either we have only strings or |
||
2859 | we have anything enclosed in '<>' */ |
||
2860 | next(); |
||
2861 | buf[0] = '\0'; |
||
2862 | if (tok == TOK_STR) { |
||
2863 | while (tok != TOK_LINEFEED) { |
||
2864 | if (tok != TOK_STR) { |
||
2865 | include_syntax: |
||
2866 | error("'#include' expects \"FILENAME\" or |
||
2867 | } |
||
2868 | pstrcat(buf, sizeof(buf), (char *)tokc.cstr->data); |
||
2869 | next(); |
||
2870 | } |
||
2871 | c = '\"'; |
||
2872 | } else { |
||
2873 | int len; |
||
2874 | while (tok != TOK_LINEFEED) { |
||
2875 | pstrcat(buf, sizeof(buf), get_tok_str(tok, &tokc)); |
||
2876 | next(); |
||
2877 | } |
||
2878 | len = strlen(buf); |
||
2879 | /* check syntax and remove '<>' */ |
||
2880 | if (len < 2 || buf[0] != '<' || buf[len - 1] != '>') |
||
2881 | goto include_syntax; |
||
2882 | memmove(buf, buf + 1, len - 2); |
||
2883 | buf[len - 2] = '\0'; |
||
2884 | c = '>'; |
||
2885 | } |
||
2886 | } |
||
2887 | |||
2888 | e = search_cached_include(s1, c, buf); |
||
2889 | if (e && define_find(e->ifndef_macro)) { |
||
2890 | /* no need to parse the include because the 'ifndef macro' |
||
2891 | is defined */ |
||
2892 | #ifdef INC_DEBUG |
||
2893 | printf("%s: skipping %s\n", file->filename, buf); |
||
2894 | #endif |
||
2895 | } else { |
||
2896 | if (c == '\"') { |
||
2897 | /* first search in current dir if "header.h" */ |
||
2898 | size = 0; |
||
2899 | p = strrchr(file->filename, '/'); |
||
2900 | if (p) |
||
2901 | size = p + 1 - file->filename; |
||
2902 | if (size > sizeof(buf1) - 1) |
||
2903 | size = sizeof(buf1) - 1; |
||
2904 | memcpy(buf1, file->filename, size); |
||
2905 | buf1[size] = '\0'; |
||
2906 | pstrcat(buf1, sizeof(buf1), buf); |
||
2907 | f = tcc_open(s1, buf1); |
||
2908 | if (f) { |
||
2909 | if (tok == TOK_INCLUDE_NEXT) |
||
2910 | tok = TOK_INCLUDE; |
||
2911 | else |
||
2912 | goto found; |
||
2913 | } |
||
2914 | } |
||
2915 | if (s1->include_stack_ptr >= s1->include_stack + INCLUDE_STACK_SIZE) |
||
2916 | error("#include recursion too deep"); |
||
2917 | /* now search in all the include paths */ |
||
2918 | n = s1->nb_include_paths + s1->nb_sysinclude_paths; |
||
2919 | for(i = 0; i < n; i++) { |
||
2920 | const char *path; |
||
2921 | if (i < s1->nb_include_paths) |
||
2922 | path = s1->include_paths[i]; |
||
2923 | else |
||
2924 | path = s1->sysinclude_paths[i - s1->nb_include_paths]; |
||
2925 | pstrcpy(buf1, sizeof(buf1), path); |
||
2926 | pstrcat(buf1, sizeof(buf1), "/"); |
||
2927 | pstrcat(buf1, sizeof(buf1), buf); |
||
2928 | f = tcc_open(s1, buf1); |
||
2929 | if (f) { |
||
2930 | if (tok == TOK_INCLUDE_NEXT) |
||
2931 | tok = TOK_INCLUDE; |
||
2932 | else |
||
2933 | goto found; |
||
2934 | } |
||
2935 | } |
||
2936 | error("include file '%s' not found", buf); |
||
2937 | f = NULL; |
||
2938 | found: |
||
2939 | #ifdef INC_DEBUG |
||
2940 | printf("%s: including %s\n", file->filename, buf1); |
||
2941 | #endif |
||
2942 | f->inc_type = c; |
||
2943 | pstrcpy(f->inc_filename, sizeof(f->inc_filename), buf); |
||
2944 | /* push current file in stack */ |
||
2945 | /* XXX: fix current line init */ |
||
2946 | *s1->include_stack_ptr++ = file; |
||
2947 | file = f; |
||
2948 | /* add include file debug info */ |
||
2949 | if (do_debug) { |
||
2950 | put_stabs(file->filename, N_BINCL, 0, 0, 0); |
||
2951 | } |
||
2952 | tok_flags |= TOK_FLAG_BOF | TOK_FLAG_BOL; |
||
2953 | ch = file->buf_ptr[0]; |
||
2954 | goto the_end; |
||
2955 | } |
||
2956 | break; |
||
2957 | case TOK_IFNDEF: |
||
2958 | c = 1; |
||
2959 | goto do_ifdef; |
||
2960 | case TOK_IF: |
||
2961 | c = expr_preprocess(); |
||
2962 | goto do_if; |
||
2963 | case TOK_IFDEF: |
||
2964 | c = 0; |
||
2965 | do_ifdef: |
||
2966 | next_nomacro(); |
||
2967 | if (tok < TOK_IDENT) |
||
2968 | error("invalid argument for '#if%sdef'", c ? "n" : ""); |
||
2969 | if (is_bof) { |
||
2970 | if (c) { |
||
2971 | #ifdef INC_DEBUG |
||
2972 | printf("#ifndef %s\n", get_tok_str(tok, NULL)); |
||
2973 | #endif |
||
2974 | file->ifndef_macro = tok; |
||
2975 | } |
||
2976 | } |
||
2977 | c = (define_find(tok) != 0) ^ c; |
||
2978 | do_if: |
||
2979 | if (s1->ifdef_stack_ptr >= s1->ifdef_stack + IFDEF_STACK_SIZE) |
||
2980 | error("memory full"); |
||
2981 | *s1->ifdef_stack_ptr++ = c; |
||
2982 | goto test_skip; |
||
2983 | case TOK_ELSE: |
||
2984 | if (s1->ifdef_stack_ptr == s1->ifdef_stack) |
||
2985 | error("#else without matching #if"); |
||
2986 | if (s1->ifdef_stack_ptr[-1] & 2) |
||
2987 | error("#else after #else"); |
||
2988 | c = (s1->ifdef_stack_ptr[-1] ^= 3); |
||
2989 | goto test_skip; |
||
2990 | case TOK_ELIF: |
||
2991 | if (s1->ifdef_stack_ptr == s1->ifdef_stack) |
||
2992 | error("#elif without matching #if"); |
||
2993 | c = s1->ifdef_stack_ptr[-1]; |
||
2994 | if (c > 1) |
||
2995 | error("#elif after #else"); |
||
2996 | /* last #if/#elif expression was true: we skip */ |
||
2997 | if (c == 1) |
||
2998 | goto skip; |
||
2999 | c = expr_preprocess(); |
||
3000 | s1->ifdef_stack_ptr[-1] = c; |
||
3001 | test_skip: |
||
3002 | if (!(c & 1)) { |
||
3003 | skip: |
||
3004 | preprocess_skip(); |
||
3005 | is_bof = 0; |
||
3006 | goto redo; |
||
3007 | } |
||
3008 | break; |
||
3009 | case TOK_ENDIF: |
||
3010 | if (s1->ifdef_stack_ptr <= file->ifdef_stack_ptr) |
||
3011 | error("#endif without matching #if"); |
||
3012 | s1->ifdef_stack_ptr--; |
||
3013 | /* '#ifndef macro' was at the start of file. Now we check if |
||
3014 | an '#endif' is exactly at the end of file */ |
||
3015 | if (file->ifndef_macro && |
||
3016 | s1->ifdef_stack_ptr == file->ifdef_stack_ptr) { |
||
3017 | file->ifndef_macro_saved = file->ifndef_macro; |
||
3018 | /* need to set to zero to avoid false matches if another |
||
3019 | #ifndef at middle of file */ |
||
3020 | file->ifndef_macro = 0; |
||
3021 | while (tok != TOK_LINEFEED) |
||
3022 | next_nomacro(); |
||
3023 | tok_flags |= TOK_FLAG_ENDIF; |
||
3024 | goto the_end; |
||
3025 | } |
||
3026 | break; |
||
3027 | case TOK_LINE: |
||
3028 | next(); |
||
3029 | if (tok != TOK_CINT) |
||
3030 | error("#line"); |
||
3031 | file->line_num = tokc.i - 1; /* the line number will be incremented after */ |
||
3032 | next(); |
||
3033 | if (tok != TOK_LINEFEED) { |
||
3034 | if (tok != TOK_STR) |
||
3035 | error("#line"); |
||
3036 | pstrcpy(file->filename, sizeof(file->filename), |
||
3037 | (char *)tokc.cstr->data); |
||
3038 | } |
||
3039 | break; |
||
3040 | case TOK_ERROR: |
||
3041 | case TOK_WARNING: |
||
3042 | c = tok; |
||
3043 | ch = file->buf_ptr[0]; |
||
3044 | skip_spaces(); |
||
3045 | q = buf; |
||
3046 | while (ch != '\n' && ch != CH_EOF) { |
||
3047 | if ((q - buf) < sizeof(buf) - 1) |
||
3048 | *q++ = ch; |
||
3049 | minp(); |
||
3050 | } |
||
3051 | *q = '\0'; |
||
3052 | if (c == TOK_ERROR) |
||
3053 | error("#error %s", buf); |
||
3054 | else |
||
3055 | warning("#warning %s", buf); |
||
3056 | break; |
||
3057 | case TOK_PRAGMA: |
||
3058 | pragma_parse(s1); |
||
3059 | break; |
||
3060 | default: |
||
3061 | if (tok == TOK_LINEFEED || tok == '!' || tok == TOK_CINT) { |
||
3062 | /* '!' is ignored to allow C scripts. numbers are ignored |
||
3063 | to emulate cpp behaviour */ |
||
3064 | } else { |
||
3065 | if (!(saved_parse_flags & PARSE_FLAG_ASM_COMMENTS)) |
||
3066 | error("invalid preprocessing directive #%s", get_tok_str(tok, &tokc)); |
||
3067 | } |
||
3068 | break; |
||
3069 | } |
||
3070 | /* ignore other preprocess commands or #! for C scripts */ |
||
3071 | while (tok != TOK_LINEFEED) |
||
3072 | next_nomacro(); |
||
3073 | the_end: |
||
3074 | parse_flags = saved_parse_flags; |
||
3075 | } |
||
3076 | |||
3077 | /* evaluate escape codes in a string. */ |
||
3078 | static void parse_escape_string(CString *outstr, const uint8_t *buf, int is_long) |
||
3079 | { |
||
3080 | int c, n; |
||
3081 | const uint8_t *p; |
||
3082 | |||
3083 | p = buf; |
||
3084 | for(;;) { |
||
3085 | c = *p; |
||
3086 | if (c == '\0') |
||
3087 | break; |
||
3088 | if (c == '\\') { |
||
3089 | p++; |
||
3090 | /* escape */ |
||
3091 | c = *p; |
||
3092 | switch(c) { |
||
3093 | case '0': case '1': case '2': case '3': |
||
3094 | case '4': case '5': case '6': case '7': |
||
3095 | /* at most three octal digits */ |
||
3096 | n = c - '0'; |
||
3097 | p++; |
||
3098 | c = *p; |
||
3099 | if (isoct(c)) { |
||
3100 | n = n * 8 + c - '0'; |
||
3101 | p++; |
||
3102 | c = *p; |
||
3103 | if (isoct(c)) { |
||
3104 | n = n * 8 + c - '0'; |
||
3105 | p++; |
||
3106 | } |
||
3107 | } |
||
3108 | c = n; |
||
3109 | goto add_char_nonext; |
||
3110 | case 'x': |
||
3111 | p++; |
||
3112 | n = 0; |
||
3113 | for(;;) { |
||
3114 | c = *p; |
||
3115 | if (c >= 'a' && c <= 'f') |
||
3116 | c = c - 'a' + 10; |
||
3117 | else if (c >= 'A' && c <= 'F') |
||
3118 | c = c - 'A' + 10; |
||
3119 | else if (isnum(c)) |
||
3120 | c = c - '0'; |
||
3121 | else |
||
3122 | break; |
||
3123 | n = n * 16 + c; |
||
3124 | p++; |
||
3125 | } |
||
3126 | c = n; |
||
3127 | goto add_char_nonext; |
||
3128 | case 'a': |
||
3129 | c = '\a'; |
||
3130 | break; |
||
3131 | case 'b': |
||
3132 | c = '\b'; |
||
3133 | break; |
||
3134 | case 'f': |
||
3135 | c = '\f'; |
||
3136 | break; |
||
3137 | case 'n': |
||
3138 | c = '\n'; |
||
3139 | break; |
||
3140 | case 'r': |
||
3141 | c = '\r'; |
||
3142 | break; |
||
3143 | case 't': |
||
3144 | c = '\t'; |
||
3145 | break; |
||
3146 | case 'v': |
||
3147 | c = '\v'; |
||
3148 | break; |
||
3149 | case 'e': |
||
3150 | if (!gnu_ext) |
||
3151 | goto invalid_escape; |
||
3152 | c = 27; |
||
3153 | break; |
||
3154 | case '\'': |
||
3155 | case '\"': |
||
3156 | case '\\': |
||
3157 | case '?': |
||
3158 | break; |
||
3159 | default: |
||
3160 | invalid_escape: |
||
3161 | if (c >= '!' && c <= '~') |
||
3162 | warning("unknown escape sequence: \'\\%c\'", c); |
||
3163 | else |
||
3164 | warning("unknown escape sequence: \'\\x%x\'", c); |
||
3165 | break; |
||
3166 | } |
||
3167 | } |
||
3168 | p++; |
||
3169 | add_char_nonext: |
||
3170 | if (!is_long) |
||
3171 | cstr_ccat(outstr, c); |
||
3172 | else |
||
3173 | cstr_wccat(outstr, c); |
||
3174 | } |
||
3175 | /* add a trailing '\0' */ |
||
3176 | if (!is_long) |
||
3177 | cstr_ccat(outstr, '\0'); |
||
3178 | else |
||
3179 | cstr_wccat(outstr, '\0'); |
||
3180 | } |
||
3181 | |||
3182 | /* we use 64 bit numbers */ |
||
3183 | #define BN_SIZE 2 |
||
3184 | |||
3185 | /* bn = (bn << shift) | or_val */ |
||
3186 | void bn_lshift(unsigned int *bn, int shift, int or_val) |
||
3187 | { |
||
3188 | int i; |
||
3189 | unsigned int v; |
||
3190 | for(i=0;i |
||
3191 | v = bn[i]; |
||
3192 | bn[i] = (v << shift) | or_val; |
||
3193 | or_val = v >> (32 - shift); |
||
3194 | } |
||
3195 | } |
||
3196 | |||
3197 | void bn_zero(unsigned int *bn) |
||
3198 | { |
||
3199 | int i; |
||
3200 | for(i=0;i |
||
3201 | bn[i] = 0; |
||
3202 | } |
||
3203 | } |
||
3204 | |||
3205 | /* parse number in null terminated string 'p' and return it in the |
||
3206 | current token */ |
||
3207 | void parse_number(const char *p) |
||
3208 | { |
||
3209 | int b, t, shift, frac_bits, s, exp_val, ch; |
||
3210 | char *q; |
||
3211 | unsigned int bn[BN_SIZE]; |
||
3212 | double d; |
||
3213 | |||
3214 | /* number */ |
||
3215 | q = token_buf; |
||
3216 | ch = *p++; |
||
3217 | t = ch; |
||
3218 | ch = *p++; |
||
3219 | *q++ = t; |
||
3220 | b = 10; |
||
3221 | if (t == '.') { |
||
3222 | goto float_frac_parse; |
||
3223 | } else if (t == '0') { |
||
3224 | if (ch == 'x' || ch == 'X') { |
||
3225 | q--; |
||
3226 | ch = *p++; |
||
3227 | b = 16; |
||
3228 | } else if (tcc_ext && (ch == 'b' || ch == 'B')) { |
||
3229 | q--; |
||
3230 | ch = *p++; |
||
3231 | b = 2; |
||
3232 | } |
||
3233 | } |
||
3234 | /* parse all digits. cannot check octal numbers at this stage |
||
3235 | because of floating point constants */ |
||
3236 | while (1) { |
||
3237 | if (ch >= 'a' && ch <= 'f') |
||
3238 | t = ch - 'a' + 10; |
||
3239 | else if (ch >= 'A' && ch <= 'F') |
||
3240 | t = ch - 'A' + 10; |
||
3241 | else if (isnum(ch)) |
||
3242 | t = ch - '0'; |
||
3243 | else |
||
3244 | break; |
||
3245 | if (t >= b) |
||
3246 | break; |
||
3247 | if (q >= token_buf + STRING_MAX_SIZE) { |
||
3248 | num_too_long: |
||
3249 | error("number too long"); |
||
3250 | } |
||
3251 | *q++ = ch; |
||
3252 | ch = *p++; |
||
3253 | } |
||
3254 | if (ch == '.' || |
||
3255 | ((ch == 'e' || ch == 'E') && b == 10) || |
||
3256 | ((ch == 'p' || ch == 'P') && (b == 16 || b == 2))) { |
||
3257 | if (b != 10) { |
||
3258 | /* NOTE: strtox should support that for hexa numbers, but |
||
3259 | non ISOC99 libcs do not support it, so we prefer to do |
||
3260 | it by hand */ |
||
3261 | /* hexadecimal or binary floats */ |
||
3262 | /* XXX: handle overflows */ |
||
3263 | *q = '\0'; |
||
3264 | if (b == 16) |
||
3265 | shift = 4; |
||
3266 | else |
||
3267 | shift = 2; |
||
3268 | bn_zero(bn); |
||
3269 | q = token_buf; |
||
3270 | while (1) { |
||
3271 | t = *q++; |
||
3272 | if (t == '\0') { |
||
3273 | break; |
||
3274 | } else if (t >= 'a') { |
||
3275 | t = t - 'a' + 10; |
||
3276 | } else if (t >= 'A') { |
||
3277 | t = t - 'A' + 10; |
||
3278 | } else { |
||
3279 | t = t - '0'; |
||
3280 | } |
||
3281 | bn_lshift(bn, shift, t); |
||
3282 | } |
||
3283 | frac_bits = 0; |
||
3284 | if (ch == '.') { |
||
3285 | ch = *p++; |
||
3286 | while (1) { |
||
3287 | t = ch; |
||
3288 | if (t >= 'a' && t <= 'f') { |
||
3289 | t = t - 'a' + 10; |
||
3290 | } else if (t >= 'A' && t <= 'F') { |
||
3291 | t = t - 'A' + 10; |
||
3292 | } else if (t >= '0' && t <= '9') { |
||
3293 | t = t - '0'; |
||
3294 | } else { |
||
3295 | break; |
||
3296 | } |
||
3297 | if (t >= b) |
||
3298 | error("invalid digit"); |
||
3299 | bn_lshift(bn, shift, t); |
||
3300 | frac_bits += shift; |
||
3301 | ch = *p++; |
||
3302 | } |
||
3303 | } |
||
3304 | if (ch != 'p' && ch != 'P') |
||
3305 | expect("exponent"); |
||
3306 | ch = *p++; |
||
3307 | s = 1; |
||
3308 | exp_val = 0; |
||
3309 | if (ch == '+') { |
||
3310 | ch = *p++; |
||
3311 | } else if (ch == '-') { |
||
3312 | s = -1; |
||
3313 | ch = *p++; |
||
3314 | } |
||
3315 | if (ch < '0' || ch > '9') |
||
3316 | expect("exponent digits"); |
||
3317 | while (ch >= '0' && ch <= '9') { |
||
3318 | exp_val = exp_val * 10 + ch - '0'; |
||
3319 | ch = *p++; |
||
3320 | } |
||
3321 | exp_val = exp_val * s; |
||
3322 | |||
3323 | /* now we can generate the number */ |
||
3324 | /* XXX: should patch directly float number */ |
||
3325 | d = (double)bn[1] * 4294967296.0 + (double)bn[0]; |
||
3326 | d = ldexp(d, exp_val - frac_bits); |
||
3327 | t = toup(ch); |
||
3328 | if (t == 'F') { |
||
3329 | ch = *p++; |
||
3330 | tok = TOK_CFLOAT; |
||
3331 | /* float : should handle overflow */ |
||
3332 | tokc.f = (float)d; |
||
3333 | } else if (t == 'L') { |
||
3334 | ch = *p++; |
||
3335 | tok = TOK_CLDOUBLE; |
||
3336 | /* XXX: not large enough */ |
||
3337 | tokc.ld = (long double)d; |
||
3338 | } else { |
||
3339 | tok = TOK_CDOUBLE; |
||
3340 | tokc.d = d; |
||
3341 | } |
||
3342 | } else { |
||
3343 | /* decimal floats */ |
||
3344 | if (ch == '.') { |
||
3345 | if (q >= token_buf + STRING_MAX_SIZE) |
||
3346 | goto num_too_long; |
||
3347 | *q++ = ch; |
||
3348 | ch = *p++; |
||
3349 | float_frac_parse: |
||
3350 | while (ch >= '0' && ch <= '9') { |
||
3351 | if (q >= token_buf + STRING_MAX_SIZE) |
||
3352 | goto num_too_long; |
||
3353 | *q++ = ch; |
||
3354 | ch = *p++; |
||
3355 | } |
||
3356 | } |
||
3357 | if (ch == 'e' || ch == 'E') { |
||
3358 | if (q >= token_buf + STRING_MAX_SIZE) |
||
3359 | goto num_too_long; |
||
3360 | *q++ = ch; |
||
3361 | ch = *p++; |
||
3362 | if (ch == '-' || ch == '+') { |
||
3363 | if (q >= token_buf + STRING_MAX_SIZE) |
||
3364 | goto num_too_long; |
||
3365 | *q++ = ch; |
||
3366 | ch = *p++; |
||
3367 | } |
||
3368 | if (ch < '0' || ch > '9') |
||
3369 | expect("exponent digits"); |
||
3370 | while (ch >= '0' && ch <= '9') { |
||
3371 | if (q >= token_buf + STRING_MAX_SIZE) |
||
3372 | goto num_too_long; |
||
3373 | *q++ = ch; |
||
3374 | ch = *p++; |
||
3375 | } |
||
3376 | } |
||
3377 | *q = '\0'; |
||
3378 | t = toup(ch); |
||
609 | andrew_pro | 3379 | //errno = 0; |
145 | halyavin | 3380 | if (t == 'F') { |
3381 | ch = *p++; |
||
3382 | tok = TOK_CFLOAT; |
||
3383 | tokc.f = strtof(token_buf, NULL); |
||
3384 | } else if (t == 'L') { |
||
3385 | ch = *p++; |
||
3386 | tok = TOK_CLDOUBLE; |
||
3387 | tokc.ld = strtold(token_buf, NULL); |
||
3388 | } else { |
||
3389 | tok = TOK_CDOUBLE; |
||
3390 | tokc.d = strtod(token_buf, NULL); |
||
3391 | } |
||
3392 | } |
||
3393 | } else { |
||
3394 | unsigned long long n, n1; |
||
3395 | int lcount, ucount; |
||
3396 | |||
3397 | /* integer number */ |
||
3398 | *q = '\0'; |
||
3399 | q = token_buf; |
||
3400 | if (b == 10 && *q == '0') { |
||
3401 | b = 8; |
||
3402 | q++; |
||
3403 | } |
||
3404 | n = 0; |
||
3405 | while(1) { |
||
3406 | t = *q++; |
||
3407 | /* no need for checks except for base 10 / 8 errors */ |
||
3408 | if (t == '\0') { |
||
3409 | break; |
||
3410 | } else if (t >= 'a') { |
||
3411 | t = t - 'a' + 10; |
||
3412 | } else if (t >= 'A') { |
||
3413 | t = t - 'A' + 10; |
||
3414 | } else { |
||
3415 | t = t - '0'; |
||
3416 | if (t >= b) |
||
3417 | error("invalid digit"); |
||
3418 | } |
||
3419 | n1 = n; |
||
3420 | n = n * b + t; |
||
3421 | /* detect overflow */ |
||
3422 | /* XXX: this test is not reliable */ |
||
3423 | if (n < n1) |
||
3424 | error("integer constant overflow"); |
||
3425 | } |
||
3426 | |||
3427 | /* XXX: not exactly ANSI compliant */ |
||
3428 | if ((n & 0xffffffff00000000LL) != 0) { |
||
3429 | if ((n >> 63) != 0) |
||
3430 | tok = TOK_CULLONG; |
||
3431 | else |
||
3432 | tok = TOK_CLLONG; |
||
3433 | } else if (n > 0x7fffffff) { |
||
3434 | tok = TOK_CUINT; |
||
3435 | } else { |
||
3436 | tok = TOK_CINT; |
||
3437 | } |
||
3438 | lcount = 0; |
||
3439 | ucount = 0; |
||
3440 | for(;;) { |
||
3441 | t = toup(ch); |
||
3442 | if (t == 'L') { |
||
3443 | if (lcount >= 2) |
||
3444 | error("three 'l's in integer constant"); |
||
3445 | lcount++; |
||
3446 | if (lcount == 2) { |
||
3447 | if (tok == TOK_CINT) |
||
3448 | tok = TOK_CLLONG; |
||
3449 | else if (tok == TOK_CUINT) |
||
3450 | tok = TOK_CULLONG; |
||
3451 | } |
||
3452 | ch = *p++; |
||
3453 | } else if (t == 'U') { |
||
3454 | if (ucount >= 1) |
||
3455 | error("two 'u's in integer constant"); |
||
3456 | ucount++; |
||
3457 | if (tok == TOK_CINT) |
||
3458 | tok = TOK_CUINT; |
||
3459 | else if (tok == TOK_CLLONG) |
||
3460 | tok = TOK_CULLONG; |
||
3461 | ch = *p++; |
||
3462 | } else { |
||
3463 | break; |
||
3464 | } |
||
3465 | } |
||
3466 | if (tok == TOK_CINT || tok == TOK_CUINT) |
||
3467 | tokc.ui = n; |
||
3468 | else |
||
3469 | tokc.ull = n; |
||
3470 | } |
||
3471 | } |
||
3472 | |||
3473 | |||
3474 | #define PARSE2(c1, tok1, c2, tok2) \ |
||
3475 | case c1: \ |
||
3476 | PEEKC(c, p); \ |
||
3477 | if (c == c2) { \ |
||
3478 | p++; \ |
||
3479 | tok = tok2; \ |
||
3480 | } else { \ |
||
3481 | tok = tok1; \ |
||
3482 | } \ |
||
3483 | break; |
||
3484 | |||
3485 | /* return next token without macro substitution */ |
||
3486 | static inline void next_nomacro1(void) |
||
3487 | { |
||
3488 | int t, c, is_long; |
||
3489 | TokenSym *ts; |
||
3490 | uint8_t *p, *p1; |
||
3491 | unsigned int h; |
||
3492 | |||
3493 | p = file->buf_ptr; |
||
3494 | redo_no_start: |
||
3495 | c = *p; |
||
3496 | switch(c) { |
||
3497 | case ' ': |
||
3498 | case '\t': |
||
3499 | case '\f': |
||
3500 | case '\v': |
||
3501 | case '\r': |
||
3502 | p++; |
||
3503 | goto redo_no_start; |
||
3504 | |||
3505 | case '\\': |
||
3506 | /* first look if it is in fact an end of buffer */ |
||
3507 | if (p >= file->buf_end) { |
||
3508 | file->buf_ptr = p; |
||
3509 | handle_eob(); |
||
3510 | p = file->buf_ptr; |
||
3511 | if (p >= file->buf_end) |
||
3512 | goto parse_eof; |
||
3513 | else |
||
3514 | goto redo_no_start; |
||
3515 | } else { |
||
3516 | file->buf_ptr = p; |
||
3517 | ch = *p; |
||
3518 | handle_stray(); |
||
3519 | p = file->buf_ptr; |
||
3520 | goto redo_no_start; |
||
3521 | } |
||
3522 | parse_eof: |
||
3523 | { |
||
3524 | TCCState *s1 = tcc_state; |
||
3525 | if (parse_flags & PARSE_FLAG_LINEFEED) { |
||
3526 | tok = TOK_LINEFEED; |
||
3527 | } else if (s1->include_stack_ptr == s1->include_stack || |
||
3528 | !(parse_flags & PARSE_FLAG_PREPROCESS)) { |
||
3529 | /* no include left : end of file. */ |
||
3530 | tok = TOK_EOF; |
||
3531 | } else { |
||
3532 | /* pop include file */ |
||
3533 | |||
3534 | /* test if previous '#endif' was after a #ifdef at |
||
3535 | start of file */ |
||
3536 | if (tok_flags & TOK_FLAG_ENDIF) { |
||
3537 | #ifdef INC_DEBUG |
||
3538 | printf("#endif %s\n", get_tok_str(file->ifndef_macro_saved, NULL)); |
||
3539 | #endif |
||
3540 | add_cached_include(s1, file->inc_type, file->inc_filename, |
||
3541 | file->ifndef_macro_saved); |
||
3542 | } |
||
3543 | |||
3544 | /* add end of include file debug info */ |
||
3545 | if (do_debug) { |
||
3546 | put_stabd(N_EINCL, 0, 0); |
||
3547 | } |
||
3548 | /* pop include stack */ |
||
3549 | tcc_close(file); |
||
3550 | s1->include_stack_ptr--; |
||
3551 | file = *s1->include_stack_ptr; |
||
3552 | p = file->buf_ptr; |
||
3553 | goto redo_no_start; |
||
3554 | } |
||
3555 | } |
||
3556 | break; |
||
3557 | |||
3558 | case '\n': |
||
3559 | if (parse_flags & PARSE_FLAG_LINEFEED) { |
||
3560 | tok = TOK_LINEFEED; |
||
3561 | } else { |
||
3562 | file->line_num++; |
||
3563 | tok_flags |= TOK_FLAG_BOL; |
||
3564 | p++; |
||
3565 | goto redo_no_start; |
||
3566 | } |
||
3567 | break; |
||
3568 | |||
3569 | case '#': |
||
3570 | /* XXX: simplify */ |
||
3571 | PEEKC(c, p); |
||
3572 | if ((tok_flags & TOK_FLAG_BOL) && |
||
3573 | (parse_flags & PARSE_FLAG_PREPROCESS)) { |
||
3574 | file->buf_ptr = p; |
||
3575 | preprocess(tok_flags & TOK_FLAG_BOF); |
||
3576 | p = file->buf_ptr; |
||
3577 | goto redo_no_start; |
||
3578 | } else { |
||
3579 | if (c == '#') { |
||
3580 | p++; |
||
3581 | tok = TOK_TWOSHARPS; |
||
3582 | } else { |
||
3583 | if (parse_flags & PARSE_FLAG_ASM_COMMENTS) { |
||
3584 | p = parse_line_comment(p - 1); |
||
3585 | goto redo_no_start; |
||
3586 | } else { |
||
3587 | tok = '#'; |
||
3588 | } |
||
3589 | } |
||
3590 | } |
||
3591 | break; |
||
3592 | |||
3593 | case 'a': case 'b': case 'c': case 'd': |
||
3594 | case 'e': case 'f': case 'g': case 'h': |
||
3595 | case 'i': case 'j': case 'k': case 'l': |
||
3596 | case 'm': case 'n': case 'o': case 'p': |
||
3597 | case 'q': case 'r': case 's': case 't': |
||
3598 | case 'u': case 'v': case 'w': case 'x': |
||
3599 | case 'y': case 'z': |
||
3600 | case 'A': case 'B': case 'C': case 'D': |
||
3601 | case 'E': case 'F': case 'G': case 'H': |
||
3602 | case 'I': case 'J': case 'K': |
||
3603 | case 'M': case 'N': case 'O': case 'P': |
||
3604 | case 'Q': case 'R': case 'S': case 'T': |
||
3605 | case 'U': case 'V': case 'W': case 'X': |
||
3606 | case 'Y': case 'Z': |
||
3607 | case '_': |
||
3608 | parse_ident_fast: |
||
3609 | p1 = p; |
||
3610 | h = TOK_HASH_INIT; |
||
3611 | h = TOK_HASH_FUNC(h, c); |
||
3612 | p++; |
||
3613 | for(;;) { |
||
3614 | c = *p; |
||
3615 | if (!isidnum_table[c]) |
||
3616 | break; |
||
3617 | h = TOK_HASH_FUNC(h, c); |
||
3618 | p++; |
||
3619 | } |
||
3620 | if (c != '\\') { |
||
3621 | TokenSym **pts; |
||
3622 | int len; |
||
3623 | |||
3624 | /* fast case : no stray found, so we have the full token |
||
3625 | and we have already hashed it */ |
||
3626 | len = p - p1; |
||
3627 | h &= (TOK_HASH_SIZE - 1); |
||
3628 | pts = &hash_ident[h]; |
||
3629 | for(;;) { |
||
3630 | ts = *pts; |
||
3631 | if (!ts) |
||
3632 | break; |
||
3633 | if (ts->len == len && !memcmp(ts->str, p1, len)) |
||
3634 | goto token_found; |
||
3635 | pts = &(ts->hash_next); |
||
3636 | } |
||
3637 | ts = tok_alloc_new(pts, p1, len); |
||
3638 | token_found: ; |
||
3639 | } else { |
||
3640 | /* slower case */ |
||
3641 | cstr_reset(&tokcstr); |
||
3642 | |||
3643 | while (p1 < p) { |
||
3644 | cstr_ccat(&tokcstr, *p1); |
||
3645 | p1++; |
||
3646 | } |
||
3647 | p--; |
||
3648 | PEEKC(c, p); |
||
3649 | parse_ident_slow: |
||
3650 | while (isidnum_table[c]) { |
||
3651 | cstr_ccat(&tokcstr, c); |
||
3652 | PEEKC(c, p); |
||
3653 | } |
||
3654 | ts = tok_alloc(tokcstr.data, tokcstr.size); |
||
3655 | } |
||
3656 | tok = ts->tok; |
||
3657 | break; |
||
3658 | case 'L': |
||
3659 | t = p[1]; |
||
3660 | if (t != '\\' && t != '\'' && t != '\"') { |
||
3661 | /* fast case */ |
||
3662 | goto parse_ident_fast; |
||
3663 | } else { |
||
3664 | PEEKC(c, p); |
||
3665 | if (c == '\'' || c == '\"') { |
||
3666 | is_long = 1; |
||
3667 | goto str_const; |
||
3668 | } else { |
||
3669 | cstr_reset(&tokcstr); |
||
3670 | cstr_ccat(&tokcstr, 'L'); |
||
3671 | goto parse_ident_slow; |
||
3672 | } |
||
3673 | } |
||
3674 | break; |
||
3675 | case '0': case '1': case '2': case '3': |
||
3676 | case '4': case '5': case '6': case '7': |
||
3677 | case '8': case '9': |
||
3678 | |||
3679 | cstr_reset(&tokcstr); |
||
3680 | /* after the first digit, accept digits, alpha, '.' or sign if |
||
3681 | prefixed by 'eEpP' */ |
||
3682 | parse_num: |
||
3683 | for(;;) { |
||
3684 | t = c; |
||
3685 | cstr_ccat(&tokcstr, c); |
||
3686 | PEEKC(c, p); |
||
3687 | if (!(isnum(c) || isid(c) || c == '.' || |
||
3688 | ((c == '+' || c == '-') && |
||
3689 | (t == 'e' || t == 'E' || t == 'p' || t == 'P')))) |
||
3690 | break; |
||
3691 | } |
||
3692 | /* We add a trailing '\0' to ease parsing */ |
||
3693 | cstr_ccat(&tokcstr, '\0'); |
||
3694 | tokc.cstr = &tokcstr; |
||
3695 | tok = TOK_PPNUM; |
||
3696 | break; |
||
3697 | case '.': |
||
3698 | /* special dot handling because it can also start a number */ |
||
3699 | PEEKC(c, p); |
||
3700 | if (isnum(c)) { |
||
3701 | cstr_reset(&tokcstr); |
||
3702 | cstr_ccat(&tokcstr, '.'); |
||
3703 | goto parse_num; |
||
3704 | } else if (c == '.') { |
||
3705 | PEEKC(c, p); |
||
3706 | if (c != '.') |
||
3707 | expect("'.'"); |
||
3708 | PEEKC(c, p); |
||
3709 | tok = TOK_DOTS; |
||
3710 | } else { |
||
3711 | tok = '.'; |
||
3712 | } |
||
3713 | break; |
||
3714 | case '\'': |
||
3715 | case '\"': |
||
3716 | is_long = 0; |
||
3717 | str_const: |
||
3718 | { |
||
3719 | CString str; |
||
3720 | int sep; |
||
3721 | |||
3722 | sep = c; |
||
3723 | |||
3724 | /* parse the string */ |
||
3725 | cstr_new(&str); |
||
3726 | p = parse_pp_string(p, sep, &str); |
||
3727 | cstr_ccat(&str, '\0'); |
||
3728 | |||
3729 | /* eval the escape (should be done as TOK_PPNUM) */ |
||
3730 | cstr_reset(&tokcstr); |
||
3731 | parse_escape_string(&tokcstr, str.data, is_long); |
||
3732 | cstr_free(&str); |
||
3733 | |||
3734 | if (sep == '\'') { |
||
3735 | int char_size; |
||
3736 | /* XXX: make it portable */ |
||
3737 | if (!is_long) |
||
3738 | char_size = 1; |
||
3739 | else |
||
3740 | char_size = sizeof(int); |
||
3741 | if (tokcstr.size <= char_size) |
||
3742 | error("empty character constant"); |
||
3743 | if (tokcstr.size > 2 * char_size) |
||
3744 | warning("multi-character character constant"); |
||
3745 | if (!is_long) { |
||
3746 | tokc.i = *(int8_t *)tokcstr.data; |
||
3747 | tok = TOK_CCHAR; |
||
3748 | } else { |
||
3749 | tokc.i = *(int *)tokcstr.data; |
||
3750 | tok = TOK_LCHAR; |
||
3751 | } |
||
3752 | } else { |
||
3753 | tokc.cstr = &tokcstr; |
||
3754 | if (!is_long) |
||
3755 | tok = TOK_STR; |
||
3756 | else |
||
3757 | tok = TOK_LSTR; |
||
3758 | } |
||
3759 | } |
||
3760 | break; |
||
3761 | |||
3762 | case '<': |
||
3763 | PEEKC(c, p); |
||
3764 | if (c == '=') { |
||
3765 | p++; |
||
3766 | tok = TOK_LE; |
||
3767 | } else if (c == '<') { |
||
3768 | PEEKC(c, p); |
||
3769 | if (c == '=') { |
||
3770 | p++; |
||
3771 | tok = TOK_A_SHL; |
||
3772 | } else { |
||
3773 | tok = TOK_SHL; |
||
3774 | } |
||
3775 | } else { |
||
3776 | tok = TOK_LT; |
||
3777 | } |
||
3778 | break; |
||
3779 | |||
3780 | case '>': |
||
3781 | PEEKC(c, p); |
||
3782 | if (c == '=') { |
||
3783 | p++; |
||
3784 | tok = TOK_GE; |
||
3785 | } else if (c == '>') { |
||
3786 | PEEKC(c, p); |
||
3787 | if (c == '=') { |
||
3788 | p++; |
||
3789 | tok = TOK_A_SAR; |
||
3790 | } else { |
||
3791 | tok = TOK_SAR; |
||
3792 | } |
||
3793 | } else { |
||
3794 | tok = TOK_GT; |
||
3795 | } |
||
3796 | break; |
||
3797 | |||
3798 | case '&': |
||
3799 | PEEKC(c, p); |
||
3800 | if (c == '&') { |
||
3801 | p++; |
||
3802 | tok = TOK_LAND; |
||
3803 | } else if (c == '=') { |
||
3804 | p++; |
||
3805 | tok = TOK_A_AND; |
||
3806 | } else { |
||
3807 | tok = '&'; |
||
3808 | } |
||
3809 | break; |
||
3810 | |||
3811 | case '|': |
||
3812 | PEEKC(c, p); |
||
3813 | if (c == '|') { |
||
3814 | p++; |
||
3815 | tok = TOK_LOR; |
||
3816 | } else if (c == '=') { |
||
3817 | p++; |
||
3818 | tok = TOK_A_OR; |
||
3819 | } else { |
||
3820 | tok = '|'; |
||
3821 | } |
||
3822 | break; |
||
3823 | |||
3824 | case '+': |
||
3825 | PEEKC(c, p); |
||
3826 | if (c == '+') { |
||
3827 | p++; |
||
3828 | tok = TOK_INC; |
||
3829 | } else if (c == '=') { |
||
3830 | p++; |
||
3831 | tok = TOK_A_ADD; |
||
3832 | } else { |
||
3833 | tok = '+'; |
||
3834 | } |
||
3835 | break; |
||
3836 | |||
3837 | case '-': |
||
3838 | PEEKC(c, p); |
||
3839 | if (c == '-') { |
||
3840 | p++; |
||
3841 | tok = TOK_DEC; |
||
3842 | } else if (c == '=') { |
||
3843 | p++; |
||
3844 | tok = TOK_A_SUB; |
||
3845 | } else if (c == '>') { |
||
3846 | p++; |
||
3847 | tok = TOK_ARROW; |
||
3848 | } else { |
||
3849 | tok = '-'; |
||
3850 | } |
||
3851 | break; |
||
3852 | |||
3853 | PARSE2('!', '!', '=', TOK_NE) |
||
3854 | PARSE2('=', '=', '=', TOK_EQ) |
||
3855 | PARSE2('*', '*', '=', TOK_A_MUL) |
||
3856 | PARSE2('%', '%', '=', TOK_A_MOD) |
||
3857 | PARSE2('^', '^', '=', TOK_A_XOR) |
||
3858 | |||
3859 | /* comments or operator */ |
||
3860 | case '/': |
||
3861 | PEEKC(c, p); |
||
3862 | if (c == '*') { |
||
3863 | p = parse_comment(p); |
||
3864 | goto redo_no_start; |
||
3865 | } else if (c == '/') { |
||
3866 | p = parse_line_comment(p); |
||
3867 | goto redo_no_start; |
||
3868 | } else if (c == '=') { |
||
3869 | p++; |
||
3870 | tok = TOK_A_DIV; |
||
3871 | } else { |
||
3872 | tok = '/'; |
||
3873 | } |
||
3874 | break; |
||
3875 | |||
3876 | /* simple tokens */ |
||
3877 | case '(': |
||
3878 | case ')': |
||
3879 | case '[': |
||
3880 | case ']': |
||
3881 | case '{': |
||
3882 | case '}': |
||
3883 | case ',': |
||
3884 | case ';': |
||
3885 | case ':': |
||
3886 | case '?': |
||
3887 | case '~': |
||
3888 | case '$': /* only used in assembler */ |
||
3889 | case '@': /* dito */ |
||
3890 | tok = c; |
||
3891 | p++; |
||
3892 | break; |
||
3893 | default: |
||
3894 | error("unrecognized character \\x%02x", c); |
||
3895 | break; |
||
3896 | } |
||
3897 | file->buf_ptr = p; |
||
3898 | tok_flags = 0; |
||
3899 | #if defined(PARSE_DEBUG) |
||
3900 | printf("token = %s\n", get_tok_str(tok, &tokc)); |
||
3901 | #endif |
||
3902 | } |
||
3903 | |||
3904 | /* return next token without macro substitution. Can read input from |
||
3905 | macro_ptr buffer */ |
||
3906 | static void next_nomacro(void) |
||
3907 | { |
||
3908 | if (macro_ptr) { |
||
3909 | redo: |
||
3910 | tok = *macro_ptr; |
||
3911 | if (tok) { |
||
3912 | TOK_GET(tok, macro_ptr, tokc); |
||
3913 | if (tok == TOK_LINENUM) { |
||
3914 | file->line_num = tokc.i; |
||
3915 | goto redo; |
||
3916 | } |
||
3917 | } |
||
3918 | } else { |
||
3919 | next_nomacro1(); |
||
3920 | } |
||
3921 | } |
||
3922 | |||
3923 | /* substitute args in macro_str and return allocated string */ |
||
3924 | static int *macro_arg_subst(Sym **nested_list, int *macro_str, Sym *args) |
||
3925 | { |
||
3926 | int *st, last_tok, t, notfirst; |
||
3927 | Sym *s; |
||
3928 | CValue cval; |
||
3929 | TokenString str; |
||
3930 | CString cstr; |
||
3931 | |||
3932 | tok_str_new(&str); |
||
3933 | last_tok = 0; |
||
3934 | while(1) { |
||
3935 | TOK_GET(t, macro_str, cval); |
||
3936 | if (!t) |
||
3937 | break; |
||
3938 | if (t == '#') { |
||
3939 | /* stringize */ |
||
3940 | TOK_GET(t, macro_str, cval); |
||
3941 | if (!t) |
||
3942 | break; |
||
3943 | s = sym_find2(args, t); |
||
3944 | if (s) { |
||
3945 | cstr_new(&cstr); |
||
3946 | st = (int *)s->c; |
||
3947 | notfirst = 0; |
||
3948 | while (*st) { |
||
3949 | if (notfirst) |
||
3950 | cstr_ccat(&cstr, ' '); |
||
3951 | TOK_GET(t, st, cval); |
||
3952 | cstr_cat(&cstr, get_tok_str(t, &cval)); |
||
3953 | notfirst = 1; |
||
3954 | } |
||
3955 | cstr_ccat(&cstr, '\0'); |
||
3956 | #ifdef PP_DEBUG |
||
3957 | printf("stringize: %s\n", (char *)cstr.data); |
||
3958 | #endif |
||
3959 | /* add string */ |
||
3960 | cval.cstr = &cstr; |
||
3961 | tok_str_add2(&str, TOK_STR, &cval); |
||
3962 | cstr_free(&cstr); |
||
3963 | } else { |
||
3964 | tok_str_add2(&str, t, &cval); |
||
3965 | } |
||
3966 | } else if (t >= TOK_IDENT) { |
||
3967 | s = sym_find2(args, t); |
||
3968 | if (s) { |
||
3969 | st = (int *)s->c; |
||
3970 | /* if '##' is present before or after, no arg substitution */ |
||
3971 | if (*macro_str == TOK_TWOSHARPS || last_tok == TOK_TWOSHARPS) { |
||
3972 | /* special case for var arg macros : ## eats the |
||
3973 | ',' if empty VA_ARGS variable. */ |
||
3974 | /* XXX: test of the ',' is not 100% |
||
3975 | reliable. should fix it to avoid security |
||
3976 | problems */ |
||
3977 | if (gnu_ext && s->type.t && |
||
3978 | last_tok == TOK_TWOSHARPS && |
||
3979 | str.len >= 2 && str.str[str.len - 2] == ',') { |
||
3980 | if (*st == 0) { |
||
3981 | /* suppress ',' '##' */ |
||
3982 | str.len -= 2; |
||
3983 | } else { |
||
3984 | /* suppress '##' and add variable */ |
||
3985 | str.len--; |
||
3986 | goto add_var; |
||
3987 | } |
||
3988 | } else { |
||
3989 | int t1; |
||
3990 | add_var: |
||
3991 | for(;;) { |
||
3992 | TOK_GET(t1, st, cval); |
||
3993 | if (!t1) |
||
3994 | break; |
||
3995 | tok_str_add2(&str, t1, &cval); |
||
3996 | } |
||
3997 | } |
||
3998 | } else { |
||
3999 | /* NOTE: the stream cannot be read when macro |
||
4000 | substituing an argument */ |
||
4001 | macro_subst(&str, nested_list, st, NULL); |
||
4002 | } |
||
4003 | } else { |
||
4004 | tok_str_add(&str, t); |
||
4005 | } |
||
4006 | } else { |
||
4007 | tok_str_add2(&str, t, &cval); |
||
4008 | } |
||
4009 | last_tok = t; |
||
4010 | } |
||
4011 | tok_str_add(&str, 0); |
||
4012 | return str.str; |
||
4013 | } |
||
4014 | |||
4015 | static char const ab_month_name[12][4] = |
||
4016 | { |
||
4017 | "Jan", "Feb", "Mar", "Apr", "May", "Jun", |
||
4018 | "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" |
||
4019 | }; |
||
4020 | |||
4021 | /* do macro substitution of current token with macro 's' and add |
||
4022 | result to (tok_str,tok_len). 'nested_list' is the list of all |
||
4023 | macros we got inside to avoid recursing. Return non zero if no |
||
4024 | substitution needs to be done */ |
||
4025 | static int macro_subst_tok(TokenString *tok_str, |
||
4026 | Sym **nested_list, Sym *s, struct macro_level **can_read_stream) |
||
4027 | { |
||
4028 | Sym *args, *sa, *sa1; |
||
4029 | int mstr_allocated, parlevel, *mstr, t, t1; |
||
4030 | TokenString str; |
||
4031 | char *cstrval; |
||
4032 | CValue cval; |
||
4033 | CString cstr; |
||
4034 | char buf[32]; |
||
4035 | |||
4036 | /* if symbol is a macro, prepare substitution */ |
||
4037 | /* special macros */ |
||
4038 | if (tok == TOK___LINE__) { |
||
4039 | snprintf(buf, sizeof(buf), "%d", file->line_num); |
||
4040 | cstrval = buf; |
||
4041 | t1 = TOK_PPNUM; |
||
4042 | goto add_cstr1; |
||
4043 | } else if (tok == TOK___FILE__) { |
||
4044 | cstrval = file->filename; |
||
4045 | goto add_cstr; |
||
4046 | } else if (tok == TOK___DATE__ || tok == TOK___TIME__) { |
||
4047 | time_t ti; |
||
4048 | struct tm *tm; |
||
4049 | |||
4050 | time(&ti); |
||
4051 | tm = localtime(&ti); |
||
4052 | if (tok == TOK___DATE__) { |
||
4053 | snprintf(buf, sizeof(buf), "%s %2d %d", |
||
4054 | ab_month_name[tm->tm_mon], tm->tm_mday, tm->tm_year + 1900); |
||
4055 | } else { |
||
4056 | snprintf(buf, sizeof(buf), "%02d:%02d:%02d", |
||
4057 | tm->tm_hour, tm->tm_min, tm->tm_sec); |
||
4058 | } |
||
4059 | cstrval = buf; |
||
4060 | add_cstr: |
||
4061 | t1 = TOK_STR; |
||
4062 | add_cstr1: |
||
4063 | cstr_new(&cstr); |
||
4064 | cstr_cat(&cstr, cstrval); |
||
4065 | cstr_ccat(&cstr, '\0'); |
||
4066 | cval.cstr = &cstr; |
||
4067 | tok_str_add2(tok_str, t1, &cval); |
||
4068 | cstr_free(&cstr); |
||
4069 | } else { |
||
4070 | mstr = (int *)s->c; |
||
4071 | mstr_allocated = 0; |
||
4072 | if (s->type.t == MACRO_FUNC) { |
||
4073 | /* NOTE: we do not use next_nomacro to avoid eating the |
||
4074 | next token. XXX: find better solution */ |
||
4075 | redo: |
||
4076 | if (macro_ptr) { |
||
4077 | t = *macro_ptr; |
||
4078 | if (t == 0 && can_read_stream) { |
||
4079 | /* end of macro stream: we must look at the token |
||
4080 | after in the file */ |
||
4081 | struct macro_level *ml = *can_read_stream; |
||
4082 | macro_ptr = NULL; |
||
4083 | if (ml) |
||
4084 | { |
||
4085 | macro_ptr = ml->p; |
||
4086 | ml->p = NULL; |
||
4087 | *can_read_stream = ml -> prev; |
||
4088 | } |
||
4089 | goto redo; |
||
4090 | } |
||
4091 | } else { |
||
4092 | /* XXX: incorrect with comments */ |
||
4093 | ch = file->buf_ptr[0]; |
||
4094 | while (is_space(ch) || ch == '\n') |
||
4095 | cinp(); |
||
4096 | t = ch; |
||
4097 | } |
||
4098 | if (t != '(') /* no macro subst */ |
||
4099 | return -1; |
||
4100 | |||
4101 | /* argument macro */ |
||
4102 | next_nomacro(); |
||
4103 | next_nomacro(); |
||
4104 | args = NULL; |
||
4105 | sa = s->next; |
||
4106 | /* NOTE: empty args are allowed, except if no args */ |
||
4107 | for(;;) { |
||
4108 | /* handle '()' case */ |
||
4109 | if (!args && !sa && tok == ')') |
||
4110 | break; |
||
4111 | if (!sa) |
||
4112 | error("macro '%s' used with too many args", |
||
4113 | get_tok_str(s->v, 0)); |
||
4114 | tok_str_new(&str); |
||
4115 | parlevel = 0; |
||
4116 | /* NOTE: non zero sa->t indicates VA_ARGS */ |
||
4117 | while ((parlevel > 0 || |
||
4118 | (tok != ')' && |
||
4119 | (tok != ',' || sa->type.t))) && |
||
4120 | tok != -1) { |
||
4121 | if (tok == '(') |
||
4122 | parlevel++; |
||
4123 | else if (tok == ')') |
||
4124 | parlevel--; |
||
4125 | tok_str_add2(&str, tok, &tokc); |
||
4126 | next_nomacro(); |
||
4127 | } |
||
4128 | tok_str_add(&str, 0); |
||
4129 | sym_push2(&args, sa->v & ~SYM_FIELD, sa->type.t, (int)str.str); |
||
4130 | sa = sa->next; |
||
4131 | if (tok == ')') { |
||
4132 | /* special case for gcc var args: add an empty |
||
4133 | var arg argument if it is omitted */ |
||
4134 | if (sa && sa->type.t && gnu_ext) |
||
4135 | continue; |
||
4136 | else |
||
4137 | break; |
||
4138 | } |
||
4139 | if (tok != ',') |
||
4140 | expect(","); |
||
4141 | next_nomacro(); |
||
4142 | } |
||
4143 | if (sa) { |
||
4144 | error("macro '%s' used with too few args", |
||
4145 | get_tok_str(s->v, 0)); |
||
4146 | } |
||
4147 | |||
4148 | /* now subst each arg */ |
||
4149 | mstr = macro_arg_subst(nested_list, mstr, args); |
||
4150 | /* free memory */ |
||
4151 | sa = args; |
||
4152 | while (sa) { |
||
4153 | sa1 = sa->prev; |
||
4154 | tok_str_free((int *)sa->c); |
||
4155 | sym_free(sa); |
||
4156 | sa = sa1; |
||
4157 | } |
||
4158 | mstr_allocated = 1; |
||
4159 | } |
||
4160 | sym_push2(nested_list, s->v, 0, 0); |
||
4161 | macro_subst(tok_str, nested_list, mstr, can_read_stream); |
||
4162 | /* pop nested defined symbol */ |
||
4163 | sa1 = *nested_list; |
||
4164 | *nested_list = sa1->prev; |
||
4165 | sym_free(sa1); |
||
4166 | if (mstr_allocated) |
||
4167 | tok_str_free(mstr); |
||
4168 | } |
||
4169 | return 0; |
||
4170 | } |
||
4171 | |||
4172 | /* handle the '##' operator. Return NULL if no '##' seen. Otherwise |
||
4173 | return the resulting string (which must be freed). */ |
||
4174 | static inline int *macro_twosharps(const int *macro_str) |
||
4175 | { |
||
4176 | TokenSym *ts; |
||
4177 | const int *macro_ptr1, *start_macro_ptr, *ptr, *saved_macro_ptr; |
||
4178 | int t; |
||
4179 | const char *p1, *p2; |
||
4180 | CValue cval; |
||
4181 | TokenString macro_str1; |
||
4182 | CString cstr; |
||
4183 | |||
4184 | start_macro_ptr = macro_str; |
||
4185 | /* we search the first '##' */ |
||
4186 | for(;;) { |
||
4187 | macro_ptr1 = macro_str; |
||
4188 | TOK_GET(t, macro_str, cval); |
||
4189 | /* nothing more to do if end of string */ |
||
4190 | if (t == 0) |
||
4191 | return NULL; |
||
4192 | if (*macro_str == TOK_TWOSHARPS) |
||
4193 | break; |
||
4194 | } |
||
4195 | |||
4196 | /* we saw '##', so we need more processing to handle it */ |
||
4197 | cstr_new(&cstr); |
||
4198 | tok_str_new(¯o_str1); |
||
4199 | tok = t; |
||
4200 | tokc = cval; |
||
4201 | |||
4202 | /* add all tokens seen so far */ |
||
4203 | for(ptr = start_macro_ptr; ptr < macro_ptr1;) { |
||
4204 | TOK_GET(t, ptr, cval); |
||
4205 | tok_str_add2(¯o_str1, t, &cval); |
||
4206 | } |
||
4207 | saved_macro_ptr = macro_ptr; |
||
4208 | /* XXX: get rid of the use of macro_ptr here */ |
||
4209 | macro_ptr = (int *)macro_str; |
||
4210 | for(;;) { |
||
4211 | while (*macro_ptr == TOK_TWOSHARPS) { |
||
4212 | macro_ptr++; |
||
4213 | macro_ptr1 = macro_ptr; |
||
4214 | t = *macro_ptr; |
||
4215 | if (t) { |
||
4216 | TOK_GET(t, macro_ptr, cval); |
||
4217 | /* We concatenate the two tokens if we have an |
||
4218 | identifier or a preprocessing number */ |
||
4219 | cstr_reset(&cstr); |
||
4220 | p1 = get_tok_str(tok, &tokc); |
||
4221 | cstr_cat(&cstr, p1); |
||
4222 | p2 = get_tok_str(t, &cval); |
||
4223 | cstr_cat(&cstr, p2); |
||
4224 | cstr_ccat(&cstr, '\0'); |
||
4225 | |||
4226 | if ((tok >= TOK_IDENT || tok == TOK_PPNUM) && |
||
4227 | (t >= TOK_IDENT || t == TOK_PPNUM)) { |
||
4228 | if (tok == TOK_PPNUM) { |
||
4229 | /* if number, then create a number token */ |
||
4230 | /* NOTE: no need to allocate because |
||
4231 | tok_str_add2() does it */ |
||
4232 | tokc.cstr = &cstr; |
||
4233 | } else { |
||
4234 | /* if identifier, we must do a test to |
||
4235 | validate we have a correct identifier */ |
||
4236 | if (t == TOK_PPNUM) { |
||
4237 | const char *p; |
||
4238 | int c; |
||
4239 | |||
4240 | p = p2; |
||
4241 | for(;;) { |
||
4242 | c = *p; |
||
4243 | if (c == '\0') |
||
4244 | break; |
||
4245 | p++; |
||
4246 | if (!isnum(c) && !isid(c)) |
||
4247 | goto error_pasting; |
||
4248 | } |
||
4249 | } |
||
4250 | ts = tok_alloc(cstr.data, strlen(cstr.data)); |
||
4251 | tok = ts->tok; /* modify current token */ |
||
4252 | } |
||
4253 | } else { |
||
4254 | const char *str = cstr.data; |
||
4255 | const unsigned char *q; |
||
4256 | |||
4257 | /* we look for a valid token */ |
||
4258 | /* XXX: do more extensive checks */ |
||
4259 | if (!strcmp(str, ">>=")) { |
||
4260 | tok = TOK_A_SAR; |
||
4261 | } else if (!strcmp(str, "<<=")) { |
||
4262 | tok = TOK_A_SHL; |
||
4263 | } else if (strlen(str) == 2) { |
||
4264 | /* search in two bytes table */ |
||
4265 | q = tok_two_chars; |
||
4266 | for(;;) { |
||
4267 | if (!*q) |
||
4268 | goto error_pasting; |
||
4269 | if (q[0] == str[0] && q[1] == str[1]) |
||
4270 | break; |
||
4271 | q += 3; |
||
4272 | } |
||
4273 | tok = q[2]; |
||
4274 | } else { |
||
4275 | error_pasting: |
||
4276 | /* NOTE: because get_tok_str use a static buffer, |
||
4277 | we must save it */ |
||
4278 | cstr_reset(&cstr); |
||
4279 | p1 = get_tok_str(tok, &tokc); |
||
4280 | cstr_cat(&cstr, p1); |
||
4281 | cstr_ccat(&cstr, '\0'); |
||
4282 | p2 = get_tok_str(t, &cval); |
||
4283 | warning("pasting \"%s\" and \"%s\" does not give a valid preprocessing token", cstr.data, p2); |
||
4284 | /* cannot merge tokens: just add them separately */ |
||
4285 | tok_str_add2(¯o_str1, tok, &tokc); |
||
4286 | /* XXX: free associated memory ? */ |
||
4287 | tok = t; |
||
4288 | tokc = cval; |
||
4289 | } |
||
4290 | } |
||
4291 | } |
||
4292 | } |
||
4293 | tok_str_add2(¯o_str1, tok, &tokc); |
||
4294 | next_nomacro(); |
||
4295 | if (tok == 0) |
||
4296 | break; |
||
4297 | } |
||
4298 | macro_ptr = (int *)saved_macro_ptr; |
||
4299 | cstr_free(&cstr); |
||
4300 | tok_str_add(¯o_str1, 0); |
||
4301 | return macro_str1.str; |
||
4302 | } |
||
4303 | |||
4304 | |||
4305 | /* do macro substitution of macro_str and add result to |
||
4306 | (tok_str,tok_len). 'nested_list' is the list of all macros we got |
||
4307 | inside to avoid recursing. */ |
||
4308 | static void macro_subst(TokenString *tok_str, Sym **nested_list, |
||
4309 | const int *macro_str, struct macro_level ** can_read_stream) |
||
4310 | { |
||
4311 | Sym *s; |
||
4312 | int *macro_str1; |
||
4313 | const int *ptr; |
||
4314 | int t, ret; |
||
4315 | CValue cval; |
||
4316 | struct macro_level ml; |
||
4317 | |||
4318 | /* first scan for '##' operator handling */ |
||
4319 | ptr = macro_str; |
||
4320 | macro_str1 = macro_twosharps(ptr); |
||
4321 | if (macro_str1) |
||
4322 | ptr = macro_str1; |
||
4323 | while (1) { |
||
4324 | /* NOTE: ptr == NULL can only happen if tokens are read from |
||
4325 | file stream due to a macro function call */ |
||
4326 | if (ptr == NULL) |
||
4327 | break; |
||
4328 | TOK_GET(t, ptr, cval); |
||
4329 | if (t == 0) |
||
4330 | break; |
||
4331 | s = define_find(t); |
||
4332 | if (s != NULL) { |
||
4333 | /* if nested substitution, do nothing */ |
||
4334 | if (sym_find2(*nested_list, t)) |
||
4335 | goto no_subst; |
||
4336 | ml.p = macro_ptr; |
||
4337 | if (can_read_stream) |
||
4338 | ml.prev = *can_read_stream, *can_read_stream = &ml; |
||
4339 | macro_ptr = (int *)ptr; |
||
4340 | tok = t; |
||
4341 | ret = macro_subst_tok(tok_str, nested_list, s, can_read_stream); |
||
4342 | ptr = (int *)macro_ptr; |
||
4343 | macro_ptr = ml.p; |
||
4344 | if (can_read_stream && *can_read_stream == &ml) |
||
4345 | *can_read_stream = ml.prev; |
||
4346 | if (ret != 0) |
||
4347 | goto no_subst; |
||
4348 | } else { |
||
4349 | no_subst: |
||
4350 | tok_str_add2(tok_str, t, &cval); |
||
4351 | } |
||
4352 | } |
||
4353 | if (macro_str1) |
||
4354 | tok_str_free(macro_str1); |
||
4355 | } |
||
4356 | |||
4357 | /* return next token with macro substitution */ |
||
4358 | static void next(void) |
||
4359 | { |
||
4360 | Sym *nested_list, *s; |
||
4361 | TokenString str; |
||
4362 | struct macro_level *ml; |
||
4363 | |||
4364 | redo: |
||
4365 | next_nomacro(); |
||
4366 | if (!macro_ptr) { |
||
4367 | /* if not reading from macro substituted string, then try |
||
4368 | to substitute macros */ |
||
4369 | if (tok >= TOK_IDENT && |
||
4370 | (parse_flags & PARSE_FLAG_PREPROCESS)) { |
||
4371 | s = define_find(tok); |
||
4372 | if (s) { |
||
4373 | /* we have a macro: we try to substitute */ |
||
4374 | tok_str_new(&str); |
||
4375 | nested_list = NULL; |
||
4376 | ml = NULL; |
||
4377 | if (macro_subst_tok(&str, &nested_list, s, &ml) == 0) { |
||
4378 | /* substitution done, NOTE: maybe empty */ |
||
4379 | tok_str_add(&str, 0); |
||
4380 | macro_ptr = str.str; |
||
4381 | macro_ptr_allocated = str.str; |
||
4382 | goto redo; |
||
4383 | } |
||
4384 | } |
||
4385 | } |
||
4386 | } else { |
||
4387 | if (tok == 0) { |
||
4388 | /* end of macro or end of unget buffer */ |
||
4389 | if (unget_buffer_enabled) { |
||
4390 | macro_ptr = unget_saved_macro_ptr; |
||
4391 | unget_buffer_enabled = 0; |
||
4392 | } else { |
||
4393 | /* end of macro string: free it */ |
||
4394 | tok_str_free(macro_ptr_allocated); |
||
4395 | macro_ptr = NULL; |
||
4396 | } |
||
4397 | goto redo; |
||
4398 | } |
||
4399 | } |
||
4400 | |||
4401 | /* convert preprocessor tokens into C tokens */ |
||
4402 | if (tok == TOK_PPNUM && |
||
4403 | (parse_flags & PARSE_FLAG_TOK_NUM)) { |
||
4404 | parse_number((char *)tokc.cstr->data); |
||
4405 | } |
||
4406 | } |
||
4407 | |||
4408 | /* push back current token and set current token to 'last_tok'. Only |
||
4409 | identifier case handled for labels. */ |
||
4410 | static inline void unget_tok(int last_tok) |
||
4411 | { |
||
4412 | int i, n; |
||
4413 | int *q; |
||
4414 | unget_saved_macro_ptr = macro_ptr; |
||
4415 | unget_buffer_enabled = 1; |
||
4416 | q = unget_saved_buffer; |
||
4417 | macro_ptr = q; |
||
4418 | *q++ = tok; |
||
4419 | n = tok_ext_size(tok) - 1; |
||
4420 | for(i=0;i |
||
4421 | *q++ = tokc.tab[i]; |
||
4422 | *q = 0; /* end of token string */ |
||
4423 | tok = last_tok; |
||
4424 | } |
||
4425 | |||
4426 | |||
4427 | void swap(int *p, int *q) |
||
4428 | { |
||
4429 | int t; |
||
4430 | t = *p; |
||
4431 | *p = *q; |
||
4432 | *q = t; |
||
4433 | } |
||
4434 | |||
4435 | void vsetc(CType *type, int r, CValue *vc) |
||
4436 | { |
||
4437 | int v; |
||
4438 | |||
4439 | if (vtop >= vstack + (VSTACK_SIZE - 1)) |
||
4440 | error("memory full"); |
||
4441 | /* cannot let cpu flags if other instruction are generated. Also |
||
4442 | avoid leaving VT_JMP anywhere except on the top of the stack |
||
4443 | because it would complicate the code generator. */ |
||
4444 | if (vtop >= vstack) { |
||
4445 | v = vtop->r & VT_VALMASK; |
||
4446 | if (v == VT_CMP || (v & ~1) == VT_JMP) |
||
4447 | gv(RC_INT); |
||
4448 | } |
||
4449 | vtop++; |
||
4450 | vtop->type = *type; |
||
4451 | vtop->r = r; |
||
4452 | vtop->r2 = VT_CONST; |
||
4453 | vtop->c = *vc; |
||
4454 | } |
||
4455 | |||
4456 | /* push integer constant */ |
||
4457 | void vpushi(int v) |
||
4458 | { |
||
4459 | CValue cval; |
||
4460 | cval.i = v; |
||
4461 | vsetc(&int_type, VT_CONST, &cval); |
||
4462 | } |
||
4463 | |||
4464 | /* Return a static symbol pointing to a section */ |
||
4465 | static Sym *get_sym_ref(CType *type, Section *sec, |
||
4466 | unsigned long offset, unsigned long size) |
||
4467 | { |
||
4468 | int v; |
||
4469 | Sym *sym; |
||
4470 | |||
4471 | v = anon_sym++; |
||
4472 | sym = global_identifier_push(v, type->t | VT_STATIC, 0); |
||
4473 | sym->type.ref = type->ref; |
||
4474 | sym->r = VT_CONST | VT_SYM; |
||
4475 | put_extern_sym(sym, sec, offset, size); |
||
4476 | return sym; |
||
4477 | } |
||
4478 | |||
4479 | /* push a reference to a section offset by adding a dummy symbol */ |
||
4480 | static void vpush_ref(CType *type, Section *sec, unsigned long offset, unsigned long size) |
||
4481 | { |
||
4482 | CValue cval; |
||
4483 | |||
4484 | cval.ul = 0; |
||
4485 | vsetc(type, VT_CONST | VT_SYM, &cval); |
||
4486 | vtop->sym = get_sym_ref(type, sec, offset, size); |
||
4487 | } |
||
4488 | |||
4489 | /* define a new external reference to a symbol 'v' of type 'u' */ |
||
4490 | static Sym *external_global_sym(int v, CType *type, int r) |
||
4491 | { |
||
4492 | Sym *s; |
||
4493 | |||
4494 | s = sym_find(v); |
||
4495 | if (!s) { |
||
4496 | /* push forward reference */ |
||
4497 | s = global_identifier_push(v, type->t | VT_EXTERN, 0); |
||
4498 | s->type.ref = type->ref; |
||
4499 | s->r = r | VT_CONST | VT_SYM; |
||
4500 | } |
||
4501 | return s; |
||
4502 | } |
||
4503 | |||
4504 | /* define a new external reference to a symbol 'v' of type 'u' */ |
||
4505 | static Sym *external_sym(int v, CType *type, int r) |
||
4506 | { |
||
4507 | Sym *s; |
||
4508 | |||
4509 | s = sym_find(v); |
||
4510 | if (!s) { |
||
4511 | /* push forward reference */ |
||
4512 | s = sym_push(v, type, r | VT_CONST | VT_SYM, 0); |
||
4513 | s->type.t |= VT_EXTERN; |
||
4514 | } else { |
||
4515 | if (!is_compatible_types(&s->type, type)) |
||
4516 | error("incompatible types for redefinition of '%s'", |
||
4517 | get_tok_str(v, NULL)); |
||
4518 | } |
||
4519 | return s; |
||
4520 | } |
||
4521 | |||
4522 | /* push a reference to global symbol v */ |
||
4523 | static void vpush_global_sym(CType *type, int v) |
||
4524 | { |
||
4525 | Sym *sym; |
||
4526 | CValue cval; |
||
4527 | |||
4528 | sym = external_global_sym(v, type, 0); |
||
4529 | cval.ul = 0; |
||
4530 | vsetc(type, VT_CONST | VT_SYM, &cval); |
||
4531 | vtop->sym = sym; |
||
4532 | } |
||
4533 | |||
4534 | void vset(CType *type, int r, int v) |
||
4535 | { |
||
4536 | CValue cval; |
||
4537 | |||
4538 | cval.i = v; |
||
4539 | vsetc(type, r, &cval); |
||
4540 | } |
||
4541 | |||
4542 | void vseti(int r, int v) |
||
4543 | { |
||
4544 | CType type; |
||
4545 | type.t = VT_INT; |
||
4546 | vset(&type, r, v); |
||
4547 | } |
||
4548 | |||
4549 | void vswap(void) |
||
4550 | { |
||
4551 | SValue tmp; |
||
4552 | |||
4553 | tmp = vtop[0]; |
||
4554 | vtop[0] = vtop[-1]; |
||
4555 | vtop[-1] = tmp; |
||
4556 | } |
||
4557 | |||
4558 | void vpushv(SValue *v) |
||
4559 | { |
||
4560 | if (vtop >= vstack + (VSTACK_SIZE - 1)) |
||
4561 | error("memory full"); |
||
4562 | vtop++; |
||
4563 | *vtop = *v; |
||
4564 | } |
||
4565 | |||
4566 | void vdup(void) |
||
4567 | { |
||
4568 | vpushv(vtop); |
||
4569 | } |
||
4570 | |||
4571 | /* save r to the memory stack, and mark it as being free */ |
||
4572 | void save_reg(int r) |
||
4573 | { |
||
4574 | int l, saved, size, align; |
||
4575 | SValue *p, sv; |
||
4576 | CType *type; |
||
4577 | |||
4578 | /* modify all stack values */ |
||
4579 | saved = 0; |
||
4580 | l = 0; |
||
4581 | for(p=vstack;p<=vtop;p++) { |
||
4582 | if ((p->r & VT_VALMASK) == r || |
||
4583 | (p->r2 & VT_VALMASK) == r) { |
||
4584 | /* must save value on stack if not already done */ |
||
4585 | if (!saved) { |
||
4586 | /* NOTE: must reload 'r' because r might be equal to r2 */ |
||
4587 | r = p->r & VT_VALMASK; |
||
4588 | /* store register in the stack */ |
||
4589 | type = &p->type; |
||
4590 | if ((p->r & VT_LVAL) || |
||
4591 | (!is_float(type->t) && (type->t & VT_BTYPE) != VT_LLONG)) |
||
4592 | type = &int_type; |
||
4593 | size = type_size(type, &align); |
||
4594 | loc = (loc - size) & -align; |
||
4595 | sv.type.t = type->t; |
||
4596 | sv.r = VT_LOCAL | VT_LVAL; |
||
4597 | sv.c.ul = loc; |
||
4598 | store(r, &sv); |
||
4599 | #ifdef TCC_TARGET_I386 |
||
4600 | /* x86 specific: need to pop fp register ST0 if saved */ |
||
4601 | if (r == TREG_ST0) { |
||
4602 | o(0xd9dd); /* fstp %st(1) */ |
||
4603 | } |
||
4604 | #endif |
||
4605 | /* special long long case */ |
||
4606 | if ((type->t & VT_BTYPE) == VT_LLONG) { |
||
4607 | sv.c.ul += 4; |
||
4608 | store(p->r2, &sv); |
||
4609 | } |
||
4610 | l = loc; |
||
4611 | saved = 1; |
||
4612 | } |
||
4613 | /* mark that stack entry as being saved on the stack */ |
||
4614 | if (p->r & VT_LVAL) { |
||
4615 | /* also clear the bounded flag because the |
||
4616 | relocation address of the function was stored in |
||
4617 | p->c.ul */ |
||
4618 | p->r = (p->r & ~(VT_VALMASK | VT_BOUNDED)) | VT_LLOCAL; |
||
4619 | } else { |
||
4620 | p->r = lvalue_type(p->type.t) | VT_LOCAL; |
||
4621 | } |
||
4622 | p->r2 = VT_CONST; |
||
4623 | p->c.ul = l; |
||
4624 | } |
||
4625 | } |
||
4626 | } |
||
4627 | |||
4628 | /* find a register of class 'rc2' with at most one reference on stack. |
||
4629 | * If none, call get_reg(rc) */ |
||
4630 | int get_reg_ex(int rc, int rc2) |
||
4631 | { |
||
4632 | int r; |
||
4633 | SValue *p; |
||
4634 | |||
4635 | for(r=0;r |
||
4636 | if (reg_classes[r] & rc2) { |
||
4637 | int n; |
||
4638 | n=0; |
||
4639 | for(p = vstack; p <= vtop; p++) { |
||
4640 | if ((p->r & VT_VALMASK) == r || |
||
4641 | (p->r2 & VT_VALMASK) == r) |
||
4642 | n++; |
||
4643 | } |
||
4644 | if (n <= 1) |
||
4645 | return r; |
||
4646 | } |
||
4647 | } |
||
4648 | return get_reg(rc); |
||
4649 | } |
||
4650 | |||
4651 | /* find a free register of class 'rc'. If none, save one register */ |
||
4652 | int get_reg(int rc) |
||
4653 | { |
||
4654 | int r; |
||
4655 | SValue *p; |
||
4656 | |||
4657 | /* find a free register */ |
||
4658 | for(r=0;r |
||
4659 | if (reg_classes[r] & rc) { |
||
4660 | for(p=vstack;p<=vtop;p++) { |
||
4661 | if ((p->r & VT_VALMASK) == r || |
||
4662 | (p->r2 & VT_VALMASK) == r) |
||
4663 | goto notfound; |
||
4664 | } |
||
4665 | return r; |
||
4666 | } |
||
4667 | notfound: ; |
||
4668 | } |
||
4669 | |||
4670 | /* no register left : free the first one on the stack (VERY |
||
4671 | IMPORTANT to start from the bottom to ensure that we don't |
||
4672 | spill registers used in gen_opi()) */ |
||
4673 | for(p=vstack;p<=vtop;p++) { |
||
4674 | r = p->r & VT_VALMASK; |
||
4675 | if (r < VT_CONST && (reg_classes[r] & rc)) |
||
4676 | goto save_found; |
||
4677 | /* also look at second register (if long long) */ |
||
4678 | r = p->r2 & VT_VALMASK; |
||
4679 | if (r < VT_CONST && (reg_classes[r] & rc)) { |
||
4680 | save_found: |
||
4681 | save_reg(r); |
||
4682 | return r; |
||
4683 | } |
||
4684 | } |
||
4685 | /* Should never comes here */ |
||
4686 | return -1; |
||
4687 | } |
||
4688 | |||
4689 | /* save registers up to (vtop - n) stack entry */ |
||
4690 | void save_regs(int n) |
||
4691 | { |
||
4692 | int r; |
||
4693 | SValue *p, *p1; |
||
4694 | p1 = vtop - n; |
||
4695 | for(p = vstack;p <= p1; p++) { |
||
4696 | r = p->r & VT_VALMASK; |
||
4697 | if (r < VT_CONST) { |
||
4698 | save_reg(r); |
||
4699 | } |
||
4700 | } |
||
4701 | } |
||
4702 | |||
4703 | /* move register 's' to 'r', and flush previous value of r to memory |
||
4704 | if needed */ |
||
4705 | void move_reg(int r, int s) |
||
4706 | { |
||
4707 | SValue sv; |
||
4708 | |||
4709 | if (r != s) { |
||
4710 | save_reg(r); |
||
4711 | sv.type.t = VT_INT; |
||
4712 | sv.r = s; |
||
4713 | sv.c.ul = 0; |
||
4714 | load(r, &sv); |
||
4715 | } |
||
4716 | } |
||
4717 | |||
4718 | /* get address of vtop (vtop MUST BE an lvalue) */ |
||
4719 | void gaddrof(void) |
||
4720 | { |
||
4721 | vtop->r &= ~VT_LVAL; |
||
4722 | /* tricky: if saved lvalue, then we can go back to lvalue */ |
||
4723 | if ((vtop->r & VT_VALMASK) == VT_LLOCAL) |
||
4724 | vtop->r = (vtop->r & ~(VT_VALMASK | VT_LVAL_TYPE)) | VT_LOCAL | VT_LVAL; |
||
4725 | } |
||
4726 | |||
4727 | #ifdef CONFIG_TCC_BCHECK |
||
4728 | /* generate lvalue bound code */ |
||
4729 | void gbound(void) |
||
4730 | { |
||
4731 | int lval_type; |
||
4732 | CType type1; |
||
4733 | |||
4734 | vtop->r &= ~VT_MUSTBOUND; |
||
4735 | /* if lvalue, then use checking code before dereferencing */ |
||
4736 | if (vtop->r & VT_LVAL) { |
||
4737 | /* if not VT_BOUNDED value, then make one */ |
||
4738 | if (!(vtop->r & VT_BOUNDED)) { |
||
4739 | lval_type = vtop->r & (VT_LVAL_TYPE | VT_LVAL); |
||
4740 | /* must save type because we must set it to int to get pointer */ |
||
4741 | type1 = vtop->type; |
||
4742 | vtop->type.t = VT_INT; |
||
4743 | gaddrof(); |
||
4744 | vpushi(0); |
||
4745 | gen_bounded_ptr_add(); |
||
4746 | vtop->r |= lval_type; |
||
4747 | vtop->type = type1; |
||
4748 | } |
||
4749 | /* then check for dereferencing */ |
||
4750 | gen_bounded_ptr_deref(); |
||
4751 | } |
||
4752 | } |
||
4753 | #endif |
||
4754 | |||
4755 | /* store vtop a register belonging to class 'rc'. lvalues are |
||
4756 | converted to values. Cannot be used if cannot be converted to |
||
4757 | register value (such as structures). */ |
||
4758 | int gv(int rc) |
||
4759 | { |
||
4760 | int r, r2, rc2, bit_pos, bit_size, size, align, i; |
||
4761 | unsigned long long ll; |
||
4762 | |||
4763 | /* NOTE: get_reg can modify vstack[] */ |
||
4764 | if (vtop->type.t & VT_BITFIELD) { |
||
4765 | bit_pos = (vtop->type.t >> VT_STRUCT_SHIFT) & 0x3f; |
||
4766 | bit_size = (vtop->type.t >> (VT_STRUCT_SHIFT + 6)) & 0x3f; |
||
4767 | /* remove bit field info to avoid loops */ |
||
4768 | vtop->type.t &= ~(VT_BITFIELD | (-1 << VT_STRUCT_SHIFT)); |
||
4769 | /* generate shifts */ |
||
4770 | vpushi(32 - (bit_pos + bit_size)); |
||
4771 | gen_op(TOK_SHL); |
||
4772 | vpushi(32 - bit_size); |
||
4773 | /* NOTE: transformed to SHR if unsigned */ |
||
4774 | gen_op(TOK_SAR); |
||
4775 | r = gv(rc); |
||
4776 | } else { |
||
4777 | if (is_float(vtop->type.t) && |
||
4778 | (vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) { |
||
4779 | Sym *sym; |
||
4780 | int *ptr; |
||
4781 | unsigned long offset; |
||
4782 | |||
4783 | /* XXX: unify with initializers handling ? */ |
||
4784 | /* CPUs usually cannot use float constants, so we store them |
||
4785 | generically in data segment */ |
||
4786 | size = type_size(&vtop->type, &align); |
||
4787 | offset = (data_section->data_offset + align - 1) & -align; |
||
4788 | data_section->data_offset = offset; |
||
4789 | /* XXX: not portable yet */ |
||
4790 | ptr = section_ptr_add(data_section, size); |
||
4791 | size = size >> 2; |
||
4792 | for(i=0;i |
||
4793 | ptr[i] = vtop->c.tab[i]; |
||
4794 | sym = get_sym_ref(&vtop->type, data_section, offset, size << 2); |
||
4795 | vtop->r |= VT_LVAL | VT_SYM; |
||
4796 | vtop->sym = sym; |
||
4797 | vtop->c.ul = 0; |
||
4798 | } |
||
4799 | #ifdef CONFIG_TCC_BCHECK |
||
4800 | if (vtop->r & VT_MUSTBOUND) |
||
4801 | gbound(); |
||
4802 | #endif |
||
4803 | |||
4804 | r = vtop->r & VT_VALMASK; |
||
4805 | /* need to reload if: |
||
4806 | - constant |
||
4807 | - lvalue (need to dereference pointer) |
||
4808 | - already a register, but not in the right class */ |
||
4809 | if (r >= VT_CONST || |
||
4810 | (vtop->r & VT_LVAL) || |
||
4811 | !(reg_classes[r] & rc) || |
||
4812 | ((vtop->type.t & VT_BTYPE) == VT_LLONG && |
||
4813 | !(reg_classes[vtop->r2] & rc))) { |
||
4814 | r = get_reg(rc); |
||
4815 | if ((vtop->type.t & VT_BTYPE) == VT_LLONG) { |
||
4816 | /* two register type load : expand to two words |
||
4817 | temporarily */ |
||
4818 | if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) { |
||
4819 | /* load constant */ |
||
4820 | ll = vtop->c.ull; |
||
4821 | vtop->c.ui = ll; /* first word */ |
||
4822 | load(r, vtop); |
||
4823 | vtop->r = r; /* save register value */ |
||
4824 | vpushi(ll >> 32); /* second word */ |
||
4825 | } else if (r >= VT_CONST || /* XXX: test to VT_CONST incorrect ? */ |
||
4826 | (vtop->r & VT_LVAL)) { |
||
4827 | /* We do not want to modifier the long long |
||
4828 | pointer here, so the safest (and less |
||
4829 | efficient) is to save all the other registers |
||
4830 | in the stack. XXX: totally inefficient. */ |
||
4831 | save_regs(1); |
||
4832 | /* load from memory */ |
||
4833 | load(r, vtop); |
||
4834 | vdup(); |
||
4835 | vtop[-1].r = r; /* save register value */ |
||
4836 | /* increment pointer to get second word */ |
||
4837 | vtop->type.t = VT_INT; |
||
4838 | gaddrof(); |
||
4839 | vpushi(4); |
||
4840 | gen_op('+'); |
||
4841 | vtop->r |= VT_LVAL; |
||
4842 | } else { |
||
4843 | /* move registers */ |
||
4844 | load(r, vtop); |
||
4845 | vdup(); |
||
4846 | vtop[-1].r = r; /* save register value */ |
||
4847 | vtop->r = vtop[-1].r2; |
||
4848 | } |
||
4849 | /* allocate second register */ |
||
4850 | rc2 = RC_INT; |
||
4851 | if (rc == RC_IRET) |
||
4852 | rc2 = RC_LRET; |
||
4853 | r2 = get_reg(rc2); |
||
4854 | load(r2, vtop); |
||
4855 | vpop(); |
||
4856 | /* write second register */ |
||
4857 | vtop->r2 = r2; |
||
4858 | } else if ((vtop->r & VT_LVAL) && !is_float(vtop->type.t)) { |
||
4859 | int t1, t; |
||
4860 | /* lvalue of scalar type : need to use lvalue type |
||
4861 | because of possible cast */ |
||
4862 | t = vtop->type.t; |
||
4863 | t1 = t; |
||
4864 | /* compute memory access type */ |
||
4865 | if (vtop->r & VT_LVAL_BYTE) |
||
4866 | t = VT_BYTE; |
||
4867 | else if (vtop->r & VT_LVAL_SHORT) |
||
4868 | t = VT_SHORT; |
||
4869 | if (vtop->r & VT_LVAL_UNSIGNED) |
||
4870 | t |= VT_UNSIGNED; |
||
4871 | vtop->type.t = t; |
||
4872 | load(r, vtop); |
||
4873 | /* restore wanted type */ |
||
4874 | vtop->type.t = t1; |
||
4875 | } else { |
||
4876 | /* one register type load */ |
||
4877 | load(r, vtop); |
||
4878 | } |
||
4879 | } |
||
4880 | vtop->r = r; |
||
4881 | #ifdef TCC_TARGET_C67 |
||
4882 | /* uses register pairs for doubles */ |
||
4883 | if ((vtop->type.t & VT_BTYPE) == VT_DOUBLE) |
||
4884 | vtop->r2 = r+1; |
||
4885 | #endif |
||
4886 | } |
||
4887 | return r; |
||
4888 | } |
||
4889 | |||
4890 | /* generate vtop[-1] and vtop[0] in resp. classes rc1 and rc2 */ |
||
4891 | void gv2(int rc1, int rc2) |
||
4892 | { |
||
4893 | int v; |
||
4894 | |||
4895 | /* generate more generic register first. But VT_JMP or VT_CMP |
||
4896 | values must be generated first in all cases to avoid possible |
||
4897 | reload errors */ |
||
4898 | v = vtop[0].r & VT_VALMASK; |
||
4899 | if (v != VT_CMP && (v & ~1) != VT_JMP && rc1 <= rc2) { |
||
4900 | vswap(); |
||
4901 | gv(rc1); |
||
4902 | vswap(); |
||
4903 | gv(rc2); |
||
4904 | /* test if reload is needed for first register */ |
||
4905 | if ((vtop[-1].r & VT_VALMASK) >= VT_CONST) { |
||
4906 | vswap(); |
||
4907 | gv(rc1); |
||
4908 | vswap(); |
||
4909 | } |
||
4910 | } else { |
||
4911 | gv(rc2); |
||
4912 | vswap(); |
||
4913 | gv(rc1); |
||
4914 | vswap(); |
||
4915 | /* test if reload is needed for first register */ |
||
4916 | if ((vtop[0].r & VT_VALMASK) >= VT_CONST) { |
||
4917 | gv(rc2); |
||
4918 | } |
||
4919 | } |
||
4920 | } |
||
4921 | |||
4922 | /* expand long long on stack in two int registers */ |
||
4923 | void lexpand(void) |
||
4924 | { |
||
4925 | int u; |
||
4926 | |||
4927 | u = vtop->type.t & VT_UNSIGNED; |
||
4928 | gv(RC_INT); |
||
4929 | vdup(); |
||
4930 | vtop[0].r = vtop[-1].r2; |
||
4931 | vtop[0].r2 = VT_CONST; |
||
4932 | vtop[-1].r2 = VT_CONST; |
||
4933 | vtop[0].type.t = VT_INT | u; |
||
4934 | vtop[-1].type.t = VT_INT | u; |
||
4935 | } |
||
4936 | |||
4937 | #ifdef TCC_TARGET_ARM |
||
4938 | /* expand long long on stack */ |
||
4939 | void lexpand_nr(void) |
||
4940 | { |
||
4941 | int u,v; |
||
4942 | |||
4943 | u = vtop->type.t & VT_UNSIGNED; |
||
4944 | vdup(); |
||
4945 | vtop->r2 = VT_CONST; |
||
4946 | vtop->type.t = VT_INT | u; |
||
4947 | v=vtop[-1].r & (VT_VALMASK | VT_LVAL); |
||
4948 | if (v == VT_CONST) { |
||
4949 | vtop[-1].c.ui = vtop->c.ull; |
||
4950 | vtop->c.ui = vtop->c.ull >> 32; |
||
4951 | vtop->r = VT_CONST; |
||
4952 | } else if (v == (VT_LVAL|VT_CONST) || v == (VT_LVAL|VT_LOCAL)) { |
||
4953 | vtop->c.ui += 4; |
||
4954 | vtop->r = vtop[-1].r; |
||
4955 | } else if (v > VT_CONST) { |
||
4956 | vtop--; |
||
4957 | lexpand(); |
||
4958 | } else |
||
4959 | vtop->r = vtop[-1].r2; |
||
4960 | vtop[-1].r2 = VT_CONST; |
||
4961 | vtop[-1].type.t = VT_INT | u; |
||
4962 | } |
||
4963 | #endif |
||
4964 | |||
4965 | /* build a long long from two ints */ |
||
4966 | void lbuild(int t) |
||
4967 | { |
||
4968 | gv2(RC_INT, RC_INT); |
||
4969 | vtop[-1].r2 = vtop[0].r; |
||
4970 | vtop[-1].type.t = t; |
||
4971 | vpop(); |
||
4972 | } |
||
4973 | |||
4974 | /* rotate n first stack elements to the bottom |
||
4975 | I1 ... In -> I2 ... In I1 [top is right] |
||
4976 | */ |
||
4977 | void vrotb(int n) |
||
4978 | { |
||
4979 | int i; |
||
4980 | SValue tmp; |
||
4981 | |||
4982 | tmp = vtop[-n + 1]; |
||
4983 | for(i=-n+1;i!=0;i++) |
||
4984 | vtop[i] = vtop[i+1]; |
||
4985 | vtop[0] = tmp; |
||
4986 | } |
||
4987 | |||
4988 | /* rotate n first stack elements to the top |
||
4989 | I1 ... In -> In I1 ... I(n-1) [top is right] |
||
4990 | */ |
||
4991 | void vrott(int n) |
||
4992 | { |
||
4993 | int i; |
||
4994 | SValue tmp; |
||
4995 | |||
4996 | tmp = vtop[0]; |
||
4997 | for(i = 0;i < n - 1; i++) |
||
4998 | vtop[-i] = vtop[-i - 1]; |
||
4999 | vtop[-n + 1] = tmp; |
||
5000 | } |
||
5001 | |||
5002 | #ifdef TCC_TARGET_ARM |
||
5003 | /* like vrott but in other direction |
||
5004 | In ... I1 -> I(n-1) ... I1 In [top is right] |
||
5005 | */ |
||
5006 | void vnrott(int n) |
||
5007 | { |
||
5008 | int i; |
||
5009 | SValue tmp; |
||
5010 | |||
5011 | tmp = vtop[-n + 1]; |
||
5012 | for(i = n - 1; i > 0; i--) |
||
5013 | vtop[-i] = vtop[-i + 1]; |
||
5014 | vtop[0] = tmp; |
||
5015 | } |
||
5016 | #endif |
||
5017 | |||
5018 | /* pop stack value */ |
||
5019 | void vpop(void) |
||
5020 | { |
||
5021 | int v; |
||
5022 | v = vtop->r & VT_VALMASK; |
||
5023 | #ifdef TCC_TARGET_I386 |
||
5024 | /* for x86, we need to pop the FP stack */ |
||
5025 | if (v == TREG_ST0 && !nocode_wanted) { |
||
5026 | o(0xd9dd); /* fstp %st(1) */ |
||
5027 | } else |
||
5028 | #endif |
||
5029 | if (v == VT_JMP || v == VT_JMPI) { |
||
5030 | /* need to put correct jump if && or || without test */ |
||
5031 | gsym(vtop->c.ul); |
||
5032 | } |
||
5033 | vtop--; |
||
5034 | } |
||
5035 | |||
5036 | /* convert stack entry to register and duplicate its value in another |
||
5037 | register */ |
||
5038 | void gv_dup(void) |
||
5039 | { |
||
5040 | int rc, t, r, r1; |
||
5041 | SValue sv; |
||
5042 | |||
5043 | t = vtop->type.t; |
||
5044 | if ((t & VT_BTYPE) == VT_LLONG) { |
||
5045 | lexpand(); |
||
5046 | gv_dup(); |
||
5047 | vswap(); |
||
5048 | vrotb(3); |
||
5049 | gv_dup(); |
||
5050 | vrotb(4); |
||
5051 | /* stack: H L L1 H1 */ |
||
5052 | lbuild(t); |
||
5053 | vrotb(3); |
||
5054 | vrotb(3); |
||
5055 | vswap(); |
||
5056 | lbuild(t); |
||
5057 | vswap(); |
||
5058 | } else { |
||
5059 | /* duplicate value */ |
||
5060 | rc = RC_INT; |
||
5061 | sv.type.t = VT_INT; |
||
5062 | if (is_float(t)) { |
||
5063 | rc = RC_FLOAT; |
||
5064 | sv.type.t = t; |
||
5065 | } |
||
5066 | r = gv(rc); |
||
5067 | r1 = get_reg(rc); |
||
5068 | sv.r = r; |
||
5069 | sv.c.ul = 0; |
||
5070 | load(r1, &sv); /* move r to r1 */ |
||
5071 | vdup(); |
||
5072 | /* duplicates value */ |
||
5073 | vtop->r = r1; |
||
5074 | } |
||
5075 | } |
||
5076 | |||
5077 | /* generate CPU independent (unsigned) long long operations */ |
||
5078 | void gen_opl(int op) |
||
5079 | { |
||
5080 | int t, a, b, op1, c, i; |
||
5081 | int func; |
||
5082 | SValue tmp; |
||
5083 | |||
5084 | switch(op) { |
||
5085 | case '/': |
||
5086 | case TOK_PDIV: |
||
5087 | func = TOK___divdi3; |
||
5088 | goto gen_func; |
||
5089 | case TOK_UDIV: |
||
5090 | func = TOK___udivdi3; |
||
5091 | goto gen_func; |
||
5092 | case '%': |
||
5093 | func = TOK___moddi3; |
||
5094 | goto gen_func; |
||
5095 | case TOK_UMOD: |
||
5096 | func = TOK___umoddi3; |
||
5097 | gen_func: |
||
5098 | /* call generic long long function */ |
||
5099 | vpush_global_sym(&func_old_type, func); |
||
5100 | vrott(3); |
||
5101 | gfunc_call(2); |
||
5102 | vpushi(0); |
||
5103 | vtop->r = REG_IRET; |
||
5104 | vtop->r2 = REG_LRET; |
||
5105 | break; |
||
5106 | case '^': |
||
5107 | case '&': |
||
5108 | case '|': |
||
5109 | case '*': |
||
5110 | case '+': |
||
5111 | case '-': |
||
5112 | t = vtop->type.t; |
||
5113 | vswap(); |
||
5114 | lexpand(); |
||
5115 | vrotb(3); |
||
5116 | lexpand(); |
||
5117 | /* stack: L1 H1 L2 H2 */ |
||
5118 | tmp = vtop[0]; |
||
5119 | vtop[0] = vtop[-3]; |
||
5120 | vtop[-3] = tmp; |
||
5121 | tmp = vtop[-2]; |
||
5122 | vtop[-2] = vtop[-3]; |
||
5123 | vtop[-3] = tmp; |
||
5124 | vswap(); |
||
5125 | /* stack: H1 H2 L1 L2 */ |
||
5126 | if (op == '*') { |
||
5127 | vpushv(vtop - 1); |
||
5128 | vpushv(vtop - 1); |
||
5129 | gen_op(TOK_UMULL); |
||
5130 | lexpand(); |
||
5131 | /* stack: H1 H2 L1 L2 ML MH */ |
||
5132 | for(i=0;i<4;i++) |
||
5133 | vrotb(6); |
||
5134 | /* stack: ML MH H1 H2 L1 L2 */ |
||
5135 | tmp = vtop[0]; |
||
5136 | vtop[0] = vtop[-2]; |
||
5137 | vtop[-2] = tmp; |
||
5138 | /* stack: ML MH H1 L2 H2 L1 */ |
||
5139 | gen_op('*'); |
||
5140 | vrotb(3); |
||
5141 | vrotb(3); |
||
5142 | gen_op('*'); |
||
5143 | /* stack: ML MH M1 M2 */ |
||
5144 | gen_op('+'); |
||
5145 | gen_op('+'); |
||
5146 | } else if (op == '+' || op == '-') { |
||
5147 | /* XXX: add non carry method too (for MIPS or alpha) */ |
||
5148 | if (op == '+') |
||
5149 | op1 = TOK_ADDC1; |
||
5150 | else |
||
5151 | op1 = TOK_SUBC1; |
||
5152 | gen_op(op1); |
||
5153 | /* stack: H1 H2 (L1 op L2) */ |
||
5154 | vrotb(3); |
||
5155 | vrotb(3); |
||
5156 | gen_op(op1 + 1); /* TOK_xxxC2 */ |
||
5157 | } else { |
||
5158 | gen_op(op); |
||
5159 | /* stack: H1 H2 (L1 op L2) */ |
||
5160 | vrotb(3); |
||
5161 | vrotb(3); |
||
5162 | /* stack: (L1 op L2) H1 H2 */ |
||
5163 | gen_op(op); |
||
5164 | /* stack: (L1 op L2) (H1 op H2) */ |
||
5165 | } |
||
5166 | /* stack: L H */ |
||
5167 | lbuild(t); |
||
5168 | break; |
||
5169 | case TOK_SAR: |
||
5170 | case TOK_SHR: |
||
5171 | case TOK_SHL: |
||
5172 | if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) { |
||
5173 | t = vtop[-1].type.t; |
||
5174 | vswap(); |
||
5175 | lexpand(); |
||
5176 | vrotb(3); |
||
5177 | /* stack: L H shift */ |
||
5178 | c = (int)vtop->c.i; |
||
5179 | /* constant: simpler */ |
||
5180 | /* NOTE: all comments are for SHL. the other cases are |
||
5181 | done by swaping words */ |
||
5182 | vpop(); |
||
5183 | if (op != TOK_SHL) |
||
5184 | vswap(); |
||
5185 | if (c >= 32) { |
||
5186 | /* stack: L H */ |
||
5187 | vpop(); |
||
5188 | if (c > 32) { |
||
5189 | vpushi(c - 32); |
||
5190 | gen_op(op); |
||
5191 | } |
||
5192 | if (op != TOK_SAR) { |
||
5193 | vpushi(0); |
||
5194 | } else { |
||
5195 | gv_dup(); |
||
5196 | vpushi(31); |
||
5197 | gen_op(TOK_SAR); |
||
5198 | } |
||
5199 | vswap(); |
||
5200 | } else { |
||
5201 | vswap(); |
||
5202 | gv_dup(); |
||
5203 | /* stack: H L L */ |
||
5204 | vpushi(c); |
||
5205 | gen_op(op); |
||
5206 | vswap(); |
||
5207 | vpushi(32 - c); |
||
5208 | if (op == TOK_SHL) |
||
5209 | gen_op(TOK_SHR); |
||
5210 | else |
||
5211 | gen_op(TOK_SHL); |
||
5212 | vrotb(3); |
||
5213 | /* stack: L L H */ |
||
5214 | vpushi(c); |
||
5215 | if (op == TOK_SHL) |
||
5216 | gen_op(TOK_SHL); |
||
5217 | else |
||
5218 | gen_op(TOK_SHR); |
||
5219 | gen_op('|'); |
||
5220 | } |
||
5221 | if (op != TOK_SHL) |
||
5222 | vswap(); |
||
5223 | lbuild(t); |
||
5224 | } else { |
||
5225 | /* XXX: should provide a faster fallback on x86 ? */ |
||
5226 | switch(op) { |
||
5227 | case TOK_SAR: |
||
5228 | func = TOK___sardi3; |
||
5229 | goto gen_func; |
||
5230 | case TOK_SHR: |
||
5231 | func = TOK___shrdi3; |
||
5232 | goto gen_func; |
||
5233 | case TOK_SHL: |
||
5234 | func = TOK___shldi3; |
||
5235 | goto gen_func; |
||
5236 | } |
||
5237 | } |
||
5238 | break; |
||
5239 | default: |
||
5240 | /* compare operations */ |
||
5241 | t = vtop->type.t; |
||
5242 | vswap(); |
||
5243 | lexpand(); |
||
5244 | vrotb(3); |
||
5245 | lexpand(); |
||
5246 | /* stack: L1 H1 L2 H2 */ |
||
5247 | tmp = vtop[-1]; |
||
5248 | vtop[-1] = vtop[-2]; |
||
5249 | vtop[-2] = tmp; |
||
5250 | /* stack: L1 L2 H1 H2 */ |
||
5251 | /* compare high */ |
||
5252 | op1 = op; |
||
5253 | /* when values are equal, we need to compare low words. since |
||
5254 | the jump is inverted, we invert the test too. */ |
||
5255 | if (op1 == TOK_LT) |
||
5256 | op1 = TOK_LE; |
||
5257 | else if (op1 == TOK_GT) |
||
5258 | op1 = TOK_GE; |
||
5259 | else if (op1 == TOK_ULT) |
||
5260 | op1 = TOK_ULE; |
||
5261 | else if (op1 == TOK_UGT) |
||
5262 | op1 = TOK_UGE; |
||
5263 | a = 0; |
||
5264 | b = 0; |
||
5265 | gen_op(op1); |
||
5266 | if (op1 != TOK_NE) { |
||
5267 | a = gtst(1, 0); |
||
5268 | } |
||
5269 | if (op != TOK_EQ) { |
||
5270 | /* generate non equal test */ |
||
5271 | /* XXX: NOT PORTABLE yet */ |
||
5272 | if (a == 0) { |
||
5273 | b = gtst(0, 0); |
||
5274 | } else { |
||
5275 | #if defined(TCC_TARGET_I386) |
||
5276 | b = psym(0x850f, 0); |
||
5277 | #elif defined(TCC_TARGET_ARM) |
||
5278 | b = ind; |
||
5279 | o(0x1A000000 | encbranch(ind, 0, 1)); |
||
5280 | #elif defined(TCC_TARGET_C67) |
||
5281 | error("not implemented"); |
||
5282 | #else |
||
5283 | #error not supported |
||
5284 | #endif |
||
5285 | } |
||
5286 | } |
||
5287 | /* compare low. Always unsigned */ |
||
5288 | op1 = op; |
||
5289 | if (op1 == TOK_LT) |
||
5290 | op1 = TOK_ULT; |
||
5291 | else if (op1 == TOK_LE) |
||
5292 | op1 = TOK_ULE; |
||
5293 | else if (op1 == TOK_GT) |
||
5294 | op1 = TOK_UGT; |
||
5295 | else if (op1 == TOK_GE) |
||
5296 | op1 = TOK_UGE; |
||
5297 | gen_op(op1); |
||
5298 | a = gtst(1, a); |
||
5299 | gsym(b); |
||
5300 | vseti(VT_JMPI, a); |
||
5301 | break; |
||
5302 | } |
||
5303 | } |
||
5304 | |||
5305 | /* handle integer constant optimizations and various machine |
||
5306 | independent opt */ |
||
5307 | void gen_opic(int op) |
||
5308 | { |
||
5309 | int fc, c1, c2, n; |
||
5310 | SValue *v1, *v2; |
||
5311 | |||
5312 | v1 = vtop - 1; |
||
5313 | v2 = vtop; |
||
5314 | /* currently, we cannot do computations with forward symbols */ |
||
5315 | c1 = (v1->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; |
||
5316 | c2 = (v2->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; |
||
5317 | if (c1 && c2) { |
||
5318 | fc = v2->c.i; |
||
5319 | switch(op) { |
||
5320 | case '+': v1->c.i += fc; break; |
||
5321 | case '-': v1->c.i -= fc; break; |
||
5322 | case '&': v1->c.i &= fc; break; |
||
5323 | case '^': v1->c.i ^= fc; break; |
||
5324 | case '|': v1->c.i |= fc; break; |
||
5325 | case '*': v1->c.i *= fc; break; |
||
5326 | |||
5327 | case TOK_PDIV: |
||
5328 | case '/': |
||
5329 | case '%': |
||
5330 | case TOK_UDIV: |
||
5331 | case TOK_UMOD: |
||
5332 | /* if division by zero, generate explicit division */ |
||
5333 | if (fc == 0) { |
||
5334 | if (const_wanted) |
||
5335 | error("division by zero in constant"); |
||
5336 | goto general_case; |
||
5337 | } |
||
5338 | switch(op) { |
||
5339 | default: v1->c.i /= fc; break; |
||
5340 | case '%': v1->c.i %= fc; break; |
||
5341 | case TOK_UDIV: v1->c.i = (unsigned)v1->c.i / fc; break; |
||
5342 | case TOK_UMOD: v1->c.i = (unsigned)v1->c.i % fc; break; |
||
5343 | } |
||
5344 | break; |
||
5345 | case TOK_SHL: v1->c.i <<= fc; break; |
||
5346 | case TOK_SHR: v1->c.i = (unsigned)v1->c.i >> fc; break; |
||
5347 | case TOK_SAR: v1->c.i >>= fc; break; |
||
5348 | /* tests */ |
||
5349 | case TOK_ULT: v1->c.i = (unsigned)v1->c.i < (unsigned)fc; break; |
||
5350 | case TOK_UGE: v1->c.i = (unsigned)v1->c.i >= (unsigned)fc; break; |
||
5351 | case TOK_EQ: v1->c.i = v1->c.i == fc; break; |
||
5352 | case TOK_NE: v1->c.i = v1->c.i != fc; break; |
||
5353 | case TOK_ULE: v1->c.i = (unsigned)v1->c.i <= (unsigned)fc; break; |
||
5354 | case TOK_UGT: v1->c.i = (unsigned)v1->c.i > (unsigned)fc; break; |
||
5355 | case TOK_LT: v1->c.i = v1->c.i < fc; break; |
||
5356 | case TOK_GE: v1->c.i = v1->c.i >= fc; break; |
||
5357 | case TOK_LE: v1->c.i = v1->c.i <= fc; break; |
||
5358 | case TOK_GT: v1->c.i = v1->c.i > fc; break; |
||
5359 | /* logical */ |
||
5360 | case TOK_LAND: v1->c.i = v1->c.i && fc; break; |
||
5361 | case TOK_LOR: v1->c.i = v1->c.i || fc; break; |
||
5362 | default: |
||
5363 | goto general_case; |
||
5364 | } |
||
5365 | vtop--; |
||
5366 | } else { |
||
5367 | /* if commutative ops, put c2 as constant */ |
||
5368 | if (c1 && (op == '+' || op == '&' || op == '^' || |
||
5369 | op == '|' || op == '*')) { |
||
5370 | vswap(); |
||
5371 | swap(&c1, &c2); |
||
5372 | } |
||
5373 | fc = vtop->c.i; |
||
5374 | if (c2 && (((op == '*' || op == '/' || op == TOK_UDIV || |
||
5375 | op == TOK_PDIV) && |
||
5376 | fc == 1) || |
||
5377 | ((op == '+' || op == '-' || op == '|' || op == '^' || |
||
5378 | op == TOK_SHL || op == TOK_SHR || op == TOK_SAR) && |
||
5379 | fc == 0) || |
||
5380 | (op == '&' && |
||
5381 | fc == -1))) { |
||
5382 | /* nothing to do */ |
||
5383 | vtop--; |
||
5384 | } else if (c2 && (op == '*' || op == TOK_PDIV || op == TOK_UDIV)) { |
||
5385 | /* try to use shifts instead of muls or divs */ |
||
5386 | if (fc > 0 && (fc & (fc - 1)) == 0) { |
||
5387 | n = -1; |
||
5388 | while (fc) { |
||
5389 | fc >>= 1; |
||
5390 | n++; |
||
5391 | } |
||
5392 | vtop->c.i = n; |
||
5393 | if (op == '*') |
||
5394 | op = TOK_SHL; |
||
5395 | else if (op == TOK_PDIV) |
||
5396 | op = TOK_SAR; |
||
5397 | else |
||
5398 | op = TOK_SHR; |
||
5399 | } |
||
5400 | goto general_case; |
||
5401 | } else if (c2 && (op == '+' || op == '-') && |
||
5402 | (vtop[-1].r & (VT_VALMASK | VT_LVAL | VT_SYM)) == |
||
5403 | (VT_CONST | VT_SYM)) { |
||
5404 | /* symbol + constant case */ |
||
5405 | if (op == '-') |
||
5406 | fc = -fc; |
||
5407 | vtop--; |
||
5408 | vtop->c.i += fc; |
||
5409 | } else { |
||
5410 | general_case: |
||
5411 | if (!nocode_wanted) { |
||
5412 | /* call low level op generator */ |
||
5413 | gen_opi(op); |
||
5414 | } else { |
||
5415 | vtop--; |
||
5416 | } |
||
5417 | } |
||
5418 | } |
||
5419 | } |
||
5420 | |||
5421 | /* generate a floating point operation with constant propagation */ |
||
5422 | void gen_opif(int op) |
||
5423 | { |
||
5424 | int c1, c2; |
||
5425 | SValue *v1, *v2; |
||
5426 | long double f1, f2; |
||
5427 | |||
5428 | v1 = vtop - 1; |
||
5429 | v2 = vtop; |
||
5430 | /* currently, we cannot do computations with forward symbols */ |
||
5431 | c1 = (v1->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; |
||
5432 | c2 = (v2->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; |
||
5433 | if (c1 && c2) { |
||
5434 | if (v1->type.t == VT_FLOAT) { |
||
5435 | f1 = v1->c.f; |
||
5436 | f2 = v2->c.f; |
||
5437 | } else if (v1->type.t == VT_DOUBLE) { |
||
5438 | f1 = v1->c.d; |
||
5439 | f2 = v2->c.d; |
||
5440 | } else { |
||
5441 | f1 = v1->c.ld; |
||
5442 | f2 = v2->c.ld; |
||
5443 | } |
||
5444 | |||
5445 | /* NOTE: we only do constant propagation if finite number (not |
||
5446 | NaN or infinity) (ANSI spec) */ |
||
5447 | if (!ieee_finite(f1) || !ieee_finite(f2)) |
||
5448 | goto general_case; |
||
5449 | |||
5450 | switch(op) { |
||
5451 | case '+': f1 += f2; break; |
||
5452 | case '-': f1 -= f2; break; |
||
5453 | case '*': f1 *= f2; break; |
||
5454 | case '/': |
||
5455 | if (f2 == 0.0) { |
||
5456 | if (const_wanted) |
||
5457 | error("division by zero in constant"); |
||
5458 | goto general_case; |
||
5459 | } |
||
5460 | f1 /= f2; |
||
5461 | break; |
||
5462 | /* XXX: also handles tests ? */ |
||
5463 | default: |
||
5464 | goto general_case; |
||
5465 | } |
||
5466 | /* XXX: overflow test ? */ |
||
5467 | if (v1->type.t == VT_FLOAT) { |
||
5468 | v1->c.f = f1; |
||
5469 | } else if (v1->type.t == VT_DOUBLE) { |
||
5470 | v1->c.d = f1; |
||
5471 | } else { |
||
5472 | v1->c.ld = f1; |
||
5473 | } |
||
5474 | vtop--; |
||
5475 | } else { |
||
5476 | general_case: |
||
5477 | if (!nocode_wanted) { |
||
5478 | gen_opf(op); |
||
5479 | } else { |
||
5480 | vtop--; |
||
5481 | } |
||
5482 | } |
||
5483 | } |
||
5484 | |||
5485 | static int pointed_size(CType *type) |
||
5486 | { |
||
5487 | int align; |
||
5488 | return type_size(pointed_type(type), &align); |
||
5489 | } |
||
5490 | |||
5491 | static inline int is_null_pointer(SValue *p) |
||
5492 | { |
||
5493 | if ((p->r & (VT_VALMASK | VT_LVAL | VT_SYM)) != VT_CONST) |
||
5494 | return 0; |
||
5495 | return ((p->type.t & VT_BTYPE) == VT_INT && p->c.i == 0) || |
||
5496 | ((p->type.t & VT_BTYPE) == VT_LLONG && p->c.ll == 0); |
||
5497 | } |
||
5498 | |||
5499 | static inline int is_integer_btype(int bt) |
||
5500 | { |
||
5501 | return (bt == VT_BYTE || bt == VT_SHORT || |
||
5502 | bt == VT_INT || bt == VT_LLONG); |
||
5503 | } |
||
5504 | |||
5505 | /* check types for comparison or substraction of pointers */ |
||
5506 | static void check_comparison_pointer_types(SValue *p1, SValue *p2, int op) |
||
5507 | { |
||
5508 | CType *type1, *type2, tmp_type1, tmp_type2; |
||
5509 | int bt1, bt2; |
||
5510 | |||
5511 | /* null pointers are accepted for all comparisons as gcc */ |
||
5512 | if (is_null_pointer(p1) || is_null_pointer(p2)) |
||
5513 | return; |
||
5514 | type1 = &p1->type; |
||
5515 | type2 = &p2->type; |
||
5516 | bt1 = type1->t & VT_BTYPE; |
||
5517 | bt2 = type2->t & VT_BTYPE; |
||
5518 | /* accept comparison between pointer and integer with a warning */ |
||
5519 | if ((is_integer_btype(bt1) || is_integer_btype(bt2)) && op != '-') { |
||
5520 | warning("comparison between pointer and integer"); |
||
5521 | return; |
||
5522 | } |
||
5523 | |||
5524 | /* both must be pointers or implicit function pointers */ |
||
5525 | if (bt1 == VT_PTR) { |
||
5526 | type1 = pointed_type(type1); |
||
5527 | } else if (bt1 != VT_FUNC) |
||
5528 | goto invalid_operands; |
||
5529 | |||
5530 | if (bt2 == VT_PTR) { |
||
5531 | type2 = pointed_type(type2); |
||
5532 | } else if (bt2 != VT_FUNC) { |
||
5533 | invalid_operands: |
||
5534 | error("invalid operands to binary %s", get_tok_str(op, NULL)); |
||
5535 | } |
||
5536 | if ((type1->t & VT_BTYPE) == VT_VOID || |
||
5537 | (type2->t & VT_BTYPE) == VT_VOID) |
||
5538 | return; |
||
5539 | tmp_type1 = *type1; |
||
5540 | tmp_type2 = *type2; |
||
5541 | tmp_type1.t &= ~(VT_UNSIGNED | VT_CONSTANT | VT_VOLATILE); |
||
5542 | tmp_type2.t &= ~(VT_UNSIGNED | VT_CONSTANT | VT_VOLATILE); |
||
5543 | if (!is_compatible_types(&tmp_type1, &tmp_type2)) { |
||
5544 | /* gcc-like error if '-' is used */ |
||
5545 | if (op == '-') |
||
5546 | goto invalid_operands; |
||
5547 | else |
||
5548 | warning("comparison of distinct pointer types lacks a cast"); |
||
5549 | } |
||
5550 | } |
||
5551 | |||
5552 | /* generic gen_op: handles types problems */ |
||
5553 | void gen_op(int op) |
||
5554 | { |
||
5555 | int u, t1, t2, bt1, bt2, t; |
||
5556 | CType type1; |
||
5557 | |||
5558 | t1 = vtop[-1].type.t; |
||
5559 | t2 = vtop[0].type.t; |
||
5560 | bt1 = t1 & VT_BTYPE; |
||
5561 | bt2 = t2 & VT_BTYPE; |
||
5562 | |||
5563 | if (bt1 == VT_PTR || bt2 == VT_PTR) { |
||
5564 | /* at least one operand is a pointer */ |
||
5565 | /* relationnal op: must be both pointers */ |
||
5566 | if (op >= TOK_ULT && op <= TOK_GT) { |
||
5567 | check_comparison_pointer_types(vtop - 1, vtop, op); |
||
5568 | /* pointers are handled are unsigned */ |
||
5569 | t = VT_INT | VT_UNSIGNED; |
||
5570 | goto std_op; |
||
5571 | } |
||
5572 | /* if both pointers, then it must be the '-' op */ |
||
5573 | if (bt1 == VT_PTR && bt2 == VT_PTR) { |
||
5574 | if (op != '-') |
||
5575 | error("cannot use pointers here"); |
||
5576 | check_comparison_pointer_types(vtop - 1, vtop, op); |
||
5577 | /* XXX: check that types are compatible */ |
||
5578 | u = pointed_size(&vtop[-1].type); |
||
5579 | gen_opic(op); |
||
5580 | /* set to integer type */ |
||
5581 | vtop->type.t = VT_INT; |
||
5582 | vpushi(u); |
||
5583 | gen_op(TOK_PDIV); |
||
5584 | } else { |
||
5585 | /* exactly one pointer : must be '+' or '-'. */ |
||
5586 | if (op != '-' && op != '+') |
||
5587 | error("cannot use pointers here"); |
||
5588 | /* Put pointer as first operand */ |
||
5589 | if (bt2 == VT_PTR) { |
||
5590 | vswap(); |
||
5591 | swap(&t1, &t2); |
||
5592 | } |
||
5593 | type1 = vtop[-1].type; |
||
5594 | /* XXX: cast to int ? (long long case) */ |
||
5595 | vpushi(pointed_size(&vtop[-1].type)); |
||
5596 | gen_op('*'); |
||
5597 | #ifdef CONFIG_TCC_BCHECK |
||
5598 | /* if evaluating constant expression, no code should be |
||
5599 | generated, so no bound check */ |
||
5600 | if (do_bounds_check && !const_wanted) { |
||
5601 | /* if bounded pointers, we generate a special code to |
||
5602 | test bounds */ |
||
5603 | if (op == '-') { |
||
5604 | vpushi(0); |
||
5605 | vswap(); |
||
5606 | gen_op('-'); |
||
5607 | } |
||
5608 | gen_bounded_ptr_add(); |
||
5609 | } else |
||
5610 | #endif |
||
5611 | { |
||
5612 | gen_opic(op); |
||
5613 | } |
||
5614 | /* put again type if gen_opic() swaped operands */ |
||
5615 | vtop->type = type1; |
||
5616 | } |
||
5617 | } else if (is_float(bt1) || is_float(bt2)) { |
||
5618 | /* compute bigger type and do implicit casts */ |
||
5619 | if (bt1 == VT_LDOUBLE || bt2 == VT_LDOUBLE) { |
||
5620 | t = VT_LDOUBLE; |
||
5621 | } else if (bt1 == VT_DOUBLE || bt2 == VT_DOUBLE) { |
||
5622 | t = VT_DOUBLE; |
||
5623 | } else { |
||
5624 | t = VT_FLOAT; |
||
5625 | } |
||
5626 | /* floats can only be used for a few operations */ |
||
5627 | if (op != '+' && op != '-' && op != '*' && op != '/' && |
||
5628 | (op < TOK_ULT || op > TOK_GT)) |
||
5629 | error("invalid operands for binary operation"); |
||
5630 | goto std_op; |
||
5631 | } else if (bt1 == VT_LLONG || bt2 == VT_LLONG) { |
||
5632 | /* cast to biggest op */ |
||
5633 | t = VT_LLONG; |
||
5634 | /* convert to unsigned if it does not fit in a long long */ |
||
5635 | if ((t1 & (VT_BTYPE | VT_UNSIGNED)) == (VT_LLONG | VT_UNSIGNED) || |
||
5636 | (t2 & (VT_BTYPE | VT_UNSIGNED)) == (VT_LLONG | VT_UNSIGNED)) |
||
5637 | t |= VT_UNSIGNED; |
||
5638 | goto std_op; |
||
5639 | } else { |
||
5640 | /* integer operations */ |
||
5641 | t = VT_INT; |
||
5642 | /* convert to unsigned if it does not fit in an integer */ |
||
5643 | if ((t1 & (VT_BTYPE | VT_UNSIGNED)) == (VT_INT | VT_UNSIGNED) || |
||
5644 | (t2 & (VT_BTYPE | VT_UNSIGNED)) == (VT_INT | VT_UNSIGNED)) |
||
5645 | t |= VT_UNSIGNED; |
||
5646 | std_op: |
||
5647 | /* XXX: currently, some unsigned operations are explicit, so |
||
5648 | we modify them here */ |
||
5649 | if (t & VT_UNSIGNED) { |
||
5650 | if (op == TOK_SAR) |
||
5651 | op = TOK_SHR; |
||
5652 | else if (op == '/') |
||
5653 | op = TOK_UDIV; |
||
5654 | else if (op == '%') |
||
5655 | op = TOK_UMOD; |
||
5656 | else if (op == TOK_LT) |
||
5657 | op = TOK_ULT; |
||
5658 | else if (op == TOK_GT) |
||
5659 | op = TOK_UGT; |
||
5660 | else if (op == TOK_LE) |
||
5661 | op = TOK_ULE; |
||
5662 | else if (op == TOK_GE) |
||
5663 | op = TOK_UGE; |
||
5664 | } |
||
5665 | vswap(); |
||
5666 | type1.t = t; |
||
5667 | gen_cast(&type1); |
||
5668 | vswap(); |
||
5669 | /* special case for shifts and long long: we keep the shift as |
||
5670 | an integer */ |
||
5671 | if (op == TOK_SHR || op == TOK_SAR || op == TOK_SHL) |
||
5672 | type1.t = VT_INT; |
||
5673 | gen_cast(&type1); |
||
5674 | if (is_float(t)) |
||
5675 | gen_opif(op); |
||
5676 | else if ((t & VT_BTYPE) == VT_LLONG) |
||
5677 | gen_opl(op); |
||
5678 | else |
||
5679 | gen_opic(op); |
||
5680 | if (op >= TOK_ULT && op <= TOK_GT) { |
||
5681 | /* relationnal op: the result is an int */ |
||
5682 | vtop->type.t = VT_INT; |
||
5683 | } else { |
||
5684 | vtop->type.t = t; |
||
5685 | } |
||
5686 | } |
||
5687 | } |
||
5688 | |||
5689 | /* generic itof for unsigned long long case */ |
||
5690 | void gen_cvt_itof1(int t) |
||
5691 | { |
||
5692 | if ((vtop->type.t & (VT_BTYPE | VT_UNSIGNED)) == |
||
5693 | (VT_LLONG | VT_UNSIGNED)) { |
||
5694 | |||
5695 | if (t == VT_FLOAT) |
||
5696 | vpush_global_sym(&func_old_type, TOK___ulltof); |
||
5697 | else if (t == VT_DOUBLE) |
||
5698 | vpush_global_sym(&func_old_type, TOK___ulltod); |
||
5699 | else |
||
5700 | vpush_global_sym(&func_old_type, TOK___ulltold); |
||
5701 | vrott(2); |
||
5702 | gfunc_call(1); |
||
5703 | vpushi(0); |
||
5704 | vtop->r = REG_FRET; |
||
5705 | } else { |
||
5706 | gen_cvt_itof(t); |
||
5707 | } |
||
5708 | } |
||
5709 | |||
5710 | /* generic ftoi for unsigned long long case */ |
||
5711 | void gen_cvt_ftoi1(int t) |
||
5712 | { |
||
5713 | int st; |
||
5714 | |||
5715 | if (t == (VT_LLONG | VT_UNSIGNED)) { |
||
5716 | /* not handled natively */ |
||
5717 | st = vtop->type.t & VT_BTYPE; |
||
5718 | if (st == VT_FLOAT) |
||
5719 | vpush_global_sym(&func_old_type, TOK___fixunssfdi); |
||
5720 | else if (st == VT_DOUBLE) |
||
5721 | vpush_global_sym(&func_old_type, TOK___fixunsdfdi); |
||
5722 | else |
||
5723 | vpush_global_sym(&func_old_type, TOK___fixunsxfdi); |
||
5724 | vrott(2); |
||
5725 | gfunc_call(1); |
||
5726 | vpushi(0); |
||
5727 | vtop->r = REG_IRET; |
||
5728 | vtop->r2 = REG_LRET; |
||
5729 | } else { |
||
5730 | gen_cvt_ftoi(t); |
||
5731 | } |
||
5732 | } |
||
5733 | |||
5734 | /* force char or short cast */ |
||
5735 | void force_charshort_cast(int t) |
||
5736 | { |
||
5737 | int bits, dbt; |
||
5738 | dbt = t & VT_BTYPE; |
||
5739 | /* XXX: add optimization if lvalue : just change type and offset */ |
||
5740 | if (dbt == VT_BYTE) |
||
5741 | bits = 8; |
||
5742 | else |
||
5743 | bits = 16; |
||
5744 | if (t & VT_UNSIGNED) { |
||
5745 | vpushi((1 << bits) - 1); |
||
5746 | gen_op('&'); |
||
5747 | } else { |
||
5748 | bits = 32 - bits; |
||
5749 | vpushi(bits); |
||
5750 | gen_op(TOK_SHL); |
||
5751 | vpushi(bits); |
||
5752 | gen_op(TOK_SAR); |
||
5753 | } |
||
5754 | } |
||
5755 | |||
5756 | /* cast 'vtop' to 'type'. Casting to bitfields is forbidden. */ |
||
5757 | static void gen_cast(CType *type) |
||
5758 | { |
||
5759 | int sbt, dbt, sf, df, c; |
||
5760 | |||
5761 | /* special delayed cast for char/short */ |
||
5762 | /* XXX: in some cases (multiple cascaded casts), it may still |
||
5763 | be incorrect */ |
||
5764 | if (vtop->r & VT_MUSTCAST) { |
||
5765 | vtop->r &= ~VT_MUSTCAST; |
||
5766 | force_charshort_cast(vtop->type.t); |
||
5767 | } |
||
5768 | |||
5769 | /* bitfields first get cast to ints */ |
||
5770 | if (vtop->type.t & VT_BITFIELD) { |
||
5771 | gv(RC_INT); |
||
5772 | } |
||
5773 | |||
5774 | dbt = type->t & (VT_BTYPE | VT_UNSIGNED); |
||
5775 | sbt = vtop->type.t & (VT_BTYPE | VT_UNSIGNED); |
||
5776 | |||
5777 | if (sbt != dbt && !nocode_wanted) { |
||
5778 | sf = is_float(sbt); |
||
5779 | df = is_float(dbt); |
||
5780 | c = (vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; |
||
5781 | if (sf && df) { |
||
5782 | /* convert from fp to fp */ |
||
5783 | if (c) { |
||
5784 | /* constant case: we can do it now */ |
||
5785 | /* XXX: in ISOC, cannot do it if error in convert */ |
||
5786 | if (dbt == VT_FLOAT && sbt == VT_DOUBLE) |
||
5787 | vtop->c.f = (float)vtop->c.d; |
||
5788 | else if (dbt == VT_FLOAT && sbt == VT_LDOUBLE) |
||
5789 | vtop->c.f = (float)vtop->c.ld; |
||
5790 | else if (dbt == VT_DOUBLE && sbt == VT_FLOAT) |
||
5791 | vtop->c.d = (double)vtop->c.f; |
||
5792 | else if (dbt == VT_DOUBLE && sbt == VT_LDOUBLE) |
||
5793 | vtop->c.d = (double)vtop->c.ld; |
||
5794 | else if (dbt == VT_LDOUBLE && sbt == VT_FLOAT) |
||
5795 | vtop->c.ld = (long double)vtop->c.f; |
||
5796 | else if (dbt == VT_LDOUBLE && sbt == VT_DOUBLE) |
||
5797 | vtop->c.ld = (long double)vtop->c.d; |
||
5798 | } else { |
||
5799 | /* non constant case: generate code */ |
||
5800 | gen_cvt_ftof(dbt); |
||
5801 | } |
||
5802 | } else if (df) { |
||
5803 | /* convert int to fp */ |
||
5804 | if (c) { |
||
5805 | switch(sbt) { |
||
5806 | case VT_LLONG | VT_UNSIGNED: |
||
5807 | case VT_LLONG: |
||
5808 | /* XXX: add const cases for long long */ |
||
5809 | goto do_itof; |
||
5810 | case VT_INT | VT_UNSIGNED: |
||
5811 | switch(dbt) { |
||
5812 | case VT_FLOAT: vtop->c.f = (float)vtop->c.ui; break; |
||
5813 | case VT_DOUBLE: vtop->c.d = (double)vtop->c.ui; break; |
||
5814 | case VT_LDOUBLE: vtop->c.ld = (long double)vtop->c.ui; break; |
||
5815 | } |
||
5816 | break; |
||
5817 | default: |
||
5818 | switch(dbt) { |
||
5819 | case VT_FLOAT: vtop->c.f = (float)vtop->c.i; break; |
||
5820 | case VT_DOUBLE: vtop->c.d = (double)vtop->c.i; break; |
||
5821 | case VT_LDOUBLE: vtop->c.ld = (long double)vtop->c.i; break; |
||
5822 | } |
||
5823 | break; |
||
5824 | } |
||
5825 | } else { |
||
5826 | do_itof: |
||
5827 | #if !defined(TCC_TARGET_ARM) |
||
5828 | gen_cvt_itof1(dbt); |
||
5829 | #else |
||
5830 | gen_cvt_itof(dbt); |
||
5831 | #endif |
||
5832 | } |
||
5833 | } else if (sf) { |
||
5834 | /* convert fp to int */ |
||
5835 | /* we handle char/short/etc... with generic code */ |
||
5836 | if (dbt != (VT_INT | VT_UNSIGNED) && |
||
5837 | dbt != (VT_LLONG | VT_UNSIGNED) && |
||
5838 | dbt != VT_LLONG) |
||
5839 | dbt = VT_INT; |
||
5840 | if (c) { |
||
5841 | switch(dbt) { |
||
5842 | case VT_LLONG | VT_UNSIGNED: |
||
5843 | case VT_LLONG: |
||
5844 | /* XXX: add const cases for long long */ |
||
5845 | goto do_ftoi; |
||
5846 | case VT_INT | VT_UNSIGNED: |
||
5847 | switch(sbt) { |
||
5848 | case VT_FLOAT: vtop->c.ui = (unsigned int)vtop->c.d; break; |
||
5849 | case VT_DOUBLE: vtop->c.ui = (unsigned int)vtop->c.d; break; |
||
5850 | case VT_LDOUBLE: vtop->c.ui = (unsigned int)vtop->c.d; break; |
||
5851 | } |
||
5852 | break; |
||
5853 | default: |
||
5854 | /* int case */ |
||
5855 | switch(sbt) { |
||
5856 | case VT_FLOAT: vtop->c.i = (int)vtop->c.d; break; |
||
5857 | case VT_DOUBLE: vtop->c.i = (int)vtop->c.d; break; |
||
5858 | case VT_LDOUBLE: vtop->c.i = (int)vtop->c.d; break; |
||
5859 | } |
||
5860 | break; |
||
5861 | } |
||
5862 | } else { |
||
5863 | do_ftoi: |
||
5864 | gen_cvt_ftoi1(dbt); |
||
5865 | } |
||
5866 | if (dbt == VT_INT && (type->t & (VT_BTYPE | VT_UNSIGNED)) != dbt) { |
||
5867 | /* additional cast for char/short/bool... */ |
||
5868 | vtop->type.t = dbt; |
||
5869 | gen_cast(type); |
||
5870 | } |
||
5871 | } else if ((dbt & VT_BTYPE) == VT_LLONG) { |
||
5872 | if ((sbt & VT_BTYPE) != VT_LLONG) { |
||
5873 | /* scalar to long long */ |
||
5874 | if (c) { |
||
5875 | if (sbt == (VT_INT | VT_UNSIGNED)) |
||
5876 | vtop->c.ll = vtop->c.ui; |
||
5877 | else |
||
5878 | vtop->c.ll = vtop->c.i; |
||
5879 | } else { |
||
5880 | /* machine independent conversion */ |
||
5881 | gv(RC_INT); |
||
5882 | /* generate high word */ |
||
5883 | if (sbt == (VT_INT | VT_UNSIGNED)) { |
||
5884 | vpushi(0); |
||
5885 | gv(RC_INT); |
||
5886 | } else { |
||
5887 | gv_dup(); |
||
5888 | vpushi(31); |
||
5889 | gen_op(TOK_SAR); |
||
5890 | } |
||
5891 | /* patch second register */ |
||
5892 | vtop[-1].r2 = vtop->r; |
||
5893 | vpop(); |
||
5894 | } |
||
5895 | } |
||
5896 | } else if (dbt == VT_BOOL) { |
||
5897 | /* scalar to bool */ |
||
5898 | vpushi(0); |
||
5899 | gen_op(TOK_NE); |
||
5900 | } else if ((dbt & VT_BTYPE) == VT_BYTE || |
||
5901 | (dbt & VT_BTYPE) == VT_SHORT) { |
||
5902 | force_charshort_cast(dbt); |
||
5903 | } else if ((dbt & VT_BTYPE) == VT_INT) { |
||
5904 | /* scalar to int */ |
||
5905 | if (sbt == VT_LLONG) { |
||
5906 | /* from long long: just take low order word */ |
||
5907 | lexpand(); |
||
5908 | vpop(); |
||
5909 | } |
||
5910 | /* if lvalue and single word type, nothing to do because |
||
5911 | the lvalue already contains the real type size (see |
||
5912 | VT_LVAL_xxx constants) */ |
||
5913 | } |
||
5914 | } |
||
5915 | vtop->type = *type; |
||
5916 | } |
||
5917 | |||
5918 | /* return type size. Put alignment at 'a' */ |
||
5919 | static int type_size(CType *type, int *a) |
||
5920 | { |
||
5921 | Sym *s; |
||
5922 | int bt; |
||
609 | andrew_pro | 5923 | int size; |
145 | halyavin | 5924 | |
5925 | bt = type->t & VT_BTYPE; |
||
5926 | if (bt == VT_STRUCT) { |
||
5927 | /* struct/union */ |
||
5928 | s = type->ref; |
||
5929 | *a = s->r; |
||
609 | andrew_pro | 5930 | |
145 | halyavin | 5931 | return s->c; |
5932 | } else if (bt == VT_PTR) { |
||
609 | andrew_pro | 5933 | |
145 | halyavin | 5934 | if (type->t & VT_ARRAY) { |
5935 | s = type->ref; |
||
609 | andrew_pro | 5936 | size=type_size(&s->type, a) * s->c; |
5937 | return size;//type_size(&s->type, a) * s->c; |
||
145 | halyavin | 5938 | } else { |
5939 | *a = PTR_SIZE; |
||
5940 | return PTR_SIZE; |
||
5941 | } |
||
5942 | } else if (bt == VT_LDOUBLE) { |
||
5943 | *a = LDOUBLE_ALIGN; |
||
5944 | return LDOUBLE_SIZE; |
||
5945 | } else if (bt == VT_DOUBLE || bt == VT_LLONG) { |
||
5946 | #ifdef TCC_TARGET_I386 |
||
5947 | *a = 4; |
||
5948 | #else |
||
5949 | *a = 8; |
||
5950 | #endif |
||
5951 | return 8; |
||
5952 | } else if (bt == VT_INT || bt == VT_ENUM || bt == VT_FLOAT) { |
||
5953 | *a = 4; |
||
5954 | return 4; |
||
5955 | } else if (bt == VT_SHORT) { |
||
5956 | *a = 2; |
||
5957 | return 2; |
||
5958 | } else { |
||
5959 | /* char, void, function, _Bool */ |
||
5960 | *a = 1; |
||
5961 | return 1; |
||
5962 | } |
||
5963 | } |
||
5964 | |||
5965 | /* return the pointed type of t */ |
||
5966 | static inline CType *pointed_type(CType *type) |
||
5967 | { |
||
5968 | return &type->ref->type; |
||
5969 | } |
||
5970 | |||
5971 | /* modify type so that its it is a pointer to type. */ |
||
5972 | static void mk_pointer(CType *type) |
||
5973 | { |
||
5974 | Sym *s; |
||
5975 | s = sym_push(SYM_FIELD, type, 0, -1); |
||
5976 | type->t = VT_PTR | (type->t & ~VT_TYPE); |
||
5977 | type->ref = s; |
||
5978 | } |
||
5979 | |||
5980 | /* compare function types. OLD functions match any new functions */ |
||
5981 | static int is_compatible_func(CType *type1, CType *type2) |
||
5982 | { |
||
5983 | Sym *s1, *s2; |
||
5984 | |||
5985 | s1 = type1->ref; |
||
5986 | s2 = type2->ref; |
||
5987 | if (!is_compatible_types(&s1->type, &s2->type)) |
||
5988 | return 0; |
||
5989 | /* check func_call */ |
||
5990 | if (s1->r != s2->r) |
||
5991 | return 0; |
||
5992 | /* XXX: not complete */ |
||
5993 | if (s1->c == FUNC_OLD || s2->c == FUNC_OLD) |
||
5994 | return 1; |
||
5995 | if (s1->c != s2->c) |
||
5996 | return 0; |
||
5997 | while (s1 != NULL) { |
||
5998 | if (s2 == NULL) |
||
5999 | return 0; |
||
6000 | if (!is_compatible_types(&s1->type, &s2->type)) |
||
6001 | return 0; |
||
6002 | s1 = s1->next; |
||
6003 | s2 = s2->next; |
||
6004 | } |
||
6005 | if (s2) |
||
6006 | return 0; |
||
6007 | return 1; |
||
6008 | } |
||
6009 | |||
6010 | /* return true if type1 and type2 are exactly the same (including |
||
6011 | qualifiers). |
||
6012 | |||
6013 | - enums are not checked as gcc __builtin_types_compatible_p () |
||
6014 | */ |
||
6015 | static int is_compatible_types(CType *type1, CType *type2) |
||
6016 | { |
||
6017 | int bt1, t1, t2; |
||
6018 | |||
6019 | t1 = type1->t & VT_TYPE; |
||
6020 | t2 = type2->t & VT_TYPE; |
||
6021 | /* XXX: bitfields ? */ |
||
6022 | if (t1 != t2) |
||
6023 | return 0; |
||
6024 | /* test more complicated cases */ |
||
6025 | bt1 = t1 & VT_BTYPE; |
||
6026 | if (bt1 == VT_PTR) { |
||
6027 | type1 = pointed_type(type1); |
||
6028 | type2 = pointed_type(type2); |
||
6029 | return is_compatible_types(type1, type2); |
||
6030 | } else if (bt1 == VT_STRUCT) { |
||
6031 | return (type1->ref == type2->ref); |
||
6032 | } else if (bt1 == VT_FUNC) { |
||
6033 | return is_compatible_func(type1, type2); |
||
6034 | } else { |
||
6035 | return 1; |
||
6036 | } |
||
6037 | } |
||
6038 | |||
6039 | /* print a type. If 'varstr' is not NULL, then the variable is also |
||
6040 | printed in the type */ |
||
6041 | /* XXX: union */ |
||
6042 | /* XXX: add array and function pointers */ |
||
6043 | void type_to_str(char *buf, int buf_size, |
||
6044 | CType *type, const char *varstr) |
||
6045 | { |
||
6046 | int bt, v, t; |
||
6047 | Sym *s, *sa; |
||
6048 | char buf1[256]; |
||
6049 | const char *tstr; |
||
6050 | |||
6051 | t = type->t & VT_TYPE; |
||
6052 | bt = t & VT_BTYPE; |
||
6053 | buf[0] = '\0'; |
||
6054 | if (t & VT_CONSTANT) |
||
6055 | pstrcat(buf, buf_size, "const "); |
||
6056 | if (t & VT_VOLATILE) |
||
6057 | pstrcat(buf, buf_size, "volatile "); |
||
6058 | if (t & VT_UNSIGNED) |
||
6059 | pstrcat(buf, buf_size, "unsigned "); |
||
6060 | switch(bt) { |
||
6061 | case VT_VOID: |
||
6062 | tstr = "void"; |
||
6063 | goto add_tstr; |
||
6064 | case VT_BOOL: |
||
6065 | tstr = "_Bool"; |
||
6066 | goto add_tstr; |
||
6067 | case VT_BYTE: |
||
6068 | tstr = "char"; |
||
6069 | goto add_tstr; |
||
6070 | case VT_SHORT: |
||
6071 | tstr = "short"; |
||
6072 | goto add_tstr; |
||
6073 | case VT_INT: |
||
6074 | tstr = "int"; |
||
6075 | goto add_tstr; |
||
6076 | case VT_LONG: |
||
6077 | tstr = "long"; |
||
6078 | goto add_tstr; |
||
6079 | case VT_LLONG: |
||
6080 | tstr = "long long"; |
||
6081 | goto add_tstr; |
||
6082 | case VT_FLOAT: |
||
6083 | tstr = "float"; |
||
6084 | goto add_tstr; |
||
6085 | case VT_DOUBLE: |
||
6086 | tstr = "double"; |
||
6087 | goto add_tstr; |
||
6088 | case VT_LDOUBLE: |
||
6089 | tstr = "long double"; |
||
6090 | add_tstr: |
||
6091 | pstrcat(buf, buf_size, tstr); |
||
6092 | break; |
||
6093 | case VT_ENUM: |
||
6094 | case VT_STRUCT: |
||
6095 | if (bt == VT_STRUCT) |
||
6096 | tstr = "struct "; |
||
6097 | else |
||
6098 | tstr = "enum "; |
||
6099 | pstrcat(buf, buf_size, tstr); |
||
6100 | v = type->ref->v & ~SYM_STRUCT; |
||
6101 | if (v >= SYM_FIRST_ANOM) |
||
6102 | pstrcat(buf, buf_size, " |
||
6103 | else |
||
6104 | pstrcat(buf, buf_size, get_tok_str(v, NULL)); |
||
6105 | break; |
||
6106 | case VT_FUNC: |
||
6107 | s = type->ref; |
||
6108 | type_to_str(buf, buf_size, &s->type, varstr); |
||
6109 | pstrcat(buf, buf_size, "("); |
||
6110 | sa = s->next; |
||
6111 | while (sa != NULL) { |
||
6112 | type_to_str(buf1, sizeof(buf1), &sa->type, NULL); |
||
6113 | pstrcat(buf, buf_size, buf1); |
||
6114 | sa = sa->next; |
||
6115 | if (sa) |
||
6116 | pstrcat(buf, buf_size, ", "); |
||
6117 | } |
||
6118 | pstrcat(buf, buf_size, ")"); |
||
6119 | goto no_var; |
||
6120 | case VT_PTR: |
||
6121 | s = type->ref; |
||
6122 | pstrcpy(buf1, sizeof(buf1), "*"); |
||
6123 | if (varstr) |
||
6124 | pstrcat(buf1, sizeof(buf1), varstr); |
||
6125 | type_to_str(buf, buf_size, &s->type, buf1); |
||
6126 | goto no_var; |
||
6127 | } |
||
6128 | if (varstr) { |
||
6129 | pstrcat(buf, buf_size, " "); |
||
6130 | pstrcat(buf, buf_size, varstr); |
||
6131 | } |
||
6132 | no_var: ; |
||
6133 | } |
||
6134 | |||
6135 | /* verify type compatibility to store vtop in 'dt' type, and generate |
||
6136 | casts if needed. */ |
||
6137 | static void gen_assign_cast(CType *dt) |
||
6138 | { |
||
6139 | CType *st, *type1, *type2, tmp_type1, tmp_type2; |
||
6140 | char buf1[256], buf2[256]; |
||
6141 | int dbt, sbt; |
||
6142 | |||
6143 | st = &vtop->type; /* source type */ |
||
6144 | dbt = dt->t & VT_BTYPE; |
||
6145 | sbt = st->t & VT_BTYPE; |
||
6146 | if (dt->t & VT_CONSTANT) |
||
6147 | warning("assignment of read-only location"); |
||
6148 | switch(dbt) { |
||
6149 | case VT_PTR: |
||
6150 | /* special cases for pointers */ |
||
6151 | /* '0' can also be a pointer */ |
||
6152 | if (is_null_pointer(vtop)) |
||
6153 | goto type_ok; |
||
6154 | /* accept implicit pointer to integer cast with warning */ |
||
6155 | if (is_integer_btype(sbt)) { |
||
6156 | warning("assignment makes pointer from integer without a cast"); |
||
6157 | goto type_ok; |
||
6158 | } |
||
6159 | type1 = pointed_type(dt); |
||
6160 | /* a function is implicitely a function pointer */ |
||
6161 | if (sbt == VT_FUNC) { |
||
6162 | if ((type1->t & VT_BTYPE) != VT_VOID && |
||
6163 | !is_compatible_types(pointed_type(dt), st)) |
||
6164 | goto error; |
||
6165 | else |
||
6166 | goto type_ok; |
||
6167 | } |
||
6168 | if (sbt != VT_PTR) |
||
6169 | goto error; |
||
6170 | type2 = pointed_type(st); |
||
6171 | if ((type1->t & VT_BTYPE) == VT_VOID || |
||
6172 | (type2->t & VT_BTYPE) == VT_VOID) { |
||
6173 | /* void * can match anything */ |
||
6174 | } else { |
||
6175 | /* exact type match, except for unsigned */ |
||
6176 | tmp_type1 = *type1; |
||
6177 | tmp_type2 = *type2; |
||
6178 | tmp_type1.t &= ~(VT_UNSIGNED | VT_CONSTANT | VT_VOLATILE); |
||
6179 | tmp_type2.t &= ~(VT_UNSIGNED | VT_CONSTANT | VT_VOLATILE); |
||
6180 | if (!is_compatible_types(&tmp_type1, &tmp_type2)) |
||
6181 | goto error; |
||
6182 | } |
||
6183 | /* check const and volatile */ |
||
6184 | if ((!(type1->t & VT_CONSTANT) && (type2->t & VT_CONSTANT)) || |
||
6185 | (!(type1->t & VT_VOLATILE) && (type2->t & VT_VOLATILE))) |
||
6186 | warning("assignment discards qualifiers from pointer target type"); |
||
6187 | break; |
||
6188 | case VT_BYTE: |
||
6189 | case VT_SHORT: |
||
6190 | case VT_INT: |
||
6191 | case VT_LLONG: |
||
6192 | if (sbt == VT_PTR || sbt == VT_FUNC) { |
||
6193 | warning("assignment makes integer from pointer without a cast"); |
||
6194 | } |
||
6195 | /* XXX: more tests */ |
||
6196 | break; |
||
6197 | case VT_STRUCT: |
||
6198 | tmp_type1 = *dt; |
||
6199 | tmp_type2 = *st; |
||
6200 | tmp_type1.t &= ~(VT_CONSTANT | VT_VOLATILE); |
||
6201 | tmp_type2.t &= ~(VT_CONSTANT | VT_VOLATILE); |
||
6202 | if (!is_compatible_types(&tmp_type1, &tmp_type2)) { |
||
6203 | error: |
||
6204 | type_to_str(buf1, sizeof(buf1), st, NULL); |
||
6205 | type_to_str(buf2, sizeof(buf2), dt, NULL); |
||
6206 | error("cannot cast '%s' to '%s'", buf1, buf2); |
||
6207 | } |
||
6208 | break; |
||
6209 | } |
||
6210 | type_ok: |
||
6211 | gen_cast(dt); |
||
6212 | } |
||
6213 | |||
6214 | /* store vtop in lvalue pushed on stack */ |
||
6215 | void vstore(void) |
||
6216 | { |
||
6217 | int sbt, dbt, ft, r, t, size, align, bit_size, bit_pos, rc, delayed_cast; |
||
6218 | |||
6219 | ft = vtop[-1].type.t; |
||
6220 | sbt = vtop->type.t & VT_BTYPE; |
||
6221 | dbt = ft & VT_BTYPE; |
||
6222 | if (((sbt == VT_INT || sbt == VT_SHORT) && dbt == VT_BYTE) || |
||
6223 | (sbt == VT_INT && dbt == VT_SHORT)) { |
||
6224 | /* optimize char/short casts */ |
||
6225 | delayed_cast = VT_MUSTCAST; |
||
6226 | vtop->type.t = ft & VT_TYPE; |
||
6227 | /* XXX: factorize */ |
||
6228 | if (ft & VT_CONSTANT) |
||
6229 | warning("assignment of read-only location"); |
||
6230 | } else { |
||
6231 | delayed_cast = 0; |
||
6232 | if (!(ft & VT_BITFIELD)) |
||
6233 | gen_assign_cast(&vtop[-1].type); |
||
6234 | } |
||
6235 | |||
6236 | if (sbt == VT_STRUCT) { |
||
6237 | /* if structure, only generate pointer */ |
||
6238 | /* structure assignment : generate memcpy */ |
||
6239 | /* XXX: optimize if small size */ |
||
6240 | if (!nocode_wanted) { |
||
6241 | size = type_size(&vtop->type, &align); |
||
6242 | |||
6243 | vpush_global_sym(&func_old_type, TOK_memcpy); |
||
6244 | |||
6245 | /* destination */ |
||
6246 | vpushv(vtop - 2); |
||
6247 | vtop->type.t = VT_INT; |
||
6248 | gaddrof(); |
||
6249 | /* source */ |
||
6250 | vpushv(vtop - 2); |
||
6251 | vtop->type.t = VT_INT; |
||
6252 | gaddrof(); |
||
6253 | /* type size */ |
||
6254 | vpushi(size); |
||
6255 | gfunc_call(3); |
||
6256 | |||
6257 | vswap(); |
||
6258 | vpop(); |
||
6259 | } else { |
||
6260 | vswap(); |
||
6261 | vpop(); |
||
6262 | } |
||
6263 | /* leave source on stack */ |
||
6264 | } else if (ft & VT_BITFIELD) { |
||
6265 | /* bitfield store handling */ |
||
6266 | bit_pos = (ft >> VT_STRUCT_SHIFT) & 0x3f; |
||
6267 | bit_size = (ft >> (VT_STRUCT_SHIFT + 6)) & 0x3f; |
||
6268 | /* remove bit field info to avoid loops */ |
||
6269 | vtop[-1].type.t = ft & ~(VT_BITFIELD | (-1 << VT_STRUCT_SHIFT)); |
||
6270 | |||
6271 | /* duplicate destination */ |
||
6272 | vdup(); |
||
6273 | vtop[-1] = vtop[-2]; |
||
6274 | |||
6275 | /* mask and shift source */ |
||
6276 | vpushi((1 << bit_size) - 1); |
||
6277 | gen_op('&'); |
||
6278 | vpushi(bit_pos); |
||
6279 | gen_op(TOK_SHL); |
||
6280 | /* load destination, mask and or with source */ |
||
6281 | vswap(); |
||
6282 | vpushi(~(((1 << bit_size) - 1) << bit_pos)); |
||
6283 | gen_op('&'); |
||
6284 | gen_op('|'); |
||
6285 | /* store result */ |
||
6286 | vstore(); |
||
6287 | } else { |
||
6288 | #ifdef CONFIG_TCC_BCHECK |
||
6289 | /* bound check case */ |
||
6290 | if (vtop[-1].r & VT_MUSTBOUND) { |
||
6291 | vswap(); |
||
6292 | gbound(); |
||
6293 | vswap(); |
||
6294 | } |
||
6295 | #endif |
||
6296 | if (!nocode_wanted) { |
||
6297 | rc = RC_INT; |
||
6298 | if (is_float(ft)) |
||
6299 | rc = RC_FLOAT; |
||
6300 | r = gv(rc); /* generate value */ |
||
6301 | /* if lvalue was saved on stack, must read it */ |
||
6302 | if ((vtop[-1].r & VT_VALMASK) == VT_LLOCAL) { |
||
6303 | SValue sv; |
||
6304 | t = get_reg(RC_INT); |
||
6305 | sv.type.t = VT_INT; |
||
6306 | sv.r = VT_LOCAL | VT_LVAL; |
||
6307 | sv.c.ul = vtop[-1].c.ul; |
||
6308 | load(t, &sv); |
||
6309 | vtop[-1].r = t | VT_LVAL; |
||
6310 | } |
||
6311 | store(r, vtop - 1); |
||
6312 | /* two word case handling : store second register at word + 4 */ |
||
6313 | if ((ft & VT_BTYPE) == VT_LLONG) { |
||
6314 | vswap(); |
||
6315 | /* convert to int to increment easily */ |
||
6316 | vtop->type.t = VT_INT; |
||
6317 | gaddrof(); |
||
6318 | vpushi(4); |
||
6319 | gen_op('+'); |
||
6320 | vtop->r |= VT_LVAL; |
||
6321 | vswap(); |
||
6322 | /* XXX: it works because r2 is spilled last ! */ |
||
6323 | store(vtop->r2, vtop - 1); |
||
6324 | } |
||
6325 | } |
||
6326 | vswap(); |
||
6327 | vtop--; /* NOT vpop() because on x86 it would flush the fp stack */ |
||
6328 | vtop->r |= delayed_cast; |
||
6329 | } |
||
6330 | } |
||
6331 | |||
6332 | /* post defines POST/PRE add. c is the token ++ or -- */ |
||
6333 | void inc(int post, int c) |
||
6334 | { |
||
6335 | test_lvalue(); |
||
6336 | vdup(); /* save lvalue */ |
||
6337 | if (post) { |
||
6338 | gv_dup(); /* duplicate value */ |
||
6339 | vrotb(3); |
||
6340 | vrotb(3); |
||
6341 | } |
||
6342 | /* add constant */ |
||
6343 | vpushi(c - TOK_MID); |
||
6344 | gen_op('+'); |
||
6345 | vstore(); /* store value */ |
||
6346 | if (post) |
||
6347 | vpop(); /* if post op, return saved value */ |
||
6348 | } |
||
6349 | |||
6350 | /* Parse GNUC __attribute__ extension. Currently, the following |
||
6351 | extensions are recognized: |
||
6352 | - aligned(n) : set data/function alignment. |
||
6353 | - packed : force data alignment to 1 |
||
6354 | - section(x) : generate data/code in this section. |
||
6355 | - unused : currently ignored, but may be used someday. |
||
6356 | - regparm(n) : pass function parameters in registers (i386 only) |
||
6357 | */ |
||
6358 | static void parse_attribute(AttributeDef *ad) |
||
6359 | { |
||
6360 | int t, n; |
||
6361 | |||
6362 | while (tok == TOK_ATTRIBUTE1 || tok == TOK_ATTRIBUTE2) { |
||
6363 | next(); |
||
6364 | skip('('); |
||
6365 | skip('('); |
||
6366 | while (tok != ')') { |
||
6367 | if (tok < TOK_IDENT) |
||
6368 | expect("attribute name"); |
||
6369 | t = tok; |
||
6370 | next(); |
||
6371 | switch(t) { |
||
6372 | case TOK_SECTION1: |
||
6373 | case TOK_SECTION2: |
||
6374 | skip('('); |
||
6375 | if (tok != TOK_STR) |
||
6376 | expect("section name"); |
||
6377 | ad->section = find_section(tcc_state, (char *)tokc.cstr->data); |
||
6378 | next(); |
||
6379 | skip(')'); |
||
6380 | break; |
||
6381 | case TOK_ALIGNED1: |
||
6382 | case TOK_ALIGNED2: |
||
6383 | if (tok == '(') { |
||
6384 | next(); |
||
6385 | n = expr_const(); |
||
6386 | if (n <= 0 || (n & (n - 1)) != 0) |
||
6387 | error("alignment must be a positive power of two"); |
||
6388 | skip(')'); |
||
6389 | } else { |
||
6390 | n = MAX_ALIGN; |
||
6391 | } |
||
6392 | ad->aligned = n; |
||
6393 | break; |
||
6394 | case TOK_PACKED1: |
||
6395 | case TOK_PACKED2: |
||
6396 | ad->packed = 1; |
||
6397 | break; |
||
6398 | case TOK_UNUSED1: |
||
6399 | case TOK_UNUSED2: |
||
6400 | /* currently, no need to handle it because tcc does not |
||
6401 | track unused objects */ |
||
6402 | break; |
||
6403 | case TOK_NORETURN1: |
||
6404 | case TOK_NORETURN2: |
||
6405 | /* currently, no need to handle it because tcc does not |
||
6406 | track unused objects */ |
||
6407 | break; |
||
6408 | case TOK_CDECL1: |
||
6409 | case TOK_CDECL2: |
||
6410 | case TOK_CDECL3: |
||
6411 | ad->func_call = FUNC_CDECL; |
||
6412 | break; |
||
6413 | case TOK_STDCALL1: |
||
6414 | case TOK_STDCALL2: |
||
6415 | case TOK_STDCALL3: |
||
6416 | ad->func_call = FUNC_STDCALL; |
||
6417 | break; |
||
6418 | #ifdef TCC_TARGET_I386 |
||
6419 | case TOK_REGPARM1: |
||
6420 | case TOK_REGPARM2: |
||
6421 | skip('('); |
||
6422 | n = expr_const(); |
||
6423 | if (n > 3) |
||
6424 | n = 3; |
||
6425 | else if (n < 0) |
||
6426 | n = 0; |
||
6427 | if (n > 0) |
||
6428 | ad->func_call = FUNC_FASTCALL1 + n - 1; |
||
6429 | skip(')'); |
||
6430 | break; |
||
6431 | #endif |
||
6432 | case TOK_DLLEXPORT: |
||
6433 | ad->dllexport = 1; |
||
6434 | break; |
||
6435 | default: |
||
6436 | if (tcc_state->warn_unsupported) |
||
6437 | warning("'%s' attribute ignored", get_tok_str(t, NULL)); |
||
6438 | /* skip parameters */ |
||
6439 | /* XXX: skip parenthesis too */ |
||
6440 | if (tok == '(') { |
||
6441 | next(); |
||
6442 | while (tok != ')' && tok != -1) |
||
6443 | next(); |
||
6444 | next(); |
||
6445 | } |
||
6446 | break; |
||
6447 | } |
||
6448 | if (tok != ',') |
||
6449 | break; |
||
6450 | next(); |
||
6451 | } |
||
6452 | skip(')'); |
||
6453 | skip(')'); |
||
6454 | } |
||
6455 | } |
||
6456 | |||
6457 | /* enum/struct/union declaration. u is either VT_ENUM or VT_STRUCT */ |
||
6458 | static void struct_decl(CType *type, int u) |
||
6459 | { |
||
6460 | int a, v, size, align, maxalign, c, offset; |
||
6461 | int bit_size, bit_pos, bsize, bt, lbit_pos; |
||
6462 | Sym *s, *ss, **ps; |
||
6463 | AttributeDef ad; |
||
6464 | CType type1, btype; |
||
6465 | |||
6466 | a = tok; /* save decl type */ |
||
6467 | next(); |
||
6468 | if (tok != '{') { |
||
6469 | v = tok; |
||
6470 | next(); |
||
6471 | /* struct already defined ? return it */ |
||
6472 | if (v < TOK_IDENT) |
||
6473 | expect("struct/union/enum name"); |
||
6474 | s = struct_find(v); |
||
6475 | if (s) { |
||
6476 | if (s->type.t != a) |
||
6477 | error("invalid type"); |
||
6478 | goto do_decl; |
||
6479 | } |
||
6480 | } else { |
||
6481 | v = anon_sym++; |
||
6482 | } |
||
6483 | type1.t = a; |
||
6484 | /* we put an undefined size for struct/union */ |
||
6485 | s = sym_push(v | SYM_STRUCT, &type1, 0, -1); |
||
6486 | s->r = 0; /* default alignment is zero as gcc */ |
||
6487 | /* put struct/union/enum name in type */ |
||
6488 | do_decl: |
||
6489 | type->t = u; |
||
6490 | type->ref = s; |
||
6491 | |||
6492 | if (tok == '{') { |
||
6493 | next(); |
||
6494 | if (s->c != -1) |
||
6495 | error("struct/union/enum already defined"); |
||
6496 | /* cannot be empty */ |
||
6497 | c = 0; |
||
6498 | /* non empty enums are not allowed */ |
||
6499 | if (a == TOK_ENUM) { |
||
6500 | for(;;) { |
||
6501 | v = tok; |
||
6502 | if (v < TOK_UIDENT) |
||
6503 | expect("identifier"); |
||
6504 | next(); |
||
6505 | if (tok == '=') { |
||
6506 | next(); |
||
6507 | c = expr_const(); |
||
6508 | } |
||
6509 | /* enum symbols have static storage */ |
||
6510 | ss = sym_push(v, &int_type, VT_CONST, c); |
||
6511 | ss->type.t |= VT_STATIC; |
||
6512 | if (tok != ',') |
||
6513 | break; |
||
6514 | next(); |
||
6515 | c++; |
||
6516 | /* NOTE: we accept a trailing comma */ |
||
6517 | if (tok == '}') |
||
6518 | break; |
||
6519 | } |
||
6520 | skip('}'); |
||
6521 | } else { |
||
6522 | maxalign = 1; |
||
6523 | ps = &s->next; |
||
6524 | bit_pos = 0; |
||
6525 | offset = 0; |
||
6526 | while (tok != '}') { |
||
6527 | parse_btype(&btype, &ad); |
||
6528 | while (1) { |
||
6529 | bit_size = -1; |
||
6530 | v = 0; |
||
6531 | type1 = btype; |
||
6532 | if (tok != ':') { |
||
6533 | type_decl(&type1, &ad, &v, TYPE_DIRECT); |
||
6534 | if ((type1.t & VT_BTYPE) == VT_FUNC || |
||
6535 | (type1.t & (VT_TYPEDEF | VT_STATIC | VT_EXTERN | VT_INLINE))) |
||
6536 | error("invalid type for '%s'", |
||
6537 | get_tok_str(v, NULL)); |
||
6538 | } |
||
6539 | if (tok == ':') { |
||
6540 | next(); |
||
6541 | bit_size = expr_const(); |
||
6542 | /* XXX: handle v = 0 case for messages */ |
||
6543 | if (bit_size < 0) |
||
6544 | error("negative width in bit-field '%s'", |
||
6545 | get_tok_str(v, NULL)); |
||
6546 | if (v && bit_size == 0) |
||
6547 | error("zero width for bit-field '%s'", |
||
6548 | get_tok_str(v, NULL)); |
||
6549 | } |
||
6550 | size = type_size(&type1, &align); |
||
6551 | if (ad.aligned) { |
||
6552 | if (align < ad.aligned) |
||
6553 | align = ad.aligned; |
||
6554 | } else if (ad.packed) { |
||
6555 | align = 1; |
||
6556 | } else if (*tcc_state->pack_stack_ptr) { |
||
6557 | if (align > *tcc_state->pack_stack_ptr) |
||
6558 | align = *tcc_state->pack_stack_ptr; |
||
6559 | } |
||
6560 | lbit_pos = 0; |
||
6561 | if (bit_size >= 0) { |
||
6562 | bt = type1.t & VT_BTYPE; |
||
6563 | if (bt != VT_INT && |
||
6564 | bt != VT_BYTE && |
||
6565 | bt != VT_SHORT && |
||
6566 | bt != VT_BOOL && |
||
6567 | bt != VT_ENUM) |
||
6568 | error("bitfields must have scalar type"); |
||
6569 | bsize = size * 8; |
||
6570 | if (bit_size > bsize) { |
||
6571 | error("width of '%s' exceeds its type", |
||
6572 | get_tok_str(v, NULL)); |
||
6573 | } else if (bit_size == bsize) { |
||
6574 | /* no need for bit fields */ |
||
6575 | bit_pos = 0; |
||
6576 | } else if (bit_size == 0) { |
||
6577 | /* XXX: what to do if only padding in a |
||
6578 | structure ? */ |
||
6579 | /* zero size: means to pad */ |
||
6580 | if (bit_pos > 0) |
||
6581 | bit_pos = bsize; |
||
6582 | } else { |
||
6583 | /* we do not have enough room ? */ |
||
6584 | if ((bit_pos + bit_size) > bsize) |
||
6585 | bit_pos = 0; |
||
6586 | lbit_pos = bit_pos; |
||
6587 | /* XXX: handle LSB first */ |
||
6588 | type1.t |= VT_BITFIELD | |
||
6589 | (bit_pos << VT_STRUCT_SHIFT) | |
||
6590 | (bit_size << (VT_STRUCT_SHIFT + 6)); |
||
6591 | bit_pos += bit_size; |
||
6592 | } |
||
6593 | } else { |
||
6594 | bit_pos = 0; |
||
6595 | } |
||
6596 | if (v) { |
||
6597 | /* add new memory data only if starting |
||
6598 | bit field */ |
||
6599 | if (lbit_pos == 0) { |
||
6600 | if (a == TOK_STRUCT) { |
||
609 | andrew_pro | 6601 | //17.09.2007 |
6602 | //c = (c + align - 1) & -align; |
||
145 | halyavin | 6603 | offset = c; |
609 | andrew_pro | 6604 | //c += size; |
6605 | if (size<=4) {c=c+size;} |
||
6606 | else |
||
6607 | {c=c+align;} |
||
145 | halyavin | 6608 | } else { |
6609 | offset = 0; |
||
6610 | if (size > c) |
||
6611 | c = size; |
||
6612 | } |
||
6613 | if (align > maxalign) |
||
6614 | maxalign = align; |
||
6615 | } |
||
6616 | #if 0 |
||
6617 | printf("add field %s offset=%d", |
||
6618 | get_tok_str(v, NULL), offset); |
||
6619 | if (type1.t & VT_BITFIELD) { |
||
6620 | printf(" pos=%d size=%d", |
||
6621 | (type1.t >> VT_STRUCT_SHIFT) & 0x3f, |
||
6622 | (type1.t >> (VT_STRUCT_SHIFT + 6)) & 0x3f); |
||
6623 | } |
||
6624 | printf("\n"); |
||
6625 | #endif |
||
6626 | ss = sym_push(v | SYM_FIELD, &type1, 0, offset); |
||
6627 | *ps = ss; |
||
6628 | ps = &ss->next; |
||
6629 | } |
||
6630 | if (tok == ';' || tok == TOK_EOF) |
||
6631 | break; |
||
6632 | skip(','); |
||
6633 | } |
||
6634 | skip(';'); |
||
6635 | } |
||
6636 | skip('}'); |
||
6637 | /* store size and alignment */ |
||
6638 | s->c = (c + maxalign - 1) & -maxalign; |
||
6639 | s->r = maxalign; |
||
6640 | } |
||
6641 | } |
||
6642 | } |
||
6643 | |||
6644 | /* return 0 if no type declaration. otherwise, return the basic type |
||
6645 | and skip it. |
||
6646 | */ |
||
6647 | static int parse_btype(CType *type, AttributeDef *ad) |
||
6648 | { |
||
6649 | int t, u, type_found, typespec_found; |
||
6650 | Sym *s; |
||
6651 | CType type1; |
||
6652 | |||
6653 | memset(ad, 0, sizeof(AttributeDef)); |
||
6654 | type_found = 0; |
||
6655 | typespec_found = 0; |
||
6656 | t = 0; |
||
6657 | while(1) { |
||
6658 | switch(tok) { |
||
6659 | case TOK_EXTENSION: |
||
6660 | /* currently, we really ignore extension */ |
||
6661 | next(); |
||
6662 | continue; |
||
6663 | |||
6664 | /* basic types */ |
||
6665 | case TOK_CHAR: |
||
6666 | u = VT_BYTE; |
||
6667 | basic_type: |
||
6668 | next(); |
||
6669 | basic_type1: |
||
6670 | if ((t & VT_BTYPE) != 0) |
||
6671 | error("too many basic types"); |
||
6672 | t |= u; |
||
6673 | typespec_found = 1; |
||
6674 | break; |
||
6675 | case TOK_VOID: |
||
6676 | u = VT_VOID; |
||
6677 | goto basic_type; |
||
6678 | case TOK_SHORT: |
||
6679 | u = VT_SHORT; |
||
6680 | goto basic_type; |
||
6681 | case TOK_INT: |
||
6682 | next(); |
||
6683 | typespec_found = 1; |
||
6684 | break; |
||
6685 | case TOK_LONG: |
||
6686 | next(); |
||
6687 | if ((t & VT_BTYPE) == VT_DOUBLE) { |
||
6688 | t = (t & ~VT_BTYPE) | VT_LDOUBLE; |
||
6689 | } else if ((t & VT_BTYPE) == VT_LONG) { |
||
6690 | t = (t & ~VT_BTYPE) | VT_LLONG; |
||
6691 | } else { |
||
6692 | u = VT_LONG; |
||
6693 | goto basic_type1; |
||
6694 | } |
||
6695 | break; |
||
6696 | case TOK_BOOL: |
||
6697 | u = VT_BOOL; |
||
6698 | goto basic_type; |
||
6699 | case TOK_FLOAT: |
||
6700 | u = VT_FLOAT; |
||
6701 | goto basic_type; |
||
6702 | case TOK_DOUBLE: |
||
6703 | next(); |
||
6704 | if ((t & VT_BTYPE) == VT_LONG) { |
||
6705 | t = (t & ~VT_BTYPE) | VT_LDOUBLE; |
||
6706 | } else { |
||
6707 | u = VT_DOUBLE; |
||
6708 | goto basic_type1; |
||
6709 | } |
||
6710 | break; |
||
6711 | case TOK_ENUM: |
||
6712 | struct_decl(&type1, VT_ENUM); |
||
6713 | basic_type2: |
||
6714 | u = type1.t; |
||
6715 | type->ref = type1.ref; |
||
6716 | goto basic_type1; |
||
6717 | case TOK_STRUCT: |
||
6718 | case TOK_UNION: |
||
6719 | struct_decl(&type1, VT_STRUCT); |
||
6720 | goto basic_type2; |
||
6721 | |||
6722 | /* type modifiers */ |
||
6723 | case TOK_CONST1: |
||
6724 | case TOK_CONST2: |
||
6725 | case TOK_CONST3: |
||
6726 | t |= VT_CONSTANT; |
||
6727 | next(); |
||
6728 | break; |
||
6729 | case TOK_VOLATILE1: |
||
6730 | case TOK_VOLATILE2: |
||
6731 | case TOK_VOLATILE3: |
||
6732 | t |= VT_VOLATILE; |
||
6733 | next(); |
||
6734 | break; |
||
6735 | case TOK_SIGNED1: |
||
6736 | case TOK_SIGNED2: |
||
6737 | case TOK_SIGNED3: |
||
6738 | typespec_found = 1; |
||
6739 | t |= VT_SIGNED; |
||
6740 | next(); |
||
6741 | break; |
||
6742 | case TOK_REGISTER: |
||
6743 | case TOK_AUTO: |
||
6744 | case TOK_RESTRICT1: |
||
6745 | case TOK_RESTRICT2: |
||
6746 | case TOK_RESTRICT3: |
||
6747 | next(); |
||
6748 | break; |
||
6749 | case TOK_UNSIGNED: |
||
6750 | t |= VT_UNSIGNED; |
||
6751 | next(); |
||
6752 | typespec_found = 1; |
||
6753 | break; |
||
6754 | |||
6755 | /* storage */ |
||
6756 | case TOK_EXTERN: |
||
6757 | t |= VT_EXTERN; |
||
6758 | next(); |
||
6759 | break; |
||
6760 | case TOK_STATIC: |
||
6761 | t |= VT_STATIC; |
||
6762 | next(); |
||
6763 | break; |
||
6764 | case TOK_TYPEDEF: |
||
6765 | t |= VT_TYPEDEF; |
||
6766 | next(); |
||
6767 | break; |
||
6768 | case TOK_INLINE1: |
||
6769 | case TOK_INLINE2: |
||
6770 | case TOK_INLINE3: |
||
6771 | t |= VT_INLINE; |
||
6772 | next(); |
||
6773 | break; |
||
6774 | |||
6775 | /* GNUC attribute */ |
||
6776 | case TOK_ATTRIBUTE1: |
||
6777 | case TOK_ATTRIBUTE2: |
||
6778 | parse_attribute(ad); |
||
6779 | break; |
||
6780 | /* GNUC typeof */ |
||
6781 | case TOK_TYPEOF1: |
||
6782 | case TOK_TYPEOF2: |
||
6783 | case TOK_TYPEOF3: |
||
6784 | next(); |
||
6785 | parse_expr_type(&type1); |
||
6786 | goto basic_type2; |
||
6787 | default: |
||
6788 | if (typespec_found) |
||
6789 | goto the_end; |
||
6790 | s = sym_find(tok); |
||
6791 | if (!s || !(s->type.t & VT_TYPEDEF)) |
||
6792 | goto the_end; |
||
6793 | t |= (s->type.t & ~VT_TYPEDEF); |
||
6794 | type->ref = s->type.ref; |
||
6795 | next(); |
||
6796 | break; |
||
6797 | } |
||
6798 | type_found = 1; |
||
6799 | } |
||
6800 | the_end: |
||
6801 | if ((t & (VT_SIGNED|VT_UNSIGNED)) == (VT_SIGNED|VT_UNSIGNED)) |
||
6802 | error("signed and unsigned modifier"); |
||
6803 | if (tcc_state->char_is_unsigned) { |
||
6804 | if ((t & (VT_SIGNED|VT_UNSIGNED|VT_BTYPE)) == VT_BYTE) |
||
6805 | t |= VT_UNSIGNED; |
||
6806 | } |
||
6807 | t &= ~VT_SIGNED; |
||
6808 | |||
6809 | /* long is never used as type */ |
||
6810 | if ((t & VT_BTYPE) == VT_LONG) |
||
6811 | t = (t & ~VT_BTYPE) | VT_INT; |
||
6812 | type->t = t; |
||
6813 | return type_found; |
||
6814 | } |
||
6815 | |||
6816 | /* convert a function parameter type (array to pointer and function to |
||
6817 | function pointer) */ |
||
6818 | static inline void convert_parameter_type(CType *pt) |
||
6819 | { |
||
6820 | /* remove const and volatile qualifiers (XXX: const could be used |
||
6821 | to indicate a const function parameter */ |
||
6822 | pt->t &= ~(VT_CONSTANT | VT_VOLATILE); |
||
6823 | /* array must be transformed to pointer according to ANSI C */ |
||
6824 | pt->t &= ~VT_ARRAY; |
||
6825 | if ((pt->t & VT_BTYPE) == VT_FUNC) { |
||
6826 | mk_pointer(pt); |
||
6827 | } |
||
6828 | } |
||
6829 | |||
6830 | static void post_type(CType *type, AttributeDef *ad) |
||
6831 | { |
||
6832 | int n, l, t1; |
||
6833 | Sym **plast, *s, *first; |
||
6834 | AttributeDef ad1; |
||
6835 | CType pt; |
||
6836 | |||
6837 | if (tok == '(') { |
||
6838 | /* function declaration */ |
||
6839 | next(); |
||
6840 | l = 0; |
||
6841 | first = NULL; |
||
6842 | plast = &first; |
||
6843 | while (tok != ')') { |
||
6844 | /* read param name and compute offset */ |
||
6845 | if (l != FUNC_OLD) { |
||
6846 | if (!parse_btype(&pt, &ad1)) { |
||
6847 | if (l) { |
||
6848 | error("invalid type"); |
||
6849 | } else { |
||
6850 | l = FUNC_OLD; |
||
6851 | goto old_proto; |
||
6852 | } |
||
6853 | } |
||
6854 | l = FUNC_NEW; |
||
6855 | if ((pt.t & VT_BTYPE) == VT_VOID && tok == ')') |
||
6856 | break; |
||
6857 | type_decl(&pt, &ad1, &n, TYPE_DIRECT | TYPE_ABSTRACT); |
||
6858 | if ((pt.t & VT_BTYPE) == VT_VOID) |
||
6859 | error("parameter declared as void"); |
||
6860 | } else { |
||
6861 | old_proto: |
||
6862 | n = tok; |
||
6863 | pt.t = VT_INT; |
||
6864 | next(); |
||
6865 | } |
||
6866 | convert_parameter_type(&pt); |
||
6867 | s = sym_push(n | SYM_FIELD, &pt, 0, 0); |
||
6868 | *plast = s; |
||
6869 | plast = &s->next; |
||
6870 | if (tok == ',') { |
||
6871 | next(); |
||
6872 | if (l == FUNC_NEW && tok == TOK_DOTS) { |
||
6873 | l = FUNC_ELLIPSIS; |
||
6874 | next(); |
||
6875 | break; |
||
6876 | } |
||
6877 | } |
||
6878 | } |
||
6879 | /* if no parameters, then old type prototype */ |
||
6880 | if (l == 0) |
||
6881 | l = FUNC_OLD; |
||
6882 | skip(')'); |
||
6883 | t1 = type->t & VT_STORAGE; |
||
6884 | /* NOTE: const is ignored in returned type as it has a special |
||
6885 | meaning in gcc / C++ */ |
||
6886 | type->t &= ~(VT_STORAGE | VT_CONSTANT); |
||
6887 | post_type(type, ad); |
||
6888 | /* we push a anonymous symbol which will contain the function prototype */ |
||
6889 | s = sym_push(SYM_FIELD, type, ad->func_call, l); |
||
6890 | s->next = first; |
||
6891 | type->t = t1 | VT_FUNC; |
||
6892 | type->ref = s; |
||
6893 | } else if (tok == '[') { |
||
6894 | /* array definition */ |
||
6895 | next(); |
||
6896 | n = -1; |
||
6897 | if (tok != ']') { |
||
6898 | n = expr_const(); |
||
6899 | if (n < 0) |
||
6900 | error("invalid array size"); |
||
6901 | } |
||
6902 | skip(']'); |
||
6903 | /* parse next post type */ |
||
6904 | t1 = type->t & VT_STORAGE; |
||
6905 | type->t &= ~VT_STORAGE; |
||
6906 | post_type(type, ad); |
||
6907 | |||
6908 | /* we push a anonymous symbol which will contain the array |
||
6909 | element type */ |
||
6910 | s = sym_push(SYM_FIELD, type, 0, n); |
||
6911 | type->t = t1 | VT_ARRAY | VT_PTR; |
||
6912 | type->ref = s; |
||
6913 | } |
||
6914 | } |
||
6915 | |||
6916 | /* Parse a type declaration (except basic type), and return the type |
||
6917 | in 'type'. 'td' is a bitmask indicating which kind of type decl is |
||
6918 | expected. 'type' should contain the basic type. 'ad' is the |
||
6919 | attribute definition of the basic type. It can be modified by |
||
6920 | type_decl(). |
||
6921 | */ |
||
6922 | static void type_decl(CType *type, AttributeDef *ad, int *v, int td) |
||
6923 | { |
||
6924 | Sym *s; |
||
6925 | CType type1, *type2; |
||
6926 | int qualifiers; |
||
6927 | |||
6928 | while (tok == '*') { |
||
6929 | qualifiers = 0; |
||
6930 | redo: |
||
6931 | next(); |
||
6932 | switch(tok) { |
||
6933 | case TOK_CONST1: |
||
6934 | case TOK_CONST2: |
||
6935 | case TOK_CONST3: |
||
6936 | qualifiers |= VT_CONSTANT; |
||
6937 | goto redo; |
||
6938 | case TOK_VOLATILE1: |
||
6939 | case TOK_VOLATILE2: |
||
6940 | case TOK_VOLATILE3: |
||
6941 | qualifiers |= VT_VOLATILE; |
||
6942 | goto redo; |
||
6943 | case TOK_RESTRICT1: |
||
6944 | case TOK_RESTRICT2: |
||
6945 | case TOK_RESTRICT3: |
||
6946 | goto redo; |
||
6947 | } |
||
6948 | mk_pointer(type); |
||
6949 | type->t |= qualifiers; |
||
6950 | } |
||
6951 | |||
6952 | /* XXX: clarify attribute handling */ |
||
6953 | if (tok == TOK_ATTRIBUTE1 || tok == TOK_ATTRIBUTE2) |
||
6954 | parse_attribute(ad); |
||
6955 | |||
6956 | /* recursive type */ |
||
6957 | /* XXX: incorrect if abstract type for functions (e.g. 'int ()') */ |
||
6958 | type1.t = 0; /* XXX: same as int */ |
||
6959 | if (tok == '(') { |
||
6960 | next(); |
||
6961 | /* XXX: this is not correct to modify 'ad' at this point, but |
||
6962 | the syntax is not clear */ |
||
6963 | if (tok == TOK_ATTRIBUTE1 || tok == TOK_ATTRIBUTE2) |
||
6964 | parse_attribute(ad); |
||
6965 | type_decl(&type1, ad, v, td); |
||
6966 | skip(')'); |
||
6967 | } else { |
||
6968 | /* type identifier */ |
||
6969 | if (tok >= TOK_IDENT && (td & TYPE_DIRECT)) { |
||
6970 | *v = tok; |
||
6971 | next(); |
||
6972 | } else { |
||
6973 | if (!(td & TYPE_ABSTRACT)) |
||
6974 | expect("identifier"); |
||
6975 | *v = 0; |
||
6976 | } |
||
6977 | } |
||
6978 | post_type(type, ad); |
||
6979 | if (tok == TOK_ATTRIBUTE1 || tok == TOK_ATTRIBUTE2) |
||
6980 | parse_attribute(ad); |
||
6981 | if (!type1.t) |
||
6982 | return; |
||
6983 | /* append type at the end of type1 */ |
||
6984 | type2 = &type1; |
||
6985 | for(;;) { |
||
6986 | s = type2->ref; |
||
6987 | type2 = &s->type; |
||
6988 | if (!type2->t) { |
||
6989 | *type2 = *type; |
||
6990 | break; |
||
6991 | } |
||
6992 | } |
||
6993 | *type = type1; |
||
6994 | } |
||
6995 | |||
6996 | /* compute the lvalue VT_LVAL_xxx needed to match type t. */ |
||
6997 | static int lvalue_type(int t) |
||
6998 | { |
||
6999 | int bt, r; |
||
7000 | r = VT_LVAL; |
||
7001 | bt = t & VT_BTYPE; |
||
7002 | if (bt == VT_BYTE || bt == VT_BOOL) |
||
7003 | r |= VT_LVAL_BYTE; |
||
7004 | else if (bt == VT_SHORT) |
||
7005 | r |= VT_LVAL_SHORT; |
||
7006 | else |
||
7007 | return r; |
||
7008 | if (t & VT_UNSIGNED) |
||
7009 | r |= VT_LVAL_UNSIGNED; |
||
7010 | return r; |
||
7011 | } |
||
7012 | |||
7013 | /* indirection with full error checking and bound check */ |
||
7014 | static void indir(void) |
||
7015 | { |
||
7016 | if ((vtop->type.t & VT_BTYPE) != VT_PTR) |
||
7017 | expect("pointer"); |
||
7018 | if ((vtop->r & VT_LVAL) && !nocode_wanted) |
||
7019 | gv(RC_INT); |
||
7020 | vtop->type = *pointed_type(&vtop->type); |
||
7021 | /* an array is never an lvalue */ |
||
7022 | if (!(vtop->type.t & VT_ARRAY)) { |
||
7023 | vtop->r |= lvalue_type(vtop->type.t); |
||
7024 | /* if bound checking, the referenced pointer must be checked */ |
||
7025 | if (do_bounds_check) |
||
7026 | vtop->r |= VT_MUSTBOUND; |
||
7027 | } |
||
7028 | } |
||
7029 | |||
7030 | /* pass a parameter to a function and do type checking and casting */ |
||
7031 | static void gfunc_param_typed(Sym *func, Sym *arg) |
||
7032 | { |
||
7033 | int func_type; |
||
7034 | CType type; |
||
7035 | |||
7036 | func_type = func->c; |
||
7037 | if (func_type == FUNC_OLD || |
||
7038 | (func_type == FUNC_ELLIPSIS && arg == NULL)) { |
||
7039 | /* default casting : only need to convert float to double */ |
||
7040 | if ((vtop->type.t & VT_BTYPE) == VT_FLOAT) { |
||
7041 | type.t = VT_DOUBLE; |
||
7042 | gen_cast(&type); |
||
7043 | } |
||
7044 | } else if (arg == NULL) { |
||
7045 | error("too many arguments to function"); |
||
7046 | } else { |
||
7047 | type = arg->type; |
||
7048 | type.t &= ~VT_CONSTANT; /* need to do that to avoid false warning */ |
||
7049 | gen_assign_cast(&type); |
||
7050 | } |
||
7051 | } |
||
7052 | |||
7053 | /* parse an expression of the form '(type)' or '(expr)' and return its |
||
7054 | type */ |
||
7055 | static void parse_expr_type(CType *type) |
||
7056 | { |
||
7057 | int n; |
||
7058 | AttributeDef ad; |
||
7059 | |||
7060 | skip('('); |
||
7061 | if (parse_btype(type, &ad)) { |
||
7062 | type_decl(type, &ad, &n, TYPE_ABSTRACT); |
||
7063 | } else { |
||
7064 | expr_type(type); |
||
7065 | } |
||
7066 | skip(')'); |
||
7067 | } |
||
7068 | |||
7069 | static void parse_type(CType *type) |
||
7070 | { |
||
7071 | AttributeDef ad; |
||
7072 | int n; |
||
7073 | |||
7074 | if (!parse_btype(type, &ad)) { |
||
7075 | expect("type"); |
||
7076 | } |
||
7077 | type_decl(type, &ad, &n, TYPE_ABSTRACT); |
||
7078 | } |
||
7079 | |||
7080 | static void vpush_tokc(int t) |
||
7081 | { |
||
7082 | CType type; |
||
7083 | type.t = t; |
||
7084 | vsetc(&type, VT_CONST, &tokc); |
||
7085 | } |
||
7086 | |||
7087 | static void unary(void) |
||
7088 | { |
||
7089 | int n, t, align, size, r; |
||
7090 | CType type; |
||
7091 | Sym *s; |
||
7092 | AttributeDef ad; |
||
7093 | |||
7094 | /* XXX: GCC 2.95.3 does not generate a table although it should be |
||
7095 | better here */ |
||
7096 | tok_next: |
||
7097 | switch(tok) { |
||
7098 | case TOK_EXTENSION: |
||
7099 | next(); |
||
7100 | goto tok_next; |
||
7101 | case TOK_CINT: |
||
7102 | case TOK_CCHAR: |
||
7103 | case TOK_LCHAR: |
||
7104 | vpushi(tokc.i); |
||
7105 | next(); |
||
7106 | break; |
||
7107 | case TOK_CUINT: |
||
7108 | vpush_tokc(VT_INT | VT_UNSIGNED); |
||
7109 | next(); |
||
7110 | break; |
||
7111 | case TOK_CLLONG: |
||
7112 | vpush_tokc(VT_LLONG); |
||
7113 | next(); |
||
7114 | break; |
||
7115 | case TOK_CULLONG: |
||
7116 | vpush_tokc(VT_LLONG | VT_UNSIGNED); |
||
7117 | next(); |
||
7118 | break; |
||
7119 | case TOK_CFLOAT: |
||
7120 | vpush_tokc(VT_FLOAT); |
||
7121 | next(); |
||
7122 | break; |
||
7123 | case TOK_CDOUBLE: |
||
7124 | vpush_tokc(VT_DOUBLE); |
||
7125 | next(); |
||
7126 | break; |
||
7127 | case TOK_CLDOUBLE: |
||
7128 | vpush_tokc(VT_LDOUBLE); |
||
7129 | next(); |
||
7130 | break; |
||
7131 | case TOK___FUNCTION__: |
||
7132 | if (!gnu_ext) |
||
7133 | goto tok_identifier; |
||
7134 | /* fall thru */ |
||
7135 | case TOK___FUNC__: |
||
7136 | { |
||
7137 | void *ptr; |
||
7138 | int len; |
||
7139 | /* special function name identifier */ |
||
7140 | len = strlen(funcname) + 1; |
||
7141 | /* generate char[len] type */ |
||
7142 | type.t = VT_BYTE; |
||
7143 | mk_pointer(&type); |
||
7144 | type.t |= VT_ARRAY; |
||
7145 | type.ref->c = len; |
||
7146 | vpush_ref(&type, data_section, data_section->data_offset, len); |
||
7147 | ptr = section_ptr_add(data_section, len); |
||
7148 | memcpy(ptr, funcname, len); |
||
7149 | next(); |
||
7150 | } |
||
7151 | break; |
||
7152 | case TOK_LSTR: |
||
7153 | t = VT_INT; |
||
7154 | goto str_init; |
||
7155 | case TOK_STR: |
||
7156 | /* string parsing */ |
||
7157 | t = VT_BYTE; |
||
7158 | str_init: |
||
7159 | if (tcc_state->warn_write_strings) |
||
7160 | t |= VT_CONSTANT; |
||
7161 | type.t = t; |
||
7162 | mk_pointer(&type); |
||
7163 | type.t |= VT_ARRAY; |
||
7164 | memset(&ad, 0, sizeof(AttributeDef)); |
||
7165 | decl_initializer_alloc(&type, &ad, VT_CONST, 2, 0, 0); |
||
7166 | break; |
||
7167 | case '(': |
||
7168 | next(); |
||
7169 | /* cast ? */ |
||
7170 | if (parse_btype(&type, &ad)) { |
||
7171 | type_decl(&type, &ad, &n, TYPE_ABSTRACT); |
||
7172 | skip(')'); |
||
7173 | /* check ISOC99 compound literal */ |
||
7174 | if (tok == '{') { |
||
7175 | /* data is allocated locally by default */ |
||
7176 | if (global_expr) |
||
7177 | r = VT_CONST; |
||
7178 | else |
||
7179 | r = VT_LOCAL; |
||
7180 | /* all except arrays are lvalues */ |
||
7181 | if (!(type.t & VT_ARRAY)) |
||
7182 | r |= lvalue_type(type.t); |
||
7183 | memset(&ad, 0, sizeof(AttributeDef)); |
||
7184 | decl_initializer_alloc(&type, &ad, r, 1, 0, 0); |
||
7185 | } else { |
||
7186 | unary(); |
||
7187 | gen_cast(&type); |
||
7188 | } |
||
7189 | } else if (tok == '{') { |
||
7190 | /* save all registers */ |
||
7191 | save_regs(0); |
||
7192 | /* statement expression : we do not accept break/continue |
||
7193 | inside as GCC does */ |
||
7194 | block(NULL, NULL, NULL, NULL, 0, 1); |
||
7195 | skip(')'); |
||
7196 | } else { |
||
7197 | gexpr(); |
||
7198 | skip(')'); |
||
7199 | } |
||
7200 | break; |
||
7201 | case '*': |
||
7202 | next(); |
||
7203 | unary(); |
||
7204 | indir(); |
||
7205 | break; |
||
7206 | case '&': |
||
7207 | next(); |
||
7208 | unary(); |
||
7209 | /* functions names must be treated as function pointers, |
||
7210 | except for unary '&' and sizeof. Since we consider that |
||
7211 | functions are not lvalues, we only have to handle it |
||
7212 | there and in function calls. */ |
||
7213 | /* arrays can also be used although they are not lvalues */ |
||
7214 | if ((vtop->type.t & VT_BTYPE) != VT_FUNC && |
||
7215 | !(vtop->type.t & VT_ARRAY)) |
||
7216 | test_lvalue(); |
||
7217 | mk_pointer(&vtop->type); |
||
7218 | gaddrof(); |
||
7219 | break; |
||
7220 | case '!': |
||
7221 | next(); |
||
7222 | unary(); |
||
7223 | if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) |
||
7224 | vtop->c.i = !vtop->c.i; |
||
7225 | else if ((vtop->r & VT_VALMASK) == VT_CMP) |
||
7226 | vtop->c.i = vtop->c.i ^ 1; |
||
7227 | else |
||
7228 | vseti(VT_JMP, gtst(1, 0)); |
||
7229 | break; |
||
7230 | case '~': |
||
7231 | next(); |
||
7232 | unary(); |
||
7233 | vpushi(-1); |
||
7234 | gen_op('^'); |
||
7235 | break; |
||
7236 | case '+': |
||
7237 | next(); |
||
7238 | /* in order to force cast, we add zero */ |
||
7239 | unary(); |
||
7240 | if ((vtop->type.t & VT_BTYPE) == VT_PTR) |
||
7241 | error("pointer not accepted for unary plus"); |
||
7242 | vpushi(0); |
||
7243 | gen_op('+'); |
||
7244 | break; |
||
7245 | case TOK_SIZEOF: |
||
7246 | case TOK_ALIGNOF1: |
||
7247 | case TOK_ALIGNOF2: |
||
7248 | t = tok; |
||
7249 | next(); |
||
7250 | if (tok == '(') { |
||
7251 | parse_expr_type(&type); |
||
7252 | } else { |
||
7253 | unary_type(&type); |
||
7254 | } |
||
7255 | size = type_size(&type, &align); |
||
7256 | if (t == TOK_SIZEOF) { |
||
7257 | if (size < 0) |
||
7258 | error("sizeof applied to an incomplete type"); |
||
7259 | vpushi(size); |
||
7260 | } else { |
||
7261 | vpushi(align); |
||
7262 | } |
||
7263 | break; |
||
7264 | |||
7265 | case TOK_builtin_types_compatible_p: |
||
7266 | { |
||
7267 | CType type1, type2; |
||
7268 | next(); |
||
7269 | skip('('); |
||
7270 | parse_type(&type1); |
||
7271 | skip(','); |
||
7272 | parse_type(&type2); |
||
7273 | skip(')'); |
||
7274 | type1.t &= ~(VT_CONSTANT | VT_VOLATILE); |
||
7275 | type2.t &= ~(VT_CONSTANT | VT_VOLATILE); |
||
7276 | vpushi(is_compatible_types(&type1, &type2)); |
||
7277 | } |
||
7278 | break; |
||
7279 | case TOK_builtin_constant_p: |
||
7280 | { |
||
7281 | int saved_nocode_wanted, res; |
||
7282 | next(); |
||
7283 | skip('('); |
||
7284 | saved_nocode_wanted = nocode_wanted; |
||
7285 | nocode_wanted = 1; |
||
7286 | gexpr(); |
||
7287 | res = (vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; |
||
7288 | vpop(); |
||
7289 | nocode_wanted = saved_nocode_wanted; |
||
7290 | skip(')'); |
||
7291 | vpushi(res); |
||
7292 | } |
||
7293 | break; |
||
7294 | case TOK_INC: |
||
7295 | case TOK_DEC: |
||
7296 | t = tok; |
||
7297 | next(); |
||
7298 | unary(); |
||
7299 | inc(0, t); |
||
7300 | break; |
||
7301 | case '-': |
||
7302 | next(); |
||
7303 | vpushi(0); |
||
7304 | unary(); |
||
7305 | gen_op('-'); |
||
7306 | break; |
||
7307 | case TOK_LAND: |
||
7308 | if (!gnu_ext) |
||
7309 | goto tok_identifier; |
||
7310 | next(); |
||
7311 | /* allow to take the address of a label */ |
||
7312 | if (tok < TOK_UIDENT) |
||
7313 | expect("label identifier"); |
||
7314 | s = label_find(tok); |
||
7315 | if (!s) { |
||
7316 | s = label_push(&global_label_stack, tok, LABEL_FORWARD); |
||
7317 | } else { |
||
7318 | if (s->r == LABEL_DECLARED) |
||
7319 | s->r = LABEL_FORWARD; |
||
7320 | } |
||
7321 | if (!s->type.t) { |
||
7322 | s->type.t = VT_VOID; |
||
7323 | mk_pointer(&s->type); |
||
7324 | s->type.t |= VT_STATIC; |
||
7325 | } |
||
7326 | vset(&s->type, VT_CONST | VT_SYM, 0); |
||
7327 | vtop->sym = s; |
||
7328 | next(); |
||
7329 | break; |
||
7330 | default: |
||
7331 | tok_identifier: |
||
7332 | t = tok; |
||
7333 | next(); |
||
7334 | if (t < TOK_UIDENT) |
||
7335 | expect("identifier"); |
||
7336 | s = sym_find(t); |
||
7337 | if (!s) { |
||
7338 | if (tok != '(') |
||
7339 | error("'%s' undeclared", get_tok_str(t, NULL)); |
||
7340 | /* for simple function calls, we tolerate undeclared |
||
7341 | external reference to int() function */ |
||
7342 | if (tcc_state->warn_implicit_function_declaration) |
||
7343 | warning("implicit declaration of function '%s'", |
||
7344 | get_tok_str(t, NULL)); |
||
7345 | s = external_global_sym(t, &func_old_type, 0); |
||
7346 | } |
||
7347 | if ((s->type.t & (VT_STATIC | VT_INLINE | VT_BTYPE)) == |
||
7348 | (VT_STATIC | VT_INLINE | VT_FUNC)) { |
||
7349 | /* if referencing an inline function, then we generate a |
||
7350 | symbol to it if not already done. It will have the |
||
7351 | effect to generate code for it at the end of the |
||
7352 | compilation unit. Inline function as always |
||
7353 | generated in the text section. */ |
||
7354 | if (!s->c) |
||
7355 | put_extern_sym(s, text_section, 0, 0); |
||
7356 | r = VT_SYM | VT_CONST; |
||
7357 | } else { |
||
7358 | r = s->r; |
||
7359 | } |
||
7360 | vset(&s->type, r, s->c); |
||
7361 | /* if forward reference, we must point to s */ |
||
7362 | if (vtop->r & VT_SYM) { |
||
7363 | vtop->sym = s; |
||
7364 | vtop->c.ul = 0; |
||
7365 | } |
||
7366 | break; |
||
7367 | } |
||
7368 | |||
7369 | /* post operations */ |
||
7370 | while (1) { |
||
7371 | if (tok == TOK_INC || tok == TOK_DEC) { |
||
7372 | inc(1, tok); |
||
7373 | next(); |
||
7374 | } else if (tok == '.' || tok == TOK_ARROW) { |
||
7375 | /* field */ |
||
7376 | if (tok == TOK_ARROW) |
||
7377 | indir(); |
||
7378 | test_lvalue(); |
||
7379 | gaddrof(); |
||
7380 | next(); |
||
7381 | /* expect pointer on structure */ |
||
7382 | if ((vtop->type.t & VT_BTYPE) != VT_STRUCT) |
||
7383 | expect("struct or union"); |
||
7384 | s = vtop->type.ref; |
||
7385 | /* find field */ |
||
7386 | tok |= SYM_FIELD; |
||
7387 | while ((s = s->next) != NULL) { |
||
7388 | if (s->v == tok) |
||
7389 | break; |
||
7390 | } |
||
7391 | if (!s) |
||
7392 | error("field not found"); |
||
7393 | /* add field offset to pointer */ |
||
7394 | vtop->type = char_pointer_type; /* change type to 'char *' */ |
||
7395 | vpushi(s->c); |
||
7396 | gen_op('+'); |
||
7397 | /* change type to field type, and set to lvalue */ |
||
7398 | vtop->type = s->type; |
||
7399 | /* an array is never an lvalue */ |
||
7400 | if (!(vtop->type.t & VT_ARRAY)) { |
||
7401 | vtop->r |= lvalue_type(vtop->type.t); |
||
7402 | /* if bound checking, the referenced pointer must be checked */ |
||
7403 | if (do_bounds_check) |
||
7404 | vtop->r |= VT_MUSTBOUND; |
||
7405 | } |
||
7406 | next(); |
||
7407 | } else if (tok == '[') { |
||
7408 | next(); |
||
7409 | gexpr(); |
||
7410 | gen_op('+'); |
||
7411 | indir(); |
||
7412 | skip(']'); |
||
7413 | } else if (tok == '(') { |
||
7414 | SValue ret; |
||
7415 | Sym *sa; |
||
7416 | int nb_args; |
||
7417 | |||
7418 | /* function call */ |
||
7419 | if ((vtop->type.t & VT_BTYPE) != VT_FUNC) { |
||
7420 | /* pointer test (no array accepted) */ |
||
7421 | if ((vtop->type.t & (VT_BTYPE | VT_ARRAY)) == VT_PTR) { |
||
7422 | vtop->type = *pointed_type(&vtop->type); |
||
7423 | if ((vtop->type.t & VT_BTYPE) != VT_FUNC) |
||
7424 | goto error_func; |
||
7425 | } else { |
||
7426 | error_func: |
||
7427 | expect("function pointer"); |
||
7428 | } |
||
7429 | } else { |
||
7430 | vtop->r &= ~VT_LVAL; /* no lvalue */ |
||
7431 | } |
||
7432 | /* get return type */ |
||
7433 | s = vtop->type.ref; |
||
7434 | next(); |
||
7435 | sa = s->next; /* first parameter */ |
||
7436 | nb_args = 0; |
||
7437 | /* compute first implicit argument if a structure is returned */ |
||
7438 | if ((s->type.t & VT_BTYPE) == VT_STRUCT) { |
||
7439 | /* get some space for the returned structure */ |
||
7440 | size = type_size(&s->type, &align); |
||
7441 | loc = (loc - size) & -align; |
||
7442 | ret.type = s->type; |
||
7443 | ret.r = VT_LOCAL | VT_LVAL; |
||
7444 | /* pass it as 'int' to avoid structure arg passing |
||
7445 | problems */ |
||
7446 | vseti(VT_LOCAL, loc); |
||
7447 | ret.c = vtop->c; |
||
7448 | nb_args++; |
||
7449 | } else { |
||
7450 | ret.type = s->type; |
||
7451 | ret.r2 = VT_CONST; |
||
7452 | /* return in register */ |
||
7453 | if (is_float(ret.type.t)) { |
||
7454 | ret.r = REG_FRET; |
||
7455 | } else { |
||
7456 | if ((ret.type.t & VT_BTYPE) == VT_LLONG) |
||
7457 | ret.r2 = REG_LRET; |
||
7458 | ret.r = REG_IRET; |
||
7459 | } |
||
7460 | ret.c.i = 0; |
||
7461 | } |
||
7462 | if (tok != ')') { |
||
7463 | for(;;) { |
||
7464 | expr_eq(); |
||
7465 | gfunc_param_typed(s, sa); |
||
7466 | nb_args++; |
||
7467 | if (sa) |
||
7468 | sa = sa->next; |
||
7469 | if (tok == ')') |
||
7470 | break; |
||
7471 | skip(','); |
||
7472 | } |
||
7473 | } |
||
7474 | if (sa) |
||
7475 | error("too few arguments to function"); |
||
7476 | skip(')'); |
||
7477 | if (!nocode_wanted) { |
||
7478 | gfunc_call(nb_args); |
||
7479 | } else { |
||
7480 | vtop -= (nb_args + 1); |
||
7481 | } |
||
7482 | /* return value */ |
||
7483 | vsetc(&ret.type, ret.r, &ret.c); |
||
7484 | vtop->r2 = ret.r2; |
||
7485 | } else { |
||
7486 | break; |
||
7487 | } |
||
7488 | } |
||
7489 | } |
||
7490 | |||
7491 | static void uneq(void) |
||
7492 | { |
||
7493 | int t; |
||
7494 | |||
7495 | unary(); |
||
7496 | if (tok == '=' || |
||
7497 | (tok >= TOK_A_MOD && tok <= TOK_A_DIV) || |
||
7498 | tok == TOK_A_XOR || tok == TOK_A_OR || |
||
7499 | tok == TOK_A_SHL || tok == TOK_A_SAR) { |
||
7500 | test_lvalue(); |
||
7501 | t = tok; |
||
7502 | next(); |
||
7503 | if (t == '=') { |
||
7504 | expr_eq(); |
||
7505 | } else { |
||
7506 | vdup(); |
||
7507 | expr_eq(); |
||
7508 | gen_op(t & 0x7f); |
||
7509 | } |
||
7510 | vstore(); |
||
7511 | } |
||
7512 | } |
||
7513 | |||
7514 | static void expr_prod(void) |
||
7515 | { |
||
7516 | int t; |
||
7517 | |||
7518 | uneq(); |
||
7519 | while (tok == '*' || tok == '/' || tok == '%') { |
||
7520 | t = tok; |
||
7521 | next(); |
||
7522 | uneq(); |
||
7523 | gen_op(t); |
||
7524 | } |
||
7525 | } |
||
7526 | |||
7527 | static void expr_sum(void) |
||
7528 | { |
||
7529 | int t; |
||
7530 | |||
7531 | expr_prod(); |
||
7532 | while (tok == '+' || tok == '-') { |
||
7533 | t = tok; |
||
7534 | next(); |
||
7535 | expr_prod(); |
||
7536 | gen_op(t); |
||
7537 | } |
||
7538 | } |
||
7539 | |||
7540 | static void expr_shift(void) |
||
7541 | { |
||
7542 | int t; |
||
7543 | |||
7544 | expr_sum(); |
||
7545 | while (tok == TOK_SHL || tok == TOK_SAR) { |
||
7546 | t = tok; |
||
7547 | next(); |
||
7548 | expr_sum(); |
||
7549 | gen_op(t); |
||
7550 | } |
||
7551 | } |
||
7552 | |||
7553 | static void expr_cmp(void) |
||
7554 | { |
||
7555 | int t; |
||
7556 | |||
7557 | expr_shift(); |
||
7558 | while ((tok >= TOK_ULE && tok <= TOK_GT) || |
||
7559 | tok == TOK_ULT || tok == TOK_UGE) { |
||
7560 | t = tok; |
||
7561 | next(); |
||
7562 | expr_shift(); |
||
7563 | gen_op(t); |
||
7564 | } |
||
7565 | } |
||
7566 | |||
7567 | static void expr_cmpeq(void) |
||
7568 | { |
||
7569 | int t; |
||
7570 | |||
7571 | expr_cmp(); |
||
7572 | while (tok == TOK_EQ || tok == TOK_NE) { |
||
7573 | t = tok; |
||
7574 | next(); |
||
7575 | expr_cmp(); |
||
7576 | gen_op(t); |
||
7577 | } |
||
7578 | } |
||
7579 | |||
7580 | static void expr_and(void) |
||
7581 | { |
||
7582 | expr_cmpeq(); |
||
7583 | while (tok == '&') { |
||
7584 | next(); |
||
7585 | expr_cmpeq(); |
||
7586 | gen_op('&'); |
||
7587 | } |
||
7588 | } |
||
7589 | |||
7590 | static void expr_xor(void) |
||
7591 | { |
||
7592 | expr_and(); |
||
7593 | while (tok == '^') { |
||
7594 | next(); |
||
7595 | expr_and(); |
||
7596 | gen_op('^'); |
||
7597 | } |
||
7598 | } |
||
7599 | |||
7600 | static void expr_or(void) |
||
7601 | { |
||
7602 | expr_xor(); |
||
7603 | while (tok == '|') { |
||
7604 | next(); |
||
7605 | expr_xor(); |
||
7606 | gen_op('|'); |
||
7607 | } |
||
7608 | } |
||
7609 | |||
7610 | /* XXX: fix this mess */ |
||
7611 | static void expr_land_const(void) |
||
7612 | { |
||
7613 | expr_or(); |
||
7614 | while (tok == TOK_LAND) { |
||
7615 | next(); |
||
7616 | expr_or(); |
||
7617 | gen_op(TOK_LAND); |
||
7618 | } |
||
7619 | } |
||
7620 | |||
7621 | /* XXX: fix this mess */ |
||
7622 | static void expr_lor_const(void) |
||
7623 | { |
||
7624 | expr_land_const(); |
||
7625 | while (tok == TOK_LOR) { |
||
7626 | next(); |
||
7627 | expr_land_const(); |
||
7628 | gen_op(TOK_LOR); |
||
7629 | } |
||
7630 | } |
||
7631 | |||
7632 | /* only used if non constant */ |
||
7633 | static void expr_land(void) |
||
7634 | { |
||
7635 | int t; |
||
7636 | |||
7637 | expr_or(); |
||
7638 | if (tok == TOK_LAND) { |
||
7639 | t = 0; |
||
7640 | for(;;) { |
||
7641 | t = gtst(1, t); |
||
7642 | if (tok != TOK_LAND) { |
||
7643 | vseti(VT_JMPI, t); |
||
7644 | break; |
||
7645 | } |
||
7646 | next(); |
||
7647 | expr_or(); |
||
7648 | } |
||
7649 | } |
||
7650 | } |
||
7651 | |||
7652 | static void expr_lor(void) |
||
7653 | { |
||
7654 | int t; |
||
7655 | |||
7656 | expr_land(); |
||
7657 | if (tok == TOK_LOR) { |
||
7658 | t = 0; |
||
7659 | for(;;) { |
||
7660 | t = gtst(0, t); |
||
7661 | if (tok != TOK_LOR) { |
||
7662 | vseti(VT_JMP, t); |
||
7663 | break; |
||
7664 | } |
||
7665 | next(); |
||
7666 | expr_land(); |
||
7667 | } |
||
7668 | } |
||
7669 | } |
||
7670 | |||
7671 | /* XXX: better constant handling */ |
||
7672 | static void expr_eq(void) |
||
7673 | { |
||
7674 | int tt, u, r1, r2, rc, t1, t2, bt1, bt2; |
||
7675 | SValue sv; |
||
7676 | CType type, type1, type2; |
||
7677 | |||
7678 | if (const_wanted) { |
||
7679 | int c1, c; |
||
7680 | expr_lor_const(); |
||
7681 | if (tok == '?') { |
||
7682 | c = vtop->c.i; |
||
7683 | vpop(); |
||
7684 | next(); |
||
7685 | if (tok == ':' && gnu_ext) { |
||
7686 | c1 = c; |
||
7687 | } else { |
||
7688 | gexpr(); |
||
7689 | c1 = vtop->c.i; |
||
7690 | vpop(); |
||
7691 | } |
||
7692 | skip(':'); |
||
7693 | expr_eq(); |
||
7694 | if (c) |
||
7695 | vtop->c.i = c1; |
||
7696 | } |
||
7697 | } else { |
||
7698 | expr_lor(); |
||
7699 | if (tok == '?') { |
||
7700 | next(); |
||
7701 | if (vtop != vstack) { |
||
7702 | /* needed to avoid having different registers saved in |
||
7703 | each branch */ |
||
7704 | if (is_float(vtop->type.t)) |
||
7705 | rc = RC_FLOAT; |
||
7706 | else |
||
7707 | rc = RC_INT; |
||
7708 | gv(rc); |
||
7709 | save_regs(1); |
||
7710 | } |
||
7711 | if (tok == ':' && gnu_ext) { |
||
7712 | gv_dup(); |
||
7713 | tt = gtst(1, 0); |
||
7714 | } else { |
||
7715 | tt = gtst(1, 0); |
||
7716 | gexpr(); |
||
7717 | } |
||
7718 | type1 = vtop->type; |
||
7719 | sv = *vtop; /* save value to handle it later */ |
||
7720 | vtop--; /* no vpop so that FP stack is not flushed */ |
||
7721 | skip(':'); |
||
7722 | u = gjmp(0); |
||
7723 | gsym(tt); |
||
7724 | expr_eq(); |
||
7725 | type2 = vtop->type; |
||
7726 | |||
7727 | t1 = type1.t; |
||
7728 | bt1 = t1 & VT_BTYPE; |
||
7729 | t2 = type2.t; |
||
7730 | bt2 = t2 & VT_BTYPE; |
||
7731 | /* cast operands to correct type according to ISOC rules */ |
||
7732 | if (is_float(bt1) || is_float(bt2)) { |
||
7733 | if (bt1 == VT_LDOUBLE || bt2 == VT_LDOUBLE) { |
||
7734 | type.t = VT_LDOUBLE; |
||
7735 | } else if (bt1 == VT_DOUBLE || bt2 == VT_DOUBLE) { |
||
7736 | type.t = VT_DOUBLE; |
||
7737 | } else { |
||
7738 | type.t = VT_FLOAT; |
||
7739 | } |
||
7740 | } else if (bt1 == VT_LLONG || bt2 == VT_LLONG) { |
||
7741 | /* cast to biggest op */ |
||
7742 | type.t = VT_LLONG; |
||
7743 | /* convert to unsigned if it does not fit in a long long */ |
||
7744 | if ((t1 & (VT_BTYPE | VT_UNSIGNED)) == (VT_LLONG | VT_UNSIGNED) || |
||
7745 | (t2 & (VT_BTYPE | VT_UNSIGNED)) == (VT_LLONG | VT_UNSIGNED)) |
||
7746 | type.t |= VT_UNSIGNED; |
||
7747 | } else if (bt1 == VT_PTR || bt2 == VT_PTR) { |
||
7748 | /* XXX: test pointer compatibility */ |
||
7749 | type = type1; |
||
7750 | } else if (bt1 == VT_STRUCT || bt2 == VT_STRUCT) { |
||
7751 | /* XXX: test structure compatibility */ |
||
7752 | type = type1; |
||
7753 | } else if (bt1 == VT_VOID || bt2 == VT_VOID) { |
||
7754 | /* NOTE: as an extension, we accept void on only one side */ |
||
7755 | type.t = VT_VOID; |
||
7756 | } else { |
||
7757 | /* integer operations */ |
||
7758 | type.t = VT_INT; |
||
7759 | /* convert to unsigned if it does not fit in an integer */ |
||
7760 | if ((t1 & (VT_BTYPE | VT_UNSIGNED)) == (VT_INT | VT_UNSIGNED) || |
||
7761 | (t2 & (VT_BTYPE | VT_UNSIGNED)) == (VT_INT | VT_UNSIGNED)) |
||
7762 | type.t |= VT_UNSIGNED; |
||
7763 | } |
||
7764 | |||
7765 | /* now we convert second operand */ |
||
7766 | gen_cast(&type); |
||
7767 | rc = RC_INT; |
||
7768 | if (is_float(type.t)) { |
||
7769 | rc = RC_FLOAT; |
||
7770 | } else if ((type.t & VT_BTYPE) == VT_LLONG) { |
||
7771 | /* for long longs, we use fixed registers to avoid having |
||
7772 | to handle a complicated move */ |
||
7773 | rc = RC_IRET; |
||
7774 | } |
||
7775 | |||
7776 | r2 = gv(rc); |
||
7777 | /* this is horrible, but we must also convert first |
||
7778 | operand */ |
||
7779 | tt = gjmp(0); |
||
7780 | gsym(u); |
||
7781 | /* put again first value and cast it */ |
||
7782 | *vtop = sv; |
||
7783 | gen_cast(&type); |
||
7784 | r1 = gv(rc); |
||
7785 | move_reg(r2, r1); |
||
7786 | vtop->r = r2; |
||
7787 | gsym(tt); |
||
7788 | } |
||
7789 | } |
||
7790 | } |
||
7791 | |||
7792 | static void gexpr(void) |
||
7793 | { |
||
7794 | while (1) { |
||
7795 | expr_eq(); |
||
7796 | if (tok != ',') |
||
7797 | break; |
||
7798 | vpop(); |
||
7799 | next(); |
||
7800 | } |
||
7801 | } |
||
7802 | |||
7803 | /* parse an expression and return its type without any side effect. */ |
||
7804 | static void expr_type(CType *type) |
||
7805 | { |
||
7806 | int saved_nocode_wanted; |
||
7807 | |||
7808 | saved_nocode_wanted = nocode_wanted; |
||
7809 | nocode_wanted = 1; |
||
7810 | gexpr(); |
||
7811 | *type = vtop->type; |
||
7812 | vpop(); |
||
7813 | nocode_wanted = saved_nocode_wanted; |
||
7814 | } |
||
7815 | |||
7816 | /* parse a unary expression and return its type without any side |
||
7817 | effect. */ |
||
7818 | static void unary_type(CType *type) |
||
7819 | { |
||
7820 | int a; |
||
7821 | |||
7822 | a = nocode_wanted; |
||
7823 | nocode_wanted = 1; |
||
7824 | unary(); |
||
7825 | *type = vtop->type; |
||
7826 | vpop(); |
||
7827 | nocode_wanted = a; |
||
7828 | } |
||
7829 | |||
7830 | /* parse a constant expression and return value in vtop. */ |
||
7831 | static void expr_const1(void) |
||
7832 | { |
||
7833 | int a; |
||
7834 | a = const_wanted; |
||
7835 | const_wanted = 1; |
||
7836 | expr_eq(); |
||
7837 | const_wanted = a; |
||
7838 | } |
||
7839 | |||
7840 | /* parse an integer constant and return its value. */ |
||
7841 | static int expr_const(void) |
||
7842 | { |
||
7843 | int c; |
||
7844 | expr_const1(); |
||
7845 | if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) != VT_CONST) |
||
7846 | expect("constant expression"); |
||
7847 | c = vtop->c.i; |
||
7848 | vpop(); |
||
7849 | return c; |
||
7850 | } |
||
7851 | |||
7852 | /* return the label token if current token is a label, otherwise |
||
7853 | return zero */ |
||
7854 | static int is_label(void) |
||
7855 | { |
||
7856 | int last_tok; |
||
7857 | |||
7858 | /* fast test first */ |
||
7859 | if (tok < TOK_UIDENT) |
||
7860 | return 0; |
||
7861 | /* no need to save tokc because tok is an identifier */ |
||
7862 | last_tok = tok; |
||
7863 | next(); |
||
7864 | if (tok == ':') { |
||
7865 | next(); |
||
7866 | return last_tok; |
||
7867 | } else { |
||
7868 | unget_tok(last_tok); |
||
7869 | return 0; |
||
7870 | } |
||
7871 | } |
||
7872 | |||
7873 | static void block(int *bsym, int *csym, int *case_sym, int *def_sym, |
||
7874 | int case_reg, int is_expr) |
||
7875 | { |
||
7876 | int a, b, c, d; |
||
7877 | Sym *s; |
||
7878 | |||
7879 | /* generate line number info */ |
||
7880 | if (do_debug && |
||
7881 | (last_line_num != file->line_num || last_ind != ind)) { |
||
7882 | put_stabn(N_SLINE, 0, file->line_num, ind - func_ind); |
||
7883 | last_ind = ind; |
||
7884 | last_line_num = file->line_num; |
||
7885 | } |
||
7886 | |||
7887 | if (is_expr) { |
||
7888 | /* default return value is (void) */ |
||
7889 | vpushi(0); |
||
7890 | vtop->type.t = VT_VOID; |
||
7891 | } |
||
7892 | |||
7893 | if (tok == TOK_IF) { |
||
7894 | /* if test */ |
||
7895 | next(); |
||
7896 | skip('('); |
||
7897 | gexpr(); |
||
7898 | skip(')'); |
||
7899 | a = gtst(1, 0); |
||
7900 | block(bsym, csym, case_sym, def_sym, case_reg, 0); |
||
7901 | c = tok; |
||
7902 | if (c == TOK_ELSE) { |
||
7903 | next(); |
||
7904 | d = gjmp(0); |
||
7905 | gsym(a); |
||
7906 | block(bsym, csym, case_sym, def_sym, case_reg, 0); |
||
7907 | gsym(d); /* patch else jmp */ |
||
7908 | } else |
||
7909 | gsym(a); |
||
7910 | } else if (tok == TOK_WHILE) { |
||
7911 | next(); |
||
7912 | d = ind; |
||
7913 | skip('('); |
||
7914 | gexpr(); |
||
7915 | skip(')'); |
||
7916 | a = gtst(1, 0); |
||
7917 | b = 0; |
||
7918 | block(&a, &b, case_sym, def_sym, case_reg, 0); |
||
7919 | gjmp_addr(d); |
||
7920 | gsym(a); |
||
7921 | gsym_addr(b, d); |
||
7922 | } else if (tok == '{') { |
||
7923 | Sym *llabel; |
||
7924 | |||
7925 | next(); |
||
7926 | /* record local declaration stack position */ |
||
7927 | s = local_stack; |
||
7928 | llabel = local_label_stack; |
||
7929 | /* handle local labels declarations */ |
||
7930 | if (tok == TOK_LABEL) { |
||
7931 | next(); |
||
7932 | for(;;) { |
||
7933 | if (tok < TOK_UIDENT) |
||
7934 | expect("label identifier"); |
||
7935 | label_push(&local_label_stack, tok, LABEL_DECLARED); |
||
7936 | next(); |
||
7937 | if (tok == ',') { |
||
7938 | next(); |
||
7939 | } else { |
||
7940 | skip(';'); |
||
7941 | break; |
||
7942 | } |
||
7943 | } |
||
7944 | } |
||
7945 | while (tok != '}') { |
||
7946 | decl(VT_LOCAL); |
||
7947 | if (tok != '}') { |
||
7948 | if (is_expr) |
||
7949 | vpop(); |
||
7950 | block(bsym, csym, case_sym, def_sym, case_reg, is_expr); |
||
7951 | } |
||
7952 | } |
||
7953 | /* pop locally defined labels */ |
||
7954 | label_pop(&local_label_stack, llabel); |
||
7955 | /* pop locally defined symbols */ |
||
7956 | sym_pop(&local_stack, s); |
||
7957 | next(); |
||
7958 | } else if (tok == TOK_RETURN) { |
||
7959 | next(); |
||
7960 | if (tok != ';') { |
||
7961 | gexpr(); |
||
7962 | gen_assign_cast(&func_vt); |
||
7963 | if ((func_vt.t & VT_BTYPE) == VT_STRUCT) { |
||
7964 | CType type; |
||
7965 | /* if returning structure, must copy it to implicit |
||
7966 | first pointer arg location */ |
||
7967 | type = func_vt; |
||
7968 | mk_pointer(&type); |
||
7969 | vset(&type, VT_LOCAL | VT_LVAL, func_vc); |
||
7970 | indir(); |
||
7971 | vswap(); |
||
7972 | /* copy structure value to pointer */ |
||
7973 | vstore(); |
||
7974 | } else if (is_float(func_vt.t)) { |
||
7975 | gv(RC_FRET); |
||
7976 | } else { |
||
7977 | gv(RC_IRET); |
||
7978 | } |
||
7979 | vtop--; /* NOT vpop() because on x86 it would flush the fp stack */ |
||
7980 | } |
||
7981 | skip(';'); |
||
7982 | rsym = gjmp(rsym); /* jmp */ |
||
7983 | } else if (tok == TOK_BREAK) { |
||
7984 | /* compute jump */ |
||
7985 | if (!bsym) |
||
7986 | error("cannot break"); |
||
7987 | *bsym = gjmp(*bsym); |
||
7988 | next(); |
||
7989 | skip(';'); |
||
7990 | } else if (tok == TOK_CONTINUE) { |
||
7991 | /* compute jump */ |
||
7992 | if (!csym) |
||
7993 | error("cannot continue"); |
||
7994 | *csym = gjmp(*csym); |
||
7995 | next(); |
||
7996 | skip(';'); |
||
7997 | } else if (tok == TOK_FOR) { |
||
7998 | int e; |
||
7999 | next(); |
||
8000 | skip('('); |
||
8001 | if (tok != ';') { |
||
8002 | gexpr(); |
||
8003 | vpop(); |
||
8004 | } |
||
8005 | skip(';'); |
||
8006 | d = ind; |
||
8007 | c = ind; |
||
8008 | a = 0; |
||
8009 | b = 0; |
||
8010 | if (tok != ';') { |
||
8011 | gexpr(); |
||
8012 | a = gtst(1, 0); |
||
8013 | } |
||
8014 | skip(';'); |
||
8015 | if (tok != ')') { |
||
8016 | e = gjmp(0); |
||
8017 | c = ind; |
||
8018 | gexpr(); |
||
8019 | vpop(); |
||
8020 | gjmp_addr(d); |
||
8021 | gsym(e); |
||
8022 | } |
||
8023 | skip(')'); |
||
8024 | block(&a, &b, case_sym, def_sym, case_reg, 0); |
||
8025 | gjmp_addr(c); |
||
8026 | gsym(a); |
||
8027 | gsym_addr(b, c); |
||
8028 | } else |
||
8029 | if (tok == TOK_DO) { |
||
8030 | next(); |
||
8031 | a = 0; |
||
8032 | b = 0; |
||
8033 | d = ind; |
||
8034 | block(&a, &b, case_sym, def_sym, case_reg, 0); |
||
8035 | skip(TOK_WHILE); |
||
8036 | skip('('); |
||
8037 | gsym(b); |
||
8038 | gexpr(); |
||
8039 | c = gtst(0, 0); |
||
8040 | gsym_addr(c, d); |
||
8041 | skip(')'); |
||
8042 | gsym(a); |
||
8043 | skip(';'); |
||
8044 | } else |
||
8045 | if (tok == TOK_SWITCH) { |
||
8046 | next(); |
||
8047 | skip('('); |
||
8048 | gexpr(); |
||
8049 | /* XXX: other types than integer */ |
||
8050 | case_reg = gv(RC_INT); |
||
8051 | vpop(); |
||
8052 | skip(')'); |
||
8053 | a = 0; |
||
8054 | b = gjmp(0); /* jump to first case */ |
||
8055 | c = 0; |
||
8056 | block(&a, csym, &b, &c, case_reg, 0); |
||
8057 | /* if no default, jmp after switch */ |
||
8058 | if (c == 0) |
||
8059 | c = ind; |
||
8060 | /* default label */ |
||
8061 | gsym_addr(b, c); |
||
8062 | /* break label */ |
||
8063 | gsym(a); |
||
8064 | } else |
||
8065 | if (tok == TOK_CASE) { |
||
8066 | int v1, v2; |
||
8067 | if (!case_sym) |
||
8068 | expect("switch"); |
||
8069 | next(); |
||
8070 | v1 = expr_const(); |
||
8071 | v2 = v1; |
||
8072 | if (gnu_ext && tok == TOK_DOTS) { |
||
8073 | next(); |
||
8074 | v2 = expr_const(); |
||
8075 | if (v2 < v1) |
||
8076 | warning("empty case range"); |
||
8077 | } |
||
8078 | /* since a case is like a label, we must skip it with a jmp */ |
||
8079 | b = gjmp(0); |
||
8080 | gsym(*case_sym); |
||
8081 | vseti(case_reg, 0); |
||
8082 | vpushi(v1); |
||
8083 | if (v1 == v2) { |
||
8084 | gen_op(TOK_EQ); |
||
8085 | *case_sym = gtst(1, 0); |
||
8086 | } else { |
||
8087 | gen_op(TOK_GE); |
||
8088 | *case_sym = gtst(1, 0); |
||
8089 | vseti(case_reg, 0); |
||
8090 | vpushi(v2); |
||
8091 | gen_op(TOK_LE); |
||
8092 | *case_sym = gtst(1, *case_sym); |
||
8093 | } |
||
8094 | gsym(b); |
||
8095 | skip(':'); |
||
8096 | is_expr = 0; |
||
8097 | goto block_after_label; |
||
8098 | } else |
||
8099 | if (tok == TOK_DEFAULT) { |
||
8100 | next(); |
||
8101 | skip(':'); |
||
8102 | if (!def_sym) |
||
8103 | expect("switch"); |
||
8104 | if (*def_sym) |
||
8105 | error("too many 'default'"); |
||
8106 | *def_sym = ind; |
||
8107 | is_expr = 0; |
||
8108 | goto block_after_label; |
||
8109 | } else |
||
8110 | if (tok == TOK_GOTO) { |
||
8111 | next(); |
||
8112 | if (tok == '*' && gnu_ext) { |
||
8113 | /* computed goto */ |
||
8114 | next(); |
||
8115 | gexpr(); |
||
8116 | if ((vtop->type.t & VT_BTYPE) != VT_PTR) |
||
8117 | expect("pointer"); |
||
8118 | ggoto(); |
||
8119 | } else if (tok >= TOK_UIDENT) { |
||
8120 | s = label_find(tok); |
||
8121 | /* put forward definition if needed */ |
||
8122 | if (!s) { |
||
8123 | s = label_push(&global_label_stack, tok, LABEL_FORWARD); |
||
8124 | } else { |
||
8125 | if (s->r == LABEL_DECLARED) |
||
8126 | s->r = LABEL_FORWARD; |
||
8127 | } |
||
8128 | /* label already defined */ |
||
8129 | if (s->r & LABEL_FORWARD) |
||
8130 | s->next = (void *)gjmp((long)s->next); |
||
8131 | else |
||
8132 | gjmp_addr((long)s->next); |
||
8133 | next(); |
||
8134 | } else { |
||
8135 | expect("label identifier"); |
||
8136 | } |
||
8137 | skip(';'); |
||
8138 | } else if (tok == TOK_ASM1 || tok == TOK_ASM2 || tok == TOK_ASM3) { |
||
8139 | asm_instr(); |
||
8140 | } else { |
||
8141 | b = is_label(); |
||
8142 | if (b) { |
||
8143 | /* label case */ |
||
8144 | s = label_find(b); |
||
8145 | if (s) { |
||
8146 | if (s->r == LABEL_DEFINED) |
||
8147 | error("duplicate label '%s'", get_tok_str(s->v, NULL)); |
||
8148 | gsym((long)s->next); |
||
8149 | s->r = LABEL_DEFINED; |
||
8150 | } else { |
||
8151 | s = label_push(&global_label_stack, b, LABEL_DEFINED); |
||
8152 | } |
||
8153 | s->next = (void *)ind; |
||
8154 | /* we accept this, but it is a mistake */ |
||
8155 | block_after_label: |
||
8156 | if (tok == '}') { |
||
8157 | warning("deprecated use of label at end of compound statement"); |
||
8158 | } else { |
||
8159 | if (is_expr) |
||
8160 | vpop(); |
||
8161 | block(bsym, csym, case_sym, def_sym, case_reg, is_expr); |
||
8162 | } |
||
8163 | } else { |
||
8164 | /* expression case */ |
||
8165 | if (tok != ';') { |
||
8166 | if (is_expr) { |
||
8167 | vpop(); |
||
8168 | gexpr(); |
||
8169 | } else { |
||
8170 | gexpr(); |
||
8171 | vpop(); |
||
8172 | } |
||
8173 | } |
||
8174 | skip(';'); |
||
8175 | } |
||
8176 | } |
||
8177 | } |
||
8178 | |||
8179 | /* t is the array or struct type. c is the array or struct |
||
8180 | address. cur_index/cur_field is the pointer to the current |
||
8181 | value. 'size_only' is true if only size info is needed (only used |
||
8182 | in arrays) */ |
||
8183 | static void decl_designator(CType *type, Section *sec, unsigned long c, |
||
8184 | int *cur_index, Sym **cur_field, |
||
8185 | int size_only) |
||
8186 | { |
||
8187 | Sym *s, *f; |
||
8188 | int notfirst, index, index_last, align, l, nb_elems, elem_size; |
||
8189 | CType type1; |
||
8190 | |||
8191 | notfirst = 0; |
||
8192 | elem_size = 0; |
||
8193 | nb_elems = 1; |
||
8194 | if (gnu_ext && (l = is_label()) != 0) |
||
8195 | goto struct_field; |
||
8196 | while (tok == '[' || tok == '.') { |
||
8197 | if (tok == '[') { |
||
8198 | if (!(type->t & VT_ARRAY)) |
||
8199 | expect("array type"); |
||
8200 | s = type->ref; |
||
8201 | next(); |
||
8202 | index = expr_const(); |
||
8203 | if (index < 0 || (s->c >= 0 && index >= s->c)) |
||
8204 | expect("invalid index"); |
||
8205 | if (tok == TOK_DOTS && gnu_ext) { |
||
8206 | next(); |
||
8207 | index_last = expr_const(); |
||
8208 | if (index_last < 0 || |
||
8209 | (s->c >= 0 && index_last >= s->c) || |
||
8210 | index_last < index) |
||
8211 | expect("invalid index"); |
||
8212 | } else { |
||
8213 | index_last = index; |
||
8214 | } |
||
8215 | skip(']'); |
||
8216 | if (!notfirst) |
||
8217 | *cur_index = index_last; |
||
8218 | type = pointed_type(type); |
||
8219 | elem_size = type_size(type, &align); |
||
8220 | c += index * elem_size; |
||
8221 | /* NOTE: we only support ranges for last designator */ |
||
8222 | nb_elems = index_last - index + 1; |
||
8223 | if (nb_elems != 1) { |
||
8224 | notfirst = 1; |
||
8225 | break; |
||
8226 | } |
||
8227 | } else { |
||
8228 | next(); |
||
8229 | l = tok; |
||
8230 | next(); |
||
8231 | struct_field: |
||
8232 | if ((type->t & VT_BTYPE) != VT_STRUCT) |
||
8233 | expect("struct/union type"); |
||
8234 | s = type->ref; |
||
8235 | l |= SYM_FIELD; |
||
8236 | f = s->next; |
||
8237 | while (f) { |
||
8238 | if (f->v == l) |
||
8239 | break; |
||
8240 | f = f->next; |
||
8241 | } |
||
8242 | if (!f) |
||
8243 | expect("field"); |
||
8244 | if (!notfirst) |
||
8245 | *cur_field = f; |
||
8246 | /* XXX: fix this mess by using explicit storage field */ |
||
8247 | type1 = f->type; |
||
8248 | type1.t |= (type->t & ~VT_TYPE); |
||
8249 | type = &type1; |
||
8250 | c += f->c; |
||
8251 | } |
||
8252 | notfirst = 1; |
||
8253 | } |
||
8254 | if (notfirst) { |
||
8255 | if (tok == '=') { |
||
8256 | next(); |
||
8257 | } else { |
||
8258 | if (!gnu_ext) |
||
8259 | expect("="); |
||
8260 | } |
||
8261 | } else { |
||
8262 | if (type->t & VT_ARRAY) { |
||
8263 | index = *cur_index; |
||
8264 | type = pointed_type(type); |
||
8265 | c += index * type_size(type, &align); |
||
8266 | } else { |
||
8267 | f = *cur_field; |
||
8268 | if (!f) |
||
8269 | error("too many field init"); |
||
8270 | /* XXX: fix this mess by using explicit storage field */ |
||
8271 | type1 = f->type; |
||
8272 | type1.t |= (type->t & ~VT_TYPE); |
||
8273 | type = &type1; |
||
8274 | c += f->c; |
||
8275 | } |
||
8276 | } |
||
8277 | decl_initializer(type, sec, c, 0, size_only); |
||
8278 | |||
8279 | /* XXX: make it more general */ |
||
8280 | if (!size_only && nb_elems > 1) { |
||
8281 | unsigned long c_end; |
||
8282 | uint8_t *src, *dst; |
||
8283 | int i; |
||
8284 | |||
8285 | if (!sec) |
||
8286 | error("range init not supported yet for dynamic storage"); |
||
8287 | c_end = c + nb_elems * elem_size; |
||
8288 | if (c_end > sec->data_allocated) |
||
8289 | section_realloc(sec, c_end); |
||
8290 | src = sec->data + c; |
||
8291 | dst = src; |
||
8292 | for(i = 1; i < nb_elems; i++) { |
||
8293 | dst += elem_size; |
||
8294 | memcpy(dst, src, elem_size); |
||
8295 | } |
||
8296 | } |
||
8297 | } |
||
8298 | |||
8299 | #define EXPR_VAL 0 |
||
8300 | #define EXPR_CONST 1 |
||
8301 | #define EXPR_ANY 2 |
||
8302 | |||
8303 | /* store a value or an expression directly in global data or in local array */ |
||
8304 | static void init_putv(CType *type, Section *sec, unsigned long c, |
||
8305 | int v, int expr_type) |
||
8306 | { |
||
8307 | int saved_global_expr, bt, bit_pos, bit_size; |
||
8308 | void *ptr; |
||
8309 | unsigned long long bit_mask; |
||
8310 | CType dtype; |
||
8311 | |||
8312 | switch(expr_type) { |
||
8313 | case EXPR_VAL: |
||
8314 | vpushi(v); |
||
8315 | break; |
||
8316 | case EXPR_CONST: |
||
8317 | /* compound literals must be allocated globally in this case */ |
||
8318 | saved_global_expr = global_expr; |
||
8319 | global_expr = 1; |
||
8320 | expr_const1(); |
||
8321 | global_expr = saved_global_expr; |
||
8322 | /* NOTE: symbols are accepted */ |
||
8323 | if ((vtop->r & (VT_VALMASK | VT_LVAL)) != VT_CONST) |
||
8324 | error("initializer element is not constant"); |
||
8325 | break; |
||
8326 | case EXPR_ANY: |
||
8327 | expr_eq(); |
||
8328 | break; |
||
8329 | } |
||
8330 | |||
8331 | dtype = *type; |
||
8332 | dtype.t &= ~VT_CONSTANT; /* need to do that to avoid false warning */ |
||
8333 | |||
8334 | if (sec) { |
||
8335 | /* XXX: not portable */ |
||
8336 | /* XXX: generate error if incorrect relocation */ |
||
8337 | gen_assign_cast(&dtype); |
||
8338 | bt = type->t & VT_BTYPE; |
||
8339 | ptr = sec->data + c; |
||
8340 | /* XXX: make code faster ? */ |
||
8341 | if (!(type->t & VT_BITFIELD)) { |
||
8342 | bit_pos = 0; |
||
8343 | bit_size = 32; |
||
8344 | bit_mask = -1LL; |
||
8345 | } else { |
||
8346 | bit_pos = (vtop->type.t >> VT_STRUCT_SHIFT) & 0x3f; |
||
8347 | bit_size = (vtop->type.t >> (VT_STRUCT_SHIFT + 6)) & 0x3f; |
||
8348 | bit_mask = (1LL << bit_size) - 1; |
||
8349 | } |
||
8350 | if ((vtop->r & VT_SYM) && |
||
8351 | (bt == VT_BYTE || |
||
8352 | bt == VT_SHORT || |
||
8353 | bt == VT_DOUBLE || |
||
8354 | bt == VT_LDOUBLE || |
||
8355 | bt == VT_LLONG || |
||
8356 | (bt == VT_INT && bit_size != 32))) |
||
8357 | error("initializer element is not computable at load time"); |
||
8358 | switch(bt) { |
||
8359 | case VT_BYTE: |
||
8360 | *(char *)ptr |= (vtop->c.i & bit_mask) << bit_pos; |
||
8361 | break; |
||
8362 | case VT_SHORT: |
||
8363 | *(short *)ptr |= (vtop->c.i & bit_mask) << bit_pos; |
||
8364 | break; |
||
8365 | case VT_DOUBLE: |
||
8366 | *(double *)ptr = vtop->c.d; |
||
8367 | break; |
||
8368 | case VT_LDOUBLE: |
||
8369 | *(long double *)ptr = vtop->c.ld; |
||
8370 | break; |
||
8371 | case VT_LLONG: |
||
8372 | *(long long *)ptr |= (vtop->c.ll & bit_mask) << bit_pos; |
||
8373 | break; |
||
8374 | default: |
||
8375 | if (vtop->r & VT_SYM) { |
||
8376 | greloc(sec, vtop->sym, c, R_DATA_32); |
||
8377 | } |
||
8378 | *(int *)ptr |= (vtop->c.i & bit_mask) << bit_pos; |
||
8379 | break; |
||
8380 | } |
||
8381 | vtop--; |
||
8382 | } else { |
||
8383 | vset(&dtype, VT_LOCAL, c); |
||
8384 | vswap(); |
||
8385 | vstore(); |
||
8386 | vpop(); |
||
8387 | } |
||
8388 | } |
||
8389 | |||
8390 | /* put zeros for variable based init */ |
||
8391 | static void init_putz(CType *t, Section *sec, unsigned long c, int size) |
||
8392 | { |
||
8393 | if (sec) { |
||
8394 | /* nothing to do because globals are already set to zero */ |
||
8395 | } else { |
||
8396 | vpush_global_sym(&func_old_type, TOK_memset); |
||
8397 | vseti(VT_LOCAL, c); |
||
8398 | vpushi(0); |
||
8399 | vpushi(size); |
||
8400 | gfunc_call(3); |
||
8401 | } |
||
8402 | } |
||
8403 | |||
8404 | /* 't' contains the type and storage info. 'c' is the offset of the |
||
8405 | object in section 'sec'. If 'sec' is NULL, it means stack based |
||
8406 | allocation. 'first' is true if array '{' must be read (multi |
||
8407 | dimension implicit array init handling). 'size_only' is true if |
||
8408 | size only evaluation is wanted (only for arrays). */ |
||
8409 | static void decl_initializer(CType *type, Section *sec, unsigned long c, |
||
8410 | int first, int size_only) |
||
8411 | { |
||
8412 | int index, array_length, n, no_oblock, nb, parlevel, i; |
||
8413 | int size1, align1, expr_type; |
||
8414 | Sym *s, *f; |
||
8415 | CType *t1; |
||
8416 | |||
8417 | if (type->t & VT_ARRAY) { |
||
8418 | s = type->ref; |
||
8419 | n = s->c; |
||
8420 | array_length = 0; |
||
8421 | t1 = pointed_type(type); |
||
8422 | size1 = type_size(t1, &align1); |
||
8423 | |||
8424 | no_oblock = 1; |
||
8425 | if ((first && tok != TOK_LSTR && tok != TOK_STR) || |
||
8426 | tok == '{') { |
||
8427 | skip('{'); |
||
8428 | no_oblock = 0; |
||
8429 | } |
||
8430 | |||
8431 | /* only parse strings here if correct type (otherwise: handle |
||
8432 | them as ((w)char *) expressions */ |
||
8433 | if ((tok == TOK_LSTR && |
||
8434 | (t1->t & VT_BTYPE) == VT_INT) || |
||
8435 | (tok == TOK_STR && |
||
8436 | (t1->t & VT_BTYPE) == VT_BYTE)) { |
||
8437 | while (tok == TOK_STR || tok == TOK_LSTR) { |
||
8438 | int cstr_len, ch; |
||
8439 | CString *cstr; |
||
8440 | |||
8441 | cstr = tokc.cstr; |
||
8442 | /* compute maximum number of chars wanted */ |
||
8443 | if (tok == TOK_STR) |
||
8444 | cstr_len = cstr->size; |
||
8445 | else |
||
8446 | cstr_len = cstr->size / sizeof(int); |
||
8447 | cstr_len--; |
||
8448 | nb = cstr_len; |
||
8449 | if (n >= 0 && nb > (n - array_length)) |
||
8450 | nb = n - array_length; |
||
8451 | if (!size_only) { |
||
8452 | if (cstr_len > nb) |
||
8453 | warning("initializer-string for array is too long"); |
||
8454 | /* in order to go faster for common case (char |
||
8455 | string in global variable, we handle it |
||
8456 | specifically */ |
||
8457 | if (sec && tok == TOK_STR && size1 == 1) { |
||
8458 | memcpy(sec->data + c + array_length, cstr->data, nb); |
||
8459 | } else { |
||
8460 | for(i=0;i |
||
8461 | if (tok == TOK_STR) |
||
8462 | ch = ((unsigned char *)cstr->data)[i]; |
||
8463 | else |
||
8464 | ch = ((int *)cstr->data)[i]; |
||
8465 | init_putv(t1, sec, c + (array_length + i) * size1, |
||
8466 | ch, EXPR_VAL); |
||
8467 | } |
||
8468 | } |
||
8469 | } |
||
8470 | array_length += nb; |
||
8471 | next(); |
||
8472 | } |
||
8473 | /* only add trailing zero if enough storage (no |
||
8474 | warning in this case since it is standard) */ |
||
8475 | if (n < 0 || array_length < n) { |
||
8476 | if (!size_only) { |
||
8477 | init_putv(t1, sec, c + (array_length * size1), 0, EXPR_VAL); |
||
8478 | } |
||
8479 | array_length++; |
||
8480 | } |
||
8481 | } else { |
||
8482 | index = 0; |
||
8483 | while (tok != '}') { |
||
8484 | decl_designator(type, sec, c, &index, NULL, size_only); |
||
8485 | if (n >= 0 && index >= n) |
||
8486 | error("index too large"); |
||
8487 | /* must put zero in holes (note that doing it that way |
||
8488 | ensures that it even works with designators) */ |
||
8489 | if (!size_only && array_length < index) { |
||
8490 | init_putz(t1, sec, c + array_length * size1, |
||
8491 | (index - array_length) * size1); |
||
8492 | } |
||
8493 | index++; |
||
8494 | if (index > array_length) |
||
8495 | array_length = index; |
||
8496 | /* special test for multi dimensional arrays (may not |
||
8497 | be strictly correct if designators are used at the |
||
8498 | same time) */ |
||
8499 | if (index >= n && no_oblock) |
||
8500 | break; |
||
8501 | if (tok == '}') |
||
8502 | break; |
||
8503 | skip(','); |
||
8504 | } |
||
8505 | } |
||
8506 | if (!no_oblock) |
||
8507 | skip('}'); |
||
8508 | /* put zeros at the end */ |
||
8509 | if (!size_only && n >= 0 && array_length < n) { |
||
8510 | init_putz(t1, sec, c + array_length * size1, |
||
8511 | (n - array_length) * size1); |
||
8512 | } |
||
8513 | /* patch type size if needed */ |
||
8514 | if (n < 0) |
||
8515 | s->c = array_length; |
||
8516 | } else if ((type->t & VT_BTYPE) == VT_STRUCT && |
||
8517 | (sec || !first || tok == '{')) { |
||
8518 | int par_count; |
||
8519 | |||
8520 | /* NOTE: the previous test is a specific case for automatic |
||
8521 | struct/union init */ |
||
8522 | /* XXX: union needs only one init */ |
||
8523 | |||
8524 | /* XXX: this test is incorrect for local initializers |
||
8525 | beginning with ( without {. It would be much more difficult |
||
8526 | to do it correctly (ideally, the expression parser should |
||
8527 | be used in all cases) */ |
||
8528 | par_count = 0; |
||
8529 | if (tok == '(') { |
||
8530 | AttributeDef ad1; |
||
8531 | CType type1; |
||
8532 | next(); |
||
8533 | while (tok == '(') { |
||
8534 | par_count++; |
||
8535 | next(); |
||
8536 | } |
||
8537 | if (!parse_btype(&type1, &ad1)) |
||
8538 | expect("cast"); |
||
8539 | type_decl(&type1, &ad1, &n, TYPE_ABSTRACT); |
||
8540 | #if 0 |
||
8541 | if (!is_assignable_types(type, &type1)) |
||
8542 | error("invalid type for cast"); |
||
8543 | #endif |
||
8544 | skip(')'); |
||
8545 | } |
||
8546 | no_oblock = 1; |
||
8547 | if (first || tok == '{') { |
||
8548 | skip('{'); |
||
8549 | no_oblock = 0; |
||
8550 | } |
||
8551 | s = type->ref; |
||
8552 | f = s->next; |
||
8553 | array_length = 0; |
||
8554 | index = 0; |
||
8555 | n = s->c; |
||
8556 | while (tok != '}') { |
||
8557 | decl_designator(type, sec, c, NULL, &f, size_only); |
||
8558 | index = f->c; |
||
8559 | if (!size_only && array_length < index) { |
||
8560 | init_putz(type, sec, c + array_length, |
||
8561 | index - array_length); |
||
8562 | } |
||
8563 | index = index + type_size(&f->type, &align1); |
||
8564 | if (index > array_length) |
||
8565 | array_length = index; |
||
8566 | f = f->next; |
||
8567 | if (no_oblock && f == NULL) |
||
8568 | break; |
||
8569 | if (tok == '}') |
||
8570 | break; |
||
8571 | skip(','); |
||
8572 | } |
||
8573 | /* put zeros at the end */ |
||
8574 | if (!size_only && array_length < n) { |
||
8575 | init_putz(type, sec, c + array_length, |
||
8576 | n - array_length); |
||
8577 | } |
||
8578 | if (!no_oblock) |
||
8579 | skip('}'); |
||
8580 | while (par_count) { |
||
8581 | skip(')'); |
||
8582 | par_count--; |
||
8583 | } |
||
8584 | } else if (tok == '{') { |
||
8585 | next(); |
||
8586 | decl_initializer(type, sec, c, first, size_only); |
||
8587 | skip('}'); |
||
8588 | } else if (size_only) { |
||
8589 | /* just skip expression */ |
||
8590 | parlevel = 0; |
||
8591 | while ((parlevel > 0 || (tok != '}' && tok != ',')) && |
||
8592 | tok != -1) { |
||
8593 | if (tok == '(') |
||
8594 | parlevel++; |
||
8595 | else if (tok == ')') |
||
8596 | parlevel--; |
||
8597 | next(); |
||
8598 | } |
||
8599 | } else { |
||
8600 | /* currently, we always use constant expression for globals |
||
8601 | (may change for scripting case) */ |
||
8602 | expr_type = EXPR_CONST; |
||
8603 | if (!sec) |
||
8604 | expr_type = EXPR_ANY; |
||
8605 | init_putv(type, sec, c, 0, expr_type); |
||
8606 | } |
||
8607 | } |
||
8608 | |||
8609 | /* parse an initializer for type 't' if 'has_init' is non zero, and |
||
8610 | allocate space in local or global data space ('r' is either |
||
8611 | VT_LOCAL or VT_CONST). If 'v' is non zero, then an associated |
||
8612 | variable 'v' of scope 'scope' is declared before initializers are |
||
8613 | parsed. If 'v' is zero, then a reference to the new object is put |
||
8614 | in the value stack. If 'has_init' is 2, a special parsing is done |
||
8615 | to handle string constants. */ |
||
8616 | static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, |
||
8617 | int has_init, int v, int scope) |
||
8618 | { |
||
8619 | int size, align, addr, data_offset; |
||
8620 | int level; |
||
8621 | ParseState saved_parse_state; |
||
8622 | TokenString init_str; |
||
8623 | Section *sec; |
||
8624 | |||
8625 | size = type_size(type, &align); |
||
8626 | /* If unknown size, we must evaluate it before |
||
8627 | evaluating initializers because |
||
8628 | initializers can generate global data too |
||
8629 | (e.g. string pointers or ISOC99 compound |
||
8630 | literals). It also simplifies local |
||
8631 | initializers handling */ |
||
8632 | tok_str_new(&init_str); |
||
8633 | if (size < 0) { |
||
8634 | if (!has_init) |
||
8635 | error("unknown type size"); |
||
8636 | /* get all init string */ |
||
8637 | if (has_init == 2) { |
||
8638 | /* only get strings */ |
||
8639 | while (tok == TOK_STR || tok == TOK_LSTR) { |
||
8640 | tok_str_add_tok(&init_str); |
||
8641 | next(); |
||
8642 | } |
||
8643 | } else { |
||
8644 | level = 0; |
||
8645 | while (level > 0 || (tok != ',' && tok != ';')) { |
||
8646 | if (tok < 0) |
||
8647 | error("unexpected end of file in initializer"); |
||
8648 | tok_str_add_tok(&init_str); |
||
8649 | if (tok == '{') |
||
8650 | level++; |
||
8651 | else if (tok == '}') { |
||
8652 | if (level == 0) |
||
8653 | break; |
||
8654 | level--; |
||
8655 | } |
||
8656 | next(); |
||
8657 | } |
||
8658 | } |
||
8659 | tok_str_add(&init_str, -1); |
||
8660 | tok_str_add(&init_str, 0); |
||
8661 | |||
8662 | /* compute size */ |
||
8663 | save_parse_state(&saved_parse_state); |
||
8664 | |||
8665 | macro_ptr = init_str.str; |
||
8666 | next(); |
||
8667 | decl_initializer(type, NULL, 0, 1, 1); |
||
8668 | /* prepare second initializer parsing */ |
||
8669 | macro_ptr = init_str.str; |
||
8670 | next(); |
||
8671 | |||
8672 | /* if still unknown size, error */ |
||
8673 | size = type_size(type, &align); |
||
8674 | if (size < 0) |
||
8675 | error("unknown type size"); |
||
8676 | } |
||
8677 | /* take into account specified alignment if bigger */ |
||
8678 | if (ad->aligned) { |
||
8679 | if (ad->aligned > align) |
||
8680 | align = ad->aligned; |
||
8681 | } else if (ad->packed) { |
||
8682 | align = 1; |
||
8683 | } |
||
8684 | if ((r & VT_VALMASK) == VT_LOCAL) { |
||
8685 | sec = NULL; |
||
8686 | if (do_bounds_check && (type->t & VT_ARRAY)) |
||
8687 | loc--; |
||
8688 | loc = (loc - size) & -align; |
||
8689 | addr = loc; |
||
8690 | /* handles bounds */ |
||
8691 | /* XXX: currently, since we do only one pass, we cannot track |
||
8692 | '&' operators, so we add only arrays */ |
||
8693 | if (do_bounds_check && (type->t & VT_ARRAY)) { |
||
8694 | unsigned long *bounds_ptr; |
||
8695 | /* add padding between regions */ |
||
8696 | loc--; |
||
8697 | /* then add local bound info */ |
||
8698 | bounds_ptr = section_ptr_add(lbounds_section, 2 * sizeof(unsigned long)); |
||
8699 | bounds_ptr[0] = addr; |
||
8700 | bounds_ptr[1] = size; |
||
8701 | } |
||
8702 | if (v) { |
||
8703 | /* local variable */ |
||
8704 | sym_push(v, type, r, addr); |
||
8705 | } else { |
||
8706 | /* push local reference */ |
||
8707 | vset(type, r, addr); |
||
8708 | } |
||
8709 | } else { |
||
8710 | Sym *sym; |
||
8711 | |||
8712 | sym = NULL; |
||
8713 | if (v && scope == VT_CONST) { |
||
8714 | /* see if the symbol was already defined */ |
||
8715 | sym = sym_find(v); |
||
8716 | if (sym) { |
||
8717 | if (!is_compatible_types(&sym->type, type)) |
||
8718 | error("incompatible types for redefinition of '%s'", |
||
8719 | get_tok_str(v, NULL)); |
||
8720 | if (sym->type.t & VT_EXTERN) { |
||
8721 | /* if the variable is extern, it was not allocated */ |
||
8722 | sym->type.t &= ~VT_EXTERN; |
||
8723 | /* set array size if it was ommited in extern |
||
8724 | declaration */ |
||
8725 | if ((sym->type.t & VT_ARRAY) && |
||
8726 | sym->type.ref->c < 0 && |
||
8727 | type->ref->c >= 0) |
||
8728 | sym->type.ref->c = type->ref->c; |
||
8729 | } else { |
||
8730 | /* we accept several definitions of the same |
||
8731 | global variable. this is tricky, because we |
||
8732 | must play with the SHN_COMMON type of the symbol */ |
||
8733 | /* XXX: should check if the variable was already |
||
8734 | initialized. It is incorrect to initialized it |
||
8735 | twice */ |
||
8736 | /* no init data, we won't add more to the symbol */ |
||
8737 | if (!has_init) |
||
8738 | goto no_alloc; |
||
8739 | } |
||
8740 | } |
||
8741 | } |
||
8742 | |||
8743 | /* allocate symbol in corresponding section */ |
||
8744 | sec = ad->section; |
||
8745 | if (!sec) { |
||
8746 | if (has_init) |
||
8747 | sec = data_section; |
||
8748 | else if (tcc_state->nocommon) |
||
8749 | sec = bss_section; |
||
8750 | } |
||
8751 | if (sec) { |
||
8752 | data_offset = sec->data_offset; |
||
8753 | data_offset = (data_offset + align - 1) & -align; |
||
8754 | addr = data_offset; |
||
8755 | /* very important to increment global pointer at this time |
||
8756 | because initializers themselves can create new initializers */ |
||
8757 | data_offset += size; |
||
8758 | /* add padding if bound check */ |
||
8759 | if (do_bounds_check) |
||
8760 | data_offset++; |
||
8761 | sec->data_offset = data_offset; |
||
8762 | /* allocate section space to put the data */ |
||
8763 | if (sec->sh_type != SHT_NOBITS && |
||
8764 | data_offset > sec->data_allocated) |
||
8765 | section_realloc(sec, data_offset); |
||
8766 | /* align section if needed */ |
||
8767 | if (align > sec->sh_addralign) |
||
8768 | sec->sh_addralign = align; |
||
8769 | } else { |
||
8770 | addr = 0; /* avoid warning */ |
||
8771 | } |
||
8772 | |||
8773 | if (v) { |
||
8774 | if (scope == VT_CONST) { |
||
8775 | if (!sym) |
||
8776 | goto do_def; |
||
8777 | } else { |
||
8778 | do_def: |
||
8779 | sym = sym_push(v, type, r | VT_SYM, 0); |
||
8780 | } |
||
8781 | /* update symbol definition */ |
||
8782 | if (sec) { |
||
8783 | put_extern_sym(sym, sec, addr, size); |
||
8784 | } else { |
||
8785 | Elf32_Sym *esym; |
||
8786 | /* put a common area */ |
||
8787 | put_extern_sym(sym, NULL, align, size); |
||
8788 | /* XXX: find a nicer way */ |
||
8789 | esym = &((Elf32_Sym *)symtab_section->data)[sym->c]; |
||
8790 | esym->st_shndx = SHN_COMMON; |
||
8791 | } |
||
8792 | } else { |
||
8793 | CValue cval; |
||
8794 | |||
8795 | /* push global reference */ |
||
8796 | sym = get_sym_ref(type, sec, addr, size); |
||
8797 | cval.ul = 0; |
||
8798 | vsetc(type, VT_CONST | VT_SYM, &cval); |
||
8799 | vtop->sym = sym; |
||
8800 | } |
||
8801 | |||
8802 | /* handles bounds now because the symbol must be defined |
||
8803 | before for the relocation */ |
||
8804 | if (do_bounds_check) { |
||
8805 | unsigned long *bounds_ptr; |
||
8806 | |||
8807 | greloc(bounds_section, sym, bounds_section->data_offset, R_DATA_32); |
||
8808 | /* then add global bound info */ |
||
8809 | bounds_ptr = section_ptr_add(bounds_section, 2 * sizeof(long)); |
||
8810 | bounds_ptr[0] = 0; /* relocated */ |
||
8811 | bounds_ptr[1] = size; |
||
8812 | } |
||
8813 | } |
||
8814 | if (has_init) { |
||
8815 | decl_initializer(type, sec, addr, 1, 0); |
||
8816 | /* restore parse state if needed */ |
||
8817 | if (init_str.str) { |
||
8818 | tok_str_free(init_str.str); |
||
8819 | restore_parse_state(&saved_parse_state); |
||
8820 | } |
||
8821 | } |
||
8822 | no_alloc: ; |
||
8823 | } |
||
8824 | |||
8825 | void put_func_debug(Sym *sym) |
||
8826 | { |
||
8827 | char buf[512]; |
||
8828 | |||
8829 | /* stabs info */ |
||
8830 | /* XXX: we put here a dummy type */ |
||
8831 | snprintf(buf, sizeof(buf), "%s:%c1", |
||
8832 | funcname, sym->type.t & VT_STATIC ? 'f' : 'F'); |
||
8833 | put_stabs_r(buf, N_FUN, 0, file->line_num, 0, |
||
8834 | cur_text_section, sym->c); |
||
8835 | last_ind = 0; |
||
8836 | last_line_num = 0; |
||
8837 | } |
||
8838 | |||
8839 | /* parse an old style function declaration list */ |
||
8840 | /* XXX: check multiple parameter */ |
||
8841 | static void func_decl_list(Sym *func_sym) |
||
8842 | { |
||
8843 | AttributeDef ad; |
||
8844 | int v; |
||
8845 | Sym *s; |
||
8846 | CType btype, type; |
||
8847 | |||
8848 | /* parse each declaration */ |
||
8849 | while (tok != '{' && tok != ';' && tok != ',' && tok != TOK_EOF) { |
||
8850 | if (!parse_btype(&btype, &ad)) |
||
8851 | expect("declaration list"); |
||
8852 | if (((btype.t & VT_BTYPE) == VT_ENUM || |
||
8853 | (btype.t & VT_BTYPE) == VT_STRUCT) && |
||
8854 | tok == ';') { |
||
8855 | /* we accept no variable after */ |
||
8856 | } else { |
||
8857 | for(;;) { |
||
8858 | type = btype; |
||
8859 | type_decl(&type, &ad, &v, TYPE_DIRECT); |
||
8860 | /* find parameter in function parameter list */ |
||
8861 | s = func_sym->next; |
||
8862 | while (s != NULL) { |
||
8863 | if ((s->v & ~SYM_FIELD) == v) |
||
8864 | goto found; |
||
8865 | s = s->next; |
||
8866 | } |
||
8867 | error("declaration for parameter '%s' but no such parameter", |
||
8868 | get_tok_str(v, NULL)); |
||
8869 | found: |
||
8870 | /* check that no storage specifier except 'register' was given */ |
||
8871 | if (type.t & VT_STORAGE) |
||
8872 | error("storage class specified for '%s'", get_tok_str(v, NULL)); |
||
8873 | convert_parameter_type(&type); |
||
8874 | /* we can add the type (NOTE: it could be local to the function) */ |
||
8875 | s->type = type; |
||
8876 | /* accept other parameters */ |
||
8877 | if (tok == ',') |
||
8878 | next(); |
||
8879 | else |
||
8880 | break; |
||
8881 | } |
||
8882 | } |
||
8883 | skip(';'); |
||
8884 | } |
||
8885 | } |
||
8886 | |||
8887 | /* parse a function defined by symbol 'sym' and generate its code in |
||
8888 | 'cur_text_section' */ |
||
8889 | static void gen_function(Sym *sym) |
||
8890 | { |
||
8891 | ind = cur_text_section->data_offset; |
||
8892 | /* NOTE: we patch the symbol size later */ |
||
8893 | put_extern_sym(sym, cur_text_section, ind, 0); |
||
8894 | funcname = get_tok_str(sym->v, NULL); |
||
8895 | func_ind = ind; |
||
8896 | /* put debug symbol */ |
||
8897 | if (do_debug) |
||
8898 | put_func_debug(sym); |
||
8899 | /* push a dummy symbol to enable local sym storage */ |
||
8900 | sym_push2(&local_stack, SYM_FIELD, 0, 0); |
||
8901 | gfunc_prolog(&sym->type); |
||
8902 | rsym = 0; |
||
8903 | block(NULL, NULL, NULL, NULL, 0, 0); |
||
8904 | gsym(rsym); |
||
8905 | gfunc_epilog(); |
||
8906 | cur_text_section->data_offset = ind; |
||
8907 | label_pop(&global_label_stack, NULL); |
||
8908 | sym_pop(&local_stack, NULL); /* reset local stack */ |
||
8909 | /* end of function */ |
||
8910 | /* patch symbol size */ |
||
8911 | ((Elf32_Sym *)symtab_section->data)[sym->c].st_size = |
||
8912 | ind - func_ind; |
||
8913 | if (do_debug) { |
||
8914 | put_stabn(N_FUN, 0, 0, ind - func_ind); |
||
8915 | } |
||
8916 | funcname = ""; /* for safety */ |
||
8917 | func_vt.t = VT_VOID; /* for safety */ |
||
8918 | ind = 0; /* for safety */ |
||
8919 | } |
||
8920 | |||
8921 | static void gen_inline_functions(void) |
||
8922 | { |
||
8923 | Sym *sym; |
||
8924 | CType *type; |
||
8925 | int *str, inline_generated; |
||
8926 | |||
8927 | /* iterate while inline function are referenced */ |
||
8928 | for(;;) { |
||
8929 | inline_generated = 0; |
||
8930 | for(sym = global_stack; sym != NULL; sym = sym->prev) { |
||
8931 | type = &sym->type; |
||
8932 | if (((type->t & VT_BTYPE) == VT_FUNC) && |
||
8933 | (type->t & (VT_STATIC | VT_INLINE)) == |
||
8934 | (VT_STATIC | VT_INLINE) && |
||
8935 | sym->c != 0) { |
||
8936 | /* the function was used: generate its code and |
||
8937 | convert it to a normal function */ |
||
8938 | str = (int *)sym->r; |
||
8939 | sym->r = VT_SYM | VT_CONST; |
||
8940 | type->t &= ~VT_INLINE; |
||
8941 | |||
8942 | macro_ptr = str; |
||
8943 | next(); |
||
8944 | cur_text_section = text_section; |
||
8945 | gen_function(sym); |
||
8946 | macro_ptr = NULL; /* fail safe */ |
||
8947 | |||
8948 | tok_str_free(str); |
||
8949 | inline_generated = 1; |
||
8950 | } |
||
8951 | } |
||
8952 | if (!inline_generated) |
||
8953 | break; |
||
8954 | } |
||
8955 | |||
8956 | /* free all remaining inline function tokens */ |
||
8957 | for(sym = global_stack; sym != NULL; sym = sym->prev) { |
||
8958 | type = &sym->type; |
||
8959 | if (((type->t & VT_BTYPE) == VT_FUNC) && |
||
8960 | (type->t & (VT_STATIC | VT_INLINE)) == |
||
8961 | (VT_STATIC | VT_INLINE)) { |
||
8962 | str = (int *)sym->r; |
||
8963 | tok_str_free(str); |
||
8964 | sym->r = 0; /* fail safe */ |
||
8965 | } |
||
8966 | } |
||
8967 | } |
||
8968 | |||
8969 | /* 'l' is VT_LOCAL or VT_CONST to define default storage type */ |
||
8970 | static void decl(int l) |
||
8971 | { |
||
8972 | int v, has_init, r; |
||
8973 | CType type, btype; |
||
8974 | Sym *sym; |
||
8975 | AttributeDef ad; |
||
8976 | |||
8977 | while (1) { |
||
8978 | if (!parse_btype(&btype, &ad)) { |
||
8979 | /* skip redundant ';' */ |
||
8980 | /* XXX: find more elegant solution */ |
||
8981 | if (tok == ';') { |
||
8982 | next(); |
||
8983 | continue; |
||
8984 | } |
||
8985 | if (l == VT_CONST && |
||
8986 | (tok == TOK_ASM1 || tok == TOK_ASM2 || tok == TOK_ASM3)) { |
||
8987 | /* global asm block */ |
||
8988 | asm_global_instr(); |
||
8989 | continue; |
||
8990 | } |
||
8991 | /* special test for old K&R protos without explicit int |
||
8992 | type. Only accepted when defining global data */ |
||
8993 | if (l == VT_LOCAL || tok < TOK_DEFINE) |
||
8994 | break; |
||
8995 | btype.t = VT_INT; |
||
8996 | } |
||
8997 | if (((btype.t & VT_BTYPE) == VT_ENUM || |
||
8998 | (btype.t & VT_BTYPE) == VT_STRUCT) && |
||
8999 | tok == ';') { |
||
9000 | /* we accept no variable after */ |
||
9001 | next(); |
||
9002 | continue; |
||
9003 | } |
||
9004 | while (1) { /* iterate thru each declaration */ |
||
9005 | type = btype; |
||
9006 | type_decl(&type, &ad, &v, TYPE_DIRECT); |
||
9007 | #if 0 |
||
9008 | { |
||
9009 | char buf[500]; |
||
9010 | type_to_str(buf, sizeof(buf), t, get_tok_str(v, NULL)); |
||
9011 | printf("type = '%s'\n", buf); |
||
9012 | } |
||
9013 | #endif |
||
9014 | if ((type.t & VT_BTYPE) == VT_FUNC) { |
||
9015 | /* if old style function prototype, we accept a |
||
9016 | declaration list */ |
||
9017 | sym = type.ref; |
||
9018 | if (sym->c == FUNC_OLD) |
||
9019 | func_decl_list(sym); |
||
9020 | } |
||
9021 | |||
9022 | if (tok == '{') { |
||
9023 | if (l == VT_LOCAL) |
||
9024 | error("cannot use local functions"); |
||
9025 | if (!(type.t & VT_FUNC)) |
||
9026 | expect("function definition"); |
||
9027 | |||
9028 | /* reject abstract declarators in function definition */ |
||
9029 | sym = type.ref; |
||
9030 | while ((sym = sym->next) != NULL) |
||
9031 | if (!(sym->v & ~SYM_FIELD)) |
||
9032 | expect("identifier"); |
||
9033 | |||
9034 | /* XXX: cannot do better now: convert extern line to static inline */ |
||
9035 | if ((type.t & (VT_EXTERN | VT_INLINE)) == (VT_EXTERN | VT_INLINE)) |
||
9036 | type.t = (type.t & ~VT_EXTERN) | VT_STATIC; |
||
9037 | |||
9038 | sym = sym_find(v); |
||
9039 | if (sym) { |
||
9040 | if ((sym->type.t & VT_BTYPE) != VT_FUNC) |
||
9041 | goto func_error1; |
||
9042 | /* specific case: if not func_call defined, we put |
||
9043 | the one of the prototype */ |
||
9044 | /* XXX: should have default value */ |
||
9045 | if (sym->type.ref->r != FUNC_CDECL && |
||
9046 | type.ref->r == FUNC_CDECL) |
||
9047 | type.ref->r = sym->type.ref->r; |
||
9048 | if (!is_compatible_types(&sym->type, &type)) { |
||
9049 | func_error1: |
||
9050 | error("incompatible types for redefinition of '%s'", |
||
9051 | get_tok_str(v, NULL)); |
||
9052 | } |
||
9053 | /* if symbol is already defined, then put complete type */ |
||
9054 | sym->type = type; |
||
9055 | } else { |
||
9056 | /* put function symbol */ |
||
9057 | sym = global_identifier_push(v, type.t, 0); |
||
9058 | sym->type.ref = type.ref; |
||
9059 | } |
||
9060 | |||
9061 | /* static inline functions are just recorded as a kind |
||
9062 | of macro. Their code will be emitted at the end of |
||
9063 | the compilation unit only if they are used */ |
||
9064 | if ((type.t & (VT_INLINE | VT_STATIC)) == |
||
9065 | (VT_INLINE | VT_STATIC)) { |
||
9066 | TokenString func_str; |
||
9067 | int block_level; |
||
9068 | |||
9069 | tok_str_new(&func_str); |
||
9070 | |||
9071 | block_level = 0; |
||
9072 | for(;;) { |
||
9073 | int t; |
||
9074 | if (tok == TOK_EOF) |
||
9075 | error("unexpected end of file"); |
||
9076 | tok_str_add_tok(&func_str); |
||
9077 | t = tok; |
||
9078 | next(); |
||
9079 | if (t == '{') { |
||
9080 | block_level++; |
||
9081 | } else if (t == '}') { |
||
9082 | block_level--; |
||
9083 | if (block_level == 0) |
||
9084 | break; |
||
9085 | } |
||
9086 | } |
||
9087 | tok_str_add(&func_str, -1); |
||
9088 | tok_str_add(&func_str, 0); |
||
9089 | sym->r = (int)func_str.str; |
||
9090 | } else { |
||
9091 | /* compute text section */ |
||
9092 | cur_text_section = ad.section; |
||
9093 | if (!cur_text_section) |
||
9094 | cur_text_section = text_section; |
||
9095 | sym->r = VT_SYM | VT_CONST; |
||
9096 | gen_function(sym); |
||
9097 | #ifdef TCC_TARGET_PE |
||
9098 | if (ad.dllexport) { |
||
9099 | ((Elf32_Sym *)symtab_section->data)[sym->c].st_other |= 1; |
||
9100 | } |
||
9101 | #endif |
||
9102 | } |
||
9103 | break; |
||
9104 | } else { |
||
9105 | if (btype.t & VT_TYPEDEF) { |
||
9106 | /* save typedefed type */ |
||
9107 | /* XXX: test storage specifiers ? */ |
||
9108 | sym = sym_push(v, &type, 0, 0); |
||
9109 | sym->type.t |= VT_TYPEDEF; |
||
9110 | } else if ((type.t & VT_BTYPE) == VT_FUNC) { |
||
9111 | /* external function definition */ |
||
9112 | /* specific case for func_call attribute */ |
||
9113 | if (ad.func_call) |
||
9114 | type.ref->r = ad.func_call; |
||
9115 | external_sym(v, &type, 0); |
||
9116 | } else { |
||
9117 | /* not lvalue if array */ |
||
9118 | r = 0; |
||
9119 | if (!(type.t & VT_ARRAY)) |
||
9120 | r |= lvalue_type(type.t); |
||
9121 | has_init = (tok == '='); |
||
9122 | if ((btype.t & VT_EXTERN) || |
||
9123 | ((type.t & VT_ARRAY) && (type.t & VT_STATIC) && |
||
9124 | !has_init && l == VT_CONST && type.ref->c < 0)) { |
||
9125 | /* external variable */ |
||
9126 | /* NOTE: as GCC, uninitialized global static |
||
9127 | arrays of null size are considered as |
||
9128 | extern */ |
||
9129 | external_sym(v, &type, r); |
||
9130 | } else { |
||
9131 | if (type.t & VT_STATIC) |
||
9132 | r |= VT_CONST; |
||
9133 | else |
||
9134 | r |= l; |
||
9135 | if (has_init) |
||
9136 | next(); |
||
9137 | decl_initializer_alloc(&type, &ad, r, |
||
9138 | has_init, v, l); |
||
9139 | } |
||
9140 | } |
||
9141 | if (tok != ',') { |
||
9142 | skip(';'); |
||
9143 | break; |
||
9144 | } |
||
9145 | next(); |
||
9146 | } |
||
9147 | } |
||
9148 | } |
||
9149 | } |
||
9150 | |||
9151 | /* better than nothing, but needs extension to handle '-E' option |
||
9152 | correctly too */ |
||
9153 | static void preprocess_init(TCCState *s1) |
||
9154 | { |
||
9155 | s1->include_stack_ptr = s1->include_stack; |
||
9156 | /* XXX: move that before to avoid having to initialize |
||
9157 | file->ifdef_stack_ptr ? */ |
||
9158 | s1->ifdef_stack_ptr = s1->ifdef_stack; |
||
9159 | file->ifdef_stack_ptr = s1->ifdef_stack_ptr; |
||
9160 | |||
9161 | /* XXX: not ANSI compliant: bound checking says error */ |
||
9162 | vtop = vstack - 1; |
||
9163 | s1->pack_stack[0] = 0; |
||
9164 | s1->pack_stack_ptr = s1->pack_stack; |
||
9165 | } |
||
9166 | |||
9167 | /* compile the C file opened in 'file'. Return non zero if errors. */ |
||
9168 | static int tcc_compile(TCCState *s1) |
||
9169 | { |
||
9170 | Sym *define_start; |
||
9171 | char buf[512]; |
||
9172 | volatile int section_sym; |
||
9173 | |||
9174 | #ifdef INC_DEBUG |
||
9175 | printf("%s: **** new file\n", file->filename); |
||
9176 | #endif |
||
9177 | preprocess_init(s1); |
||
9178 | |||
9179 | funcname = ""; |
||
9180 | anon_sym = SYM_FIRST_ANOM; |
||
9181 | |||
9182 | /* file info: full path + filename */ |
||
9183 | section_sym = 0; /* avoid warning */ |
||
9184 | if (do_debug) { |
||
9185 | section_sym = put_elf_sym(symtab_section, 0, 0, |
||
9186 | ELF32_ST_INFO(STB_LOCAL, STT_SECTION), 0, |
||
9187 | text_section->sh_num, NULL); |
||
9188 | getcwd(buf, sizeof(buf)); |
||
9189 | pstrcat(buf, sizeof(buf), "/"); |
||
9190 | put_stabs_r(buf, N_SO, 0, 0, |
||
9191 | text_section->data_offset, text_section, section_sym); |
||
9192 | put_stabs_r(file->filename, N_SO, 0, 0, |
||
9193 | text_section->data_offset, text_section, section_sym); |
||
9194 | } |
||
9195 | /* an elf symbol of type STT_FILE must be put so that STB_LOCAL |
||
9196 | symbols can be safely used */ |
||
9197 | put_elf_sym(symtab_section, 0, 0, |
||
9198 | ELF32_ST_INFO(STB_LOCAL, STT_FILE), 0, |
||
9199 | SHN_ABS, file->filename); |
||
9200 | |||
9201 | /* define some often used types */ |
||
9202 | int_type.t = VT_INT; |
||
9203 | |||
9204 | char_pointer_type.t = VT_BYTE; |
||
9205 | mk_pointer(&char_pointer_type); |
||
9206 | |||
9207 | func_old_type.t = VT_FUNC; |
||
9208 | func_old_type.ref = sym_push(SYM_FIELD, &int_type, FUNC_CDECL, FUNC_OLD); |
||
9209 | |||
9210 | #if 0 |
||
9211 | /* define 'void *alloca(unsigned int)' builtin function */ |
||
9212 | { |
||
9213 | Sym *s1; |
||
9214 | |||
9215 | p = anon_sym++; |
||
9216 | sym = sym_push(p, mk_pointer(VT_VOID), FUNC_CDECL, FUNC_NEW); |
||
9217 | s1 = sym_push(SYM_FIELD, VT_UNSIGNED | VT_INT, 0, 0); |
||
9218 | s1->next = NULL; |
||
9219 | sym->next = s1; |
||
9220 | sym_push(TOK_alloca, VT_FUNC | (p << VT_STRUCT_SHIFT), VT_CONST, 0); |
||
9221 | } |
||
9222 | #endif |
||
9223 | |||
9224 | define_start = define_stack; |
||
9225 | |||
9226 | if (setjmp(s1->error_jmp_buf) == 0) { |
||
9227 | s1->nb_errors = 0; |
||
9228 | s1->error_set_jmp_enabled = 1; |
||
9229 | |||
9230 | ch = file->buf_ptr[0]; |
||
9231 | tok_flags = TOK_FLAG_BOL | TOK_FLAG_BOF; |
||
9232 | parse_flags = PARSE_FLAG_PREPROCESS | PARSE_FLAG_TOK_NUM; |
||
9233 | next(); |
||
9234 | decl(VT_CONST); |
||
9235 | if (tok != TOK_EOF) |
||
9236 | expect("declaration"); |
||
9237 | |||
9238 | /* end of translation unit info */ |
||
9239 | if (do_debug) { |
||
9240 | put_stabs_r(NULL, N_SO, 0, 0, |
||
9241 | text_section->data_offset, text_section, section_sym); |
||
9242 | } |
||
9243 | } |
||
9244 | s1->error_set_jmp_enabled = 0; |
||
9245 | |||
9246 | /* reset define stack, but leave -Dsymbols (may be incorrect if |
||
9247 | they are undefined) */ |
||
9248 | free_defines(define_start); |
||
9249 | |||
9250 | gen_inline_functions(); |
||
9251 | |||
9252 | sym_pop(&global_stack, NULL); |
||
9253 | |||
9254 | return s1->nb_errors != 0 ? -1 : 0; |
||
9255 | } |
||
9256 | |||
9257 | #ifdef LIBTCC |
||
9258 | int tcc_compile_string(TCCState *s, const char *str) |
||
9259 | { |
||
9260 | BufferedFile bf1, *bf = &bf1; |
||
9261 | int ret, len; |
||
9262 | char *buf; |
||
9263 | |||
9264 | /* init file structure */ |
||
9265 | bf->fd = -1; |
||
9266 | /* XXX: avoid copying */ |
||
9267 | len = strlen(str); |
||
9268 | buf = tcc_malloc(len + 1); |
||
9269 | if (!buf) |
||
9270 | return -1; |
||
9271 | memcpy(buf, str, len); |
||
9272 | buf[len] = CH_EOB; |
||
9273 | bf->buf_ptr = buf; |
||
9274 | bf->buf_end = buf + len; |
||
9275 | pstrcpy(bf->filename, sizeof(bf->filename), " |
||
9276 | bf->line_num = 1; |
||
9277 | file = bf; |
||
9278 | |||
9279 | ret = tcc_compile(s); |
||
9280 | |||
9281 | tcc_free(buf); |
||
9282 | |||
9283 | /* currently, no need to close */ |
||
9284 | return ret; |
||
9285 | } |
||
9286 | #endif |
||
9287 | |||
9288 | /* define a preprocessor symbol. A value can also be provided with the '=' operator */ |
||
9289 | void tcc_define_symbol(TCCState *s1, const char *sym, const char *value) |
||
9290 | { |
||
9291 | BufferedFile bf1, *bf = &bf1; |
||
9292 | |||
9293 | pstrcpy(bf->buffer, IO_BUF_SIZE, sym); |
||
9294 | pstrcat(bf->buffer, IO_BUF_SIZE, " "); |
||
9295 | /* default value */ |
||
9296 | if (!value) |
||
9297 | value = "1"; |
||
9298 | pstrcat(bf->buffer, IO_BUF_SIZE, value); |
||
9299 | |||
9300 | /* init file structure */ |
||
9301 | bf->fd = -1; |
||
9302 | bf->buf_ptr = bf->buffer; |
||
9303 | bf->buf_end = bf->buffer + strlen(bf->buffer); |
||
9304 | *bf->buf_end = CH_EOB; |
||
9305 | bf->filename[0] = '\0'; |
||
9306 | bf->line_num = 1; |
||
9307 | file = bf; |
||
9308 | |||
9309 | s1->include_stack_ptr = s1->include_stack; |
||
9310 | |||
9311 | /* parse with define parser */ |
||
9312 | ch = file->buf_ptr[0]; |
||
9313 | next_nomacro(); |
||
9314 | parse_define(); |
||
9315 | file = NULL; |
||
9316 | } |
||
9317 | |||
9318 | /* undefine a preprocessor symbol */ |
||
9319 | void tcc_undefine_symbol(TCCState *s1, const char *sym) |
||
9320 | { |
||
9321 | TokenSym *ts; |
||
9322 | Sym *s; |
||
9323 | ts = tok_alloc(sym, strlen(sym)); |
||
9324 | s = define_find(ts->tok); |
||
9325 | /* undefine symbol by putting an invalid name */ |
||
9326 | if (s) |
||
9327 | define_undef(s); |
||
9328 | } |
||
9329 | |||
9330 | #ifdef CONFIG_TCC_ASM |
||
9331 | |||
9332 | #ifdef TCC_TARGET_I386 |
||
9333 | #include "i386-asm.c" |
||
9334 | #endif |
||
9335 | #include "tccasm.c" |
||
9336 | |||
9337 | #else |
||
9338 | static void asm_instr(void) |
||
9339 | { |
||
9340 | error("inline asm() not supported"); |
||
9341 | } |
||
9342 | static void asm_global_instr(void) |
||
9343 | { |
||
9344 | error("inline asm() not supported"); |
||
9345 | } |
||
9346 | #endif |
||
9347 | |||
9348 | #include "tccelf.c" |
||
9349 | |||
9350 | #ifdef TCC_TARGET_COFF |
||
9351 | #include "tcccoff.c" |
||
9352 | #endif |
||
9353 | |||
9354 | #if defined(TCC_TARGET_PE) || defined(TCC_TARGET_MEOS) |
||
9355 | #include "tccpe.c" |
||
9356 | #endif |
||
9357 | |||
609 | andrew_pro | 9358 | #ifdef TCC_TARGET_MEOS |
9359 | #include "tccmeos.c" |
||
9360 | #endif |
||
9361 | |||
145 | halyavin | 9362 | /* print the position in the source file of PC value 'pc' by reading |
9363 | the stabs debug information */ |
||
9364 | static void rt_printline(unsigned long wanted_pc) |
||
9365 | { |
||
9366 | Stab_Sym *sym, *sym_end; |
||
9367 | char func_name[128], last_func_name[128]; |
||
9368 | unsigned long func_addr, last_pc, pc; |
||
9369 | const char *incl_files[INCLUDE_STACK_SIZE]; |
||
9370 | int incl_index, len, last_line_num, i; |
||
9371 | const char *str, *p; |
||
9372 | |||
609 | andrew_pro | 9373 | printf("0x%08lx:", wanted_pc); |
145 | halyavin | 9374 | |
9375 | func_name[0] = '\0'; |
||
9376 | func_addr = 0; |
||
9377 | incl_index = 0; |
||
9378 | last_func_name[0] = '\0'; |
||
9379 | last_pc = 0xffffffff; |
||
9380 | last_line_num = 1; |
||
9381 | sym = (Stab_Sym *)stab_section->data + 1; |
||
9382 | sym_end = (Stab_Sym *)(stab_section->data + stab_section->data_offset); |
||
9383 | while (sym < sym_end) { |
||
9384 | switch(sym->n_type) { |
||
9385 | /* function start or end */ |
||
9386 | case N_FUN: |
||
9387 | if (sym->n_strx == 0) { |
||
9388 | /* we test if between last line and end of function */ |
||
9389 | pc = sym->n_value + func_addr; |
||
9390 | if (wanted_pc >= last_pc && wanted_pc < pc) |
||
9391 | goto found; |
||
9392 | func_name[0] = '\0'; |
||
9393 | func_addr = 0; |
||
9394 | } else { |
||
9395 | str = stabstr_section->data + sym->n_strx; |
||
9396 | p = strchr(str, ':'); |
||
9397 | if (!p) { |
||
9398 | pstrcpy(func_name, sizeof(func_name), str); |
||
9399 | } else { |
||
9400 | len = p - str; |
||
9401 | if (len > sizeof(func_name) - 1) |
||
9402 | len = sizeof(func_name) - 1; |
||
9403 | memcpy(func_name, str, len); |
||
9404 | func_name[len] = '\0'; |
||
9405 | } |
||
9406 | func_addr = sym->n_value; |
||
9407 | } |
||
9408 | break; |
||
9409 | /* line number info */ |
||
9410 | case N_SLINE: |
||
9411 | pc = sym->n_value + func_addr; |
||
9412 | if (wanted_pc >= last_pc && wanted_pc < pc) |
||
9413 | goto found; |
||
9414 | last_pc = pc; |
||
9415 | last_line_num = sym->n_desc; |
||
9416 | /* XXX: slow! */ |
||
9417 | strcpy(last_func_name, func_name); |
||
9418 | break; |
||
9419 | /* include files */ |
||
9420 | case N_BINCL: |
||
9421 | str = stabstr_section->data + sym->n_strx; |
||
9422 | add_incl: |
||
9423 | if (incl_index < INCLUDE_STACK_SIZE) { |
||
9424 | incl_files[incl_index++] = str; |
||
9425 | } |
||
9426 | break; |
||
9427 | case N_EINCL: |
||
9428 | if (incl_index > 1) |
||
9429 | incl_index--; |
||
9430 | break; |
||
9431 | case N_SO: |
||
9432 | if (sym->n_strx == 0) { |
||
9433 | incl_index = 0; /* end of translation unit */ |
||
9434 | } else { |
||
9435 | str = stabstr_section->data + sym->n_strx; |
||
9436 | /* do not add path */ |
||
9437 | len = strlen(str); |
||
9438 | if (len > 0 && str[len - 1] != '/') |
||
9439 | goto add_incl; |
||
9440 | } |
||
9441 | break; |
||
9442 | } |
||
9443 | sym++; |
||
9444 | } |
||
9445 | |||
9446 | /* second pass: we try symtab symbols (no line number info) */ |
||
9447 | incl_index = 0; |
||
9448 | { |
||
9449 | Elf32_Sym *sym, *sym_end; |
||
9450 | int type; |
||
9451 | |||
9452 | sym_end = (Elf32_Sym *)(symtab_section->data + symtab_section->data_offset); |
||
9453 | for(sym = (Elf32_Sym *)symtab_section->data + 1; |
||
9454 | sym < sym_end; |
||
9455 | sym++) { |
||
9456 | type = ELF32_ST_TYPE(sym->st_info); |
||
9457 | if (type == STT_FUNC) { |
||
9458 | if (wanted_pc >= sym->st_value && |
||
9459 | wanted_pc < sym->st_value + sym->st_size) { |
||
9460 | pstrcpy(last_func_name, sizeof(last_func_name), |
||
9461 | strtab_section->data + sym->st_name); |
||
9462 | goto found; |
||
9463 | } |
||
9464 | } |
||
9465 | } |
||
9466 | } |
||
9467 | /* did not find any info: */ |
||
609 | andrew_pro | 9468 | printf(" ???\n"); |
145 | halyavin | 9469 | return; |
9470 | found: |
||
9471 | if (last_func_name[0] != '\0') { |
||
609 | andrew_pro | 9472 | printf(" %s()", last_func_name); |
145 | halyavin | 9473 | } |
9474 | if (incl_index > 0) { |
||
609 | andrew_pro | 9475 | printf(" (%s:%d", |
145 | halyavin | 9476 | incl_files[incl_index - 1], last_line_num); |
9477 | for(i = incl_index - 2; i >= 0; i--) |
||
609 | andrew_pro | 9478 | printf(", included from %s", incl_files[i]); |
9479 | printf(")"); |
||
145 | halyavin | 9480 | } |
609 | andrew_pro | 9481 | printf("\n"); |
145 | halyavin | 9482 | } |
9483 | |||
9484 | #if !defined(WIN32) && !defined(CONFIG_TCCBOOT) |
||
9485 | |||
9486 | #ifdef __i386__ |
||
9487 | |||
9488 | /* fix for glibc 2.1 */ |
||
9489 | #ifndef REG_EIP |
||
9490 | #define REG_EIP EIP |
||
9491 | #define REG_EBP EBP |
||
9492 | #endif |
||
9493 | |||
9494 | /* return the PC at frame level 'level'. Return non zero if not found */ |
||
609 | andrew_pro | 9495 | /* |
145 | halyavin | 9496 | static int rt_get_caller_pc(unsigned long *paddr, |
9497 | ucontext_t *uc, int level) |
||
9498 | { |
||
9499 | unsigned long fp; |
||
9500 | int i; |
||
9501 | |||
9502 | if (level == 0) { |
||
9503 | #if defined(__FreeBSD__) |
||
9504 | *paddr = uc->uc_mcontext.mc_eip; |
||
9505 | #elif defined(__dietlibc__) |
||
9506 | *paddr = uc->uc_mcontext.eip; |
||
9507 | #else |
||
9508 | *paddr = uc->uc_mcontext.gregs[REG_EIP]; |
||
9509 | #endif |
||
9510 | return 0; |
||
9511 | } else { |
||
9512 | #if defined(__FreeBSD__) |
||
9513 | fp = uc->uc_mcontext.mc_ebp; |
||
9514 | #elif defined(__dietlibc__) |
||
9515 | fp = uc->uc_mcontext.ebp; |
||
9516 | #else |
||
9517 | fp = uc->uc_mcontext.gregs[REG_EBP]; |
||
9518 | #endif |
||
9519 | for(i=1;i |
||
609 | andrew_pro | 9520 | // XXX: check address validity with program info |
145 | halyavin | 9521 | if (fp <= 0x1000 || fp >= 0xc0000000) |
9522 | return -1; |
||
9523 | fp = ((unsigned long *)fp)[0]; |
||
9524 | } |
||
9525 | *paddr = ((unsigned long *)fp)[1]; |
||
9526 | return 0; |
||
9527 | } |
||
9528 | } |
||
609 | andrew_pro | 9529 | */ |
145 | halyavin | 9530 | #else |
9531 | |||
9532 | #warning add arch specific rt_get_caller_pc() |
||
609 | andrew_pro | 9533 | /* |
145 | halyavin | 9534 | static int rt_get_caller_pc(unsigned long *paddr, |
9535 | ucontext_t *uc, int level) |
||
9536 | { |
||
9537 | return -1; |
||
9538 | } |
||
609 | andrew_pro | 9539 | */ |
145 | halyavin | 9540 | #endif |
9541 | |||
9542 | /* emit a run time error at position 'pc' */ |
||
609 | andrew_pro | 9543 | /* |
145 | halyavin | 9544 | void rt_error(ucontext_t *uc, const char *fmt, ...) |
9545 | { |
||
9546 | va_list ap; |
||
9547 | unsigned long pc; |
||
9548 | int i; |
||
9549 | |||
9550 | va_start(ap, fmt); |
||
609 | andrew_pro | 9551 | printf("Runtime error: "); |
9552 | //vfprintf(stderr, fmt, ap); |
||
9553 | printf("\n"); |
||
145 | halyavin | 9554 | for(i=0;i |
9555 | if (rt_get_caller_pc(&pc, uc, i) < 0) |
||
9556 | break; |
||
9557 | if (i == 0) |
||
609 | andrew_pro | 9558 | printf("at "); |
145 | halyavin | 9559 | else |
609 | andrew_pro | 9560 | printf("by "); |
145 | halyavin | 9561 | rt_printline(pc); |
9562 | } |
||
9563 | exit(255); |
||
9564 | va_end(ap); |
||
9565 | } |
||
9566 | |||
609 | andrew_pro | 9567 | */ |
145 | halyavin | 9568 | /* signal handler for fatal errors */ |
609 | andrew_pro | 9569 | /* |
145 | halyavin | 9570 | static void sig_error(int signum, siginfo_t *siginf, void *puc) |
9571 | { |
||
9572 | ucontext_t *uc = puc; |
||
9573 | |||
9574 | switch(signum) { |
||
9575 | case SIGFPE: |
||
9576 | switch(siginf->si_code) { |
||
9577 | case FPE_INTDIV: |
||
9578 | case FPE_FLTDIV: |
||
9579 | rt_error(uc, "division by zero"); |
||
9580 | break; |
||
9581 | default: |
||
9582 | rt_error(uc, "floating point exception"); |
||
9583 | break; |
||
9584 | } |
||
9585 | break; |
||
9586 | case SIGBUS: |
||
9587 | case SIGSEGV: |
||
9588 | if (rt_bound_error_msg && *rt_bound_error_msg) |
||
9589 | rt_error(uc, *rt_bound_error_msg); |
||
9590 | else |
||
9591 | rt_error(uc, "dereferencing invalid pointer"); |
||
9592 | break; |
||
9593 | case SIGILL: |
||
9594 | rt_error(uc, "illegal instruction"); |
||
9595 | break; |
||
9596 | case SIGABRT: |
||
9597 | rt_error(uc, "abort() called"); |
||
9598 | break; |
||
9599 | default: |
||
9600 | rt_error(uc, "caught signal %d", signum); |
||
9601 | break; |
||
9602 | } |
||
9603 | exit(255); |
||
9604 | } |
||
609 | andrew_pro | 9605 | */ |
145 | halyavin | 9606 | #endif |
9607 | |||
609 | andrew_pro | 9608 | |
145 | halyavin | 9609 | /* do all relocations (needed before using tcc_get_symbol()) */ |
9610 | int tcc_relocate(TCCState *s1) |
||
9611 | { |
||
9612 | Section *s; |
||
9613 | int i; |
||
9614 | |||
9615 | s1->nb_errors = 0; |
||
9616 | |||
9617 | #if defined(TCC_TARGET_PE) || defined(TCC_TARGET_MEOS) |
||
9618 | pe_add_runtime(s1); |
||
9619 | #else |
||
9620 | tcc_add_runtime(s1); |
||
9621 | #endif |
||
9622 | |||
9623 | relocate_common_syms(); |
||
9624 | |||
9625 | tcc_add_linker_symbols(s1); |
||
9626 | |||
9627 | build_got_entries(s1); |
||
9628 | |||
9629 | /* compute relocation address : section are relocated in place. We |
||
9630 | also alloc the bss space */ |
||
9631 | for(i = 1; i < s1->nb_sections; i++) { |
||
9632 | s = s1->sections[i]; |
||
9633 | if (s->sh_flags & SHF_ALLOC) { |
||
9634 | if (s->sh_type == SHT_NOBITS) |
||
9635 | s->data = tcc_mallocz(s->data_offset); |
||
9636 | s->sh_addr = (unsigned long)s->data; |
||
9637 | } |
||
9638 | } |
||
9639 | |||
9640 | relocate_syms(s1, 1); |
||
9641 | |||
9642 | if (s1->nb_errors != 0) |
||
9643 | return -1; |
||
9644 | |||
9645 | /* relocate each section */ |
||
9646 | for(i = 1; i < s1->nb_sections; i++) { |
||
9647 | s = s1->sections[i]; |
||
9648 | if (s->reloc) |
||
9649 | relocate_section(s1, s); |
||
9650 | } |
||
9651 | return 0; |
||
9652 | } |
||
9653 | |||
9654 | /* launch the compiled program with the given arguments */ |
||
9655 | int tcc_run(TCCState *s1, int argc, char **argv) |
||
9656 | { |
||
9657 | int (*prog_main)(int, char **); |
||
9658 | |||
9659 | if (tcc_relocate(s1) < 0) |
||
9660 | return -1; |
||
9661 | |||
9662 | prog_main = tcc_get_symbol_err(s1, "main"); |
||
9663 | |||
9664 | if (do_debug) { |
||
9665 | #if defined(WIN32) || defined(CONFIG_TCCBOOT) |
||
9666 | error("debug mode currently not available for Windows"); |
||
9667 | #else |
||
609 | andrew_pro | 9668 | //struct sigaction sigact; |
145 | halyavin | 9669 | /* install TCC signal handlers to print debug info on fatal |
9670 | runtime errors */ |
||
609 | andrew_pro | 9671 | //sigact.sa_flags = SA_SIGINFO | SA_RESETHAND; |
9672 | //sigact.sa_sigaction = sig_error; |
||
9673 | //sigemptyset(&sigact.sa_mask); |
||
9674 | //sigaction(SIGFPE, &sigact, NULL); |
||
9675 | //sigaction(SIGILL, &sigact, NULL); |
||
9676 | //sigaction(SIGSEGV, &sigact, NULL); |
||
9677 | //sigaction(SIGBUS, &sigact, NULL); |
||
9678 | //sigaction(SIGABRT, &sigact, NULL); |
||
145 | halyavin | 9679 | #endif |
9680 | } |
||
9681 | |||
9682 | #ifdef CONFIG_TCC_BCHECK |
||
9683 | if (do_bounds_check) { |
||
9684 | void (*bound_init)(void); |
||
9685 | |||
9686 | /* set error function */ |
||
9687 | rt_bound_error_msg = (void *)tcc_get_symbol_err(s1, |
||
9688 | "__bound_error_msg"); |
||
9689 | |||
9690 | /* XXX: use .init section so that it also work in binary ? */ |
||
9691 | bound_init = (void *)tcc_get_symbol_err(s1, "__bound_init"); |
||
9692 | bound_init(); |
||
9693 | } |
||
9694 | #endif |
||
9695 | return (*prog_main)(argc, argv); |
||
9696 | } |
||
9697 | |||
9698 | TCCState *tcc_new(void) |
||
9699 | { |
||
9700 | const char *p, *r; |
||
9701 | TCCState *s; |
||
9702 | TokenSym *ts; |
||
9703 | int i, c; |
||
9704 | |||
9705 | s = tcc_mallocz(sizeof(TCCState)); |
||
9706 | if (!s) |
||
9707 | return NULL; |
||
9708 | tcc_state = s; |
||
9709 | s->output_type = TCC_OUTPUT_MEMORY; |
||
9710 | |||
9711 | /* init isid table */ |
||
9712 | for(i=0;i<256;i++) |
||
9713 | isidnum_table[i] = isid(i) || isnum(i); |
||
9714 | |||
9715 | /* add all tokens */ |
||
9716 | table_ident = NULL; |
||
9717 | memset(hash_ident, 0, TOK_HASH_SIZE * sizeof(TokenSym *)); |
||
9718 | |||
9719 | tok_ident = TOK_IDENT; |
||
9720 | p = tcc_keywords; |
||
9721 | while (*p) { |
||
9722 | r = p; |
||
9723 | for(;;) { |
||
9724 | c = *r++; |
||
9725 | if (c == '\0') |
||
9726 | break; |
||
9727 | } |
||
9728 | ts = tok_alloc(p, r - p - 1); |
||
9729 | p = r; |
||
9730 | } |
||
9731 | |||
9732 | /* we add dummy defines for some special macros to speed up tests |
||
9733 | and to have working defined() */ |
||
9734 | define_push(TOK___LINE__, MACRO_OBJ, NULL, NULL); |
||
9735 | define_push(TOK___FILE__, MACRO_OBJ, NULL, NULL); |
||
9736 | define_push(TOK___DATE__, MACRO_OBJ, NULL, NULL); |
||
9737 | define_push(TOK___TIME__, MACRO_OBJ, NULL, NULL); |
||
9738 | |||
9739 | /* standard defines */ |
||
9740 | tcc_define_symbol(s, "__STDC__", NULL); |
||
9741 | #if defined(TCC_TARGET_I386) |
||
9742 | tcc_define_symbol(s, "__i386__", NULL); |
||
9743 | #endif |
||
9744 | #if defined(TCC_TARGET_ARM) |
||
9745 | tcc_define_symbol(s, "__ARM_ARCH_4__", NULL); |
||
9746 | tcc_define_symbol(s, "__arm_elf__", NULL); |
||
9747 | tcc_define_symbol(s, "__arm_elf", NULL); |
||
9748 | tcc_define_symbol(s, "arm_elf", NULL); |
||
9749 | tcc_define_symbol(s, "__arm__", NULL); |
||
9750 | tcc_define_symbol(s, "__arm", NULL); |
||
9751 | tcc_define_symbol(s, "arm", NULL); |
||
9752 | tcc_define_symbol(s, "__APCS_32__", NULL); |
||
9753 | #endif |
||
9754 | #if defined(linux) |
||
9755 | tcc_define_symbol(s, "__linux__", NULL); |
||
9756 | tcc_define_symbol(s, "linux", NULL); |
||
9757 | #endif |
||
9758 | /* tiny C specific defines */ |
||
9759 | tcc_define_symbol(s, "__TINYC__", NULL); |
||
9760 | |||
9761 | /* tiny C & gcc defines */ |
||
9762 | tcc_define_symbol(s, "__SIZE_TYPE__", "unsigned int"); |
||
9763 | tcc_define_symbol(s, "__PTRDIFF_TYPE__", "int"); |
||
9764 | tcc_define_symbol(s, "__WCHAR_TYPE__", "int"); |
||
9765 | |||
9766 | /* default library paths */ |
||
9767 | #ifdef TCC_TARGET_PE |
||
9768 | { |
||
9769 | char buf[1024]; |
||
9770 | snprintf(buf, sizeof(buf), "%s/lib", tcc_lib_path); |
||
9771 | tcc_add_library_path(s, buf); |
||
9772 | } |
||
9773 | #else |
||
609 | andrew_pro | 9774 | #ifdef TCC_TARGET_MEOS |
9775 | tcc_add_library_path(s, ".//lib"); |
||
9776 | #else |
||
145 | halyavin | 9777 | tcc_add_library_path(s, "/usr/local/lib"); |
9778 | tcc_add_library_path(s, "/usr/lib"); |
||
609 | andrew_pro | 9779 | tcc_add_library_path(s, "/lib"); |
145 | halyavin | 9780 | #endif |
9781 | #endif |
||
9782 | |||
9783 | /* no section zero */ |
||
9784 | dynarray_add((void ***)&s->sections, &s->nb_sections, NULL); |
||
9785 | |||
9786 | /* create standard sections */ |
||
9787 | text_section = new_section(s, ".text", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR); |
||
9788 | data_section = new_section(s, ".data", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE); |
||
9789 | bss_section = new_section(s, ".bss", SHT_NOBITS, SHF_ALLOC | SHF_WRITE); |
||
9790 | |||
9791 | /* symbols are always generated for linking stage */ |
||
9792 | symtab_section = new_symtab(s, ".symtab", SHT_SYMTAB, 0, |
||
9793 | ".strtab", |
||
9794 | ".hashtab", SHF_PRIVATE); |
||
9795 | strtab_section = symtab_section->link; |
||
9796 | |||
9797 | /* private symbol table for dynamic symbols */ |
||
9798 | s->dynsymtab_section = new_symtab(s, ".dynsymtab", SHT_SYMTAB, SHF_PRIVATE, |
||
9799 | ".dynstrtab", |
||
9800 | ".dynhashtab", SHF_PRIVATE); |
||
9801 | s->alacarte_link = 1; |
||
9802 | |||
9803 | #ifdef CHAR_IS_UNSIGNED |
||
9804 | s->char_is_unsigned = 1; |
||
9805 | #endif |
||
9806 | #if defined(TCC_TARGET_PE) && 0 |
||
9807 | /* XXX: currently the PE linker is not ready to support that */ |
||
9808 | s->leading_underscore = 1; |
||
9809 | #endif |
||
9810 | return s; |
||
9811 | } |
||
9812 | |||
9813 | void tcc_delete(TCCState *s1) |
||
9814 | { |
||
9815 | int i, n; |
||
9816 | |||
9817 | /* free -D defines */ |
||
9818 | free_defines(NULL); |
||
9819 | |||
9820 | /* free tokens */ |
||
9821 | n = tok_ident - TOK_IDENT; |
||
9822 | for(i = 0; i < n; i++) |
||
9823 | tcc_free(table_ident[i]); |
||
9824 | tcc_free(table_ident); |
||
9825 | |||
9826 | /* free all sections */ |
||
9827 | |||
9828 | free_section(symtab_section->hash); |
||
9829 | |||
9830 | free_section(s1->dynsymtab_section->hash); |
||
9831 | free_section(s1->dynsymtab_section->link); |
||
9832 | free_section(s1->dynsymtab_section); |
||
9833 | |||
9834 | for(i = 1; i < s1->nb_sections; i++) |
||
9835 | free_section(s1->sections[i]); |
||
9836 | tcc_free(s1->sections); |
||
9837 | |||
9838 | /* free loaded dlls array */ |
||
9839 | for(i = 0; i < s1->nb_loaded_dlls; i++) |
||
9840 | tcc_free(s1->loaded_dlls[i]); |
||
9841 | tcc_free(s1->loaded_dlls); |
||
9842 | |||
9843 | /* library paths */ |
||
9844 | for(i = 0; i < s1->nb_library_paths; i++) |
||
9845 | tcc_free(s1->library_paths[i]); |
||
9846 | tcc_free(s1->library_paths); |
||
9847 | |||
9848 | /* cached includes */ |
||
9849 | for(i = 0; i < s1->nb_cached_includes; i++) |
||
9850 | tcc_free(s1->cached_includes[i]); |
||
9851 | tcc_free(s1->cached_includes); |
||
9852 | |||
9853 | for(i = 0; i < s1->nb_include_paths; i++) |
||
9854 | tcc_free(s1->include_paths[i]); |
||
9855 | tcc_free(s1->include_paths); |
||
9856 | |||
9857 | for(i = 0; i < s1->nb_sysinclude_paths; i++) |
||
9858 | tcc_free(s1->sysinclude_paths[i]); |
||
9859 | tcc_free(s1->sysinclude_paths); |
||
9860 | |||
9861 | tcc_free(s1); |
||
9862 | } |
||
9863 | |||
9864 | int tcc_add_include_path(TCCState *s1, const char *pathname) |
||
9865 | { |
||
9866 | char *pathname1; |
||
9867 | |||
9868 | pathname1 = tcc_strdup(pathname); |
||
9869 | dynarray_add((void ***)&s1->include_paths, &s1->nb_include_paths, pathname1); |
||
9870 | return 0; |
||
9871 | } |
||
9872 | |||
9873 | int tcc_add_sysinclude_path(TCCState *s1, const char *pathname) |
||
9874 | { |
||
9875 | char *pathname1; |
||
9876 | |||
9877 | pathname1 = tcc_strdup(pathname); |
||
9878 | dynarray_add((void ***)&s1->sysinclude_paths, &s1->nb_sysinclude_paths, pathname1); |
||
9879 | return 0; |
||
9880 | } |
||
9881 | |||
9882 | static int tcc_add_file_internal(TCCState *s1, const char *filename, int flags) |
||
9883 | { |
||
9884 | const char *ext, *filename1; |
||
9885 | Elf32_Ehdr ehdr; |
||
9886 | int fd, ret; |
||
9887 | BufferedFile *saved_file; |
||
9888 | |||
9889 | /* find source file type with extension */ |
||
9890 | filename1 = strrchr(filename, '/'); |
||
9891 | if (filename1) |
||
9892 | filename1++; |
||
9893 | else |
||
9894 | filename1 = filename; |
||
9895 | ext = strrchr(filename1, '.'); |
||
9896 | if (ext) |
||
9897 | ext++; |
||
9898 | |||
9899 | /* open the file */ |
||
9900 | saved_file = file; |
||
9901 | file = tcc_open(s1, filename); |
||
9902 | if (!file) { |
||
9903 | if (flags & AFF_PRINT_ERROR) { |
||
9904 | error_noabort("file '%s' not found", filename); |
||
9905 | } |
||
9906 | ret = -1; |
||
9907 | goto fail1; |
||
9908 | } |
||
9909 | |||
9910 | if (!ext || !strcmp(ext, "c")) { |
||
9911 | /* C file assumed */ |
||
9912 | ret = tcc_compile(s1); |
||
9913 | } else |
||
9914 | #ifdef CONFIG_TCC_ASM |
||
9915 | if (!strcmp(ext, "S")) { |
||
9916 | /* preprocessed assembler */ |
||
9917 | ret = tcc_assemble(s1, 1); |
||
9918 | } else if (!strcmp(ext, "s")) { |
||
9919 | /* non preprocessed assembler */ |
||
9920 | ret = tcc_assemble(s1, 0); |
||
9921 | } else |
||
9922 | #endif |
||
9923 | #ifdef TCC_TARGET_PE |
||
9924 | if (!strcmp(ext, "def")) { |
||
9925 | ret = pe_load_def_file(s1, fdopen(file->fd, "rb")); |
||
9926 | } else |
||
9927 | #endif |
||
9928 | { |
||
9929 | fd = file->fd; |
||
9930 | /* assume executable format: auto guess file type */ |
||
9931 | ret = read(fd, &ehdr, sizeof(ehdr)); |
||
9932 | lseek(fd, 0, SEEK_SET); |
||
9933 | if (ret <= 0) { |
||
9934 | error_noabort("could not read header"); |
||
9935 | goto fail; |
||
9936 | } else if (ret != sizeof(ehdr)) { |
||
9937 | goto try_load_script; |
||
9938 | } |
||
9939 | |||
9940 | if (ehdr.e_ident[0] == ELFMAG0 && |
||
9941 | ehdr.e_ident[1] == ELFMAG1 && |
||
9942 | ehdr.e_ident[2] == ELFMAG2 && |
||
9943 | ehdr.e_ident[3] == ELFMAG3) { |
||
9944 | file->line_num = 0; /* do not display line number if error */ |
||
9945 | if (ehdr.e_type == ET_REL) { |
||
9946 | ret = tcc_load_object_file(s1, fd, 0); |
||
9947 | } else if (ehdr.e_type == ET_DYN) { |
||
9948 | if (s1->output_type == TCC_OUTPUT_MEMORY) { |
||
9949 | #if defined(TCC_TARGET_PE) || defined(TCC_TARGET_MEOS) |
||
9950 | ret = -1; |
||
9951 | #else |
||
9952 | void *h; |
||
9953 | h = dlopen(filename, RTLD_GLOBAL | RTLD_LAZY); |
||
9954 | if (h) |
||
9955 | ret = 0; |
||
9956 | else |
||
9957 | ret = -1; |
||
9958 | #endif |
||
9959 | } else { |
||
9960 | ret = tcc_load_dll(s1, fd, filename, |
||
9961 | (flags & AFF_REFERENCED_DLL) != 0); |
||
9962 | } |
||
9963 | } else { |
||
9964 | error_noabort("unrecognized ELF file"); |
||
9965 | goto fail; |
||
9966 | } |
||
9967 | } else if (memcmp((char *)&ehdr, ARMAG, 8) == 0) { |
||
9968 | file->line_num = 0; /* do not display line number if error */ |
||
9969 | ret = tcc_load_archive(s1, fd); |
||
9970 | } else |
||
9971 | #ifdef TCC_TARGET_COFF |
||
9972 | if (*(uint16_t *)(&ehdr) == COFF_C67_MAGIC) { |
||
9973 | ret = tcc_load_coff(s1, fd); |
||
9974 | } else |
||
9975 | #endif |
||
9976 | { |
||
9977 | /* as GNU ld, consider it is an ld script if not recognized */ |
||
9978 | try_load_script: |
||
9979 | ret = tcc_load_ldscript(s1); |
||
9980 | if (ret < 0) { |
||
9981 | error_noabort("unrecognized file type"); |
||
9982 | goto fail; |
||
9983 | } |
||
9984 | } |
||
9985 | } |
||
9986 | the_end: |
||
9987 | tcc_close(file); |
||
9988 | fail1: |
||
9989 | file = saved_file; |
||
9990 | return ret; |
||
9991 | fail: |
||
9992 | ret = -1; |
||
9993 | goto the_end; |
||
9994 | } |
||
9995 | |||
9996 | int tcc_add_file(TCCState *s, const char *filename) |
||
9997 | { |
||
9998 | return tcc_add_file_internal(s, filename, AFF_PRINT_ERROR); |
||
9999 | } |
||
10000 | |||
10001 | int tcc_add_library_path(TCCState *s, const char *pathname) |
||
10002 | { |
||
10003 | char *pathname1; |
||
10004 | |||
10005 | pathname1 = tcc_strdup(pathname); |
||
10006 | dynarray_add((void ***)&s->library_paths, &s->nb_library_paths, pathname1); |
||
10007 | return 0; |
||
10008 | } |
||
10009 | |||
10010 | /* find and load a dll. Return non zero if not found */ |
||
10011 | /* XXX: add '-rpath' option support ? */ |
||
10012 | static int tcc_add_dll(TCCState *s, const char *filename, int flags) |
||
10013 | { |
||
10014 | char buf[1024]; |
||
10015 | int i; |
||
10016 | |||
10017 | for(i = 0; i < s->nb_library_paths; i++) { |
||
10018 | snprintf(buf, sizeof(buf), "%s/%s", |
||
10019 | s->library_paths[i], filename); |
||
10020 | if (tcc_add_file_internal(s, buf, flags) == 0) |
||
10021 | return 0; |
||
10022 | } |
||
10023 | return -1; |
||
10024 | } |
||
10025 | |||
10026 | /* the library name is the same as the argument of the '-l' option */ |
||
10027 | int tcc_add_library(TCCState *s, const char *libraryname) |
||
10028 | { |
||
10029 | char buf[1024]; |
||
10030 | int i; |
||
10031 | |||
10032 | /* first we look for the dynamic library if not static linking */ |
||
10033 | if (!s->static_link) { |
||
10034 | #ifdef TCC_TARGET_PE |
||
10035 | snprintf(buf, sizeof(buf), "%s.def", libraryname); |
||
10036 | #else |
||
10037 | snprintf(buf, sizeof(buf), "lib%s.so", libraryname); |
||
10038 | #endif |
||
10039 | if (tcc_add_dll(s, buf, 0) == 0) |
||
10040 | return 0; |
||
10041 | } |
||
10042 | |||
10043 | /* then we look for the static library */ |
||
10044 | for(i = 0; i < s->nb_library_paths; i++) { |
||
10045 | snprintf(buf, sizeof(buf), "%s/lib%s.a", |
||
10046 | s->library_paths[i], libraryname); |
||
10047 | if (tcc_add_file_internal(s, buf, 0) == 0) |
||
10048 | return 0; |
||
10049 | } |
||
10050 | return -1; |
||
10051 | } |
||
10052 | |||
10053 | int tcc_add_symbol(TCCState *s, const char *name, unsigned long val) |
||
10054 | { |
||
10055 | add_elf_sym(symtab_section, val, 0, |
||
10056 | ELF32_ST_INFO(STB_GLOBAL, STT_NOTYPE), 0, |
||
10057 | SHN_ABS, name); |
||
10058 | return 0; |
||
10059 | } |
||
10060 | |||
10061 | int tcc_set_output_type(TCCState *s, int output_type) |
||
10062 | { |
||
10063 | s->output_type = output_type; |
||
10064 | |||
10065 | if (!s->nostdinc) { |
||
10066 | char buf[1024]; |
||
10067 | |||
10068 | /* default include paths */ |
||
10069 | /* XXX: reverse order needed if -isystem support */ |
||
10070 | #if !defined(TCC_TARGET_PE) && !defined(TCC_TARGET_MEOS) |
||
10071 | tcc_add_sysinclude_path(s, "/usr/local/include"); |
||
10072 | tcc_add_sysinclude_path(s, "/usr/include"); |
||
10073 | #endif |
||
609 | andrew_pro | 10074 | |
10075 | #if defined(TCC_TARGET_MEOS) |
||
10076 | tcc_add_sysinclude_path(s, ".//include"); |
||
10077 | #endif |
||
145 | halyavin | 10078 | snprintf(buf, sizeof(buf), "%s/include", tcc_lib_path); |
10079 | tcc_add_sysinclude_path(s, buf); |
||
10080 | #ifdef TCC_TARGET_PE |
||
10081 | snprintf(buf, sizeof(buf), "%s/include/winapi", tcc_lib_path); |
||
10082 | tcc_add_sysinclude_path(s, buf); |
||
10083 | #endif |
||
10084 | } |
||
10085 | |||
10086 | /* if bound checking, then add corresponding sections */ |
||
10087 | #ifdef CONFIG_TCC_BCHECK |
||
10088 | if (do_bounds_check) { |
||
10089 | /* define symbol */ |
||
10090 | tcc_define_symbol(s, "__BOUNDS_CHECKING_ON", NULL); |
||
10091 | /* create bounds sections */ |
||
10092 | bounds_section = new_section(s, ".bounds", |
||
10093 | SHT_PROGBITS, SHF_ALLOC); |
||
10094 | lbounds_section = new_section(s, ".lbounds", |
||
10095 | SHT_PROGBITS, SHF_ALLOC); |
||
10096 | } |
||
10097 | #endif |
||
10098 | |||
10099 | if (s->char_is_unsigned) { |
||
10100 | tcc_define_symbol(s, "__CHAR_UNSIGNED__", NULL); |
||
10101 | } |
||
10102 | |||
10103 | /* add debug sections */ |
||
10104 | if (do_debug) { |
||
10105 | /* stab symbols */ |
||
10106 | stab_section = new_section(s, ".stab", SHT_PROGBITS, 0); |
||
10107 | stab_section->sh_entsize = sizeof(Stab_Sym); |
||
10108 | stabstr_section = new_section(s, ".stabstr", SHT_STRTAB, 0); |
||
10109 | put_elf_str(stabstr_section, ""); |
||
10110 | stab_section->link = stabstr_section; |
||
10111 | /* put first entry */ |
||
10112 | put_stabs("", 0, 0, 0, 0); |
||
10113 | } |
||
10114 | |||
10115 | /* add libc crt1/crti objects */ |
||
10116 | #if !defined(TCC_TARGET_PE) && !defined(TCC_TARGET_MEOS) |
||
10117 | if ((output_type == TCC_OUTPUT_EXE || output_type == TCC_OUTPUT_DLL) && |
||
10118 | !s->nostdlib) { |
||
10119 | if (output_type != TCC_OUTPUT_DLL) |
||
10120 | tcc_add_file(s, CONFIG_TCC_CRT_PREFIX "/crt1.o"); |
||
10121 | tcc_add_file(s, CONFIG_TCC_CRT_PREFIX "/crti.o"); |
||
10122 | } |
||
609 | andrew_pro | 10123 | #endif |
10124 | #if defined(TCC_TARGET_MEOS) |
||
10125 | if (s->output_type != TCC_OUTPUT_OBJ) |
||
10126 | tcc_add_file(s,".//start.o"); |
||
145 | halyavin | 10127 | #endif |
10128 | return 0; |
||
10129 | } |
||
10130 | |||
10131 | #define WD_ALL 0x0001 /* warning is activated when using -Wall */ |
||
10132 | #define FD_INVERT 0x0002 /* invert value before storing */ |
||
10133 | |||
10134 | typedef struct FlagDef { |
||
10135 | uint16_t offset; |
||
10136 | uint16_t flags; |
||
10137 | const char *name; |
||
10138 | } FlagDef; |
||
10139 | |||
10140 | static const FlagDef warning_defs[] = { |
||
10141 | { offsetof(TCCState, warn_unsupported), 0, "unsupported" }, |
||
10142 | { offsetof(TCCState, warn_write_strings), 0, "write-strings" }, |
||
10143 | { offsetof(TCCState, warn_error), 0, "error" }, |
||
10144 | { offsetof(TCCState, warn_implicit_function_declaration), WD_ALL, |
||
10145 | "implicit-function-declaration" }, |
||
10146 | }; |
||
10147 | |||
10148 | static int set_flag(TCCState *s, const FlagDef *flags, int nb_flags, |
||
10149 | const char *name, int value) |
||
10150 | { |
||
10151 | int i; |
||
10152 | const FlagDef *p; |
||
10153 | const char *r; |
||
10154 | |||
10155 | r = name; |
||
10156 | if (r[0] == 'n' && r[1] == 'o' && r[2] == '-') { |
||
10157 | r += 3; |
||
10158 | value = !value; |
||
10159 | } |
||
10160 | for(i = 0, p = flags; i < nb_flags; i++, p++) { |
||
10161 | if (!strcmp(r, p->name)) |
||
10162 | goto found; |
||
10163 | } |
||
10164 | return -1; |
||
10165 | found: |
||
10166 | if (p->flags & FD_INVERT) |
||
10167 | value = !value; |
||
10168 | *(int *)((uint8_t *)s + p->offset) = value; |
||
10169 | return 0; |
||
10170 | } |
||
10171 | |||
10172 | |||
10173 | /* set/reset a warning */ |
||
10174 | int tcc_set_warning(TCCState *s, const char *warning_name, int value) |
||
10175 | { |
||
10176 | int i; |
||
10177 | const FlagDef *p; |
||
10178 | |||
10179 | if (!strcmp(warning_name, "all")) { |
||
10180 | for(i = 0, p = warning_defs; i < countof(warning_defs); i++, p++) { |
||
10181 | if (p->flags & WD_ALL) |
||
10182 | *(int *)((uint8_t *)s + p->offset) = 1; |
||
10183 | } |
||
10184 | return 0; |
||
10185 | } else { |
||
10186 | return set_flag(s, warning_defs, countof(warning_defs), |
||
10187 | warning_name, value); |
||
10188 | } |
||
10189 | } |
||
10190 | |||
10191 | static const FlagDef flag_defs[] = { |
||
10192 | { offsetof(TCCState, char_is_unsigned), 0, "unsigned-char" }, |
||
10193 | { offsetof(TCCState, char_is_unsigned), FD_INVERT, "signed-char" }, |
||
10194 | { offsetof(TCCState, nocommon), FD_INVERT, "common" }, |
||
10195 | { offsetof(TCCState, leading_underscore), 0, "leading-underscore" }, |
||
10196 | }; |
||
10197 | |||
10198 | /* set/reset a flag */ |
||
10199 | int tcc_set_flag(TCCState *s, const char *flag_name, int value) |
||
10200 | { |
||
10201 | return set_flag(s, flag_defs, countof(flag_defs), |
||
10202 | flag_name, value); |
||
10203 | } |
||
10204 | |||
10205 | #if !defined(LIBTCC) |
||
10206 | |||
10207 | /* extract the basename of a file */ |
||
10208 | static const char *tcc_basename(const char *name) |
||
10209 | { |
||
10210 | const char *p; |
||
10211 | p = strrchr(name, '/'); |
||
10212 | #ifdef WIN32 |
||
10213 | if (!p) |
||
10214 | p = strrchr(name, '\\'); |
||
10215 | #endif |
||
10216 | if (!p) |
||
10217 | p = name; |
||
10218 | else |
||
10219 | p++; |
||
10220 | return p; |
||
10221 | } |
||
10222 | |||
10223 | static int64_t getclock_us(void) |
||
10224 | { |
||
10225 | #ifdef WIN32 |
||
10226 | struct _timeb tb; |
||
10227 | _ftime(&tb); |
||
10228 | return (tb.time * 1000LL + tb.millitm) * 1000LL; |
||
10229 | #else |
||
10230 | struct timeval tv; |
||
10231 | gettimeofday(&tv, NULL); |
||
10232 | return tv.tv_sec * 1000000LL + tv.tv_usec; |
||
10233 | #endif |
||
10234 | } |
||
10235 | |||
10236 | void help(void) |
||
10237 | { |
||
10238 | printf("tcc version " TCC_VERSION " - Tiny C Compiler - Copyright (C) 2001-2005 Fabrice Bellard\n" |
||
10239 | "usage: tcc [-v] [-c] [-o outfile] [-Bdir] [-bench] [-Idir] [-Dsym[=val]] [-Usym]\n" |
||
10240 | " [-Wwarn] [-g] [-b] [-bt N] [-Ldir] [-llib] [-shared] [-static]\n" |
||
10241 | " [infile1 infile2...] [-run infile args...]\n" |
||
10242 | "\n" |
||
10243 | "General options:\n" |
||
10244 | " -v display current version\n" |
||
10245 | " -c compile only - generate an object file\n" |
||
10246 | " -o outfile set output filename\n" |
||
10247 | " -Bdir set tcc internal library path\n" |
||
10248 | " -bench output compilation statistics\n" |
||
10249 | " -run run compiled source\n" |
||
10250 | " -fflag set or reset (with 'no-' prefix) 'flag' (see man page)\n" |
||
10251 | " -Wwarning set or reset (with 'no-' prefix) 'warning' (see man page)\n" |
||
10252 | " -w disable all warnings\n" |
||
10253 | "Preprocessor options:\n" |
||
10254 | " -Idir add include path 'dir'\n" |
||
10255 | " -Dsym[=val] define 'sym' with value 'val'\n" |
||
10256 | " -Usym undefine 'sym'\n" |
||
10257 | "Linker options:\n" |
||
10258 | " -Ldir add library path 'dir'\n" |
||
10259 | " -llib link with dynamic or static library 'lib'\n" |
||
10260 | " -shared generate a shared library\n" |
||
10261 | " -static static linking\n" |
||
10262 | " -rdynamic export all global symbols to dynamic linker\n" |
||
10263 | " -r relocatable output\n" |
||
10264 | "Debugger options:\n" |
||
10265 | " -g generate runtime debug info\n" |
||
10266 | " -bt N show N callers in stack traces\n" |
||
10267 | ); |
||
10268 | } |
||
10269 | |||
10270 | #define TCC_OPTION_HAS_ARG 0x0001 |
||
10271 | #define TCC_OPTION_NOSEP 0x0002 /* cannot have space before option and arg */ |
||
10272 | |||
10273 | typedef struct TCCOption { |
||
10274 | const char *name; |
||
10275 | uint16_t index; |
||
10276 | uint16_t flags; |
||
10277 | } TCCOption; |
||
10278 | |||
10279 | enum { |
||
10280 | TCC_OPTION_HELP, |
||
10281 | TCC_OPTION_I, |
||
10282 | TCC_OPTION_D, |
||
10283 | TCC_OPTION_U, |
||
10284 | TCC_OPTION_L, |
||
10285 | TCC_OPTION_B, |
||
10286 | TCC_OPTION_l, |
||
10287 | TCC_OPTION_bench, |
||
10288 | TCC_OPTION_bt, |
||
10289 | TCC_OPTION_b, |
||
10290 | TCC_OPTION_g, |
||
10291 | TCC_OPTION_c, |
||
10292 | TCC_OPTION_static, |
||
10293 | TCC_OPTION_shared, |
||
10294 | TCC_OPTION_o, |
||
10295 | TCC_OPTION_r, |
||
10296 | TCC_OPTION_Wl, |
||
10297 | TCC_OPTION_W, |
||
10298 | TCC_OPTION_O, |
||
10299 | TCC_OPTION_m, |
||
10300 | TCC_OPTION_f, |
||
10301 | TCC_OPTION_nostdinc, |
||
10302 | TCC_OPTION_nostdlib, |
||
10303 | TCC_OPTION_print_search_dirs, |
||
10304 | TCC_OPTION_rdynamic, |
||
10305 | TCC_OPTION_run, |
||
10306 | TCC_OPTION_v, |
||
10307 | TCC_OPTION_w, |
||
10308 | TCC_OPTION_pipe, |
||
10309 | }; |
||
10310 | |||
10311 | static const TCCOption tcc_options[] = { |
||
10312 | { "h", TCC_OPTION_HELP, 0 }, |
||
10313 | { "?", TCC_OPTION_HELP, 0 }, |
||
10314 | { "I", TCC_OPTION_I, TCC_OPTION_HAS_ARG }, |
||
10315 | { "D", TCC_OPTION_D, TCC_OPTION_HAS_ARG }, |
||
10316 | { "U", TCC_OPTION_U, TCC_OPTION_HAS_ARG }, |
||
10317 | { "L", TCC_OPTION_L, TCC_OPTION_HAS_ARG }, |
||
10318 | { "B", TCC_OPTION_B, TCC_OPTION_HAS_ARG }, |
||
10319 | { "l", TCC_OPTION_l, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, |
||
10320 | { "bench", TCC_OPTION_bench, 0 }, |
||
10321 | { "bt", TCC_OPTION_bt, TCC_OPTION_HAS_ARG }, |
||
10322 | #ifdef CONFIG_TCC_BCHECK |
||
10323 | { "b", TCC_OPTION_b, 0 }, |
||
10324 | #endif |
||
10325 | { "g", TCC_OPTION_g, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, |
||
10326 | { "c", TCC_OPTION_c, 0 }, |
||
10327 | { "static", TCC_OPTION_static, 0 }, |
||
10328 | { "shared", TCC_OPTION_shared, 0 }, |
||
10329 | { "o", TCC_OPTION_o, TCC_OPTION_HAS_ARG }, |
||
10330 | { "run", TCC_OPTION_run, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, |
||
10331 | { "rdynamic", TCC_OPTION_rdynamic, 0 }, |
||
10332 | { "r", TCC_OPTION_r, 0 }, |
||
10333 | { "Wl,", TCC_OPTION_Wl, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, |
||
10334 | { "W", TCC_OPTION_W, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, |
||
10335 | { "O", TCC_OPTION_O, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, |
||
10336 | { "m", TCC_OPTION_m, TCC_OPTION_HAS_ARG }, |
||
10337 | { "f", TCC_OPTION_f, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, |
||
10338 | { "nostdinc", TCC_OPTION_nostdinc, 0 }, |
||
10339 | { "nostdlib", TCC_OPTION_nostdlib, 0 }, |
||
10340 | { "print-search-dirs", TCC_OPTION_print_search_dirs, 0 }, |
||
10341 | { "v", TCC_OPTION_v, 0 }, |
||
10342 | { "w", TCC_OPTION_w, 0 }, |
||
10343 | { "pipe", TCC_OPTION_pipe, 0}, |
||
10344 | { NULL }, |
||
10345 | }; |
||
10346 | |||
10347 | /* convert 'str' into an array of space separated strings */ |
||
10348 | static int expand_args(char ***pargv, const char *str) |
||
10349 | { |
||
10350 | const char *s1; |
||
10351 | char **argv, *arg; |
||
10352 | int argc, len; |
||
10353 | |||
10354 | argc = 0; |
||
10355 | argv = NULL; |
||
10356 | for(;;) { |
||
10357 | while (is_space(*str)) |
||
10358 | str++; |
||
10359 | if (*str == '\0') |
||
10360 | break; |
||
10361 | s1 = str; |
||
10362 | while (*str != '\0' && !is_space(*str)) |
||
10363 | str++; |
||
10364 | len = str - s1; |
||
10365 | arg = tcc_malloc(len + 1); |
||
10366 | memcpy(arg, s1, len); |
||
10367 | arg[len] = '\0'; |
||
10368 | dynarray_add((void ***)&argv, &argc, arg); |
||
10369 | } |
||
10370 | *pargv = argv; |
||
10371 | return argc; |
||
10372 | } |
||
10373 | |||
10374 | static char **files; |
||
10375 | static int nb_files, nb_libraries; |
||
10376 | static int multiple_files; |
||
10377 | static int print_search_dirs; |
||
10378 | static int output_type; |
||
10379 | static int reloc_output; |
||
10380 | static const char *outfile; |
||
10381 | |||
10382 | int parse_args(TCCState *s, int argc, char **argv) |
||
10383 | { |
||
10384 | int optind; |
||
609 | andrew_pro | 10385 | int i; |
145 | halyavin | 10386 | const TCCOption *popt; |
10387 | const char *optarg, *p1, *r1; |
||
10388 | char *r; |
||
609 | andrew_pro | 10389 | /* |
10390 | printf("\n%d\n",argc); |
||
145 | halyavin | 10391 | |
609 | andrew_pro | 10392 | for(i=0;i |
10393 | { |
||
10394 | printf("\n parameter %d = %s",i+1,argv[i]); |
||
10395 | } |
||
10396 | printf("\n"); |
||
10397 | */ |
||
145 | halyavin | 10398 | optind = 0; |
10399 | while (1) { |
||
10400 | if (optind >= argc) { |
||
10401 | if (nb_files == 0 && !print_search_dirs) |
||
609 | andrew_pro | 10402 | goto show_help; |
145 | halyavin | 10403 | else |
10404 | break; |
||
10405 | } |
||
10406 | r = argv[optind++]; |
||
10407 | if (r[0] != '-') { |
||
609 | andrew_pro | 10408 | |
145 | halyavin | 10409 | /* add a new file */ |
10410 | dynarray_add((void ***)&files, &nb_files, r); |
||
10411 | if (!multiple_files) { |
||
10412 | optind--; |
||
10413 | /* argv[0] will be this file */ |
||
10414 | break; |
||
10415 | } |
||
10416 | } else { |
||
10417 | /* find option in table (match only the first chars */ |
||
10418 | popt = tcc_options; |
||
10419 | for(;;) { |
||
10420 | p1 = popt->name; |
||
10421 | if (p1 == NULL) |
||
609 | andrew_pro | 10422 | printf("\n invalid option -- '%s'", r); |
145 | halyavin | 10423 | r1 = r + 1; |
10424 | for(;;) { |
||
10425 | if (*p1 == '\0') |
||
10426 | goto option_found; |
||
10427 | if (*r1 != *p1) |
||
10428 | break; |
||
10429 | p1++; |
||
10430 | r1++; |
||
10431 | } |
||
10432 | popt++; |
||
10433 | } |
||
10434 | option_found: |
||
10435 | if (popt->flags & TCC_OPTION_HAS_ARG) { |
||
10436 | if (*r1 != '\0' || (popt->flags & TCC_OPTION_NOSEP)) { |
||
10437 | optarg = r1; |
||
10438 | } else { |
||
10439 | if (optind >= argc) |
||
609 | andrew_pro | 10440 | printf("\n argument to '%s' is missing", r); |
145 | halyavin | 10441 | optarg = argv[optind++]; |
10442 | } |
||
10443 | } else { |
||
10444 | if (*r1 != '\0') |
||
10445 | goto show_help; |
||
10446 | optarg = NULL; |
||
10447 | } |
||
10448 | |||
10449 | switch(popt->index) { |
||
10450 | case TCC_OPTION_HELP: |
||
10451 | show_help: |
||
10452 | help(); |
||
10453 | exit(1); |
||
10454 | case TCC_OPTION_I: |
||
10455 | if (tcc_add_include_path(s, optarg) < 0) |
||
609 | andrew_pro | 10456 | printf("\n too many include paths"); |
145 | halyavin | 10457 | break; |
10458 | case TCC_OPTION_D: |
||
10459 | { |
||
10460 | char *sym, *value; |
||
10461 | sym = (char *)optarg; |
||
10462 | value = strchr(sym, '='); |
||
10463 | if (value) { |
||
10464 | *value = '\0'; |
||
10465 | value++; |
||
10466 | } |
||
10467 | tcc_define_symbol(s, sym, value); |
||
10468 | } |
||
10469 | break; |
||
10470 | case TCC_OPTION_U: |
||
10471 | tcc_undefine_symbol(s, optarg); |
||
10472 | break; |
||
10473 | case TCC_OPTION_L: |
||
10474 | tcc_add_library_path(s, optarg); |
||
10475 | break; |
||
10476 | case TCC_OPTION_B: |
||
10477 | /* set tcc utilities path (mainly for tcc development) */ |
||
10478 | tcc_lib_path = optarg; |
||
10479 | break; |
||
10480 | case TCC_OPTION_l: |
||
10481 | dynarray_add((void ***)&files, &nb_files, r); |
||
10482 | nb_libraries++; |
||
10483 | break; |
||
10484 | case TCC_OPTION_bench: |
||
10485 | do_bench = 1; |
||
10486 | break; |
||
10487 | case TCC_OPTION_bt: |
||
10488 | num_callers = atoi(optarg); |
||
10489 | break; |
||
10490 | #ifdef CONFIG_TCC_BCHECK |
||
10491 | case TCC_OPTION_b: |
||
10492 | do_bounds_check = 1; |
||
10493 | do_debug = 1; |
||
10494 | break; |
||
10495 | #endif |
||
10496 | case TCC_OPTION_g: |
||
10497 | do_debug = 1; |
||
10498 | break; |
||
10499 | case TCC_OPTION_c: |
||
10500 | multiple_files = 1; |
||
10501 | output_type = TCC_OUTPUT_OBJ; |
||
10502 | break; |
||
10503 | case TCC_OPTION_static: |
||
10504 | s->static_link = 1; |
||
10505 | break; |
||
10506 | case TCC_OPTION_shared: |
||
10507 | output_type = TCC_OUTPUT_DLL; |
||
10508 | break; |
||
10509 | case TCC_OPTION_o: |
||
10510 | multiple_files = 1; |
||
10511 | outfile = optarg; |
||
10512 | break; |
||
10513 | case TCC_OPTION_r: |
||
10514 | /* generate a .o merging several output files */ |
||
10515 | reloc_output = 1; |
||
10516 | output_type = TCC_OUTPUT_OBJ; |
||
10517 | break; |
||
10518 | case TCC_OPTION_nostdinc: |
||
10519 | s->nostdinc = 1; |
||
10520 | break; |
||
10521 | case TCC_OPTION_nostdlib: |
||
10522 | s->nostdlib = 1; |
||
10523 | break; |
||
10524 | case TCC_OPTION_print_search_dirs: |
||
10525 | print_search_dirs = 1; |
||
10526 | break; |
||
10527 | case TCC_OPTION_run: |
||
10528 | { |
||
10529 | int argc1; |
||
10530 | char **argv1; |
||
10531 | argc1 = expand_args(&argv1, optarg); |
||
10532 | if (argc1 > 0) { |
||
10533 | parse_args(s, argc1, argv1); |
||
10534 | } |
||
10535 | multiple_files = 0; |
||
10536 | output_type = TCC_OUTPUT_MEMORY; |
||
10537 | } |
||
10538 | break; |
||
10539 | case TCC_OPTION_v: |
||
10540 | printf("tcc version %s\n", TCC_VERSION); |
||
10541 | exit(0); |
||
10542 | case TCC_OPTION_f: |
||
10543 | if (tcc_set_flag(s, optarg, 1) < 0 && s->warn_unsupported) |
||
10544 | goto unsupported_option; |
||
10545 | break; |
||
10546 | case TCC_OPTION_W: |
||
10547 | if (tcc_set_warning(s, optarg, 1) < 0 && |
||
10548 | s->warn_unsupported) |
||
10549 | goto unsupported_option; |
||
10550 | break; |
||
10551 | case TCC_OPTION_w: |
||
10552 | s->warn_none = 1; |
||
10553 | break; |
||
10554 | case TCC_OPTION_rdynamic: |
||
10555 | s->rdynamic = 1; |
||
10556 | break; |
||
10557 | case TCC_OPTION_Wl: |
||
10558 | { |
||
10559 | const char *p; |
||
10560 | if (strstart(optarg, "-Ttext,", &p)) { |
||
10561 | s->text_addr = strtoul(p, NULL, 16); |
||
10562 | s->has_text_addr = 1; |
||
10563 | } else if (strstart(optarg, "--oformat,", &p)) { |
||
10564 | if (strstart(p, "elf32-", NULL)) { |
||
10565 | s->output_format = TCC_OUTPUT_FORMAT_ELF; |
||
10566 | } else if (!strcmp(p, "binary")) { |
||
10567 | s->output_format = TCC_OUTPUT_FORMAT_BINARY; |
||
10568 | } else |
||
10569 | #ifdef TCC_TARGET_COFF |
||
10570 | if (!strcmp(p, "coff")) { |
||
10571 | s->output_format = TCC_OUTPUT_FORMAT_COFF; |
||
10572 | } else |
||
10573 | #endif |
||
10574 | { |
||
609 | andrew_pro | 10575 | printf("\n target %s not found", p); |
145 | halyavin | 10576 | } |
10577 | } else { |
||
609 | andrew_pro | 10578 | printf("\n unsupported linker option '%s'", optarg); |
145 | halyavin | 10579 | } |
10580 | } |
||
10581 | break; |
||
10582 | default: |
||
10583 | if (s->warn_unsupported) { |
||
10584 | unsupported_option: |
||
10585 | warning("unsupported option '%s'", r); |
||
609 | andrew_pro | 10586 | printf("\n unsupported option '%s'", r); |
145 | halyavin | 10587 | } |
10588 | break; |
||
10589 | } |
||
10590 | } |
||
10591 | } |
||
10592 | return optind; |
||
10593 | } |
||
10594 | |||
6410 | siemargl | 10595 | int main(int argc, char **argv) |
145 | halyavin | 10596 | { |
10597 | int i; |
||
10598 | TCCState *s; |
||
10599 | int nb_objfiles, ret, optind; |
||
10600 | char objfilename[1024]; |
||
10601 | int64_t start_time = 0; |
||
609 | andrew_pro | 10602 | int bug; |
145 | halyavin | 10603 | |
609 | andrew_pro | 10604 | printf("\nTinyC compiler started.\n "); |
145 | halyavin | 10605 | #ifdef WIN32 |
10606 | /* on win32, we suppose the lib and includes are at the location |
||
10607 | of 'tcc.exe' */ |
||
10608 | { |
||
10609 | static char path[1024]; |
||
10610 | char *p, *d; |
||
10611 | |||
10612 | GetModuleFileNameA(NULL, path, sizeof path); |
||
10613 | p = d = strlwr(path); |
||
10614 | while (*d) |
||
10615 | { |
||
10616 | if (*d == '\\') *d = '/', p = d; |
||
10617 | ++d; |
||
10618 | } |
||
10619 | *p = '\0'; |
||
10620 | tcc_lib_path = path; |
||
10621 | } |
||
10622 | #endif |
||
10623 | |||
10624 | s = tcc_new(); |
||
10625 | output_type = TCC_OUTPUT_EXE; |
||
10626 | outfile = NULL; |
||
10627 | multiple_files = 1; |
||
10628 | files = NULL; |
||
10629 | nb_files = 0; |
||
10630 | nb_libraries = 0; |
||
10631 | reloc_output = 0; |
||
10632 | print_search_dirs = 0; |
||
609 | andrew_pro | 10633 | printf("TinyC initializated.\n"); |
10634 | bug=argc; |
||
10635 | if (bug==0) {bug==1;} |
||
10636 | optind = parse_args(s, bug - 1, argv + 1) + 1; |
||
10637 | printf("\n Arguments parsed.\n"); |
||
145 | halyavin | 10638 | |
10639 | if (print_search_dirs) { |
||
10640 | /* enough for Linux kernel */ |
||
10641 | printf("install: %s/\n", tcc_lib_path); |
||
10642 | return 0; |
||
10643 | } |
||
10644 | |||
10645 | nb_objfiles = nb_files - nb_libraries; |
||
10646 | |||
10647 | /* if outfile provided without other options, we output an |
||
10648 | executable */ |
||
10649 | if (outfile && output_type == TCC_OUTPUT_MEMORY) |
||
10650 | output_type = TCC_OUTPUT_EXE; |
||
10651 | |||
609 | andrew_pro | 10652 | /* check -c |
10653 | consistency : only single file handled. XXX: checks file type */ |
||
145 | halyavin | 10654 | if (output_type == TCC_OUTPUT_OBJ && !reloc_output) { |
10655 | /* accepts only a single input file */ |
||
10656 | if (nb_objfiles != 1) |
||
609 | andrew_pro | 10657 | printf("\n cannot specify multiple files with -c"); |
145 | halyavin | 10658 | if (nb_libraries != 0) |
609 | andrew_pro | 10659 | printf("\n cannot specify libraries with -c"); |
145 | halyavin | 10660 | } |
10661 | |||
10662 | if (output_type != TCC_OUTPUT_MEMORY) { |
||
10663 | if (!outfile) { |
||
10664 | /* compute default outfile name */ |
||
10665 | pstrcpy(objfilename, sizeof(objfilename) - 1, |
||
10666 | /* strip path */ |
||
10667 | tcc_basename(files[0])); |
||
10668 | #ifdef TCC_TARGET_PE |
||
10669 | pe_guess_outfile(objfilename, output_type); |
||
10670 | #else |
||
10671 | if (output_type == TCC_OUTPUT_OBJ && !reloc_output) { |
||
10672 | char *ext = strrchr(objfilename, '.'); |
||
10673 | if (!ext) |
||
10674 | goto default_outfile; |
||
10675 | /* add .o extension */ |
||
10676 | strcpy(ext + 1, "o"); |
||
10677 | } else { |
||
10678 | default_outfile: |
||
10679 | pstrcpy(objfilename, sizeof(objfilename), "a.out"); |
||
10680 | } |
||
10681 | #endif |
||
10682 | outfile = objfilename; |
||
10683 | } |
||
10684 | } |
||
10685 | |||
10686 | if (do_bench) { |
||
10687 | start_time = getclock_us(); |
||
10688 | } |
||
10689 | |||
10690 | tcc_set_output_type(s, output_type); |
||
10691 | |||
10692 | /* compile or add each files or library */ |
||
10693 | for(i = 0;i < nb_files; i++) { |
||
10694 | const char *filename; |
||
10695 | |||
10696 | filename = files[i]; |
||
10697 | if (filename[0] == '-') { |
||
10698 | if (tcc_add_library(s, filename + 2) < 0) |
||
10699 | error("cannot find %s", filename); |
||
10700 | } else { |
||
10701 | if (tcc_add_file(s, filename) < 0) { |
||
10702 | ret = 1; |
||
10703 | goto the_end; |
||
10704 | } |
||
10705 | } |
||
10706 | } |
||
10707 | |||
10708 | /* free all files */ |
||
10709 | tcc_free(files); |
||
10710 | |||
10711 | if (do_bench) { |
||
10712 | double total_time; |
||
10713 | total_time = (double)(getclock_us() - start_time) / 1000000.0; |
||
10714 | if (total_time < 0.001) |
||
10715 | total_time = 0.001; |
||
10716 | if (total_bytes < 1) |
||
10717 | total_bytes = 1; |
||
10718 | printf("%d idents, %d lines, %d bytes, %0.3f s, %d lines/s, %0.1f MB/s\n", |
||
10719 | tok_ident - TOK_IDENT, total_lines, total_bytes, |
||
10720 | total_time, (int)(total_lines / total_time), |
||
10721 | total_bytes / total_time / 1000000.0); |
||
10722 | } |
||
10723 | |||
10724 | if (s->output_type == TCC_OUTPUT_MEMORY) { |
||
10725 | ret = tcc_run(s, argc - optind, argv + optind); |
||
10726 | } else |
||
10727 | #ifdef TCC_TARGET_PE |
||
10728 | if (s->output_type != TCC_OUTPUT_OBJ) { |
||
10729 | ret = tcc_output_pe(s, outfile); |
||
609 | andrew_pro | 10730 | } else |
10731 | #else |
||
10732 | #ifdef TCC_TARGET_MEOS |
||
145 | halyavin | 10733 | if (s->output_type != TCC_OUTPUT_OBJ) { |
10734 | ret = tcc_output_me(s, outfile); |
||
609 | andrew_pro | 10735 | } else |
145 | halyavin | 10736 | #endif |
609 | andrew_pro | 10737 | #endif |
145 | halyavin | 10738 | |
10739 | { |
||
10740 | tcc_output_file(s, outfile); |
||
10741 | ret = 0; |
||
10742 | } |
||
10743 | the_end: |
||
10744 | /* XXX: cannot do it with bound checking because of the malloc hooks */ |
||
10745 | if (!do_bounds_check) |
||
10746 | tcc_delete(s); |
||
10747 | |||
10748 | #ifdef MEM_DEBUG |
||
10749 | if (do_bench) { |
||
10750 | printf("memory: %d bytes, max = %d bytes\n", mem_cur_size, mem_max_size); |
||
10751 | } |
||
10752 | #endif |
||
609 | andrew_pro | 10753 | printf("\n TinyC finished work\n"); |
145 | halyavin | 10754 | return ret; |
10755 | } |
||
10756 | |||
10757 | #endif>>>>>>>> |