added compound literals parsing - fixed string init with {}
[tinycc.git] / tcc.c
blob9045c3a6b0bec1961d2c3602969e121e435adb09
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 <tcclib.h>
22 //#define DEBUG
23 /* preprocessor debug */
24 //#define PP_DEBUG
26 /* these sizes are dummy for unix, because malloc() does not use
27 memory when the pages are not used */
28 #define TEXT_SIZE (4*1024*1024)
29 #define DATA_SIZE (4*1024*1024)
31 #define INCLUDE_STACK_SIZE 32
32 #define IFDEF_STACK_SIZE 64
33 #define VSTACK_SIZE 64
34 #define STRING_MAX_SIZE 1024
35 #define INCLUDE_PATHS_MAX 32
37 #define TOK_HASH_SIZE 521
38 #define TOK_ALLOC_INCR 256 /* must be a power of two */
39 #define SYM_HASH_SIZE 263
41 /* number of available temporary registers */
42 #define NB_REGS 3
43 /* defined if function parameters must be evaluated in reverse order */
44 #define INVERT_FUNC_PARAMS
46 /* token symbol management */
47 typedef struct TokenSym {
48 struct TokenSym *hash_next;
49 int tok; /* token number */
50 int len;
51 char str[1];
52 } TokenSym;
54 /* symbol management */
55 typedef struct Sym {
56 int v; /* symbol token */
57 int t; /* associated type */
58 int c; /* associated number */
59 struct Sym *next; /* next related symbol */
60 struct Sym *prev; /* prev symbol in stack */
61 struct Sym *hash_next; /* next symbol in hash table */
62 } Sym;
64 typedef struct SymStack {
65 struct Sym *top;
66 struct Sym *hash[SYM_HASH_SIZE];
67 } SymStack;
69 #define SYM_STRUCT 0x40000000 /* struct/union/enum symbol space */
70 #define SYM_FIELD 0x20000000 /* struct/union field symbol space */
72 #define FUNC_NEW 1 /* ansi function prototype */
73 #define FUNC_OLD 2 /* old function prototype */
74 #define FUNC_ELLIPSIS 3 /* ansi function prototype with ... */
76 /* field 'Sym.t' for macros */
77 #define MACRO_OBJ 0 /* object like macro */
78 #define MACRO_FUNC 1 /* function like macro */
80 /* type_decl() types */
81 #define TYPE_ABSTRACT 1 /* type without variable */
82 #define TYPE_DIRECT 2 /* type with variable */
84 typedef struct {
85 FILE *file;
86 char *filename;
87 int line_num;
88 } IncludeFile;
90 /* loc : local variable index
91 glo : global variable index
92 ind : output code ptr
93 rsym: return symbol
94 prog: output code
95 anon_sym: anonymous symbol index
97 FILE *file;
98 int tok, tok1, tokc, rsym, anon_sym,
99 prog, ind, loc, glo, vt, vc, const_wanted, line_num;
100 int global_expr; /* true if compound literals must be allocated
101 globally (used during initializers parsing */
102 int tok_ident;
103 TokenSym **table_ident;
104 TokenSym *hash_ident[521];
105 char token_buf[STRING_MAX_SIZE + 1];
106 char *filename, *funcname;
107 SymStack define_stack, global_stack, local_stack, label_stack;
109 int vstack[VSTACK_SIZE], *vstack_ptr;
110 int *macro_ptr, *macro_ptr_allocated;
111 IncludeFile include_stack[INCLUDE_STACK_SIZE], *include_stack_ptr;
112 int ifdef_stack[IFDEF_STACK_SIZE], *ifdef_stack_ptr;
113 char *include_paths[INCLUDE_PATHS_MAX];
114 int nb_include_paths;
116 /* The current value can be: */
117 #define VT_VALMASK 0x000f
118 #define VT_CONST 0x000a /* constant in vc
119 (must be first non register value) */
120 #define VT_LLOCAL 0x000b /* lvalue, offset on stack */
121 #define VT_LOCAL 0x000c /* offset on stack */
122 #define VT_CMP 0x000d /* the value is stored in processor flags (in vc) */
123 #define VT_JMP 0x000e /* value is the consequence of jmp true */
124 #define VT_JMPI 0x000f /* value is the consequence of jmp false */
125 #define VT_LVAL 0x0010 /* var is an lvalue */
126 #define VT_LVALN -17 /* ~VT_LVAL */
127 #define VT_FORWARD 0x0020 /* value is forward reference
128 (only used for functions) */
130 /* types */
131 #define VT_INT 0
132 #define VT_VOID 0x00040
133 #define VT_BYTE 0x00080 /* signed byte type */
134 #define VT_PTR 0x00100 /* pointer increment */
135 #define VT_UNSIGNED 0x00200 /* unsigned type */
136 #define VT_ARRAY 0x00400 /* array type (only used in parsing) */
137 #define VT_ENUM 0x00800 /* enum definition */
138 #define VT_FUNC 0x01000 /* function type */
139 #define VT_STRUCT 0x002000 /* struct/union definition */
140 #define VT_TYPEDEF 0x004000 /* typedef definition */
141 #define VT_EXTERN 0x008000 /* extern definition */
142 #define VT_STATIC 0x010000 /* static variable */
143 #define VT_SHORT 0x020000 /* short type */
144 #define VT_STRUCT_SHIFT 18 /* structure/enum name shift (14 bits left) */
146 #define VT_TYPE 0xffffffc0 /* type mask */
147 #define VT_TYPEN 0x0000003f /* ~VT_TYPE */
148 #define VT_FUNCN -4097 /* ~VT_FUNC */
150 /* token values */
152 /* warning: the following compare tokens depend on i386 asm code */
153 #define TOK_ULT 0x92
154 #define TOK_UGE 0x93
155 #define TOK_EQ 0x94
156 #define TOK_NE 0x95
157 #define TOK_ULE 0x96
158 #define TOK_UGT 0x97
159 #define TOK_LT 0x9c
160 #define TOK_GE 0x9d
161 #define TOK_LE 0x9e
162 #define TOK_GT 0x9f
164 #define TOK_LAND 0xa0
165 #define TOK_LOR 0xa1
167 #define TOK_DEC 0xa2
168 #define TOK_MID 0xa3 /* inc/dec, to void constant */
169 #define TOK_INC 0xa4
170 #define TOK_ARROW 0xa7
171 #define TOK_DOTS 0xa8 /* three dots */
172 #define TOK_SHR 0xa9 /* unsigned shift right */
173 #define TOK_UDIV 0xb0 /* unsigned division */
174 #define TOK_UMOD 0xb1 /* unsigned modulo */
175 #define TOK_PDIV 0xb2 /* fast division with undefined rounding for pointers */
176 #define TOK_NUM 0xb3 /* number in tokc */
177 #define TOK_CCHAR 0xb4 /* char constant in tokc */
178 #define TOK_STR 0xb5 /* pointer to string in tokc */
179 #define TOK_TWOSHARPS 0xb6 /* ## preprocessing token */
180 #define TOK_LCHAR 0xb7
181 #define TOK_LSTR 0xb8
183 #define TOK_SHL 0x01 /* shift left */
184 #define TOK_SAR 0x02 /* signed shift right */
186 /* assignement operators : normal operator or 0x80 */
187 #define TOK_A_MOD 0xa5
188 #define TOK_A_AND 0xa6
189 #define TOK_A_MUL 0xaa
190 #define TOK_A_ADD 0xab
191 #define TOK_A_SUB 0xad
192 #define TOK_A_DIV 0xaf
193 #define TOK_A_XOR 0xde
194 #define TOK_A_OR 0xfc
195 #define TOK_A_SHL 0x81
196 #define TOK_A_SAR 0x82
198 /* all identificators and strings have token above that */
199 #define TOK_IDENT 256
201 enum {
202 TOK_INT = TOK_IDENT,
203 TOK_VOID,
204 TOK_CHAR,
205 TOK_IF,
206 TOK_ELSE,
207 TOK_WHILE,
208 TOK_BREAK,
209 TOK_RETURN,
210 TOK_FOR,
211 TOK_EXTERN,
212 TOK_STATIC,
213 TOK_UNSIGNED,
214 TOK_GOTO,
215 TOK_DO,
216 TOK_CONTINUE,
217 TOK_SWITCH,
218 TOK_CASE,
220 /* ignored types Must have contiguous values */
221 TOK_CONST,
222 TOK_VOLATILE,
223 TOK_LONG,
224 TOK_REGISTER,
225 TOK_SIGNED,
226 TOK_AUTO,
227 TOK_INLINE,
228 TOK_RESTRICT,
230 /* unsupported type */
231 TOK_FLOAT,
232 TOK_DOUBLE,
234 TOK_SHORT,
235 TOK_STRUCT,
236 TOK_UNION,
237 TOK_TYPEDEF,
238 TOK_DEFAULT,
239 TOK_ENUM,
240 TOK_SIZEOF,
242 /* preprocessor only */
243 TOK_DEFINE,
244 TOK_INCLUDE,
245 TOK_IFDEF,
246 TOK_IFNDEF,
247 TOK_ELIF,
248 TOK_ENDIF,
249 TOK_DEFINED,
250 TOK_UNDEF,
251 TOK_ERROR,
252 TOK_LINE,
253 TOK___LINE__,
254 TOK___FILE__,
255 TOK___DATE__,
256 TOK___TIME__,
257 TOK___VA_ARGS__,
259 /* special identifiers */
260 TOK___FUNC__,
261 TOK_MAIN,
264 void sum();
265 void next();
266 void next_nomacro();
267 int expr_const();
268 void expr_eq();
269 void expr();
270 void decl();
271 void decl_initializer(int t, int c, int first, int size_only);
272 int decl_initializer_alloc(int t, int has_init);
273 int gv();
274 void move_reg();
275 void save_reg();
276 void macro_subst(int **tok_str, int *tok_len,
277 Sym **nested_list, int *macro_str);
278 int save_reg_forced(int r);
279 int type_size(int t, int *a);
280 int pointed_type(int t);
281 int pointed_size(int t);
282 int ist(void);
283 int type_decl(int *v, int t, int td);
285 #ifdef PROFILE
286 /* dummy function for profiling */
287 void *dlopen(const char *filename, int flag)
289 return (void *)1;
291 const char *dlerror(void)
293 return "error";
296 void *dlsym(void *handle, char *symbol)
298 return (void *)1;
301 #endif
303 inline int isid(c)
305 return (c >= 'a' && c <= 'z') ||
306 (c >= 'A' && c <= 'Z') ||
307 c == '_';
310 inline int isnum(c)
312 return c >= '0' & c <= '9';
315 void printline()
317 IncludeFile *f;
318 for(f = include_stack; f < include_stack_ptr; f++)
319 fprintf(stderr, "In file included from %s:%d:\n",
320 f->filename, f->line_num);
321 fprintf(stderr, "%s:%d: ", filename, line_num);
324 void error(const char *fmt, ...)
326 va_list ap;
327 va_start(ap, fmt);
328 printline();
329 vfprintf(stderr, fmt, ap);
330 fprintf(stderr, "\n");
331 exit(1);
332 va_end(ap);
335 void expect(const char *msg)
337 error("%s expected", msg);
340 void warning(const char *msg)
342 printline();
343 fprintf(stderr, "warning: %s\n", msg);
346 void skip(c)
348 if (tok != c)
349 error("'%c' expected", c);
350 next();
353 void test_lvalue()
355 if (!(vt & VT_LVAL))
356 expect("lvalue");
359 TokenSym *tok_alloc(char *str, int len)
361 TokenSym *ts, **pts, **ptable;
362 int h, i;
364 if (len <= 0)
365 len = strlen(str);
366 h = 1;
367 for(i=0;i<len;i++)
368 h = ((h << 8) | (str[i] & 0xff)) % TOK_HASH_SIZE;
370 pts = &hash_ident[h];
371 while (1) {
372 ts = *pts;
373 if (!ts)
374 break;
375 if (ts->len == len && !memcmp(ts->str, str, len))
376 return ts;
377 pts = &(ts->hash_next);
379 /* expand token table if needed */
380 i = tok_ident - TOK_IDENT;
381 if ((i % TOK_ALLOC_INCR) == 0) {
382 ptable = realloc(table_ident, (i + TOK_ALLOC_INCR) * sizeof(TokenSym *));
383 if (!ptable)
384 error("memory full");
385 table_ident = ptable;
387 ts = malloc(sizeof(TokenSym) + len);
388 if (!ts)
389 error("memory full");
390 table_ident[i] = ts;
391 ts->tok = tok_ident++;
392 ts->len = len;
393 ts->hash_next = NULL;
394 memcpy(ts->str, str, len + 1);
395 *pts = ts;
396 return ts;
399 void add_char(char **pp, int c)
401 char *p;
402 p = *pp;
403 if (c == '\'' || c == '\"' || c == '\\') {
404 /* XXX: could be more precise if char or string */
405 *p++ = '\\';
407 if (c >= 32 && c <= 126) {
408 *p++ = c;
409 } else {
410 *p++ = '\\';
411 if (c == '\n') {
412 *p++ = 'n';
413 } else {
414 *p++ = '0' + ((c >> 6) & 7);
415 *p++ = '0' + ((c >> 3) & 7);
416 *p++ = '0' + (c & 7);
419 *pp = p;
422 /* XXX: buffer overflow */
423 char *get_tok_str(int v, int c)
425 static char buf[STRING_MAX_SIZE + 1];
426 TokenSym *ts;
427 char *p;
428 int i;
430 if (v == TOK_NUM) {
431 sprintf(buf, "%d", c);
432 return buf;
433 } else if (v == TOK_CCHAR || v == TOK_LCHAR) {
434 p = buf;
435 *p++ = '\'';
436 add_char(&p, c);
437 *p++ = '\'';
438 *p = '\0';
439 return buf;
440 } else if (v == TOK_STR || v == TOK_LSTR) {
441 ts = (TokenSym *)c;
442 p = buf;
443 *p++ = '\"';
444 for(i=0;i<ts->len;i++)
445 add_char(&p, ts->str[i]);
446 *p++ = '\"';
447 *p = '\0';
448 return buf;
449 } else if (v < TOK_IDENT) {
450 p = buf;
451 *p++ = v;
452 *p = '\0';
453 return buf;
454 } else if (v < tok_ident) {
455 return table_ident[v - TOK_IDENT]->str;
456 } else {
457 /* should never happen */
458 return NULL;
462 /* push, without hashing */
463 Sym *sym_push2(Sym **ps, int v, int t, int c)
465 Sym *s;
466 s = malloc(sizeof(Sym));
467 if (!s)
468 error("memory full");
469 s->v = v;
470 s->t = t;
471 s->c = c;
472 s->next = NULL;
473 /* add in stack */
474 s->prev = *ps;
475 *ps = s;
476 return s;
479 /* find a symbol and return its associated structure. 's' is the top
480 of the symbol stack */
481 Sym *sym_find2(Sym *s, int v)
483 while (s) {
484 if (s->v == v)
485 return s;
486 s = s->prev;
488 return NULL;
491 /* find a symbol and return its associated structure. 'st' is the
492 symbol stack */
493 Sym *sym_find1(SymStack *st, int v)
495 Sym *s;
497 s = st->hash[v % SYM_HASH_SIZE];
498 while (s) {
499 if (s->v == v)
500 return s;
501 s = s->hash_next;
503 return 0;
506 Sym *sym_push1(SymStack *st, int v, int t, int c)
508 Sym *s, **ps;
509 s = sym_push2(&st->top, v, t, c);
510 /* add in hash table */
511 ps = &st->hash[s->v % SYM_HASH_SIZE];
512 s->hash_next = *ps;
513 *ps = s;
514 return s;
517 /* find a symbol in the right symbol space */
518 Sym *sym_find(int v)
520 Sym *s;
521 s = sym_find1(&local_stack, v);
522 if (!s)
523 s = sym_find1(&global_stack, v);
524 return s;
527 /* push a given symbol on the symbol stack */
528 Sym *sym_push(int v, int t, int c)
530 if (local_stack.top)
531 return sym_push1(&local_stack, v, t, c);
532 else
533 return sym_push1(&global_stack, v, t, c);
536 /* pop symbols until top reaches 'b' */
537 void sym_pop(SymStack *st, Sym *b)
539 Sym *s, *ss;
541 s = st->top;
542 while(s != b) {
543 ss = s->prev;
544 /* free hash table entry */
545 st->hash[s->v % SYM_HASH_SIZE] = s->hash_next;
546 free(s);
547 s = ss;
549 st->top = b;
552 int ch, ch1;
554 /* read next char from current input file */
555 void inp()
557 redo:
558 ch1 = fgetc(file);
559 if (ch1 == -1) {
560 if (include_stack_ptr == include_stack)
561 return;
562 /* pop include stack */
563 fclose(file);
564 free(filename);
565 include_stack_ptr--;
566 file = include_stack_ptr->file;
567 filename = include_stack_ptr->filename;
568 line_num = include_stack_ptr->line_num;
569 goto redo;
571 if (ch1 == '\n')
572 line_num++;
573 // printf("ch1=%c 0x%x\n", ch1, ch1);
576 /* input with '\\n' handling */
577 void minp()
579 redo:
580 ch = ch1;
581 inp();
582 if (ch == '\\' && ch1 == '\n') {
583 inp();
584 goto redo;
586 //printf("ch=%c 0x%x\n", ch, ch);
589 /* same as minp, but also skip comments */
590 void cinp()
592 int c;
594 if (ch1 == '/') {
595 inp();
596 if (ch1 == '/') {
597 /* single line C++ comments */
598 inp();
599 while (ch1 != '\n' && ch1 != -1)
600 inp();
601 inp();
602 ch = ' '; /* return space */
603 } else if (ch1 == '*') {
604 /* C comments */
605 inp();
606 while (ch1 != -1) {
607 c = ch1;
608 inp();
609 if (c == '*' && ch1 == '/') {
610 inp();
611 ch = ' '; /* return space */
612 break;
615 } else {
616 ch = '/';
618 } else {
619 minp();
623 void skip_spaces()
625 while (ch == ' ' || ch == '\t')
626 cinp();
629 /* skip block of text until #else, #elif or #endif. skip also pairs of
630 #if/#endif */
631 void preprocess_skip()
633 int a;
634 a = 0;
635 while (1) {
636 while (ch != '\n') {
637 if (ch == -1)
638 expect("#endif");
639 cinp();
641 cinp();
642 skip_spaces();
643 if (ch == '#') {
644 cinp();
645 next_nomacro();
646 if (a == 0 &&
647 (tok == TOK_ELSE || tok == TOK_ELIF || tok == TOK_ENDIF))
648 break;
649 if (tok == TOK_IF || tok == TOK_IFDEF || tok == TOK_IFNDEF)
650 a++;
651 else if (tok == TOK_ENDIF)
652 a--;
657 inline int is_long_tok(int t)
659 return (t == TOK_NUM ||
660 t == TOK_CCHAR || t == TOK_LCHAR ||
661 t == TOK_STR || t == TOK_LSTR);
664 void tok_add(int **tok_str, int *tok_len, int t)
666 int len, *str;
667 len = *tok_len;
668 str = *tok_str;
669 if ((len & 63) == 0) {
670 str = realloc(str, (len + 64) * sizeof(int));
671 if (!str)
672 return;
673 *tok_str = str;
675 str[len++] = t;
676 *tok_len = len;
679 void tok_add2(int **tok_str, int *tok_len, int t, int c)
681 tok_add(tok_str, tok_len, t);
682 if (is_long_tok(t))
683 tok_add(tok_str, tok_len, c);
686 /* eval an expression for #if/#elif */
687 int expr_preprocess()
689 int *str, len, c, t;
691 str = NULL;
692 len = 0;
693 while (1) {
694 skip_spaces();
695 if (ch == '\n')
696 break;
697 next(); /* do macro subst */
698 if (tok == TOK_DEFINED) {
699 next_nomacro();
700 t = tok;
701 if (t == '(')
702 next_nomacro();
703 c = sym_find1(&define_stack, tok) != 0;
704 if (t == '(')
705 next_nomacro();
706 tok = TOK_NUM;
707 tokc = c;
708 } else if (tok >= TOK_IDENT) {
709 /* if undefined macro */
710 tok = TOK_NUM;
711 tokc = 0;
713 tok_add2(&str, &len, tok, tokc);
715 tok_add(&str, &len, -1); /* simulate end of file */
716 tok_add(&str, &len, 0);
717 /* now evaluate C constant expression */
718 macro_ptr = str;
719 next();
720 c = expr_const();
721 macro_ptr = NULL;
722 free(str);
723 return c != 0;
726 #ifdef DEBUG
727 void tok_print(int *str)
729 int t, c;
731 while (1) {
732 t = *str++;
733 if (!t)
734 break;
735 c = 0;
736 if (is_long_tok(t))
737 c = *str++;
738 printf(" %s", get_tok_str(t, c));
740 printf("\n");
742 #endif
744 /* XXX: should be more factorized */
745 void define_symbol(char *sym)
747 TokenSym *ts;
748 int *str, len;
750 ts = tok_alloc(sym, 0);
751 str = NULL;
752 len = 0;
753 tok_add2(&str, &len, TOK_NUM, 1);
754 tok_add(&str, &len, 0);
755 sym_push1(&define_stack, ts->tok, MACRO_OBJ, (int)str);
758 void preprocess()
760 int size, i, c, v, t, *str, len;
761 char buf[1024], *q, *p;
762 char buf1[1024];
763 FILE *f;
764 Sym **ps, *first, *s;
766 cinp();
767 next_nomacro();
768 redo:
769 if (tok == TOK_DEFINE) {
770 next_nomacro();
771 v = tok;
772 /* XXX: should check if same macro (ANSI) */
773 first = NULL;
774 t = MACRO_OBJ;
775 /* '(' must be just after macro definition for MACRO_FUNC */
776 if (ch == '(') {
777 next_nomacro();
778 next_nomacro();
779 ps = &first;
780 while (tok != ')') {
781 if (tok == TOK_DOTS)
782 tok = TOK___VA_ARGS__;
783 s = sym_push1(&define_stack, tok | SYM_FIELD, 0, 0);
784 *ps = s;
785 ps = &s->next;
786 next_nomacro();
787 if (tok != ',')
788 break;
789 next_nomacro();
791 t = MACRO_FUNC;
793 str = NULL;
794 len = 0;
795 while (1) {
796 skip_spaces();
797 if (ch == '\n' || ch == -1)
798 break;
799 next_nomacro();
800 tok_add2(&str, &len, tok, tokc);
802 tok_add(&str, &len, 0);
803 #ifdef PP_DEBUG
804 printf("define %s %d: ", get_tok_str(v, 0), t);
805 tok_print(str);
806 #endif
807 s = sym_push1(&define_stack, v, t, (int)str);
808 s->next = first;
809 } else if (tok == TOK_UNDEF) {
810 next_nomacro();
811 s = sym_find1(&define_stack, tok);
812 /* undefine symbol by putting an invalid name */
813 if (s)
814 s->v = 0;
815 } else if (tok == TOK_INCLUDE) {
816 skip_spaces();
817 if (ch == '<') {
818 c = '>';
819 goto read_name;
820 } else if (ch == '\"') {
821 c = ch;
822 read_name:
823 minp();
824 q = buf;
825 while (ch != c && ch != '\n' && ch != -1) {
826 if ((q - buf) < sizeof(buf) - 1)
827 *q++ = ch;
828 minp();
830 *q = '\0';
831 } else {
832 next();
833 if (tok != TOK_STR)
834 error("#include syntax error");
835 /* XXX: buffer overflow */
836 strcpy(buf, get_tok_str(tok, tokc));
837 c = '\"';
839 if (include_stack_ptr >= include_stack + INCLUDE_STACK_SIZE)
840 error("memory full");
841 if (c == '\"') {
842 /* first search in current dir if "header.h" */
843 /* XXX: buffer overflow */
844 size = 0;
845 p = strrchr(filename, '/');
846 if (p)
847 size = p + 1 - filename;
848 memcpy(buf1, filename, size);
849 buf1[size] = '\0';
850 strcat(buf1, buf);
851 f = fopen(buf1, "r");
852 if (f)
853 goto found;
855 /* now search in standard include path */
856 for(i=nb_include_paths - 1;i>=0;i--) {
857 strcpy(buf1, include_paths[i]);
858 strcat(buf1, "/");
859 strcat(buf1, buf);
860 f = fopen(buf1, "r");
861 if (f)
862 goto found;
864 error("include file not found");
865 f = NULL;
866 found:
867 /* push current file in stack */
868 /* XXX: fix current line init */
869 include_stack_ptr->file = file;
870 include_stack_ptr->filename = filename;
871 include_stack_ptr->line_num = line_num;
872 include_stack_ptr++;
873 file = f;
874 filename = strdup(buf1);
875 line_num = 1;
876 } else if (tok == TOK_IFNDEF) {
877 c = 1;
878 goto do_ifdef;
879 } else if (tok == TOK_IF) {
880 c = expr_preprocess();
881 goto do_if;
882 } else if (tok == TOK_IFDEF) {
883 c = 0;
884 do_ifdef:
885 next_nomacro();
886 c = (sym_find1(&define_stack, tok) != 0) ^ c;
887 do_if:
888 if (ifdef_stack_ptr >= ifdef_stack + IFDEF_STACK_SIZE)
889 error("memory full");
890 *ifdef_stack_ptr++ = c;
891 goto test_skip;
892 } else if (tok == TOK_ELSE) {
893 if (ifdef_stack_ptr == ifdef_stack ||
894 (ifdef_stack_ptr[-1] & 2))
895 error("#else after #else");
896 c = (ifdef_stack_ptr[-1] ^= 3);
897 goto test_skip;
898 } else if (tok == TOK_ELIF) {
899 if (ifdef_stack_ptr == ifdef_stack ||
900 ifdef_stack_ptr[-1] > 1)
901 error("#elif after #else");
902 c = expr_preprocess();
903 ifdef_stack_ptr[-1] = c;
904 test_skip:
905 if (!(c & 1)) {
906 preprocess_skip();
907 goto redo;
909 } else if (tok == TOK_ENDIF) {
910 if (ifdef_stack_ptr == ifdef_stack)
911 expect("#if");
912 ifdef_stack_ptr--;
913 } else if (tok == TOK_LINE) {
914 next();
915 if (tok != TOK_NUM)
916 error("#line");
917 line_num = tokc;
918 skip_spaces();
919 if (ch != '\n') {
920 next();
921 if (tok != TOK_STR)
922 error("#line");
923 /* XXX: potential memory leak */
924 filename = strdup(get_tok_str(tok, tokc));
926 } else if (tok == TOK_ERROR) {
927 error("#error");
929 /* ignore other preprocess commands or #! for C scripts */
930 while (ch != '\n' && ch != -1)
931 cinp();
934 /* read a number in base b */
935 int getn(b)
937 int n, t;
938 n = 0;
939 while (1) {
940 if (ch >= 'a' & ch <= 'f')
941 t = ch - 'a' + 10;
942 else if (ch >= 'A' & ch <= 'F')
943 t = ch - 'A' + 10;
944 else if (isnum(ch))
945 t = ch - '0';
946 else
947 break;
948 if (t < 0 | t >= b)
949 break;
950 n = n * b + t;
951 cinp();
953 return n;
956 /* read a character for string or char constant and eval escape codes */
957 int getq()
959 int c;
961 c = ch;
962 minp();
963 if (c == '\\') {
964 if (isnum(ch)) {
965 /* at most three octal digits */
966 c = ch - '0';
967 minp();
968 if (isnum(ch)) {
969 c = c * 8 + ch - '0';
970 minp();
971 if (isnum(ch)) {
972 c = c * 8 + ch - '0';
973 minp();
976 return c;
977 } else if (ch == 'x') {
978 minp();
979 return getn(16);
980 } else {
981 if (ch == 'a')
982 c = '\a';
983 else if (ch == 'b')
984 c = '\b';
985 else if (ch == 'f')
986 c = '\f';
987 else if (ch == 'n')
988 c = '\n';
989 else if (ch == 'r')
990 c = '\r';
991 else if (ch == 't')
992 c = '\t';
993 else if (ch == 'v')
994 c = '\v';
995 else
996 c = ch;
997 minp();
1000 return c;
1003 /* return next token without macro substitution */
1004 void next_nomacro1()
1006 int b;
1007 char *q;
1008 TokenSym *ts;
1010 /* skip spaces */
1011 while(1) {
1012 while (ch == '\n') {
1013 cinp();
1014 while (ch == ' ' || ch == 9)
1015 cinp();
1016 if (ch == '#') {
1017 /* preprocessor command if # at start of line after
1018 spaces */
1019 preprocess();
1022 if (ch != ' ' && ch != '\t' && ch != '\f')
1023 break;
1024 cinp();
1026 if (isid(ch)) {
1027 q = token_buf;
1028 *q++ = ch;
1029 cinp();
1030 if (q[-1] == 'L') {
1031 /* XXX: not supported entirely (needs different
1032 preprocessor architecture) */
1033 if (ch == '\'') {
1034 tok = TOK_LCHAR;
1035 goto char_const;
1037 if (ch == '\"') {
1038 tok = TOK_LSTR;
1039 goto str_const;
1042 while (isid(ch) | isnum(ch)) {
1043 if (q >= token_buf + STRING_MAX_SIZE)
1044 error("ident too long");
1045 *q++ = ch;
1046 cinp();
1048 *q = '\0';
1049 ts = tok_alloc(token_buf, q - token_buf);
1050 tok = ts->tok;
1051 } else if (isnum(ch)) {
1052 /* number */
1053 b = 10;
1054 if (ch == '0') {
1055 cinp();
1056 b = 8;
1057 if (ch == 'x' || ch == 'X') {
1058 cinp();
1059 b = 16;
1060 } else if (ch == 'b' || ch == 'B') {
1061 cinp();
1062 b = 2;
1065 tokc = getn(b);
1066 /* XXX: add unsigned constant support (ANSI) */
1067 while (ch == 'L' || ch == 'l' || ch == 'U' || ch == 'u')
1068 cinp();
1069 tok = TOK_NUM;
1070 } else if (ch == '\'') {
1071 tok = TOK_CCHAR;
1072 char_const:
1073 minp();
1074 tokc = getq();
1075 if (ch != '\'')
1076 expect("\'");
1077 minp();
1078 } else if (ch == '\"') {
1079 tok = TOK_STR;
1080 str_const:
1081 minp();
1082 q = token_buf;
1083 while (ch != '\"') {
1084 b = getq();
1085 if (ch == -1)
1086 error("unterminated string");
1087 if (q >= token_buf + STRING_MAX_SIZE)
1088 error("string too long");
1089 *q++ = b;
1091 *q = '\0';
1092 tokc = (int)tok_alloc(token_buf, q - token_buf);
1093 minp();
1094 } else {
1095 q = "<=\236>=\235!=\225&&\240||\241++\244--\242==\224<<\1>>\2+=\253-=\255*=\252/=\257%=\245&=\246^=\336|=\374->\247..\250##\266";
1096 /* two chars */
1097 tok = ch;
1098 cinp();
1099 while (*q) {
1100 if (*q == tok & q[1] == ch) {
1101 cinp();
1102 tok = q[2] & 0xff;
1103 /* three chars tests */
1104 if (tok == TOK_SHL | tok == TOK_SAR) {
1105 if (ch == '=') {
1106 tok = tok | 0x80;
1107 cinp();
1109 } else if (tok == TOK_DOTS) {
1110 if (ch != '.')
1111 error("parse error");
1112 cinp();
1114 return;
1116 q = q + 3;
1118 /* single char substitutions */
1119 if (tok == '<')
1120 tok = TOK_LT;
1121 else if (tok == '>')
1122 tok = TOK_GT;
1126 /* return next token without macro substitution. Can read input from
1127 macro_ptr buffer */
1128 void next_nomacro()
1130 if (macro_ptr) {
1131 tok = *macro_ptr;
1132 if (tok) {
1133 macro_ptr++;
1134 if (is_long_tok(tok))
1135 tokc = *macro_ptr++;
1137 } else {
1138 next_nomacro1();
1142 /* substitute args in macro_str and return allocated string */
1143 int *macro_arg_subst(Sym **nested_list, int *macro_str, Sym *args)
1145 int *st, last_tok, t, c, notfirst, *str, len;
1146 Sym *s;
1147 TokenSym *ts;
1149 str = NULL;
1150 len = 0;
1151 last_tok = 0;
1152 while(1) {
1153 t = *macro_str++;
1154 if (!t)
1155 break;
1156 if (t == '#') {
1157 /* stringize */
1158 t = *macro_str++;
1159 if (!t)
1160 break;
1161 s = sym_find2(args, t);
1162 if (s) {
1163 token_buf[0] = '\0';
1164 st = (int *)s->c;
1165 /* XXX: buffer overflow */
1166 notfirst = 0;
1167 while (*st) {
1168 if (notfirst)
1169 strcat(token_buf, " ");
1170 t = *st++;
1171 c = 0;
1172 if (is_long_tok(t))
1173 c = *st++;
1174 strcat(token_buf, get_tok_str(t, c));
1175 notfirst = 1;
1177 #ifdef PP_DEBUG
1178 printf("stringize: %s\n", token_buf);
1179 #endif
1180 /* add string */
1181 ts = tok_alloc(token_buf, 0);
1182 tok_add2(&str, &len, TOK_STR, (int)ts);
1183 } else {
1184 tok_add(&str, &len, t);
1186 } else if (is_long_tok(t)) {
1187 tok_add2(&str, &len, t, *macro_str++);
1188 } else {
1189 s = sym_find2(args, t);
1190 if (s) {
1191 st = (int *)s->c;
1192 /* if '##' is present before or after , no arg substitution */
1193 if (*macro_str == TOK_TWOSHARPS || last_tok == TOK_TWOSHARPS) {
1194 while (*st)
1195 tok_add(&str, &len, *st++);
1196 } else {
1197 macro_subst(&str, &len, nested_list, st);
1199 } else {
1200 tok_add(&str, &len, t);
1203 last_tok = t;
1205 tok_add(&str, &len, 0);
1206 return str;
1209 /* handle the '##' operator */
1210 int *macro_twosharps(int *macro_str)
1212 TokenSym *ts;
1213 int *macro_str1, macro_str1_len, *macro_ptr1;
1214 int t, c;
1215 char *p;
1217 macro_str1 = NULL;
1218 macro_str1_len = 0;
1219 tok = 0;
1220 while (1) {
1221 next_nomacro();
1222 if (tok == 0)
1223 break;
1224 if (*macro_ptr == TOK_TWOSHARPS) {
1225 macro_ptr++;
1226 macro_ptr1 = macro_ptr;
1227 t = *macro_ptr;
1228 if (t) {
1229 macro_ptr++;
1230 c = 0;
1231 if (is_long_tok(t))
1232 c = *macro_ptr++;
1233 /* XXX: we handle only most common cases:
1234 ident + ident or ident + number */
1235 if (tok >= TOK_IDENT &&
1236 (t >= TOK_IDENT || t == TOK_NUM)) {
1237 /* XXX: buffer overflow */
1238 p = get_tok_str(tok, tokc);
1239 strcpy(token_buf, p);
1240 p = get_tok_str(t, c);
1241 strcat(token_buf, p);
1242 ts = tok_alloc(token_buf, 0);
1243 tok_add2(&macro_str1, &macro_str1_len, ts->tok, 0);
1244 } else {
1245 /* cannot merge tokens: skip '##' */
1246 macro_ptr = macro_ptr1;
1249 } else {
1250 tok_add2(&macro_str1, &macro_str1_len, tok, tokc);
1253 tok_add(&macro_str1, &macro_str1_len, 0);
1254 return macro_str1;
1259 /* do macro substitution of macro_str and add result to
1260 (tok_str,tok_len). If macro_str is NULL, then input stream token is
1261 substituted. 'nested_list' is the list of all macros we got inside
1262 to avoid recursing. */
1263 void macro_subst(int **tok_str, int *tok_len,
1264 Sym **nested_list, int *macro_str)
1266 Sym *s, *args, *sa, *sa1;
1267 int *str, parlevel, len, *mstr, t, *saved_macro_ptr;
1268 int mstr_allocated, *macro_str1;
1270 saved_macro_ptr = macro_ptr;
1271 macro_ptr = macro_str;
1272 macro_str1 = NULL;
1273 if (macro_str) {
1274 /* first scan for '##' operator handling */
1275 macro_str1 = macro_twosharps(macro_str);
1276 macro_ptr = macro_str1;
1279 while (1) {
1280 next_nomacro();
1281 if (tok == 0)
1282 break;
1283 /* special macros */
1284 if (tok == TOK___LINE__) {
1285 tok_add2(tok_str, tok_len, TOK_NUM, line_num);
1286 } else if (tok == TOK___FILE__) {
1287 tok_add2(tok_str, tok_len, TOK_STR,
1288 (int)tok_alloc(filename, 0));
1289 } else if (tok == TOK___DATE__) {
1290 tok_add2(tok_str, tok_len, TOK_STR,
1291 (int)tok_alloc("Jan 1 1970", 0));
1292 } else if (tok == TOK___TIME__) {
1293 tok_add2(tok_str, tok_len, TOK_STR,
1294 (int)tok_alloc("00:00:00", 0));
1295 } else if ((s = sym_find1(&define_stack, tok)) != NULL) {
1296 /* if symbol is a macro, prepare substitution */
1297 /* if nested substitution, do nothing */
1298 if (sym_find2(*nested_list, tok))
1299 goto no_subst;
1300 mstr = (int *)s->c;
1301 mstr_allocated = 0;
1302 if (s->t == MACRO_FUNC) {
1303 /* NOTE: we do not use next_nomacro to avoid eating the
1304 next token. XXX: find better solution */
1305 if (macro_ptr) {
1306 t = *macro_ptr;
1307 } else {
1308 while (ch == ' ' || ch == '\t' || ch == '\n')
1309 cinp();
1310 t = ch;
1312 if (t != '(') /* no macro subst */
1313 goto no_subst;
1315 /* argument macro */
1316 next_nomacro();
1317 next_nomacro();
1318 args = NULL;
1319 sa = s->next;
1320 while (tok != ')' && sa) {
1321 len = 0;
1322 str = NULL;
1323 parlevel = 0;
1324 while ((parlevel > 0 ||
1325 (tok != ')' &&
1326 (tok != ',' ||
1327 sa->v == (TOK___VA_ARGS__ | SYM_FIELD)))) &&
1328 tok != -1) {
1329 if (tok == '(')
1330 parlevel++;
1331 else if (tok == ')')
1332 parlevel--;
1333 tok_add2(&str, &len, tok, tokc);
1334 next_nomacro();
1336 tok_add(&str, &len, 0);
1337 sym_push2(&args, sa->v & ~SYM_FIELD, 0, (int)str);
1338 if (tok != ',')
1339 break;
1340 next_nomacro();
1341 sa = sa->next;
1343 if (tok != ')')
1344 expect(")");
1345 /* now subst each arg */
1346 mstr = macro_arg_subst(nested_list, mstr, args);
1347 /* free memory */
1348 sa = args;
1349 while (sa) {
1350 sa1 = sa->prev;
1351 free((int *)sa->c);
1352 free(sa);
1353 sa = sa1;
1355 mstr_allocated = 1;
1357 sym_push2(nested_list, s->v, 0, 0);
1358 macro_subst(tok_str, tok_len, nested_list, mstr);
1359 /* pop nested defined symbol */
1360 sa1 = *nested_list;
1361 *nested_list = sa1->prev;
1362 free(sa1);
1363 if (mstr_allocated)
1364 free(mstr);
1365 } else {
1366 no_subst:
1367 /* no need to add if reading input stream */
1368 if (!macro_str)
1369 return;
1370 tok_add2(tok_str, tok_len, tok, tokc);
1372 /* only replace one macro while parsing input stream */
1373 if (!macro_str)
1374 return;
1376 macro_ptr = saved_macro_ptr;
1377 if (macro_str1)
1378 free(macro_str1);
1381 /* return next token with macro substitution */
1382 void next()
1384 int len, *ptr;
1385 Sym *nested_list;
1387 /* special 'ungettok' case for label parsing */
1388 if (tok1) {
1389 tok = tok1;
1390 tok1 = 0;
1391 } else {
1392 redo:
1393 if (!macro_ptr) {
1394 /* if not reading from macro substuted string, then try to substitute */
1395 len = 0;
1396 ptr = NULL;
1397 nested_list = NULL;
1398 macro_subst(&ptr, &len, &nested_list, NULL);
1399 if (ptr) {
1400 tok_add(&ptr, &len, 0);
1401 macro_ptr = ptr;
1402 macro_ptr_allocated = ptr;
1403 goto redo;
1405 if (tok == 0)
1406 goto redo;
1407 } else {
1408 next_nomacro();
1409 if (tok == 0) {
1410 /* end of macro string: free it */
1411 free(macro_ptr_allocated);
1412 macro_ptr = NULL;
1413 goto redo;
1417 #ifdef DEBUG
1418 printf("token = %s\n", get_tok_str(tok, tokc));
1419 #endif
1422 void swap(int *p, int *q)
1424 int t;
1425 t = *p;
1426 *p = *q;
1427 *q = t;
1430 void vset(t, v)
1432 vt = t;
1433 vc = v;
1436 /******************************************************/
1437 /* X86 code generator */
1439 void g(c)
1441 *(char *)ind++ = c;
1444 void o(c)
1446 while (c) {
1447 g(c);
1448 c = c / 256;
1452 /* output a symbol and patch all calls to it */
1453 void gsym_addr(t, a)
1455 int n;
1456 while (t) {
1457 n = *(int *)t; /* next value */
1458 *(int *)t = a - t - 4;
1459 t = n;
1463 void gsym(t)
1465 gsym_addr(t, ind);
1468 /* psym is used to put an instruction with a data field which is a
1469 reference to a symbol. It is in fact the same as oad ! */
1470 #define psym oad
1472 /* instruction + 4 bytes data. Return the address of the data */
1473 int oad(c, s)
1475 o(c);
1476 *(int *)ind = s;
1477 s = ind;
1478 ind = ind + 4;
1479 return s;
1482 /* XXX: generate correct pointer for forward references to functions */
1483 /* r = (ft, fc) */
1484 void load(r, ft, fc)
1486 int v, t;
1488 v = ft & VT_VALMASK;
1489 if (ft & VT_LVAL) {
1490 if (v == VT_LLOCAL) {
1491 load(r, VT_LOCAL | VT_LVAL, fc);
1492 v = r;
1494 if ((ft & VT_TYPE) == VT_BYTE)
1495 o(0xbe0f); /* movsbl */
1496 else if ((ft & VT_TYPE) == (VT_BYTE | VT_UNSIGNED))
1497 o(0xb60f); /* movzbl */
1498 else if ((ft & VT_TYPE) == VT_SHORT)
1499 o(0xbf0f); /* movswl */
1500 else if ((ft & VT_TYPE) == (VT_SHORT | VT_UNSIGNED))
1501 o(0xb70f); /* movzwl */
1502 else
1503 o(0x8b); /* movl */
1504 if (v == VT_CONST) {
1505 oad(0x05 + r * 8, fc); /* 0xXX, r */
1506 } else if (v == VT_LOCAL) {
1507 oad(0x85 + r * 8, fc); /* xx(%ebp), r */
1508 } else {
1509 g(0x00 + r * 8 + v); /* (v), r */
1511 } else {
1512 if (v == VT_CONST) {
1513 oad(0xb8 + r, fc); /* mov $xx, r */
1514 } else if (v == VT_LOCAL) {
1515 o(0x8d);
1516 oad(0x85 + r * 8, fc); /* lea xxx(%ebp), r */
1517 } else if (v == VT_CMP) {
1518 oad(0xb8 + r, 0); /* mov $0, r */
1519 o(0x0f); /* setxx %br */
1520 o(fc);
1521 o(0xc0 + r);
1522 } else if (v == VT_JMP || v == VT_JMPI) {
1523 t = v & 1;
1524 oad(0xb8 + r, t); /* mov $1, r */
1525 oad(0xe9, 5); /* jmp after */
1526 gsym(fc);
1527 oad(0xb8 + r, t ^ 1); /* mov $0, r */
1528 } else if (v != r) {
1529 o(0x89);
1530 o(0xc0 + r + v * 8); /* mov v, r */
1535 /* (ft, fc) = r */
1536 /* WARNING: r must not be allocated on the stack */
1537 void store(r, ft, fc)
1539 int fr, b;
1541 fr = ft & VT_VALMASK;
1542 b = (ft & VT_TYPE) == VT_BYTE;
1543 /* XXX: incorrect if reg to reg */
1544 if (ft & VT_SHORT)
1545 o(0x66);
1546 o(0x89 - b);
1547 if (fr == VT_CONST) {
1548 oad(0x05 + r * 8, fc); /* mov r,xxx */
1549 } else if (fr == VT_LOCAL) {
1550 oad(0x85 + r * 8, fc); /* mov r,xxx(%ebp) */
1551 } else if (ft & VT_LVAL) {
1552 g(fr + r * 8); /* mov r, (fr) */
1553 } else if (fr != r) {
1554 o(0xc0 + fr + r * 8); /* mov r, fr */
1558 void gfunc_param(void)
1560 o(0x50 + gv()); /* push r */
1563 int gjmp(t)
1565 return psym(0xe9, t);
1568 /* generate a test. set 'inv' to invert test */
1569 int gtst(inv, t)
1571 int v, *p;
1572 v = vt & VT_VALMASK;
1573 if (v == VT_CMP) {
1574 /* fast case : can jump directly since flags are set */
1575 g(0x0f);
1576 t = psym((vc - 16) ^ inv, t);
1577 } else if (v == VT_JMP || v == VT_JMPI) {
1578 /* && or || optimization */
1579 if ((v & 1) == inv) {
1580 /* insert vc jump list in t */
1581 p = &vc;
1582 while (*p != 0)
1583 p = (int *)*p;
1584 *p = t;
1585 t = vc;
1586 } else {
1587 t = gjmp(t);
1588 gsym(vc);
1590 } else if ((vt & (VT_VALMASK | VT_LVAL)) == VT_CONST) {
1591 /* constant jmp optimization */
1592 if ((vc != 0) != inv)
1593 t = gjmp(t);
1594 } else {
1595 v = gv();
1596 o(0x85);
1597 o(0xc0 + v * 9);
1598 g(0x0f);
1599 t = psym(0x85 ^ inv, t);
1601 return t;
1604 /* generate a binary operation 'v = r op fr' instruction and modifies
1605 (vt,vc) if needed */
1606 void gen_op1(op, r, fr)
1608 int t;
1609 if (op == '+') {
1610 o(0x01);
1611 o(0xc0 + r + fr * 8);
1612 } else if (op == '-') {
1613 o(0x29);
1614 o(0xc0 + r + fr * 8);
1615 } else if (op == '&') {
1616 o(0x21);
1617 o(0xc0 + r + fr * 8);
1618 } else if (op == '^') {
1619 o(0x31);
1620 o(0xc0 + r + fr * 8);
1621 } else if (op == '|') {
1622 o(0x09);
1623 o(0xc0 + r + fr * 8);
1624 } else if (op == '*') {
1625 o(0xaf0f); /* imul fr, r */
1626 o(0xc0 + fr + r * 8);
1627 } else if (op == TOK_SHL | op == TOK_SHR | op == TOK_SAR) {
1628 /* op2 is %ecx */
1629 if (fr != 1) {
1630 if (r == 1) {
1631 r = fr;
1632 fr = 1;
1633 o(0x87); /* xchg r, %ecx */
1634 o(0xc1 + r * 8);
1635 } else
1636 move_reg(1, fr);
1638 o(0xd3); /* shl/shr/sar %cl, r */
1639 if (op == TOK_SHL)
1640 o(0xe0 + r);
1641 else if (op == TOK_SHR)
1642 o(0xe8 + r);
1643 else
1644 o(0xf8 + r);
1645 vt = (vt & VT_TYPE) | r;
1646 } else if (op == '/' | op == TOK_UDIV | op == TOK_PDIV |
1647 op == '%' | op == TOK_UMOD) {
1648 save_reg(2); /* save edx */
1649 t = save_reg_forced(fr); /* save fr and get op2 location */
1650 move_reg(0, r); /* op1 is %eax */
1651 if (op == TOK_UDIV | op == TOK_UMOD) {
1652 o(0xf7d231); /* xor %edx, %edx, div t(%ebp), %eax */
1653 oad(0xb5, t);
1654 } else {
1655 o(0xf799); /* cltd, idiv t(%ebp), %eax */
1656 oad(0xbd, t);
1658 if (op == '%' | op == TOK_UMOD)
1659 r = 2;
1660 else
1661 r = 0;
1662 vt = (vt & VT_TYPE) | r;
1663 } else {
1664 o(0x39);
1665 o(0xc0 + r + fr * 8); /* cmp fr, r */
1666 vset(VT_CMP, op);
1670 /* end of X86 code generator */
1671 /*************************************************************/
1673 int save_reg_forced(int r)
1675 int i, l, *p, t;
1676 /* store register */
1677 loc = (loc - 4) & -3;
1678 store(r, VT_LOCAL, loc);
1679 l = loc;
1681 /* modify all stack values */
1682 for(p=vstack;p<vstack_ptr;p+=2) {
1683 i = p[0] & VT_VALMASK;
1684 if (i == r) {
1685 if (p[0] & VT_LVAL)
1686 t = VT_LLOCAL;
1687 else
1688 t = VT_LOCAL;
1689 p[0] = (p[0] & VT_TYPE) | VT_LVAL | t;
1690 p[1] = l;
1693 return l;
1696 /* save r to memory. and mark it as being free */
1697 void save_reg(r)
1699 int i, *p;
1701 /* modify all stack values */
1702 for(p=vstack;p<vstack_ptr;p+=2) {
1703 i = p[0] & VT_VALMASK;
1704 if (i == r) {
1705 save_reg_forced(r);
1706 break;
1711 /* find a free register. If none, save one register */
1712 int get_reg()
1714 int r, i, *p;
1716 /* find a free register */
1717 for(r=0;r<NB_REGS;r++) {
1718 for(p=vstack;p<vstack_ptr;p+=2) {
1719 i = p[0] & VT_VALMASK;
1720 if (i == r)
1721 goto notfound;
1723 return r;
1724 notfound: ;
1727 /* no register left : free the first one on the stack (very
1728 important to start from the bottom to ensure that we don't
1729 spill registers used in gen_op()) */
1730 for(p=vstack;p<vstack_ptr;p+=2) {
1731 r = p[0] & VT_VALMASK;
1732 if (r < VT_CONST) {
1733 save_reg(r);
1734 break;
1737 return r;
1740 void save_regs()
1742 int r, *p;
1743 for(p=vstack;p<vstack_ptr;p+=2) {
1744 r = p[0] & VT_VALMASK;
1745 if (r < VT_CONST) {
1746 save_reg(r);
1751 /* move register 's' to 'r', and flush previous value of r to memory
1752 if needed */
1753 void move_reg(r, s)
1755 if (r != s) {
1756 save_reg(r);
1757 load(r, s, 0);
1761 /* convert a stack entry in register */
1762 int gvp(int *p)
1764 int r;
1765 r = p[0] & VT_VALMASK;
1766 if (r >= VT_CONST || (p[0] & VT_LVAL))
1767 r = get_reg();
1768 load(r, p[0], p[1]);
1769 p[0] = (p[0] & VT_TYPE) | r;
1770 return r;
1773 void vpush()
1775 if (vstack_ptr >= vstack + VSTACK_SIZE)
1776 error("memory full");
1777 *vstack_ptr++ = vt;
1778 *vstack_ptr++ = vc;
1779 /* cannot let cpu flags if other instruction are generated */
1780 if ((vt & VT_VALMASK) == VT_CMP)
1781 gvp(vstack_ptr - 2);
1784 void vpop(int *ft, int *fc)
1786 *fc = *--vstack_ptr;
1787 *ft = *--vstack_ptr;
1790 /* generate a value in a register from vt and vc */
1791 int gv()
1793 int r;
1794 vpush();
1795 r = gvp(vstack_ptr - 2);
1796 vpop(&vt, &vc);
1797 return r;
1800 /* handle constant optimizations and various machine independant opt */
1801 void gen_opc(op)
1803 int fr, ft, fc, r, c1, c2, n;
1805 vpop(&ft, &fc);
1806 vpop(&vt, &vc);
1807 c1 = (vt & (VT_VALMASK | VT_LVAL)) == VT_CONST;
1808 c2 = (ft & (VT_VALMASK | VT_LVAL)) == VT_CONST;
1809 if (c1 && c2) {
1810 switch(op) {
1811 case '+': vc += fc; break;
1812 case '-': vc -= fc; break;
1813 case '&': vc &= fc; break;
1814 case '^': vc ^= fc; break;
1815 case '|': vc |= fc; break;
1816 case '*': vc *= fc; break;
1817 case TOK_PDIV:
1818 case '/': vc /= fc; break; /* XXX: zero case ? */
1819 case '%': vc %= fc; break; /* XXX: zero case ? */
1820 case TOK_UDIV: vc = (unsigned)vc / fc; break; /* XXX: zero case ? */
1821 case TOK_UMOD: vc = (unsigned)vc % fc; break; /* XXX: zero case ? */
1822 case TOK_SHL: vc <<= fc; break;
1823 case TOK_SHR: vc = (unsigned)vc >> fc; break;
1824 case TOK_SAR: vc >>= fc; break;
1825 /* tests */
1826 case TOK_ULT: vc = (unsigned)vc < (unsigned)fc; break;
1827 case TOK_UGE: vc = (unsigned)vc >= (unsigned)fc; break;
1828 case TOK_EQ: vc = vc == fc; break;
1829 case TOK_NE: vc = vc != fc; break;
1830 case TOK_ULE: vc = (unsigned)vc <= (unsigned)fc; break;
1831 case TOK_UGT: vc = (unsigned)vc > (unsigned)fc; break;
1832 case TOK_LT: vc = vc < fc; break;
1833 case TOK_GE: vc = vc >= fc; break;
1834 case TOK_LE: vc = vc <= fc; break;
1835 case TOK_GT: vc = vc > fc; break;
1836 /* logical */
1837 case TOK_LAND: vc = vc && fc; break;
1838 case TOK_LOR: vc = vc || fc; break;
1839 default:
1840 goto general_case;
1842 } else {
1843 /* if commutative ops, put c2 as constant */
1844 if (c1 && (op == '+' || op == '&' || op == '^' ||
1845 op == '|' || op == '*')) {
1846 swap(&vt, &ft);
1847 swap(&vc, &fc);
1848 swap(&c1, &c2);
1850 if (c2 && (((op == '*' || op == '/' || op == TOK_UDIV ||
1851 op == TOK_PDIV) &&
1852 fc == 1) ||
1853 ((op == '+' || op == '-' || op == '|' || op == '^' ||
1854 op == TOK_SHL || op == TOK_SHR || op == TOK_SAR) &&
1855 fc == 0) ||
1856 (op == '&' &&
1857 fc == -1))) {
1858 } else if (c2 && (op == '*' || op == TOK_PDIV || op == TOK_UDIV)) {
1859 /* try to use shifts instead of muls or divs */
1860 if (fc > 0 && (fc & (fc - 1)) == 0) {
1861 n = -1;
1862 while (fc) {
1863 fc >>= 1;
1864 n++;
1866 fc = n;
1867 if (op == '*')
1868 op = TOK_SHL;
1869 else if (op == TOK_PDIV)
1870 op = TOK_SAR;
1871 else
1872 op = TOK_SHR;
1874 goto general_case;
1875 } else {
1876 general_case:
1877 vpush();
1878 vt = ft;
1879 vc = fc;
1880 vpush();
1881 r = gvp(vstack_ptr - 4);
1882 fr = gvp(vstack_ptr - 2);
1883 vpop(&ft, &fc);
1884 vpop(&vt, &vc);
1885 /* call low level op generator */
1886 gen_op1(op, r, fr);
1891 int pointed_size(int t)
1893 return type_size(pointed_type(t), &t);
1896 /* generic gen_op: handles types problems */
1897 void gen_op(int op)
1899 int u, t1, t2;
1901 vpush();
1902 t1 = vstack_ptr[-4];
1903 t2 = vstack_ptr[-2];
1904 if (op == '+' | op == '-') {
1905 if ((t1 & VT_PTR) && (t2 & VT_PTR)) {
1906 if (op != '-')
1907 error("invalid type");
1908 /* XXX: check that types are compatible */
1909 u = pointed_size(t1);
1910 gen_opc(op);
1911 vpush();
1912 vstack_ptr[-2] &= ~VT_TYPE; /* set to integer */
1913 vset(VT_CONST, u);
1914 gen_op(TOK_PDIV);
1915 } else if ((t1 | t2) & VT_PTR) {
1916 if (t2 & VT_PTR) {
1917 swap(vstack_ptr - 4, vstack_ptr - 2);
1918 swap(vstack_ptr - 3, vstack_ptr - 1);
1919 swap(&t1, &t2);
1921 /* stack-4 contains pointer, stack-2 value to add */
1922 vset(VT_CONST, pointed_size(vstack_ptr[-4]));
1923 gen_op('*');
1924 vpush();
1925 gen_opc(op);
1926 /* put again type if gen_opc() swaped operands */
1927 vt = (vt & VT_TYPEN) | (t1 & VT_TYPE);
1928 } else {
1929 gen_opc(op);
1931 } else {
1932 /* XXX: test types and compute returned value */
1933 if ((t1 | t2) & (VT_UNSIGNED | VT_PTR)) {
1934 if (op == TOK_SAR)
1935 op = TOK_SHR;
1936 else if (op == '/')
1937 op = TOK_UDIV;
1938 else if (op == '%')
1939 op = TOK_UMOD;
1940 else if (op == TOK_LT)
1941 op = TOK_ULT;
1942 else if (op == TOK_GT)
1943 op = TOK_UGT;
1944 else if (op == TOK_LE)
1945 op = TOK_ULE;
1946 else if (op == TOK_GE)
1947 op = TOK_UGE;
1949 gen_opc(op);
1953 /* return type size. Put alignment at 'a' */
1954 int type_size(int t, int *a)
1956 Sym *s;
1958 /* int, enum or pointer */
1959 if (t & VT_STRUCT) {
1960 /* struct/union */
1961 s = sym_find(((unsigned)t >> VT_STRUCT_SHIFT) | SYM_STRUCT);
1962 *a = 4; /* XXX: cannot store it yet. Doing that is safe */
1963 return s->c;
1964 } else if (t & VT_ARRAY) {
1965 s = sym_find(((unsigned)t >> VT_STRUCT_SHIFT));
1966 return type_size(s->t, a) * s->c;
1967 } else if ((t & VT_PTR) |
1968 (t & VT_TYPE) == 0 |
1969 (t & VT_ENUM)) {
1970 *a = 4;
1971 return 4;
1972 } else if (t & VT_SHORT) {
1973 *a = 2;
1974 return 2;
1975 } else {
1976 *a = 1;
1977 return 1;
1981 /* return the pointed type of t */
1982 int pointed_type(int t)
1984 Sym *s;
1985 s = sym_find(((unsigned)t >> VT_STRUCT_SHIFT));
1986 return s->t | (t & VT_TYPEN);
1989 int mk_pointer(int t)
1991 int p;
1992 p = anon_sym++;
1993 sym_push(p, t, -1);
1994 return VT_PTR | (p << VT_STRUCT_SHIFT) | (t & VT_TYPEN);
1997 /* store value in lvalue pushed on stack */
1998 void vstore()
2000 int ft, fc, r, t;
2002 r = gv(); /* generate value */
2003 vpush();
2004 ft = vstack_ptr[-4];
2005 fc = vstack_ptr[-3];
2006 if ((ft & VT_VALMASK) == VT_LLOCAL) {
2007 t = get_reg();
2008 load(t, VT_LOCAL | VT_LVAL, fc);
2009 ft = (ft & ~VT_VALMASK) | t;
2011 store(r, ft, fc);
2012 vstack_ptr -= 4;
2015 /* post defines POST/PRE add. c is the token ++ or -- */
2016 void inc(post, c)
2018 int r, r1;
2019 test_lvalue();
2020 if (post)
2021 vpush(); /* room for returned value */
2022 vpush(); /* save lvalue */
2023 r = gv();
2024 vpush(); /* save value */
2025 if (post) {
2026 /* duplicate value */
2027 r1 = get_reg();
2028 load(r1, r, 0); /* move r to r1 */
2029 vstack_ptr[-6] = (vt & VT_TYPE) | r1;
2030 vstack_ptr[-5] = 0;
2032 /* add constant */
2033 vset(VT_CONST, c - TOK_MID);
2034 gen_op('+');
2035 vstore(); /* store value */
2036 if (post)
2037 vpop(&vt, &vc);
2040 /* enum/struct/union declaration */
2041 int struct_decl(u)
2043 int a, t, b, v, size, align, maxalign, c;
2044 Sym *s, *ss, **ps;
2046 a = tok; /* save decl type */
2047 next();
2048 if (tok != '{') {
2049 v = tok;
2050 next();
2051 /* struct already defined ? return it */
2052 /* XXX: check consistency */
2053 if (s = sym_find(v | SYM_STRUCT)) {
2054 if (s->t != a)
2055 error("invalid type");
2056 goto do_decl;
2058 } else {
2059 v = anon_sym++;
2061 s = sym_push(v | SYM_STRUCT, a, 0);
2062 /* put struct/union/enum name in type */
2063 do_decl:
2064 u = u | (v << VT_STRUCT_SHIFT);
2066 if (tok == '{') {
2067 next();
2068 if (s->c)
2069 error("struct/union/enum already defined");
2070 /* cannot be empty */
2071 c = 0;
2072 maxalign = 0;
2073 ps = &s->next;
2074 while (1) {
2075 if (a == TOK_ENUM) {
2076 v = tok;
2077 next();
2078 if (tok == '=') {
2079 next();
2080 c = expr_const();
2082 sym_push(v, VT_CONST, c);
2083 if (tok == ',')
2084 next();
2085 c++;
2086 } else {
2087 b = ist();
2088 while (1) {
2089 t = type_decl(&v, b, TYPE_DIRECT);
2090 if (t & (VT_FUNC | VT_TYPEDEF))
2091 error("invalid type");
2092 /* XXX: align & correct type size */
2093 v |= SYM_FIELD;
2094 size = type_size(t, &align);
2095 if (a == TOK_STRUCT) {
2096 c = (c + align - 1) & -align;
2097 ss = sym_push(v, t, c);
2098 c += size;
2099 } else {
2100 ss = sym_push(v, t, 0);
2101 if (size > c)
2102 c = size;
2104 if (align > maxalign)
2105 maxalign = align;
2106 *ps = ss;
2107 ps = &ss->next;
2108 if (tok == ';' || tok == -1)
2109 break;
2110 skip(',');
2112 skip(';');
2114 if (tok == '}')
2115 break;
2117 skip('}');
2118 /* size for struct/union, dummy for enum */
2119 s->c = (c + maxalign - 1) & -maxalign;
2121 return u;
2124 /* return 0 if no type declaration. otherwise, return the basic type
2125 and skip it.
2126 XXX: A '2' is ored to ensure non zero return if int type.
2128 int ist(void)
2130 int t;
2131 Sym *s;
2133 t = 0;
2134 while(1) {
2135 if (tok == TOK_ENUM) {
2136 t |= struct_decl(VT_ENUM);
2137 } else if (tok == TOK_STRUCT || tok == TOK_UNION) {
2138 t |= struct_decl(VT_STRUCT);
2139 } else {
2140 if (tok == TOK_CHAR) {
2141 t |= VT_BYTE;
2142 } else if (tok == TOK_VOID) {
2143 t |= VT_VOID;
2144 } else if (tok == TOK_SHORT) {
2145 t |= VT_SHORT;
2146 } else if (tok == TOK_INT |
2147 (tok >= TOK_CONST & tok <= TOK_INLINE)) {
2148 /* ignored types */
2149 } else if (tok == TOK_FLOAT || tok == TOK_DOUBLE) {
2150 /* We allow that to compile standard headers */
2151 // warning("floats not supported");
2152 } else if (tok == TOK_EXTERN) {
2153 t |= VT_EXTERN;
2154 } else if (tok == TOK_STATIC) {
2155 t |= VT_STATIC;
2156 } else if (tok == TOK_UNSIGNED) {
2157 t |= VT_UNSIGNED;
2158 } else if (tok == TOK_TYPEDEF) {
2159 t |= VT_TYPEDEF;
2160 } else {
2161 s = sym_find(tok);
2162 if (!s || !(s->t & VT_TYPEDEF))
2163 break;
2164 t |= (s->t & ~VT_TYPEDEF);
2166 next();
2168 t |= 2;
2170 return t;
2173 int post_type(t)
2175 int p, n, pt, l, a;
2176 Sym *last, *s;
2178 if (tok == '(') {
2179 /* function declaration */
2180 next();
2181 a = 4;
2182 l = 0;
2183 last = NULL;
2184 while (tok != ')') {
2185 /* read param name and compute offset */
2186 if (l != FUNC_OLD) {
2187 if (!(pt = ist())) {
2188 if (l) {
2189 error("invalid type");
2190 } else {
2191 l = FUNC_OLD;
2192 goto old_proto;
2195 if (pt & VT_VOID && tok == ')')
2196 break;
2197 l = FUNC_NEW;
2198 pt = type_decl(&n, pt, TYPE_DIRECT | TYPE_ABSTRACT);
2199 } else {
2200 old_proto:
2201 n = tok;
2202 pt = 0; /* int type */
2203 next();
2205 /* array must be transformed to pointer according to ANSI C */
2206 pt &= ~VT_ARRAY;
2207 /* XXX: size will be different someday */
2208 a = a + 4;
2209 s = sym_push(n | SYM_FIELD, VT_LOCAL | VT_LVAL | pt, a);
2210 s->next = last;
2211 last = s;
2212 if (tok == ',') {
2213 next();
2214 if (l == FUNC_NEW && tok == TOK_DOTS) {
2215 l = FUNC_ELLIPSIS;
2216 next();
2217 break;
2221 skip(')');
2222 t = post_type(t);
2223 /* we push a anonymous symbol which will contain the function prototype */
2224 p = anon_sym++;
2225 s = sym_push(p, t, l);
2226 s->next = last;
2227 t = VT_FUNC | (p << VT_STRUCT_SHIFT);
2228 } else if (tok == '[') {
2229 /* array definition */
2230 next();
2231 n = -1;
2232 if (tok != ']') {
2233 n = expr_const();
2234 if (n < 0)
2235 error("invalid array size");
2237 skip(']');
2238 /* parse next post type */
2239 t = post_type(t);
2241 /* we push a anonymous symbol which will contain the array
2242 element type */
2243 p = anon_sym++;
2244 sym_push(p, t, n);
2245 t = VT_ARRAY | VT_PTR | (p << VT_STRUCT_SHIFT);
2247 return t;
2250 /* Read a type declaration (except basic type), and return the
2251 type. If v is true, then also put variable name in 'vc' */
2252 int type_decl(int *v, int t, int td)
2254 int u, p;
2255 Sym *s;
2257 t = t & -3; /* suppress the ored '2' */
2258 while (tok == '*') {
2259 next();
2260 while (tok == TOK_CONST || tok == TOK_VOLATILE || tok == TOK_RESTRICT)
2261 next();
2262 t = mk_pointer(t);
2265 /* recursive type */
2266 /* XXX: incorrect if abstract type for functions (e.g. 'int ()') */
2267 if (tok == '(') {
2268 next();
2269 u = type_decl(v, 0, td);
2270 skip(')');
2271 } else {
2272 u = 0;
2273 /* type identifier */
2274 if (tok >= TOK_IDENT && (td & TYPE_DIRECT)) {
2275 *v = tok;
2276 next();
2277 } else {
2278 if (!(td & TYPE_ABSTRACT))
2279 expect("identifier");
2280 *v = 0;
2283 /* append t at the end of u */
2284 t = post_type(t);
2285 if (!u)
2286 return t;
2287 p = u;
2288 while(1) {
2289 s = sym_find((unsigned)p >> VT_STRUCT_SHIFT);
2290 p = s->t;
2291 if (!p) {
2292 s->t = t;
2293 break;
2296 return u;
2299 /* define a new external reference to a function 'v' of type 'u' */
2300 Sym *external_func(v, u)
2302 int n;
2303 Sym *s;
2304 s = sym_find(v);
2305 if (!s) {
2306 n = (int)dlsym(0, get_tok_str(v, 0));
2307 if (n == 0) {
2308 /* used to generate symbol list */
2309 s = sym_push1(&global_stack,
2310 v, u | VT_CONST | VT_LVAL | VT_FORWARD, 0);
2311 } else {
2312 /* int f() */
2313 s = sym_push1(&global_stack,
2314 v, u | VT_CONST | VT_LVAL, n);
2317 return s;
2320 void indir()
2322 if (vt & VT_LVAL)
2323 gv();
2324 if (!(vt & VT_PTR))
2325 expect("pointer");
2326 vt = pointed_type(vt);
2327 if (!(vt & VT_ARRAY)) /* an array is never an lvalue */
2328 vt |= VT_LVAL;
2331 void unary()
2333 int n, t, ft, fc, p, r, align;
2334 Sym *s;
2336 if (tok == TOK_NUM || tok == TOK_CCHAR || tok == TOK_LCHAR) {
2337 vset(VT_CONST, tokc);
2338 next();
2339 } else if (tok == TOK___FUNC__) {
2340 /* special function name identifier */
2341 /* generate (char *) type */
2342 vset(VT_CONST | mk_pointer(VT_BYTE), glo);
2343 strcpy((void *)glo, funcname);
2344 glo += strlen(funcname) + 1;
2345 } else if (tok == TOK_LSTR) {
2346 t = VT_INT;
2347 goto str_init;
2348 } else if (tok == TOK_STR) {
2349 /* string parsing */
2350 t = VT_BYTE;
2351 str_init:
2352 type_size(t, &align);
2353 glo = (glo + align - 1) & -align;
2354 fc = glo;
2355 /* we must declare it as an array first to use initializer parser */
2356 t = VT_CONST | VT_ARRAY | mk_pointer(t);
2357 decl_initializer(t, glo, 1, 0);
2358 glo += type_size(t, &align);
2359 /* put it as pointer */
2360 vset(t & ~VT_ARRAY, fc);
2361 } else {
2362 t = tok;
2363 next();
2364 if (t == '(') {
2365 /* cast ? */
2366 if (t = ist()) {
2367 ft = type_decl(&n, t, TYPE_ABSTRACT);
2368 skip(')');
2369 /* check ISOC99 compound literal */
2370 if (tok == '{') {
2371 /* data is allocated locally by default */
2372 if (global_expr)
2373 ft |= VT_CONST;
2374 else
2375 ft |= VT_LOCAL;
2376 /* all except arrays are lvalues */
2377 if (!(ft & VT_ARRAY))
2378 ft |= VT_LVAL;
2379 fc = decl_initializer_alloc(ft, 1);
2380 vset(ft, fc);
2381 } else {
2382 unary();
2383 vt = (vt & VT_TYPEN) | ft;
2385 } else {
2386 expr();
2387 skip(')');
2389 } else if (t == '*') {
2390 unary();
2391 indir();
2392 } else if (t == '&') {
2393 unary();
2394 test_lvalue();
2395 vt = mk_pointer(vt & VT_LVALN);
2396 } else
2397 if (t == '!') {
2398 unary();
2399 if ((vt & (VT_CONST | VT_LVAL)) == VT_CONST)
2400 vc = !vc;
2401 else if ((vt & VT_VALMASK) == VT_CMP)
2402 vc = vc ^ 1;
2403 else
2404 vset(VT_JMP, gtst(1, 0));
2405 } else
2406 if (t == '~') {
2407 unary();
2408 vpush();
2409 vset(VT_CONST, -1);
2410 gen_op('^');
2411 } else
2412 if (t == '+') {
2413 unary();
2414 } else
2415 if (t == TOK_SIZEOF) {
2416 /* XXX: some code can be generated */
2417 if (tok == '(') {
2418 next();
2419 if (t = ist())
2420 vt = type_decl(&n, t, TYPE_ABSTRACT);
2421 else
2422 expr();
2423 skip(')');
2424 } else {
2425 unary();
2427 vset(VT_CONST, type_size(vt, &t));
2428 } else
2429 if (t == TOK_INC | t == TOK_DEC) {
2430 unary();
2431 inc(0, t);
2432 } else if (t == '-') {
2433 vset(VT_CONST, 0);
2434 vpush();
2435 unary();
2436 gen_op('-');
2437 } else
2439 s = sym_find(t);
2440 if (!s) {
2441 if (tok != '(')
2442 error("'%s' undeclared", get_tok_str(t, 0));
2443 /* for simple function calls, we tolerate undeclared
2444 external reference */
2445 p = anon_sym++;
2446 sym_push1(&global_stack, p, 0, FUNC_OLD);
2447 /* int() function */
2448 s = external_func(t, VT_FUNC | (p << VT_STRUCT_SHIFT));
2450 vset(s->t, s->c);
2451 /* if forward reference, we must point to s->c */
2452 if (vt & VT_FORWARD)
2453 vc = (int)&s->c;
2457 /* post operations */
2458 while (1) {
2459 if (tok == TOK_INC | tok == TOK_DEC) {
2460 inc(1, tok);
2461 next();
2462 } else if (tok == '.' | tok == TOK_ARROW) {
2463 /* field */
2464 if (tok == TOK_ARROW)
2465 indir();
2466 test_lvalue();
2467 vt &= VT_LVALN;
2468 next();
2469 /* expect pointer on structure */
2470 if (!(vt & VT_STRUCT))
2471 expect("struct or union");
2472 s = sym_find(((unsigned)vt >> VT_STRUCT_SHIFT) | SYM_STRUCT);
2473 /* find field */
2474 tok |= SYM_FIELD;
2475 while (s = s->next) {
2476 if (s->v == tok)
2477 break;
2479 if (!s)
2480 error("field not found");
2481 /* add field offset to pointer */
2482 vt = vt & VT_TYPEN; /* change type to int */
2483 vpush();
2484 vset(VT_CONST, s->c);
2485 gen_op('+');
2486 /* change type to field type, and set to lvalue */
2487 vt = (vt & VT_TYPEN) | s->t;
2488 /* an array is never an lvalue */
2489 if (!(vt & VT_ARRAY))
2490 vt |= VT_LVAL;
2491 next();
2492 } else if (tok == '[') {
2493 next();
2494 vpush();
2495 expr();
2496 gen_op('+');
2497 indir();
2498 skip(']');
2499 } else if (tok == '(') {
2500 /* function call */
2501 save_regs(); /* save used temporary registers */
2502 /* lvalue is implied */
2503 vt = vt & VT_LVALN;
2504 if ((vt & VT_VALMASK) != VT_CONST) {
2505 /* evaluate function address */
2506 r = gv();
2507 o(0x50 + r); /* push r */
2509 ft = vt;
2510 fc = vc;
2511 next();
2512 #ifdef INVERT_FUNC_PARAMS
2514 int *str, len, parlevel, *saved_macro_ptr;
2515 Sym *args, *s1;
2517 /* read each argument and store it on a stack */
2518 /* XXX: merge it with macro args ? */
2519 args = NULL;
2520 while (tok != ')') {
2521 len = 0;
2522 str = NULL;
2523 parlevel = 0;
2524 while ((parlevel > 0 || (tok != ')' && tok != ',')) &&
2525 tok != -1) {
2526 if (tok == '(')
2527 parlevel++;
2528 else if (tok == ')')
2529 parlevel--;
2530 tok_add2(&str, &len, tok, tokc);
2531 next();
2533 tok_add(&str, &len, -1); /* end of file added */
2534 tok_add(&str, &len, 0);
2535 sym_push2(&args, 0, 0, (int)str);
2536 if (tok != ',')
2537 break;
2538 next();
2540 if (tok != ')')
2541 expect(")");
2543 /* now generate code in reverse order by reading the stack */
2544 saved_macro_ptr = macro_ptr;
2545 t = 0;
2546 while (args) {
2547 t += 4;
2548 macro_ptr = (int *)args->c;
2549 next();
2550 expr_eq();
2551 gfunc_param();
2552 s1 = args->prev;
2553 free((int *)args->c);
2554 free(args);
2555 args = s1;
2557 macro_ptr = saved_macro_ptr;
2558 /* restore token */
2559 tok = ')';
2561 #else
2562 t = 0;
2563 while (tok != ')') {
2564 t += 4;
2565 expr_eq();
2566 gfunc_param();
2567 if (tok == ',')
2568 next();
2570 #endif
2571 skip(')');
2572 if ((ft & VT_VALMASK) == VT_CONST) {
2573 /* forward reference */
2574 if (ft & VT_FORWARD) {
2575 *(int *)fc = psym(0xe8, *(int *)fc);
2576 } else
2577 oad(0xe8, fc - ind - 5);
2578 } else {
2579 oad(0x2494ff, t); /* call *xxx(%esp) */
2580 t = t + 4;
2582 if (t)
2583 oad(0xc481, t);
2584 /* get return type */
2585 s = sym_find((unsigned)ft >> VT_STRUCT_SHIFT);
2586 vt = s->t | 0; /* return register is eax */
2587 } else {
2588 break;
2593 void uneq()
2595 int t;
2597 unary();
2598 if (tok == '=' |
2599 (tok >= TOK_A_MOD & tok <= TOK_A_DIV) |
2600 tok == TOK_A_XOR | tok == TOK_A_OR |
2601 tok == TOK_A_SHL | tok == TOK_A_SAR) {
2602 test_lvalue();
2603 vpush();
2604 t = tok;
2605 next();
2606 if (t == '=') {
2607 expr_eq();
2608 /* XXX: be more precise */
2609 if ((vt & VT_PTR) != (vstack_ptr[-2] & VT_PTR))
2610 warning("incompatible type");
2611 } else {
2612 vpush();
2613 expr_eq();
2614 gen_op(t & 0x7f);
2616 vstore();
2620 void sum(l)
2622 int t;
2624 if (l == 0)
2625 uneq();
2626 else {
2627 sum(--l);
2628 while ((l == 0 & (tok == '*' | tok == '/' | tok == '%')) |
2629 (l == 1 & (tok == '+' | tok == '-')) |
2630 (l == 2 & (tok == TOK_SHL | tok == TOK_SAR)) |
2631 (l == 3 & ((tok >= TOK_ULE & tok <= TOK_GT) |
2632 tok == TOK_ULT | tok == TOK_UGE)) |
2633 (l == 4 & (tok == TOK_EQ | tok == TOK_NE)) |
2634 (l == 5 & tok == '&') |
2635 (l == 6 & tok == '^') |
2636 (l == 7 & tok == '|') |
2637 (l == 8 & tok == TOK_LAND) |
2638 (l == 9 & tok == TOK_LOR)) {
2639 vpush();
2640 t = tok;
2641 next();
2642 sum(l);
2643 gen_op(t);
2648 /* only used if non constant */
2649 void eand()
2651 int t;
2653 sum(8);
2654 t = 0;
2655 while (1) {
2656 if (tok != TOK_LAND) {
2657 if (t) {
2658 t = gtst(1, t);
2659 vset(VT_JMPI, t);
2661 break;
2663 t = gtst(1, t);
2664 next();
2665 sum(8);
2669 void eor()
2671 int t;
2673 eand();
2674 t = 0;
2675 while (1) {
2676 if (tok != TOK_LOR) {
2677 if (t) {
2678 t = gtst(0, t);
2679 vset(VT_JMP, t);
2681 break;
2683 t = gtst(0, t);
2684 next();
2685 eand();
2689 /* XXX: better constant handling */
2690 void expr_eq()
2692 int t, u, c, r1, r2;
2694 if (const_wanted) {
2695 sum(10);
2696 if (tok == '?') {
2697 c = vc;
2698 next();
2699 expr();
2700 t = vc;
2701 skip(':');
2702 expr_eq();
2703 if (c)
2704 vc = t;
2706 } else {
2707 eor();
2708 if (tok == '?') {
2709 next();
2710 t = gtst(1, 0);
2711 expr();
2712 r1 = gv();
2713 skip(':');
2714 u = gjmp(0);
2715 gsym(t);
2716 expr_eq();
2717 r2 = gv();
2718 move_reg(r1, r2);
2719 vt = (vt & VT_TYPE) | r1;
2720 gsym(u);
2725 void expr()
2727 while (1) {
2728 expr_eq();
2729 if (tok != ',')
2730 break;
2731 next();
2735 int expr_const()
2737 int a;
2738 a = const_wanted;
2739 const_wanted = 1;
2740 expr_eq();
2741 if ((vt & (VT_CONST | VT_LVAL)) != VT_CONST)
2742 expect("constant");
2743 const_wanted = a;
2744 return vc;
2747 void block(int *bsym, int *csym, int *case_sym, int *def_sym, int case_reg)
2749 int a, b, c, d;
2750 Sym *s;
2752 if (tok == TOK_IF) {
2753 /* if test */
2754 next();
2755 skip('(');
2756 expr();
2757 skip(')');
2758 a = gtst(1, 0);
2759 block(bsym, csym, case_sym, def_sym, case_reg);
2760 c = tok;
2761 if (c == TOK_ELSE) {
2762 next();
2763 d = gjmp(0);
2764 gsym(a);
2765 block(bsym, csym, case_sym, def_sym, case_reg);
2766 gsym(d); /* patch else jmp */
2767 } else
2768 gsym(a);
2769 } else if (tok == TOK_WHILE) {
2770 next();
2771 d = ind;
2772 skip('(');
2773 expr();
2774 skip(')');
2775 a = gtst(1, 0);
2776 b = 0;
2777 block(&a, &b, case_sym, def_sym, case_reg);
2778 oad(0xe9, d - ind - 5); /* jmp */
2779 gsym(a);
2780 gsym_addr(b, d);
2781 } else if (tok == '{') {
2782 next();
2783 /* declarations */
2784 s = local_stack.top;
2785 while (tok != '}') {
2786 decl(VT_LOCAL);
2787 block(bsym, csym, case_sym, def_sym, case_reg);
2789 /* pop locally defined symbols */
2790 sym_pop(&local_stack, s);
2791 next();
2792 } else if (tok == TOK_RETURN) {
2793 next();
2794 if (tok != ';') {
2795 expr();
2796 move_reg(0, gv());
2798 skip(';');
2799 rsym = gjmp(rsym); /* jmp */
2800 } else if (tok == TOK_BREAK) {
2801 /* compute jump */
2802 if (!bsym)
2803 error("cannot break");
2804 *bsym = gjmp(*bsym);
2805 next();
2806 skip(';');
2807 } else if (tok == TOK_CONTINUE) {
2808 /* compute jump */
2809 if (!csym)
2810 error("cannot continue");
2811 *csym = gjmp(*csym);
2812 next();
2813 skip(';');
2814 } else if (tok == TOK_FOR) {
2815 int e;
2816 next();
2817 skip('(');
2818 if (tok != ';')
2819 expr();
2820 skip(';');
2821 d = ind;
2822 c = ind;
2823 a = 0;
2824 b = 0;
2825 if (tok != ';') {
2826 expr();
2827 a = gtst(1, 0);
2829 skip(';');
2830 if (tok != ')') {
2831 e = gjmp(0);
2832 c = ind;
2833 expr();
2834 oad(0xe9, d - ind - 5); /* jmp */
2835 gsym(e);
2837 skip(')');
2838 block(&a, &b, case_sym, def_sym, case_reg);
2839 oad(0xe9, c - ind - 5); /* jmp */
2840 gsym(a);
2841 gsym_addr(b, c);
2842 } else
2843 if (tok == TOK_DO) {
2844 next();
2845 a = 0;
2846 b = 0;
2847 d = ind;
2848 block(&a, &b, case_sym, def_sym, case_reg);
2849 skip(TOK_WHILE);
2850 skip('(');
2851 gsym(b);
2852 expr();
2853 c = gtst(0, 0);
2854 gsym_addr(c, d);
2855 skip(')');
2856 gsym(a);
2857 } else
2858 if (tok == TOK_SWITCH) {
2859 next();
2860 skip('(');
2861 expr();
2862 case_reg = gv();
2863 skip(')');
2864 a = 0;
2865 b = 0;
2866 c = 0;
2867 block(&a, csym, &b, &c, case_reg);
2868 /* if no default, jmp after switch */
2869 if (c == 0)
2870 c = ind;
2871 /* default label */
2872 gsym_addr(b, c);
2873 /* break label */
2874 gsym(a);
2875 } else
2876 if (tok == TOK_CASE) {
2877 next();
2878 a = expr_const();
2879 if (!case_sym)
2880 expect("switch");
2881 gsym(*case_sym);
2882 vset(case_reg, 0);
2883 vpush();
2884 vset(VT_CONST, a);
2885 gen_op(TOK_EQ);
2886 *case_sym = gtst(1, 0);
2887 skip(':');
2888 block(bsym, csym, case_sym, def_sym, case_reg);
2889 } else
2890 if (tok == TOK_DEFAULT) {
2891 next();
2892 skip(':');
2893 if (!def_sym)
2894 expect("switch");
2895 if (*def_sym)
2896 error("too many 'default'");
2897 *def_sym = ind;
2898 block(bsym, csym, case_sym, def_sym, case_reg);
2899 } else
2900 if (tok == TOK_GOTO) {
2901 next();
2902 s = sym_find1(&label_stack, tok);
2903 /* put forward definition if needed */
2904 if (!s)
2905 s = sym_push1(&label_stack, tok, VT_FORWARD, 0);
2906 /* label already defined */
2907 if (s->t & VT_FORWARD)
2908 s->c = gjmp(s->c); /* jmp xxx */
2909 else
2910 oad(0xe9, s->c - ind - 5); /* jmp xxx */
2911 next();
2912 skip(';');
2913 } else {
2914 b = tok;
2915 next();
2916 if (tok == ':') {
2917 next();
2918 /* label case */
2919 s = sym_find1(&label_stack, b);
2920 if (s) {
2921 if (!(s->t & VT_FORWARD))
2922 error("multiple defined label");
2923 gsym(s->c);
2924 s->c = ind;
2925 s->t = 0;
2926 } else {
2927 sym_push1(&label_stack, b, 0, ind);
2929 block(bsym, csym, case_sym, def_sym, case_reg);
2930 } else {
2931 /* expression case: go backward of one token */
2932 /* XXX: currently incorrect if number/string/char */
2933 tok1 = tok;
2934 tok = b;
2935 if (tok != ';') {
2936 expr();
2938 skip(';');
2943 /* t is the array or struct type. c is the array or struct
2944 address. cur_index/cur_field is the pointer to the current
2945 value. 'size_only' is true if only size info is needed (only used
2946 in arrays) */
2947 void decl_designator(int t, int c,
2948 int *cur_index, Sym **cur_field,
2949 int size_only)
2951 Sym *s, *f;
2952 int notfirst, index, align;
2954 notfirst = 0;
2955 while (tok == '[' || tok == '.') {
2956 if (tok == '[') {
2957 if (!(t & VT_ARRAY))
2958 expect("array type");
2959 s = sym_find(((unsigned)t >> VT_STRUCT_SHIFT));
2960 next();
2961 index = expr_const();
2962 if (index < 0 || (s->c >= 0 && index >= s->c))
2963 expect("invalid index");
2964 skip(']');
2965 if (!notfirst)
2966 *cur_index = index;
2967 t = pointed_type(t);
2968 c += index * type_size(t, &align);
2969 } else {
2970 if (!(t & VT_STRUCT))
2971 expect("struct/union type");
2972 next();
2973 s = sym_find(((unsigned)t >> VT_STRUCT_SHIFT) | SYM_STRUCT);
2974 tok |= SYM_FIELD;
2975 f = s->next;
2976 while (f) {
2977 if (f->v == tok)
2978 break;
2979 f = f->next;
2981 if (!f)
2982 expect("field");
2983 next();
2984 if (!notfirst)
2985 *cur_field = f;
2986 t = f->t | (t & VT_TYPEN);
2987 c += f->c;
2989 notfirst = 1;
2991 if (notfirst) {
2992 skip('=');
2993 } else {
2994 if (t & VT_ARRAY) {
2995 index = *cur_index;
2996 t = pointed_type(t);
2997 c += index * type_size(t, &align);
2998 } else {
2999 f = *cur_field;
3000 if (!f)
3001 error("too many field init");
3002 t = f->t | (t & VT_TYPEN);
3003 c += f->c;
3006 decl_initializer(t, c, 0, size_only);
3009 /* store a value or an expression directly in global data or in local array */
3011 void init_putv(int t, int c, int v, int is_expr)
3013 int saved_global_expr;
3015 if ((t & VT_VALMASK) == VT_CONST) {
3016 if (is_expr) {
3017 /* compound literals must be allocated globally in this case */
3018 saved_global_expr = global_expr;
3019 global_expr = 1;
3020 v = expr_const();
3021 global_expr = saved_global_expr;
3023 if (t & VT_BYTE)
3024 *(char *)c = v;
3025 else if (t & VT_SHORT)
3026 *(short *)c = v;
3027 else
3028 *(int *)c = v;
3029 } else {
3030 vt = t;
3031 vc = c;
3032 vpush();
3033 if (is_expr)
3034 expr_eq();
3035 else
3036 vset(VT_CONST, v);
3037 vstore();
3041 /* put zeros for variable based init */
3042 void init_putz(int t, int c, int size)
3044 int memset_addr, r;
3046 if ((t & VT_VALMASK) == VT_CONST) {
3047 /* nothing to do because global are already set to zero */
3048 } else {
3049 vset(VT_CONST, size);
3050 r = gv();
3051 o(0x50 + r);
3052 vset(VT_CONST, 0);
3053 r = gv();
3054 o(0x50 + r);
3055 vset(VT_LOCAL, c);
3056 r = gv();
3057 o(0x50 + r);
3058 memset_addr = (int)&memset;
3059 oad(0xe8, memset_addr - ind - 5);
3060 oad(0xc481, 3 * 4);
3064 /* 't' contains the type and storage info. c is the address of the
3065 object. 'first' is true if array '{' must be read (multi dimension
3066 implicit array init handling). 'size_only' is true if size only
3067 evaluation is wanted (only for arrays). */
3068 void decl_initializer(int t, int c, int first, int size_only)
3070 int index, array_length, n, no_oblock, nb, parlevel, i;
3071 int t1, size1, align1;
3072 Sym *s, *f;
3073 TokenSym *ts;
3075 if (t & VT_ARRAY) {
3076 s = sym_find(((unsigned)t >> VT_STRUCT_SHIFT));
3077 n = s->c;
3078 array_length = 0;
3079 t1 = pointed_type(t);
3080 size1 = type_size(t1, &align1);
3082 no_oblock = 1;
3083 if ((first && tok != TOK_LSTR && tok != TOK_STR) ||
3084 tok == '{') {
3085 skip('{');
3086 no_oblock = 0;
3089 /* only parse strings here if correct type (otherwise: handle
3090 them as ((w)char *) expressions */
3091 if ((tok == TOK_LSTR &&
3092 (t1 & VT_TYPE & ~VT_UNSIGNED) == VT_INT) ||
3093 (tok == TOK_STR &&
3094 (t1 & VT_TYPE & ~VT_UNSIGNED) == VT_BYTE)) {
3095 /* XXX: move multiple string parsing in parser ? */
3096 while (tok == TOK_STR || tok == TOK_LSTR) {
3097 ts = (TokenSym *)tokc;
3098 /* compute maximum number of chars wanted */
3099 nb = ts->len;
3100 if (n >= 0 && nb > (n - array_length))
3101 nb = n - array_length;
3102 if (!size_only) {
3103 if (ts->len > nb)
3104 warning("initializer-string for array is too long");
3105 for(i=0;i<nb;i++) {
3106 init_putv(t1, c + (array_length + i) * size1,
3107 ts->str[i], 0);
3110 array_length += nb;
3111 next();
3113 /* only add trailing zero if enough storage (no
3114 warning in this case since it is standard) */
3115 if (n < 0 || array_length < n) {
3116 if (!size_only) {
3117 init_putv(t1, c + (array_length * size1), 0, 0);
3119 array_length++;
3121 } else {
3122 index = 0;
3123 while (tok != '}') {
3124 decl_designator(t, c, &index, NULL, size_only);
3125 if (n >= 0 && index >= n)
3126 error("index too large");
3127 /* must put zero in holes (note that doing it that way
3128 ensures that it even works with designators) */
3129 if (!size_only && array_length < index) {
3130 init_putz(t1, c + array_length * size1,
3131 (index - array_length) * size1);
3133 index++;
3134 if (index > array_length)
3135 array_length = index;
3136 /* special test for multi dimensional arrays (may not
3137 be strictly correct if designators are used at the
3138 same time) */
3139 if (index >= n && no_oblock)
3140 break;
3141 if (tok == '}')
3142 break;
3143 skip(',');
3146 if (!no_oblock)
3147 skip('}');
3148 /* put zeros at the end */
3149 if (!size_only && n >= 0 && array_length < n) {
3150 init_putz(t1, c + array_length * size1,
3151 (n - array_length) * size1);
3153 /* patch type size if needed */
3154 if (n < 0)
3155 s->c = array_length;
3156 } else if (t & VT_STRUCT) {
3157 /* XXX: union needs only one init */
3158 skip('{');
3159 s = sym_find(((unsigned)t >> VT_STRUCT_SHIFT) | SYM_STRUCT);
3160 f = s->next;
3161 array_length = 0;
3162 index = 0;
3163 n = s->c;
3164 while (tok != '}') {
3165 decl_designator(t, c, NULL, &f, size_only);
3166 /* fill with zero between fields */
3167 index = f->c;
3168 if (!size_only && array_length < index) {
3169 init_putz(t, c + array_length,
3170 index - array_length);
3172 index = index + type_size(f->t, &align1);
3173 if (index > array_length)
3174 array_length = index;
3175 if (tok == '}')
3176 break;
3177 skip(',');
3178 f = f->next;
3180 /* put zeros at the end */
3181 if (!size_only && array_length < n) {
3182 init_putz(t, c + array_length,
3183 n - array_length);
3185 skip('}');
3186 } else if (tok == '{') {
3187 next();
3188 decl_initializer(t, c, first, size_only);
3189 skip('}');
3190 } else if (size_only) {
3191 /* just skip expression */
3192 parlevel = 0;
3193 while ((parlevel > 0 || (tok != '}' && tok != ',')) &&
3194 tok != -1) {
3195 if (tok == '(')
3196 parlevel++;
3197 else if (tok == ')')
3198 parlevel--;
3199 next();
3201 } else {
3202 init_putv(t, c, 0, 1);
3206 /* parse an initializer for type 't' if 'has_init' is true, and
3207 allocate space in local or global data space. The allocated address
3208 in returned */
3209 int decl_initializer_alloc(int t, int has_init)
3211 int size, align, addr, tok1;
3212 int *init_str, init_len, level, *saved_macro_ptr;
3214 size = type_size(t, &align);
3215 /* If unknown size, we must evaluate it before
3216 evaluating initializers because
3217 initializers can generate global data too
3218 (e.g. string pointers or ISOC99 compound
3219 literals). It also simplifies local
3220 initializers handling */
3221 init_len = 0;
3222 init_str = NULL;
3223 saved_macro_ptr = NULL; /* avoid warning */
3224 tok1 = 0;
3225 if (size < 0) {
3226 if (!has_init)
3227 error("unknown type size");
3228 /* get all init string */
3229 level = 0;
3230 while (level > 0 || (tok != ',' && tok != ';')) {
3231 if (tok < 0)
3232 error("unexpect end of file in initializer");
3233 tok_add2(&init_str, &init_len, tok, tokc);
3234 if (tok == '{')
3235 level++;
3236 else if (tok == '}') {
3237 if (level == 0)
3238 break;
3239 level--;
3241 next();
3243 tok1 = tok;
3244 tok_add(&init_str, &init_len, -1);
3245 tok_add(&init_str, &init_len, 0);
3247 /* compute size */
3248 saved_macro_ptr = macro_ptr;
3249 macro_ptr = init_str;
3250 next();
3251 decl_initializer(t, 0, 1, 1);
3252 /* prepare second initializer parsing */
3253 macro_ptr = init_str;
3254 next();
3256 /* if still unknown size, error */
3257 size = type_size(t, &align);
3258 if (size < 0)
3259 error("unknown type size");
3261 if ((t & VT_VALMASK) == VT_LOCAL) {
3262 loc = (loc - size) & -align;
3263 addr = loc;
3264 } else {
3265 glo = (glo + align - 1) & -align;
3266 addr = glo;
3267 /* very important to increment global
3268 pointer at this time because
3269 initializers themselves can create new
3270 initializers */
3271 glo += size;
3273 if (has_init) {
3274 decl_initializer(t, addr, 1, 0);
3275 /* restore parse state if needed */
3276 if (init_str) {
3277 free(init_str);
3278 macro_ptr = saved_macro_ptr;
3279 tok = tok1;
3282 return addr;
3286 /* 'l' is VT_LOCAL or VT_CONST to define default storage type */
3287 void decl(l)
3289 int *a, t, b, v, u, n, addr, has_init;
3290 Sym *sym;
3292 while (b = ist()) {
3293 if ((b & (VT_ENUM | VT_STRUCT)) && tok == ';') {
3294 /* we accept no variable after */
3295 next();
3296 continue;
3298 while (1) { /* iterate thru each declaration */
3299 t = type_decl(&v, b, TYPE_DIRECT);
3300 if (tok == '{') {
3301 if (!(t & VT_FUNC))
3302 expect("function definition");
3303 /* patch forward references */
3304 if ((sym = sym_find(v)) && (sym->t & VT_FORWARD)) {
3305 gsym(sym->c);
3306 sym->c = ind;
3307 sym->t = VT_CONST | VT_LVAL | t;
3308 } else {
3309 /* put function address */
3310 sym_push1(&global_stack, v, VT_CONST | VT_LVAL | t, ind);
3312 funcname = get_tok_str(v, 0);
3313 /* push a dummy symbol to enable local sym storage */
3314 sym_push1(&local_stack, 0, 0, 0);
3315 /* define parameters */
3316 sym = sym_find((unsigned)t >> VT_STRUCT_SHIFT);
3317 while (sym = sym->next)
3318 sym_push(sym->v & ~SYM_FIELD, sym->t, sym->c);
3319 loc = 0;
3320 o(0xe58955); /* push %ebp, mov %esp, %ebp */
3321 a = (int *)oad(0xec81, 0); /* sub $xxx, %esp */
3322 rsym = 0;
3323 block(0, 0, 0, 0, 0);
3324 gsym(rsym);
3325 o(0xc3c9); /* leave, ret */
3326 *a = (-loc + 3) & -4; /* align local size to word &
3327 save local variables */
3328 sym_pop(&label_stack, 0); /* reset label stack */
3329 sym_pop(&local_stack, 0); /* reset local stack */
3330 funcname = "";
3331 break;
3332 } else {
3333 if (b & VT_TYPEDEF) {
3334 /* save typedefed type */
3335 sym_push(v, t | VT_TYPEDEF, 0);
3336 } else if (t & VT_FUNC) {
3337 /* XXX: incorrect to flush, but needed while
3338 waiting for function prototypes */
3339 /* external function definition */
3340 external_func(v, t);
3341 } else {
3342 /* not lvalue if array */
3343 if (!(t & VT_ARRAY))
3344 t |= VT_LVAL;
3345 if (b & VT_EXTERN) {
3346 /* external variable */
3347 /* XXX: factorize with external function def */
3348 n = (int)dlsym(NULL, get_tok_str(v, 0));
3349 if (!n)
3350 error("unknown external variable");
3351 sym_push(v, VT_CONST | t, n);
3352 } else {
3353 u = l;
3354 if (t & VT_STATIC)
3355 u = VT_CONST;
3356 u |= t;
3357 has_init = (tok == '=');
3358 if (has_init)
3359 next();
3360 addr = decl_initializer_alloc(u, has_init);
3361 sym_push(v, u, addr);
3364 if (tok != ',') {
3365 skip(';');
3366 break;
3368 next();
3374 /* open a dynamic library so that its symbol are available for
3375 compiled programs */
3376 void open_dll(char *libname)
3378 char buf[1024];
3379 void *h;
3381 snprintf(buf, sizeof(buf), "lib%s.so", libname);
3382 h = dlopen(buf, RTLD_GLOBAL | RTLD_LAZY);
3383 if (!h)
3384 error((char *)dlerror());
3387 /* output a binary file (for testing) */
3388 void build_exe(char *filename)
3390 FILE *f;
3391 f = fopen(filename, "w");
3392 fwrite((void *)prog, 1, ind - prog, f);
3393 fclose(f);
3396 int main(int argc, char **argv)
3398 Sym *s;
3399 int (*t)();
3400 char *p, *r, *outfile;
3401 int optind;
3403 include_paths[0] = "/usr/include";
3404 include_paths[1] = "/usr/lib/tcc";
3405 include_paths[2] = "/usr/local/lib/tcc";
3406 nb_include_paths = 3;
3408 /* add all tokens */
3409 tok_ident = TOK_IDENT;
3410 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";
3411 while (*p) {
3412 r = p;
3413 while (*r++);
3414 tok_alloc(p, r - p - 1);
3415 p = r;
3418 /* standard defines */
3419 define_symbol("__STDC__");
3420 #ifdef __i386__
3421 define_symbol("__i386__");
3422 #endif
3424 optind = 1;
3425 outfile = NULL;
3426 while (1) {
3427 if (optind >= argc) {
3428 show_help:
3429 printf("tcc version 0.9 - Tiny C Compiler - Copyright (C) 2001 Fabrice Bellard\n"
3430 "usage: tcc [-Idir] [-Dsym] [-llib] infile [infile_arg...]\n");
3431 return 1;
3433 r = argv[optind];
3434 if (r[0] != '-')
3435 break;
3436 optind++;
3437 if (r[1] == 'I') {
3438 if (nb_include_paths >= INCLUDE_PATHS_MAX)
3439 error("too many include paths");
3440 include_paths[nb_include_paths++] = r + 2;
3441 } else if (r[1] == 'D') {
3442 define_symbol(r + 2);
3443 } else if (r[1] == 'l') {
3444 open_dll(r + 2);
3445 } else if (r[1] == 'o') {
3446 /* currently, only for testing, so not documented */
3447 if (optind >= argc)
3448 goto show_help;
3449 outfile = argv[optind++];
3450 } else {
3451 fprintf(stderr, "invalid option -- '%s'\n", r);
3452 exit(1);
3456 filename = argv[optind];
3457 line_num = 1;
3458 funcname = "";
3459 file = fopen(filename, "r");
3460 if (!file) {
3461 perror(filename);
3462 exit(1);
3464 include_stack_ptr = include_stack;
3465 ifdef_stack_ptr = ifdef_stack;
3467 glo = (int)malloc(DATA_SIZE);
3468 memset((void *)glo, 0, DATA_SIZE);
3469 prog = (int)malloc(TEXT_SIZE);
3470 vstack_ptr = vstack;
3471 anon_sym = 1 << (31 - VT_STRUCT_SHIFT);
3472 ind = prog;
3473 inp();
3474 ch = '\n'; /* needed to parse correctly first preprocessor command */
3475 next();
3476 decl(VT_CONST);
3477 if (tok != -1)
3478 expect("declaration");
3479 if (outfile) {
3480 build_exe(outfile);
3481 return 0;
3482 } else {
3483 s = sym_find(TOK_MAIN);
3484 if (!s)
3485 error("main() not defined");
3486 t = (int (*)())s->c;
3487 #ifdef PROFILE
3488 return 1;
3489 #else
3490 return (*t)(argc - optind, argv + optind);
3491 #endif