fixed switch - preparation for new types
[tinycc.git] / tcc.c
blob51447bb66ca4eeb11319796a113355d9678068d6
1 /*
2 * TCC - Tiny C Compiler
3 *
4 * Copyright (c) 2001 Fabrice Bellard
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include <string.h>
23 #ifndef CONFIG_TCC_STATIC
24 #include <dlfcn.h>
25 #endif
27 //#define DEBUG
28 /* preprocessor debug */
29 //#define PP_DEBUG
31 /* these sizes are dummy for unix, because malloc() does not use
32 memory when the pages are not used */
33 #define TEXT_SIZE (4*1024*1024)
34 #define DATA_SIZE (4*1024*1024)
36 #define INCLUDE_STACK_SIZE 32
37 #define IFDEF_STACK_SIZE 64
38 #define VSTACK_SIZE 64
39 #define STRING_MAX_SIZE 1024
40 #define INCLUDE_PATHS_MAX 32
42 #define TOK_HASH_SIZE 521
43 #define TOK_ALLOC_INCR 256 /* must be a power of two */
44 #define SYM_HASH_SIZE 263
46 /* number of available temporary registers */
47 #define NB_REGS 3
48 /* return register for functions */
49 #define FUNC_RET_REG 0
50 /* defined if function parameters must be evaluated in reverse order */
51 #define INVERT_FUNC_PARAMS
52 /* defined if structures are passed as pointers. Otherwise structures
53 are directly pushed on stack. */
54 //#define FUNC_STRUCT_PARAM_AS_PTR
56 /* token symbol management */
57 typedef struct TokenSym {
58 struct TokenSym *hash_next;
59 int tok; /* token number */
60 int len;
61 char str[1];
62 } TokenSym;
64 /* symbol management */
65 typedef struct Sym {
66 int v; /* symbol token */
67 int t; /* associated type */
68 int c; /* associated number */
69 struct Sym *next; /* next related symbol */
70 struct Sym *prev; /* prev symbol in stack */
71 struct Sym *hash_next; /* next symbol in hash table */
72 } Sym;
74 typedef struct SymStack {
75 struct Sym *top;
76 struct Sym *hash[SYM_HASH_SIZE];
77 } SymStack;
79 /* relocation entry (currently only used for functions or variables */
80 typedef struct Reloc {
81 int type; /* type of relocation */
82 int addr; /* address of relocation */
83 struct Reloc *next; /* next relocation */
84 } Reloc;
86 #define RELOC_ADDR32 1 /* 32 bits relocation */
87 #define RELOC_REL32 2 /* 32 bits relative relocation */
90 #define SYM_STRUCT 0x40000000 /* struct/union/enum symbol space */
91 #define SYM_FIELD 0x20000000 /* struct/union field symbol space */
92 #define SYM_FIRST_ANOM (1 << (31 - VT_STRUCT_SHIFT)) /* first anonymous sym */
94 #define FUNC_NEW 1 /* ansi function prototype */
95 #define FUNC_OLD 2 /* old function prototype */
96 #define FUNC_ELLIPSIS 3 /* ansi function prototype with ... */
98 /* field 'Sym.t' for macros */
99 #define MACRO_OBJ 0 /* object like macro */
100 #define MACRO_FUNC 1 /* function like macro */
102 /* type_decl() types */
103 #define TYPE_ABSTRACT 1 /* type without variable */
104 #define TYPE_DIRECT 2 /* type with variable */
106 typedef struct {
107 FILE *file;
108 char *filename;
109 int line_num;
110 } IncludeFile;
112 /* parser */
113 FILE *file;
114 int ch, ch1, tok, tokc, tok1, tok1c;
116 /* loc : local variable index
117 glo : global variable index
118 ind : output code ptr
119 rsym: return symbol
120 prog: output code
121 anon_sym: anonymous symbol index
123 int rsym, anon_sym,
124 prog, ind, loc, glo, vt, vc, const_wanted, line_num;
125 int global_expr; /* true if compound literals must be allocated
126 globally (used during initializers parsing */
127 int func_vt, func_vc; /* current function return type (used by
128 return instruction) */
129 int tok_ident;
130 TokenSym **table_ident;
131 TokenSym *hash_ident[TOK_HASH_SIZE];
132 char token_buf[STRING_MAX_SIZE + 1];
133 char *filename, *funcname;
134 /* contains global symbols which remain between each translation unit */
135 SymStack extern_stack;
136 SymStack define_stack, global_stack, local_stack, label_stack;
138 int vstack[VSTACK_SIZE], *vstack_ptr;
139 int *macro_ptr, *macro_ptr_allocated;
140 IncludeFile include_stack[INCLUDE_STACK_SIZE], *include_stack_ptr;
141 int ifdef_stack[IFDEF_STACK_SIZE], *ifdef_stack_ptr;
142 char *include_paths[INCLUDE_PATHS_MAX];
143 int nb_include_paths;
145 /* use GNU C extensions */
146 int gnu_ext = 1;
148 /* The current value can be: */
149 #define VT_VALMASK 0x000f
150 #define VT_CONST 0x000a /* constant in vc
151 (must be first non register value) */
152 #define VT_LLOCAL 0x000b /* lvalue, offset on stack */
153 #define VT_LOCAL 0x000c /* offset on stack */
154 #define VT_CMP 0x000d /* the value is stored in processor flags (in vc) */
155 #define VT_JMP 0x000e /* value is the consequence of jmp true */
156 #define VT_JMPI 0x000f /* value is the consequence of jmp false */
157 #define VT_LVAL 0x0010 /* var is an lvalue */
158 #define VT_LVALN -17 /* ~VT_LVAL */
159 #define VT_FORWARD 0x0020 /* value is forward reference
160 (only used for functions) */
161 /* storage */
162 #define VT_EXTERN 0x00000040 /* extern definition */
163 #define VT_STATIC 0x00000080 /* static variable */
164 #define VT_TYPEDEF 0x00000100 /* typedef definition */
166 /* types */
167 #define VT_STRUCT_SHIFT 15 /* structure/enum name shift (14 bits left) */
169 #define VT_BTYPE_SHIFT 9
170 #define VT_INT (0 << VT_BTYPE_SHIFT) /* integer type */
171 #define VT_BYTE (1 << VT_BTYPE_SHIFT) /* signed byte type */
172 #define VT_SHORT (2 << VT_BTYPE_SHIFT) /* short type */
173 #define VT_VOID (3 << VT_BTYPE_SHIFT) /* void type */
174 #define VT_PTR (4 << VT_BTYPE_SHIFT) /* pointer increment */
175 #define VT_ENUM (5 << VT_BTYPE_SHIFT) /* enum definition */
176 #define VT_FUNC (6 << VT_BTYPE_SHIFT) /* function type */
177 #define VT_STRUCT (7 << VT_BTYPE_SHIFT) /* struct/union definition */
178 #define VT_BTYPE (0xf << VT_BTYPE_SHIFT) /* mask for basic type */
179 #define VT_UNSIGNED (0x10 << VT_BTYPE_SHIFT) /* unsigned type */
180 #define VT_ARRAY (0x20 << VT_BTYPE_SHIFT) /* array type (also has VT_PTR) */
182 #define VT_TYPE 0xfffffe00 /* type mask */
184 /* token values */
186 /* warning: the following compare tokens depend on i386 asm code */
187 #define TOK_ULT 0x92
188 #define TOK_UGE 0x93
189 #define TOK_EQ 0x94
190 #define TOK_NE 0x95
191 #define TOK_ULE 0x96
192 #define TOK_UGT 0x97
193 #define TOK_LT 0x9c
194 #define TOK_GE 0x9d
195 #define TOK_LE 0x9e
196 #define TOK_GT 0x9f
198 #define TOK_LAND 0xa0
199 #define TOK_LOR 0xa1
201 #define TOK_DEC 0xa2
202 #define TOK_MID 0xa3 /* inc/dec, to void constant */
203 #define TOK_INC 0xa4
204 #define TOK_ARROW 0xa7
205 #define TOK_DOTS 0xa8 /* three dots */
206 #define TOK_SHR 0xa9 /* unsigned shift right */
207 #define TOK_UDIV 0xb0 /* unsigned division */
208 #define TOK_UMOD 0xb1 /* unsigned modulo */
209 #define TOK_PDIV 0xb2 /* fast division with undefined rounding for pointers */
210 #define TOK_NUM 0xb3 /* number in tokc */
211 #define TOK_CCHAR 0xb4 /* char constant in tokc */
212 #define TOK_STR 0xb5 /* pointer to string in tokc */
213 #define TOK_TWOSHARPS 0xb6 /* ## preprocessing token */
214 #define TOK_LCHAR 0xb7
215 #define TOK_LSTR 0xb8
217 #define TOK_SHL 0x01 /* shift left */
218 #define TOK_SAR 0x02 /* signed shift right */
220 /* assignement operators : normal operator or 0x80 */
221 #define TOK_A_MOD 0xa5
222 #define TOK_A_AND 0xa6
223 #define TOK_A_MUL 0xaa
224 #define TOK_A_ADD 0xab
225 #define TOK_A_SUB 0xad
226 #define TOK_A_DIV 0xaf
227 #define TOK_A_XOR 0xde
228 #define TOK_A_OR 0xfc
229 #define TOK_A_SHL 0x81
230 #define TOK_A_SAR 0x82
232 /* all identificators and strings have token above that */
233 #define TOK_IDENT 256
235 enum {
236 TOK_INT = TOK_IDENT,
237 TOK_VOID,
238 TOK_CHAR,
239 TOK_IF,
240 TOK_ELSE,
241 TOK_WHILE,
242 TOK_BREAK,
243 TOK_RETURN,
244 TOK_FOR,
245 TOK_EXTERN,
246 TOK_STATIC,
247 TOK_UNSIGNED,
248 TOK_GOTO,
249 TOK_DO,
250 TOK_CONTINUE,
251 TOK_SWITCH,
252 TOK_CASE,
254 /* ignored types Must have contiguous values */
255 TOK_CONST,
256 TOK_VOLATILE,
257 TOK_LONG,
258 TOK_REGISTER,
259 TOK_SIGNED,
260 TOK_AUTO,
261 TOK_INLINE,
262 TOK_RESTRICT,
264 /* unsupported type */
265 TOK_FLOAT,
266 TOK_DOUBLE,
268 TOK_SHORT,
269 TOK_STRUCT,
270 TOK_UNION,
271 TOK_TYPEDEF,
272 TOK_DEFAULT,
273 TOK_ENUM,
274 TOK_SIZEOF,
276 /* preprocessor only */
277 TOK_UIDENT, /* first "user" ident (not keyword) */
278 TOK_DEFINE = TOK_UIDENT,
279 TOK_INCLUDE,
280 TOK_IFDEF,
281 TOK_IFNDEF,
282 TOK_ELIF,
283 TOK_ENDIF,
284 TOK_DEFINED,
285 TOK_UNDEF,
286 TOK_ERROR,
287 TOK_LINE,
288 TOK___LINE__,
289 TOK___FILE__,
290 TOK___DATE__,
291 TOK___TIME__,
292 TOK___VA_ARGS__,
294 /* special identifiers */
295 TOK___FUNC__,
296 TOK_MAIN,
299 void sum();
300 void next(void);
301 void next_nomacro();
302 int expr_const();
303 void expr_eq();
304 void expr(void);
305 void decl(int l);
306 void decl_initializer(int t, int c, int first, int size_only);
307 int decl_initializer_alloc(int t, int has_init);
308 int gv(void);
309 void move_reg();
310 void save_reg();
311 void vpush(void);
312 int get_reg(void);
313 void macro_subst(int **tok_str, int *tok_len,
314 Sym **nested_list, int *macro_str);
315 int save_reg_forced(int r);
316 void vstore(void);
317 int type_size(int t, int *a);
318 int pointed_type(int t);
319 int pointed_size(int t);
320 int ist(void);
321 int type_decl(int *v, int t, int td);
323 #ifdef CONFIG_TCC_STATIC
325 #define RTLD_LAZY 0x001
326 #define RTLD_NOW 0x002
327 #define RTLD_GLOBAL 0x100
329 /* dummy function for profiling */
330 void *dlopen(const char *filename, int flag)
332 return NULL;
335 const char *dlerror(void)
337 return "error";
340 typedef struct TCCSyms {
341 char *str;
342 void *ptr;
343 } TCCSyms;
345 #define TCCSYM(a) { #a, &a, },
347 /* add the symbol you want here if no dynamic linking is done */
348 static TCCSyms tcc_syms[] = {
349 TCCSYM(printf)
350 TCCSYM(fprintf)
351 TCCSYM(fopen)
352 TCCSYM(fclose)
353 { NULL, NULL },
356 void *dlsym(void *handle, char *symbol)
358 TCCSyms *p;
359 p = tcc_syms;
360 while (p->str != NULL) {
361 if (!strcmp(p->str, symbol))
362 return p->ptr;
363 p++;
365 return NULL;
368 #endif
370 inline int isid(int c)
372 return (c >= 'a' && c <= 'z') ||
373 (c >= 'A' && c <= 'Z') ||
374 c == '_';
377 inline int isnum(int c)
379 return c >= '0' & c <= '9';
382 void printline(void)
384 IncludeFile *f;
385 for(f = include_stack; f < include_stack_ptr; f++)
386 fprintf(stderr, "In file included from %s:%d:\n",
387 f->filename, f->line_num);
388 fprintf(stderr, "%s:%d: ", filename, line_num);
391 void error(const char *fmt, ...)
393 va_list ap;
394 va_start(ap, fmt);
395 printline();
396 vfprintf(stderr, fmt, ap);
397 fprintf(stderr, "\n");
398 exit(1);
399 va_end(ap);
402 void expect(const char *msg)
404 error("%s expected", msg);
407 void warning(const char *msg)
409 printline();
410 fprintf(stderr, "warning: %s\n", msg);
413 void skip(int c)
415 if (tok != c)
416 error("'%c' expected", c);
417 next();
420 void test_lvalue(void)
422 if (!(vt & VT_LVAL))
423 expect("lvalue");
426 TokenSym *tok_alloc(char *str, int len)
428 TokenSym *ts, **pts, **ptable;
429 int h, i;
431 if (len <= 0)
432 len = strlen(str);
433 h = 1;
434 for(i=0;i<len;i++)
435 h = ((h << 8) | (str[i] & 0xff)) % TOK_HASH_SIZE;
437 pts = &hash_ident[h];
438 while (1) {
439 ts = *pts;
440 if (!ts)
441 break;
442 if (ts->len == len && !memcmp(ts->str, str, len))
443 return ts;
444 pts = &(ts->hash_next);
447 if (tok_ident >= SYM_FIRST_ANOM)
448 error("memory full");
450 /* expand token table if needed */
451 i = tok_ident - TOK_IDENT;
452 if ((i % TOK_ALLOC_INCR) == 0) {
453 ptable = realloc(table_ident, (i + TOK_ALLOC_INCR) * sizeof(TokenSym *));
454 if (!ptable)
455 error("memory full");
456 table_ident = ptable;
459 ts = malloc(sizeof(TokenSym) + len);
460 if (!ts)
461 error("memory full");
462 table_ident[i] = ts;
463 ts->tok = tok_ident++;
464 ts->len = len;
465 ts->hash_next = NULL;
466 memcpy(ts->str, str, len + 1);
467 *pts = ts;
468 return ts;
471 void add_char(char **pp, int c)
473 char *p;
474 p = *pp;
475 if (c == '\'' || c == '\"' || c == '\\') {
476 /* XXX: could be more precise if char or string */
477 *p++ = '\\';
479 if (c >= 32 && c <= 126) {
480 *p++ = c;
481 } else {
482 *p++ = '\\';
483 if (c == '\n') {
484 *p++ = 'n';
485 } else {
486 *p++ = '0' + ((c >> 6) & 7);
487 *p++ = '0' + ((c >> 3) & 7);
488 *p++ = '0' + (c & 7);
491 *pp = p;
494 /* XXX: buffer overflow */
495 char *get_tok_str(int v, int c)
497 static char buf[STRING_MAX_SIZE + 1];
498 TokenSym *ts;
499 char *p;
500 int i;
502 if (v == TOK_NUM) {
503 sprintf(buf, "%d", c);
504 return buf;
505 } else if (v == TOK_CCHAR || v == TOK_LCHAR) {
506 p = buf;
507 *p++ = '\'';
508 add_char(&p, c);
509 *p++ = '\'';
510 *p = '\0';
511 return buf;
512 } else if (v == TOK_STR || v == TOK_LSTR) {
513 ts = (TokenSym *)c;
514 p = buf;
515 *p++ = '\"';
516 for(i=0;i<ts->len;i++)
517 add_char(&p, ts->str[i]);
518 *p++ = '\"';
519 *p = '\0';
520 return buf;
521 } else if (v < TOK_IDENT) {
522 p = buf;
523 *p++ = v;
524 *p = '\0';
525 return buf;
526 } else if (v < tok_ident) {
527 return table_ident[v - TOK_IDENT]->str;
528 } else {
529 /* should never happen */
530 return NULL;
534 /* push, without hashing */
535 Sym *sym_push2(Sym **ps, int v, int t, int c)
537 Sym *s;
538 s = malloc(sizeof(Sym));
539 if (!s)
540 error("memory full");
541 s->v = v;
542 s->t = t;
543 s->c = c;
544 s->next = NULL;
545 /* add in stack */
546 s->prev = *ps;
547 *ps = s;
548 return s;
551 /* find a symbol and return its associated structure. 's' is the top
552 of the symbol stack */
553 Sym *sym_find2(Sym *s, int v)
555 while (s) {
556 if (s->v == v)
557 return s;
558 s = s->prev;
560 return NULL;
563 /* find a symbol and return its associated structure. 'st' is the
564 symbol stack */
565 Sym *sym_find1(SymStack *st, int v)
567 Sym *s;
569 s = st->hash[v % SYM_HASH_SIZE];
570 while (s) {
571 if (s->v == v)
572 return s;
573 s = s->hash_next;
575 return 0;
578 Sym *sym_push1(SymStack *st, int v, int t, int c)
580 Sym *s, **ps;
581 s = sym_push2(&st->top, v, t, c);
582 /* add in hash table */
583 ps = &st->hash[s->v % SYM_HASH_SIZE];
584 s->hash_next = *ps;
585 *ps = s;
586 return s;
589 /* find a symbol in the right symbol space */
590 Sym *sym_find(int v)
592 Sym *s;
593 s = sym_find1(&local_stack, v);
594 if (!s)
595 s = sym_find1(&global_stack, v);
596 return s;
599 /* push a given symbol on the symbol stack */
600 Sym *sym_push(int v, int t, int c)
602 if (local_stack.top)
603 return sym_push1(&local_stack, v, t, c);
604 else
605 return sym_push1(&global_stack, v, t, c);
608 /* pop symbols until top reaches 'b' */
609 void sym_pop(SymStack *st, Sym *b)
611 Sym *s, *ss;
613 s = st->top;
614 while(s != b) {
615 ss = s->prev;
616 /* free hash table entry */
617 st->hash[s->v % SYM_HASH_SIZE] = s->hash_next;
618 free(s);
619 s = ss;
621 st->top = b;
624 /* undefined a hashed symbol (used for #undef). Its name is set to
625 zero */
626 void sym_undef(SymStack *st, Sym *s)
628 Sym **ss;
629 ss = &st->hash[s->v % SYM_HASH_SIZE];
630 while (*ss != NULL) {
631 if (*ss == s)
632 break;
633 ss = &(*ss)->hash_next;
635 *ss = s->hash_next;
636 s->v = 0;
639 /* no need to put that inline */
640 int handle_eof(void)
642 if (include_stack_ptr == include_stack)
643 return -1;
644 /* pop include stack */
645 fclose(file);
646 free(filename);
647 include_stack_ptr--;
648 file = include_stack_ptr->file;
649 filename = include_stack_ptr->filename;
650 line_num = include_stack_ptr->line_num;
651 return 0;
654 /* read next char from current input file */
655 static inline void inp(void)
657 redo:
658 /* faster than fgetc */
659 ch1 = getc_unlocked(file);
660 if (ch1 == -1) {
661 if (handle_eof() < 0)
662 return;
663 else
664 goto redo;
666 if (ch1 == '\n')
667 line_num++;
668 // printf("ch1=%c 0x%x\n", ch1, ch1);
671 /* input with '\\n' handling */
672 static inline void minp(void)
674 redo:
675 ch = ch1;
676 inp();
677 if (ch == '\\' && ch1 == '\n') {
678 inp();
679 goto redo;
681 //printf("ch=%c 0x%x\n", ch, ch);
685 /* same as minp, but also skip comments */
686 void cinp(void)
688 int c;
690 if (ch1 == '/') {
691 inp();
692 if (ch1 == '/') {
693 /* single line C++ comments */
694 inp();
695 while (ch1 != '\n' && ch1 != -1)
696 inp();
697 inp();
698 ch = ' '; /* return space */
699 } else if (ch1 == '*') {
700 /* C comments */
701 inp();
702 while (ch1 != -1) {
703 c = ch1;
704 inp();
705 if (c == '*' && ch1 == '/') {
706 inp();
707 ch = ' '; /* return space */
708 break;
711 } else {
712 ch = '/';
714 } else {
715 minp();
719 void skip_spaces(void)
721 while (ch == ' ' || ch == '\t')
722 cinp();
725 /* skip block of text until #else, #elif or #endif. skip also pairs of
726 #if/#endif */
727 void preprocess_skip()
729 int a;
730 a = 0;
731 while (1) {
732 while (ch != '\n') {
733 if (ch == -1)
734 expect("#endif");
735 cinp();
737 cinp();
738 skip_spaces();
739 if (ch == '#') {
740 cinp();
741 next_nomacro();
742 if (a == 0 &&
743 (tok == TOK_ELSE || tok == TOK_ELIF || tok == TOK_ENDIF))
744 break;
745 if (tok == TOK_IF || tok == TOK_IFDEF || tok == TOK_IFNDEF)
746 a++;
747 else if (tok == TOK_ENDIF)
748 a--;
753 inline int is_long_tok(int t)
755 return (t == TOK_NUM ||
756 t == TOK_CCHAR || t == TOK_LCHAR ||
757 t == TOK_STR || t == TOK_LSTR);
760 void tok_add(int **tok_str, int *tok_len, int t)
762 int len, *str;
763 len = *tok_len;
764 str = *tok_str;
765 if ((len & 63) == 0) {
766 str = realloc(str, (len + 64) * sizeof(int));
767 if (!str)
768 return;
769 *tok_str = str;
771 str[len++] = t;
772 *tok_len = len;
775 void tok_add2(int **tok_str, int *tok_len, int t, int c)
777 tok_add(tok_str, tok_len, t);
778 if (is_long_tok(t))
779 tok_add(tok_str, tok_len, c);
782 /* eval an expression for #if/#elif */
783 int expr_preprocess()
785 int *str, len, c, t;
787 str = NULL;
788 len = 0;
789 while (1) {
790 skip_spaces();
791 if (ch == '\n')
792 break;
793 next(); /* do macro subst */
794 if (tok == TOK_DEFINED) {
795 next_nomacro();
796 t = tok;
797 if (t == '(')
798 next_nomacro();
799 c = sym_find1(&define_stack, tok) != 0;
800 if (t == '(')
801 next_nomacro();
802 tok = TOK_NUM;
803 tokc = c;
804 } else if (tok >= TOK_IDENT) {
805 /* if undefined macro */
806 tok = TOK_NUM;
807 tokc = 0;
809 tok_add2(&str, &len, tok, tokc);
811 tok_add(&str, &len, -1); /* simulate end of file */
812 tok_add(&str, &len, 0);
813 /* now evaluate C constant expression */
814 macro_ptr = str;
815 next();
816 c = expr_const();
817 macro_ptr = NULL;
818 free(str);
819 return c != 0;
822 #ifdef DEBUG
823 void tok_print(int *str)
825 int t, c;
827 while (1) {
828 t = *str++;
829 if (!t)
830 break;
831 c = 0;
832 if (is_long_tok(t))
833 c = *str++;
834 printf(" %s", get_tok_str(t, c));
836 printf("\n");
838 #endif
840 /* XXX: should be more factorized */
841 void define_symbol(char *sym)
843 TokenSym *ts;
844 int *str, len;
846 ts = tok_alloc(sym, 0);
847 str = NULL;
848 len = 0;
849 tok_add2(&str, &len, TOK_NUM, 1);
850 tok_add(&str, &len, 0);
851 sym_push1(&define_stack, ts->tok, MACRO_OBJ, (int)str);
854 void preprocess()
856 int size, i, c, v, t, *str, len;
857 char buf[1024], *q, *p;
858 char buf1[1024];
859 FILE *f;
860 Sym **ps, *first, *s;
862 cinp();
863 next_nomacro();
864 redo:
865 if (tok == TOK_DEFINE) {
866 next_nomacro();
867 v = tok;
868 /* XXX: should check if same macro (ANSI) */
869 first = NULL;
870 t = MACRO_OBJ;
871 /* '(' must be just after macro definition for MACRO_FUNC */
872 if (ch == '(') {
873 next_nomacro();
874 next_nomacro();
875 ps = &first;
876 while (tok != ')') {
877 if (tok == TOK_DOTS)
878 tok = TOK___VA_ARGS__;
879 s = sym_push1(&define_stack, tok | SYM_FIELD, 0, 0);
880 *ps = s;
881 ps = &s->next;
882 next_nomacro();
883 if (tok != ',')
884 break;
885 next_nomacro();
887 t = MACRO_FUNC;
889 str = NULL;
890 len = 0;
891 while (1) {
892 skip_spaces();
893 if (ch == '\n' || ch == -1)
894 break;
895 next_nomacro();
896 tok_add2(&str, &len, tok, tokc);
898 tok_add(&str, &len, 0);
899 #ifdef PP_DEBUG
900 printf("define %s %d: ", get_tok_str(v, 0), t);
901 tok_print(str);
902 #endif
903 s = sym_push1(&define_stack, v, t, (int)str);
904 s->next = first;
905 } else if (tok == TOK_UNDEF) {
906 next_nomacro();
907 s = sym_find1(&define_stack, tok);
908 /* undefine symbol by putting an invalid name */
909 if (s)
910 sym_undef(&define_stack, s);
911 } else if (tok == TOK_INCLUDE) {
912 skip_spaces();
913 if (ch == '<') {
914 c = '>';
915 goto read_name;
916 } else if (ch == '\"') {
917 c = ch;
918 read_name:
919 minp();
920 q = buf;
921 while (ch != c && ch != '\n' && ch != -1) {
922 if ((q - buf) < sizeof(buf) - 1)
923 *q++ = ch;
924 minp();
926 *q = '\0';
927 } else {
928 next();
929 if (tok != TOK_STR)
930 error("#include syntax error");
931 /* XXX: buffer overflow */
932 strcpy(buf, get_tok_str(tok, tokc));
933 c = '\"';
935 if (include_stack_ptr >= include_stack + INCLUDE_STACK_SIZE)
936 error("memory full");
937 if (c == '\"') {
938 /* first search in current dir if "header.h" */
939 /* XXX: buffer overflow */
940 size = 0;
941 p = strrchr(filename, '/');
942 if (p)
943 size = p + 1 - filename;
944 memcpy(buf1, filename, size);
945 buf1[size] = '\0';
946 strcat(buf1, buf);
947 f = fopen(buf1, "r");
948 if (f)
949 goto found;
951 /* now search in standard include path */
952 for(i=nb_include_paths - 1;i>=0;i--) {
953 strcpy(buf1, include_paths[i]);
954 strcat(buf1, "/");
955 strcat(buf1, buf);
956 f = fopen(buf1, "r");
957 if (f)
958 goto found;
960 error("include file '%s' not found", buf1);
961 f = NULL;
962 found:
963 /* push current file in stack */
964 /* XXX: fix current line init */
965 include_stack_ptr->file = file;
966 include_stack_ptr->filename = filename;
967 include_stack_ptr->line_num = line_num;
968 include_stack_ptr++;
969 file = f;
970 filename = strdup(buf1);
971 line_num = 1;
972 } else if (tok == TOK_IFNDEF) {
973 c = 1;
974 goto do_ifdef;
975 } else if (tok == TOK_IF) {
976 c = expr_preprocess();
977 goto do_if;
978 } else if (tok == TOK_IFDEF) {
979 c = 0;
980 do_ifdef:
981 next_nomacro();
982 c = (sym_find1(&define_stack, tok) != 0) ^ c;
983 do_if:
984 if (ifdef_stack_ptr >= ifdef_stack + IFDEF_STACK_SIZE)
985 error("memory full");
986 *ifdef_stack_ptr++ = c;
987 goto test_skip;
988 } else if (tok == TOK_ELSE) {
989 if (ifdef_stack_ptr == ifdef_stack ||
990 (ifdef_stack_ptr[-1] & 2))
991 error("#else after #else");
992 c = (ifdef_stack_ptr[-1] ^= 3);
993 goto test_skip;
994 } else if (tok == TOK_ELIF) {
995 if (ifdef_stack_ptr == ifdef_stack ||
996 ifdef_stack_ptr[-1] > 1)
997 error("#elif after #else");
998 c = expr_preprocess();
999 ifdef_stack_ptr[-1] = c;
1000 test_skip:
1001 if (!(c & 1)) {
1002 preprocess_skip();
1003 goto redo;
1005 } else if (tok == TOK_ENDIF) {
1006 if (ifdef_stack_ptr == ifdef_stack)
1007 expect("#if");
1008 ifdef_stack_ptr--;
1009 } else if (tok == TOK_LINE) {
1010 next();
1011 if (tok != TOK_NUM)
1012 error("#line");
1013 line_num = tokc;
1014 skip_spaces();
1015 if (ch != '\n') {
1016 next();
1017 if (tok != TOK_STR)
1018 error("#line");
1019 /* XXX: potential memory leak */
1020 filename = strdup(get_tok_str(tok, tokc));
1022 } else if (tok == TOK_ERROR) {
1023 error("#error");
1025 /* ignore other preprocess commands or #! for C scripts */
1026 while (ch != '\n' && ch != -1)
1027 cinp();
1030 /* read a number in base b */
1031 int getn(b)
1033 int n, t;
1034 n = 0;
1035 while (1) {
1036 if (ch >= 'a' & ch <= 'f')
1037 t = ch - 'a' + 10;
1038 else if (ch >= 'A' & ch <= 'F')
1039 t = ch - 'A' + 10;
1040 else if (isnum(ch))
1041 t = ch - '0';
1042 else
1043 break;
1044 if (t < 0 | t >= b)
1045 break;
1046 n = n * b + t;
1047 cinp();
1049 return n;
1052 /* read a character for string or char constant and eval escape codes */
1053 int getq()
1055 int c;
1057 c = ch;
1058 minp();
1059 if (c == '\\') {
1060 if (isnum(ch)) {
1061 /* at most three octal digits */
1062 c = ch - '0';
1063 minp();
1064 if (isnum(ch)) {
1065 c = c * 8 + ch - '0';
1066 minp();
1067 if (isnum(ch)) {
1068 c = c * 8 + ch - '0';
1069 minp();
1072 return c;
1073 } else if (ch == 'x') {
1074 minp();
1075 return getn(16);
1076 } else {
1077 if (ch == 'a')
1078 c = '\a';
1079 else if (ch == 'b')
1080 c = '\b';
1081 else if (ch == 'f')
1082 c = '\f';
1083 else if (ch == 'n')
1084 c = '\n';
1085 else if (ch == 'r')
1086 c = '\r';
1087 else if (ch == 't')
1088 c = '\t';
1089 else if (ch == 'v')
1090 c = '\v';
1091 else
1092 c = ch;
1093 minp();
1096 return c;
1099 /* return next token without macro substitution */
1100 void next_nomacro1()
1102 int b;
1103 char *q;
1104 TokenSym *ts;
1106 /* skip spaces */
1107 while(1) {
1108 while (ch == '\n') {
1109 cinp();
1110 while (ch == ' ' || ch == 9)
1111 cinp();
1112 if (ch == '#') {
1113 /* preprocessor command if # at start of line after
1114 spaces */
1115 preprocess();
1118 if (ch != ' ' && ch != '\t' && ch != '\f')
1119 break;
1120 cinp();
1122 if (isid(ch)) {
1123 q = token_buf;
1124 *q++ = ch;
1125 cinp();
1126 if (q[-1] == 'L') {
1127 if (ch == '\'') {
1128 tok = TOK_LCHAR;
1129 goto char_const;
1131 if (ch == '\"') {
1132 tok = TOK_LSTR;
1133 goto str_const;
1136 while (isid(ch) | isnum(ch)) {
1137 if (q >= token_buf + STRING_MAX_SIZE)
1138 error("ident too long");
1139 *q++ = ch;
1140 cinp();
1142 *q = '\0';
1143 ts = tok_alloc(token_buf, q - token_buf);
1144 tok = ts->tok;
1145 } else if (isnum(ch)) {
1146 /* number */
1147 b = 10;
1148 if (ch == '0') {
1149 cinp();
1150 b = 8;
1151 if (ch == 'x' || ch == 'X') {
1152 cinp();
1153 b = 16;
1154 } else if (ch == 'b' || ch == 'B') {
1155 cinp();
1156 b = 2;
1159 tokc = getn(b);
1160 /* XXX: add unsigned constant support (ANSI) */
1161 while (ch == 'L' || ch == 'l' || ch == 'U' || ch == 'u')
1162 cinp();
1163 tok = TOK_NUM;
1164 } else if (ch == '\'') {
1165 tok = TOK_CCHAR;
1166 char_const:
1167 minp();
1168 tokc = getq();
1169 if (ch != '\'')
1170 expect("\'");
1171 minp();
1172 } else if (ch == '\"') {
1173 tok = TOK_STR;
1174 str_const:
1175 minp();
1176 q = token_buf;
1177 while (ch != '\"') {
1178 b = getq();
1179 if (ch == -1)
1180 error("unterminated string");
1181 if (q >= token_buf + STRING_MAX_SIZE)
1182 error("string too long");
1183 *q++ = b;
1185 *q = '\0';
1186 tokc = (int)tok_alloc(token_buf, q - token_buf);
1187 minp();
1188 } else {
1189 q = "<=\236>=\235!=\225&&\240||\241++\244--\242==\224<<\1>>\2+=\253-=\255*=\252/=\257%=\245&=\246^=\336|=\374->\247..\250##\266";
1190 /* two chars */
1191 tok = ch;
1192 cinp();
1193 while (*q) {
1194 if (*q == tok & q[1] == ch) {
1195 cinp();
1196 tok = q[2] & 0xff;
1197 /* three chars tests */
1198 if (tok == TOK_SHL | tok == TOK_SAR) {
1199 if (ch == '=') {
1200 tok = tok | 0x80;
1201 cinp();
1203 } else if (tok == TOK_DOTS) {
1204 if (ch != '.')
1205 error("parse error");
1206 cinp();
1208 return;
1210 q = q + 3;
1212 /* single char substitutions */
1213 if (tok == '<')
1214 tok = TOK_LT;
1215 else if (tok == '>')
1216 tok = TOK_GT;
1220 /* return next token without macro substitution. Can read input from
1221 macro_ptr buffer */
1222 void next_nomacro()
1224 if (macro_ptr) {
1225 tok = *macro_ptr;
1226 if (tok) {
1227 macro_ptr++;
1228 if (is_long_tok(tok))
1229 tokc = *macro_ptr++;
1231 } else {
1232 next_nomacro1();
1236 /* substitute args in macro_str and return allocated string */
1237 int *macro_arg_subst(Sym **nested_list, int *macro_str, Sym *args)
1239 int *st, last_tok, t, c, notfirst, *str, len;
1240 Sym *s;
1241 TokenSym *ts;
1243 str = NULL;
1244 len = 0;
1245 last_tok = 0;
1246 while(1) {
1247 t = *macro_str++;
1248 if (!t)
1249 break;
1250 if (t == '#') {
1251 /* stringize */
1252 t = *macro_str++;
1253 if (!t)
1254 break;
1255 s = sym_find2(args, t);
1256 if (s) {
1257 token_buf[0] = '\0';
1258 st = (int *)s->c;
1259 /* XXX: buffer overflow */
1260 notfirst = 0;
1261 while (*st) {
1262 if (notfirst)
1263 strcat(token_buf, " ");
1264 t = *st++;
1265 c = 0;
1266 if (is_long_tok(t))
1267 c = *st++;
1268 strcat(token_buf, get_tok_str(t, c));
1269 notfirst = 1;
1271 #ifdef PP_DEBUG
1272 printf("stringize: %s\n", token_buf);
1273 #endif
1274 /* add string */
1275 ts = tok_alloc(token_buf, 0);
1276 tok_add2(&str, &len, TOK_STR, (int)ts);
1277 } else {
1278 tok_add(&str, &len, t);
1280 } else if (is_long_tok(t)) {
1281 tok_add2(&str, &len, t, *macro_str++);
1282 } else {
1283 s = sym_find2(args, t);
1284 if (s) {
1285 st = (int *)s->c;
1286 /* if '##' is present before or after , no arg substitution */
1287 if (*macro_str == TOK_TWOSHARPS || last_tok == TOK_TWOSHARPS) {
1288 while (*st)
1289 tok_add(&str, &len, *st++);
1290 } else {
1291 macro_subst(&str, &len, nested_list, st);
1293 } else {
1294 tok_add(&str, &len, t);
1297 last_tok = t;
1299 tok_add(&str, &len, 0);
1300 return str;
1303 /* handle the '##' operator */
1304 int *macro_twosharps(int *macro_str)
1306 TokenSym *ts;
1307 int *macro_str1, macro_str1_len, *macro_ptr1;
1308 int t, c;
1309 char *p;
1311 macro_str1 = NULL;
1312 macro_str1_len = 0;
1313 tok = 0;
1314 while (1) {
1315 next_nomacro();
1316 if (tok == 0)
1317 break;
1318 if (*macro_ptr == TOK_TWOSHARPS) {
1319 macro_ptr++;
1320 macro_ptr1 = macro_ptr;
1321 t = *macro_ptr;
1322 if (t) {
1323 macro_ptr++;
1324 c = 0;
1325 if (is_long_tok(t))
1326 c = *macro_ptr++;
1327 /* XXX: we handle only most common cases:
1328 ident + ident or ident + number */
1329 if (tok >= TOK_IDENT &&
1330 (t >= TOK_IDENT || t == TOK_NUM)) {
1331 /* XXX: buffer overflow */
1332 p = get_tok_str(tok, tokc);
1333 strcpy(token_buf, p);
1334 p = get_tok_str(t, c);
1335 strcat(token_buf, p);
1336 ts = tok_alloc(token_buf, 0);
1337 tok_add2(&macro_str1, &macro_str1_len, ts->tok, 0);
1338 } else {
1339 /* cannot merge tokens: skip '##' */
1340 macro_ptr = macro_ptr1;
1343 } else {
1344 tok_add2(&macro_str1, &macro_str1_len, tok, tokc);
1347 tok_add(&macro_str1, &macro_str1_len, 0);
1348 return macro_str1;
1353 /* do macro substitution of macro_str and add result to
1354 (tok_str,tok_len). If macro_str is NULL, then input stream token is
1355 substituted. 'nested_list' is the list of all macros we got inside
1356 to avoid recursing. */
1357 void macro_subst(int **tok_str, int *tok_len,
1358 Sym **nested_list, int *macro_str)
1360 Sym *s, *args, *sa, *sa1;
1361 int *str, parlevel, len, *mstr, t, *saved_macro_ptr;
1362 int mstr_allocated, *macro_str1;
1364 saved_macro_ptr = macro_ptr;
1365 macro_ptr = macro_str;
1366 macro_str1 = NULL;
1367 if (macro_str) {
1368 /* first scan for '##' operator handling */
1369 macro_str1 = macro_twosharps(macro_str);
1370 macro_ptr = macro_str1;
1373 while (1) {
1374 next_nomacro();
1375 if (tok == 0)
1376 break;
1377 /* special macros */
1378 if (tok == TOK___LINE__) {
1379 tok_add2(tok_str, tok_len, TOK_NUM, line_num);
1380 } else if (tok == TOK___FILE__) {
1381 tok_add2(tok_str, tok_len, TOK_STR,
1382 (int)tok_alloc(filename, 0));
1383 } else if (tok == TOK___DATE__) {
1384 tok_add2(tok_str, tok_len, TOK_STR,
1385 (int)tok_alloc("Jan 1 1970", 0));
1386 } else if (tok == TOK___TIME__) {
1387 tok_add2(tok_str, tok_len, TOK_STR,
1388 (int)tok_alloc("00:00:00", 0));
1389 } else if ((s = sym_find1(&define_stack, tok)) != NULL) {
1390 /* if symbol is a macro, prepare substitution */
1391 /* if nested substitution, do nothing */
1392 if (sym_find2(*nested_list, tok))
1393 goto no_subst;
1394 mstr = (int *)s->c;
1395 mstr_allocated = 0;
1396 if (s->t == MACRO_FUNC) {
1397 /* NOTE: we do not use next_nomacro to avoid eating the
1398 next token. XXX: find better solution */
1399 if (macro_ptr) {
1400 t = *macro_ptr;
1401 } else {
1402 while (ch == ' ' || ch == '\t' || ch == '\n')
1403 cinp();
1404 t = ch;
1406 if (t != '(') /* no macro subst */
1407 goto no_subst;
1409 /* argument macro */
1410 next_nomacro();
1411 next_nomacro();
1412 args = NULL;
1413 sa = s->next;
1414 while (tok != ')' && sa) {
1415 len = 0;
1416 str = NULL;
1417 parlevel = 0;
1418 while ((parlevel > 0 ||
1419 (tok != ')' &&
1420 (tok != ',' ||
1421 sa->v == (TOK___VA_ARGS__ | SYM_FIELD)))) &&
1422 tok != -1) {
1423 if (tok == '(')
1424 parlevel++;
1425 else if (tok == ')')
1426 parlevel--;
1427 tok_add2(&str, &len, tok, tokc);
1428 next_nomacro();
1430 tok_add(&str, &len, 0);
1431 sym_push2(&args, sa->v & ~SYM_FIELD, 0, (int)str);
1432 if (tok != ',')
1433 break;
1434 next_nomacro();
1435 sa = sa->next;
1437 if (tok != ')')
1438 expect(")");
1439 /* now subst each arg */
1440 mstr = macro_arg_subst(nested_list, mstr, args);
1441 /* free memory */
1442 sa = args;
1443 while (sa) {
1444 sa1 = sa->prev;
1445 free((int *)sa->c);
1446 free(sa);
1447 sa = sa1;
1449 mstr_allocated = 1;
1451 sym_push2(nested_list, s->v, 0, 0);
1452 macro_subst(tok_str, tok_len, nested_list, mstr);
1453 /* pop nested defined symbol */
1454 sa1 = *nested_list;
1455 *nested_list = sa1->prev;
1456 free(sa1);
1457 if (mstr_allocated)
1458 free(mstr);
1459 } else {
1460 no_subst:
1461 /* no need to add if reading input stream */
1462 if (!macro_str)
1463 return;
1464 tok_add2(tok_str, tok_len, tok, tokc);
1466 /* only replace one macro while parsing input stream */
1467 if (!macro_str)
1468 return;
1470 macro_ptr = saved_macro_ptr;
1471 if (macro_str1)
1472 free(macro_str1);
1475 /* return next token with macro substitution */
1476 void next(void)
1478 int len, *ptr;
1479 Sym *nested_list;
1481 /* special 'ungettok' case for label parsing */
1482 if (tok1) {
1483 tok = tok1;
1484 tokc = tok1c;
1485 tok1 = 0;
1486 } else {
1487 redo:
1488 if (!macro_ptr) {
1489 /* if not reading from macro substuted string, then try to substitute */
1490 len = 0;
1491 ptr = NULL;
1492 nested_list = NULL;
1493 macro_subst(&ptr, &len, &nested_list, NULL);
1494 if (ptr) {
1495 tok_add(&ptr, &len, 0);
1496 macro_ptr = ptr;
1497 macro_ptr_allocated = ptr;
1498 goto redo;
1500 if (tok == 0)
1501 goto redo;
1502 } else {
1503 next_nomacro();
1504 if (tok == 0) {
1505 /* end of macro string: free it */
1506 free(macro_ptr_allocated);
1507 macro_ptr = NULL;
1508 goto redo;
1512 #if defined(DEBUG)
1513 printf("token = %s\n", get_tok_str(tok, tokc));
1514 #endif
1517 void swap(int *p, int *q)
1519 int t;
1520 t = *p;
1521 *p = *q;
1522 *q = t;
1525 void vset(t, v)
1527 vt = t;
1528 vc = v;
1531 /******************************************************/
1532 /* X86 code generator */
1534 typedef struct GFuncContext {
1535 int args_size;
1536 } GFuncContext;
1538 void g(int c)
1540 *(char *)ind++ = c;
1543 void o(int c)
1545 while (c) {
1546 g(c);
1547 c = c / 256;
1551 void gen_le32(int c)
1553 g(c);
1554 g(c >> 8);
1555 g(c >> 16);
1556 g(c >> 24);
1559 /* add a new relocation entry to symbol 's' */
1560 void greloc(Sym *s, int addr, int type)
1562 Reloc *p;
1563 p = malloc(sizeof(Reloc));
1564 if (!p)
1565 error("memory full");
1566 p->type = type;
1567 p->addr = addr;
1568 p->next = (Reloc *)s->c;
1569 s->c = (int)p;
1572 /* patch each relocation entry with value 'val' */
1573 void greloc_patch(Sym *s, int val)
1575 Reloc *p, *p1;
1577 p = (Reloc *)s->c;
1578 while (p != NULL) {
1579 p1 = p->next;
1580 switch(p->type) {
1581 case RELOC_ADDR32:
1582 *(int *)p->addr = val;
1583 break;
1584 case RELOC_REL32:
1585 *(int *)p->addr = val - p->addr - 4;
1586 break;
1588 free(p);
1589 p = p1;
1591 s->c = val;
1592 s->t &= ~VT_FORWARD;
1595 /* output a symbol and patch all calls to it */
1596 void gsym_addr(t, a)
1598 int n;
1599 while (t) {
1600 n = *(int *)t; /* next value */
1601 *(int *)t = a - t - 4;
1602 t = n;
1606 void gsym(t)
1608 gsym_addr(t, ind);
1611 /* psym is used to put an instruction with a data field which is a
1612 reference to a symbol. It is in fact the same as oad ! */
1613 #define psym oad
1615 /* instruction + 4 bytes data. Return the address of the data */
1616 int oad(int c, int s)
1618 o(c);
1619 *(int *)ind = s;
1620 s = ind;
1621 ind = ind + 4;
1622 return s;
1625 /* output constant with relocation if 't & VT_FORWARD' is true */
1626 void gen_addr32(int c, int t)
1628 if (!(t & VT_FORWARD)) {
1629 gen_le32(c);
1630 } else {
1631 greloc((Sym *)c, ind, RELOC_ADDR32);
1632 gen_le32(0);
1636 /* XXX: generate correct pointer for forward references to functions */
1637 /* r = (ft, fc) */
1638 void load(r, ft, fc)
1640 int v, t;
1642 v = ft & VT_VALMASK;
1643 if (ft & VT_LVAL) {
1644 if (v == VT_LLOCAL) {
1645 load(r, VT_LOCAL | VT_LVAL, fc);
1646 v = r;
1648 if ((ft & VT_TYPE) == VT_BYTE)
1649 o(0xbe0f); /* movsbl */
1650 else if ((ft & VT_TYPE) == (VT_BYTE | VT_UNSIGNED))
1651 o(0xb60f); /* movzbl */
1652 else if ((ft & VT_TYPE) == VT_SHORT)
1653 o(0xbf0f); /* movswl */
1654 else if ((ft & VT_TYPE) == (VT_SHORT | VT_UNSIGNED))
1655 o(0xb70f); /* movzwl */
1656 else
1657 o(0x8b); /* movl */
1658 if (v == VT_CONST) {
1659 o(0x05 + r * 8); /* 0xXX, r */
1660 gen_addr32(fc, ft);
1661 } else if (v == VT_LOCAL) {
1662 oad(0x85 + r * 8, fc); /* xx(%ebp), r */
1663 } else {
1664 g(0x00 + r * 8 + v); /* (v), r */
1666 } else {
1667 if (v == VT_CONST) {
1668 o(0xb8 + r); /* mov $xx, r */
1669 gen_addr32(fc, ft);
1670 } else if (v == VT_LOCAL) {
1671 o(0x8d);
1672 oad(0x85 + r * 8, fc); /* lea xxx(%ebp), r */
1673 } else if (v == VT_CMP) {
1674 oad(0xb8 + r, 0); /* mov $0, r */
1675 o(0x0f); /* setxx %br */
1676 o(fc);
1677 o(0xc0 + r);
1678 } else if (v == VT_JMP || v == VT_JMPI) {
1679 t = v & 1;
1680 oad(0xb8 + r, t); /* mov $1, r */
1681 oad(0xe9, 5); /* jmp after */
1682 gsym(fc);
1683 oad(0xb8 + r, t ^ 1); /* mov $0, r */
1684 } else if (v != r) {
1685 o(0x89);
1686 o(0xc0 + r + v * 8); /* mov v, r */
1691 /* (ft, fc) = r */
1692 /* WARNING: r must not be allocated on the stack */
1693 void store(r, ft, fc)
1695 int fr, bt;
1697 fr = ft & VT_VALMASK;
1698 bt = ft & VT_BTYPE;
1699 /* XXX: incorrect if reg to reg */
1700 if (bt == VT_SHORT)
1701 o(0x66);
1702 if (bt == VT_BYTE)
1703 o(0x88);
1704 else
1705 o(0x89);
1706 if (fr == VT_CONST) {
1707 o(0x05 + r * 8); /* mov r,xxx */
1708 gen_addr32(fc, ft);
1709 } else if (fr == VT_LOCAL) {
1710 oad(0x85 + r * 8, fc); /* mov r,xxx(%ebp) */
1711 } else if (ft & VT_LVAL) {
1712 g(fr + r * 8); /* mov r, (fr) */
1713 } else if (fr != r) {
1714 o(0xc0 + fr + r * 8); /* mov r, fr */
1718 /* start function call and return function call context */
1719 void gfunc_start(GFuncContext *c)
1721 c->args_size = 0;
1724 /* push function parameter which is in (vt, vc) */
1725 void gfunc_param(GFuncContext *c)
1727 int size, align, ft, fc, r;
1729 if ((vt & (VT_BTYPE | VT_LVAL)) == (VT_STRUCT | VT_LVAL)) {
1730 size = type_size(vt, &align);
1731 /* align to stack align size */
1732 size = (size + 3) & ~3;
1733 /* allocate the necessary size on stack */
1734 oad(0xec81, size); /* sub $xxx, %esp */
1735 /* generate structure store */
1736 r = get_reg();
1737 o(0x89); /* mov %esp, r */
1738 o(0xe0 + r);
1739 ft = vt;
1740 fc = vc;
1741 vset(VT_INT | r, 0);
1742 vpush();
1743 vt = ft;
1744 vc = fc;
1745 vstore();
1746 c->args_size += size;
1747 } else {
1748 /* simple type (currently always same size) */
1749 /* XXX: implicit cast ? */
1750 r = gv();
1751 o(0x50 + r); /* push r */
1752 c->args_size += 4;
1756 /* generate function call with address in (vt, vc) and free function
1757 context */
1758 void gfunc_call(GFuncContext *c)
1760 int r;
1761 if ((vt & (VT_VALMASK | VT_LVAL)) == VT_CONST) {
1762 /* constant case */
1763 /* forward reference */
1764 if (vt & VT_FORWARD) {
1765 greloc((Sym *)vc, ind + 1, RELOC_REL32);
1766 oad(0xe8, 0);
1767 } else {
1768 oad(0xe8, vc - ind - 5);
1770 } else {
1771 /* otherwise, indirect call */
1772 r = gv();
1773 o(0xff); /* call *r */
1774 o(0xd0 + r);
1776 if (c->args_size)
1777 oad(0xc481, c->args_size); /* add $xxx, %esp */
1780 int gjmp(int t)
1782 return psym(0xe9, t);
1785 /* generate a test. set 'inv' to invert test */
1786 int gtst(int inv, int t)
1788 int v, *p;
1789 v = vt & VT_VALMASK;
1790 if (v == VT_CMP) {
1791 /* fast case : can jump directly since flags are set */
1792 g(0x0f);
1793 t = psym((vc - 16) ^ inv, t);
1794 } else if (v == VT_JMP || v == VT_JMPI) {
1795 /* && or || optimization */
1796 if ((v & 1) == inv) {
1797 /* insert vc jump list in t */
1798 p = &vc;
1799 while (*p != 0)
1800 p = (int *)*p;
1801 *p = t;
1802 t = vc;
1803 } else {
1804 t = gjmp(t);
1805 gsym(vc);
1807 } else if ((vt & (VT_VALMASK | VT_LVAL)) == VT_CONST) {
1808 /* constant jmp optimization */
1809 if ((vc != 0) != inv)
1810 t = gjmp(t);
1811 } else {
1812 v = gv();
1813 o(0x85);
1814 o(0xc0 + v * 9);
1815 g(0x0f);
1816 t = psym(0x85 ^ inv, t);
1818 return t;
1821 /* generate a binary operation 'v = r op fr' instruction and modifies
1822 (vt,vc) if needed */
1823 void gen_op1(int op, int r, int fr)
1825 int t;
1826 if (op == '+') {
1827 o(0x01);
1828 o(0xc0 + r + fr * 8);
1829 } else if (op == '-') {
1830 o(0x29);
1831 o(0xc0 + r + fr * 8);
1832 } else if (op == '&') {
1833 o(0x21);
1834 o(0xc0 + r + fr * 8);
1835 } else if (op == '^') {
1836 o(0x31);
1837 o(0xc0 + r + fr * 8);
1838 } else if (op == '|') {
1839 o(0x09);
1840 o(0xc0 + r + fr * 8);
1841 } else if (op == '*') {
1842 o(0xaf0f); /* imul fr, r */
1843 o(0xc0 + fr + r * 8);
1844 } else if (op == TOK_SHL | op == TOK_SHR | op == TOK_SAR) {
1845 /* op2 is %ecx */
1846 if (fr != 1) {
1847 if (r == 1) {
1848 r = fr;
1849 fr = 1;
1850 o(0x87); /* xchg r, %ecx */
1851 o(0xc1 + r * 8);
1852 } else
1853 move_reg(1, fr);
1855 o(0xd3); /* shl/shr/sar %cl, r */
1856 if (op == TOK_SHL)
1857 o(0xe0 + r);
1858 else if (op == TOK_SHR)
1859 o(0xe8 + r);
1860 else
1861 o(0xf8 + r);
1862 vt = (vt & VT_TYPE) | r;
1863 } else if (op == '/' | op == TOK_UDIV | op == TOK_PDIV |
1864 op == '%' | op == TOK_UMOD) {
1865 save_reg(2); /* save edx */
1866 t = save_reg_forced(fr); /* save fr and get op2 location */
1867 move_reg(0, r); /* op1 is %eax */
1868 if (op == TOK_UDIV | op == TOK_UMOD) {
1869 o(0xf7d231); /* xor %edx, %edx, div t(%ebp), %eax */
1870 oad(0xb5, t);
1871 } else {
1872 o(0xf799); /* cltd, idiv t(%ebp), %eax */
1873 oad(0xbd, t);
1875 if (op == '%' | op == TOK_UMOD)
1876 r = 2;
1877 else
1878 r = 0;
1879 vt = (vt & VT_TYPE) | r;
1880 } else {
1881 o(0x39);
1882 o(0xc0 + r + fr * 8); /* cmp fr, r */
1883 vset(VT_CMP, op);
1887 /* end of X86 code generator */
1888 /*************************************************************/
1890 int save_reg_forced(int r)
1892 int i, l, *p, t;
1893 /* store register */
1894 loc = (loc - 4) & -3;
1895 store(r, VT_LOCAL, loc);
1896 l = loc;
1898 /* modify all stack values */
1899 for(p=vstack;p<vstack_ptr;p+=2) {
1900 i = p[0] & VT_VALMASK;
1901 if (i == r) {
1902 if (p[0] & VT_LVAL)
1903 t = VT_LLOCAL;
1904 else
1905 t = VT_LOCAL;
1906 p[0] = (p[0] & VT_TYPE) | VT_LVAL | t;
1907 p[1] = l;
1910 return l;
1913 /* save r to memory. and mark it as being free */
1914 void save_reg(r)
1916 int i, *p;
1918 /* modify all stack values */
1919 for(p=vstack;p<vstack_ptr;p+=2) {
1920 i = p[0] & VT_VALMASK;
1921 if (i == r) {
1922 save_reg_forced(r);
1923 break;
1928 /* find a free register. If none, save one register */
1929 int get_reg(void)
1931 int r, i, *p;
1933 /* find a free register */
1934 for(r=0;r<NB_REGS;r++) {
1935 for(p=vstack;p<vstack_ptr;p+=2) {
1936 i = p[0] & VT_VALMASK;
1937 if (i == r)
1938 goto notfound;
1940 return r;
1941 notfound: ;
1944 /* no register left : free the first one on the stack (very
1945 important to start from the bottom to ensure that we don't
1946 spill registers used in gen_op()) */
1947 for(p=vstack;p<vstack_ptr;p+=2) {
1948 r = p[0] & VT_VALMASK;
1949 if (r < VT_CONST) {
1950 save_reg(r);
1951 break;
1954 return r;
1957 void save_regs()
1959 int r, *p;
1960 for(p=vstack;p<vstack_ptr;p+=2) {
1961 r = p[0] & VT_VALMASK;
1962 if (r < VT_CONST) {
1963 save_reg(r);
1968 /* move register 's' to 'r', and flush previous value of r to memory
1969 if needed */
1970 void move_reg(r, s)
1972 if (r != s) {
1973 save_reg(r);
1974 load(r, s, 0);
1978 /* convert a stack entry in register. lvalues are converted as
1979 values. Cannot be used if cannot be converted to register value
1980 (such as structures). */
1981 int gvp(int *p)
1983 int r;
1984 r = p[0] & VT_VALMASK;
1985 if (r >= VT_CONST || (p[0] & VT_LVAL))
1986 r = get_reg();
1987 /* NOTE: get_reg can modify p[] */
1988 load(r, p[0], p[1]);
1989 p[0] = (p[0] & VT_TYPE) | r;
1990 return r;
1993 void vpush(void)
1995 if (vstack_ptr >= vstack + VSTACK_SIZE)
1996 error("memory full");
1997 *vstack_ptr++ = vt;
1998 *vstack_ptr++ = vc;
1999 /* cannot let cpu flags if other instruction are generated */
2000 /* XXX: VT_JMP test too ? */
2001 if ((vt & VT_VALMASK) == VT_CMP)
2002 gvp(vstack_ptr - 2);
2005 void vpop(int *ft, int *fc)
2007 *fc = *--vstack_ptr;
2008 *ft = *--vstack_ptr;
2011 /* generate a value in a register from vt and vc */
2012 int gv(void)
2014 int r;
2015 vpush();
2016 r = gvp(vstack_ptr - 2);
2017 vpop(&vt, &vc);
2018 return r;
2021 /* handle constant optimizations and various machine independant opt */
2022 void gen_opc(op)
2024 int fr, ft, fc, r, c1, c2, n;
2026 vpop(&ft, &fc);
2027 vpop(&vt, &vc);
2028 c1 = (vt & (VT_VALMASK | VT_LVAL)) == VT_CONST;
2029 c2 = (ft & (VT_VALMASK | VT_LVAL)) == VT_CONST;
2030 if (c1 && c2) {
2031 switch(op) {
2032 case '+': vc += fc; break;
2033 case '-': vc -= fc; break;
2034 case '&': vc &= fc; break;
2035 case '^': vc ^= fc; break;
2036 case '|': vc |= fc; break;
2037 case '*': vc *= fc; break;
2038 case TOK_PDIV:
2039 case '/': vc /= fc; break; /* XXX: zero case ? */
2040 case '%': vc %= fc; break; /* XXX: zero case ? */
2041 case TOK_UDIV: vc = (unsigned)vc / fc; break; /* XXX: zero case ? */
2042 case TOK_UMOD: vc = (unsigned)vc % fc; break; /* XXX: zero case ? */
2043 case TOK_SHL: vc <<= fc; break;
2044 case TOK_SHR: vc = (unsigned)vc >> fc; break;
2045 case TOK_SAR: vc >>= fc; break;
2046 /* tests */
2047 case TOK_ULT: vc = (unsigned)vc < (unsigned)fc; break;
2048 case TOK_UGE: vc = (unsigned)vc >= (unsigned)fc; break;
2049 case TOK_EQ: vc = vc == fc; break;
2050 case TOK_NE: vc = vc != fc; break;
2051 case TOK_ULE: vc = (unsigned)vc <= (unsigned)fc; break;
2052 case TOK_UGT: vc = (unsigned)vc > (unsigned)fc; break;
2053 case TOK_LT: vc = vc < fc; break;
2054 case TOK_GE: vc = vc >= fc; break;
2055 case TOK_LE: vc = vc <= fc; break;
2056 case TOK_GT: vc = vc > fc; break;
2057 /* logical */
2058 case TOK_LAND: vc = vc && fc; break;
2059 case TOK_LOR: vc = vc || fc; break;
2060 default:
2061 goto general_case;
2063 } else {
2064 /* if commutative ops, put c2 as constant */
2065 if (c1 && (op == '+' || op == '&' || op == '^' ||
2066 op == '|' || op == '*')) {
2067 swap(&vt, &ft);
2068 swap(&vc, &fc);
2069 swap(&c1, &c2);
2071 if (c2 && (((op == '*' || op == '/' || op == TOK_UDIV ||
2072 op == TOK_PDIV) &&
2073 fc == 1) ||
2074 ((op == '+' || op == '-' || op == '|' || op == '^' ||
2075 op == TOK_SHL || op == TOK_SHR || op == TOK_SAR) &&
2076 fc == 0) ||
2077 (op == '&' &&
2078 fc == -1))) {
2079 } else if (c2 && (op == '*' || op == TOK_PDIV || op == TOK_UDIV)) {
2080 /* try to use shifts instead of muls or divs */
2081 if (fc > 0 && (fc & (fc - 1)) == 0) {
2082 n = -1;
2083 while (fc) {
2084 fc >>= 1;
2085 n++;
2087 fc = n;
2088 if (op == '*')
2089 op = TOK_SHL;
2090 else if (op == TOK_PDIV)
2091 op = TOK_SAR;
2092 else
2093 op = TOK_SHR;
2095 goto general_case;
2096 } else {
2097 general_case:
2098 vpush();
2099 vt = ft;
2100 vc = fc;
2101 vpush();
2102 r = gvp(vstack_ptr - 4);
2103 fr = gvp(vstack_ptr - 2);
2104 vpop(&ft, &fc);
2105 vpop(&vt, &vc);
2106 /* call low level op generator */
2107 gen_op1(op, r, fr);
2112 int pointed_size(int t)
2114 return type_size(pointed_type(t), &t);
2117 /* generic gen_op: handles types problems */
2118 void gen_op(int op)
2120 int u, t1, t2;
2122 vpush();
2123 t1 = vstack_ptr[-4];
2124 t2 = vstack_ptr[-2];
2125 if (op == '+' | op == '-') {
2126 if ((t1 & VT_BTYPE) == VT_PTR &&
2127 (t2 & VT_BTYPE) == VT_PTR) {
2128 if (op != '-')
2129 error("invalid type");
2130 /* XXX: check that types are compatible */
2131 u = pointed_size(t1);
2132 gen_opc(op);
2133 vpush();
2134 vstack_ptr[-2] &= ~VT_TYPE; /* set to integer */
2135 vset(VT_CONST, u);
2136 gen_op(TOK_PDIV);
2137 } else if ((t1 & VT_BTYPE) == VT_PTR ||
2138 (t2 & VT_BTYPE) == VT_PTR) {
2139 if ((t2 & VT_BTYPE) == VT_PTR) {
2140 swap(vstack_ptr - 4, vstack_ptr - 2);
2141 swap(vstack_ptr - 3, vstack_ptr - 1);
2142 swap(&t1, &t2);
2144 /* stack-4 contains pointer, stack-2 value to add */
2145 vset(VT_CONST, pointed_size(vstack_ptr[-4]));
2146 gen_op('*');
2147 vpush();
2148 gen_opc(op);
2149 /* put again type if gen_opc() swaped operands */
2150 vt = (vt & ~VT_TYPE) | (t1 & VT_TYPE);
2151 } else {
2152 gen_opc(op);
2154 } else {
2155 /* XXX: test types and compute returned value */
2156 if ((t1 | t2) & VT_UNSIGNED ||
2157 (t1 & VT_BTYPE) == VT_PTR ||
2158 (t2 & VT_BTYPE) == VT_PTR) {
2159 if (op == TOK_SAR)
2160 op = TOK_SHR;
2161 else if (op == '/')
2162 op = TOK_UDIV;
2163 else if (op == '%')
2164 op = TOK_UMOD;
2165 else if (op == TOK_LT)
2166 op = TOK_ULT;
2167 else if (op == TOK_GT)
2168 op = TOK_UGT;
2169 else if (op == TOK_LE)
2170 op = TOK_ULE;
2171 else if (op == TOK_GE)
2172 op = TOK_UGE;
2174 gen_opc(op);
2178 /* cast (vt, vc) to 't' type */
2179 void gen_cast(int t)
2181 int r, bits;
2182 r = vt & VT_VALMASK;
2183 if (!(t & VT_LVAL)) {
2184 /* if not lvalue, then we convert now */
2185 if ((t & VT_TYPE & ~VT_UNSIGNED) == VT_BYTE)
2186 bits = 8;
2187 else if ((t & VT_TYPE & ~VT_UNSIGNED) == VT_SHORT)
2188 bits = 16;
2189 else
2190 goto the_end;
2191 vpush();
2192 if (t & VT_UNSIGNED) {
2193 vset(VT_CONST, (1 << bits) - 1);
2194 gen_op('&');
2195 } else {
2196 bits = 32 - bits;
2197 vset(VT_CONST, bits);
2198 gen_op(TOK_SHL);
2199 vpush();
2200 vset(VT_CONST, bits);
2201 gen_op(TOK_SAR);
2204 the_end:
2205 vt = (vt & ~VT_TYPE) | t;
2208 /* return type size. Put alignment at 'a' */
2209 int type_size(int t, int *a)
2211 Sym *s;
2212 int bt;
2214 bt = t & VT_BTYPE;
2215 if (bt == VT_STRUCT) {
2216 /* struct/union */
2217 s = sym_find(((unsigned)t >> VT_STRUCT_SHIFT) | SYM_STRUCT);
2218 *a = 4; /* XXX: cannot store it yet. Doing that is safe */
2219 return s->c;
2220 } else if (t & VT_ARRAY) {
2221 s = sym_find(((unsigned)t >> VT_STRUCT_SHIFT));
2222 return type_size(s->t, a) * s->c;
2223 } else if (bt == VT_PTR ||
2224 bt == VT_INT ||
2225 bt == VT_ENUM) {
2226 *a = 4;
2227 return 4;
2228 } else if (bt == VT_SHORT) {
2229 *a = 2;
2230 return 2;
2231 } else {
2232 /* void or function */
2233 *a = 1;
2234 return 1;
2238 /* return the pointed type of t */
2239 int pointed_type(int t)
2241 Sym *s;
2242 s = sym_find(((unsigned)t >> VT_STRUCT_SHIFT));
2243 return s->t | (t & ~VT_TYPE);
2246 int mk_pointer(int t)
2248 int p;
2249 p = anon_sym++;
2250 sym_push(p, t, -1);
2251 return VT_PTR | (p << VT_STRUCT_SHIFT) | (t & ~VT_TYPE);
2254 /* store value in lvalue pushed on stack */
2255 void vstore(void)
2257 int ft, fc, r, t, size, align;
2258 GFuncContext gf;
2260 if ((vt & VT_BTYPE) == VT_STRUCT) {
2261 /* if structure, only generate pointer */
2262 /* structure assignment : generate memcpy */
2263 /* XXX: optimize if small size */
2265 gfunc_start(&gf);
2266 /* type size */
2267 ft = vt;
2268 fc = vc;
2269 size = type_size(vt, &align);
2270 vset(VT_CONST, size);
2271 gfunc_param(&gf);
2272 /* source */
2273 vt = ft & ~VT_LVAL;
2274 vc = fc;
2275 gfunc_param(&gf);
2276 /* destination */
2277 vpop(&vt, &vc);
2278 vt &= ~VT_LVAL;
2279 gfunc_param(&gf);
2281 save_regs();
2282 vset(VT_CONST, (int)&memcpy);
2283 gfunc_call(&gf);
2285 /* generate again current type */
2286 vt = ft;
2287 vc = fc;
2288 } else {
2289 r = gv(); /* generate value */
2290 vpush();
2291 ft = vstack_ptr[-4];
2292 fc = vstack_ptr[-3];
2293 /* if lvalue was saved on stack, must read it */
2294 if ((ft & VT_VALMASK) == VT_LLOCAL) {
2295 t = get_reg();
2296 load(t, VT_LOCAL | VT_LVAL, fc);
2297 ft = (ft & ~VT_VALMASK) | t;
2299 store(r, ft, fc);
2300 vstack_ptr -= 4;
2304 /* post defines POST/PRE add. c is the token ++ or -- */
2305 void inc(post, c)
2307 int r, r1;
2308 test_lvalue();
2309 if (post)
2310 vpush(); /* room for returned value */
2311 vpush(); /* save lvalue */
2312 r = gv();
2313 vpush(); /* save value */
2314 if (post) {
2315 /* duplicate value */
2316 r1 = get_reg();
2317 load(r1, r, 0); /* move r to r1 */
2318 vstack_ptr[-6] = (vt & VT_TYPE) | r1;
2319 vstack_ptr[-5] = 0;
2321 /* add constant */
2322 vset(VT_CONST, c - TOK_MID);
2323 gen_op('+');
2324 vstore(); /* store value */
2325 if (post)
2326 vpop(&vt, &vc);
2329 /* enum/struct/union declaration */
2330 int struct_decl(int u)
2332 int a, t, b, v, size, align, maxalign, c;
2333 Sym *s, *ss, **ps;
2335 a = tok; /* save decl type */
2336 next();
2337 if (tok != '{') {
2338 v = tok;
2339 next();
2340 /* struct already defined ? return it */
2341 /* XXX: check consistency */
2342 if (s = sym_find(v | SYM_STRUCT)) {
2343 if (s->t != a)
2344 error("invalid type");
2345 goto do_decl;
2347 } else {
2348 v = anon_sym++;
2350 s = sym_push(v | SYM_STRUCT, a, 0);
2351 /* put struct/union/enum name in type */
2352 do_decl:
2353 u = u | (v << VT_STRUCT_SHIFT);
2355 if (tok == '{') {
2356 next();
2357 if (s->c)
2358 error("struct/union/enum already defined");
2359 /* cannot be empty */
2360 c = 0;
2361 maxalign = 0;
2362 ps = &s->next;
2363 while (1) {
2364 if (a == TOK_ENUM) {
2365 v = tok;
2366 next();
2367 if (tok == '=') {
2368 next();
2369 c = expr_const();
2371 /* enum symbols have static storage */
2372 sym_push(v, VT_CONST | VT_STATIC, c);
2373 if (tok == ',')
2374 next();
2375 c++;
2376 } else {
2377 b = ist();
2378 while (1) {
2379 t = type_decl(&v, b, TYPE_DIRECT);
2380 if ((t & VT_BTYPE) == VT_FUNC ||
2381 (t & (VT_TYPEDEF | VT_STATIC | VT_EXTERN)))
2382 error("invalid type");
2383 /* XXX: align & correct type size */
2384 v |= SYM_FIELD;
2385 size = type_size(t, &align);
2386 if (a == TOK_STRUCT) {
2387 c = (c + align - 1) & -align;
2388 ss = sym_push(v, t, c);
2389 c += size;
2390 } else {
2391 ss = sym_push(v, t, 0);
2392 if (size > c)
2393 c = size;
2395 if (align > maxalign)
2396 maxalign = align;
2397 *ps = ss;
2398 ps = &ss->next;
2399 if (tok == ';' || tok == -1)
2400 break;
2401 skip(',');
2403 skip(';');
2405 if (tok == '}')
2406 break;
2408 skip('}');
2409 /* size for struct/union, dummy for enum */
2410 s->c = (c + maxalign - 1) & -maxalign;
2412 return u;
2415 /* return 0 if no type declaration. otherwise, return the basic type
2416 and skip it.
2417 XXX: A '2' is ored to ensure non zero return if int type.
2419 int ist(void)
2421 int t, u;
2422 Sym *s;
2424 t = 0;
2425 while(1) {
2426 switch(tok) {
2427 /* basic types */
2428 case TOK_CHAR:
2429 u = VT_BYTE;
2430 basic_type:
2431 next();
2432 basic_type1:
2433 if ((t & VT_BTYPE) != 0)
2434 error("too many basic types %x", t);
2435 t |= u;
2436 break;
2437 case TOK_VOID:
2438 u = VT_VOID;
2439 goto basic_type;
2440 case TOK_SHORT:
2441 u = VT_SHORT;
2442 goto basic_type;
2443 case TOK_INT:
2444 next();
2445 break;
2446 case TOK_LONG:
2447 /* XXX: add long type */
2448 u = VT_INT;
2449 goto basic_type;
2450 case TOK_FLOAT:
2451 case TOK_DOUBLE:
2452 /* XXX: add float types */
2453 u = VT_INT;
2454 goto basic_type;
2455 case TOK_ENUM:
2456 u = struct_decl(VT_ENUM);
2457 goto basic_type1;
2458 case TOK_STRUCT:
2459 case TOK_UNION:
2460 u = struct_decl(VT_STRUCT);
2461 goto basic_type1;
2463 /* type modifiers */
2464 case TOK_CONST:
2465 case TOK_VOLATILE:
2466 case TOK_REGISTER:
2467 case TOK_SIGNED:
2468 case TOK_AUTO:
2469 case TOK_INLINE:
2470 case TOK_RESTRICT:
2471 next();
2472 break;
2473 case TOK_UNSIGNED:
2474 t |= VT_UNSIGNED;
2475 next();
2476 break;
2478 /* storage */
2479 case TOK_EXTERN:
2480 t |= VT_EXTERN;
2481 next();
2482 break;
2483 case TOK_STATIC:
2484 t |= VT_STATIC;
2485 next();
2486 break;
2487 case TOK_TYPEDEF:
2488 t |= VT_TYPEDEF;
2489 next();
2490 break;
2491 default:
2492 s = sym_find(tok);
2493 if (!s || !(s->t & VT_TYPEDEF))
2494 goto the_end;
2495 t |= (s->t & ~VT_TYPEDEF);
2496 next();
2497 break;
2499 t |= 2;
2501 the_end:
2502 return t;
2505 int post_type(int t)
2507 int p, n, pt, l, t1;
2508 Sym **plast, *s, *first;
2510 if (tok == '(') {
2511 /* function declaration */
2512 next();
2513 l = 0;
2514 first = NULL;
2515 plast = &first;
2516 while (tok != ')') {
2517 /* read param name and compute offset */
2518 if (l != FUNC_OLD) {
2519 if (!(pt = ist())) {
2520 if (l) {
2521 error("invalid type");
2522 } else {
2523 l = FUNC_OLD;
2524 goto old_proto;
2527 if ((pt & VT_BTYPE) == VT_VOID && tok == ')')
2528 break;
2529 l = FUNC_NEW;
2530 pt = type_decl(&n, pt, TYPE_DIRECT | TYPE_ABSTRACT);
2531 } else {
2532 old_proto:
2533 n = tok;
2534 pt = VT_INT;
2535 next();
2537 /* array must be transformed to pointer according to ANSI C */
2538 pt &= ~VT_ARRAY;
2539 s = sym_push(n | SYM_FIELD, pt, 0);
2540 *plast = s;
2541 plast = &s->next;
2542 if (tok == ',') {
2543 next();
2544 if (l == FUNC_NEW && tok == TOK_DOTS) {
2545 l = FUNC_ELLIPSIS;
2546 next();
2547 break;
2551 skip(')');
2552 t1 = t & (VT_TYPEDEF | VT_STATIC | VT_EXTERN);
2553 t = post_type(t & ~(VT_TYPEDEF | VT_STATIC | VT_EXTERN));
2554 /* we push a anonymous symbol which will contain the function prototype */
2555 p = anon_sym++;
2556 s = sym_push(p, t, l);
2557 s->next = first;
2558 t = t1 | VT_FUNC | (p << VT_STRUCT_SHIFT);
2559 } else if (tok == '[') {
2560 /* array definition */
2561 next();
2562 n = -1;
2563 if (tok != ']') {
2564 n = expr_const();
2565 if (n < 0)
2566 error("invalid array size");
2568 skip(']');
2569 /* parse next post type */
2570 t1 = t & (VT_TYPEDEF | VT_STATIC | VT_EXTERN);
2571 t = post_type(t & ~(VT_TYPEDEF | VT_STATIC | VT_EXTERN));
2573 /* we push a anonymous symbol which will contain the array
2574 element type */
2575 p = anon_sym++;
2576 sym_push(p, t, n);
2577 t = t1 | VT_ARRAY | VT_PTR | (p << VT_STRUCT_SHIFT);
2579 return t;
2582 /* Read a type declaration (except basic type), and return the
2583 type. If v is true, then also put variable name in 'vc' */
2584 int type_decl(int *v, int t, int td)
2586 int u, p;
2587 Sym *s;
2589 t = t & -3; /* suppress the ored '2' */
2590 while (tok == '*') {
2591 next();
2592 while (tok == TOK_CONST || tok == TOK_VOLATILE || tok == TOK_RESTRICT)
2593 next();
2594 t = mk_pointer(t);
2597 /* recursive type */
2598 /* XXX: incorrect if abstract type for functions (e.g. 'int ()') */
2599 if (tok == '(') {
2600 next();
2601 u = type_decl(v, 0, td);
2602 skip(')');
2603 } else {
2604 u = 0;
2605 /* type identifier */
2606 if (tok >= TOK_IDENT && (td & TYPE_DIRECT)) {
2607 *v = tok;
2608 next();
2609 } else {
2610 if (!(td & TYPE_ABSTRACT))
2611 expect("identifier");
2612 *v = 0;
2615 /* append t at the end of u */
2616 t = post_type(t);
2617 if (!u)
2618 return t;
2619 p = u;
2620 while(1) {
2621 s = sym_find((unsigned)p >> VT_STRUCT_SHIFT);
2622 p = s->t;
2623 if (!p) {
2624 s->t = t;
2625 break;
2628 return u;
2631 /* define a new external reference to a function 'v' of type 'u' */
2632 Sym *external_sym(int v, int u)
2634 Sym *s;
2635 s = sym_find(v);
2636 if (!s) {
2637 /* push forward reference */
2638 s = sym_push1(&global_stack,
2639 v, u | VT_CONST | VT_FORWARD, 0);
2641 return s;
2644 void indir(void)
2646 if (vt & VT_LVAL)
2647 gv();
2648 if ((vt & VT_BTYPE) != VT_PTR)
2649 expect("pointer");
2650 vt = pointed_type(vt);
2651 if (!(vt & VT_ARRAY)) /* an array is never an lvalue */
2652 vt |= VT_LVAL;
2655 void unary(void)
2657 int n, t, ft, fc, p, align, size;
2658 Sym *s;
2659 GFuncContext gf;
2661 if (tok == TOK_NUM || tok == TOK_CCHAR || tok == TOK_LCHAR) {
2662 vset(VT_CONST, tokc);
2663 next();
2664 } else if (tok == TOK___FUNC__) {
2665 /* special function name identifier */
2666 /* generate (char *) type */
2667 vset(VT_CONST | mk_pointer(VT_BYTE), glo);
2668 strcpy((void *)glo, funcname);
2669 glo += strlen(funcname) + 1;
2670 next();
2671 } else if (tok == TOK_LSTR) {
2672 t = VT_INT;
2673 goto str_init;
2674 } else if (tok == TOK_STR) {
2675 /* string parsing */
2676 t = VT_BYTE;
2677 str_init:
2678 type_size(t, &align);
2679 glo = (glo + align - 1) & -align;
2680 fc = glo;
2681 /* we must declare it as an array first to use initializer parser */
2682 t = VT_CONST | VT_ARRAY | mk_pointer(t);
2683 decl_initializer(t, glo, 1, 0);
2684 glo += type_size(t, &align);
2685 /* put it as pointer */
2686 vset(t & ~VT_ARRAY, fc);
2687 } else {
2688 t = tok;
2689 next();
2690 if (t == '(') {
2691 /* cast ? */
2692 if (t = ist()) {
2693 ft = type_decl(&n, t, TYPE_ABSTRACT);
2694 skip(')');
2695 /* check ISOC99 compound literal */
2696 if (tok == '{') {
2697 /* data is allocated locally by default */
2698 if (global_expr)
2699 ft |= VT_CONST;
2700 else
2701 ft |= VT_LOCAL;
2702 /* all except arrays are lvalues */
2703 if (!(ft & VT_ARRAY))
2704 ft |= VT_LVAL;
2705 fc = decl_initializer_alloc(ft, 1);
2706 vset(ft, fc);
2707 } else {
2708 unary();
2709 gen_cast(ft);
2711 } else {
2712 expr();
2713 skip(')');
2715 } else if (t == '*') {
2716 unary();
2717 indir();
2718 } else if (t == '&') {
2719 unary();
2720 /* functions names must be treated as function pointers,
2721 except for unary '&' and sizeof. Since we consider that
2722 functions are not lvalues, we only have to handle it
2723 there and in function calls. */
2724 if ((vt & VT_BTYPE) != VT_FUNC)
2725 test_lvalue();
2726 vt = mk_pointer(vt & VT_LVALN);
2727 } else
2728 if (t == '!') {
2729 unary();
2730 if ((vt & (VT_VALMASK | VT_LVAL)) == VT_CONST)
2731 vc = !vc;
2732 else if ((vt & VT_VALMASK) == VT_CMP)
2733 vc = vc ^ 1;
2734 else
2735 vset(VT_JMP, gtst(1, 0));
2736 } else
2737 if (t == '~') {
2738 unary();
2739 vpush();
2740 vset(VT_CONST, -1);
2741 gen_op('^');
2742 } else
2743 if (t == '+') {
2744 unary();
2745 } else
2746 if (t == TOK_SIZEOF) {
2747 /* XXX: some code can be generated */
2748 if (tok == '(') {
2749 next();
2750 if (t = ist())
2751 vt = type_decl(&n, t, TYPE_ABSTRACT);
2752 else
2753 expr();
2754 skip(')');
2755 } else {
2756 unary();
2758 vset(VT_CONST, type_size(vt, &t));
2759 } else
2760 if (t == TOK_INC | t == TOK_DEC) {
2761 unary();
2762 inc(0, t);
2763 } else if (t == '-') {
2764 vset(VT_CONST, 0);
2765 vpush();
2766 unary();
2767 gen_op('-');
2768 } else
2770 s = sym_find(t);
2771 if (!s) {
2772 if (tok != '(')
2773 error("'%s' undeclared", get_tok_str(t, 0));
2774 /* for simple function calls, we tolerate undeclared
2775 external reference */
2776 p = anon_sym++;
2777 sym_push1(&global_stack, p, 0, FUNC_OLD);
2778 /* int() function */
2779 s = external_sym(t, VT_FUNC | (p << VT_STRUCT_SHIFT));
2781 vset(s->t, s->c);
2782 /* if forward reference, we must point to s */
2783 if (vt & VT_FORWARD)
2784 vc = (int)s;
2788 /* post operations */
2789 while (1) {
2790 if (tok == TOK_INC | tok == TOK_DEC) {
2791 inc(1, tok);
2792 next();
2793 } else if (tok == '.' | tok == TOK_ARROW) {
2794 /* field */
2795 if (tok == TOK_ARROW)
2796 indir();
2797 test_lvalue();
2798 vt &= VT_LVALN;
2799 next();
2800 /* expect pointer on structure */
2801 if ((vt & VT_BTYPE) != VT_STRUCT)
2802 expect("struct or union");
2803 s = sym_find(((unsigned)vt >> VT_STRUCT_SHIFT) | SYM_STRUCT);
2804 /* find field */
2805 tok |= SYM_FIELD;
2806 while (s = s->next) {
2807 if (s->v == tok)
2808 break;
2810 if (!s)
2811 error("field not found");
2812 /* add field offset to pointer */
2813 vt = (vt & ~VT_TYPE) | VT_INT; /* change type to int */
2814 vpush();
2815 vset(VT_CONST, s->c);
2816 gen_op('+');
2817 /* change type to field type, and set to lvalue */
2818 vt = (vt & ~VT_TYPE) | s->t;
2819 /* an array is never an lvalue */
2820 if (!(vt & VT_ARRAY))
2821 vt |= VT_LVAL;
2822 next();
2823 } else if (tok == '[') {
2824 next();
2825 vpush();
2826 expr();
2827 gen_op('+');
2828 indir();
2829 skip(']');
2830 } else if (tok == '(') {
2831 int rett, retc;
2833 /* function call */
2834 if ((vt & VT_BTYPE) != VT_FUNC) {
2835 /* pointer test (no array accepted) */
2836 if ((vt & (VT_BTYPE | VT_ARRAY)) == VT_PTR) {
2837 vt = pointed_type(vt);
2838 if ((vt & VT_BTYPE) != VT_FUNC)
2839 goto error_func;
2840 } else {
2841 error_func:
2842 expect("function pointer");
2844 } else {
2845 vt &= ~VT_LVAL; /* no lvalue */
2848 /* get return type */
2849 s = sym_find((unsigned)vt >> VT_STRUCT_SHIFT);
2850 vpush(); /* push function address */
2851 save_regs(); /* save used temporary registers */
2852 gfunc_start(&gf);
2853 next();
2854 #ifdef INVERT_FUNC_PARAMS
2856 int *str, len, parlevel, *saved_macro_ptr;
2857 Sym *args, *s1;
2859 /* read each argument and store it on a stack */
2860 /* XXX: merge it with macro args ? */
2861 args = NULL;
2862 while (tok != ')') {
2863 len = 0;
2864 str = NULL;
2865 parlevel = 0;
2866 while ((parlevel > 0 || (tok != ')' && tok != ',')) &&
2867 tok != -1) {
2868 if (tok == '(')
2869 parlevel++;
2870 else if (tok == ')')
2871 parlevel--;
2872 tok_add2(&str, &len, tok, tokc);
2873 next();
2875 tok_add(&str, &len, -1); /* end of file added */
2876 tok_add(&str, &len, 0);
2877 sym_push2(&args, 0, 0, (int)str);
2878 if (tok != ',')
2879 break;
2880 next();
2882 if (tok != ')')
2883 expect(")");
2885 /* now generate code in reverse order by reading the stack */
2886 saved_macro_ptr = macro_ptr;
2887 while (args) {
2888 macro_ptr = (int *)args->c;
2889 next();
2890 expr_eq();
2891 if (tok != -1)
2892 expect("',' or ')'");
2893 gfunc_param(&gf);
2894 s1 = args->prev;
2895 free((int *)args->c);
2896 free(args);
2897 args = s1;
2899 macro_ptr = saved_macro_ptr;
2900 /* restore token */
2901 tok = ')';
2903 #endif
2904 /* compute first implicit argument if a structure is returned */
2905 if ((s->t & VT_BTYPE) == VT_STRUCT) {
2906 /* get some space for the returned structure */
2907 size = type_size(s->t, &align);
2908 loc = (loc - size) & -align;
2909 rett = s->t | VT_LOCAL | VT_LVAL;
2910 /* pass it as 'int' to avoid structure arg passing
2911 problems */
2912 vset(VT_INT | VT_LOCAL, loc);
2913 retc = vc;
2914 gfunc_param(&gf);
2915 } else {
2916 rett = s->t | FUNC_RET_REG; /* return in register */
2917 retc = 0;
2919 #ifndef INVERT_FUNC_PARAMS
2920 while (tok != ')') {
2921 expr_eq();
2922 gfunc_param(&gf);
2923 if (tok == ',')
2924 next();
2926 #endif
2927 skip(')');
2928 vpop(&vt, &vc);
2929 gfunc_call(&gf);
2930 /* return value */
2931 vt = rett;
2932 vc = retc;
2933 } else {
2934 break;
2939 int is_compatible_types(int t1, int t2)
2941 Sym *s1, *s2;
2942 int bt1, bt2;
2944 t1 &= VT_TYPE;
2945 t2 &= VT_TYPE;
2946 bt1 = t1 & VT_BTYPE;
2947 bt2 = t2 & VT_BTYPE;
2948 if (bt1 == VT_PTR) {
2949 t1 = pointed_type(t1);
2950 /* if function, then convert implictely to function pointer */
2951 if (bt2 != VT_FUNC) {
2952 if (bt2 != VT_PTR)
2953 return 0;
2954 t2 = pointed_type(t2);
2956 /* void matches everything */
2957 t1 &= VT_TYPE;
2958 t2 &= VT_TYPE;
2959 if (t1 == VT_VOID || t2 == VT_VOID)
2960 return 1;
2961 return is_compatible_types(t1, t2);
2962 } else if (bt1 == VT_STRUCT) {
2963 return (t2 == t1);
2964 } else if (bt1 == VT_FUNC) {
2965 if (bt2 != VT_FUNC)
2966 return 0;
2967 s1 = sym_find(((unsigned)t1 >> VT_STRUCT_SHIFT));
2968 s2 = sym_find(((unsigned)t2 >> VT_STRUCT_SHIFT));
2969 if (!is_compatible_types(s1->t, s2->t))
2970 return 0;
2971 /* XXX: not complete */
2972 if (s1->c == FUNC_OLD || s2->c == FUNC_OLD)
2973 return 1;
2974 if (s1->c != s2->c)
2975 return 0;
2976 while (s1 != NULL) {
2977 if (s2 == NULL)
2978 return 0;
2979 if (!is_compatible_types(s1->t, s2->t))
2980 return 0;
2981 s1 = s1->next;
2982 s2 = s2->next;
2984 if (s2)
2985 return 0;
2986 return 1;
2987 } else {
2988 /* XXX: not complete */
2989 return 1;
2993 int check_assign_types(int t1, int t2)
2995 t1 &= VT_TYPE;
2996 t2 &= VT_TYPE;
2997 if ((t1 & VT_BTYPE) == VT_PTR &&
2998 (t2 & VT_BTYPE) == VT_FUNC) {
2999 return is_compatible_types(pointed_type(t1), t2);
3000 } else {
3001 return is_compatible_types(t1, t2);
3006 void uneq()
3008 int t;
3010 unary();
3011 if (tok == '=' |
3012 (tok >= TOK_A_MOD & tok <= TOK_A_DIV) |
3013 tok == TOK_A_XOR | tok == TOK_A_OR |
3014 tok == TOK_A_SHL | tok == TOK_A_SAR) {
3015 test_lvalue();
3016 vpush();
3017 t = tok;
3018 next();
3019 if (t == '=') {
3020 expr_eq();
3021 if (!check_assign_types(vstack_ptr[-2], vt))
3022 warning("incompatible types");
3023 } else {
3024 vpush();
3025 expr_eq();
3026 gen_op(t & 0x7f);
3028 vstore();
3032 void sum(l)
3034 int t;
3036 if (l == 0)
3037 uneq();
3038 else {
3039 sum(--l);
3040 while ((l == 0 & (tok == '*' | tok == '/' | tok == '%')) |
3041 (l == 1 & (tok == '+' | tok == '-')) |
3042 (l == 2 & (tok == TOK_SHL | tok == TOK_SAR)) |
3043 (l == 3 & ((tok >= TOK_ULE & tok <= TOK_GT) |
3044 tok == TOK_ULT | tok == TOK_UGE)) |
3045 (l == 4 & (tok == TOK_EQ | tok == TOK_NE)) |
3046 (l == 5 & tok == '&') |
3047 (l == 6 & tok == '^') |
3048 (l == 7 & tok == '|') |
3049 (l == 8 & tok == TOK_LAND) |
3050 (l == 9 & tok == TOK_LOR)) {
3051 vpush();
3052 t = tok;
3053 next();
3054 sum(l);
3055 gen_op(t);
3060 /* only used if non constant */
3061 void eand(void)
3063 int t;
3065 sum(8);
3066 t = 0;
3067 while (1) {
3068 if (tok != TOK_LAND) {
3069 if (t) {
3070 t = gtst(1, t);
3071 vset(VT_JMPI, t);
3073 break;
3075 t = gtst(1, t);
3076 next();
3077 sum(8);
3081 void eor(void)
3083 int t;
3085 eand();
3086 t = 0;
3087 while (1) {
3088 if (tok != TOK_LOR) {
3089 if (t) {
3090 t = gtst(0, t);
3091 vset(VT_JMP, t);
3093 break;
3095 t = gtst(0, t);
3096 next();
3097 eand();
3101 /* XXX: better constant handling */
3102 void expr_eq()
3104 int t, u, c, r1, r2;
3106 if (const_wanted) {
3107 sum(10);
3108 if (tok == '?') {
3109 c = vc;
3110 next();
3111 expr();
3112 t = vc;
3113 skip(':');
3114 expr_eq();
3115 if (c)
3116 vc = t;
3118 } else {
3119 eor();
3120 if (tok == '?') {
3121 next();
3122 t = gtst(1, 0);
3123 expr();
3124 r1 = gv();
3125 skip(':');
3126 u = gjmp(0);
3127 gsym(t);
3128 expr_eq();
3129 r2 = gv();
3130 move_reg(r1, r2);
3131 vt = (vt & VT_TYPE) | r1;
3132 gsym(u);
3137 void expr()
3139 while (1) {
3140 expr_eq();
3141 if (tok != ',')
3142 break;
3143 next();
3147 int expr_const()
3149 int a;
3150 a = const_wanted;
3151 const_wanted = 1;
3152 expr_eq();
3153 if ((vt & (VT_CONST | VT_LVAL)) != VT_CONST)
3154 expect("constant");
3155 const_wanted = a;
3156 return vc;
3159 /* return the label token if current token is a label, otherwise
3160 return zero */
3161 int is_label(void)
3163 int t, c;
3165 /* fast test first */
3166 if (tok < TOK_UIDENT)
3167 return 0;
3168 t = tok;
3169 c = tokc;
3170 next();
3171 if (tok == ':') {
3172 next();
3173 return t;
3174 } else {
3175 /* XXX: may not work in all cases (macros ?) */
3176 tok1 = tok;
3177 tok1c = tokc;
3178 tok = t;
3179 tokc = c;
3180 return 0;
3184 void block(int *bsym, int *csym, int *case_sym, int *def_sym, int case_reg)
3186 int a, b, c, d;
3187 Sym *s;
3189 if (tok == TOK_IF) {
3190 /* if test */
3191 next();
3192 skip('(');
3193 expr();
3194 skip(')');
3195 a = gtst(1, 0);
3196 block(bsym, csym, case_sym, def_sym, case_reg);
3197 c = tok;
3198 if (c == TOK_ELSE) {
3199 next();
3200 d = gjmp(0);
3201 gsym(a);
3202 block(bsym, csym, case_sym, def_sym, case_reg);
3203 gsym(d); /* patch else jmp */
3204 } else
3205 gsym(a);
3206 } else if (tok == TOK_WHILE) {
3207 next();
3208 d = ind;
3209 skip('(');
3210 expr();
3211 skip(')');
3212 a = gtst(1, 0);
3213 b = 0;
3214 block(&a, &b, case_sym, def_sym, case_reg);
3215 oad(0xe9, d - ind - 5); /* jmp */
3216 gsym(a);
3217 gsym_addr(b, d);
3218 } else if (tok == '{') {
3219 next();
3220 /* declarations */
3221 s = local_stack.top;
3222 while (tok != '}') {
3223 decl(VT_LOCAL);
3224 if (tok != '}')
3225 block(bsym, csym, case_sym, def_sym, case_reg);
3227 /* pop locally defined symbols */
3228 sym_pop(&local_stack, s);
3229 next();
3230 } else if (tok == TOK_RETURN) {
3231 next();
3232 if (tok != ';') {
3233 if ((func_vt & VT_BTYPE) == VT_STRUCT) {
3234 /* if returning structure, must copy it to implicit
3235 first pointer arg location */
3236 vset(mk_pointer(func_vt) | VT_LOCAL | VT_LVAL, func_vc);
3237 indir();
3238 vpush();
3240 expr();
3241 if ((func_vt & VT_BTYPE) == VT_STRUCT) {
3242 /* copy structure value to pointer */
3243 vstore();
3244 } else {
3245 /* move return value to standard return register */
3246 move_reg(FUNC_RET_REG, gv());
3249 skip(';');
3250 rsym = gjmp(rsym); /* jmp */
3251 } else if (tok == TOK_BREAK) {
3252 /* compute jump */
3253 if (!bsym)
3254 error("cannot break");
3255 *bsym = gjmp(*bsym);
3256 next();
3257 skip(';');
3258 } else if (tok == TOK_CONTINUE) {
3259 /* compute jump */
3260 if (!csym)
3261 error("cannot continue");
3262 *csym = gjmp(*csym);
3263 next();
3264 skip(';');
3265 } else if (tok == TOK_FOR) {
3266 int e;
3267 next();
3268 skip('(');
3269 if (tok != ';')
3270 expr();
3271 skip(';');
3272 d = ind;
3273 c = ind;
3274 a = 0;
3275 b = 0;
3276 if (tok != ';') {
3277 expr();
3278 a = gtst(1, 0);
3280 skip(';');
3281 if (tok != ')') {
3282 e = gjmp(0);
3283 c = ind;
3284 expr();
3285 oad(0xe9, d - ind - 5); /* jmp */
3286 gsym(e);
3288 skip(')');
3289 block(&a, &b, case_sym, def_sym, case_reg);
3290 oad(0xe9, c - ind - 5); /* jmp */
3291 gsym(a);
3292 gsym_addr(b, c);
3293 } else
3294 if (tok == TOK_DO) {
3295 next();
3296 a = 0;
3297 b = 0;
3298 d = ind;
3299 block(&a, &b, case_sym, def_sym, case_reg);
3300 skip(TOK_WHILE);
3301 skip('(');
3302 gsym(b);
3303 expr();
3304 c = gtst(0, 0);
3305 gsym_addr(c, d);
3306 skip(')');
3307 gsym(a);
3308 skip(';');
3309 } else
3310 if (tok == TOK_SWITCH) {
3311 next();
3312 skip('(');
3313 expr();
3314 case_reg = gv();
3315 skip(')');
3316 a = 0;
3317 b = gjmp(0); /* jump to first case */
3318 c = 0;
3319 block(&a, csym, &b, &c, case_reg);
3320 /* if no default, jmp after switch */
3321 if (c == 0)
3322 c = ind;
3323 /* default label */
3324 gsym_addr(b, c);
3325 /* break label */
3326 gsym(a);
3327 } else
3328 if (tok == TOK_CASE) {
3329 next();
3330 a = expr_const();
3331 if (!case_sym)
3332 expect("switch");
3333 /* since a case is like a label, we must skip it with a jmp */
3334 b = gjmp(0);
3335 gsym(*case_sym);
3336 vset(case_reg, 0);
3337 vpush();
3338 vset(VT_CONST, a);
3339 gen_op(TOK_EQ);
3340 *case_sym = gtst(1, 0);
3341 gsym(b);
3342 skip(':');
3343 block(bsym, csym, case_sym, def_sym, case_reg);
3344 } else
3345 if (tok == TOK_DEFAULT) {
3346 next();
3347 skip(':');
3348 if (!def_sym)
3349 expect("switch");
3350 if (*def_sym)
3351 error("too many 'default'");
3352 *def_sym = ind;
3353 block(bsym, csym, case_sym, def_sym, case_reg);
3354 } else
3355 if (tok == TOK_GOTO) {
3356 next();
3357 s = sym_find1(&label_stack, tok);
3358 /* put forward definition if needed */
3359 if (!s)
3360 s = sym_push1(&label_stack, tok, VT_FORWARD, 0);
3361 /* label already defined */
3362 if (s->t & VT_FORWARD)
3363 s->c = gjmp(s->c); /* jmp xxx */
3364 else
3365 oad(0xe9, s->c - ind - 5); /* jmp xxx */
3366 next();
3367 skip(';');
3368 } else {
3369 b = is_label();
3370 if (b) {
3371 /* label case */
3372 s = sym_find1(&label_stack, b);
3373 if (s) {
3374 if (!(s->t & VT_FORWARD))
3375 error("multiple defined label");
3376 gsym(s->c);
3377 s->c = ind;
3378 s->t = 0;
3379 } else {
3380 sym_push1(&label_stack, b, 0, ind);
3382 /* we accept this, but it is a mistake */
3383 if (tok == '}')
3384 warning("deprecated use of label at end of compound statement");
3385 else
3386 block(bsym, csym, case_sym, def_sym, case_reg);
3387 } else {
3388 /* expression case */
3389 if (tok != ';') {
3390 expr();
3392 skip(';');
3397 /* t is the array or struct type. c is the array or struct
3398 address. cur_index/cur_field is the pointer to the current
3399 value. 'size_only' is true if only size info is needed (only used
3400 in arrays) */
3401 void decl_designator(int t, int c,
3402 int *cur_index, Sym **cur_field,
3403 int size_only)
3405 Sym *s, *f;
3406 int notfirst, index, align, l;
3408 notfirst = 0;
3409 if (gnu_ext && (l = is_label()) != 0)
3410 goto struct_field;
3412 while (tok == '[' || tok == '.') {
3413 if (tok == '[') {
3414 if (!(t & VT_ARRAY))
3415 expect("array type");
3416 s = sym_find(((unsigned)t >> VT_STRUCT_SHIFT));
3417 next();
3418 index = expr_const();
3419 if (index < 0 || (s->c >= 0 && index >= s->c))
3420 expect("invalid index");
3421 skip(']');
3422 if (!notfirst)
3423 *cur_index = index;
3424 t = pointed_type(t);
3425 c += index * type_size(t, &align);
3426 } else {
3427 next();
3428 l = tok;
3429 next();
3430 struct_field:
3431 if ((t & VT_BTYPE) != VT_STRUCT)
3432 expect("struct/union type");
3433 s = sym_find(((unsigned)t >> VT_STRUCT_SHIFT) | SYM_STRUCT);
3434 l |= SYM_FIELD;
3435 f = s->next;
3436 while (f) {
3437 if (f->v == l)
3438 break;
3439 f = f->next;
3441 if (!f)
3442 expect("field");
3443 if (!notfirst)
3444 *cur_field = f;
3445 t = f->t | (t & ~VT_TYPE);
3446 c += f->c;
3448 notfirst = 1;
3450 if (notfirst) {
3451 if (tok == '=') {
3452 next();
3453 } else {
3454 if (!gnu_ext)
3455 expect("=");
3457 } else {
3458 if (t & VT_ARRAY) {
3459 index = *cur_index;
3460 t = pointed_type(t);
3461 c += index * type_size(t, &align);
3462 } else {
3463 f = *cur_field;
3464 if (!f)
3465 error("too many field init");
3466 t = f->t | (t & ~VT_TYPE);
3467 c += f->c;
3470 decl_initializer(t, c, 0, size_only);
3473 /* store a value or an expression directly in global data or in local array */
3475 void init_putv(int t, int c, int v, int is_expr)
3477 int saved_global_expr;
3479 if ((t & VT_VALMASK) == VT_CONST) {
3480 if (is_expr) {
3481 /* compound literals must be allocated globally in this case */
3482 saved_global_expr = global_expr;
3483 global_expr = 1;
3484 v = expr_const();
3485 global_expr = saved_global_expr;
3487 if ((t & VT_BTYPE) == VT_BYTE)
3488 *(char *)c = v;
3489 else if ((t & VT_BTYPE) == VT_SHORT)
3490 *(short *)c = v;
3491 else
3492 *(int *)c = v;
3493 } else {
3494 vt = t;
3495 vc = c;
3496 vpush();
3497 if (is_expr)
3498 expr_eq();
3499 else
3500 vset(VT_CONST, v);
3501 vstore();
3505 /* put zeros for variable based init */
3506 void init_putz(int t, int c, int size)
3508 GFuncContext gf;
3510 if ((t & VT_VALMASK) == VT_CONST) {
3511 /* nothing to do because global are already set to zero */
3512 } else {
3513 gfunc_start(&gf);
3514 vset(VT_CONST, size);
3515 gfunc_param(&gf);
3516 vset(VT_CONST, 0);
3517 gfunc_param(&gf);
3518 vset(VT_LOCAL, c);
3519 gfunc_param(&gf);
3520 vset(VT_CONST, (int)&memset);
3521 gfunc_call(&gf);
3525 /* 't' contains the type and storage info. c is the address of the
3526 object. 'first' is true if array '{' must be read (multi dimension
3527 implicit array init handling). 'size_only' is true if size only
3528 evaluation is wanted (only for arrays). */
3529 void decl_initializer(int t, int c, int first, int size_only)
3531 int index, array_length, n, no_oblock, nb, parlevel, i;
3532 int t1, size1, align1;
3533 Sym *s, *f;
3534 TokenSym *ts;
3536 if (t & VT_ARRAY) {
3537 s = sym_find(((unsigned)t >> VT_STRUCT_SHIFT));
3538 n = s->c;
3539 array_length = 0;
3540 t1 = pointed_type(t);
3541 size1 = type_size(t1, &align1);
3543 no_oblock = 1;
3544 if ((first && tok != TOK_LSTR && tok != TOK_STR) ||
3545 tok == '{') {
3546 skip('{');
3547 no_oblock = 0;
3550 /* only parse strings here if correct type (otherwise: handle
3551 them as ((w)char *) expressions */
3552 if ((tok == TOK_LSTR &&
3553 (t1 & VT_BTYPE) == VT_INT) ||
3554 (tok == TOK_STR &&
3555 (t1 & VT_BTYPE) == VT_BYTE)) {
3556 /* XXX: move multiple string parsing in parser ? */
3557 while (tok == TOK_STR || tok == TOK_LSTR) {
3558 ts = (TokenSym *)tokc;
3559 /* compute maximum number of chars wanted */
3560 nb = ts->len;
3561 if (n >= 0 && nb > (n - array_length))
3562 nb = n - array_length;
3563 if (!size_only) {
3564 if (ts->len > nb)
3565 warning("initializer-string for array is too long");
3566 for(i=0;i<nb;i++) {
3567 init_putv(t1, c + (array_length + i) * size1,
3568 ts->str[i], 0);
3571 array_length += nb;
3572 next();
3574 /* only add trailing zero if enough storage (no
3575 warning in this case since it is standard) */
3576 if (n < 0 || array_length < n) {
3577 if (!size_only) {
3578 init_putv(t1, c + (array_length * size1), 0, 0);
3580 array_length++;
3582 } else {
3583 index = 0;
3584 while (tok != '}') {
3585 decl_designator(t, c, &index, NULL, size_only);
3586 if (n >= 0 && index >= n)
3587 error("index too large");
3588 /* must put zero in holes (note that doing it that way
3589 ensures that it even works with designators) */
3590 if (!size_only && array_length < index) {
3591 init_putz(t1, c + array_length * size1,
3592 (index - array_length) * size1);
3594 index++;
3595 if (index > array_length)
3596 array_length = index;
3597 /* special test for multi dimensional arrays (may not
3598 be strictly correct if designators are used at the
3599 same time) */
3600 if (index >= n && no_oblock)
3601 break;
3602 if (tok == '}')
3603 break;
3604 skip(',');
3607 if (!no_oblock)
3608 skip('}');
3609 /* put zeros at the end */
3610 if (!size_only && n >= 0 && array_length < n) {
3611 init_putz(t1, c + array_length * size1,
3612 (n - array_length) * size1);
3614 /* patch type size if needed */
3615 if (n < 0)
3616 s->c = array_length;
3617 } else if ((t & VT_BTYPE) == VT_STRUCT && tok == '{') {
3618 /* XXX: union needs only one init */
3619 next();
3620 s = sym_find(((unsigned)t >> VT_STRUCT_SHIFT) | SYM_STRUCT);
3621 f = s->next;
3622 array_length = 0;
3623 index = 0;
3624 n = s->c;
3625 while (tok != '}') {
3626 decl_designator(t, c, NULL, &f, size_only);
3627 /* fill with zero between fields */
3628 index = f->c;
3629 if (!size_only && array_length < index) {
3630 init_putz(t, c + array_length,
3631 index - array_length);
3633 index = index + type_size(f->t, &align1);
3634 if (index > array_length)
3635 array_length = index;
3636 if (tok == '}')
3637 break;
3638 skip(',');
3639 f = f->next;
3641 /* put zeros at the end */
3642 if (!size_only && array_length < n) {
3643 init_putz(t, c + array_length,
3644 n - array_length);
3646 skip('}');
3647 } else if (tok == '{') {
3648 next();
3649 decl_initializer(t, c, first, size_only);
3650 skip('}');
3651 } else if (size_only) {
3652 /* just skip expression */
3653 parlevel = 0;
3654 while ((parlevel > 0 || (tok != '}' && tok != ',')) &&
3655 tok != -1) {
3656 if (tok == '(')
3657 parlevel++;
3658 else if (tok == ')')
3659 parlevel--;
3660 next();
3662 } else {
3663 init_putv(t, c, 0, 1);
3667 /* parse an initializer for type 't' if 'has_init' is true, and
3668 allocate space in local or global data space. The allocated address
3669 in returned */
3670 int decl_initializer_alloc(int t, int has_init)
3672 int size, align, addr, tok1;
3673 int *init_str, init_len, level, *saved_macro_ptr;
3675 size = type_size(t, &align);
3676 /* If unknown size, we must evaluate it before
3677 evaluating initializers because
3678 initializers can generate global data too
3679 (e.g. string pointers or ISOC99 compound
3680 literals). It also simplifies local
3681 initializers handling */
3682 init_len = 0;
3683 init_str = NULL;
3684 saved_macro_ptr = NULL; /* avoid warning */
3685 tok1 = 0;
3686 if (size < 0) {
3687 if (!has_init)
3688 error("unknown type size");
3689 /* get all init string */
3690 level = 0;
3691 while (level > 0 || (tok != ',' && tok != ';')) {
3692 if (tok < 0)
3693 error("unexpect end of file in initializer");
3694 tok_add2(&init_str, &init_len, tok, tokc);
3695 if (tok == '{')
3696 level++;
3697 else if (tok == '}') {
3698 if (level == 0)
3699 break;
3700 level--;
3702 next();
3704 tok1 = tok;
3705 tok_add(&init_str, &init_len, -1);
3706 tok_add(&init_str, &init_len, 0);
3708 /* compute size */
3709 saved_macro_ptr = macro_ptr;
3710 macro_ptr = init_str;
3711 next();
3712 decl_initializer(t, 0, 1, 1);
3713 /* prepare second initializer parsing */
3714 macro_ptr = init_str;
3715 next();
3717 /* if still unknown size, error */
3718 size = type_size(t, &align);
3719 if (size < 0)
3720 error("unknown type size");
3722 if ((t & VT_VALMASK) == VT_LOCAL) {
3723 loc = (loc - size) & -align;
3724 addr = loc;
3725 } else {
3726 glo = (glo + align - 1) & -align;
3727 addr = glo;
3728 /* very important to increment global
3729 pointer at this time because
3730 initializers themselves can create new
3731 initializers */
3732 glo += size;
3734 if (has_init) {
3735 decl_initializer(t, addr, 1, 0);
3736 /* restore parse state if needed */
3737 if (init_str) {
3738 free(init_str);
3739 macro_ptr = saved_macro_ptr;
3740 tok = tok1;
3743 return addr;
3747 /* 'l' is VT_LOCAL or VT_CONST to define default storage type */
3748 void decl(int l)
3750 int *a, t, b, v, u, addr, has_init, size, align;
3751 Sym *sym;
3753 while (1) {
3754 b = ist();
3755 if (!b) {
3756 /* skip redundant ';' */
3757 /* XXX: find more elegant solution */
3758 if (tok == ';') {
3759 next();
3760 continue;
3762 /* special test for old K&R protos without explicit int
3763 type. Only accepted when defining global data */
3764 if (l == VT_LOCAL || tok < TOK_DEFINE)
3765 break;
3766 b = VT_INT;
3768 if (((b & VT_BTYPE) == VT_ENUM ||
3769 (b & VT_BTYPE) == VT_STRUCT) &&
3770 tok == ';') {
3771 /* we accept no variable after */
3772 next();
3773 continue;
3775 while (1) { /* iterate thru each declaration */
3776 t = type_decl(&v, b, TYPE_DIRECT);
3777 if (tok == '{') {
3778 if (l == VT_LOCAL)
3779 error("cannot use local functions");
3780 if (!(t & VT_FUNC))
3781 expect("function definition");
3782 /* patch forward references */
3783 if ((sym = sym_find(v)) && (sym->t & VT_FORWARD)) {
3784 greloc_patch(sym, ind);
3785 sym->t = VT_CONST | t;
3786 } else {
3787 /* put function address */
3788 sym_push1(&global_stack, v, VT_CONST | t, ind);
3790 funcname = get_tok_str(v, 0);
3791 /* push a dummy symbol to enable local sym storage */
3792 sym_push1(&local_stack, 0, 0, 0);
3793 /* define parameters */
3794 sym = sym_find((unsigned)t >> VT_STRUCT_SHIFT);
3795 /* XXX: the following is x86 dependant -> move it to
3796 x86 code gen */
3797 addr = 8;
3798 /* if the function returns a structure, then add an
3799 implicit pointer parameter */
3800 func_vt = sym->t;
3801 if ((func_vt & VT_BTYPE) == VT_STRUCT) {
3802 func_vc = addr;
3803 addr += 4;
3805 while (sym = sym->next) {
3806 u = sym->t;
3807 sym_push(sym->v & ~SYM_FIELD,
3808 u | VT_LOCAL | VT_LVAL,
3809 addr);
3810 if ((u & VT_BTYPE) == VT_STRUCT) {
3811 #ifdef FUNC_STRUCT_PARAM_AS_PTR
3812 /* structs are passed as pointer */
3813 size = 4;
3814 #else
3815 /* structs are directly put on stack (x86
3816 like) */
3817 size = type_size(u, &align);
3818 size = (size + 3) & ~3;
3819 #endif
3820 } else {
3821 /* XXX: size will be different someday */
3822 size = 4;
3824 addr += size;
3826 loc = 0;
3827 o(0xe58955); /* push %ebp, mov %esp, %ebp */
3828 a = (int *)oad(0xec81, 0); /* sub $xxx, %esp */
3829 rsym = 0;
3830 block(0, 0, 0, 0, 0);
3831 gsym(rsym);
3832 o(0xc3c9); /* leave, ret */
3833 *a = (-loc + 3) & -4; /* align local size to word &
3834 save local variables */
3835 sym_pop(&label_stack, 0); /* reset label stack */
3836 sym_pop(&local_stack, 0); /* reset local stack */
3837 funcname = ""; /* for safety */
3838 func_vt = VT_VOID; /* for safety */
3839 break;
3840 } else {
3841 if (b & VT_TYPEDEF) {
3842 /* save typedefed type */
3843 /* XXX: test storage specifiers ? */
3844 sym_push(v, t | VT_TYPEDEF, 0);
3845 } else if ((t & VT_BTYPE) == VT_FUNC) {
3846 /* external function definition */
3847 external_sym(v, t);
3848 } else {
3849 /* not lvalue if array */
3850 if (!(t & VT_ARRAY))
3851 t |= VT_LVAL;
3852 if (b & VT_EXTERN) {
3853 /* external variable */
3854 external_sym(v, t);
3855 } else {
3856 u = l;
3857 if (t & VT_STATIC)
3858 u = VT_CONST;
3859 u |= t;
3860 has_init = (tok == '=');
3861 if (has_init)
3862 next();
3863 addr = decl_initializer_alloc(u, has_init);
3864 if (l == VT_CONST) {
3865 /* global scope: see if already defined */
3866 sym = sym_find(v);
3867 if (!sym)
3868 goto do_def;
3869 if (!is_compatible_types(sym->t, u))
3870 error("incompatible types for redefinition of '%s'",
3871 get_tok_str(v, 0));
3872 if (!(sym->t & VT_FORWARD))
3873 error("redefinition of '%s'", get_tok_str(v, 0));
3874 greloc_patch(sym, addr);
3875 } else {
3876 do_def:
3877 sym_push(v, u, addr);
3881 if (tok != ',') {
3882 skip(';');
3883 break;
3885 next();
3891 /* put all global symbols in the extern stack and do all the
3892 resolving which can be done without using external symbols from DLLs */
3893 /* XXX: could try to verify types, but would not to save them in
3894 extern_stack too */
3895 void resolve_global_syms(void)
3897 Sym *s, *s1, *ext_sym;
3898 Reloc **p;
3900 s = global_stack.top;
3901 while (s != NULL) {
3902 s1 = s->prev;
3903 /* do not save static or typedefed symbols or types */
3904 if (!(s->t & (VT_STATIC | VT_TYPEDEF)) &&
3905 !(s->v & (SYM_FIELD | SYM_STRUCT)) &&
3906 (s->v < SYM_FIRST_ANOM)) {
3907 ext_sym = sym_find1(&extern_stack, s->v);
3908 if (!ext_sym) {
3909 /* if the symbol do not exist, we simply save it */
3910 sym_push1(&extern_stack, s->v, s->t, s->c);
3911 } else if (ext_sym->t & VT_FORWARD) {
3912 /* external symbol already exists, but only as forward
3913 definition */
3914 if (!(s->t & VT_FORWARD)) {
3915 /* s is not forward, so we can relocate all symbols */
3916 greloc_patch(ext_sym, s->c);
3917 } else {
3918 /* the two symbols are forward: merge them */
3919 p = (Reloc **)&ext_sym->c;
3920 while (*p != NULL)
3921 p = &(*p)->next;
3922 *p = (Reloc *)s->c;
3924 } else {
3925 /* external symbol already exists and is defined :
3926 patch all references to it */
3927 if (!(s->t & VT_FORWARD))
3928 error("'%s' defined twice", get_tok_str(s->v, 0));
3929 greloc_patch(s, ext_sym->c);
3932 s = s1;
3936 /* compile a C file. Return non zero if errors. */
3937 int tcc_compile_file(const char *filename1)
3939 Sym *define_start;
3941 filename = (char *)filename1;
3943 line_num = 1;
3944 funcname = "";
3945 file = fopen(filename, "r");
3946 if (!file)
3947 error("file '%s' not found", filename);
3948 include_stack_ptr = include_stack;
3949 ifdef_stack_ptr = ifdef_stack;
3951 vstack_ptr = vstack;
3952 anon_sym = SYM_FIRST_ANOM;
3954 define_start = define_stack.top;
3955 inp();
3956 ch = '\n'; /* needed to parse correctly first preprocessor command */
3957 next();
3958 decl(VT_CONST);
3959 if (tok != -1)
3960 expect("declaration");
3961 fclose(file);
3963 /* reset define stack, but leave -Dsymbols (may be incorrect if
3964 they are undefined) */
3965 sym_pop(&define_stack, define_start);
3967 resolve_global_syms();
3969 sym_pop(&global_stack, NULL);
3971 return 0;
3974 /* open a dynamic library so that its symbol are available for
3975 compiled programs */
3976 void open_dll(char *libname)
3978 char buf[1024];
3979 void *h;
3981 snprintf(buf, sizeof(buf), "lib%s.so", libname);
3982 h = dlopen(buf, RTLD_GLOBAL | RTLD_LAZY);
3983 if (!h)
3984 error((char *)dlerror());
3987 void resolve_extern_syms(void)
3989 Sym *s, *s1;
3990 char *str;
3991 int addr;
3993 s = extern_stack.top;
3994 while (s != NULL) {
3995 s1 = s->prev;
3996 if (s->t & VT_FORWARD) {
3997 /* if there is at least one relocation to do, then find it
3998 and patch it */
3999 if (s->c) {
4000 str = get_tok_str(s->v, 0);
4001 addr = (int)dlsym(NULL, str);
4002 if (!addr)
4003 error("unresolved external reference '%s'", str);
4004 greloc_patch(s, addr);
4007 s = s1;
4011 /* output a binary file (for testing) */
4012 void build_exe(char *filename)
4014 FILE *f;
4015 f = fopen(filename, "w");
4016 fwrite((void *)prog, 1, ind - prog, f);
4017 fclose(f);
4020 int main(int argc, char **argv)
4022 Sym *s;
4023 int (*t)();
4024 char *p, *r, *outfile;
4025 int optind;
4027 include_paths[0] = "/usr/include";
4028 include_paths[1] = "/usr/lib/tcc";
4029 include_paths[2] = "/usr/local/lib/tcc";
4030 nb_include_paths = 3;
4032 /* add all tokens */
4033 tok_ident = TOK_IDENT;
4034 p = "int\0void\0char\0if\0else\0while\0break\0return\0for\0extern\0static\0unsigned\0goto\0do\0continue\0switch\0case\0const\0volatile\0long\0register\0signed\0auto\0inline\0restrict\0float\0double\0short\0struct\0union\0typedef\0default\0enum\0sizeof\0define\0include\0ifdef\0ifndef\0elif\0endif\0defined\0undef\0error\0line\0__LINE__\0__FILE__\0__DATE__\0__TIME__\0__VA_ARGS__\0__func__\0main\0";
4035 while (*p) {
4036 r = p;
4037 while (*r++);
4038 tok_alloc(p, r - p - 1);
4039 p = r;
4042 /* standard defines */
4043 define_symbol("__STDC__");
4044 #ifdef __i386__
4045 define_symbol("__i386__");
4046 #endif
4047 /* tiny C specific defines */
4048 define_symbol("__TINYC__");
4050 glo = (int)malloc(DATA_SIZE);
4051 memset((void *)glo, 0, DATA_SIZE);
4052 prog = (int)malloc(TEXT_SIZE);
4053 ind = prog;
4055 optind = 1;
4056 outfile = NULL;
4057 while (1) {
4058 if (optind >= argc) {
4059 show_help:
4060 printf("tcc version 0.9.1 - Tiny C Compiler - Copyright (C) 2001 Fabrice Bellard\n"
4061 "usage: tcc [-Idir] [-Dsym] [-llib] [-i infile]... infile [infile_args...]\n");
4062 return 1;
4064 r = argv[optind];
4065 if (r[0] != '-')
4066 break;
4067 optind++;
4068 if (r[1] == 'I') {
4069 if (nb_include_paths >= INCLUDE_PATHS_MAX)
4070 error("too many include paths");
4071 include_paths[nb_include_paths++] = r + 2;
4072 } else if (r[1] == 'D') {
4073 define_symbol(r + 2);
4074 } else if (r[1] == 'l') {
4075 open_dll(r + 2);
4076 } else if (r[1] == 'i') {
4077 if (optind >= argc)
4078 goto show_help;
4079 tcc_compile_file(argv[optind++]);
4080 } else if (r[1] == 'o') {
4081 /* currently, only for testing, so not documented */
4082 if (optind >= argc)
4083 goto show_help;
4084 outfile = argv[optind++];
4085 } else {
4086 fprintf(stderr, "invalid option -- '%s'\n", r);
4087 exit(1);
4091 tcc_compile_file(argv[optind]);
4093 resolve_extern_syms();
4095 if (outfile) {
4096 build_exe(outfile);
4097 return 0;
4098 } else {
4099 s = sym_find1(&extern_stack, TOK_MAIN);
4100 if (!s || (s->t & VT_FORWARD))
4101 error("main() not defined");
4102 t = (int (*)())s->c;
4103 return (*t)(argc - optind, argv + optind);