eval function args in reverse order - added short and unsigned char support - added...
[tinycc.git] / tcc.c
blob4551162ab6552b912421e3adbbb5bb9f258305ad
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 /* number of available temporary registers */
38 #define NB_REGS 3
39 /* defined if function parameters must be evaluated in revert order */
40 #define INVERT_FUNC_PARAMS
42 /* token symbol management */
43 typedef struct TokenSym {
44 struct TokenSym *next;
45 int tok; /* token number */
46 int len;
47 char str[1];
48 } TokenSym;
50 /* symbol management */
51 typedef struct Sym {
52 int v; /* symbol token */
53 int t; /* associated type */
54 int c; /* associated number */
55 struct Sym *next; /* next related symbol */
56 struct Sym *prev; /* prev symbol in stack */
57 } Sym;
59 #define SYM_STRUCT 0x40000000 /* struct/union/enum symbol space */
60 #define SYM_FIELD 0x20000000 /* struct/union field symbol space */
62 #define FUNC_NEW 1 /* ansi function prototype */
63 #define FUNC_OLD 2 /* old function prototype */
64 #define FUNC_ELLIPSIS 3 /* ansi function prototype with ... */
66 /* field 'Sym.t' for macros */
67 #define MACRO_OBJ 0 /* object like macro */
68 #define MACRO_FUNC 1 /* function like macro */
70 /* type_decl() types */
71 #define TYPE_ABSTRACT 1 /* type without variable */
72 #define TYPE_DIRECT 2 /* type with variable */
74 typedef struct {
75 FILE *file;
76 char *filename;
77 int line_num;
78 } IncludeFile;
80 /* loc : local variable index
81 glo : global variable index
82 ind : output code ptr
83 rsym: return symbol
84 prog: output code
85 anon_sym: anonymous symbol index
87 FILE *file;
88 int tok, tok1, tokc, rsym, anon_sym,
89 prog, ind, loc, glo, vt, vc, const_wanted, line_num;
90 TokenSym *first_ident;
91 char token_buf[STRING_MAX_SIZE + 1];
92 char *filename;
93 Sym *define_stack, *global_stack, *local_stack, *label_stack;
95 int vstack[VSTACK_SIZE], *vstack_ptr;
96 int *macro_ptr, *macro_ptr_allocated;
97 IncludeFile include_stack[INCLUDE_STACK_SIZE], *include_stack_ptr;
98 int ifdef_stack[IFDEF_STACK_SIZE], *ifdef_stack_ptr;
99 char *include_paths[INCLUDE_PATHS_MAX];
100 int nb_include_paths;
102 /* The current value can be: */
103 #define VT_VALMASK 0x000f
104 #define VT_CONST 0x000a /* constant in vc
105 (must be first non register value) */
106 #define VT_LLOCAL 0x000b /* lvalue, offset on stack */
107 #define VT_LOCAL 0x000c /* offset on stack */
108 #define VT_CMP 0x000d /* the value is stored in processor flags (in vc) */
109 #define VT_JMP 0x000e /* value is the consequence of jmp true */
110 #define VT_JMPI 0x000f /* value is the consequence of jmp false */
111 #define VT_LVAL 0x0010 /* var is an lvalue */
112 #define VT_LVALN -17 /* ~VT_LVAL */
113 #define VT_FORWARD 0x0020 /* value is forward reference
114 (only used for functions) */
116 /* types */
117 #define VT_VOID 0x00040
118 #define VT_BYTE 0x00080 /* signed byte type */
119 #define VT_PTR 0x00100 /* pointer increment */
120 #define VT_UNSIGNED 0x00200 /* unsigned type */
121 #define VT_ARRAY 0x00400 /* array type (only used in parsing) */
122 #define VT_ENUM 0x00800 /* enum definition */
123 #define VT_FUNC 0x01000 /* function type */
124 #define VT_STRUCT 0x002000 /* struct/union definition */
125 #define VT_TYPEDEF 0x004000 /* typedef definition */
126 #define VT_EXTERN 0x008000 /* extern definition */
127 #define VT_STATIC 0x010000 /* static variable */
128 #define VT_SHORT 0x020000 /* short type */
129 #define VT_STRUCT_SHIFT 18 /* structure/enum name shift (14 bits left) */
131 #define VT_TYPE 0xffffffc0 /* type mask */
132 #define VT_TYPEN 0x0000003f /* ~VT_TYPE */
133 #define VT_FUNCN -4097 /* ~VT_FUNC */
135 /* token values */
137 /* warning: the following compare tokens depend on i386 asm code */
138 #define TOK_ULT 0x92
139 #define TOK_UGE 0x93
140 #define TOK_EQ 0x94
141 #define TOK_NE 0x95
142 #define TOK_ULE 0x96
143 #define TOK_UGT 0x97
144 #define TOK_LT 0x9c
145 #define TOK_GE 0x9d
146 #define TOK_LE 0x9e
147 #define TOK_GT 0x9f
149 #define TOK_LAND 0xa0
150 #define TOK_LOR 0xa1
152 #define TOK_DEC 0xa2
153 #define TOK_MID 0xa3 /* inc/dec, to void constant */
154 #define TOK_INC 0xa4
155 #define TOK_ARROW 0xa7
156 #define TOK_DOTS 0xa8 /* three dots */
157 #define TOK_SHR 0xa9 /* unsigned shift right */
158 #define TOK_UDIV 0xb0 /* unsigned division */
159 #define TOK_UMOD 0xb1 /* unsigned modulo */
160 #define TOK_PDIV 0xb2 /* fast division with undefined rounding for pointers */
161 #define TOK_NUM 0xb3 /* number in tokc */
162 #define TOK_CCHAR 0xb4 /* char constant in tokc */
163 #define TOK_STR 0xb5 /* pointer to string in tokc */
165 #define TOK_TWOSHARPS 0xb6 /* ## preprocessing token */
167 #define TOK_SHL 0x01 /* shift left */
168 #define TOK_SAR 0x02 /* signed shift right */
170 /* assignement operators : normal operator or 0x80 */
171 #define TOK_A_MOD 0xa5
172 #define TOK_A_AND 0xa6
173 #define TOK_A_MUL 0xaa
174 #define TOK_A_ADD 0xab
175 #define TOK_A_SUB 0xad
176 #define TOK_A_DIV 0xaf
177 #define TOK_A_XOR 0xde
178 #define TOK_A_OR 0xfc
179 #define TOK_A_SHL 0x81
180 #define TOK_A_SAR 0x82
182 /* all identificators and strings have token above that */
183 #define TOK_IDENT 256
185 enum {
186 TOK_INT = TOK_IDENT,
187 TOK_VOID,
188 TOK_CHAR,
189 TOK_IF,
190 TOK_ELSE,
191 TOK_WHILE,
192 TOK_BREAK,
193 TOK_RETURN,
194 TOK_FOR,
195 TOK_EXTERN,
196 TOK_STATIC,
197 TOK_UNSIGNED,
198 TOK_GOTO,
199 TOK_DO,
200 TOK_CONTINUE,
201 TOK_SWITCH,
202 TOK_CASE,
204 /* ignored types Must have contiguous values */
205 TOK_CONST,
206 TOK_VOLATILE,
207 TOK_LONG,
208 TOK_REGISTER,
209 TOK_SIGNED,
210 TOK_AUTO,
211 TOK_INLINE,
213 /* unsupported type */
214 TOK_FLOAT,
215 TOK_DOUBLE,
217 TOK_SHORT,
218 TOK_STRUCT,
219 TOK_UNION,
220 TOK_TYPEDEF,
221 TOK_DEFAULT,
222 TOK_ENUM,
223 TOK_SIZEOF,
225 /* preprocessor only */
226 TOK_DEFINE,
227 TOK_INCLUDE,
228 TOK_IFDEF,
229 TOK_IFNDEF,
230 TOK_ELIF,
231 TOK_ENDIF,
232 TOK_DEFINED,
233 TOK_UNDEF,
235 /* special identifiers */
236 TOK_MAIN,
239 void sum();
240 void next();
241 void next_nomacro();
242 int expr_const();
243 void expr_eq();
244 void expr();
245 void decl();
246 int gv();
247 void move_reg();
248 void save_reg();
249 void macro_subst(int **tok_str, int *tok_len,
250 Sym **nested_list, int *macro_str);
251 int save_reg_forced(int r);
252 int type_size(int t, int *a);
253 int pointed_type(int t);
254 int pointed_size(int t);
255 int ist(void);
256 int type_decl(int *v, int t, int td);
258 #ifdef PROFILE
259 /* dummy function for profiling */
260 void *dlopen(const char *filename, int flag)
262 return (void *)1;
264 const char *dlerror(void)
266 return "error";
269 void *dlsym(void *handle, char *symbol)
271 return (void *)1;
274 #endif
276 int isid(c)
278 return (c >= 'a' & c <= 'z') |
279 (c >= 'A' & c <= 'Z') |
280 c == '_';
283 int isnum(c)
285 return c >= '0' & c <= '9';
288 void printline()
290 IncludeFile *f;
291 for(f = include_stack; f < include_stack_ptr; f++)
292 fprintf(stderr, "In file included from %s:%d:\n",
293 f->filename, f->line_num);
294 fprintf(stderr, "%s:%d: ", filename, line_num);
297 void error(const char *fmt, ...)
299 va_list ap;
300 va_start(ap, fmt);
301 printline();
302 vfprintf(stderr, fmt, ap);
303 fprintf(stderr, "\n");
304 exit(1);
305 va_end(ap);
308 void expect(const char *msg)
310 error("%s expected", msg);
313 void warning(const char *msg)
315 printline();
316 fprintf(stderr, "warning: %s\n", msg);
319 void skip(c)
321 if (tok != c)
322 error("'%c' expected", c);
323 next();
326 void test_lvalue()
328 if (!(vt & VT_LVAL))
329 expect("lvalue");
332 TokenSym *tok_alloc(char *str, int len)
334 TokenSym *ts, **pts;
335 int t;
337 t = TOK_IDENT;
338 pts = &first_ident;
339 while (1) {
340 ts = *pts;
341 if (!ts)
342 break;
343 if (ts->len == len && !memcmp(ts->str, str, len))
344 return ts;
345 t++;
346 pts = &(ts->next);
348 ts = malloc(sizeof(TokenSym) + len);
349 if (!ts)
350 error("memory full");
351 ts->tok = t;
352 ts->len = len;
353 ts->next = NULL;
354 memcpy(ts->str, str, len + 1);
356 *pts = ts;
357 return ts;
360 void add_char(char **pp, int c)
362 char *p;
363 p = *pp;
364 if (c == '\'' || c == '\"' || c == '\\') {
365 /* XXX: could be more precise if char or string */
366 *p++ = '\\';
368 if (c >= 32 && c <= 126) {
369 *p++ = c;
370 } else {
371 *p++ = '\\';
372 if (c == '\n') {
373 *p++ = 'n';
374 } else {
375 *p++ = '0' + ((c >> 6) & 7);
376 *p++ = '0' + ((c >> 3) & 7);
377 *p++ = '0' + (c & 7);
380 *pp = p;
383 /* XXX: buffer overflow */
384 char *get_tok_str(int v, int c)
386 static char buf[STRING_MAX_SIZE + 1];
387 TokenSym *ts;
388 char *p;
389 int i;
391 if (v == TOK_NUM) {
392 sprintf(buf, "%d", c);
393 return buf;
394 } else if (v == TOK_CCHAR) {
395 p = buf;
396 *p++ = '\'';
397 add_char(&p, c);
398 *p++ = '\'';
399 *p = '\0';
400 return buf;
401 } else if (v == TOK_STR) {
402 ts = (TokenSym *)c;
403 p = buf;
404 *p++ = '\"';
405 for(i=0;i<ts->len;i++)
406 add_char(&p, ts->str[i]);
407 *p++ = '\"';
408 *p = '\0';
409 return buf;
410 } else if (v < TOK_IDENT) {
411 p = buf;
412 *p++ = v;
413 *p = '\0';
414 return buf;
415 } else {
416 ts = first_ident;
417 while (ts != NULL) {
418 if (ts->tok == v)
419 return ts->str;
420 ts = ts->next;
422 return NULL;
426 /* find a symbol and return its associated structure. 's' is the top
427 of the symbol stack */
428 Sym *sym_find1(Sym *s, int v)
430 while (s) {
431 if (s->v == v)
432 return s;
433 s = s->prev;
435 return 0;
438 Sym *sym_push1(Sym **ps, int v, int t, int c)
440 Sym *s;
441 s = malloc(sizeof(Sym));
442 if (!s)
443 error("memory full");
444 s->v = v;
445 s->t = t;
446 s->c = c;
447 s->next = NULL;
448 s->prev = *ps;
449 *ps = s;
450 return s;
453 /* find a symbol in the right symbol space */
454 Sym *sym_find(int v)
456 Sym *s;
457 s = sym_find1(local_stack, v);
458 if (!s)
459 s = sym_find1(global_stack, v);
460 return s;
463 /* push a given symbol on the symbol stack */
464 Sym *sym_push(int v, int t, int c)
466 if (local_stack)
467 return sym_push1(&local_stack, v, t, c);
468 else
469 return sym_push1(&global_stack, v, t, c);
472 /* pop symbols until top reaches 'b' */
473 void sym_pop(Sym **ps, Sym *b)
475 Sym *s, *ss;
477 s = *ps;
478 while(s != b) {
479 ss = s->prev;
480 free(s);
481 s = ss;
483 *ps = b;
486 int ch, ch1;
488 /* read next char from current input file */
489 void inp()
491 redo:
492 ch1 = fgetc(file);
493 if (ch1 == -1) {
494 if (include_stack_ptr == include_stack)
495 return;
496 /* pop include stack */
497 fclose(file);
498 free(filename);
499 include_stack_ptr--;
500 file = include_stack_ptr->file;
501 filename = include_stack_ptr->filename;
502 line_num = include_stack_ptr->line_num;
503 goto redo;
505 if (ch1 == '\n')
506 line_num++;
507 // printf("ch1=%c 0x%x\n", ch1, ch1);
510 /* input with '\\n' handling */
511 void minp()
513 redo:
514 ch = ch1;
515 inp();
516 if (ch == '\\' && ch1 == '\n') {
517 inp();
518 goto redo;
520 //printf("ch=%c 0x%x\n", ch, ch);
523 /* same as minp, but also skip comments */
524 void cinp()
526 int c;
528 if (ch1 == '/') {
529 inp();
530 if (ch1 == '/') {
531 /* single line C++ comments */
532 inp();
533 while (ch1 != '\n' && ch1 != -1)
534 inp();
535 inp();
536 ch = ' '; /* return space */
537 } else if (ch1 == '*') {
538 /* C comments */
539 inp();
540 while (ch1 != -1) {
541 c = ch1;
542 inp();
543 if (c == '*' && ch1 == '/') {
544 inp();
545 ch = ' '; /* return space */
546 break;
549 } else {
550 ch = '/';
552 } else {
553 minp();
557 void skip_spaces()
559 while (ch == ' ' || ch == '\t')
560 cinp();
563 /* skip block of text until #else, #elif or #endif. skip also pairs of
564 #if/#endif */
565 void preprocess_skip()
567 int a;
568 a = 0;
569 while (1) {
570 while (ch != '\n') {
571 if (ch == -1)
572 expect("#endif");
573 cinp();
575 cinp();
576 skip_spaces();
577 if (ch == '#') {
578 cinp();
579 next_nomacro();
580 if (a == 0 &&
581 (tok == TOK_ELSE || tok == TOK_ELIF || tok == TOK_ENDIF))
582 break;
583 if (tok == TOK_IF || tok == TOK_IFDEF || tok == TOK_IFNDEF)
584 a++;
585 else if (tok == TOK_ENDIF)
586 a--;
591 void tok_add(int **tok_str, int *tok_len, int t)
593 int len, *str;
594 len = *tok_len;
595 str = *tok_str;
596 if ((len & 63) == 0) {
597 str = realloc(str, (len + 64) * sizeof(int));
598 if (!str)
599 return;
600 *tok_str = str;
602 str[len++] = t;
603 *tok_len = len;
606 void tok_add2(int **tok_str, int *tok_len, int t, int c)
608 tok_add(tok_str, tok_len, t);
609 if (t == TOK_NUM || t == TOK_CCHAR || t == TOK_STR)
610 tok_add(tok_str, tok_len, c);
613 /* eval an expression for #if/#elif */
614 int expr_preprocess()
616 int *str, len, c, t;
618 str = NULL;
619 len = 0;
620 while (1) {
621 skip_spaces();
622 if (ch == '\n')
623 break;
624 next(); /* do macro subst */
625 if (tok == TOK_DEFINED) {
626 next_nomacro();
627 t = tok;
628 if (t == '(')
629 next_nomacro();
630 c = sym_find1(define_stack, tok) != 0;
631 if (t == '(')
632 next_nomacro();
633 tok = TOK_NUM;
634 tokc = c;
635 } else if (tok >= TOK_IDENT) {
636 /* if undefined macro */
637 tok = TOK_NUM;
638 tokc = 0;
640 tok_add2(&str, &len, tok, tokc);
642 tok_add(&str, &len, -1); /* simulate end of file */
643 tok_add(&str, &len, 0);
644 /* now evaluate C constant expression */
645 macro_ptr = str;
646 next();
647 c = expr_const();
648 macro_ptr = NULL;
649 free(str);
650 return c != 0;
653 #ifdef DEBUG
654 void tok_print(int *str)
656 int t, c;
658 while (1) {
659 t = *str++;
660 if (!t)
661 break;
662 c = 0;
663 if (t == TOK_NUM || t == TOK_CCHAR || t == TOK_STR)
664 c = *str++;
665 printf(" %s", get_tok_str(t, c));
667 printf("\n");
669 #endif
671 /* XXX: should be more factorized */
672 void define_symbol(char *sym)
674 TokenSym *ts;
675 int *str, len;
677 ts = tok_alloc(sym, strlen(sym));
678 str = NULL;
679 len = 0;
680 tok_add2(&str, &len, TOK_NUM, 1);
681 tok_add(&str, &len, 0);
682 sym_push1(&define_stack, ts->tok, MACRO_OBJ, (int)str);
685 void preprocess()
687 int size, i, c, v, t, *str, len;
688 char buf[1024], *q, *p;
689 char buf1[1024];
690 FILE *f;
691 Sym **ps, *first, *s;
693 cinp();
694 next_nomacro();
695 redo:
696 if (tok == TOK_DEFINE) {
697 next_nomacro();
698 v = tok;
699 /* XXX: should check if same macro (ANSI) */
700 first = NULL;
701 t = MACRO_OBJ;
702 /* '(' must be just after macro definition for MACRO_FUNC */
703 if (ch == '(') {
704 next_nomacro();
705 next_nomacro();
706 ps = &first;
707 while (tok != ')') {
708 s = sym_push1(&define_stack, tok | SYM_FIELD, 0, 0);
709 *ps = s;
710 ps = &s->next;
711 next_nomacro();
712 if (tok != ',')
713 break;
714 next_nomacro();
716 t = MACRO_FUNC;
718 str = NULL;
719 len = 0;
720 while (1) {
721 skip_spaces();
722 if (ch == '\n' || ch == -1)
723 break;
724 next_nomacro();
725 tok_add2(&str, &len, tok, tokc);
727 tok_add(&str, &len, 0);
728 #ifdef PP_DEBUG
729 printf("define %s %d: ", get_tok_str(v, 0), t);
730 tok_print(str);
731 #endif
732 s = sym_push1(&define_stack, v, t, (int)str);
733 s->next = first;
734 } else if (tok == TOK_UNDEF) {
735 next_nomacro();
736 s = sym_find1(define_stack, tok);
737 /* undefine symbol by putting an invalid name */
738 if (s)
739 s->v = 0;
740 } else if (tok == TOK_INCLUDE) {
741 skip_spaces();
742 if (ch == '<') {
743 c = '>';
744 goto read_name;
745 } else if (ch == '\"') {
746 c = ch;
747 read_name:
748 minp();
749 q = buf;
750 while (ch != c && ch != '\n' && ch != -1) {
751 if ((q - buf) < sizeof(buf) - 1)
752 *q++ = ch;
753 minp();
755 *q = '\0';
756 if (include_stack_ptr >= include_stack + INCLUDE_STACK_SIZE)
757 error("memory full");
758 if (c == '\"') {
759 /* first search in current dir if "header.h" */
760 /* XXX: buffer overflow */
761 size = 0;
762 p = strrchr(filename, '/');
763 if (p)
764 size = p + 1 - filename;
765 memcpy(buf1, filename, size);
766 buf1[size] = '\0';
767 strcat(buf1, buf);
768 f = fopen(buf1, "r");
769 if (f)
770 goto found;
772 /* now search in standard include path */
773 for(i=nb_include_paths - 1;i>=0;i--) {
774 strcpy(buf1, include_paths[i]);
775 strcat(buf1, "/");
776 strcat(buf1, buf);
777 f = fopen(buf1, "r");
778 if (f)
779 goto found;
781 error("include file not found");
782 f = NULL;
783 found:
784 /* push current file in stack */
785 /* XXX: fix current line init */
786 include_stack_ptr->file = file;
787 include_stack_ptr->filename = filename;
788 include_stack_ptr->line_num = line_num;
789 include_stack_ptr++;
790 file = f;
791 filename = strdup(buf1);
792 line_num = 1;
794 } else if (tok == TOK_IFNDEF) {
795 c = 1;
796 goto do_ifdef;
797 } else if (tok == TOK_IF) {
798 c = expr_preprocess();
799 goto do_if;
800 } else if (tok == TOK_IFDEF) {
801 c = 0;
802 do_ifdef:
803 next_nomacro();
804 c = (sym_find1(define_stack, tok) != 0) ^ c;
805 do_if:
806 if (ifdef_stack_ptr >= ifdef_stack + IFDEF_STACK_SIZE)
807 error("memory full");
808 *ifdef_stack_ptr++ = c;
809 goto test_skip;
810 } else if (tok == TOK_ELSE) {
811 if (ifdef_stack_ptr == ifdef_stack ||
812 (ifdef_stack_ptr[-1] & 2))
813 error("#else after #else");
814 c = (ifdef_stack_ptr[-1] ^= 3);
815 goto test_skip;
816 } else if (tok == TOK_ELIF) {
817 if (ifdef_stack_ptr == ifdef_stack ||
818 ifdef_stack_ptr[-1] > 1)
819 error("#elif after #else");
820 c = expr_preprocess();
821 ifdef_stack_ptr[-1] = c;
822 test_skip:
823 if (!(c & 1)) {
824 preprocess_skip();
825 goto redo;
827 } else if (tok == TOK_ENDIF) {
828 if (ifdef_stack_ptr == ifdef_stack)
829 expect("#if");
830 ifdef_stack_ptr--;
832 /* ignore other preprocess commands or #! for C scripts */
833 while (ch != '\n' && ch != -1)
834 cinp();
837 /* read a number in base b */
838 int getn(b)
840 int n, t;
841 n = 0;
842 while (1) {
843 if (ch >= 'a' & ch <= 'f')
844 t = ch - 'a' + 10;
845 else if (ch >= 'A' & ch <= 'F')
846 t = ch - 'A' + 10;
847 else if (isnum(ch))
848 t = ch - '0';
849 else
850 break;
851 if (t < 0 | t >= b)
852 break;
853 n = n * b + t;
854 cinp();
856 return n;
859 /* read a character for string or char constant and eval escape codes */
860 int getq()
862 int c;
864 c = ch;
865 minp();
866 if (c == '\\') {
867 if (isnum(ch)) {
868 return getn(8);
869 } else {
870 if (ch == 'a')
871 c = '\a';
872 else if (ch == 'b')
873 c = '\b';
874 else if (ch == 'f')
875 c = '\f';
876 else if (ch == 'n')
877 c = '\n';
878 else if (ch == 'r')
879 c = '\r';
880 else if (ch == 't')
881 c = '\t';
882 else if (ch == 'v')
883 c = '\v';
884 else
885 c = ch;
886 minp();
889 return c;
892 /* return next token without macro substitution */
893 void next_nomacro1()
895 int b;
896 char *q;
897 TokenSym *ts;
899 /* skip spaces */
900 while(1) {
901 while (ch == '\n') {
902 cinp();
903 while (ch == ' ' || ch == 9)
904 cinp();
905 if (ch == '#') {
906 /* preprocessor command if # at start of line after
907 spaces */
908 preprocess();
911 if (ch != ' ' && ch != '\t' && ch != '\f')
912 break;
913 cinp();
915 if (isid(ch)) {
916 q = token_buf;
917 while (isid(ch) | isnum(ch)) {
918 if (q >= token_buf + STRING_MAX_SIZE)
919 error("ident too long");
920 *q++ = ch;
921 cinp();
923 *q = '\0';
924 ts = tok_alloc(token_buf, q - token_buf);
925 tok = ts->tok;
926 } else if (isnum(ch)) {
927 /* number */
928 b = 10;
929 if (ch == '0') {
930 cinp();
931 b = 8;
932 if (ch == 'x' || ch == 'X') {
933 cinp();
934 b = 16;
937 tokc = getn(b);
938 /* XXX: add unsigned constant support (ANSI) */
939 while (ch == 'L' || ch == 'l' || ch == 'U' || ch == 'u')
940 cinp();
941 tok = TOK_NUM;
942 } else if (ch == '\'') {
943 minp();
944 tokc = getq();
945 tok = TOK_CCHAR;
946 if (ch != '\'')
947 expect("\'");
948 minp();
949 } else if (ch == '\"') {
950 minp();
951 q = token_buf;
952 while (ch != '\"') {
953 b = getq();
954 if (ch == -1)
955 error("unterminated string");
956 if (q >= token_buf + STRING_MAX_SIZE)
957 error("string too long");
958 *q++ = b;
960 *q = '\0';
961 tokc = (int)tok_alloc(token_buf, q - token_buf);
962 tok = TOK_STR;
963 minp();
964 } else {
965 q = "<=\236>=\235!=\225&&\240||\241++\244--\242==\224<<\1>>\2+=\253-=\255*=\252/=\257%=\245&=\246^=\336|=\374->\247..\250##\266";
966 /* two chars */
967 tok = ch;
968 cinp();
969 while (*q) {
970 if (*q == tok & q[1] == ch) {
971 cinp();
972 tok = q[2] & 0xff;
973 /* three chars tests */
974 if (tok == TOK_SHL | tok == TOK_SAR) {
975 if (ch == '=') {
976 tok = tok | 0x80;
977 cinp();
979 } else if (tok == TOK_DOTS) {
980 if (ch != '.')
981 error("parse error");
982 cinp();
984 return;
986 q = q + 3;
988 /* single char substitutions */
989 if (tok == '<')
990 tok = TOK_LT;
991 else if (tok == '>')
992 tok = TOK_GT;
996 /* return next token without macro substitution. Can read input from
997 macro_ptr buffer */
998 void next_nomacro()
1000 if (macro_ptr) {
1001 tok = *macro_ptr;
1002 if (tok) {
1003 macro_ptr++;
1004 if (tok == TOK_NUM || tok == TOK_CCHAR || tok == TOK_STR)
1005 tokc = *macro_ptr++;
1007 } else {
1008 next_nomacro1();
1012 /* substitute args in macro_str and return allocated string */
1013 int *macro_arg_subst(Sym **nested_list, int *macro_str, Sym *args)
1015 int *st, last_tok, t, c, notfirst, *str, len;
1016 Sym *s;
1017 TokenSym *ts;
1019 str = NULL;
1020 len = 0;
1021 last_tok = 0;
1022 while(1) {
1023 t = *macro_str++;
1024 if (!t)
1025 break;
1026 if (t == '#') {
1027 /* stringize */
1028 t = *macro_str++;
1029 if (!t)
1030 break;
1031 s = sym_find1(args, t);
1032 if (s) {
1033 token_buf[0] = '\0';
1034 st = (int *)s->c;
1035 /* XXX: buffer overflow */
1036 notfirst = 0;
1037 while (*st) {
1038 if (notfirst)
1039 strcat(token_buf, " ");
1040 t = *st++;
1041 c = 0;
1042 if (t == TOK_NUM || t == TOK_CCHAR || t == TOK_STR)
1043 c = *st++;
1044 strcat(token_buf, get_tok_str(t, c));
1045 notfirst = 1;
1047 #ifdef PP_DEBUG
1048 printf("stringize: %s\n", token_buf);
1049 #endif
1050 /* add string */
1051 ts = tok_alloc(token_buf, strlen(token_buf));
1052 tok_add2(&str, &len, TOK_STR, (int)ts);
1053 } else {
1054 tok_add(&str, &len, t);
1056 } else if (t == TOK_NUM || t == TOK_CCHAR || t == TOK_STR) {
1057 tok_add2(&str, &len, t, *macro_ptr++);
1058 } else {
1059 s = sym_find1(args, t);
1060 if (s) {
1061 st = (int *)s->c;
1062 /* if '##' is present before or after , no arg substitution */
1063 if (*macro_str == TOK_TWOSHARPS || last_tok == TOK_TWOSHARPS) {
1064 while (*st)
1065 tok_add(&str, &len, *st++);
1066 } else {
1067 macro_subst(&str, &len, nested_list, st);
1069 } else {
1070 tok_add(&str, &len, t);
1073 last_tok = t;
1075 tok_add(&str, &len, 0);
1076 return str;
1079 /* handle the '##' operator */
1080 int *macro_twosharps(int *macro_str)
1082 TokenSym *ts;
1083 int *macro_str1, macro_str1_len, *macro_ptr1;
1084 int t, c;
1085 char *p;
1087 macro_str1 = NULL;
1088 macro_str1_len = 0;
1089 tok = 0;
1090 while (1) {
1091 next_nomacro();
1092 if (tok == 0)
1093 break;
1094 if (*macro_ptr == TOK_TWOSHARPS) {
1095 macro_ptr++;
1096 macro_ptr1 = macro_ptr;
1097 t = *macro_ptr;
1098 if (t) {
1099 macro_ptr++;
1100 c = 0;
1101 if (t == TOK_NUM || t == TOK_CCHAR || t == TOK_STR)
1102 c = *macro_ptr++;
1103 /* XXX: we handle only most common cases:
1104 ident + ident or ident + number */
1105 if (tok >= TOK_IDENT &&
1106 (t >= TOK_IDENT || t == TOK_NUM)) {
1107 /* XXX: buffer overflow */
1108 p = get_tok_str(tok, tokc);
1109 strcpy(token_buf, p);
1110 p = get_tok_str(t, c);
1111 strcat(token_buf, p);
1112 ts = tok_alloc(token_buf, strlen(token_buf));
1113 tok_add2(&macro_str1, &macro_str1_len, ts->tok, 0);
1114 } else {
1115 /* cannot merge tokens: skip '##' */
1116 macro_ptr = macro_ptr1;
1119 } else {
1120 tok_add2(&macro_str1, &macro_str1_len, tok, tokc);
1123 tok_add(&macro_str1, &macro_str1_len, 0);
1124 return macro_str1;
1129 /* do macro substitution of macro_str and add result to
1130 (tok_str,tok_len). If macro_str is NULL, then input stream token is
1131 substituted. 'nested_list' is the list of all macros we got inside
1132 to avoid recursing. */
1133 void macro_subst(int **tok_str, int *tok_len,
1134 Sym **nested_list, int *macro_str)
1136 Sym *s, *args, *sa;
1137 int *str, parlevel, len, *mstr, t, *saved_macro_ptr;
1138 int mstr_allocated, *macro_str1;
1140 saved_macro_ptr = macro_ptr;
1141 macro_ptr = macro_str;
1142 macro_str1 = NULL;
1143 if (macro_str) {
1144 /* first scan for '##' operator handling */
1145 macro_str1 = macro_twosharps(macro_str);
1146 macro_ptr = macro_str1;
1149 while (1) {
1150 next_nomacro();
1151 if (tok == 0)
1152 break;
1153 /* if symbol is a macro, prepare substitution */
1154 s = sym_find1(define_stack, tok);
1155 if (s) {
1156 /* if nested substitution, do nothing */
1157 if (sym_find1(*nested_list, tok))
1158 goto no_subst;
1159 mstr = (int *)s->c;
1160 mstr_allocated = 0;
1161 if (s->t == MACRO_FUNC) {
1162 /* NOTE: we do not use next_nomacro to avoid eating the
1163 next token. XXX: find better solution */
1164 if (macro_ptr) {
1165 t = *macro_ptr;
1166 } else {
1167 while (ch == ' ' || ch == '\t' || ch == '\n')
1168 cinp();
1169 t = ch;
1171 if (t != '(') /* no macro subst */
1172 goto no_subst;
1174 /* argument macro */
1175 next_nomacro();
1176 next_nomacro();
1177 args = NULL;
1178 sa = s->next;
1179 while (tok != ')' && sa) {
1180 len = 0;
1181 str = NULL;
1182 parlevel = 0;
1183 while ((parlevel > 0 || (tok != ')' && tok != ',')) &&
1184 tok != -1) {
1185 if (tok == '(')
1186 parlevel++;
1187 else if (tok == ')')
1188 parlevel--;
1189 tok_add2(&str, &len, tok, tokc);
1190 next_nomacro();
1192 tok_add(&str, &len, 0);
1193 sym_push1(&args, sa->v & ~SYM_FIELD, 0, (int)str);
1194 if (tok != ',')
1195 break;
1196 next_nomacro();
1197 sa = sa->next;
1199 if (tok != ')')
1200 expect(")");
1201 /* now subst each arg */
1202 mstr = macro_arg_subst(nested_list, mstr, args);
1203 /* free memory */
1204 sa = args;
1205 while (sa) {
1206 free((int *)sa->c);
1207 sa = sa->prev;
1209 sym_pop(&args, NULL);
1210 mstr_allocated = 1;
1212 sym_push1(nested_list, s->v, 0, 0);
1213 macro_subst(tok_str, tok_len, nested_list, mstr);
1214 sym_pop(nested_list, (*nested_list)->prev);
1215 if (mstr_allocated)
1216 free(mstr);
1217 /* only replace one macro while parsing input stream */
1218 if (!macro_str)
1219 return;
1220 } else {
1221 no_subst:
1222 /* no need to add if reading input stream */
1223 if (!macro_str)
1224 return;
1225 tok_add2(tok_str, tok_len, tok, tokc);
1228 macro_ptr = saved_macro_ptr;
1229 if (macro_str1)
1230 free(macro_str1);
1233 /* return next token with macro substitution */
1234 void next()
1236 int len, *ptr;
1237 Sym *nested_list;
1239 /* special 'ungettok' case for label parsing */
1240 if (tok1) {
1241 tok = tok1;
1242 tok1 = 0;
1243 } else {
1244 redo:
1245 if (!macro_ptr) {
1246 /* if not reading from macro substuted string, then try to substitute */
1247 len = 0;
1248 ptr = NULL;
1249 nested_list = NULL;
1250 macro_subst(&ptr, &len, &nested_list, NULL);
1251 if (ptr) {
1252 tok_add(&ptr, &len, 0);
1253 macro_ptr = ptr;
1254 macro_ptr_allocated = ptr;
1255 goto redo;
1257 if (tok == 0)
1258 goto redo;
1259 } else {
1260 next_nomacro();
1261 if (tok == 0) {
1262 /* end of macro string: free it */
1263 free(macro_ptr_allocated);
1264 macro_ptr = NULL;
1265 goto redo;
1269 #ifdef DEBUG
1270 printf("token = %s\n", get_tok_str(tok, tokc));
1271 #endif
1274 void swap(int *p, int *q)
1276 int t;
1277 t = *p;
1278 *p = *q;
1279 *q = t;
1282 void vset(t, v)
1284 vt = t;
1285 vc = v;
1288 /******************************************************/
1289 /* X86 code generator */
1291 void g(c)
1293 *(char *)ind++ = c;
1296 void o(c)
1298 while (c) {
1299 g(c);
1300 c = c / 256;
1304 /* output a symbol and patch all calls to it */
1305 void gsym_addr(t, a)
1307 int n;
1308 while (t) {
1309 n = *(int *)t; /* next value */
1310 *(int *)t = a - t - 4;
1311 t = n;
1315 void gsym(t)
1317 gsym_addr(t, ind);
1320 /* psym is used to put an instruction with a data field which is a
1321 reference to a symbol. It is in fact the same as oad ! */
1322 #define psym oad
1324 /* instruction + 4 bytes data. Return the address of the data */
1325 int oad(c, s)
1327 o(c);
1328 *(int *)ind = s;
1329 s = ind;
1330 ind = ind + 4;
1331 return s;
1334 /* XXX: generate correct pointer for forward references to functions */
1335 /* r = (ft, fc) */
1336 void load(r, ft, fc)
1338 int v, t;
1340 v = ft & VT_VALMASK;
1341 if (ft & VT_LVAL) {
1342 if (v == VT_LLOCAL) {
1343 load(r, VT_LOCAL | VT_LVAL, fc);
1344 v = r;
1346 if ((ft & VT_TYPE) == VT_BYTE)
1347 o(0xbe0f); /* movsbl */
1348 else if ((ft & VT_TYPE) == (VT_BYTE | VT_UNSIGNED))
1349 o(0xb60f); /* movzbl */
1350 else if ((ft & VT_TYPE) == VT_SHORT)
1351 o(0xbf0f); /* movswl */
1352 else if ((ft & VT_TYPE) == (VT_SHORT | VT_UNSIGNED))
1353 o(0xb70f); /* movzwl */
1354 else
1355 o(0x8b); /* movl */
1356 if (v == VT_CONST) {
1357 oad(0x05 + r * 8, fc); /* 0xXX, r */
1358 } else if (v == VT_LOCAL) {
1359 oad(0x85 + r * 8, fc); /* xx(%ebp), r */
1360 } else {
1361 g(0x00 + r * 8 + v); /* (v), r */
1363 } else {
1364 if (v == VT_CONST) {
1365 oad(0xb8 + r, fc); /* mov $xx, r */
1366 } else if (v == VT_LOCAL) {
1367 o(0x8d);
1368 oad(0x85 + r * 8, fc); /* lea xxx(%ebp), r */
1369 } else if (v == VT_CMP) {
1370 oad(0xb8 + r, 0); /* mov $0, r */
1371 o(0x0f); /* setxx %br */
1372 o(fc);
1373 o(0xc0 + r);
1374 } else if (v == VT_JMP || v == VT_JMPI) {
1375 t = v & 1;
1376 oad(0xb8 + r, t); /* mov $1, r */
1377 oad(0xe9, 5); /* jmp after */
1378 gsym(fc);
1379 oad(0xb8 + r, t ^ 1); /* mov $0, r */
1380 } else if (v != r) {
1381 o(0x89);
1382 o(0xc0 + r + v * 8); /* mov v, r */
1387 /* (ft, fc) = r */
1388 /* WARNING: r must not be allocated on the stack */
1389 void store(r, ft, fc)
1391 int fr, b;
1393 fr = ft & VT_VALMASK;
1394 b = (ft & VT_TYPE) == VT_BYTE;
1395 /* XXX: incorrect if reg to reg */
1396 if (ft & VT_SHORT)
1397 o(0x66);
1398 o(0x89 - b);
1399 if (fr == VT_CONST) {
1400 oad(0x05 + r * 8, fc); /* mov r,xxx */
1401 } else if (fr == VT_LOCAL) {
1402 oad(0x85 + r * 8, fc); /* mov r,xxx(%ebp) */
1403 } else if (ft & VT_LVAL) {
1404 g(fr + r * 8); /* mov r, (fr) */
1405 } else if (fr != r) {
1406 o(0xc0 + fr + r * 8); /* mov r, fr */
1410 void gfunc_param(void)
1412 o(0x50 + gv()); /* push r */
1415 int gjmp(t)
1417 return psym(0xe9, t);
1420 /* generate a test. set 'inv' to invert test */
1421 int gtst(inv, t)
1423 int v, *p;
1424 v = vt & VT_VALMASK;
1425 if (v == VT_CMP) {
1426 /* fast case : can jump directly since flags are set */
1427 g(0x0f);
1428 t = psym((vc - 16) ^ inv, t);
1429 } else if (v == VT_JMP || v == VT_JMPI) {
1430 /* && or || optimization */
1431 if ((v & 1) == inv) {
1432 /* insert vc jump list in t */
1433 p = &vc;
1434 while (*p != 0)
1435 p = (int *)*p;
1436 *p = t;
1437 t = vc;
1438 } else {
1439 t = gjmp(t);
1440 gsym(vc);
1442 } else if ((vt & (VT_VALMASK | VT_LVAL)) == VT_CONST) {
1443 /* constant jmp optimization */
1444 if ((vc != 0) != inv)
1445 t = gjmp(t);
1446 } else {
1447 v = gv();
1448 o(0x85);
1449 o(0xc0 + v * 9);
1450 g(0x0f);
1451 t = psym(0x85 ^ inv, t);
1453 return t;
1456 /* generate a binary operation 'v = r op fr' instruction and modifies
1457 (vt,vc) if needed */
1458 void gen_op1(op, r, fr)
1460 int t;
1461 if (op == '+') {
1462 o(0x01);
1463 o(0xc0 + r + fr * 8);
1464 } else if (op == '-') {
1465 o(0x29);
1466 o(0xc0 + r + fr * 8);
1467 } else if (op == '&') {
1468 o(0x21);
1469 o(0xc0 + r + fr * 8);
1470 } else if (op == '^') {
1471 o(0x31);
1472 o(0xc0 + r + fr * 8);
1473 } else if (op == '|') {
1474 o(0x09);
1475 o(0xc0 + r + fr * 8);
1476 } else if (op == '*') {
1477 o(0xaf0f); /* imul fr, r */
1478 o(0xc0 + fr + r * 8);
1479 } else if (op == TOK_SHL | op == TOK_SHR | op == TOK_SAR) {
1480 /* op2 is %ecx */
1481 if (fr != 1) {
1482 if (r == 1) {
1483 r = fr;
1484 fr = 1;
1485 o(0x87); /* xchg r, %ecx */
1486 o(0xc1 + r * 8);
1487 } else
1488 move_reg(1, fr);
1490 o(0xd3); /* shl/shr/sar %cl, r */
1491 if (op == TOK_SHL)
1492 o(0xe0 + r);
1493 else if (op == TOK_SHR)
1494 o(0xe8 + r);
1495 else
1496 o(0xf8 + r);
1497 vt = (vt & VT_TYPE) | r;
1498 } else if (op == '/' | op == TOK_UDIV | op == TOK_PDIV |
1499 op == '%' | op == TOK_UMOD) {
1500 save_reg(2); /* save edx */
1501 t = save_reg_forced(fr); /* save fr and get op2 location */
1502 move_reg(0, r); /* op1 is %eax */
1503 if (op == TOK_UDIV | op == TOK_UMOD) {
1504 o(0xf7d231); /* xor %edx, %edx, div t(%ebp), %eax */
1505 oad(0xb5, t);
1506 } else {
1507 o(0xf799); /* cltd, idiv t(%ebp), %eax */
1508 oad(0xbd, t);
1510 if (op == '%' | op == TOK_UMOD)
1511 r = 2;
1512 else
1513 r = 0;
1514 vt = (vt & VT_TYPE) | r;
1515 } else {
1516 o(0x39);
1517 o(0xc0 + r + fr * 8); /* cmp fr, r */
1518 vset(VT_CMP, op);
1522 /* end of X86 code generator */
1523 /*************************************************************/
1525 int save_reg_forced(int r)
1527 int i, l, *p, t;
1528 /* store register */
1529 loc = (loc - 4) & -3;
1530 store(r, VT_LOCAL, loc);
1531 l = loc;
1533 /* modify all stack values */
1534 for(p=vstack;p<vstack_ptr;p+=2) {
1535 i = p[0] & VT_VALMASK;
1536 if (i == r) {
1537 if (p[0] & VT_LVAL)
1538 t = VT_LLOCAL;
1539 else
1540 t = VT_LOCAL;
1541 p[0] = (p[0] & VT_TYPE) | VT_LVAL | t;
1542 p[1] = l;
1545 return l;
1548 /* save r to memory. and mark it as being free */
1549 void save_reg(r)
1551 int i, *p;
1553 /* modify all stack values */
1554 for(p=vstack;p<vstack_ptr;p+=2) {
1555 i = p[0] & VT_VALMASK;
1556 if (i == r) {
1557 save_reg_forced(r);
1558 break;
1563 /* find a free register. If none, save one register */
1564 int get_reg()
1566 int r, i, *p;
1568 /* find a free register */
1569 for(r=0;r<NB_REGS;r++) {
1570 for(p=vstack;p<vstack_ptr;p+=2) {
1571 i = p[0] & VT_VALMASK;
1572 if (i == r)
1573 goto notfound;
1575 return r;
1576 notfound: ;
1579 /* no register left : free the first one on the stack (very
1580 important to start from the bottom to ensure that we don't
1581 spill registers used in gen_op()) */
1582 for(p=vstack;p<vstack_ptr;p+=2) {
1583 r = p[0] & VT_VALMASK;
1584 if (r < VT_CONST) {
1585 save_reg(r);
1586 break;
1589 return r;
1592 void save_regs()
1594 int r, *p;
1595 for(p=vstack;p<vstack_ptr;p+=2) {
1596 r = p[0] & VT_VALMASK;
1597 if (r < VT_CONST) {
1598 save_reg(r);
1603 /* move register 's' to 'r', and flush previous value of r to memory
1604 if needed */
1605 void move_reg(r, s)
1607 if (r != s) {
1608 save_reg(r);
1609 load(r, s, 0);
1613 /* convert a stack entry in register */
1614 int gvp(int *p)
1616 int r;
1617 r = p[0] & VT_VALMASK;
1618 if (r >= VT_CONST || (p[0] & VT_LVAL))
1619 r = get_reg();
1620 load(r, p[0], p[1]);
1621 p[0] = (p[0] & VT_TYPE) | r;
1622 return r;
1625 void vpush()
1627 if (vstack_ptr >= vstack + VSTACK_SIZE)
1628 error("memory full");
1629 *vstack_ptr++ = vt;
1630 *vstack_ptr++ = vc;
1631 /* cannot let cpu flags if other instruction are generated */
1632 if ((vt & VT_VALMASK) == VT_CMP)
1633 gvp(vstack_ptr - 2);
1636 void vpop(int *ft, int *fc)
1638 *fc = *--vstack_ptr;
1639 *ft = *--vstack_ptr;
1642 /* generate a value in a register from vt and vc */
1643 int gv()
1645 int r;
1646 vpush();
1647 r = gvp(vstack_ptr - 2);
1648 vpop(&vt, &vc);
1649 return r;
1652 /* handle constant optimizations and various machine independant opt */
1653 void gen_opc(op)
1655 int fr, ft, fc, r, c1, c2, n;
1657 vpop(&ft, &fc);
1658 vpop(&vt, &vc);
1659 c1 = (vt & (VT_VALMASK | VT_LVAL)) == VT_CONST;
1660 c2 = (ft & (VT_VALMASK | VT_LVAL)) == VT_CONST;
1661 if (c1 && c2) {
1662 switch(op) {
1663 case '+': vc += fc; break;
1664 case '-': vc -= fc; break;
1665 case '&': vc &= fc; break;
1666 case '^': vc ^= fc; break;
1667 case '|': vc |= fc; break;
1668 case '*': vc *= fc; break;
1669 case TOK_PDIV:
1670 case '/': vc /= fc; break; /* XXX: zero case ? */
1671 case '%': vc %= fc; break; /* XXX: zero case ? */
1672 case TOK_UDIV: vc = (unsigned)vc / fc; break; /* XXX: zero case ? */
1673 case TOK_UMOD: vc = (unsigned)vc % fc; break; /* XXX: zero case ? */
1674 case TOK_SHL: vc <<= fc; break;
1675 case TOK_SHR: vc = (unsigned)vc >> fc; break;
1676 case TOK_SAR: vc >>= fc; break;
1677 /* tests */
1678 case TOK_ULT: vc = (unsigned)vc < (unsigned)fc; break;
1679 case TOK_UGE: vc = (unsigned)vc >= (unsigned)fc; break;
1680 case TOK_EQ: vc = vc == fc; break;
1681 case TOK_NE: vc = vc != fc; break;
1682 case TOK_ULE: vc = (unsigned)vc <= (unsigned)fc; break;
1683 case TOK_UGT: vc = (unsigned)vc > (unsigned)fc; break;
1684 case TOK_LT: vc = vc < fc; break;
1685 case TOK_GE: vc = vc >= fc; break;
1686 case TOK_LE: vc = vc <= fc; break;
1687 case TOK_GT: vc = vc > fc; break;
1688 /* logical */
1689 case TOK_LAND: vc = vc && fc; break;
1690 case TOK_LOR: vc = vc || fc; break;
1691 default:
1692 goto general_case;
1694 } else {
1695 /* if commutative ops, put c2 as constant */
1696 if (c1 && (op == '+' || op == '&' || op == '^' ||
1697 op == '|' || op == '*')) {
1698 swap(&vt, &ft);
1699 swap(&vc, &fc);
1700 swap(&c1, &c2);
1702 if (c2 && (((op == '*' || op == '/' || op == TOK_UDIV ||
1703 op == TOK_PDIV) &&
1704 fc == 1) ||
1705 ((op == '+' || op == '-' || op == '|' || op == '^' ||
1706 op == TOK_SHL || op == TOK_SHR || op == TOK_SAR) &&
1707 fc == 0) ||
1708 (op == '&' &&
1709 fc == -1))) {
1710 } else if (c2 && (op == '*' || op == TOK_PDIV || op == TOK_UDIV)) {
1711 /* try to use shifts instead of muls or divs */
1712 if (fc > 0 && (fc & (fc - 1)) == 0) {
1713 n = -1;
1714 while (fc) {
1715 fc >>= 1;
1716 n++;
1718 fc = n;
1719 if (op == '*')
1720 op = TOK_SHL;
1721 else if (op == TOK_PDIV)
1722 op = TOK_SAR;
1723 else
1724 op = TOK_SHR;
1726 goto general_case;
1727 } else {
1728 general_case:
1729 vpush();
1730 vt = ft;
1731 vc = fc;
1732 vpush();
1733 r = gvp(vstack_ptr - 4);
1734 fr = gvp(vstack_ptr - 2);
1735 vpop(&ft, &fc);
1736 vpop(&vt, &vc);
1737 /* call low level op generator */
1738 gen_op1(op, r, fr);
1743 int pointed_size(int t)
1745 return type_size(pointed_type(t), &t);
1748 /* generic gen_op: handles types problems */
1749 void gen_op(int op)
1751 int u, t1, t2;
1753 vpush();
1754 t1 = vstack_ptr[-4];
1755 t2 = vstack_ptr[-2];
1756 if (op == '+' | op == '-') {
1757 if ((t1 & VT_PTR) && (t2 & VT_PTR)) {
1758 if (op != '-')
1759 error("invalid type");
1760 /* XXX: check that types are compatible */
1761 u = pointed_size(t1);
1762 gen_opc(op);
1763 vpush();
1764 vstack_ptr[-2] &= ~VT_TYPE; /* set to integer */
1765 vset(VT_CONST, u);
1766 gen_op(TOK_PDIV);
1767 } else if ((t1 | t2) & VT_PTR) {
1768 if (t2 & VT_PTR) {
1769 swap(vstack_ptr - 4, vstack_ptr - 2);
1770 swap(vstack_ptr - 3, vstack_ptr - 1);
1771 swap(&t1, &t2);
1773 /* stack-4 contains pointer, stack-2 value to add */
1774 vset(VT_CONST, pointed_size(vstack_ptr[-4]));
1775 gen_op('*');
1776 vpush();
1777 gen_opc(op);
1778 /* put again type if gen_opc() swaped operands */
1779 vt = (vt & VT_TYPEN) | (t1 & VT_TYPE);
1780 } else {
1781 gen_opc(op);
1783 } else {
1784 /* XXX: test types and compute returned value */
1785 if ((t1 | t2) & (VT_UNSIGNED | VT_PTR)) {
1786 if (op == TOK_SAR)
1787 op = TOK_SHR;
1788 else if (op == '/')
1789 op = TOK_UDIV;
1790 else if (op == '%')
1791 op = TOK_UMOD;
1792 else if (op == TOK_LT)
1793 op = TOK_ULT;
1794 else if (op == TOK_GT)
1795 op = TOK_UGT;
1796 else if (op == TOK_LE)
1797 op = TOK_ULE;
1798 else if (op == TOK_GE)
1799 op = TOK_UGE;
1801 gen_opc(op);
1805 /* return type size. Put alignment at 'a' */
1806 int type_size(int t, int *a)
1808 Sym *s;
1810 /* int, enum or pointer */
1811 if (t & VT_STRUCT) {
1812 /* struct/union */
1813 s = sym_find(((unsigned)t >> VT_STRUCT_SHIFT) | SYM_STRUCT);
1814 *a = 4; /* XXX: cannot store it yet. Doing that is safe */
1815 return s->c;
1816 } else if (t & VT_ARRAY) {
1817 s = sym_find(((unsigned)t >> VT_STRUCT_SHIFT));
1818 return type_size(s->t, a) * s->c;
1819 } else if ((t & VT_PTR) |
1820 (t & VT_TYPE) == 0 |
1821 (t & VT_ENUM)) {
1822 *a = 4;
1823 return 4;
1824 } else if (t & VT_SHORT) {
1825 *a = 2;
1826 return 2;
1827 } else {
1828 *a = 1;
1829 return 1;
1833 /* return the pointed type of t */
1834 int pointed_type(int t)
1836 Sym *s;
1837 s = sym_find(((unsigned)t >> VT_STRUCT_SHIFT));
1838 return s->t | (t & VT_TYPEN);
1841 int mk_pointer(int t)
1843 int p;
1844 p = anon_sym++;
1845 sym_push(p, t, -1);
1846 return VT_PTR | (p << VT_STRUCT_SHIFT) | (t & VT_TYPEN);
1849 /* store value in lvalue pushed on stack */
1850 void vstore()
1852 int ft, fc, r, t;
1854 r = gv(); /* generate value */
1855 vpush();
1856 ft = vstack_ptr[-4];
1857 fc = vstack_ptr[-3];
1858 if ((ft & VT_VALMASK) == VT_LLOCAL) {
1859 t = get_reg();
1860 load(t, VT_LOCAL | VT_LVAL, fc);
1861 ft = (ft & ~VT_VALMASK) | t;
1863 store(r, ft, fc);
1864 vstack_ptr -= 4;
1867 /* post defines POST/PRE add. c is the token ++ or -- */
1868 void inc(post, c)
1870 int r, r1;
1871 test_lvalue();
1872 if (post)
1873 vpush(); /* room for returned value */
1874 vpush(); /* save lvalue */
1875 r = gv();
1876 vpush(); /* save value */
1877 if (post) {
1878 /* duplicate value */
1879 r1 = get_reg();
1880 load(r1, r, 0); /* move r to r1 */
1881 vstack_ptr[-6] = (vt & VT_TYPE) | r1;
1882 vstack_ptr[-5] = 0;
1884 /* add constant */
1885 vset(VT_CONST, c - TOK_MID);
1886 gen_op('+');
1887 vstore(); /* store value */
1888 if (post)
1889 vpop(&vt, &vc);
1892 /* enum/struct/union declaration */
1893 int struct_decl(u)
1895 int a, t, b, v, size, align, maxalign, c;
1896 Sym *slast, *s, *ss;
1898 a = tok; /* save decl type */
1899 next();
1900 if (tok != '{') {
1901 v = tok;
1902 next();
1903 /* struct already defined ? return it */
1904 /* XXX: check consistency */
1905 if (s = sym_find(v | SYM_STRUCT)) {
1906 if (s->t != a)
1907 error("invalid type");
1908 goto do_decl;
1910 } else {
1911 v = anon_sym++;
1913 s = sym_push(v | SYM_STRUCT, a, 0);
1914 /* put struct/union/enum name in type */
1915 do_decl:
1916 u = u | (v << VT_STRUCT_SHIFT);
1918 if (tok == '{') {
1919 next();
1920 if (s->c)
1921 error("struct/union/enum already defined");
1922 /* cannot be empty */
1923 c = 0;
1924 maxalign = 0;
1925 slast = NULL;
1926 while (1) {
1927 if (a == TOK_ENUM) {
1928 v = tok;
1929 next();
1930 if (tok == '=') {
1931 next();
1932 c = expr_const();
1934 sym_push(v, VT_CONST, c);
1935 if (tok == ',')
1936 next();
1937 c++;
1938 } else {
1939 b = ist();
1940 while (1) {
1941 t = type_decl(&v, b, TYPE_DIRECT);
1942 if (t & (VT_FUNC | VT_TYPEDEF))
1943 error("invalid type");
1944 /* XXX: align & correct type size */
1945 v |= SYM_FIELD;
1946 size = type_size(t, &align);
1947 if (a == TOK_STRUCT) {
1948 c = (c + align - 1) & -align;
1949 ss = sym_push(v, t, c);
1950 c += size;
1951 } else {
1952 ss = sym_push(v, t, 0);
1953 if (size > c)
1954 c = size;
1956 if (align > maxalign)
1957 maxalign = align;
1958 ss->next = slast;
1959 slast = ss;
1960 if (tok == ';' || tok == -1)
1961 break;
1962 skip(',');
1964 skip(';');
1966 if (tok == '}')
1967 break;
1969 skip('}');
1970 s->next = slast;
1971 /* size for struct/union, dummy for enum */
1972 s->c = (c + maxalign - 1) & -maxalign;
1974 return u;
1977 /* return 0 if no type declaration. otherwise, return the basic type
1978 and skip it.
1979 XXX: A '2' is ored to ensure non zero return if int type.
1981 int ist(void)
1983 int t;
1984 Sym *s;
1986 t = 0;
1987 while(1) {
1988 if (tok == TOK_ENUM) {
1989 t |= struct_decl(VT_ENUM);
1990 } else if (tok == TOK_STRUCT || tok == TOK_UNION) {
1991 t |= struct_decl(VT_STRUCT);
1992 } else {
1993 if (tok == TOK_CHAR) {
1994 t |= VT_BYTE;
1995 } else if (tok == TOK_VOID) {
1996 t |= VT_VOID;
1997 } else if (tok == TOK_SHORT) {
1998 t |= VT_SHORT;
1999 } else if (tok == TOK_INT |
2000 (tok >= TOK_CONST & tok <= TOK_INLINE)) {
2001 /* ignored types */
2002 } else if (tok == TOK_FLOAT || tok == TOK_DOUBLE) {
2003 /* We allow that to compile standard headers */
2004 // warning("floats not supported");
2005 } else if (tok == TOK_EXTERN) {
2006 t |= VT_EXTERN;
2007 } else if (tok == TOK_STATIC) {
2008 t |= VT_STATIC;
2009 } else if (tok == TOK_UNSIGNED) {
2010 t |= VT_UNSIGNED;
2011 } else if (tok == TOK_TYPEDEF) {
2012 t |= VT_TYPEDEF;
2013 } else {
2014 s = sym_find(tok);
2015 if (!s || !(s->t & VT_TYPEDEF))
2016 break;
2017 t |= (s->t & ~VT_TYPEDEF);
2019 next();
2021 t |= 2;
2023 return t;
2026 int post_type(t)
2028 int p, n, pt, l, a;
2029 Sym *last, *s;
2031 if (tok == '(') {
2032 /* function declaration */
2033 next();
2034 a = 4;
2035 l = 0;
2036 last = NULL;
2037 while (tok != ')') {
2038 /* read param name and compute offset */
2039 if (l != FUNC_OLD) {
2040 if (!(pt = ist())) {
2041 if (l) {
2042 error("invalid type");
2043 } else {
2044 l = FUNC_OLD;
2045 goto old_proto;
2048 if (pt & VT_VOID && tok == ')')
2049 break;
2050 l = FUNC_NEW;
2051 pt = type_decl(&n, pt, TYPE_DIRECT | TYPE_ABSTRACT);
2052 } else {
2053 old_proto:
2054 n = tok;
2055 pt = 0; /* int type */
2056 next();
2058 /* array must be transformed to pointer according to ANSI C */
2059 pt &= ~VT_ARRAY;
2060 /* XXX: size will be different someday */
2061 a = a + 4;
2062 s = sym_push(n | SYM_FIELD, VT_LOCAL | VT_LVAL | pt, a);
2063 s->next = last;
2064 last = s;
2065 if (tok == ',') {
2066 next();
2067 if (l == FUNC_NEW && tok == TOK_DOTS) {
2068 l = FUNC_ELLIPSIS;
2069 next();
2070 break;
2074 skip(')');
2075 t = post_type(t);
2076 /* we push a anonymous symbol which will contain the function prototype */
2077 p = anon_sym++;
2078 s = sym_push(p, t, l);
2079 s->next = last;
2080 t = VT_FUNC | (p << VT_STRUCT_SHIFT);
2081 } else if (tok == '[') {
2082 /* array definition */
2083 next();
2084 n = -1;
2085 if (tok != ']') {
2086 n = expr_const();
2087 if (n < 0)
2088 error("invalid array size");
2090 skip(']');
2091 /* parse next post type */
2092 t = post_type(t);
2094 /* we push a anonymous symbol which will contain the array
2095 element type */
2096 p = anon_sym++;
2097 sym_push(p, t, n);
2098 t = VT_ARRAY | VT_PTR | (p << VT_STRUCT_SHIFT);
2100 return t;
2103 /* Read a type declaration (except basic type), and return the
2104 type. If v is true, then also put variable name in 'vc' */
2105 int type_decl(int *v, int t, int td)
2107 int u, p;
2108 Sym *s;
2110 t = t & -3; /* suppress the ored '2' */
2111 while (tok == '*') {
2112 next();
2113 while (tok == TOK_CONST || tok == TOK_VOLATILE)
2114 next();
2115 t = mk_pointer(t);
2118 /* recursive type */
2119 /* XXX: incorrect if abstract type for functions (e.g. 'int ()') */
2120 if (tok == '(') {
2121 next();
2122 u = type_decl(v, 0, td);
2123 skip(')');
2124 } else {
2125 u = 0;
2126 /* type identifier */
2127 if (tok >= TOK_IDENT && (td & TYPE_DIRECT)) {
2128 *v = tok;
2129 next();
2130 } else {
2131 if (!(td & TYPE_ABSTRACT))
2132 expect("identifier");
2133 *v = 0;
2136 /* append t at the end of u */
2137 t = post_type(t);
2138 if (!u)
2139 return t;
2140 p = u;
2141 while(1) {
2142 s = sym_find((unsigned)p >> VT_STRUCT_SHIFT);
2143 p = s->t;
2144 if (!p) {
2145 s->t = t;
2146 break;
2149 return u;
2152 /* define a new external reference to a function 'v' of type 'u' */
2153 Sym *external_func(v, u)
2155 int n;
2156 Sym *s;
2157 s = sym_find(v);
2158 if (!s) {
2159 n = (int)dlsym(0, get_tok_str(v, 0));
2160 if (n == 0) {
2161 /* used to generate symbol list */
2162 s = sym_push1(&global_stack,
2163 v, u | VT_CONST | VT_LVAL | VT_FORWARD, 0);
2164 } else {
2165 /* int f() */
2166 s = sym_push1(&global_stack,
2167 v, u | VT_CONST | VT_LVAL, n);
2170 return s;
2173 void indir()
2175 if (vt & VT_LVAL)
2176 gv();
2177 if (!(vt & VT_PTR))
2178 expect("pointer");
2179 vt = pointed_type(vt);
2180 if (!(vt & VT_ARRAY)) /* an array is never an lvalue */
2181 vt |= VT_LVAL;
2184 void unary()
2186 int n, t, ft, fc, p, r;
2187 Sym *s;
2189 if (tok == TOK_NUM || tok == TOK_CCHAR) {
2190 vset(VT_CONST, tokc);
2191 next();
2192 } else if (tok == TOK_STR) {
2193 TokenSym *ts;
2194 /* generate (char *) type */
2195 vset(VT_CONST | mk_pointer(VT_TYPE), glo);
2196 while (tok == TOK_STR) {
2197 ts = (TokenSym *)tokc;
2198 memcpy((void *)glo, ts->str, ts->len);
2199 glo += ts->len;
2200 next();
2202 *(char *)glo++ = 0;
2203 } else {
2204 t = tok;
2205 next();
2206 if (t == '(') {
2207 /* cast ? */
2208 if (t = ist()) {
2209 ft = type_decl(&n, t, TYPE_ABSTRACT);
2210 skip(')');
2211 unary();
2212 vt = (vt & VT_TYPEN) | ft;
2213 } else {
2214 expr();
2215 skip(')');
2217 } else if (t == '*') {
2218 unary();
2219 indir();
2220 } else if (t == '&') {
2221 unary();
2222 test_lvalue();
2223 vt = mk_pointer(vt & VT_LVALN);
2224 } else
2225 if (t == '!') {
2226 unary();
2227 if ((vt & (VT_CONST | VT_LVAL)) == VT_CONST)
2228 vc = !vc;
2229 else if ((vt & VT_VALMASK) == VT_CMP)
2230 vc = vc ^ 1;
2231 else
2232 vset(VT_JMP, gtst(1, 0));
2233 } else
2234 if (t == '~') {
2235 unary();
2236 vpush();
2237 vset(VT_CONST, -1);
2238 gen_op('^');
2239 } else
2240 if (t == '+') {
2241 unary();
2242 } else
2243 if (t == TOK_SIZEOF) {
2244 /* XXX: some code can be generated */
2245 if (tok == '(') {
2246 next();
2247 if (t = ist())
2248 vt = type_decl(&n, t, TYPE_ABSTRACT);
2249 else
2250 expr();
2251 skip(')');
2252 } else {
2253 unary();
2255 vset(VT_CONST, type_size(vt, &t));
2256 } else
2257 if (t == TOK_INC | t == TOK_DEC) {
2258 unary();
2259 inc(0, t);
2260 } else if (t == '-') {
2261 vset(VT_CONST, 0);
2262 vpush();
2263 unary();
2264 gen_op('-');
2265 } else
2267 s = sym_find(t);
2268 if (!s) {
2269 if (tok != '(')
2270 error("undefined symbol");
2271 /* for simple function calls, we tolerate undeclared
2272 external reference */
2273 p = anon_sym++;
2274 sym_push1(&global_stack, p, 0, FUNC_OLD);
2275 /* int() function */
2276 s = external_func(t, VT_FUNC | (p << VT_STRUCT_SHIFT));
2278 vset(s->t, s->c);
2279 /* if forward reference, we must point to s->c */
2280 if (vt & VT_FORWARD)
2281 vc = (int)&s->c;
2285 /* post operations */
2286 while (1) {
2287 if (tok == TOK_INC | tok == TOK_DEC) {
2288 inc(1, tok);
2289 next();
2290 } else if (tok == '.' | tok == TOK_ARROW) {
2291 /* field */
2292 if (tok == TOK_ARROW)
2293 indir();
2294 test_lvalue();
2295 vt &= VT_LVALN;
2296 next();
2297 /* expect pointer on structure */
2298 if (!(vt & VT_STRUCT))
2299 expect("struct or union");
2300 s = sym_find(((unsigned)vt >> VT_STRUCT_SHIFT) | SYM_STRUCT);
2301 /* find field */
2302 tok |= SYM_FIELD;
2303 while (s = s->next) {
2304 if (s->v == tok)
2305 break;
2307 if (!s)
2308 error("field not found");
2309 /* add field offset to pointer */
2310 vt = vt & VT_TYPEN; /* change type to int */
2311 vpush();
2312 vset(VT_CONST, s->c);
2313 gen_op('+');
2314 /* change type to field type, and set to lvalue */
2315 vt = (vt & VT_TYPEN) | s->t;
2316 /* an array is never an lvalue */
2317 if (!(vt & VT_ARRAY))
2318 vt |= VT_LVAL;
2319 next();
2320 } else if (tok == '[') {
2321 next();
2322 vpush();
2323 expr();
2324 gen_op('+');
2325 indir();
2326 skip(']');
2327 } else if (tok == '(') {
2328 /* function call */
2329 save_regs(); /* save used temporary registers */
2330 /* lvalue is implied */
2331 vt = vt & VT_LVALN;
2332 if ((vt & VT_VALMASK) != VT_CONST) {
2333 /* evaluate function address */
2334 r = gv();
2335 o(0x50 + r); /* push r */
2337 ft = vt;
2338 fc = vc;
2339 next();
2340 #ifdef INVERT_FUNC_PARAMS
2342 int *str, len, parlevel, *saved_macro_ptr;
2343 Sym *args;
2345 /* read each argument and store it on a stack */
2346 /* XXX: merge it with macro args ? */
2347 args = NULL;
2348 while (tok != ')') {
2349 len = 0;
2350 str = NULL;
2351 parlevel = 0;
2352 while ((parlevel > 0 || (tok != ')' && tok != ',')) &&
2353 tok != -1) {
2354 if (tok == '(')
2355 parlevel++;
2356 else if (tok == ')')
2357 parlevel--;
2358 tok_add2(&str, &len, tok, tokc);
2359 next();
2361 tok_add(&str, &len, -1); /* end of file added */
2362 tok_add(&str, &len, 0);
2363 sym_push1(&args, 0, 0, (int)str);
2364 if (tok != ',')
2365 break;
2366 next();
2368 if (tok != ')')
2369 expect(")");
2371 /* now generate code in reverse order by reading the stack */
2372 saved_macro_ptr = macro_ptr;
2373 t = 0;
2374 while (args) {
2375 t += 4;
2376 macro_ptr = (int *)args->c;
2377 next();
2378 expr_eq();
2379 gfunc_param();
2380 free((int *)args->c);
2381 sym_pop(&args, args->prev);
2383 macro_ptr = saved_macro_ptr;
2384 /* restore token */
2385 tok = ')';
2387 #else
2388 t = 0;
2389 while (tok != ')') {
2390 t += 4;
2391 expr_eq();
2392 gfunc_param();
2393 if (tok == ',')
2394 next();
2396 #endif
2397 skip(')');
2398 if ((ft & VT_VALMASK) == VT_CONST) {
2399 /* forward reference */
2400 if (ft & VT_FORWARD) {
2401 *(int *)fc = psym(0xe8, *(int *)fc);
2402 } else
2403 oad(0xe8, fc - ind - 5);
2404 } else {
2405 oad(0x2494ff, t); /* call *xxx(%esp) */
2406 t = t + 4;
2408 if (t)
2409 oad(0xc481, t);
2410 /* get return type */
2411 s = sym_find((unsigned)ft >> VT_STRUCT_SHIFT);
2412 vt = s->t | 0; /* return register is eax */
2413 } else {
2414 break;
2419 void uneq()
2421 int t;
2423 unary();
2424 if (tok == '=' |
2425 (tok >= TOK_A_MOD & tok <= TOK_A_DIV) |
2426 tok == TOK_A_XOR | tok == TOK_A_OR |
2427 tok == TOK_A_SHL | tok == TOK_A_SAR) {
2428 test_lvalue();
2429 vpush();
2430 t = tok;
2431 next();
2432 if (t == '=') {
2433 expr_eq();
2434 /* XXX: be more precise */
2435 if ((vt & VT_PTR) != (vstack_ptr[-2] & VT_PTR))
2436 warning("incompatible type");
2437 } else {
2438 vpush();
2439 expr_eq();
2440 gen_op(t & 0x7f);
2442 vstore();
2446 void sum(l)
2448 int t;
2450 if (l == 0)
2451 uneq();
2452 else {
2453 sum(--l);
2454 while ((l == 0 & (tok == '*' | tok == '/' | tok == '%')) |
2455 (l == 1 & (tok == '+' | tok == '-')) |
2456 (l == 2 & (tok == TOK_SHL | tok == TOK_SAR)) |
2457 (l == 3 & ((tok >= TOK_ULE & tok <= TOK_GT) |
2458 tok == TOK_ULT | tok == TOK_UGE)) |
2459 (l == 4 & (tok == TOK_EQ | tok == TOK_NE)) |
2460 (l == 5 & tok == '&') |
2461 (l == 6 & tok == '^') |
2462 (l == 7 & tok == '|') |
2463 (l == 8 & tok == TOK_LAND) |
2464 (l == 9 & tok == TOK_LOR)) {
2465 vpush();
2466 t = tok;
2467 next();
2468 sum(l);
2469 gen_op(t);
2474 /* only used if non constant */
2475 void eand()
2477 int t;
2479 sum(8);
2480 t = 0;
2481 while (1) {
2482 if (tok != TOK_LAND) {
2483 if (t) {
2484 t = gtst(1, t);
2485 vset(VT_JMPI, t);
2487 break;
2489 t = gtst(1, t);
2490 next();
2491 sum(8);
2495 void eor()
2497 int t;
2499 eand();
2500 t = 0;
2501 while (1) {
2502 if (tok != TOK_LOR) {
2503 if (t) {
2504 t = gtst(0, t);
2505 vset(VT_JMP, t);
2507 break;
2509 t = gtst(0, t);
2510 next();
2511 eand();
2515 /* XXX: better constant handling */
2516 void expr_eq()
2518 int t, u, c, r1, r2;
2520 if (const_wanted) {
2521 sum(10);
2522 if (tok == '?') {
2523 c = vc;
2524 next();
2525 expr();
2526 t = vc;
2527 skip(':');
2528 expr_eq();
2529 if (c)
2530 vc = t;
2532 } else {
2533 eor();
2534 if (tok == '?') {
2535 next();
2536 t = gtst(1, 0);
2537 expr();
2538 r1 = gv();
2539 skip(':');
2540 u = gjmp(0);
2541 gsym(t);
2542 expr_eq();
2543 r2 = gv();
2544 move_reg(r1, r2);
2545 vt = (vt & VT_TYPE) | r1;
2546 gsym(u);
2551 void expr()
2553 while (1) {
2554 expr_eq();
2555 if (tok != ',')
2556 break;
2557 next();
2561 int expr_const()
2563 int a;
2564 a = const_wanted;
2565 const_wanted = 1;
2566 expr_eq();
2567 if ((vt & (VT_CONST | VT_LVAL)) != VT_CONST)
2568 expect("constant");
2569 const_wanted = a;
2570 return vc;
2573 void block(int *bsym, int *csym, int *case_sym, int *def_sym, int case_reg)
2575 int a, b, c, d;
2576 Sym *s;
2578 if (tok == TOK_IF) {
2579 /* if test */
2580 next();
2581 skip('(');
2582 expr();
2583 skip(')');
2584 a = gtst(1, 0);
2585 block(bsym, csym, case_sym, def_sym, case_reg);
2586 c = tok;
2587 if (c == TOK_ELSE) {
2588 next();
2589 d = gjmp(0);
2590 gsym(a);
2591 block(bsym, csym, case_sym, def_sym, case_reg);
2592 gsym(d); /* patch else jmp */
2593 } else
2594 gsym(a);
2595 } else if (tok == TOK_WHILE) {
2596 next();
2597 d = ind;
2598 skip('(');
2599 expr();
2600 skip(')');
2601 a = gtst(1, 0);
2602 b = 0;
2603 block(&a, &b, case_sym, def_sym, case_reg);
2604 oad(0xe9, d - ind - 5); /* jmp */
2605 gsym(a);
2606 gsym_addr(b, d);
2607 } else if (tok == '{') {
2608 next();
2609 /* declarations */
2610 s = local_stack;
2611 decl(VT_LOCAL);
2612 while (tok != '}')
2613 block(bsym, csym, case_sym, def_sym, case_reg);
2614 /* pop locally defined symbols */
2615 sym_pop(&local_stack, s);
2616 next();
2617 } else if (tok == TOK_RETURN) {
2618 next();
2619 if (tok != ';') {
2620 expr();
2621 move_reg(0, gv());
2623 skip(';');
2624 rsym = gjmp(rsym); /* jmp */
2625 } else if (tok == TOK_BREAK) {
2626 /* compute jump */
2627 if (!bsym)
2628 error("cannot break");
2629 *bsym = gjmp(*bsym);
2630 next();
2631 skip(';');
2632 } else if (tok == TOK_CONTINUE) {
2633 /* compute jump */
2634 if (!csym)
2635 error("cannot continue");
2636 *csym = gjmp(*csym);
2637 next();
2638 skip(';');
2639 } else if (tok == TOK_FOR) {
2640 int e;
2641 next();
2642 skip('(');
2643 if (tok != ';')
2644 expr();
2645 skip(';');
2646 d = ind;
2647 c = ind;
2648 a = 0;
2649 b = 0;
2650 if (tok != ';') {
2651 expr();
2652 a = gtst(1, 0);
2654 skip(';');
2655 if (tok != ')') {
2656 e = gjmp(0);
2657 c = ind;
2658 expr();
2659 oad(0xe9, d - ind - 5); /* jmp */
2660 gsym(e);
2662 skip(')');
2663 block(&a, &b, case_sym, def_sym, case_reg);
2664 oad(0xe9, c - ind - 5); /* jmp */
2665 gsym(a);
2666 gsym_addr(b, c);
2667 } else
2668 if (tok == TOK_DO) {
2669 next();
2670 a = 0;
2671 b = 0;
2672 d = ind;
2673 block(&a, &b, case_sym, def_sym, case_reg);
2674 skip(TOK_WHILE);
2675 skip('(');
2676 gsym(b);
2677 expr();
2678 c = gtst(0, 0);
2679 gsym_addr(c, d);
2680 skip(')');
2681 gsym(a);
2682 } else
2683 if (tok == TOK_SWITCH) {
2684 next();
2685 skip('(');
2686 expr();
2687 case_reg = gv();
2688 skip(')');
2689 a = 0;
2690 b = 0;
2691 c = 0;
2692 block(&a, csym, &b, &c, case_reg);
2693 /* if no default, jmp after switch */
2694 if (c == 0)
2695 c = ind;
2696 /* default label */
2697 gsym_addr(b, c);
2698 /* break label */
2699 gsym(a);
2700 } else
2701 if (tok == TOK_CASE) {
2702 next();
2703 a = expr_const();
2704 if (!case_sym)
2705 expect("switch");
2706 gsym(*case_sym);
2707 vset(case_reg, 0);
2708 vpush();
2709 vset(VT_CONST, a);
2710 gen_op(TOK_EQ);
2711 *case_sym = gtst(1, 0);
2712 skip(':');
2713 block(bsym, csym, case_sym, def_sym, case_reg);
2714 } else
2715 if (tok == TOK_DEFAULT) {
2716 next();
2717 skip(':');
2718 if (!def_sym)
2719 expect("switch");
2720 if (*def_sym)
2721 error("too many 'default'");
2722 *def_sym = ind;
2723 block(bsym, csym, case_sym, def_sym, case_reg);
2724 } else
2725 if (tok == TOK_GOTO) {
2726 next();
2727 s = sym_find1(label_stack, tok);
2728 /* put forward definition if needed */
2729 if (!s)
2730 s = sym_push1(&label_stack, tok, VT_FORWARD, 0);
2731 /* label already defined */
2732 if (s->t & VT_FORWARD)
2733 s->c = gjmp(s->c); /* jmp xxx */
2734 else
2735 oad(0xe9, s->c - ind - 5); /* jmp xxx */
2736 next();
2737 skip(';');
2738 } else {
2739 b = tok;
2740 next();
2741 if (tok == ':') {
2742 next();
2743 /* label case */
2744 s = sym_find1(label_stack, b);
2745 if (s) {
2746 if (!(s->t & VT_FORWARD))
2747 error("multiple defined label");
2748 gsym(s->c);
2749 s->c = ind;
2750 s->t = 0;
2751 } else {
2752 sym_push1(&label_stack, b, 0, ind);
2754 block(bsym, csym, case_sym, def_sym, case_reg);
2755 } else {
2756 /* expression case: go backward of one token */
2757 /* XXX: currently incorrect if number/string/char */
2758 tok1 = tok;
2759 tok = b;
2760 if (tok != ';') {
2761 expr();
2763 skip(';');
2768 /* 'l' is VT_LOCAL or VT_CONST to define default storage type */
2769 void decl(l)
2771 int *a, t, b, size, align, v, u, n;
2772 Sym *sym;
2774 while (b = ist()) {
2775 if ((b & (VT_ENUM | VT_STRUCT)) && tok == ';') {
2776 /* we accept no variable after */
2777 next();
2778 continue;
2780 while (1) { /* iterate thru each declaration */
2781 t = type_decl(&v, b, TYPE_DIRECT);
2782 if (tok == '{') {
2783 if (!(t & VT_FUNC))
2784 expect("function defintion");
2785 /* patch forward references */
2786 if ((sym = sym_find(v)) && (sym->t & VT_FORWARD)) {
2787 gsym(sym->c);
2788 sym->c = ind;
2789 sym->t = VT_CONST | VT_LVAL | t;
2790 } else {
2791 /* put function address */
2792 sym_push1(&global_stack, v, VT_CONST | VT_LVAL | t, ind);
2794 /* push a dummy symbol to enable local sym storage */
2795 sym_push1(&local_stack, 0, 0, 0);
2796 /* define parameters */
2797 sym = sym_find((unsigned)t >> VT_STRUCT_SHIFT);
2798 while (sym = sym->next)
2799 sym_push(sym->v & ~SYM_FIELD, sym->t, sym->c);
2800 loc = 0;
2801 o(0xe58955); /* push %ebp, mov %esp, %ebp */
2802 a = (int *)oad(0xec81, 0); /* sub $xxx, %esp */
2803 rsym = 0;
2804 block(0, 0, 0, 0, 0);
2805 gsym(rsym);
2806 o(0xc3c9); /* leave, ret */
2807 *a = (-loc + 3) & -4; /* align local size to word &
2808 save local variables */
2809 sym_pop(&label_stack, 0); /* reset label stack */
2810 sym_pop(&local_stack, 0); /* reset local stack */
2811 break;
2812 } else {
2813 if (b & VT_TYPEDEF) {
2814 /* save typedefed type */
2815 sym_push(v, t | VT_TYPEDEF, 0);
2816 } else if (t & VT_FUNC) {
2817 /* XXX: incorrect to flush, but needed while
2818 waiting for function prototypes */
2819 /* external function definition */
2820 external_func(v, t);
2821 } else {
2822 /* not lvalue if array */
2823 if (!(t & VT_ARRAY))
2824 t |= VT_LVAL;
2825 if (b & VT_EXTERN) {
2826 /* external variable */
2827 /* XXX: factorize with external function def */
2828 n = (int)dlsym(NULL, get_tok_str(v, 0));
2829 if (!n)
2830 error("unknown external variable");
2831 sym_push(v, VT_CONST | t, n);
2832 } else {
2833 u = l;
2834 if (t & VT_STATIC)
2835 u = VT_CONST;
2836 u |= t;
2837 size = type_size(t, &align);
2838 if (size < 0)
2839 error("invalid size");
2840 if ((u & VT_VALMASK) == VT_LOCAL) {
2841 /* allocate space down on the stack */
2842 loc = (loc - size) & -align;
2843 sym_push(v, u, loc);
2844 } else {
2845 /* allocate space up in the data space */
2846 glo = (glo + align - 1) & -align;
2847 sym_push(v, u, glo);
2848 glo += size;
2852 if (tok != ',') {
2853 skip(';');
2854 break;
2856 next();
2862 /* open a dynamic library so that its symbol are available for
2863 compiled programs */
2864 void open_dll(char *libname)
2866 char buf[1024];
2867 void *h;
2869 snprintf(buf, sizeof(buf), "lib%s.so", libname);
2870 h = dlopen(buf, RTLD_GLOBAL | RTLD_LAZY);
2871 if (!h)
2872 error((char *)dlerror());
2875 int main(int argc, char **argv)
2877 Sym *s;
2878 int (*t)();
2879 char *p, *r;
2880 int optind;
2882 include_paths[0] = "/usr/include";
2883 include_paths[1] = "/usr/lib/tcc";
2884 include_paths[2] = "/usr/local/lib/tcc";
2885 nb_include_paths = 3;
2887 /* add all tokens */
2888 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\0float\0double\0short\0struct\0union\0typedef\0default\0enum\0sizeof\0define\0include\0ifdef\0ifndef\0elif\0endif\0defined\0undef\0main\0";
2889 while (*p) {
2890 r = p;
2891 while (*r++);
2892 tok_alloc(p, r - p - 1);
2893 p = r;
2896 /* standard defines */
2897 define_symbol("__STDC__");
2898 #ifdef __i386__
2899 define_symbol("__i386__");
2900 #endif
2902 optind = 1;
2903 while (1) {
2904 if (optind >= argc) {
2905 printf("tcc version 0.9 - Tiny C Compiler - Copyright (C) 2001 Fabrice Bellard\n"
2906 "usage: tcc [-Idir] [-Dsym] [-llib] infile [infile_arg...]\n");
2907 return 1;
2909 r = argv[optind];
2910 if (r[0] != '-')
2911 break;
2912 if (r[1] == 'I') {
2913 if (nb_include_paths >= INCLUDE_PATHS_MAX)
2914 error("too many include paths");
2915 include_paths[nb_include_paths++] = r + 2;
2916 } else if (r[1] == 'D') {
2917 define_symbol(r + 2);
2918 } else if (r[1] == 'l') {
2919 open_dll(r + 2);
2920 } else {
2921 fprintf(stderr, "invalid option -- '%s'\n", r);
2922 exit(1);
2924 optind++;
2927 filename = argv[optind];
2928 line_num = 1;
2929 file = fopen(filename, "r");
2930 if (!file) {
2931 perror(filename);
2932 exit(1);
2934 include_stack_ptr = include_stack;
2935 ifdef_stack_ptr = ifdef_stack;
2937 glo = (int)malloc(DATA_SIZE);
2938 memset((void *)glo, 0, DATA_SIZE);
2939 prog = (int)malloc(TEXT_SIZE);
2940 vstack_ptr = vstack;
2941 anon_sym = 1 << (31 - VT_STRUCT_SHIFT);
2942 ind = prog;
2943 inp();
2944 ch = '\n'; /* needed to parse correctly first preprocessor command */
2945 next();
2946 decl(VT_CONST);
2947 if (tok != -1)
2948 expect("declaration");
2949 #ifdef TEST
2951 FILE *f;
2952 f = fopen(argv[optind + 1], "w");
2953 fwrite((void *)prog, 1, ind - prog, f);
2954 fclose(f);
2955 return 0;
2957 #else
2958 s = sym_find(TOK_MAIN);
2959 if (!s)
2960 error("main() not defined");
2961 t = (int (*)())s->c;
2962 #ifdef PROFILE
2963 return 1;
2964 #else
2965 return (*t)(argc - optind, argv + optind);
2966 #endif
2967 #endif