better type storage
[tinycc.git] / tcc.c
blob3b1dacf5a1383da7077e880e315a53f4ef8f599b
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);
446 /* expand token table if needed */
447 i = tok_ident - TOK_IDENT;
448 if ((i % TOK_ALLOC_INCR) == 0) {
449 ptable = realloc(table_ident, (i + TOK_ALLOC_INCR) * sizeof(TokenSym *));
450 if (!ptable)
451 error("memory full");
452 table_ident = ptable;
454 ts = malloc(sizeof(TokenSym) + len);
455 if (!ts || tok_ident >= SYM_FIRST_ANOM)
456 error("memory full");
457 table_ident[i] = ts;
458 ts->tok = tok_ident++;
459 ts->len = len;
460 ts->hash_next = NULL;
461 memcpy(ts->str, str, len + 1);
462 *pts = ts;
463 return ts;
466 void add_char(char **pp, int c)
468 char *p;
469 p = *pp;
470 if (c == '\'' || c == '\"' || c == '\\') {
471 /* XXX: could be more precise if char or string */
472 *p++ = '\\';
474 if (c >= 32 && c <= 126) {
475 *p++ = c;
476 } else {
477 *p++ = '\\';
478 if (c == '\n') {
479 *p++ = 'n';
480 } else {
481 *p++ = '0' + ((c >> 6) & 7);
482 *p++ = '0' + ((c >> 3) & 7);
483 *p++ = '0' + (c & 7);
486 *pp = p;
489 /* XXX: buffer overflow */
490 char *get_tok_str(int v, int c)
492 static char buf[STRING_MAX_SIZE + 1];
493 TokenSym *ts;
494 char *p;
495 int i;
497 if (v == TOK_NUM) {
498 sprintf(buf, "%d", c);
499 return buf;
500 } else if (v == TOK_CCHAR || v == TOK_LCHAR) {
501 p = buf;
502 *p++ = '\'';
503 add_char(&p, c);
504 *p++ = '\'';
505 *p = '\0';
506 return buf;
507 } else if (v == TOK_STR || v == TOK_LSTR) {
508 ts = (TokenSym *)c;
509 p = buf;
510 *p++ = '\"';
511 for(i=0;i<ts->len;i++)
512 add_char(&p, ts->str[i]);
513 *p++ = '\"';
514 *p = '\0';
515 return buf;
516 } else if (v < TOK_IDENT) {
517 p = buf;
518 *p++ = v;
519 *p = '\0';
520 return buf;
521 } else if (v < tok_ident) {
522 return table_ident[v - TOK_IDENT]->str;
523 } else {
524 /* should never happen */
525 return NULL;
529 /* push, without hashing */
530 Sym *sym_push2(Sym **ps, int v, int t, int c)
532 Sym *s;
533 s = malloc(sizeof(Sym));
534 if (!s)
535 error("memory full");
536 s->v = v;
537 s->t = t;
538 s->c = c;
539 s->next = NULL;
540 /* add in stack */
541 s->prev = *ps;
542 *ps = s;
543 return s;
546 /* find a symbol and return its associated structure. 's' is the top
547 of the symbol stack */
548 Sym *sym_find2(Sym *s, int v)
550 while (s) {
551 if (s->v == v)
552 return s;
553 s = s->prev;
555 return NULL;
558 /* find a symbol and return its associated structure. 'st' is the
559 symbol stack */
560 Sym *sym_find1(SymStack *st, int v)
562 Sym *s;
564 s = st->hash[v % SYM_HASH_SIZE];
565 while (s) {
566 if (s->v == v)
567 return s;
568 s = s->hash_next;
570 return 0;
573 Sym *sym_push1(SymStack *st, int v, int t, int c)
575 Sym *s, **ps;
576 s = sym_push2(&st->top, v, t, c);
577 /* add in hash table */
578 ps = &st->hash[s->v % SYM_HASH_SIZE];
579 s->hash_next = *ps;
580 *ps = s;
581 return s;
584 /* find a symbol in the right symbol space */
585 Sym *sym_find(int v)
587 Sym *s;
588 s = sym_find1(&local_stack, v);
589 if (!s)
590 s = sym_find1(&global_stack, v);
591 return s;
594 /* push a given symbol on the symbol stack */
595 Sym *sym_push(int v, int t, int c)
597 if (local_stack.top)
598 return sym_push1(&local_stack, v, t, c);
599 else
600 return sym_push1(&global_stack, v, t, c);
603 /* pop symbols until top reaches 'b' */
604 void sym_pop(SymStack *st, Sym *b)
606 Sym *s, *ss;
608 s = st->top;
609 while(s != b) {
610 ss = s->prev;
611 /* free hash table entry */
612 st->hash[s->v % SYM_HASH_SIZE] = s->hash_next;
613 free(s);
614 s = ss;
616 st->top = b;
619 /* undefined a hashed symbol (used for #undef). Its name is set to
620 zero */
621 void sym_undef(SymStack *st, Sym *s)
623 Sym **ss;
624 ss = &st->hash[s->v % SYM_HASH_SIZE];
625 while (*ss != NULL) {
626 if (*ss == s)
627 break;
628 ss = &(*ss)->hash_next;
630 *ss = s->hash_next;
631 s->v = 0;
634 /* no need to put that inline */
635 int handle_eof(void)
637 if (include_stack_ptr == include_stack)
638 return -1;
639 /* pop include stack */
640 fclose(file);
641 free(filename);
642 include_stack_ptr--;
643 file = include_stack_ptr->file;
644 filename = include_stack_ptr->filename;
645 line_num = include_stack_ptr->line_num;
646 return 0;
649 /* read next char from current input file */
650 static inline void inp(void)
652 redo:
653 /* faster than fgetc */
654 ch1 = getc_unlocked(file);
655 if (ch1 == -1) {
656 if (handle_eof() < 0)
657 return;
658 else
659 goto redo;
661 if (ch1 == '\n')
662 line_num++;
663 // printf("ch1=%c 0x%x\n", ch1, ch1);
666 /* input with '\\n' handling */
667 static inline void minp(void)
669 redo:
670 ch = ch1;
671 inp();
672 if (ch == '\\' && ch1 == '\n') {
673 inp();
674 goto redo;
676 //printf("ch=%c 0x%x\n", ch, ch);
680 /* same as minp, but also skip comments */
681 void cinp(void)
683 int c;
685 if (ch1 == '/') {
686 inp();
687 if (ch1 == '/') {
688 /* single line C++ comments */
689 inp();
690 while (ch1 != '\n' && ch1 != -1)
691 inp();
692 inp();
693 ch = ' '; /* return space */
694 } else if (ch1 == '*') {
695 /* C comments */
696 inp();
697 while (ch1 != -1) {
698 c = ch1;
699 inp();
700 if (c == '*' && ch1 == '/') {
701 inp();
702 ch = ' '; /* return space */
703 break;
706 } else {
707 ch = '/';
709 } else {
710 minp();
714 void skip_spaces(void)
716 while (ch == ' ' || ch == '\t')
717 cinp();
720 /* skip block of text until #else, #elif or #endif. skip also pairs of
721 #if/#endif */
722 void preprocess_skip()
724 int a;
725 a = 0;
726 while (1) {
727 while (ch != '\n') {
728 if (ch == -1)
729 expect("#endif");
730 cinp();
732 cinp();
733 skip_spaces();
734 if (ch == '#') {
735 cinp();
736 next_nomacro();
737 if (a == 0 &&
738 (tok == TOK_ELSE || tok == TOK_ELIF || tok == TOK_ENDIF))
739 break;
740 if (tok == TOK_IF || tok == TOK_IFDEF || tok == TOK_IFNDEF)
741 a++;
742 else if (tok == TOK_ENDIF)
743 a--;
748 inline int is_long_tok(int t)
750 return (t == TOK_NUM ||
751 t == TOK_CCHAR || t == TOK_LCHAR ||
752 t == TOK_STR || t == TOK_LSTR);
755 void tok_add(int **tok_str, int *tok_len, int t)
757 int len, *str;
758 len = *tok_len;
759 str = *tok_str;
760 if ((len & 63) == 0) {
761 str = realloc(str, (len + 64) * sizeof(int));
762 if (!str)
763 return;
764 *tok_str = str;
766 str[len++] = t;
767 *tok_len = len;
770 void tok_add2(int **tok_str, int *tok_len, int t, int c)
772 tok_add(tok_str, tok_len, t);
773 if (is_long_tok(t))
774 tok_add(tok_str, tok_len, c);
777 /* eval an expression for #if/#elif */
778 int expr_preprocess()
780 int *str, len, c, t;
782 str = NULL;
783 len = 0;
784 while (1) {
785 skip_spaces();
786 if (ch == '\n')
787 break;
788 next(); /* do macro subst */
789 if (tok == TOK_DEFINED) {
790 next_nomacro();
791 t = tok;
792 if (t == '(')
793 next_nomacro();
794 c = sym_find1(&define_stack, tok) != 0;
795 if (t == '(')
796 next_nomacro();
797 tok = TOK_NUM;
798 tokc = c;
799 } else if (tok >= TOK_IDENT) {
800 /* if undefined macro */
801 tok = TOK_NUM;
802 tokc = 0;
804 tok_add2(&str, &len, tok, tokc);
806 tok_add(&str, &len, -1); /* simulate end of file */
807 tok_add(&str, &len, 0);
808 /* now evaluate C constant expression */
809 macro_ptr = str;
810 next();
811 c = expr_const();
812 macro_ptr = NULL;
813 free(str);
814 return c != 0;
817 #ifdef DEBUG
818 void tok_print(int *str)
820 int t, c;
822 while (1) {
823 t = *str++;
824 if (!t)
825 break;
826 c = 0;
827 if (is_long_tok(t))
828 c = *str++;
829 printf(" %s", get_tok_str(t, c));
831 printf("\n");
833 #endif
835 /* XXX: should be more factorized */
836 void define_symbol(char *sym)
838 TokenSym *ts;
839 int *str, len;
841 ts = tok_alloc(sym, 0);
842 str = NULL;
843 len = 0;
844 tok_add2(&str, &len, TOK_NUM, 1);
845 tok_add(&str, &len, 0);
846 sym_push1(&define_stack, ts->tok, MACRO_OBJ, (int)str);
849 void preprocess()
851 int size, i, c, v, t, *str, len;
852 char buf[1024], *q, *p;
853 char buf1[1024];
854 FILE *f;
855 Sym **ps, *first, *s;
857 cinp();
858 next_nomacro();
859 redo:
860 if (tok == TOK_DEFINE) {
861 next_nomacro();
862 v = tok;
863 /* XXX: should check if same macro (ANSI) */
864 first = NULL;
865 t = MACRO_OBJ;
866 /* '(' must be just after macro definition for MACRO_FUNC */
867 if (ch == '(') {
868 next_nomacro();
869 next_nomacro();
870 ps = &first;
871 while (tok != ')') {
872 if (tok == TOK_DOTS)
873 tok = TOK___VA_ARGS__;
874 s = sym_push1(&define_stack, tok | SYM_FIELD, 0, 0);
875 *ps = s;
876 ps = &s->next;
877 next_nomacro();
878 if (tok != ',')
879 break;
880 next_nomacro();
882 t = MACRO_FUNC;
884 str = NULL;
885 len = 0;
886 while (1) {
887 skip_spaces();
888 if (ch == '\n' || ch == -1)
889 break;
890 next_nomacro();
891 tok_add2(&str, &len, tok, tokc);
893 tok_add(&str, &len, 0);
894 #ifdef PP_DEBUG
895 printf("define %s %d: ", get_tok_str(v, 0), t);
896 tok_print(str);
897 #endif
898 s = sym_push1(&define_stack, v, t, (int)str);
899 s->next = first;
900 } else if (tok == TOK_UNDEF) {
901 next_nomacro();
902 s = sym_find1(&define_stack, tok);
903 /* undefine symbol by putting an invalid name */
904 if (s)
905 sym_undef(&define_stack, s);
906 } else if (tok == TOK_INCLUDE) {
907 skip_spaces();
908 if (ch == '<') {
909 c = '>';
910 goto read_name;
911 } else if (ch == '\"') {
912 c = ch;
913 read_name:
914 minp();
915 q = buf;
916 while (ch != c && ch != '\n' && ch != -1) {
917 if ((q - buf) < sizeof(buf) - 1)
918 *q++ = ch;
919 minp();
921 *q = '\0';
922 } else {
923 next();
924 if (tok != TOK_STR)
925 error("#include syntax error");
926 /* XXX: buffer overflow */
927 strcpy(buf, get_tok_str(tok, tokc));
928 c = '\"';
930 if (include_stack_ptr >= include_stack + INCLUDE_STACK_SIZE)
931 error("memory full");
932 if (c == '\"') {
933 /* first search in current dir if "header.h" */
934 /* XXX: buffer overflow */
935 size = 0;
936 p = strrchr(filename, '/');
937 if (p)
938 size = p + 1 - filename;
939 memcpy(buf1, filename, size);
940 buf1[size] = '\0';
941 strcat(buf1, buf);
942 f = fopen(buf1, "r");
943 if (f)
944 goto found;
946 /* now search in standard include path */
947 for(i=nb_include_paths - 1;i>=0;i--) {
948 strcpy(buf1, include_paths[i]);
949 strcat(buf1, "/");
950 strcat(buf1, buf);
951 f = fopen(buf1, "r");
952 if (f)
953 goto found;
955 error("include file '%s' not found", buf1);
956 f = NULL;
957 found:
958 /* push current file in stack */
959 /* XXX: fix current line init */
960 include_stack_ptr->file = file;
961 include_stack_ptr->filename = filename;
962 include_stack_ptr->line_num = line_num;
963 include_stack_ptr++;
964 file = f;
965 filename = strdup(buf1);
966 line_num = 1;
967 } else if (tok == TOK_IFNDEF) {
968 c = 1;
969 goto do_ifdef;
970 } else if (tok == TOK_IF) {
971 c = expr_preprocess();
972 goto do_if;
973 } else if (tok == TOK_IFDEF) {
974 c = 0;
975 do_ifdef:
976 next_nomacro();
977 c = (sym_find1(&define_stack, tok) != 0) ^ c;
978 do_if:
979 if (ifdef_stack_ptr >= ifdef_stack + IFDEF_STACK_SIZE)
980 error("memory full");
981 *ifdef_stack_ptr++ = c;
982 goto test_skip;
983 } else if (tok == TOK_ELSE) {
984 if (ifdef_stack_ptr == ifdef_stack ||
985 (ifdef_stack_ptr[-1] & 2))
986 error("#else after #else");
987 c = (ifdef_stack_ptr[-1] ^= 3);
988 goto test_skip;
989 } else if (tok == TOK_ELIF) {
990 if (ifdef_stack_ptr == ifdef_stack ||
991 ifdef_stack_ptr[-1] > 1)
992 error("#elif after #else");
993 c = expr_preprocess();
994 ifdef_stack_ptr[-1] = c;
995 test_skip:
996 if (!(c & 1)) {
997 preprocess_skip();
998 goto redo;
1000 } else if (tok == TOK_ENDIF) {
1001 if (ifdef_stack_ptr == ifdef_stack)
1002 expect("#if");
1003 ifdef_stack_ptr--;
1004 } else if (tok == TOK_LINE) {
1005 next();
1006 if (tok != TOK_NUM)
1007 error("#line");
1008 line_num = tokc;
1009 skip_spaces();
1010 if (ch != '\n') {
1011 next();
1012 if (tok != TOK_STR)
1013 error("#line");
1014 /* XXX: potential memory leak */
1015 filename = strdup(get_tok_str(tok, tokc));
1017 } else if (tok == TOK_ERROR) {
1018 error("#error");
1020 /* ignore other preprocess commands or #! for C scripts */
1021 while (ch != '\n' && ch != -1)
1022 cinp();
1025 /* read a number in base b */
1026 int getn(b)
1028 int n, t;
1029 n = 0;
1030 while (1) {
1031 if (ch >= 'a' & ch <= 'f')
1032 t = ch - 'a' + 10;
1033 else if (ch >= 'A' & ch <= 'F')
1034 t = ch - 'A' + 10;
1035 else if (isnum(ch))
1036 t = ch - '0';
1037 else
1038 break;
1039 if (t < 0 | t >= b)
1040 break;
1041 n = n * b + t;
1042 cinp();
1044 return n;
1047 /* read a character for string or char constant and eval escape codes */
1048 int getq()
1050 int c;
1052 c = ch;
1053 minp();
1054 if (c == '\\') {
1055 if (isnum(ch)) {
1056 /* at most three octal digits */
1057 c = ch - '0';
1058 minp();
1059 if (isnum(ch)) {
1060 c = c * 8 + ch - '0';
1061 minp();
1062 if (isnum(ch)) {
1063 c = c * 8 + ch - '0';
1064 minp();
1067 return c;
1068 } else if (ch == 'x') {
1069 minp();
1070 return getn(16);
1071 } else {
1072 if (ch == 'a')
1073 c = '\a';
1074 else if (ch == 'b')
1075 c = '\b';
1076 else if (ch == 'f')
1077 c = '\f';
1078 else if (ch == 'n')
1079 c = '\n';
1080 else if (ch == 'r')
1081 c = '\r';
1082 else if (ch == 't')
1083 c = '\t';
1084 else if (ch == 'v')
1085 c = '\v';
1086 else
1087 c = ch;
1088 minp();
1091 return c;
1094 /* return next token without macro substitution */
1095 void next_nomacro1()
1097 int b;
1098 char *q;
1099 TokenSym *ts;
1101 /* skip spaces */
1102 while(1) {
1103 while (ch == '\n') {
1104 cinp();
1105 while (ch == ' ' || ch == 9)
1106 cinp();
1107 if (ch == '#') {
1108 /* preprocessor command if # at start of line after
1109 spaces */
1110 preprocess();
1113 if (ch != ' ' && ch != '\t' && ch != '\f')
1114 break;
1115 cinp();
1117 if (isid(ch)) {
1118 q = token_buf;
1119 *q++ = ch;
1120 cinp();
1121 if (q[-1] == 'L') {
1122 if (ch == '\'') {
1123 tok = TOK_LCHAR;
1124 goto char_const;
1126 if (ch == '\"') {
1127 tok = TOK_LSTR;
1128 goto str_const;
1131 while (isid(ch) | isnum(ch)) {
1132 if (q >= token_buf + STRING_MAX_SIZE)
1133 error("ident too long");
1134 *q++ = ch;
1135 cinp();
1137 *q = '\0';
1138 ts = tok_alloc(token_buf, q - token_buf);
1139 tok = ts->tok;
1140 } else if (isnum(ch)) {
1141 /* number */
1142 b = 10;
1143 if (ch == '0') {
1144 cinp();
1145 b = 8;
1146 if (ch == 'x' || ch == 'X') {
1147 cinp();
1148 b = 16;
1149 } else if (ch == 'b' || ch == 'B') {
1150 cinp();
1151 b = 2;
1154 tokc = getn(b);
1155 /* XXX: add unsigned constant support (ANSI) */
1156 while (ch == 'L' || ch == 'l' || ch == 'U' || ch == 'u')
1157 cinp();
1158 tok = TOK_NUM;
1159 } else if (ch == '\'') {
1160 tok = TOK_CCHAR;
1161 char_const:
1162 minp();
1163 tokc = getq();
1164 if (ch != '\'')
1165 expect("\'");
1166 minp();
1167 } else if (ch == '\"') {
1168 tok = TOK_STR;
1169 str_const:
1170 minp();
1171 q = token_buf;
1172 while (ch != '\"') {
1173 b = getq();
1174 if (ch == -1)
1175 error("unterminated string");
1176 if (q >= token_buf + STRING_MAX_SIZE)
1177 error("string too long");
1178 *q++ = b;
1180 *q = '\0';
1181 tokc = (int)tok_alloc(token_buf, q - token_buf);
1182 minp();
1183 } else {
1184 q = "<=\236>=\235!=\225&&\240||\241++\244--\242==\224<<\1>>\2+=\253-=\255*=\252/=\257%=\245&=\246^=\336|=\374->\247..\250##\266";
1185 /* two chars */
1186 tok = ch;
1187 cinp();
1188 while (*q) {
1189 if (*q == tok & q[1] == ch) {
1190 cinp();
1191 tok = q[2] & 0xff;
1192 /* three chars tests */
1193 if (tok == TOK_SHL | tok == TOK_SAR) {
1194 if (ch == '=') {
1195 tok = tok | 0x80;
1196 cinp();
1198 } else if (tok == TOK_DOTS) {
1199 if (ch != '.')
1200 error("parse error");
1201 cinp();
1203 return;
1205 q = q + 3;
1207 /* single char substitutions */
1208 if (tok == '<')
1209 tok = TOK_LT;
1210 else if (tok == '>')
1211 tok = TOK_GT;
1215 /* return next token without macro substitution. Can read input from
1216 macro_ptr buffer */
1217 void next_nomacro()
1219 if (macro_ptr) {
1220 tok = *macro_ptr;
1221 if (tok) {
1222 macro_ptr++;
1223 if (is_long_tok(tok))
1224 tokc = *macro_ptr++;
1226 } else {
1227 next_nomacro1();
1231 /* substitute args in macro_str and return allocated string */
1232 int *macro_arg_subst(Sym **nested_list, int *macro_str, Sym *args)
1234 int *st, last_tok, t, c, notfirst, *str, len;
1235 Sym *s;
1236 TokenSym *ts;
1238 str = NULL;
1239 len = 0;
1240 last_tok = 0;
1241 while(1) {
1242 t = *macro_str++;
1243 if (!t)
1244 break;
1245 if (t == '#') {
1246 /* stringize */
1247 t = *macro_str++;
1248 if (!t)
1249 break;
1250 s = sym_find2(args, t);
1251 if (s) {
1252 token_buf[0] = '\0';
1253 st = (int *)s->c;
1254 /* XXX: buffer overflow */
1255 notfirst = 0;
1256 while (*st) {
1257 if (notfirst)
1258 strcat(token_buf, " ");
1259 t = *st++;
1260 c = 0;
1261 if (is_long_tok(t))
1262 c = *st++;
1263 strcat(token_buf, get_tok_str(t, c));
1264 notfirst = 1;
1266 #ifdef PP_DEBUG
1267 printf("stringize: %s\n", token_buf);
1268 #endif
1269 /* add string */
1270 ts = tok_alloc(token_buf, 0);
1271 tok_add2(&str, &len, TOK_STR, (int)ts);
1272 } else {
1273 tok_add(&str, &len, t);
1275 } else if (is_long_tok(t)) {
1276 tok_add2(&str, &len, t, *macro_str++);
1277 } else {
1278 s = sym_find2(args, t);
1279 if (s) {
1280 st = (int *)s->c;
1281 /* if '##' is present before or after , no arg substitution */
1282 if (*macro_str == TOK_TWOSHARPS || last_tok == TOK_TWOSHARPS) {
1283 while (*st)
1284 tok_add(&str, &len, *st++);
1285 } else {
1286 macro_subst(&str, &len, nested_list, st);
1288 } else {
1289 tok_add(&str, &len, t);
1292 last_tok = t;
1294 tok_add(&str, &len, 0);
1295 return str;
1298 /* handle the '##' operator */
1299 int *macro_twosharps(int *macro_str)
1301 TokenSym *ts;
1302 int *macro_str1, macro_str1_len, *macro_ptr1;
1303 int t, c;
1304 char *p;
1306 macro_str1 = NULL;
1307 macro_str1_len = 0;
1308 tok = 0;
1309 while (1) {
1310 next_nomacro();
1311 if (tok == 0)
1312 break;
1313 if (*macro_ptr == TOK_TWOSHARPS) {
1314 macro_ptr++;
1315 macro_ptr1 = macro_ptr;
1316 t = *macro_ptr;
1317 if (t) {
1318 macro_ptr++;
1319 c = 0;
1320 if (is_long_tok(t))
1321 c = *macro_ptr++;
1322 /* XXX: we handle only most common cases:
1323 ident + ident or ident + number */
1324 if (tok >= TOK_IDENT &&
1325 (t >= TOK_IDENT || t == TOK_NUM)) {
1326 /* XXX: buffer overflow */
1327 p = get_tok_str(tok, tokc);
1328 strcpy(token_buf, p);
1329 p = get_tok_str(t, c);
1330 strcat(token_buf, p);
1331 ts = tok_alloc(token_buf, 0);
1332 tok_add2(&macro_str1, &macro_str1_len, ts->tok, 0);
1333 } else {
1334 /* cannot merge tokens: skip '##' */
1335 macro_ptr = macro_ptr1;
1338 } else {
1339 tok_add2(&macro_str1, &macro_str1_len, tok, tokc);
1342 tok_add(&macro_str1, &macro_str1_len, 0);
1343 return macro_str1;
1348 /* do macro substitution of macro_str and add result to
1349 (tok_str,tok_len). If macro_str is NULL, then input stream token is
1350 substituted. 'nested_list' is the list of all macros we got inside
1351 to avoid recursing. */
1352 void macro_subst(int **tok_str, int *tok_len,
1353 Sym **nested_list, int *macro_str)
1355 Sym *s, *args, *sa, *sa1;
1356 int *str, parlevel, len, *mstr, t, *saved_macro_ptr;
1357 int mstr_allocated, *macro_str1;
1359 saved_macro_ptr = macro_ptr;
1360 macro_ptr = macro_str;
1361 macro_str1 = NULL;
1362 if (macro_str) {
1363 /* first scan for '##' operator handling */
1364 macro_str1 = macro_twosharps(macro_str);
1365 macro_ptr = macro_str1;
1368 while (1) {
1369 next_nomacro();
1370 if (tok == 0)
1371 break;
1372 /* special macros */
1373 if (tok == TOK___LINE__) {
1374 tok_add2(tok_str, tok_len, TOK_NUM, line_num);
1375 } else if (tok == TOK___FILE__) {
1376 tok_add2(tok_str, tok_len, TOK_STR,
1377 (int)tok_alloc(filename, 0));
1378 } else if (tok == TOK___DATE__) {
1379 tok_add2(tok_str, tok_len, TOK_STR,
1380 (int)tok_alloc("Jan 1 1970", 0));
1381 } else if (tok == TOK___TIME__) {
1382 tok_add2(tok_str, tok_len, TOK_STR,
1383 (int)tok_alloc("00:00:00", 0));
1384 } else if ((s = sym_find1(&define_stack, tok)) != NULL) {
1385 /* if symbol is a macro, prepare substitution */
1386 /* if nested substitution, do nothing */
1387 if (sym_find2(*nested_list, tok))
1388 goto no_subst;
1389 mstr = (int *)s->c;
1390 mstr_allocated = 0;
1391 if (s->t == MACRO_FUNC) {
1392 /* NOTE: we do not use next_nomacro to avoid eating the
1393 next token. XXX: find better solution */
1394 if (macro_ptr) {
1395 t = *macro_ptr;
1396 } else {
1397 while (ch == ' ' || ch == '\t' || ch == '\n')
1398 cinp();
1399 t = ch;
1401 if (t != '(') /* no macro subst */
1402 goto no_subst;
1404 /* argument macro */
1405 next_nomacro();
1406 next_nomacro();
1407 args = NULL;
1408 sa = s->next;
1409 while (tok != ')' && sa) {
1410 len = 0;
1411 str = NULL;
1412 parlevel = 0;
1413 while ((parlevel > 0 ||
1414 (tok != ')' &&
1415 (tok != ',' ||
1416 sa->v == (TOK___VA_ARGS__ | SYM_FIELD)))) &&
1417 tok != -1) {
1418 if (tok == '(')
1419 parlevel++;
1420 else if (tok == ')')
1421 parlevel--;
1422 tok_add2(&str, &len, tok, tokc);
1423 next_nomacro();
1425 tok_add(&str, &len, 0);
1426 sym_push2(&args, sa->v & ~SYM_FIELD, 0, (int)str);
1427 if (tok != ',')
1428 break;
1429 next_nomacro();
1430 sa = sa->next;
1432 if (tok != ')')
1433 expect(")");
1434 /* now subst each arg */
1435 mstr = macro_arg_subst(nested_list, mstr, args);
1436 /* free memory */
1437 sa = args;
1438 while (sa) {
1439 sa1 = sa->prev;
1440 free((int *)sa->c);
1441 free(sa);
1442 sa = sa1;
1444 mstr_allocated = 1;
1446 sym_push2(nested_list, s->v, 0, 0);
1447 macro_subst(tok_str, tok_len, nested_list, mstr);
1448 /* pop nested defined symbol */
1449 sa1 = *nested_list;
1450 *nested_list = sa1->prev;
1451 free(sa1);
1452 if (mstr_allocated)
1453 free(mstr);
1454 } else {
1455 no_subst:
1456 /* no need to add if reading input stream */
1457 if (!macro_str)
1458 return;
1459 tok_add2(tok_str, tok_len, tok, tokc);
1461 /* only replace one macro while parsing input stream */
1462 if (!macro_str)
1463 return;
1465 macro_ptr = saved_macro_ptr;
1466 if (macro_str1)
1467 free(macro_str1);
1470 /* return next token with macro substitution */
1471 void next()
1473 int len, *ptr;
1474 Sym *nested_list;
1476 /* special 'ungettok' case for label parsing */
1477 if (tok1) {
1478 tok = tok1;
1479 tokc = tok1c;
1480 tok1 = 0;
1481 } else {
1482 redo:
1483 if (!macro_ptr) {
1484 /* if not reading from macro substuted string, then try to substitute */
1485 len = 0;
1486 ptr = NULL;
1487 nested_list = NULL;
1488 macro_subst(&ptr, &len, &nested_list, NULL);
1489 if (ptr) {
1490 tok_add(&ptr, &len, 0);
1491 macro_ptr = ptr;
1492 macro_ptr_allocated = ptr;
1493 goto redo;
1495 if (tok == 0)
1496 goto redo;
1497 } else {
1498 next_nomacro();
1499 if (tok == 0) {
1500 /* end of macro string: free it */
1501 free(macro_ptr_allocated);
1502 macro_ptr = NULL;
1503 goto redo;
1507 #if defined(DEBUG)
1508 printf("token = %s\n", get_tok_str(tok, tokc));
1509 #endif
1512 void swap(int *p, int *q)
1514 int t;
1515 t = *p;
1516 *p = *q;
1517 *q = t;
1520 void vset(t, v)
1522 vt = t;
1523 vc = v;
1526 /******************************************************/
1527 /* X86 code generator */
1529 typedef struct GFuncContext {
1530 int args_size;
1531 } GFuncContext;
1533 void g(int c)
1535 *(char *)ind++ = c;
1538 void o(int c)
1540 while (c) {
1541 g(c);
1542 c = c / 256;
1546 void gen_le32(int c)
1548 g(c);
1549 g(c >> 8);
1550 g(c >> 16);
1551 g(c >> 24);
1554 /* add a new relocation entry to symbol 's' */
1555 void greloc(Sym *s, int addr, int type)
1557 Reloc *p;
1558 p = malloc(sizeof(Reloc));
1559 if (!p)
1560 error("memory full");
1561 p->type = type;
1562 p->addr = addr;
1563 p->next = (Reloc *)s->c;
1564 s->c = (int)p;
1567 /* patch each relocation entry with value 'val' */
1568 void greloc_patch(Sym *s, int val)
1570 Reloc *p, *p1;
1572 p = (Reloc *)s->c;
1573 while (p != NULL) {
1574 p1 = p->next;
1575 switch(p->type) {
1576 case RELOC_ADDR32:
1577 *(int *)p->addr = val;
1578 break;
1579 case RELOC_REL32:
1580 *(int *)p->addr = val - p->addr - 4;
1581 break;
1583 free(p);
1584 p = p1;
1586 s->c = val;
1587 s->t &= ~VT_FORWARD;
1590 /* output a symbol and patch all calls to it */
1591 void gsym_addr(t, a)
1593 int n;
1594 while (t) {
1595 n = *(int *)t; /* next value */
1596 *(int *)t = a - t - 4;
1597 t = n;
1601 void gsym(t)
1603 gsym_addr(t, ind);
1606 /* psym is used to put an instruction with a data field which is a
1607 reference to a symbol. It is in fact the same as oad ! */
1608 #define psym oad
1610 /* instruction + 4 bytes data. Return the address of the data */
1611 int oad(int c, int s)
1613 o(c);
1614 *(int *)ind = s;
1615 s = ind;
1616 ind = ind + 4;
1617 return s;
1620 /* output constant with relocation if 't & VT_FORWARD' is true */
1621 void gen_addr32(int c, int t)
1623 if (!(t & VT_FORWARD)) {
1624 gen_le32(c);
1625 } else {
1626 greloc((Sym *)c, ind, RELOC_ADDR32);
1627 gen_le32(0);
1631 /* XXX: generate correct pointer for forward references to functions */
1632 /* r = (ft, fc) */
1633 void load(r, ft, fc)
1635 int v, t;
1637 v = ft & VT_VALMASK;
1638 if (ft & VT_LVAL) {
1639 if (v == VT_LLOCAL) {
1640 load(r, VT_LOCAL | VT_LVAL, fc);
1641 v = r;
1643 if ((ft & VT_TYPE) == VT_BYTE)
1644 o(0xbe0f); /* movsbl */
1645 else if ((ft & VT_TYPE) == (VT_BYTE | VT_UNSIGNED))
1646 o(0xb60f); /* movzbl */
1647 else if ((ft & VT_TYPE) == VT_SHORT)
1648 o(0xbf0f); /* movswl */
1649 else if ((ft & VT_TYPE) == (VT_SHORT | VT_UNSIGNED))
1650 o(0xb70f); /* movzwl */
1651 else
1652 o(0x8b); /* movl */
1653 if (v == VT_CONST) {
1654 o(0x05 + r * 8); /* 0xXX, r */
1655 gen_addr32(fc, ft);
1656 } else if (v == VT_LOCAL) {
1657 oad(0x85 + r * 8, fc); /* xx(%ebp), r */
1658 } else {
1659 g(0x00 + r * 8 + v); /* (v), r */
1661 } else {
1662 if (v == VT_CONST) {
1663 o(0xb8 + r); /* mov $xx, r */
1664 gen_addr32(fc, ft);
1665 } else if (v == VT_LOCAL) {
1666 o(0x8d);
1667 oad(0x85 + r * 8, fc); /* lea xxx(%ebp), r */
1668 } else if (v == VT_CMP) {
1669 oad(0xb8 + r, 0); /* mov $0, r */
1670 o(0x0f); /* setxx %br */
1671 o(fc);
1672 o(0xc0 + r);
1673 } else if (v == VT_JMP || v == VT_JMPI) {
1674 t = v & 1;
1675 oad(0xb8 + r, t); /* mov $1, r */
1676 oad(0xe9, 5); /* jmp after */
1677 gsym(fc);
1678 oad(0xb8 + r, t ^ 1); /* mov $0, r */
1679 } else if (v != r) {
1680 o(0x89);
1681 o(0xc0 + r + v * 8); /* mov v, r */
1686 /* (ft, fc) = r */
1687 /* WARNING: r must not be allocated on the stack */
1688 void store(r, ft, fc)
1690 int fr, bt;
1692 fr = ft & VT_VALMASK;
1693 bt = ft & VT_BTYPE;
1694 /* XXX: incorrect if reg to reg */
1695 if (bt == VT_SHORT)
1696 o(0x66);
1697 if (bt == VT_BYTE)
1698 o(0x88);
1699 else
1700 o(0x89);
1701 if (fr == VT_CONST) {
1702 o(0x05 + r * 8); /* mov r,xxx */
1703 gen_addr32(fc, ft);
1704 } else if (fr == VT_LOCAL) {
1705 oad(0x85 + r * 8, fc); /* mov r,xxx(%ebp) */
1706 } else if (ft & VT_LVAL) {
1707 g(fr + r * 8); /* mov r, (fr) */
1708 } else if (fr != r) {
1709 o(0xc0 + fr + r * 8); /* mov r, fr */
1713 /* start function call and return function call context */
1714 void gfunc_start(GFuncContext *c)
1716 c->args_size = 0;
1719 /* push function parameter which is in (vt, vc) */
1720 void gfunc_param(GFuncContext *c)
1722 int size, align, ft, fc, r;
1724 if ((vt & (VT_BTYPE | VT_LVAL)) == (VT_STRUCT | VT_LVAL)) {
1725 size = type_size(vt, &align);
1726 /* align to stack align size */
1727 size = (size + 3) & ~3;
1728 /* allocate the necessary size on stack */
1729 oad(0xec81, size); /* sub $xxx, %esp */
1730 /* generate structure store */
1731 r = get_reg();
1732 o(0x89); /* mov %esp, r */
1733 o(0xe0 + r);
1734 ft = vt;
1735 fc = vc;
1736 vset(VT_INT | r, 0);
1737 vpush();
1738 vt = ft;
1739 vc = fc;
1740 vstore();
1741 c->args_size += size;
1742 } else {
1743 /* simple type (currently always same size) */
1744 /* XXX: implicit cast ? */
1745 r = gv();
1746 o(0x50 + r); /* push r */
1747 c->args_size += 4;
1751 /* generate function call with address in (vt, vc) and free function
1752 context */
1753 void gfunc_call(GFuncContext *c)
1755 int r;
1756 if ((vt & (VT_VALMASK | VT_LVAL)) == VT_CONST) {
1757 /* constant case */
1758 /* forward reference */
1759 if (vt & VT_FORWARD) {
1760 greloc((Sym *)vc, ind + 1, RELOC_REL32);
1761 oad(0xe8, 0);
1762 } else {
1763 oad(0xe8, vc - ind - 5);
1765 } else {
1766 /* otherwise, indirect call */
1767 r = gv();
1768 o(0xff); /* call *r */
1769 o(0xd0 + r);
1771 if (c->args_size)
1772 oad(0xc481, c->args_size); /* add $xxx, %esp */
1775 int gjmp(int t)
1777 return psym(0xe9, t);
1780 /* generate a test. set 'inv' to invert test */
1781 int gtst(int inv, int t)
1783 int v, *p;
1784 v = vt & VT_VALMASK;
1785 if (v == VT_CMP) {
1786 /* fast case : can jump directly since flags are set */
1787 g(0x0f);
1788 t = psym((vc - 16) ^ inv, t);
1789 } else if (v == VT_JMP || v == VT_JMPI) {
1790 /* && or || optimization */
1791 if ((v & 1) == inv) {
1792 /* insert vc jump list in t */
1793 p = &vc;
1794 while (*p != 0)
1795 p = (int *)*p;
1796 *p = t;
1797 t = vc;
1798 } else {
1799 t = gjmp(t);
1800 gsym(vc);
1802 } else if ((vt & (VT_VALMASK | VT_LVAL)) == VT_CONST) {
1803 /* constant jmp optimization */
1804 if ((vc != 0) != inv)
1805 t = gjmp(t);
1806 } else {
1807 v = gv();
1808 o(0x85);
1809 o(0xc0 + v * 9);
1810 g(0x0f);
1811 t = psym(0x85 ^ inv, t);
1813 return t;
1816 /* generate a binary operation 'v = r op fr' instruction and modifies
1817 (vt,vc) if needed */
1818 void gen_op1(int op, int r, int fr)
1820 int t;
1821 if (op == '+') {
1822 o(0x01);
1823 o(0xc0 + r + fr * 8);
1824 } else if (op == '-') {
1825 o(0x29);
1826 o(0xc0 + r + fr * 8);
1827 } else if (op == '&') {
1828 o(0x21);
1829 o(0xc0 + r + fr * 8);
1830 } else if (op == '^') {
1831 o(0x31);
1832 o(0xc0 + r + fr * 8);
1833 } else if (op == '|') {
1834 o(0x09);
1835 o(0xc0 + r + fr * 8);
1836 } else if (op == '*') {
1837 o(0xaf0f); /* imul fr, r */
1838 o(0xc0 + fr + r * 8);
1839 } else if (op == TOK_SHL | op == TOK_SHR | op == TOK_SAR) {
1840 /* op2 is %ecx */
1841 if (fr != 1) {
1842 if (r == 1) {
1843 r = fr;
1844 fr = 1;
1845 o(0x87); /* xchg r, %ecx */
1846 o(0xc1 + r * 8);
1847 } else
1848 move_reg(1, fr);
1850 o(0xd3); /* shl/shr/sar %cl, r */
1851 if (op == TOK_SHL)
1852 o(0xe0 + r);
1853 else if (op == TOK_SHR)
1854 o(0xe8 + r);
1855 else
1856 o(0xf8 + r);
1857 vt = (vt & VT_TYPE) | r;
1858 } else if (op == '/' | op == TOK_UDIV | op == TOK_PDIV |
1859 op == '%' | op == TOK_UMOD) {
1860 save_reg(2); /* save edx */
1861 t = save_reg_forced(fr); /* save fr and get op2 location */
1862 move_reg(0, r); /* op1 is %eax */
1863 if (op == TOK_UDIV | op == TOK_UMOD) {
1864 o(0xf7d231); /* xor %edx, %edx, div t(%ebp), %eax */
1865 oad(0xb5, t);
1866 } else {
1867 o(0xf799); /* cltd, idiv t(%ebp), %eax */
1868 oad(0xbd, t);
1870 if (op == '%' | op == TOK_UMOD)
1871 r = 2;
1872 else
1873 r = 0;
1874 vt = (vt & VT_TYPE) | r;
1875 } else {
1876 o(0x39);
1877 o(0xc0 + r + fr * 8); /* cmp fr, r */
1878 vset(VT_CMP, op);
1882 /* end of X86 code generator */
1883 /*************************************************************/
1885 int save_reg_forced(int r)
1887 int i, l, *p, t;
1888 /* store register */
1889 loc = (loc - 4) & -3;
1890 store(r, VT_LOCAL, loc);
1891 l = loc;
1893 /* modify all stack values */
1894 for(p=vstack;p<vstack_ptr;p+=2) {
1895 i = p[0] & VT_VALMASK;
1896 if (i == r) {
1897 if (p[0] & VT_LVAL)
1898 t = VT_LLOCAL;
1899 else
1900 t = VT_LOCAL;
1901 p[0] = (p[0] & VT_TYPE) | VT_LVAL | t;
1902 p[1] = l;
1905 return l;
1908 /* save r to memory. and mark it as being free */
1909 void save_reg(r)
1911 int i, *p;
1913 /* modify all stack values */
1914 for(p=vstack;p<vstack_ptr;p+=2) {
1915 i = p[0] & VT_VALMASK;
1916 if (i == r) {
1917 save_reg_forced(r);
1918 break;
1923 /* find a free register. If none, save one register */
1924 int get_reg(void)
1926 int r, i, *p;
1928 /* find a free register */
1929 for(r=0;r<NB_REGS;r++) {
1930 for(p=vstack;p<vstack_ptr;p+=2) {
1931 i = p[0] & VT_VALMASK;
1932 if (i == r)
1933 goto notfound;
1935 return r;
1936 notfound: ;
1939 /* no register left : free the first one on the stack (very
1940 important to start from the bottom to ensure that we don't
1941 spill registers used in gen_op()) */
1942 for(p=vstack;p<vstack_ptr;p+=2) {
1943 r = p[0] & VT_VALMASK;
1944 if (r < VT_CONST) {
1945 save_reg(r);
1946 break;
1949 return r;
1952 void save_regs()
1954 int r, *p;
1955 for(p=vstack;p<vstack_ptr;p+=2) {
1956 r = p[0] & VT_VALMASK;
1957 if (r < VT_CONST) {
1958 save_reg(r);
1963 /* move register 's' to 'r', and flush previous value of r to memory
1964 if needed */
1965 void move_reg(r, s)
1967 if (r != s) {
1968 save_reg(r);
1969 load(r, s, 0);
1973 /* convert a stack entry in register. lvalues are converted as
1974 values. Cannot be used if cannot be converted to register value
1975 (such as structures). */
1976 int gvp(int *p)
1978 int r;
1979 r = p[0] & VT_VALMASK;
1980 if (r >= VT_CONST || (p[0] & VT_LVAL))
1981 r = get_reg();
1982 /* NOTE: get_reg can modify p[] */
1983 load(r, p[0], p[1]);
1984 p[0] = (p[0] & VT_TYPE) | r;
1985 return r;
1988 void vpush(void)
1990 if (vstack_ptr >= vstack + VSTACK_SIZE)
1991 error("memory full");
1992 *vstack_ptr++ = vt;
1993 *vstack_ptr++ = vc;
1994 /* cannot let cpu flags if other instruction are generated */
1995 /* XXX: VT_JMP test too ? */
1996 if ((vt & VT_VALMASK) == VT_CMP)
1997 gvp(vstack_ptr - 2);
2000 void vpop(int *ft, int *fc)
2002 *fc = *--vstack_ptr;
2003 *ft = *--vstack_ptr;
2006 /* generate a value in a register from vt and vc */
2007 int gv(void)
2009 int r;
2010 vpush();
2011 r = gvp(vstack_ptr - 2);
2012 vpop(&vt, &vc);
2013 return r;
2016 /* handle constant optimizations and various machine independant opt */
2017 void gen_opc(op)
2019 int fr, ft, fc, r, c1, c2, n;
2021 vpop(&ft, &fc);
2022 vpop(&vt, &vc);
2023 c1 = (vt & (VT_VALMASK | VT_LVAL)) == VT_CONST;
2024 c2 = (ft & (VT_VALMASK | VT_LVAL)) == VT_CONST;
2025 if (c1 && c2) {
2026 switch(op) {
2027 case '+': vc += fc; break;
2028 case '-': vc -= fc; break;
2029 case '&': vc &= fc; break;
2030 case '^': vc ^= fc; break;
2031 case '|': vc |= fc; break;
2032 case '*': vc *= fc; break;
2033 case TOK_PDIV:
2034 case '/': vc /= fc; break; /* XXX: zero case ? */
2035 case '%': vc %= fc; break; /* XXX: zero case ? */
2036 case TOK_UDIV: vc = (unsigned)vc / fc; break; /* XXX: zero case ? */
2037 case TOK_UMOD: vc = (unsigned)vc % fc; break; /* XXX: zero case ? */
2038 case TOK_SHL: vc <<= fc; break;
2039 case TOK_SHR: vc = (unsigned)vc >> fc; break;
2040 case TOK_SAR: vc >>= fc; break;
2041 /* tests */
2042 case TOK_ULT: vc = (unsigned)vc < (unsigned)fc; break;
2043 case TOK_UGE: vc = (unsigned)vc >= (unsigned)fc; break;
2044 case TOK_EQ: vc = vc == fc; break;
2045 case TOK_NE: vc = vc != fc; break;
2046 case TOK_ULE: vc = (unsigned)vc <= (unsigned)fc; break;
2047 case TOK_UGT: vc = (unsigned)vc > (unsigned)fc; break;
2048 case TOK_LT: vc = vc < fc; break;
2049 case TOK_GE: vc = vc >= fc; break;
2050 case TOK_LE: vc = vc <= fc; break;
2051 case TOK_GT: vc = vc > fc; break;
2052 /* logical */
2053 case TOK_LAND: vc = vc && fc; break;
2054 case TOK_LOR: vc = vc || fc; break;
2055 default:
2056 goto general_case;
2058 } else {
2059 /* if commutative ops, put c2 as constant */
2060 if (c1 && (op == '+' || op == '&' || op == '^' ||
2061 op == '|' || op == '*')) {
2062 swap(&vt, &ft);
2063 swap(&vc, &fc);
2064 swap(&c1, &c2);
2066 if (c2 && (((op == '*' || op == '/' || op == TOK_UDIV ||
2067 op == TOK_PDIV) &&
2068 fc == 1) ||
2069 ((op == '+' || op == '-' || op == '|' || op == '^' ||
2070 op == TOK_SHL || op == TOK_SHR || op == TOK_SAR) &&
2071 fc == 0) ||
2072 (op == '&' &&
2073 fc == -1))) {
2074 } else if (c2 && (op == '*' || op == TOK_PDIV || op == TOK_UDIV)) {
2075 /* try to use shifts instead of muls or divs */
2076 if (fc > 0 && (fc & (fc - 1)) == 0) {
2077 n = -1;
2078 while (fc) {
2079 fc >>= 1;
2080 n++;
2082 fc = n;
2083 if (op == '*')
2084 op = TOK_SHL;
2085 else if (op == TOK_PDIV)
2086 op = TOK_SAR;
2087 else
2088 op = TOK_SHR;
2090 goto general_case;
2091 } else {
2092 general_case:
2093 vpush();
2094 vt = ft;
2095 vc = fc;
2096 vpush();
2097 r = gvp(vstack_ptr - 4);
2098 fr = gvp(vstack_ptr - 2);
2099 vpop(&ft, &fc);
2100 vpop(&vt, &vc);
2101 /* call low level op generator */
2102 gen_op1(op, r, fr);
2107 int pointed_size(int t)
2109 return type_size(pointed_type(t), &t);
2112 /* generic gen_op: handles types problems */
2113 void gen_op(int op)
2115 int u, t1, t2;
2117 vpush();
2118 t1 = vstack_ptr[-4];
2119 t2 = vstack_ptr[-2];
2120 if (op == '+' | op == '-') {
2121 if ((t1 & VT_BTYPE) == VT_PTR &&
2122 (t2 & VT_BTYPE) == VT_PTR) {
2123 if (op != '-')
2124 error("invalid type");
2125 /* XXX: check that types are compatible */
2126 u = pointed_size(t1);
2127 gen_opc(op);
2128 vpush();
2129 vstack_ptr[-2] &= ~VT_TYPE; /* set to integer */
2130 vset(VT_CONST, u);
2131 gen_op(TOK_PDIV);
2132 } else if ((t1 & VT_BTYPE) == VT_PTR ||
2133 (t2 & VT_BTYPE) == VT_PTR) {
2134 if ((t2 & VT_BTYPE) == VT_PTR) {
2135 swap(vstack_ptr - 4, vstack_ptr - 2);
2136 swap(vstack_ptr - 3, vstack_ptr - 1);
2137 swap(&t1, &t2);
2139 /* stack-4 contains pointer, stack-2 value to add */
2140 vset(VT_CONST, pointed_size(vstack_ptr[-4]));
2141 gen_op('*');
2142 vpush();
2143 gen_opc(op);
2144 /* put again type if gen_opc() swaped operands */
2145 vt = (vt & ~VT_TYPE) | (t1 & VT_TYPE);
2146 } else {
2147 gen_opc(op);
2149 } else {
2150 /* XXX: test types and compute returned value */
2151 if ((t1 | t2) & VT_UNSIGNED ||
2152 (t1 & VT_BTYPE) == VT_PTR ||
2153 (t2 & VT_BTYPE) == VT_PTR) {
2154 if (op == TOK_SAR)
2155 op = TOK_SHR;
2156 else if (op == '/')
2157 op = TOK_UDIV;
2158 else if (op == '%')
2159 op = TOK_UMOD;
2160 else if (op == TOK_LT)
2161 op = TOK_ULT;
2162 else if (op == TOK_GT)
2163 op = TOK_UGT;
2164 else if (op == TOK_LE)
2165 op = TOK_ULE;
2166 else if (op == TOK_GE)
2167 op = TOK_UGE;
2169 gen_opc(op);
2173 /* cast (vt, vc) to 't' type */
2174 void gen_cast(int t)
2176 int r, bits;
2177 r = vt & VT_VALMASK;
2178 if (!(t & VT_LVAL)) {
2179 /* if not lvalue, then we convert now */
2180 if ((t & VT_TYPE & ~VT_UNSIGNED) == VT_BYTE)
2181 bits = 8;
2182 else if ((t & VT_TYPE & ~VT_UNSIGNED) == VT_SHORT)
2183 bits = 16;
2184 else
2185 goto the_end;
2186 vpush();
2187 if (t & VT_UNSIGNED) {
2188 vset(VT_CONST, (1 << bits) - 1);
2189 gen_op('&');
2190 } else {
2191 bits = 32 - bits;
2192 vset(VT_CONST, bits);
2193 gen_op(TOK_SHL);
2194 vpush();
2195 vset(VT_CONST, bits);
2196 gen_op(TOK_SAR);
2199 the_end:
2200 vt = (vt & ~VT_TYPE) | t;
2203 /* return type size. Put alignment at 'a' */
2204 int type_size(int t, int *a)
2206 Sym *s;
2207 int bt;
2209 bt = t & VT_BTYPE;
2210 if (bt == VT_STRUCT) {
2211 /* struct/union */
2212 s = sym_find(((unsigned)t >> VT_STRUCT_SHIFT) | SYM_STRUCT);
2213 *a = 4; /* XXX: cannot store it yet. Doing that is safe */
2214 return s->c;
2215 } else if (t & VT_ARRAY) {
2216 s = sym_find(((unsigned)t >> VT_STRUCT_SHIFT));
2217 return type_size(s->t, a) * s->c;
2218 } else if (bt == VT_PTR ||
2219 bt == VT_INT ||
2220 bt == VT_ENUM) {
2221 *a = 4;
2222 return 4;
2223 } else if (bt == VT_SHORT) {
2224 *a = 2;
2225 return 2;
2226 } else {
2227 /* void or function */
2228 *a = 1;
2229 return 1;
2233 /* return the pointed type of t */
2234 int pointed_type(int t)
2236 Sym *s;
2237 s = sym_find(((unsigned)t >> VT_STRUCT_SHIFT));
2238 return s->t | (t & ~VT_TYPE);
2241 int mk_pointer(int t)
2243 int p;
2244 p = anon_sym++;
2245 sym_push(p, t, -1);
2246 return VT_PTR | (p << VT_STRUCT_SHIFT) | (t & ~VT_TYPE);
2249 /* store value in lvalue pushed on stack */
2250 void vstore(void)
2252 int ft, fc, r, t, size, align;
2253 GFuncContext gf;
2255 if ((vt & VT_BTYPE) == VT_STRUCT) {
2256 /* if structure, only generate pointer */
2257 /* structure assignment : generate memcpy */
2258 /* XXX: optimize if small size */
2260 gfunc_start(&gf);
2261 /* type size */
2262 ft = vt;
2263 fc = vc;
2264 size = type_size(vt, &align);
2265 vset(VT_CONST, size);
2266 gfunc_param(&gf);
2267 /* source */
2268 vt = ft & ~VT_LVAL;
2269 vc = fc;
2270 gfunc_param(&gf);
2271 /* destination */
2272 vpop(&vt, &vc);
2273 vt &= ~VT_LVAL;
2274 gfunc_param(&gf);
2276 save_regs();
2277 vset(VT_CONST, (int)&memcpy);
2278 gfunc_call(&gf);
2280 /* generate again current type */
2281 vt = ft;
2282 vc = fc;
2283 } else {
2284 r = gv(); /* generate value */
2285 vpush();
2286 ft = vstack_ptr[-4];
2287 fc = vstack_ptr[-3];
2288 /* if lvalue was saved on stack, must read it */
2289 if ((ft & VT_VALMASK) == VT_LLOCAL) {
2290 t = get_reg();
2291 load(t, VT_LOCAL | VT_LVAL, fc);
2292 ft = (ft & ~VT_VALMASK) | t;
2294 store(r, ft, fc);
2295 vstack_ptr -= 4;
2299 /* post defines POST/PRE add. c is the token ++ or -- */
2300 void inc(post, c)
2302 int r, r1;
2303 test_lvalue();
2304 if (post)
2305 vpush(); /* room for returned value */
2306 vpush(); /* save lvalue */
2307 r = gv();
2308 vpush(); /* save value */
2309 if (post) {
2310 /* duplicate value */
2311 r1 = get_reg();
2312 load(r1, r, 0); /* move r to r1 */
2313 vstack_ptr[-6] = (vt & VT_TYPE) | r1;
2314 vstack_ptr[-5] = 0;
2316 /* add constant */
2317 vset(VT_CONST, c - TOK_MID);
2318 gen_op('+');
2319 vstore(); /* store value */
2320 if (post)
2321 vpop(&vt, &vc);
2324 /* enum/struct/union declaration */
2325 int struct_decl(int u)
2327 int a, t, b, v, size, align, maxalign, c;
2328 Sym *s, *ss, **ps;
2330 a = tok; /* save decl type */
2331 next();
2332 if (tok != '{') {
2333 v = tok;
2334 next();
2335 /* struct already defined ? return it */
2336 /* XXX: check consistency */
2337 if (s = sym_find(v | SYM_STRUCT)) {
2338 if (s->t != a)
2339 error("invalid type");
2340 goto do_decl;
2342 } else {
2343 v = anon_sym++;
2345 s = sym_push(v | SYM_STRUCT, a, 0);
2346 /* put struct/union/enum name in type */
2347 do_decl:
2348 u = u | (v << VT_STRUCT_SHIFT);
2350 if (tok == '{') {
2351 next();
2352 if (s->c)
2353 error("struct/union/enum already defined");
2354 /* cannot be empty */
2355 c = 0;
2356 maxalign = 0;
2357 ps = &s->next;
2358 while (1) {
2359 if (a == TOK_ENUM) {
2360 v = tok;
2361 next();
2362 if (tok == '=') {
2363 next();
2364 c = expr_const();
2366 /* enum symbols have static storage */
2367 sym_push(v, VT_CONST | VT_STATIC, c);
2368 if (tok == ',')
2369 next();
2370 c++;
2371 } else {
2372 b = ist();
2373 while (1) {
2374 t = type_decl(&v, b, TYPE_DIRECT);
2375 if ((t & VT_BTYPE) == VT_FUNC ||
2376 (t & (VT_TYPEDEF | VT_STATIC | VT_EXTERN)))
2377 error("invalid type");
2378 /* XXX: align & correct type size */
2379 v |= SYM_FIELD;
2380 size = type_size(t, &align);
2381 if (a == TOK_STRUCT) {
2382 c = (c + align - 1) & -align;
2383 ss = sym_push(v, t, c);
2384 c += size;
2385 } else {
2386 ss = sym_push(v, t, 0);
2387 if (size > c)
2388 c = size;
2390 if (align > maxalign)
2391 maxalign = align;
2392 *ps = ss;
2393 ps = &ss->next;
2394 if (tok == ';' || tok == -1)
2395 break;
2396 skip(',');
2398 skip(';');
2400 if (tok == '}')
2401 break;
2403 skip('}');
2404 /* size for struct/union, dummy for enum */
2405 s->c = (c + maxalign - 1) & -maxalign;
2407 return u;
2410 /* return 0 if no type declaration. otherwise, return the basic type
2411 and skip it.
2412 XXX: A '2' is ored to ensure non zero return if int type.
2414 int ist(void)
2416 int t;
2417 Sym *s;
2419 t = 0;
2420 while(1) {
2421 if (tok == TOK_ENUM) {
2422 t |= struct_decl(VT_ENUM);
2423 } else if (tok == TOK_STRUCT || tok == TOK_UNION) {
2424 t |= struct_decl(VT_STRUCT);
2425 } else {
2426 if (tok == TOK_CHAR) {
2427 t |= VT_BYTE;
2428 } else if (tok == TOK_VOID) {
2429 t |= VT_VOID;
2430 } else if (tok == TOK_SHORT) {
2431 t |= VT_SHORT;
2432 } else if (tok == TOK_INT |
2433 (tok >= TOK_CONST & tok <= TOK_INLINE)) {
2434 /* ignored types */
2435 } else if (tok == TOK_FLOAT || tok == TOK_DOUBLE) {
2436 /* We allow that to compile standard headers */
2437 // warning("floats not supported");
2438 } else if (tok == TOK_EXTERN) {
2439 t |= VT_EXTERN;
2440 } else if (tok == TOK_STATIC) {
2441 t |= VT_STATIC;
2442 } else if (tok == TOK_UNSIGNED) {
2443 t |= VT_UNSIGNED;
2444 } else if (tok == TOK_TYPEDEF) {
2445 t |= VT_TYPEDEF;
2446 } else {
2447 s = sym_find(tok);
2448 if (!s || !(s->t & VT_TYPEDEF))
2449 break;
2450 t |= (s->t & ~VT_TYPEDEF);
2452 next();
2454 t |= 2;
2456 return t;
2459 int post_type(int t)
2461 int p, n, pt, l, t1;
2462 Sym **plast, *s, *first;
2464 if (tok == '(') {
2465 /* function declaration */
2466 next();
2467 l = 0;
2468 first = NULL;
2469 plast = &first;
2470 while (tok != ')') {
2471 /* read param name and compute offset */
2472 if (l != FUNC_OLD) {
2473 if (!(pt = ist())) {
2474 if (l) {
2475 error("invalid type");
2476 } else {
2477 l = FUNC_OLD;
2478 goto old_proto;
2481 if ((pt & VT_BTYPE) == VT_VOID && tok == ')')
2482 break;
2483 l = FUNC_NEW;
2484 pt = type_decl(&n, pt, TYPE_DIRECT | TYPE_ABSTRACT);
2485 } else {
2486 old_proto:
2487 n = tok;
2488 pt = VT_INT;
2489 next();
2491 /* array must be transformed to pointer according to ANSI C */
2492 pt &= ~VT_ARRAY;
2493 s = sym_push(n | SYM_FIELD, pt, 0);
2494 *plast = s;
2495 plast = &s->next;
2496 if (tok == ',') {
2497 next();
2498 if (l == FUNC_NEW && tok == TOK_DOTS) {
2499 l = FUNC_ELLIPSIS;
2500 next();
2501 break;
2505 skip(')');
2506 t1 = t & (VT_TYPEDEF | VT_STATIC | VT_EXTERN);
2507 t = post_type(t & ~(VT_TYPEDEF | VT_STATIC | VT_EXTERN));
2508 /* we push a anonymous symbol which will contain the function prototype */
2509 p = anon_sym++;
2510 s = sym_push(p, t, l);
2511 s->next = first;
2512 t = t1 | VT_FUNC | (p << VT_STRUCT_SHIFT);
2513 } else if (tok == '[') {
2514 /* array definition */
2515 next();
2516 n = -1;
2517 if (tok != ']') {
2518 n = expr_const();
2519 if (n < 0)
2520 error("invalid array size");
2522 skip(']');
2523 /* parse next post type */
2524 t1 = t & (VT_TYPEDEF | VT_STATIC | VT_EXTERN);
2525 t = post_type(t & ~(VT_TYPEDEF | VT_STATIC | VT_EXTERN));
2527 /* we push a anonymous symbol which will contain the array
2528 element type */
2529 p = anon_sym++;
2530 sym_push(p, t, n);
2531 t = t1 | VT_ARRAY | VT_PTR | (p << VT_STRUCT_SHIFT);
2533 return t;
2536 /* Read a type declaration (except basic type), and return the
2537 type. If v is true, then also put variable name in 'vc' */
2538 int type_decl(int *v, int t, int td)
2540 int u, p;
2541 Sym *s;
2543 t = t & -3; /* suppress the ored '2' */
2544 while (tok == '*') {
2545 next();
2546 while (tok == TOK_CONST || tok == TOK_VOLATILE || tok == TOK_RESTRICT)
2547 next();
2548 t = mk_pointer(t);
2551 /* recursive type */
2552 /* XXX: incorrect if abstract type for functions (e.g. 'int ()') */
2553 if (tok == '(') {
2554 next();
2555 u = type_decl(v, 0, td);
2556 skip(')');
2557 } else {
2558 u = 0;
2559 /* type identifier */
2560 if (tok >= TOK_IDENT && (td & TYPE_DIRECT)) {
2561 *v = tok;
2562 next();
2563 } else {
2564 if (!(td & TYPE_ABSTRACT))
2565 expect("identifier");
2566 *v = 0;
2569 /* append t at the end of u */
2570 t = post_type(t);
2571 if (!u)
2572 return t;
2573 p = u;
2574 while(1) {
2575 s = sym_find((unsigned)p >> VT_STRUCT_SHIFT);
2576 p = s->t;
2577 if (!p) {
2578 s->t = t;
2579 break;
2582 return u;
2585 /* define a new external reference to a function 'v' of type 'u' */
2586 Sym *external_sym(int v, int u)
2588 Sym *s;
2589 s = sym_find(v);
2590 if (!s) {
2591 /* push forward reference */
2592 s = sym_push1(&global_stack,
2593 v, u | VT_CONST | VT_FORWARD, 0);
2595 return s;
2598 void indir(void)
2600 if (vt & VT_LVAL)
2601 gv();
2602 if ((vt & VT_BTYPE) != VT_PTR)
2603 expect("pointer");
2604 vt = pointed_type(vt);
2605 if (!(vt & VT_ARRAY)) /* an array is never an lvalue */
2606 vt |= VT_LVAL;
2609 void unary(void)
2611 int n, t, ft, fc, p, align, size;
2612 Sym *s;
2613 GFuncContext gf;
2615 if (tok == TOK_NUM || tok == TOK_CCHAR || tok == TOK_LCHAR) {
2616 vset(VT_CONST, tokc);
2617 next();
2618 } else if (tok == TOK___FUNC__) {
2619 /* special function name identifier */
2620 /* generate (char *) type */
2621 vset(VT_CONST | mk_pointer(VT_BYTE), glo);
2622 strcpy((void *)glo, funcname);
2623 glo += strlen(funcname) + 1;
2624 next();
2625 } else if (tok == TOK_LSTR) {
2626 t = VT_INT;
2627 goto str_init;
2628 } else if (tok == TOK_STR) {
2629 /* string parsing */
2630 t = VT_BYTE;
2631 str_init:
2632 type_size(t, &align);
2633 glo = (glo + align - 1) & -align;
2634 fc = glo;
2635 /* we must declare it as an array first to use initializer parser */
2636 t = VT_CONST | VT_ARRAY | mk_pointer(t);
2637 decl_initializer(t, glo, 1, 0);
2638 glo += type_size(t, &align);
2639 /* put it as pointer */
2640 vset(t & ~VT_ARRAY, fc);
2641 } else {
2642 t = tok;
2643 next();
2644 if (t == '(') {
2645 /* cast ? */
2646 if (t = ist()) {
2647 ft = type_decl(&n, t, TYPE_ABSTRACT);
2648 skip(')');
2649 /* check ISOC99 compound literal */
2650 if (tok == '{') {
2651 /* data is allocated locally by default */
2652 if (global_expr)
2653 ft |= VT_CONST;
2654 else
2655 ft |= VT_LOCAL;
2656 /* all except arrays are lvalues */
2657 if (!(ft & VT_ARRAY))
2658 ft |= VT_LVAL;
2659 fc = decl_initializer_alloc(ft, 1);
2660 vset(ft, fc);
2661 } else {
2662 unary();
2663 gen_cast(ft);
2665 } else {
2666 expr();
2667 skip(')');
2669 } else if (t == '*') {
2670 unary();
2671 indir();
2672 } else if (t == '&') {
2673 unary();
2674 /* functions names must be treated as function pointers,
2675 except for unary '&' and sizeof. Since we consider that
2676 functions are not lvalues, we only have to handle it
2677 there and in function calls. */
2678 if ((vt & VT_BTYPE) != VT_FUNC)
2679 test_lvalue();
2680 vt = mk_pointer(vt & VT_LVALN);
2681 } else
2682 if (t == '!') {
2683 unary();
2684 if ((vt & (VT_VALMASK | VT_LVAL)) == VT_CONST)
2685 vc = !vc;
2686 else if ((vt & VT_VALMASK) == VT_CMP)
2687 vc = vc ^ 1;
2688 else
2689 vset(VT_JMP, gtst(1, 0));
2690 } else
2691 if (t == '~') {
2692 unary();
2693 vpush();
2694 vset(VT_CONST, -1);
2695 gen_op('^');
2696 } else
2697 if (t == '+') {
2698 unary();
2699 } else
2700 if (t == TOK_SIZEOF) {
2701 /* XXX: some code can be generated */
2702 if (tok == '(') {
2703 next();
2704 if (t = ist())
2705 vt = type_decl(&n, t, TYPE_ABSTRACT);
2706 else
2707 expr();
2708 skip(')');
2709 } else {
2710 unary();
2712 vset(VT_CONST, type_size(vt, &t));
2713 } else
2714 if (t == TOK_INC | t == TOK_DEC) {
2715 unary();
2716 inc(0, t);
2717 } else if (t == '-') {
2718 vset(VT_CONST, 0);
2719 vpush();
2720 unary();
2721 gen_op('-');
2722 } else
2724 s = sym_find(t);
2725 if (!s) {
2726 if (tok != '(')
2727 error("'%s' undeclared", get_tok_str(t, 0));
2728 /* for simple function calls, we tolerate undeclared
2729 external reference */
2730 p = anon_sym++;
2731 sym_push1(&global_stack, p, 0, FUNC_OLD);
2732 /* int() function */
2733 s = external_sym(t, VT_FUNC | (p << VT_STRUCT_SHIFT));
2735 vset(s->t, s->c);
2736 /* if forward reference, we must point to s */
2737 if (vt & VT_FORWARD)
2738 vc = (int)s;
2742 /* post operations */
2743 while (1) {
2744 if (tok == TOK_INC | tok == TOK_DEC) {
2745 inc(1, tok);
2746 next();
2747 } else if (tok == '.' | tok == TOK_ARROW) {
2748 /* field */
2749 if (tok == TOK_ARROW)
2750 indir();
2751 test_lvalue();
2752 vt &= VT_LVALN;
2753 next();
2754 /* expect pointer on structure */
2755 if ((vt & VT_BTYPE) != VT_STRUCT)
2756 expect("struct or union");
2757 s = sym_find(((unsigned)vt >> VT_STRUCT_SHIFT) | SYM_STRUCT);
2758 /* find field */
2759 tok |= SYM_FIELD;
2760 while (s = s->next) {
2761 if (s->v == tok)
2762 break;
2764 if (!s)
2765 error("field not found");
2766 /* add field offset to pointer */
2767 vt = (vt & ~VT_TYPE) | VT_INT; /* change type to int */
2768 vpush();
2769 vset(VT_CONST, s->c);
2770 gen_op('+');
2771 /* change type to field type, and set to lvalue */
2772 vt = (vt & ~VT_TYPE) | s->t;
2773 /* an array is never an lvalue */
2774 if (!(vt & VT_ARRAY))
2775 vt |= VT_LVAL;
2776 next();
2777 } else if (tok == '[') {
2778 next();
2779 vpush();
2780 expr();
2781 gen_op('+');
2782 indir();
2783 skip(']');
2784 } else if (tok == '(') {
2785 int rett, retc;
2787 /* function call */
2788 if ((vt & VT_BTYPE) != VT_FUNC) {
2789 /* pointer test (no array accepted) */
2790 if ((vt & (VT_BTYPE | VT_ARRAY)) == VT_PTR) {
2791 vt = pointed_type(vt);
2792 if ((vt & VT_BTYPE) != VT_FUNC)
2793 goto error_func;
2794 } else {
2795 error_func:
2796 expect("function pointer");
2798 } else {
2799 vt &= ~VT_LVAL; /* no lvalue */
2802 /* get return type */
2803 s = sym_find((unsigned)vt >> VT_STRUCT_SHIFT);
2804 vpush(); /* push function address */
2805 save_regs(); /* save used temporary registers */
2806 gfunc_start(&gf);
2807 next();
2808 #ifdef INVERT_FUNC_PARAMS
2810 int *str, len, parlevel, *saved_macro_ptr;
2811 Sym *args, *s1;
2813 /* read each argument and store it on a stack */
2814 /* XXX: merge it with macro args ? */
2815 args = NULL;
2816 while (tok != ')') {
2817 len = 0;
2818 str = NULL;
2819 parlevel = 0;
2820 while ((parlevel > 0 || (tok != ')' && tok != ',')) &&
2821 tok != -1) {
2822 if (tok == '(')
2823 parlevel++;
2824 else if (tok == ')')
2825 parlevel--;
2826 tok_add2(&str, &len, tok, tokc);
2827 next();
2829 tok_add(&str, &len, -1); /* end of file added */
2830 tok_add(&str, &len, 0);
2831 sym_push2(&args, 0, 0, (int)str);
2832 if (tok != ',')
2833 break;
2834 next();
2836 if (tok != ')')
2837 expect(")");
2839 /* now generate code in reverse order by reading the stack */
2840 saved_macro_ptr = macro_ptr;
2841 while (args) {
2842 macro_ptr = (int *)args->c;
2843 next();
2844 expr_eq();
2845 if (tok != -1)
2846 expect("',' or ')'");
2847 gfunc_param(&gf);
2848 s1 = args->prev;
2849 free((int *)args->c);
2850 free(args);
2851 args = s1;
2853 macro_ptr = saved_macro_ptr;
2854 /* restore token */
2855 tok = ')';
2857 #endif
2858 /* compute first implicit argument if a structure is returned */
2859 if ((s->t & VT_BTYPE) == VT_STRUCT) {
2860 /* get some space for the returned structure */
2861 size = type_size(s->t, &align);
2862 loc = (loc - size) & -align;
2863 rett = s->t | VT_LOCAL | VT_LVAL;
2864 /* pass it as 'int' to avoid structure arg passing
2865 problems */
2866 vset(VT_INT | VT_LOCAL, loc);
2867 retc = vc;
2868 gfunc_param(&gf);
2869 } else {
2870 rett = s->t | FUNC_RET_REG; /* return in register */
2871 retc = 0;
2873 #ifndef INVERT_FUNC_PARAMS
2874 while (tok != ')') {
2875 expr_eq();
2876 gfunc_param(&gf);
2877 if (tok == ',')
2878 next();
2880 #endif
2881 skip(')');
2882 vpop(&vt, &vc);
2883 gfunc_call(&gf);
2884 /* return value */
2885 vt = rett;
2886 vc = retc;
2887 } else {
2888 break;
2893 int is_compatible_types(int t1, int t2)
2895 Sym *s1, *s2;
2896 int bt1, bt2;
2898 t1 &= VT_TYPE;
2899 t2 &= VT_TYPE;
2900 bt1 = t1 & VT_BTYPE;
2901 bt2 = t2 & VT_BTYPE;
2902 if (bt1 == VT_PTR) {
2903 t1 = pointed_type(t1);
2904 /* if function, then convert implictely to function pointer */
2905 if (bt2 != VT_FUNC) {
2906 if (bt2 != VT_PTR)
2907 return 0;
2908 t2 = pointed_type(t2);
2910 /* void matches everything */
2911 t1 &= VT_TYPE;
2912 t2 &= VT_TYPE;
2913 if (t1 == VT_VOID || t2 == VT_VOID)
2914 return 1;
2915 return is_compatible_types(t1, t2);
2916 } else if (bt1 == VT_STRUCT) {
2917 return (t2 == t1);
2918 } else if (bt1 == VT_FUNC) {
2919 if (bt2 != VT_FUNC)
2920 return 0;
2921 s1 = sym_find(((unsigned)t1 >> VT_STRUCT_SHIFT));
2922 s2 = sym_find(((unsigned)t2 >> VT_STRUCT_SHIFT));
2923 if (!is_compatible_types(s1->t, s2->t))
2924 return 0;
2925 /* XXX: not complete */
2926 if (s1->c == FUNC_OLD || s2->c == FUNC_OLD)
2927 return 1;
2928 if (s1->c != s2->c)
2929 return 0;
2930 while (s1 != NULL) {
2931 if (s2 == NULL)
2932 return 0;
2933 if (!is_compatible_types(s1->t, s2->t))
2934 return 0;
2935 s1 = s1->next;
2936 s2 = s2->next;
2938 if (s2)
2939 return 0;
2940 return 1;
2941 } else {
2942 /* XXX: not complete */
2943 return 1;
2947 int check_assign_types(int t1, int t2)
2949 t1 &= VT_TYPE;
2950 t2 &= VT_TYPE;
2951 if ((t1 & VT_BTYPE) == VT_PTR &&
2952 (t2 & VT_BTYPE) == VT_FUNC) {
2953 return is_compatible_types(pointed_type(t1), t2);
2954 } else {
2955 return is_compatible_types(t1, t2);
2960 void uneq()
2962 int t;
2964 unary();
2965 if (tok == '=' |
2966 (tok >= TOK_A_MOD & tok <= TOK_A_DIV) |
2967 tok == TOK_A_XOR | tok == TOK_A_OR |
2968 tok == TOK_A_SHL | tok == TOK_A_SAR) {
2969 test_lvalue();
2970 vpush();
2971 t = tok;
2972 next();
2973 if (t == '=') {
2974 expr_eq();
2975 if (!check_assign_types(vstack_ptr[-2], vt))
2976 warning("incompatible types");
2977 } else {
2978 vpush();
2979 expr_eq();
2980 gen_op(t & 0x7f);
2982 vstore();
2986 void sum(l)
2988 int t;
2990 if (l == 0)
2991 uneq();
2992 else {
2993 sum(--l);
2994 while ((l == 0 & (tok == '*' | tok == '/' | tok == '%')) |
2995 (l == 1 & (tok == '+' | tok == '-')) |
2996 (l == 2 & (tok == TOK_SHL | tok == TOK_SAR)) |
2997 (l == 3 & ((tok >= TOK_ULE & tok <= TOK_GT) |
2998 tok == TOK_ULT | tok == TOK_UGE)) |
2999 (l == 4 & (tok == TOK_EQ | tok == TOK_NE)) |
3000 (l == 5 & tok == '&') |
3001 (l == 6 & tok == '^') |
3002 (l == 7 & tok == '|') |
3003 (l == 8 & tok == TOK_LAND) |
3004 (l == 9 & tok == TOK_LOR)) {
3005 vpush();
3006 t = tok;
3007 next();
3008 sum(l);
3009 gen_op(t);
3014 /* only used if non constant */
3015 void eand(void)
3017 int t;
3019 sum(8);
3020 t = 0;
3021 while (1) {
3022 if (tok != TOK_LAND) {
3023 if (t) {
3024 t = gtst(1, t);
3025 vset(VT_JMPI, t);
3027 break;
3029 t = gtst(1, t);
3030 next();
3031 sum(8);
3035 void eor(void)
3037 int t;
3039 eand();
3040 t = 0;
3041 while (1) {
3042 if (tok != TOK_LOR) {
3043 if (t) {
3044 t = gtst(0, t);
3045 vset(VT_JMP, t);
3047 break;
3049 t = gtst(0, t);
3050 next();
3051 eand();
3055 /* XXX: better constant handling */
3056 void expr_eq()
3058 int t, u, c, r1, r2;
3060 if (const_wanted) {
3061 sum(10);
3062 if (tok == '?') {
3063 c = vc;
3064 next();
3065 expr();
3066 t = vc;
3067 skip(':');
3068 expr_eq();
3069 if (c)
3070 vc = t;
3072 } else {
3073 eor();
3074 if (tok == '?') {
3075 next();
3076 t = gtst(1, 0);
3077 expr();
3078 r1 = gv();
3079 skip(':');
3080 u = gjmp(0);
3081 gsym(t);
3082 expr_eq();
3083 r2 = gv();
3084 move_reg(r1, r2);
3085 vt = (vt & VT_TYPE) | r1;
3086 gsym(u);
3091 void expr()
3093 while (1) {
3094 expr_eq();
3095 if (tok != ',')
3096 break;
3097 next();
3101 int expr_const()
3103 int a;
3104 a = const_wanted;
3105 const_wanted = 1;
3106 expr_eq();
3107 if ((vt & (VT_CONST | VT_LVAL)) != VT_CONST)
3108 expect("constant");
3109 const_wanted = a;
3110 return vc;
3113 /* return the label token if current token is a label, otherwise
3114 return zero */
3115 int is_label(void)
3117 int t, c;
3119 /* fast test first */
3120 if (tok < TOK_UIDENT)
3121 return 0;
3122 t = tok;
3123 c = tokc;
3124 next();
3125 if (tok == ':') {
3126 next();
3127 return t;
3128 } else {
3129 /* XXX: may not work in all cases (macros ?) */
3130 tok1 = tok;
3131 tok1c = tokc;
3132 tok = t;
3133 tokc = c;
3134 return 0;
3138 void block(int *bsym, int *csym, int *case_sym, int *def_sym, int case_reg)
3140 int a, b, c, d;
3141 Sym *s;
3143 if (tok == TOK_IF) {
3144 /* if test */
3145 next();
3146 skip('(');
3147 expr();
3148 skip(')');
3149 a = gtst(1, 0);
3150 block(bsym, csym, case_sym, def_sym, case_reg);
3151 c = tok;
3152 if (c == TOK_ELSE) {
3153 next();
3154 d = gjmp(0);
3155 gsym(a);
3156 block(bsym, csym, case_sym, def_sym, case_reg);
3157 gsym(d); /* patch else jmp */
3158 } else
3159 gsym(a);
3160 } else if (tok == TOK_WHILE) {
3161 next();
3162 d = ind;
3163 skip('(');
3164 expr();
3165 skip(')');
3166 a = gtst(1, 0);
3167 b = 0;
3168 block(&a, &b, case_sym, def_sym, case_reg);
3169 oad(0xe9, d - ind - 5); /* jmp */
3170 gsym(a);
3171 gsym_addr(b, d);
3172 } else if (tok == '{') {
3173 next();
3174 /* declarations */
3175 s = local_stack.top;
3176 while (tok != '}') {
3177 decl(VT_LOCAL);
3178 if (tok != '}')
3179 block(bsym, csym, case_sym, def_sym, case_reg);
3181 /* pop locally defined symbols */
3182 sym_pop(&local_stack, s);
3183 next();
3184 } else if (tok == TOK_RETURN) {
3185 next();
3186 if (tok != ';') {
3187 if ((func_vt & VT_BTYPE) == VT_STRUCT) {
3188 /* if returning structure, must copy it to implicit
3189 first pointer arg location */
3190 vset(mk_pointer(func_vt) | VT_LOCAL | VT_LVAL, func_vc);
3191 indir();
3192 vpush();
3194 expr();
3195 if ((func_vt & VT_BTYPE) == VT_STRUCT) {
3196 /* copy structure value to pointer */
3197 vstore();
3198 } else {
3199 /* move return value to standard return register */
3200 move_reg(FUNC_RET_REG, gv());
3203 skip(';');
3204 rsym = gjmp(rsym); /* jmp */
3205 } else if (tok == TOK_BREAK) {
3206 /* compute jump */
3207 if (!bsym)
3208 error("cannot break");
3209 *bsym = gjmp(*bsym);
3210 next();
3211 skip(';');
3212 } else if (tok == TOK_CONTINUE) {
3213 /* compute jump */
3214 if (!csym)
3215 error("cannot continue");
3216 *csym = gjmp(*csym);
3217 next();
3218 skip(';');
3219 } else if (tok == TOK_FOR) {
3220 int e;
3221 next();
3222 skip('(');
3223 if (tok != ';')
3224 expr();
3225 skip(';');
3226 d = ind;
3227 c = ind;
3228 a = 0;
3229 b = 0;
3230 if (tok != ';') {
3231 expr();
3232 a = gtst(1, 0);
3234 skip(';');
3235 if (tok != ')') {
3236 e = gjmp(0);
3237 c = ind;
3238 expr();
3239 oad(0xe9, d - ind - 5); /* jmp */
3240 gsym(e);
3242 skip(')');
3243 block(&a, &b, case_sym, def_sym, case_reg);
3244 oad(0xe9, c - ind - 5); /* jmp */
3245 gsym(a);
3246 gsym_addr(b, c);
3247 } else
3248 if (tok == TOK_DO) {
3249 next();
3250 a = 0;
3251 b = 0;
3252 d = ind;
3253 block(&a, &b, case_sym, def_sym, case_reg);
3254 skip(TOK_WHILE);
3255 skip('(');
3256 gsym(b);
3257 expr();
3258 c = gtst(0, 0);
3259 gsym_addr(c, d);
3260 skip(')');
3261 gsym(a);
3262 skip(';');
3263 } else
3264 if (tok == TOK_SWITCH) {
3265 next();
3266 skip('(');
3267 expr();
3268 case_reg = gv();
3269 skip(')');
3270 a = 0;
3271 b = 0;
3272 c = 0;
3273 block(&a, csym, &b, &c, case_reg);
3274 /* if no default, jmp after switch */
3275 if (c == 0)
3276 c = ind;
3277 /* default label */
3278 gsym_addr(b, c);
3279 /* break label */
3280 gsym(a);
3281 } else
3282 if (tok == TOK_CASE) {
3283 next();
3284 a = expr_const();
3285 if (!case_sym)
3286 expect("switch");
3287 gsym(*case_sym);
3288 vset(case_reg, 0);
3289 vpush();
3290 vset(VT_CONST, a);
3291 gen_op(TOK_EQ);
3292 *case_sym = gtst(1, 0);
3293 skip(':');
3294 block(bsym, csym, case_sym, def_sym, case_reg);
3295 } else
3296 if (tok == TOK_DEFAULT) {
3297 next();
3298 skip(':');
3299 if (!def_sym)
3300 expect("switch");
3301 if (*def_sym)
3302 error("too many 'default'");
3303 *def_sym = ind;
3304 block(bsym, csym, case_sym, def_sym, case_reg);
3305 } else
3306 if (tok == TOK_GOTO) {
3307 next();
3308 s = sym_find1(&label_stack, tok);
3309 /* put forward definition if needed */
3310 if (!s)
3311 s = sym_push1(&label_stack, tok, VT_FORWARD, 0);
3312 /* label already defined */
3313 if (s->t & VT_FORWARD)
3314 s->c = gjmp(s->c); /* jmp xxx */
3315 else
3316 oad(0xe9, s->c - ind - 5); /* jmp xxx */
3317 next();
3318 skip(';');
3319 } else {
3320 b = is_label();
3321 if (b) {
3322 /* label case */
3323 s = sym_find1(&label_stack, b);
3324 if (s) {
3325 if (!(s->t & VT_FORWARD))
3326 error("multiple defined label");
3327 gsym(s->c);
3328 s->c = ind;
3329 s->t = 0;
3330 } else {
3331 sym_push1(&label_stack, b, 0, ind);
3333 /* we accept this, but it is a mistake */
3334 if (tok == '}')
3335 warning("deprecated use of label at end of compound statement");
3336 else
3337 block(bsym, csym, case_sym, def_sym, case_reg);
3338 } else {
3339 /* expression case */
3340 if (tok != ';') {
3341 expr();
3343 skip(';');
3348 /* t is the array or struct type. c is the array or struct
3349 address. cur_index/cur_field is the pointer to the current
3350 value. 'size_only' is true if only size info is needed (only used
3351 in arrays) */
3352 void decl_designator(int t, int c,
3353 int *cur_index, Sym **cur_field,
3354 int size_only)
3356 Sym *s, *f;
3357 int notfirst, index, align, l;
3359 notfirst = 0;
3360 if (gnu_ext && (l = is_label()) != 0)
3361 goto struct_field;
3363 while (tok == '[' || tok == '.') {
3364 if (tok == '[') {
3365 if (!(t & VT_ARRAY))
3366 expect("array type");
3367 s = sym_find(((unsigned)t >> VT_STRUCT_SHIFT));
3368 next();
3369 index = expr_const();
3370 if (index < 0 || (s->c >= 0 && index >= s->c))
3371 expect("invalid index");
3372 skip(']');
3373 if (!notfirst)
3374 *cur_index = index;
3375 t = pointed_type(t);
3376 c += index * type_size(t, &align);
3377 } else {
3378 next();
3379 l = tok;
3380 next();
3381 struct_field:
3382 if ((t & VT_BTYPE) != VT_STRUCT)
3383 expect("struct/union type");
3384 s = sym_find(((unsigned)t >> VT_STRUCT_SHIFT) | SYM_STRUCT);
3385 l |= SYM_FIELD;
3386 f = s->next;
3387 while (f) {
3388 if (f->v == l)
3389 break;
3390 f = f->next;
3392 if (!f)
3393 expect("field");
3394 if (!notfirst)
3395 *cur_field = f;
3396 t = f->t | (t & ~VT_TYPE);
3397 c += f->c;
3399 notfirst = 1;
3401 if (notfirst) {
3402 if (tok == '=') {
3403 next();
3404 } else {
3405 if (!gnu_ext)
3406 expect("=");
3408 } else {
3409 if (t & VT_ARRAY) {
3410 index = *cur_index;
3411 t = pointed_type(t);
3412 c += index * type_size(t, &align);
3413 } else {
3414 f = *cur_field;
3415 if (!f)
3416 error("too many field init");
3417 t = f->t | (t & ~VT_TYPE);
3418 c += f->c;
3421 decl_initializer(t, c, 0, size_only);
3424 /* store a value or an expression directly in global data or in local array */
3426 void init_putv(int t, int c, int v, int is_expr)
3428 int saved_global_expr;
3430 if ((t & VT_VALMASK) == VT_CONST) {
3431 if (is_expr) {
3432 /* compound literals must be allocated globally in this case */
3433 saved_global_expr = global_expr;
3434 global_expr = 1;
3435 v = expr_const();
3436 global_expr = saved_global_expr;
3438 if ((t & VT_BTYPE) == VT_BYTE)
3439 *(char *)c = v;
3440 else if ((t & VT_BTYPE) == VT_SHORT)
3441 *(short *)c = v;
3442 else
3443 *(int *)c = v;
3444 } else {
3445 vt = t;
3446 vc = c;
3447 vpush();
3448 if (is_expr)
3449 expr_eq();
3450 else
3451 vset(VT_CONST, v);
3452 vstore();
3456 /* put zeros for variable based init */
3457 void init_putz(int t, int c, int size)
3459 GFuncContext gf;
3461 if ((t & VT_VALMASK) == VT_CONST) {
3462 /* nothing to do because global are already set to zero */
3463 } else {
3464 gfunc_start(&gf);
3465 vset(VT_CONST, size);
3466 gfunc_param(&gf);
3467 vset(VT_CONST, 0);
3468 gfunc_param(&gf);
3469 vset(VT_LOCAL, c);
3470 gfunc_param(&gf);
3471 vset(VT_CONST, (int)&memset);
3472 gfunc_call(&gf);
3476 /* 't' contains the type and storage info. c is the address of the
3477 object. 'first' is true if array '{' must be read (multi dimension
3478 implicit array init handling). 'size_only' is true if size only
3479 evaluation is wanted (only for arrays). */
3480 void decl_initializer(int t, int c, int first, int size_only)
3482 int index, array_length, n, no_oblock, nb, parlevel, i;
3483 int t1, size1, align1;
3484 Sym *s, *f;
3485 TokenSym *ts;
3487 if (t & VT_ARRAY) {
3488 s = sym_find(((unsigned)t >> VT_STRUCT_SHIFT));
3489 n = s->c;
3490 array_length = 0;
3491 t1 = pointed_type(t);
3492 size1 = type_size(t1, &align1);
3494 no_oblock = 1;
3495 if ((first && tok != TOK_LSTR && tok != TOK_STR) ||
3496 tok == '{') {
3497 skip('{');
3498 no_oblock = 0;
3501 /* only parse strings here if correct type (otherwise: handle
3502 them as ((w)char *) expressions */
3503 if ((tok == TOK_LSTR &&
3504 (t1 & VT_BTYPE) == VT_INT) ||
3505 (tok == TOK_STR &&
3506 (t1 & VT_BTYPE) == VT_BYTE)) {
3507 /* XXX: move multiple string parsing in parser ? */
3508 while (tok == TOK_STR || tok == TOK_LSTR) {
3509 ts = (TokenSym *)tokc;
3510 /* compute maximum number of chars wanted */
3511 nb = ts->len;
3512 if (n >= 0 && nb > (n - array_length))
3513 nb = n - array_length;
3514 if (!size_only) {
3515 if (ts->len > nb)
3516 warning("initializer-string for array is too long");
3517 for(i=0;i<nb;i++) {
3518 init_putv(t1, c + (array_length + i) * size1,
3519 ts->str[i], 0);
3522 array_length += nb;
3523 next();
3525 /* only add trailing zero if enough storage (no
3526 warning in this case since it is standard) */
3527 if (n < 0 || array_length < n) {
3528 if (!size_only) {
3529 init_putv(t1, c + (array_length * size1), 0, 0);
3531 array_length++;
3533 } else {
3534 index = 0;
3535 while (tok != '}') {
3536 decl_designator(t, c, &index, NULL, size_only);
3537 if (n >= 0 && index >= n)
3538 error("index too large");
3539 /* must put zero in holes (note that doing it that way
3540 ensures that it even works with designators) */
3541 if (!size_only && array_length < index) {
3542 init_putz(t1, c + array_length * size1,
3543 (index - array_length) * size1);
3545 index++;
3546 if (index > array_length)
3547 array_length = index;
3548 /* special test for multi dimensional arrays (may not
3549 be strictly correct if designators are used at the
3550 same time) */
3551 if (index >= n && no_oblock)
3552 break;
3553 if (tok == '}')
3554 break;
3555 skip(',');
3558 if (!no_oblock)
3559 skip('}');
3560 /* put zeros at the end */
3561 if (!size_only && n >= 0 && array_length < n) {
3562 init_putz(t1, c + array_length * size1,
3563 (n - array_length) * size1);
3565 /* patch type size if needed */
3566 if (n < 0)
3567 s->c = array_length;
3568 } else if ((t & VT_BTYPE) == VT_STRUCT && tok == '{') {
3569 /* XXX: union needs only one init */
3570 next();
3571 s = sym_find(((unsigned)t >> VT_STRUCT_SHIFT) | SYM_STRUCT);
3572 f = s->next;
3573 array_length = 0;
3574 index = 0;
3575 n = s->c;
3576 while (tok != '}') {
3577 decl_designator(t, c, NULL, &f, size_only);
3578 /* fill with zero between fields */
3579 index = f->c;
3580 if (!size_only && array_length < index) {
3581 init_putz(t, c + array_length,
3582 index - array_length);
3584 index = index + type_size(f->t, &align1);
3585 if (index > array_length)
3586 array_length = index;
3587 if (tok == '}')
3588 break;
3589 skip(',');
3590 f = f->next;
3592 /* put zeros at the end */
3593 if (!size_only && array_length < n) {
3594 init_putz(t, c + array_length,
3595 n - array_length);
3597 skip('}');
3598 } else if (tok == '{') {
3599 next();
3600 decl_initializer(t, c, first, size_only);
3601 skip('}');
3602 } else if (size_only) {
3603 /* just skip expression */
3604 parlevel = 0;
3605 while ((parlevel > 0 || (tok != '}' && tok != ',')) &&
3606 tok != -1) {
3607 if (tok == '(')
3608 parlevel++;
3609 else if (tok == ')')
3610 parlevel--;
3611 next();
3613 } else {
3614 init_putv(t, c, 0, 1);
3618 /* parse an initializer for type 't' if 'has_init' is true, and
3619 allocate space in local or global data space. The allocated address
3620 in returned */
3621 int decl_initializer_alloc(int t, int has_init)
3623 int size, align, addr, tok1;
3624 int *init_str, init_len, level, *saved_macro_ptr;
3626 size = type_size(t, &align);
3627 /* If unknown size, we must evaluate it before
3628 evaluating initializers because
3629 initializers can generate global data too
3630 (e.g. string pointers or ISOC99 compound
3631 literals). It also simplifies local
3632 initializers handling */
3633 init_len = 0;
3634 init_str = NULL;
3635 saved_macro_ptr = NULL; /* avoid warning */
3636 tok1 = 0;
3637 if (size < 0) {
3638 if (!has_init)
3639 error("unknown type size");
3640 /* get all init string */
3641 level = 0;
3642 while (level > 0 || (tok != ',' && tok != ';')) {
3643 if (tok < 0)
3644 error("unexpect end of file in initializer");
3645 tok_add2(&init_str, &init_len, tok, tokc);
3646 if (tok == '{')
3647 level++;
3648 else if (tok == '}') {
3649 if (level == 0)
3650 break;
3651 level--;
3653 next();
3655 tok1 = tok;
3656 tok_add(&init_str, &init_len, -1);
3657 tok_add(&init_str, &init_len, 0);
3659 /* compute size */
3660 saved_macro_ptr = macro_ptr;
3661 macro_ptr = init_str;
3662 next();
3663 decl_initializer(t, 0, 1, 1);
3664 /* prepare second initializer parsing */
3665 macro_ptr = init_str;
3666 next();
3668 /* if still unknown size, error */
3669 size = type_size(t, &align);
3670 if (size < 0)
3671 error("unknown type size");
3673 if ((t & VT_VALMASK) == VT_LOCAL) {
3674 loc = (loc - size) & -align;
3675 addr = loc;
3676 } else {
3677 glo = (glo + align - 1) & -align;
3678 addr = glo;
3679 /* very important to increment global
3680 pointer at this time because
3681 initializers themselves can create new
3682 initializers */
3683 glo += size;
3685 if (has_init) {
3686 decl_initializer(t, addr, 1, 0);
3687 /* restore parse state if needed */
3688 if (init_str) {
3689 free(init_str);
3690 macro_ptr = saved_macro_ptr;
3691 tok = tok1;
3694 return addr;
3698 /* 'l' is VT_LOCAL or VT_CONST to define default storage type */
3699 void decl(int l)
3701 int *a, t, b, v, u, addr, has_init, size, align;
3702 Sym *sym;
3704 while (1) {
3705 b = ist();
3706 if (!b) {
3707 /* skip redundant ';' */
3708 /* XXX: find more elegant solution */
3709 if (tok == ';') {
3710 next();
3711 continue;
3713 /* special test for old K&R protos without explicit int
3714 type. Only accepted when defining global data */
3715 if (l == VT_LOCAL || tok < TOK_DEFINE)
3716 break;
3717 b = VT_INT;
3719 if (((b & VT_BTYPE) == VT_ENUM ||
3720 (b & VT_BTYPE) == VT_STRUCT) &&
3721 tok == ';') {
3722 /* we accept no variable after */
3723 next();
3724 continue;
3726 while (1) { /* iterate thru each declaration */
3727 t = type_decl(&v, b, TYPE_DIRECT);
3728 if (tok == '{') {
3729 if (l == VT_LOCAL)
3730 error("cannot use local functions");
3731 if (!(t & VT_FUNC))
3732 expect("function definition");
3733 /* patch forward references */
3734 if ((sym = sym_find(v)) && (sym->t & VT_FORWARD)) {
3735 greloc_patch(sym, ind);
3736 sym->t = VT_CONST | t;
3737 } else {
3738 /* put function address */
3739 sym_push1(&global_stack, v, VT_CONST | t, ind);
3741 funcname = get_tok_str(v, 0);
3742 /* push a dummy symbol to enable local sym storage */
3743 sym_push1(&local_stack, 0, 0, 0);
3744 /* define parameters */
3745 sym = sym_find((unsigned)t >> VT_STRUCT_SHIFT);
3746 /* XXX: the following is x86 dependant -> move it to
3747 x86 code gen */
3748 addr = 8;
3749 /* if the function returns a structure, then add an
3750 implicit pointer parameter */
3751 func_vt = sym->t;
3752 if ((func_vt & VT_BTYPE) == VT_STRUCT) {
3753 func_vc = addr;
3754 addr += 4;
3756 while (sym = sym->next) {
3757 u = sym->t;
3758 sym_push(sym->v & ~SYM_FIELD,
3759 u | VT_LOCAL | VT_LVAL,
3760 addr);
3761 if ((u & VT_BTYPE) == VT_STRUCT) {
3762 #ifdef FUNC_STRUCT_PARAM_AS_PTR
3763 /* structs are passed as pointer */
3764 size = 4;
3765 #else
3766 /* structs are directly put on stack (x86
3767 like) */
3768 size = type_size(u, &align);
3769 size = (size + 3) & ~3;
3770 #endif
3771 } else {
3772 /* XXX: size will be different someday */
3773 size = 4;
3775 addr += size;
3777 loc = 0;
3778 o(0xe58955); /* push %ebp, mov %esp, %ebp */
3779 a = (int *)oad(0xec81, 0); /* sub $xxx, %esp */
3780 rsym = 0;
3781 block(0, 0, 0, 0, 0);
3782 gsym(rsym);
3783 o(0xc3c9); /* leave, ret */
3784 *a = (-loc + 3) & -4; /* align local size to word &
3785 save local variables */
3786 sym_pop(&label_stack, 0); /* reset label stack */
3787 sym_pop(&local_stack, 0); /* reset local stack */
3788 funcname = ""; /* for safety */
3789 func_vt = VT_VOID; /* for safety */
3790 break;
3791 } else {
3792 if (b & VT_TYPEDEF) {
3793 /* save typedefed type */
3794 /* XXX: test storage specifiers ? */
3795 sym_push(v, t | VT_TYPEDEF, 0);
3796 } else if ((t & VT_BTYPE) == VT_FUNC) {
3797 /* external function definition */
3798 external_sym(v, t);
3799 } else {
3800 /* not lvalue if array */
3801 if (!(t & VT_ARRAY))
3802 t |= VT_LVAL;
3803 if (b & VT_EXTERN) {
3804 /* external variable */
3805 external_sym(v, t);
3806 } else {
3807 u = l;
3808 if (t & VT_STATIC)
3809 u = VT_CONST;
3810 u |= t;
3811 has_init = (tok == '=');
3812 if (has_init)
3813 next();
3814 addr = decl_initializer_alloc(u, has_init);
3815 if (l == VT_CONST) {
3816 /* global scope: see if already defined */
3817 sym = sym_find(v);
3818 if (!sym)
3819 goto do_def;
3820 if (!is_compatible_types(sym->t, u))
3821 error("incompatible types for redefinition of '%s'",
3822 get_tok_str(v, 0));
3823 if (!(sym->t & VT_FORWARD))
3824 error("redefinition of '%s'", get_tok_str(v, 0));
3825 greloc_patch(sym, addr);
3826 } else {
3827 do_def:
3828 sym_push(v, u, addr);
3832 if (tok != ',') {
3833 skip(';');
3834 break;
3836 next();
3842 /* put all global symbols in the extern stack and do all the
3843 resolving which can be done without using external symbols from DLLs */
3844 /* XXX: could try to verify types, but would not to save them in
3845 extern_stack too */
3846 void resolve_global_syms(void)
3848 Sym *s, *s1, *ext_sym;
3849 Reloc **p;
3851 s = global_stack.top;
3852 while (s != NULL) {
3853 s1 = s->prev;
3854 /* do not save static or typedefed symbols or types */
3855 if (!(s->t & (VT_STATIC | VT_TYPEDEF)) &&
3856 !(s->v & (SYM_FIELD | SYM_STRUCT)) &&
3857 (s->v < SYM_FIRST_ANOM)) {
3858 ext_sym = sym_find1(&extern_stack, s->v);
3859 if (!ext_sym) {
3860 /* if the symbol do not exist, we simply save it */
3861 sym_push1(&extern_stack, s->v, s->t, s->c);
3862 } else if (ext_sym->t & VT_FORWARD) {
3863 /* external symbol already exists, but only as forward
3864 definition */
3865 if (!(s->t & VT_FORWARD)) {
3866 /* s is not forward, so we can relocate all symbols */
3867 greloc_patch(ext_sym, s->c);
3868 } else {
3869 /* the two symbols are forward: merge them */
3870 p = (Reloc **)&ext_sym->c;
3871 while (*p != NULL)
3872 p = &(*p)->next;
3873 *p = (Reloc *)s->c;
3875 } else {
3876 /* external symbol already exists and is defined :
3877 patch all references to it */
3878 if (!(s->t & VT_FORWARD))
3879 error("'%s' defined twice", get_tok_str(s->v, 0));
3880 greloc_patch(s, ext_sym->c);
3883 s = s1;
3887 /* compile a C file. Return non zero if errors. */
3888 int tcc_compile_file(const char *filename1)
3890 Sym *define_start;
3892 filename = (char *)filename1;
3894 line_num = 1;
3895 funcname = "";
3896 file = fopen(filename, "r");
3897 if (!file)
3898 error("file '%s' not found", filename);
3899 include_stack_ptr = include_stack;
3900 ifdef_stack_ptr = ifdef_stack;
3902 vstack_ptr = vstack;
3903 anon_sym = SYM_FIRST_ANOM;
3905 define_start = define_stack.top;
3906 inp();
3907 ch = '\n'; /* needed to parse correctly first preprocessor command */
3908 next();
3909 decl(VT_CONST);
3910 if (tok != -1)
3911 expect("declaration");
3912 fclose(file);
3914 /* reset define stack, but leave -Dsymbols (may be incorrect if
3915 they are undefined) */
3916 sym_pop(&define_stack, define_start);
3918 resolve_global_syms();
3920 sym_pop(&global_stack, NULL);
3922 return 0;
3925 /* open a dynamic library so that its symbol are available for
3926 compiled programs */
3927 void open_dll(char *libname)
3929 char buf[1024];
3930 void *h;
3932 snprintf(buf, sizeof(buf), "lib%s.so", libname);
3933 h = dlopen(buf, RTLD_GLOBAL | RTLD_LAZY);
3934 if (!h)
3935 error((char *)dlerror());
3938 void resolve_extern_syms(void)
3940 Sym *s, *s1;
3941 char *str;
3942 int addr;
3944 s = extern_stack.top;
3945 while (s != NULL) {
3946 s1 = s->prev;
3947 if (s->t & VT_FORWARD) {
3948 /* if there is at least one relocation to do, then find it
3949 and patch it */
3950 if (s->c) {
3951 str = get_tok_str(s->v, 0);
3952 addr = (int)dlsym(NULL, str);
3953 if (!addr)
3954 error("unresolved external reference '%s'", str);
3955 greloc_patch(s, addr);
3958 s = s1;
3962 /* output a binary file (for testing) */
3963 void build_exe(char *filename)
3965 FILE *f;
3966 f = fopen(filename, "w");
3967 fwrite((void *)prog, 1, ind - prog, f);
3968 fclose(f);
3971 int main(int argc, char **argv)
3973 Sym *s;
3974 int (*t)();
3975 char *p, *r, *outfile;
3976 int optind;
3978 include_paths[0] = "/usr/include";
3979 include_paths[1] = "/usr/lib/tcc";
3980 include_paths[2] = "/usr/local/lib/tcc";
3981 nb_include_paths = 3;
3983 /* add all tokens */
3984 tok_ident = TOK_IDENT;
3985 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";
3986 while (*p) {
3987 r = p;
3988 while (*r++);
3989 tok_alloc(p, r - p - 1);
3990 p = r;
3993 /* standard defines */
3994 define_symbol("__STDC__");
3995 #ifdef __i386__
3996 define_symbol("__i386__");
3997 #endif
3998 /* tiny C specific defines */
3999 define_symbol("__TINYC__");
4001 glo = (int)malloc(DATA_SIZE);
4002 memset((void *)glo, 0, DATA_SIZE);
4003 prog = (int)malloc(TEXT_SIZE);
4004 ind = prog;
4006 optind = 1;
4007 outfile = NULL;
4008 while (1) {
4009 if (optind >= argc) {
4010 show_help:
4011 printf("tcc version 0.9.1 - Tiny C Compiler - Copyright (C) 2001 Fabrice Bellard\n"
4012 "usage: tcc [-Idir] [-Dsym] [-llib] [-i infile]... infile [infile_args...]\n");
4013 return 1;
4015 r = argv[optind];
4016 if (r[0] != '-')
4017 break;
4018 optind++;
4019 if (r[1] == 'I') {
4020 if (nb_include_paths >= INCLUDE_PATHS_MAX)
4021 error("too many include paths");
4022 include_paths[nb_include_paths++] = r + 2;
4023 } else if (r[1] == 'D') {
4024 define_symbol(r + 2);
4025 } else if (r[1] == 'l') {
4026 open_dll(r + 2);
4027 } else if (r[1] == 'i') {
4028 if (optind >= argc)
4029 goto show_help;
4030 tcc_compile_file(argv[optind++]);
4031 } else if (r[1] == 'o') {
4032 /* currently, only for testing, so not documented */
4033 if (optind >= argc)
4034 goto show_help;
4035 outfile = argv[optind++];
4036 } else {
4037 fprintf(stderr, "invalid option -- '%s'\n", r);
4038 exit(1);
4042 tcc_compile_file(argv[optind]);
4044 resolve_extern_syms();
4046 if (outfile) {
4047 build_exe(outfile);
4048 return 0;
4049 } else {
4050 s = sym_find1(&extern_stack, TOK_MAIN);
4051 if (!s || (s->t & VT_FORWARD))
4052 error("main() not defined");
4053 t = (int (*)())s->c;
4054 return (*t)(argc - optind, argv + optind);