added std libs
[tinycc.git] / tcc.c
blob6e03422aabd1e8ab1fa933f03bce16743f85fe92
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 #define TEXT_SIZE 50000
27 #define DATA_SIZE 50000
28 #define INCLUDE_STACK_SIZE 32
29 #define IFDEF_STACK_SIZE 64
30 #define VSTACK_SIZE 64
31 #define STRING_MAX_SIZE 1024
32 #define INCLUDE_PATHS_MAX 32
34 #define NB_REGS 3
36 /* token symbol management */
37 typedef struct TokenSym {
38 struct TokenSym *next;
39 int tok; /* token number */
40 int len;
41 char str[1];
42 } TokenSym;
44 /* symbol management */
45 typedef struct Sym {
46 int v; /* symbol token */
47 int t; /* associated type */
48 int c; /* associated number */
49 struct Sym *next; /* next related symbol */
50 struct Sym *prev; /* prev symbol in stack */
51 } Sym;
53 #define SYM_STRUCT 0x40000000 /* struct/union/enum symbol space */
54 #define SYM_FIELD 0x20000000 /* struct/union field symbol space */
56 #define FUNC_NEW 1 /* ansi function prototype */
57 #define FUNC_OLD 2 /* old function prototype */
58 #define FUNC_ELLIPSIS 3 /* ansi function prototype with ... */
60 /* field t for macros */
61 #define MACRO_OBJ 0 /* object like macro */
62 #define MACRO_FUNC 1 /* function like macro */
64 typedef struct {
65 FILE *file;
66 char *filename;
67 int line_num;
68 } IncludeFile;
70 /* loc : local variable index
71 glo : global variable index
72 ind : output code ptr
73 rsym: return symbol
74 prog: output code
75 anon_sym: anonymous symbol index
77 FILE *file;
78 int tok, tok1, tokc, rsym, anon_sym,
79 prog, ind, loc, glo, vt, vc, const_wanted, line_num;
80 TokenSym *first_ident;
81 char token_buf[STRING_MAX_SIZE + 1];
82 char *filename;
83 Sym *define_stack, *global_stack, *local_stack, *label_stack;
85 int vstack[VSTACK_SIZE], *vstack_ptr;
86 int *macro_ptr, *macro_ptr_allocated;
87 IncludeFile include_stack[INCLUDE_STACK_SIZE], *include_stack_ptr;
88 int ifdef_stack[IFDEF_STACK_SIZE], *ifdef_stack_ptr;
89 char *include_paths[INCLUDE_PATHS_MAX];
90 int nb_include_paths;
92 /* The current value can be: */
93 #define VT_VALMASK 0x000f
94 #define VT_CONST 0x000a /* constant in vc
95 (must be first non register value) */
96 #define VT_LLOCAL 0x000b /* lvalue, offset on stack */
97 #define VT_LOCAL 0x000c /* offset on stack */
98 #define VT_CMP 0x000d /* the value is stored in processor flags (in vc) */
99 #define VT_JMP 0x000e /* value is the consequence of jmp true */
100 #define VT_JMPI 0x000f /* value is the consequence of jmp false */
101 #define VT_LVAL 0x0010 /* var is an lvalue */
102 #define VT_LVALN -17 /* ~VT_LVAL */
103 #define VT_FORWARD 0x0020 /* value is forward reference
104 (only used for functions) */
106 #define VT_VOID 0x00040
107 #define VT_BYTE 0x00080 /* byte type */
108 #define VT_PTR 0x00100 /* pointer increment */
109 #define VT_UNSIGNED 0x00200 /* unsigned type */
110 #define VT_ARRAY 0x00400 /* array type (only used in parsing) */
111 #define VT_ENUM 0x00800 /* enum definition */
112 #define VT_FUNC 0x01000 /* function type */
113 #define VT_STRUCT 0x002000 /* struct/union definition */
114 #define VT_TYPEDEF 0x004000 /* typedef definition */
115 #define VT_EXTERN 0x008000 /* extern definition */
116 #define VT_STATIC 0x010000 /* static variable */
117 #define VT_STRUCT_SHIFT 17 /* structure/enum name shift (12 bits lefts) */
119 #define VT_TYPE 0xffffffc0 /* type mask */
120 #define VT_TYPEN 0x0000003f /* ~VT_TYPE */
121 #define VT_FUNCN -4097 /* ~VT_FUNC */
124 /* Special infos */
126 /* token values */
128 /* warning: the following compare tokens depend on i386 asm code */
129 #define TOK_ULT 0x92
130 #define TOK_UGE 0x93
131 #define TOK_EQ 0x94
132 #define TOK_NE 0x95
133 #define TOK_ULE 0x96
134 #define TOK_UGT 0x97
135 #define TOK_LT 0x9c
136 #define TOK_GE 0x9d
137 #define TOK_LE 0x9e
138 #define TOK_GT 0x9f
140 #define TOK_LAND 0xa0
141 #define TOK_LOR 0xa1
143 #define TOK_DEC 0xa2
144 #define TOK_MID 0xa3 /* inc/dec, to void constant */
145 #define TOK_INC 0xa4
146 #define TOK_ARROW 0xa7
147 #define TOK_DOTS 0xa8 /* three dots */
148 #define TOK_SHR 0xa9 /* unsigned shift right */
149 #define TOK_UDIV 0xb0 /* unsigned division */
150 #define TOK_UMOD 0xb1 /* unsigned modulo */
151 #define TOK_PDIV 0xb2 /* fast division with undefined rounding for pointers */
152 #define TOK_NUM 0xb3 /* number in tokc */
153 #define TOK_CCHAR 0xb4 /* char constant in tokc */
154 #define TOK_STR 0xb5 /* pointer to string in tokc */
156 #define TOK_TWOSHARPS 0xb6 /* ## preprocessing token */
158 #define TOK_SHL 0x01 /* shift left */
159 #define TOK_SAR 0x02 /* signed shift right */
161 /* assignement operators : normal operator or 0x80 */
162 #define TOK_A_MOD 0xa5
163 #define TOK_A_AND 0xa6
164 #define TOK_A_MUL 0xaa
165 #define TOK_A_ADD 0xab
166 #define TOK_A_SUB 0xad
167 #define TOK_A_DIV 0xaf
168 #define TOK_A_XOR 0xde
169 #define TOK_A_OR 0xfc
170 #define TOK_A_SHL 0x81
171 #define TOK_A_SAR 0x82
173 /* all identificators and strings have token above that */
174 #define TOK_IDENT 256
176 enum {
177 TOK_INT = TOK_IDENT,
178 TOK_VOID,
179 TOK_CHAR,
180 TOK_IF,
181 TOK_ELSE,
182 TOK_WHILE,
183 TOK_BREAK,
184 TOK_RETURN,
185 TOK_FOR,
186 TOK_EXTERN,
187 TOK_STATIC,
188 TOK_UNSIGNED,
189 TOK_GOTO,
190 TOK_DO,
191 TOK_CONTINUE,
192 TOK_SWITCH,
193 TOK_CASE,
195 /* ignored types Must have contiguous values */
196 TOK_CONST,
197 TOK_VOLATILE,
198 TOK_LONG,
199 TOK_REGISTER,
200 TOK_SIGNED,
201 TOK_AUTO,
202 TOK_INLINE,
204 /* unsupported type */
205 TOK_FLOAT,
206 TOK_DOUBLE,
208 TOK_SHORT,
209 TOK_STRUCT,
210 TOK_UNION,
211 TOK_TYPEDEF,
212 TOK_DEFAULT,
213 TOK_ENUM,
214 TOK_SIZEOF,
216 /* preprocessor only */
217 TOK_DEFINE,
218 TOK_INCLUDE,
219 TOK_IFDEF,
220 TOK_IFNDEF,
221 TOK_ELIF,
222 TOK_ENDIF,
223 TOK_DEFINED,
224 TOK_UNDEF,
226 /* special identifiers */
227 TOK_MAIN,
230 void sum();
231 void next();
232 void next_nomacro();
233 int expr_const();
234 void expr_eq();
235 void expr();
236 void decl();
237 int gv();
238 void move_reg();
239 void save_reg();
240 void macro_subst(int **tok_str, int *tok_len,
241 Sym **nested_list, int *macro_str);
242 int save_reg_forced(int r);
243 int type_size(int t, int *a);
244 int pointed_type(int t);
245 int pointed_size(int t);
246 int ist(void);
247 int typ(int *v, int t);
249 int isid(c)
251 return (c >= 'a' & c <= 'z') |
252 (c >= 'A' & c <= 'Z') |
253 c == '_';
256 int isnum(c)
258 return c >= '0' & c <= '9';
261 void printline()
263 IncludeFile *f;
264 for(f = include_stack; f < include_stack_ptr; f++)
265 printf("In file included from %s:%d:\n", f->filename, f->line_num);
266 printf("%s:%d: ", filename, line_num);
269 /* XXX: use stderr ? */
270 void error(char *msg)
272 printline();
273 printf("%s\n", msg);
274 exit(1);
277 void expect(char *msg)
279 printline();
280 printf("%s expected\n", msg);
281 exit(1);
284 void warning(char *msg)
286 printline();
287 printf("warning: %s\n", msg);
290 void skip(c)
292 if (tok != c) {
293 printline();
294 printf("'%c' expected\n", c);
295 exit(1);
297 next();
300 void test_lvalue()
302 if (!(vt & VT_LVAL))
303 expect("lvalue");
306 TokenSym *tok_alloc(char *str, int len)
308 TokenSym *ts, **pts;
309 int t;
311 t = TOK_IDENT;
312 pts = &first_ident;
313 while (1) {
314 ts = *pts;
315 if (!ts)
316 break;
317 if (ts->len == len && !memcmp(ts->str, str, len))
318 return ts;
319 t++;
320 pts = &(ts->next);
322 ts = malloc(sizeof(TokenSym) + len);
323 if (!ts)
324 error("memory full");
325 ts->tok = t;
326 ts->len = len;
327 ts->next = NULL;
328 memcpy(ts->str, str, len + 1);
330 *pts = ts;
331 return ts;
334 void add_char(char **pp, int c)
336 char *p;
337 p = *pp;
338 if (c == '\'' || c == '\"' || c == '\\') {
339 /* XXX: could be more precise if char or string */
340 *p++ = '\\';
342 if (c >= 32 && c <= 126) {
343 *p++ = c;
344 } else {
345 *p++ = '\\';
346 if (c == '\n') {
347 *p++ = 'n';
348 } else {
349 *p++ = '0' + ((c >> 6) & 7);
350 *p++ = '0' + ((c >> 3) & 7);
351 *p++ = '0' + (c & 7);
354 *pp = p;
357 /* XXX: buffer overflow */
358 char *get_tok_str(int v, int c)
360 static char buf[STRING_MAX_SIZE + 1];
361 TokenSym *ts;
362 char *p;
363 int i;
365 if (v == TOK_NUM) {
366 sprintf(buf, "%d", c);
367 return buf;
368 } else if (v == TOK_CCHAR) {
369 p = buf;
370 *p++ = '\'';
371 add_char(&p, c);
372 *p++ = '\'';
373 *p = '\0';
374 return buf;
375 } else if (v == TOK_STR) {
376 ts = (TokenSym *)c;
377 p = buf;
378 *p++ = '\"';
379 for(i=0;i<ts->len;i++)
380 add_char(&p, ts->str[i]);
381 *p++ = '\"';
382 *p = '\0';
383 return buf;
384 } else if (v < TOK_IDENT) {
385 p = buf;
386 *p++ = v;
387 *p = '\0';
388 return buf;
389 } else {
390 ts = first_ident;
391 while (ts != NULL) {
392 if (ts->tok == v)
393 return ts->str;
394 ts = ts->next;
396 return NULL;
400 /* find a symbol and return its associated structure. 's' is the top
401 of the symbol stack */
402 Sym *sym_find1(Sym *s, int v)
404 while (s) {
405 if (s->v == v)
406 return s;
407 s = s->prev;
409 return 0;
412 Sym *sym_push1(Sym **ps, int v, int t, int c)
414 Sym *s;
415 s = malloc(sizeof(Sym));
416 if (!s)
417 error("memory full");
418 s->v = v;
419 s->t = t;
420 s->c = c;
421 s->next = NULL;
422 s->prev = *ps;
423 *ps = s;
424 return s;
427 /* find a symbol in the right symbol space */
428 Sym *sym_find(int v)
430 Sym *s;
431 s = sym_find1(local_stack, v);
432 if (!s)
433 s = sym_find1(global_stack, v);
434 return s;
437 /* push a given symbol on the symbol stack */
438 Sym *sym_push(int v, int t, int c)
440 if (local_stack)
441 return sym_push1(&local_stack, v, t, c);
442 else
443 return sym_push1(&global_stack, v, t, c);
446 /* pop symbols until top reaches 'b' */
447 void sym_pop(Sym **ps, Sym *b)
449 Sym *s, *ss;
451 s = *ps;
452 while(s != b) {
453 ss = s->prev;
454 free(s);
455 s = ss;
457 *ps = b;
460 int ch, ch1;
462 /* read next char from current input file */
463 void inp()
465 redo:
466 ch1 = fgetc(file);
467 if (ch1 == -1) {
468 if (include_stack_ptr == include_stack)
469 return;
470 /* pop include stack */
471 fclose(file);
472 free(filename);
473 include_stack_ptr--;
474 file = include_stack_ptr->file;
475 filename = include_stack_ptr->filename;
476 line_num = include_stack_ptr->line_num;
477 goto redo;
479 if (ch1 == '\n')
480 line_num++;
481 // printf("ch1=%c 0x%x\n", ch1, ch1);
484 /* input with '\\n' handling */
485 void minp()
487 redo:
488 ch = ch1;
489 inp();
490 if (ch == '\\' && ch1 == '\n') {
491 inp();
492 goto redo;
494 //printf("ch=%c 0x%x\n", ch, ch);
497 /* same as minp, but also skip comments */
498 /* XXX: skip strings & chars */
499 void cinp()
501 int c;
503 if (ch1 == '/') {
504 inp();
505 if (ch1 == '/') {
506 /* single line C++ comments */
507 inp();
508 while (ch1 != '\n' && ch1 != -1)
509 inp();
510 inp();
511 ch = ' '; /* return space */
512 } else if (ch1 == '*') {
513 /* C comments */
514 inp();
515 while (ch1 != -1) {
516 c = ch1;
517 inp();
518 if (c == '*' && ch1 == '/') {
519 inp();
520 ch = ' '; /* return space */
521 break;
524 } else {
525 ch = '/';
527 } else {
528 minp();
532 void skip_spaces()
534 while (ch == ' ' || ch == '\t')
535 cinp();
538 /* skip block of text until #else, #elif or #endif. skip also pairs of
539 #if/#endif */
540 void preprocess_skip()
542 int a;
543 a = 0;
544 while (1) {
545 while (ch != '\n') {
546 if (ch == -1)
547 expect("#endif");
548 cinp();
550 cinp();
551 skip_spaces();
552 if (ch == '#') {
553 cinp();
554 next_nomacro();
555 if (a == 0 &&
556 (tok == TOK_ELSE || tok == TOK_ELIF || tok == TOK_ENDIF))
557 break;
558 if (tok == TOK_IF || tok == TOK_IFDEF || tok == TOK_IFNDEF)
559 a++;
560 else if (tok == TOK_ENDIF)
561 a--;
566 /* parse until eol and add given char */
567 char *get_str(c)
569 char *str;
570 int size, n;
572 str = NULL;
573 size = 0;
574 n = 0;
575 while (1) {
576 if ((n + 1) >= size) {
577 size += 128;
578 str = realloc(str, size);
579 if (!str)
580 error("memory full");
582 if (ch == -1 || ch == '\n') {
583 str[n++] = c;
584 str[n++] = '\0';
585 break;
587 str[n++] = ch;
588 cinp();
590 return str;
593 void tok_add(int **tok_str, int *tok_len, int t)
595 int len, *str;
596 len = *tok_len;
597 str = *tok_str;
598 if ((len & 63) == 0) {
599 str = realloc(str, (len + 64) * sizeof(int));
600 if (!str)
601 return;
602 *tok_str = str;
604 str[len++] = t;
605 *tok_len = len;
608 void tok_add2(int **tok_str, int *tok_len, int t, int c)
610 tok_add(tok_str, tok_len, t);
611 if (t == TOK_NUM || t == TOK_CCHAR || t == TOK_STR)
612 tok_add(tok_str, tok_len, c);
615 /* eval an expression for #if/#elif */
616 int expr_preprocess()
618 int *str, len, c, t;
619 int *saved_macro_ptr;
621 str = NULL;
622 len = 0;
623 while (1) {
624 skip_spaces();
625 if (ch == '\n')
626 break;
627 next(); /* do macro subst */
628 if (tok == TOK_DEFINED) {
629 next_nomacro();
630 t = tok;
631 if (t == '(')
632 next_nomacro();
633 c = sym_find1(define_stack, tok) != 0;
634 if (t == '(')
635 next_nomacro();
636 tok = TOK_NUM;
637 tokc = c;
638 } else if (tok >= TOK_IDENT) {
639 /* if undefined macro */
640 tok = TOK_NUM;
641 tokc = 0;
643 tok_add2(&str, &len, tok, tokc);
645 tok_add(&str, &len, -1); /* simulate end of file */
646 tok_add(&str, &len, 0);
647 /* now evaluate C constant expression */
648 saved_macro_ptr = macro_ptr;
649 macro_ptr = str;
650 next();
651 c = expr_const();
652 macro_ptr = saved_macro_ptr;
653 free(str);
654 return c != 0;
657 #ifdef DEBUG
658 void tok_print(int *str)
660 int t, c;
662 while (1) {
663 t = *str++;
664 if (!t)
665 break;
666 c = 0;
667 if (t == TOK_NUM || t == TOK_CCHAR || t == TOK_STR)
668 c = *str++;
669 printf(" %s", get_tok_str(t, c));
671 printf("\n");
673 #endif
675 void preprocess()
677 int size, i, c, v, t, *str, len;
678 char buf[1024], *q, *p;
679 char buf1[1024];
680 FILE *f;
681 Sym **ps, *first, *s;
683 cinp();
684 next_nomacro();
685 redo:
686 if (tok == TOK_DEFINE) {
687 next_nomacro();
688 v = tok;
689 /* XXX: should check if same macro (ANSI) */
690 if (sym_find1(define_stack, v))
691 warning("macro redefinition");
692 first = NULL;
693 t = MACRO_OBJ;
694 /* '(' must be just after macro definition for MACRO_FUNC */
695 if (ch == '(') {
696 next_nomacro();
697 next_nomacro();
698 ps = &first;
699 while (tok != ')') {
700 s = sym_push1(&define_stack, tok | SYM_FIELD, 0, 0);
701 *ps = s;
702 ps = &s->next;
703 next_nomacro();
704 if (tok != ',')
705 break;
706 next_nomacro();
708 t = MACRO_FUNC;
710 str = NULL;
711 len = 0;
712 while (1) {
713 skip_spaces();
714 if (ch == '\n' || ch == -1)
715 break;
716 next_nomacro();
717 tok_add2(&str, &len, tok, tokc);
719 tok_add(&str, &len, 0);
720 #ifdef PP_DEBUG
721 printf("define %s %d: ", get_tok_str(v, 0), t);
722 tok_print(str);
723 #endif
724 s = sym_push1(&define_stack, v, t, (int)str);
725 s->next = first;
726 } else if (tok == TOK_UNDEF) {
727 next_nomacro();
728 s = sym_find1(define_stack, tok);
729 /* undefine symbol by putting an invalid name */
730 if (s)
731 s->v = 0;
732 } else if (tok == TOK_INCLUDE) {
733 skip_spaces();
734 if (ch == '<') {
735 c = '>';
736 goto read_name;
737 } else if (ch == '\"') {
738 c = ch;
739 read_name:
740 minp();
741 q = buf;
742 while (ch != c && ch != '\n' && ch != -1) {
743 if ((q - buf) < sizeof(buf) - 1)
744 *q++ = ch;
745 minp();
747 *q = '\0';
748 if (include_stack_ptr >= include_stack + INCLUDE_STACK_SIZE)
749 error("memory full");
750 if (c == '\"') {
751 /* first search in current dir if "header.h" */
752 /* XXX: buffer overflow */
753 size = 0;
754 p = strrchr(filename, '/');
755 if (p)
756 size = p + 1 - filename;
757 memcpy(buf1, filename, size);
758 buf1[size] = '\0';
759 strcat(buf1, buf);
760 f = fopen(buf1, "r");
761 if (f)
762 goto found;
764 /* now search in standard include path */
765 for(i=nb_include_paths - 1;i>=0;i--) {
766 strcpy(buf1, include_paths[i]);
767 strcat(buf1, "/");
768 strcat(buf1, buf);
769 f = fopen(buf1, "r");
770 if (f)
771 goto found;
773 error("include file not found");
774 f = NULL;
775 found:
776 /* push current file in stack */
777 /* XXX: fix current line init */
778 include_stack_ptr->file = file;
779 include_stack_ptr->filename = filename;
780 include_stack_ptr->line_num = line_num;
781 include_stack_ptr++;
782 file = f;
783 filename = strdup(buf1);
784 line_num = 1;
786 } else if (tok == TOK_IFNDEF) {
787 c = 1;
788 goto do_ifdef;
789 } else if (tok == TOK_IF) {
790 c = expr_preprocess();
791 goto do_if;
792 } else if (tok == TOK_IFDEF) {
793 c = 0;
794 do_ifdef:
795 next_nomacro();
796 c = (sym_find1(define_stack, tok) != 0) ^ c;
797 do_if:
798 if (ifdef_stack_ptr >= ifdef_stack + IFDEF_STACK_SIZE)
799 error("memory full");
800 *ifdef_stack_ptr++ = c;
801 goto test_skip;
802 } else if (tok == TOK_ELSE) {
803 if (ifdef_stack_ptr == ifdef_stack ||
804 (ifdef_stack_ptr[-1] & 2))
805 error("#else after #else");
806 c = (ifdef_stack_ptr[-1] ^= 3);
807 goto test_skip;
808 } else if (tok == TOK_ELIF) {
809 if (ifdef_stack_ptr == ifdef_stack ||
810 ifdef_stack_ptr[-1] > 1)
811 error("#elif after #else");
812 c = expr_preprocess();
813 ifdef_stack_ptr[-1] = c;
814 test_skip:
815 if (!(c & 1)) {
816 preprocess_skip();
817 goto redo;
819 } else if (tok == TOK_ENDIF) {
820 if (ifdef_stack_ptr == ifdef_stack)
821 expect("#if");
822 ifdef_stack_ptr--;
824 /* ignore other preprocess commands or #! for C scripts */
825 while (ch != '\n' && ch != -1)
826 cinp();
829 /* read a number in base b */
830 int getn(b)
832 int n, t;
833 n = 0;
834 while (1) {
835 if (ch >= 'a' & ch <= 'f')
836 t = ch - 'a' + 10;
837 else if (ch >= 'A' & ch <= 'F')
838 t = ch - 'A' + 10;
839 else if (isnum(ch))
840 t = ch - '0';
841 else
842 break;
843 if (t < 0 | t >= b)
844 break;
845 n = n * b + t;
846 cinp();
848 return n;
851 /* read a character for string or char constant and eval escape codes */
852 int getq()
854 int c;
856 c = ch;
857 minp();
858 if (c == '\\') {
859 if (isnum(ch)) {
860 return getn(8);
861 } else {
862 if (ch == 'a')
863 c = '\a';
864 else if (ch == 'b')
865 c = '\b';
866 else if (ch == 'f')
867 c = '\f';
868 else if (ch == 'n')
869 c = '\n';
870 else if (ch == 'r')
871 c = '\r';
872 else if (ch == 't')
873 c = '\t';
874 else if (ch == 'v')
875 c = '\v';
876 else
877 c = ch;
878 minp();
881 return c;
884 /* return next token without macro substitution */
885 void next_nomacro1()
887 int b;
888 char *q;
889 TokenSym *ts;
891 /* skip spaces */
892 while(1) {
893 while (ch == '\n') {
894 cinp();
895 while (ch == ' ' || ch == 9)
896 cinp();
897 if (ch == '#') {
898 /* preprocessor command if # at start of line after
899 spaces */
900 preprocess();
903 if (ch != ' ' && ch != '\t' && ch != '\f')
904 break;
905 cinp();
907 if (isid(ch)) {
908 q = token_buf;
909 while (isid(ch) | isnum(ch)) {
910 if (q >= token_buf + STRING_MAX_SIZE)
911 error("ident too long");
912 *q++ = ch;
913 cinp();
915 *q = '\0';
916 ts = tok_alloc(token_buf, q - token_buf);
917 tok = ts->tok;
918 } else if (isnum(ch)) {
919 /* number */
920 b = 10;
921 if (ch == '0') {
922 cinp();
923 b = 8;
924 if (ch == 'x' || ch == 'X') {
925 cinp();
926 b = 16;
929 tokc = getn(b);
930 /* XXX: add unsigned constant support (ANSI) */
931 while (ch == 'L' || ch == 'l' || ch == 'U' || ch == 'u')
932 cinp();
933 tok = TOK_NUM;
934 } else if (ch == '\'') {
935 minp();
936 tokc = getq();
937 tok = TOK_CCHAR;
938 if (ch != '\'')
939 expect("\'");
940 minp();
941 } else if (ch == '\"') {
942 minp();
943 q = token_buf;
944 while (ch != '\"') {
945 b = getq();
946 if (ch == -1)
947 error("unterminated string");
948 if (q >= token_buf + STRING_MAX_SIZE)
949 error("string too long");
950 *q++ = b;
952 *q = '\0';
953 tokc = (int)tok_alloc(token_buf, q - token_buf);
954 tok = TOK_STR;
955 minp();
956 } else {
957 q = "<=\236>=\235!=\225&&\240||\241++\244--\242==\224<<\1>>\2+=\253-=\255*=\252/=\257%=\245&=\246^=\336|=\374->\247..\250##\266";
958 /* two chars */
959 tok = ch;
960 cinp();
961 while (*q) {
962 if (*q == tok & q[1] == ch) {
963 cinp();
964 tok = q[2] & 0xff;
965 /* three chars tests */
966 if (tok == TOK_SHL | tok == TOK_SAR) {
967 if (ch == '=') {
968 tok = tok | 0x80;
969 cinp();
971 } else if (tok == TOK_DOTS) {
972 if (ch != '.')
973 error("parse error");
974 cinp();
976 return;
978 q = q + 3;
980 /* single char substitutions */
981 if (tok == '<')
982 tok = TOK_LT;
983 else if (tok == '>')
984 tok = TOK_GT;
988 /* return next token without macro substitution. Can read input from
989 macro_ptr buffer */
990 void next_nomacro()
992 if (macro_ptr) {
993 tok = *macro_ptr;
994 if (tok) {
995 macro_ptr++;
996 if (tok == TOK_NUM || tok == TOK_CCHAR || tok == TOK_STR)
997 tokc = *macro_ptr++;
999 } else {
1000 next_nomacro1();
1004 /* substitute args in macro_str and return allocated string */
1005 int *macro_arg_subst(Sym **nested_list, int *macro_str, Sym *args)
1007 int *st, last_tok, t, c, notfirst, *str, len;
1008 Sym *s;
1009 TokenSym *ts;
1011 str = NULL;
1012 len = 0;
1013 last_tok = 0;
1014 while(1) {
1015 t = *macro_str++;
1016 if (!t)
1017 break;
1018 if (t == '#') {
1019 /* stringize */
1020 t = *macro_str++;
1021 if (!t)
1022 break;
1023 s = sym_find1(args, t);
1024 if (s) {
1025 token_buf[0] = '\0';
1026 st = (int *)s->c;
1027 /* XXX: buffer overflow */
1028 notfirst = 0;
1029 while (*st) {
1030 if (notfirst)
1031 strcat(token_buf, " ");
1032 t = *st++;
1033 c = 0;
1034 if (t == TOK_NUM || t == TOK_CCHAR || t == TOK_STR)
1035 c = *st++;
1036 strcat(token_buf, get_tok_str(t, c));
1037 notfirst = 1;
1039 #ifdef PP_DEBUG
1040 printf("stringize: %s\n", token_buf);
1041 #endif
1042 /* add string */
1043 ts = tok_alloc(token_buf, strlen(token_buf));
1044 tok_add2(&str, &len, TOK_STR, (int)ts);
1045 } else {
1046 tok_add(&str, &len, t);
1048 } else if (t == TOK_NUM || t == TOK_CCHAR || t == TOK_STR) {
1049 tok_add2(&str, &len, t, *macro_ptr++);
1050 } else {
1051 s = sym_find1(args, t);
1052 if (s) {
1053 st = (int *)s->c;
1054 /* if '##' is present before or after , no arg substitution */
1055 if (*macro_str == TOK_TWOSHARPS || last_tok == TOK_TWOSHARPS) {
1056 while (*st)
1057 tok_add(&str, &len, *st++);
1058 } else {
1059 macro_subst(&str, &len, nested_list, st);
1061 } else {
1062 tok_add(&str, &len, t);
1065 last_tok = t;
1067 tok_add(&str, &len, 0);
1068 return str;
1071 /* handle the '##' operator */
1072 int *macro_twosharps(int *macro_str)
1074 TokenSym *ts;
1075 int *macro_str1, macro_str1_len, *macro_ptr1;
1076 int t, c;
1077 char *p;
1079 macro_str1 = NULL;
1080 macro_str1_len = 0;
1081 tok = 0;
1082 while (1) {
1083 next_nomacro();
1084 if (tok == 0)
1085 break;
1086 if (*macro_ptr == TOK_TWOSHARPS) {
1087 macro_ptr++;
1088 macro_ptr1 = macro_ptr;
1089 t = *macro_ptr;
1090 if (t) {
1091 macro_ptr++;
1092 c = 0;
1093 if (t == TOK_NUM || t == TOK_CCHAR || t == TOK_STR)
1094 c = *macro_ptr++;
1095 /* XXX: we handle only most common cases:
1096 ident + ident or ident + number */
1097 if (tok >= TOK_IDENT &&
1098 (t >= TOK_IDENT || t == TOK_NUM)) {
1099 /* XXX: buffer overflow */
1100 p = get_tok_str(tok, tokc);
1101 strcpy(token_buf, p);
1102 p = get_tok_str(t, c);
1103 strcat(token_buf, p);
1104 ts = tok_alloc(token_buf, strlen(token_buf));
1105 tok_add2(&macro_str1, &macro_str1_len, ts->tok, 0);
1106 } else {
1107 /* cannot merge tokens: skip '##' */
1108 macro_ptr = macro_ptr1;
1111 } else {
1112 tok_add2(&macro_str1, &macro_str1_len, tok, tokc);
1115 tok_add(&macro_str1, &macro_str1_len, 0);
1116 return macro_str1;
1121 /* do macro substitution of macro_str and add result to
1122 (tok_str,tok_len). If macro_str is NULL, then input stream token is
1123 substituted. 'nested_list' is the list of all macros we got inside
1124 to avoid recursing. */
1125 void macro_subst(int **tok_str, int *tok_len,
1126 Sym **nested_list, int *macro_str)
1128 Sym *s, *args, *sa;
1129 int *str, parlevel, len, *mstr, t, *saved_macro_ptr;
1130 int mstr_allocated, *macro_str1;
1132 saved_macro_ptr = macro_ptr;
1133 macro_ptr = macro_str;
1134 macro_str1 = NULL;
1135 if (macro_str) {
1136 /* first scan for '##' operator handling */
1137 macro_str1 = macro_twosharps(macro_str);
1138 macro_ptr = macro_str1;
1141 while (1) {
1142 next_nomacro();
1143 if (tok == 0)
1144 break;
1145 /* if symbol is a macro, prepare substitution */
1146 s = sym_find1(define_stack, tok);
1147 if (s) {
1148 /* if nested substitution, do nothing */
1149 if (sym_find1(*nested_list, tok))
1150 goto no_subst;
1151 mstr = (int *)s->c;
1152 mstr_allocated = 0;
1153 if (s->t == MACRO_FUNC) {
1154 /* NOTE: we do not use next_nomacro to avoid eating the
1155 next token. XXX: find better solution */
1156 if (macro_ptr) {
1157 t = *macro_ptr;
1158 } else {
1159 while (ch == ' ' || ch == '\t' || ch == '\n')
1160 cinp();
1161 t = ch;
1163 if (t != '(') /* no macro subst */
1164 goto no_subst;
1166 /* argument macro */
1167 next_nomacro();
1168 next_nomacro();
1169 args = NULL;
1170 sa = s->next;
1171 while (tok != ')' && sa) {
1172 len = 0;
1173 str = NULL;
1174 parlevel = 0;
1175 while ((parlevel > 0 || (tok != ')' && tok != ',')) &&
1176 tok != -1) {
1177 if (tok == '(')
1178 parlevel++;
1179 else if (tok == ')')
1180 parlevel--;
1181 tok_add2(&str, &len, tok, tokc);
1182 next_nomacro();
1184 tok_add(&str, &len, 0);
1185 sym_push1(&args, sa->v & ~SYM_FIELD, 0, (int)str);
1186 if (tok != ',')
1187 break;
1188 next_nomacro();
1189 sa = sa->next;
1191 if (tok != ')')
1192 expect(")");
1193 /* now subst each arg */
1194 mstr = macro_arg_subst(nested_list, mstr, args);
1195 sym_pop(&args, NULL);
1196 mstr_allocated = 1;
1198 sym_push1(nested_list, s->v, 0, 0);
1199 macro_subst(tok_str, tok_len, nested_list, mstr);
1200 sym_pop(nested_list, (*nested_list)->prev);
1201 if (mstr_allocated)
1202 free(mstr);
1203 /* only replace one macro while parsing input stream */
1204 if (!macro_str)
1205 return;
1206 } else {
1207 no_subst:
1208 /* no need to add if reading input stream */
1209 if (!macro_str)
1210 return;
1211 tok_add2(tok_str, tok_len, tok, tokc);
1214 macro_ptr = saved_macro_ptr;
1215 if (macro_str1)
1216 free(macro_str1);
1219 /* return next token with macro substitution */
1220 void next()
1222 int len, *ptr;
1223 Sym *nested_list;
1225 /* special 'ungettok' case for label parsing */
1226 if (tok1) {
1227 tok = tok1;
1228 tok1 = 0;
1229 } else {
1230 redo:
1231 if (!macro_ptr) {
1232 /* if not reading from macro substuted string, then try to substitute */
1233 len = 0;
1234 ptr = NULL;
1235 nested_list = NULL;
1236 macro_subst(&ptr, &len, &nested_list, NULL);
1237 if (ptr) {
1238 tok_add(&ptr, &len, 0);
1239 macro_ptr = ptr;
1240 macro_ptr_allocated = ptr;
1241 goto redo;
1243 if (tok == 0)
1244 goto redo;
1245 } else {
1246 next_nomacro();
1247 if (tok == 0) {
1248 /* end of macro string: free it */
1249 free(macro_ptr_allocated);
1250 macro_ptr = NULL;
1251 goto redo;
1255 #ifdef DEBUG
1256 printf("token = %s\n", get_tok_str(tok, tokc));
1257 #endif
1260 void swap(int *p, int *q)
1262 int t;
1263 t = *p;
1264 *p = *q;
1265 *q = t;
1268 void vset(t, v)
1270 vt = t;
1271 vc = v;
1274 /******************************************************/
1275 /* X86 code generator */
1277 void g(c)
1279 *(char *)ind++ = c;
1282 void o(c)
1284 while (c) {
1285 g(c);
1286 c = c / 256;
1290 /* output a symbol and patch all calls to it */
1291 void gsym_addr(t, a)
1293 int n;
1294 while (t) {
1295 n = *(int *)t; /* next value */
1296 *(int *)t = a - t - 4;
1297 t = n;
1301 void gsym(t)
1303 gsym_addr(t, ind);
1306 /* psym is used to put an instruction with a data field which is a
1307 reference to a symbol. It is in fact the same as oad ! */
1308 #define psym oad
1310 /* instruction + 4 bytes data. Return the address of the data */
1311 int oad(c, s)
1313 o(c);
1314 *(int *)ind = s;
1315 s = ind;
1316 ind = ind + 4;
1317 return s;
1320 /* XXX: generate correct pointer for forward references to functions */
1321 /* r = (ft, fc) */
1322 void load(r, ft, fc)
1324 int v, t;
1326 v = ft & VT_VALMASK;
1327 if (ft & VT_LVAL) {
1328 if (v == VT_LLOCAL) {
1329 load(r, VT_LOCAL | VT_LVAL, fc);
1330 v = r;
1332 if ((ft & VT_TYPE) == VT_BYTE)
1333 o(0xbe0f); /* movsbl */
1334 else
1335 o(0x8b); /* movl */
1336 if (v == VT_CONST) {
1337 oad(0x05 + r * 8, fc); /* 0xXX, r */
1338 } else if (v == VT_LOCAL) {
1339 oad(0x85 + r * 8, fc); /* xx(%ebp), r */
1340 } else {
1341 g(0x00 + r * 8 + v); /* (v), r */
1343 } else {
1344 if (v == VT_CONST) {
1345 oad(0xb8 + r, fc); /* mov $xx, r */
1346 } else if (v == VT_LOCAL) {
1347 o(0x8d);
1348 oad(0x85 + r * 8, fc); /* lea xxx(%ebp), r */
1349 } else if (v == VT_CMP) {
1350 oad(0xb8 + r, 0); /* mov $0, r */
1351 o(0x0f); /* setxx %br */
1352 o(fc);
1353 o(0xc0 + r);
1354 } else if (v == VT_JMP || v == VT_JMPI) {
1355 t = v & 1;
1356 oad(0xb8 + r, t); /* mov $1, r */
1357 oad(0xe9, 5); /* jmp after */
1358 gsym(fc);
1359 oad(0xb8 + r, t ^ 1); /* mov $0, r */
1360 } else if (v != r) {
1361 o(0x89);
1362 o(0xc0 + r + v * 8); /* mov v, r */
1367 /* (ft, fc) = r */
1368 /* WARNING: r must not be allocated on the stack */
1369 void store(r, ft, fc)
1371 int fr, b;
1373 fr = ft & VT_VALMASK;
1374 b = (ft & VT_TYPE) == VT_BYTE;
1375 o(0x89 - b);
1376 if (fr == VT_CONST) {
1377 oad(0x05 + r * 8, fc); /* mov r,xxx */
1378 } else if (fr == VT_LOCAL) {
1379 oad(0x85 + r * 8, fc); /* mov r,xxx(%ebp) */
1380 } else if (ft & VT_LVAL) {
1381 g(fr + r * 8); /* mov r, (fr) */
1382 } else if (fr != r) {
1383 o(0xc0 + fr + r * 8); /* mov r, fr */
1387 int gjmp(t)
1389 return psym(0xe9, t);
1392 /* generate a test. set 'inv' to invert test */
1393 int gtst(inv, t)
1395 int v, *p;
1396 v = vt & VT_VALMASK;
1397 if (v == VT_CMP) {
1398 /* fast case : can jump directly since flags are set */
1399 g(0x0f);
1400 t = psym((vc - 16) ^ inv, t);
1401 } else if (v == VT_JMP || v == VT_JMPI) {
1402 /* && or || optimization */
1403 if ((v & 1) == inv) {
1404 /* insert vc jump list in t */
1405 p = &vc;
1406 while (*p != 0)
1407 p = (int *)*p;
1408 *p = t;
1409 t = vc;
1410 } else {
1411 t = gjmp(t);
1412 gsym(vc);
1414 } else if ((vt & (VT_VALMASK | VT_LVAL)) == VT_CONST) {
1415 /* constant jmp optimization */
1416 if ((vc != 0) != inv)
1417 t = gjmp(t);
1418 } else {
1419 v = gv();
1420 o(0x85);
1421 o(0xc0 + v * 9);
1422 g(0x0f);
1423 t = psym(0x85 ^ inv, t);
1425 return t;
1428 /* generate a binary operation 'v = r op fr' instruction and modifies
1429 (vt,vc) if needed */
1430 void gen_op1(op, r, fr)
1432 int t;
1433 if (op == '+') {
1434 o(0x01);
1435 o(0xc0 + r + fr * 8);
1436 } else if (op == '-') {
1437 o(0x29);
1438 o(0xc0 + r + fr * 8);
1439 } else if (op == '&') {
1440 o(0x21);
1441 o(0xc0 + r + fr * 8);
1442 } else if (op == '^') {
1443 o(0x31);
1444 o(0xc0 + r + fr * 8);
1445 } else if (op == '|') {
1446 o(0x09);
1447 o(0xc0 + r + fr * 8);
1448 } else if (op == '*') {
1449 o(0xaf0f); /* imul fr, r */
1450 o(0xc0 + fr + r * 8);
1451 } else if (op == TOK_SHL | op == TOK_SHR | op == TOK_SAR) {
1452 /* op2 is %ecx */
1453 if (fr != 1) {
1454 if (r == 1) {
1455 r = fr;
1456 fr = 1;
1457 o(0x87); /* xchg r, %ecx */
1458 o(0xc1 + r * 8);
1459 } else
1460 move_reg(1, fr);
1462 o(0xd3); /* shl/shr/sar %cl, r */
1463 if (op == TOK_SHL)
1464 o(0xe0 + r);
1465 else if (op == TOK_SHR)
1466 o(0xe8 + r);
1467 else
1468 o(0xf8 + r);
1469 vt = (vt & VT_TYPE) | r;
1470 } else if (op == '/' | op == TOK_UDIV | op == TOK_PDIV |
1471 op == '%' | op == TOK_UMOD) {
1472 save_reg(2); /* save edx */
1473 t = save_reg_forced(fr); /* save fr and get op2 location */
1474 move_reg(0, r); /* op1 is %eax */
1475 if (op == TOK_UDIV | op == TOK_UMOD) {
1476 o(0xf7d231); /* xor %edx, %edx, div t(%ebp), %eax */
1477 oad(0xb5, t);
1478 } else {
1479 o(0xf799); /* cltd, idiv t(%ebp), %eax */
1480 oad(0xbd, t);
1482 if (op == '%' | op == TOK_UMOD)
1483 r = 2;
1484 else
1485 r = 0;
1486 vt = (vt & VT_TYPE) | r;
1487 } else {
1488 o(0x39);
1489 o(0xc0 + r + fr * 8); /* cmp fr, r */
1490 vset(VT_CMP, op);
1494 /* end of X86 code generator */
1495 /*************************************************************/
1497 int save_reg_forced(int r)
1499 int i, l, *p, t;
1500 /* store register */
1501 loc = (loc - 4) & -3;
1502 store(r, VT_LOCAL, loc);
1503 l = loc;
1505 /* modify all stack values */
1506 for(p=vstack;p<vstack_ptr;p+=2) {
1507 i = p[0] & VT_VALMASK;
1508 if (i == r) {
1509 if (p[0] & VT_LVAL)
1510 t = VT_LLOCAL;
1511 else
1512 t = VT_LOCAL;
1513 p[0] = (p[0] & VT_TYPE) | VT_LVAL | t;
1514 p[1] = l;
1517 return l;
1520 /* save r to memory. and mark it as being free */
1521 void save_reg(r)
1523 int i, *p;
1525 /* modify all stack values */
1526 for(p=vstack;p<vstack_ptr;p+=2) {
1527 i = p[0] & VT_VALMASK;
1528 if (i == r) {
1529 save_reg_forced(r);
1530 break;
1535 /* find a free register. If none, save one register */
1536 int get_reg()
1538 int r, i, *p;
1540 /* find a free register */
1541 for(r=0;r<NB_REGS;r++) {
1542 for(p=vstack;p<vstack_ptr;p+=2) {
1543 i = p[0] & VT_VALMASK;
1544 if (i == r)
1545 goto notfound;
1547 return r;
1548 notfound: ;
1551 /* no register left : free the first one on the stack (very
1552 important to start from the bottom to ensure that we don't
1553 spill registers used in gen_op()) */
1554 for(p=vstack;p<vstack_ptr;p+=2) {
1555 r = p[0] & VT_VALMASK;
1556 if (r < VT_CONST) {
1557 save_reg(r);
1558 break;
1561 return r;
1564 void save_regs()
1566 int r, *p;
1567 for(p=vstack;p<vstack_ptr;p+=2) {
1568 r = p[0] & VT_VALMASK;
1569 if (r < VT_CONST) {
1570 save_reg(r);
1575 /* move register 's' to 'r', and flush previous value of r to memory
1576 if needed */
1577 void move_reg(r, s)
1579 if (r != s) {
1580 save_reg(r);
1581 load(r, s, 0);
1585 /* convert a stack entry in register */
1586 int gvp(int *p)
1588 int r;
1589 r = p[0] & VT_VALMASK;
1590 if (r >= VT_CONST || (p[0] & VT_LVAL))
1591 r = get_reg();
1592 load(r, p[0], p[1]);
1593 p[0] = (p[0] & VT_TYPE) | r;
1594 return r;
1597 void vpush()
1599 if (vstack_ptr >= vstack + VSTACK_SIZE)
1600 error("memory full");
1601 *vstack_ptr++ = vt;
1602 *vstack_ptr++ = vc;
1603 /* cannot let cpu flags if other instruction are generated */
1604 if ((vt & VT_VALMASK) == VT_CMP)
1605 gvp(vstack_ptr - 2);
1608 void vpop(int *ft, int *fc)
1610 *fc = *--vstack_ptr;
1611 *ft = *--vstack_ptr;
1614 /* generate a value in a register from vt and vc */
1615 int gv()
1617 int r;
1618 vpush();
1619 r = gvp(vstack_ptr - 2);
1620 vpop(&vt, &vc);
1621 return r;
1624 /* handle constant optimizations and various machine independant opt */
1625 void gen_opc(op)
1627 int fr, ft, fc, r, c1, c2, n;
1629 vpop(&ft, &fc);
1630 vpop(&vt, &vc);
1631 c1 = (vt & (VT_VALMASK | VT_LVAL)) == VT_CONST;
1632 c2 = (ft & (VT_VALMASK | VT_LVAL)) == VT_CONST;
1633 if (c1 && c2) {
1634 switch(op) {
1635 case '+': vc += fc; break;
1636 case '-': vc -= fc; break;
1637 case '&': vc &= fc; break;
1638 case '^': vc ^= fc; break;
1639 case '|': vc |= fc; break;
1640 case '*': vc *= fc; break;
1641 case TOK_PDIV:
1642 case '/': vc /= fc; break; /* XXX: zero case ? */
1643 case '%': vc %= fc; break; /* XXX: zero case ? */
1644 case TOK_UDIV: vc = (unsigned)vc / fc; break; /* XXX: zero case ? */
1645 case TOK_UMOD: vc = (unsigned)vc % fc; break; /* XXX: zero case ? */
1646 case TOK_SHL: vc <<= fc; break;
1647 case TOK_SHR: vc = (unsigned)vc >> fc; break;
1648 case TOK_SAR: vc >>= fc; break;
1649 /* tests */
1650 case TOK_ULT: vc = (unsigned)vc < (unsigned)fc; break;
1651 case TOK_UGE: vc = (unsigned)vc >= (unsigned)fc; break;
1652 case TOK_EQ: vc = vc == fc; break;
1653 case TOK_NE: vc = vc != fc; break;
1654 case TOK_ULE: vc = (unsigned)vc <= (unsigned)fc; break;
1655 case TOK_UGT: vc = (unsigned)vc > (unsigned)fc; break;
1656 case TOK_LT: vc = vc < fc; break;
1657 case TOK_GE: vc = vc >= fc; break;
1658 case TOK_LE: vc = vc <= fc; break;
1659 case TOK_GT: vc = vc > fc; break;
1660 /* logical */
1661 case TOK_LAND: vc = vc && fc; break;
1662 case TOK_LOR: vc = vc || fc; break;
1663 default:
1664 goto general_case;
1666 } else {
1667 /* if commutative ops, put c2 as constant */
1668 if (c1 && (op == '+' || op == '&' || op == '^' ||
1669 op == '|' || op == '*')) {
1670 swap(&vt, &ft);
1671 swap(&vc, &fc);
1672 swap(&c1, &c2);
1674 if (c2 && (((op == '*' || op == '/' || op == TOK_UDIV ||
1675 op == TOK_PDIV) &&
1676 fc == 1) ||
1677 ((op == '+' || op == '-' || op == '|' || op == '^' ||
1678 op == TOK_SHL || op == TOK_SHR || op == TOK_SAR) &&
1679 fc == 0) ||
1680 (op == '&' &&
1681 fc == -1))) {
1682 } else if (c2 && (op == '*' || op == TOK_PDIV || op == TOK_UDIV)) {
1683 /* try to use shifts instead of muls or divs */
1684 if (fc > 0 && (fc & (fc - 1)) == 0) {
1685 n = -1;
1686 while (fc) {
1687 fc >>= 1;
1688 n++;
1690 fc = n;
1691 if (op == '*')
1692 op = TOK_SHL;
1693 else if (op == TOK_PDIV)
1694 op = TOK_SAR;
1695 else
1696 op = TOK_SHR;
1698 goto general_case;
1699 } else {
1700 general_case:
1701 vpush();
1702 vt = ft;
1703 vc = fc;
1704 vpush();
1705 r = gvp(vstack_ptr - 4);
1706 fr = gvp(vstack_ptr - 2);
1707 vpop(&ft, &fc);
1708 vpop(&vt, &vc);
1709 /* call low level op generator */
1710 gen_op1(op, r, fr);
1715 int pointed_size(int t)
1717 return type_size(pointed_type(t), &t);
1720 /* generic gen_op: handles types problems */
1721 void gen_op(int op)
1723 int u, t1, t2;
1725 vpush();
1726 t1 = vstack_ptr[-4];
1727 t2 = vstack_ptr[-2];
1728 if (op == '+' | op == '-') {
1729 if ((t1 & VT_PTR) && (t2 & VT_PTR)) {
1730 if (op != '-')
1731 error("invalid type");
1732 /* XXX: check that types are compatible */
1733 u = pointed_size(t1);
1734 gen_opc(op);
1735 vpush();
1736 vstack_ptr[-2] &= ~VT_TYPE; /* set to integer */
1737 vset(VT_CONST, u);
1738 gen_op(TOK_PDIV);
1739 } else if ((t1 | t2) & VT_PTR) {
1740 if (t2 & VT_PTR) {
1741 swap(vstack_ptr - 4, vstack_ptr - 2);
1742 swap(vstack_ptr - 3, vstack_ptr - 1);
1743 swap(&t1, &t2);
1745 /* stack-4 contains pointer, stack-2 value to add */
1746 vset(VT_CONST, pointed_size(vstack_ptr[-4]));
1747 gen_op('*');
1748 vpush();
1749 gen_opc(op);
1750 /* put again type if gen_opc() swaped operands */
1751 vt = (vt & VT_TYPEN) | (t1 & VT_TYPE);
1752 } else {
1753 gen_opc(op);
1755 } else {
1756 /* XXX: test types and compute returned value */
1757 if ((t1 | t2) & (VT_UNSIGNED | VT_PTR)) {
1758 if (op == TOK_SAR)
1759 op = TOK_SHR;
1760 else if (op == '/')
1761 op = TOK_UDIV;
1762 else if (op == '%')
1763 op = TOK_UMOD;
1764 else if (op == TOK_LT)
1765 op = TOK_ULT;
1766 else if (op == TOK_GT)
1767 op = TOK_UGT;
1768 else if (op == TOK_LE)
1769 op = TOK_ULE;
1770 else if (op == TOK_GE)
1771 op = TOK_UGE;
1773 gen_opc(op);
1777 /* return type size. Put alignment at 'a' */
1778 int type_size(int t, int *a)
1780 Sym *s;
1782 /* int, enum or pointer */
1783 if (t & VT_STRUCT) {
1784 /* struct/union */
1785 s = sym_find(((unsigned)t >> VT_STRUCT_SHIFT) | SYM_STRUCT);
1786 *a = 4; /* XXX: cannot store it yet. Doing that is safe */
1787 return s->c;
1788 } else if (t & VT_ARRAY) {
1789 s = sym_find(((unsigned)t >> VT_STRUCT_SHIFT));
1790 return type_size(s->t, a) * s->c;
1791 } else if ((t & VT_PTR) |
1792 (t & VT_TYPE) == 0 |
1793 (t & VT_ENUM)) {
1794 *a = 4;
1795 return 4;
1796 } else {
1797 *a = 1;
1798 return 1;
1802 /* return the pointed type of t */
1803 int pointed_type(int t)
1805 Sym *s;
1806 s = sym_find(((unsigned)t >> VT_STRUCT_SHIFT));
1807 return s->t | (t & VT_TYPEN);
1810 int mk_pointer(int t)
1812 int p;
1813 p = anon_sym++;
1814 sym_push(p, t, -1);
1815 return VT_PTR | (p << VT_STRUCT_SHIFT) | (t & VT_TYPEN);
1818 /* store value in lvalue pushed on stack */
1819 void vstore()
1821 int ft, fc, r, t;
1823 r = gv(); /* generate value */
1824 vpush();
1825 ft = vstack_ptr[-4];
1826 fc = vstack_ptr[-3];
1827 if ((ft & VT_VALMASK) == VT_LLOCAL) {
1828 t = get_reg();
1829 load(t, VT_LOCAL | VT_LVAL, fc);
1830 ft = (ft & ~VT_VALMASK) | t;
1832 store(r, ft, fc);
1833 vstack_ptr -= 4;
1836 /* post defines POST/PRE add. c is the token ++ or -- */
1837 void inc(post, c)
1839 int r, r1;
1840 test_lvalue();
1841 if (post)
1842 vpush(); /* room for returned value */
1843 vpush(); /* save lvalue */
1844 r = gv();
1845 vpush(); /* save value */
1846 if (post) {
1847 /* duplicate value */
1848 r1 = get_reg();
1849 load(r1, r, 0); /* move r to r1 */
1850 vstack_ptr[-6] = (vt & VT_TYPE) | r1;
1851 vstack_ptr[-5] = 0;
1853 /* add constant */
1854 vset(VT_CONST, c - TOK_MID);
1855 gen_op('+');
1856 vstore(); /* store value */
1857 if (post)
1858 vpop(&vt, &vc);
1861 /* enum/struct/union declaration */
1862 int struct_decl(u)
1864 int a, t, b, v, size, align, maxalign, c;
1865 Sym *slast, *s, *ss;
1867 a = tok; /* save decl type */
1868 next();
1869 if (tok != '{') {
1870 v = tok;
1871 next();
1872 /* struct already defined ? return it */
1873 /* XXX: check consistency */
1874 if (s = sym_find(v | SYM_STRUCT)) {
1875 if (s->t != a)
1876 error("invalid type");
1877 u = u | (v << VT_STRUCT_SHIFT);
1878 return u;
1880 } else {
1881 v = anon_sym++;
1883 s = sym_push(v | SYM_STRUCT, a, 0);
1884 /* put struct/union/enum name in type */
1885 u = u | (v << VT_STRUCT_SHIFT);
1887 if (tok == '{') {
1888 next();
1889 /* cannot be empty */
1890 c = 0;
1891 maxalign = 0;
1892 slast = NULL;
1893 while (1) {
1894 if (a == TOK_ENUM) {
1895 v = tok;
1896 next();
1897 if (tok == '=') {
1898 next();
1899 c = expr_const();
1901 sym_push(v, VT_CONST, c);
1902 if (tok == ',')
1903 next();
1904 c++;
1905 } else {
1906 b = ist();
1907 while (1) {
1908 t = typ(&v, b);
1909 if (t & (VT_FUNC | VT_TYPEDEF))
1910 error("invalid type");
1911 /* XXX: align & correct type size */
1912 v |= SYM_FIELD;
1913 size = type_size(t, &align);
1914 if (a == TOK_STRUCT) {
1915 c = (c + align - 1) & -align;
1916 ss = sym_push(v, t, c);
1917 c += size;
1918 } else {
1919 ss = sym_push(v, t, 0);
1920 if (size > c)
1921 c = size;
1923 if (align > maxalign)
1924 maxalign = align;
1925 ss->next = slast;
1926 slast = ss;
1927 if (tok == ';' || tok == -1)
1928 break;
1929 skip(',');
1931 skip(';');
1933 if (tok == '}')
1934 break;
1936 skip('}');
1937 s->next = slast;
1938 /* size for struct/union, dummy for enum */
1939 s->c = (c + maxalign - 1) & -maxalign;
1941 return u;
1944 /* return 0 if no type declaration. otherwise, return the basic type
1945 and skip it.
1946 XXX: A '2' is ored to ensure non zero return if int type.
1948 int ist(void)
1950 int t;
1951 Sym *s;
1953 t = 0;
1954 while(1) {
1955 if (tok == TOK_ENUM) {
1956 t |= struct_decl(VT_ENUM);
1957 } else if (tok == TOK_STRUCT || tok == TOK_UNION) {
1958 t |= struct_decl(VT_STRUCT);
1959 } else {
1960 if (tok == TOK_CHAR) {
1961 t |= VT_BYTE;
1962 } else if (tok == TOK_VOID) {
1963 t |= VT_VOID;
1964 } else if (tok == TOK_INT | tok == TOK_SHORT |
1965 (tok >= TOK_CONST & tok <= TOK_INLINE)) {
1966 /* ignored types */
1967 } else if (tok == TOK_FLOAT || tok == TOK_DOUBLE) {
1968 warning("floats not supported");
1969 } else if (tok == TOK_EXTERN) {
1970 t |= VT_EXTERN;
1971 } else if (tok == TOK_STATIC) {
1972 t |= VT_STATIC;
1973 } else if (tok == TOK_UNSIGNED) {
1974 t |= VT_UNSIGNED;
1975 } else if (tok == TOK_TYPEDEF) {
1976 t |= VT_TYPEDEF;
1977 } else {
1978 s = sym_find(tok);
1979 if (!s || !(s->t & VT_TYPEDEF))
1980 break;
1981 t = s->t & ~VT_TYPEDEF;
1983 next();
1985 t |= 2;
1987 return t;
1990 int post_type(t)
1992 int p, n, pt, l, a;
1993 Sym *last, *s;
1995 if (tok == '(') {
1996 /* function declaration */
1997 next();
1998 a = 4;
1999 l = 0;
2000 last = NULL;
2001 while (tok != ')') {
2002 /* read param name and compute offset */
2003 if (l != FUNC_OLD) {
2004 if (!(pt = ist())) {
2005 if (l) {
2006 error("invalid type");
2007 } else {
2008 l = FUNC_OLD;
2009 goto old_proto;
2012 if (pt & VT_VOID && tok == ')')
2013 break;
2014 l = FUNC_NEW;
2015 pt = typ(&n, pt); /* XXX: should accept
2016 both arg/non arg if v == 0 */
2017 } else {
2018 old_proto:
2019 n = tok;
2020 pt = 0; /* int type */
2021 next();
2023 /* array must be transformed to pointer according to ANSI C */
2024 pt &= ~VT_ARRAY;
2025 /* XXX: size will be different someday */
2026 a = a + 4;
2027 s = sym_push(n | SYM_FIELD, VT_LOCAL | VT_LVAL | pt, a);
2028 s->next = last;
2029 last = s;
2030 if (tok == ',') {
2031 next();
2032 if (l == FUNC_NEW && tok == TOK_DOTS) {
2033 l = FUNC_ELLIPSIS;
2034 next();
2035 break;
2039 skip(')');
2040 t = post_type(t);
2041 /* we push a anonymous symbol which will contain the function prototype */
2042 p = anon_sym++;
2043 s = sym_push(p, t, l);
2044 s->next = last;
2045 t = VT_FUNC | (p << VT_STRUCT_SHIFT);
2046 } else if (tok == '[') {
2047 /* array definition */
2048 next();
2049 n = -1;
2050 if (tok != ']') {
2051 n = expr_const();
2052 if (n < 0)
2053 error("invalid array size");
2055 skip(']');
2056 /* parse next post type */
2057 t = post_type(t);
2059 /* we push a anonymous symbol which will contain the array
2060 element type */
2061 p = anon_sym++;
2062 sym_push(p, t, n);
2063 t = VT_ARRAY | VT_PTR | (p << VT_STRUCT_SHIFT);
2065 return t;
2068 /* Read a type declaration (except basic type), and return the
2069 type. If v is true, then also put variable name in 'vc' */
2070 int typ(int *v, int t)
2072 int u, p;
2073 Sym *s;
2075 t = t & -3; /* suppress the ored '2' */
2076 while (tok == '*') {
2077 next();
2078 t = mk_pointer(t);
2081 /* recursive type */
2082 /* XXX: incorrect if abstract type for functions (e.g. 'int ()') */
2083 if (tok == '(') {
2084 next();
2085 u = typ(v, 0);
2086 skip(')');
2087 } else {
2088 u = 0;
2089 /* type identifier */
2090 if (v) {
2091 *v = tok;
2092 next();
2095 /* append t at the end of u */
2096 t = post_type(t);
2097 if (!u)
2098 return t;
2099 p = u;
2100 while(1) {
2101 s = sym_find((unsigned)p >> VT_STRUCT_SHIFT);
2102 p = s->t;
2103 if (!p) {
2104 s->t = t;
2105 break;
2108 return u;
2111 /* define a new external reference to a function 'v' of type 'u' */
2112 Sym *external_func(v, u)
2114 int n;
2115 Sym *s;
2116 s = sym_find(v);
2117 if (!s) {
2118 n = (int)dlsym(0, get_tok_str(v, 0));
2119 if (n == 0) {
2120 /* used to generate symbol list */
2121 s = sym_push1(&global_stack,
2122 v, u | VT_CONST | VT_LVAL | VT_FORWARD, 0);
2123 } else {
2124 /* int f() */
2125 s = sym_push1(&global_stack,
2126 v, u | VT_CONST | VT_LVAL, n);
2129 return s;
2132 void indir()
2134 if (vt & VT_LVAL)
2135 gv();
2136 if (!(vt & VT_PTR))
2137 expect("pointer");
2138 vt = pointed_type(vt);
2139 if (!(vt & VT_ARRAY)) /* an array is never an lvalue */
2140 vt |= VT_LVAL;
2143 void unary()
2145 int n, t, ft, fc, p, r;
2146 Sym *s;
2148 if (tok == TOK_NUM || tok == TOK_CCHAR) {
2149 vset(VT_CONST, tokc);
2150 next();
2151 } else if (tok == TOK_STR) {
2152 TokenSym *ts;
2153 /* generate (char *) type */
2154 vset(VT_CONST | mk_pointer(VT_TYPE), glo);
2155 while (tok == TOK_STR) {
2156 ts = (TokenSym *)tokc;
2157 memcpy((void *)glo, ts->str, ts->len);
2158 glo += ts->len;
2159 next();
2161 *(char *)glo++ = 0;
2162 } else {
2163 t = tok;
2164 next();
2165 if (t == '(') {
2166 /* cast ? */
2167 if (t = ist()) {
2168 ft = typ(0, t);
2169 skip(')');
2170 unary();
2171 vt = (vt & VT_TYPEN) | ft;
2172 } else {
2173 expr();
2174 skip(')');
2176 } else if (t == '*') {
2177 unary();
2178 indir();
2179 } else if (t == '&') {
2180 unary();
2181 test_lvalue();
2182 vt = mk_pointer(vt & VT_LVALN);
2183 } else
2184 if (t == '!') {
2185 unary();
2186 if ((vt & (VT_CONST | VT_LVAL)) == VT_CONST)
2187 vc = !vc;
2188 else if ((vt & VT_VALMASK) == VT_CMP)
2189 vc = vc ^ 1;
2190 else
2191 vset(VT_JMP, gtst(1, 0));
2192 } else
2193 if (t == '~') {
2194 unary();
2195 vpush();
2196 vset(VT_CONST, -1);
2197 gen_op('^');
2198 } else
2199 if (t == '+') {
2200 unary();
2201 } else
2202 if (t == TOK_SIZEOF) {
2203 /* XXX: some code can be generated */
2204 if (tok == '(') {
2205 next();
2206 if (t = ist())
2207 vt = typ(0, t);
2208 else
2209 expr();
2210 skip(')');
2211 } else {
2212 unary();
2214 vset(VT_CONST, type_size(vt, &t));
2215 } else
2216 if (t == TOK_INC | t == TOK_DEC) {
2217 unary();
2218 inc(0, t);
2219 } else if (t == '-') {
2220 vset(VT_CONST, 0);
2221 vpush();
2222 unary();
2223 gen_op('-');
2224 } else
2226 s = sym_find(t);
2227 if (!s) {
2228 if (tok != '(')
2229 error("undefined symbol");
2230 /* for simple function calls, we tolerate undeclared
2231 external reference */
2232 p = anon_sym++;
2233 sym_push1(&global_stack, p, 0, FUNC_OLD);
2234 /* int() function */
2235 s = external_func(t, VT_FUNC | (p << VT_STRUCT_SHIFT));
2237 vset(s->t, s->c);
2238 /* if forward reference, we must point to s->c */
2239 if (vt & VT_FORWARD)
2240 vc = (int)&s->c;
2244 /* post operations */
2245 while (1) {
2246 if (tok == TOK_INC | tok == TOK_DEC) {
2247 inc(1, tok);
2248 next();
2249 } else if (tok == '.' | tok == TOK_ARROW) {
2250 /* field */
2251 if (tok == TOK_ARROW)
2252 indir();
2253 test_lvalue();
2254 vt &= VT_LVALN;
2255 next();
2256 /* expect pointer on structure */
2257 if (!(vt & VT_STRUCT))
2258 expect("struct or union");
2259 s = sym_find(((unsigned)vt >> VT_STRUCT_SHIFT) | SYM_STRUCT);
2260 /* find field */
2261 tok |= SYM_FIELD;
2262 while (s = s->next) {
2263 if (s->v == tok)
2264 break;
2266 if (!s)
2267 error("field not found");
2268 /* add field offset to pointer */
2269 vt = vt & VT_TYPEN; /* change type to int */
2270 vpush();
2271 vset(VT_CONST, s->c);
2272 gen_op('+');
2273 /* change type to field type, and set to lvalue */
2274 vt = (vt & VT_TYPEN) | s->t;
2275 /* an array is never an lvalue */
2276 if (!(vt & VT_ARRAY))
2277 vt |= VT_LVAL;
2278 next();
2279 } else if (tok == '[') {
2280 next();
2281 vpush();
2282 expr();
2283 gen_op('+');
2284 indir();
2285 skip(']');
2286 } else if (tok == '(') {
2287 /* function call */
2288 save_regs(); /* save used temporary registers */
2289 /* lvalue is implied */
2290 vt = vt & VT_LVALN;
2291 if ((vt & VT_VALMASK) != VT_CONST) {
2292 /* evaluate function address */
2293 r = gv();
2294 o(0x50 + r); /* push r */
2296 ft = vt;
2297 fc = vc;
2298 next();
2299 t = 0;
2300 while (tok != ')') {
2301 t = t + 4;
2302 expr_eq();
2303 r = gv();
2304 o(0x50 + r); /* push r */
2305 if (tok == ',')
2306 next();
2308 skip(')');
2309 /* horrible, but needed : convert to native ordering (could
2310 parse parameters in reverse order, but would cost more
2311 code) */
2312 n = 0;
2313 p = t - 4;
2314 while (n < p) {
2315 oad(0x24848b, p); /* mov x(%esp,1), %eax */
2316 oad(0x248487, n); /* xchg x(%esp,1), %eax */
2317 oad(0x248489, p); /* mov %eax, x(%esp,1) */
2318 n = n + 4;
2319 p = p - 4;
2321 if ((ft & VT_VALMASK) == VT_CONST) {
2322 /* forward reference */
2323 if (ft & VT_FORWARD) {
2324 *(int *)fc = psym(0xe8, *(int *)fc);
2325 } else
2326 oad(0xe8, fc - ind - 5);
2327 } else {
2328 oad(0x2494ff, t); /* call *xxx(%esp) */
2329 t = t + 4;
2331 if (t)
2332 oad(0xc481, t);
2333 /* get return type */
2334 s = sym_find((unsigned)ft >> VT_STRUCT_SHIFT);
2335 vt = s->t | 0; /* return register is eax */
2336 } else {
2337 break;
2342 void uneq()
2344 int t;
2346 unary();
2347 if (tok == '=' |
2348 (tok >= TOK_A_MOD & tok <= TOK_A_DIV) |
2349 tok == TOK_A_XOR | tok == TOK_A_OR |
2350 tok == TOK_A_SHL | tok == TOK_A_SAR) {
2351 test_lvalue();
2352 vpush();
2353 t = tok;
2354 next();
2355 if (t == '=') {
2356 expr_eq();
2357 /* XXX: be more precise */
2358 if ((vt & VT_PTR) != (vstack_ptr[-2] & VT_PTR))
2359 warning("incompatible type");
2360 } else {
2361 vpush();
2362 expr_eq();
2363 gen_op(t & 0x7f);
2365 vstore();
2369 void sum(l)
2371 int t;
2373 if (l == 0)
2374 uneq();
2375 else {
2376 sum(--l);
2377 while ((l == 0 & (tok == '*' | tok == '/' | tok == '%')) |
2378 (l == 1 & (tok == '+' | tok == '-')) |
2379 (l == 2 & (tok == TOK_SHL | tok == TOK_SAR)) |
2380 (l == 3 & ((tok >= TOK_ULE & tok <= TOK_GT) |
2381 tok == TOK_ULT | tok == TOK_UGE)) |
2382 (l == 4 & (tok == TOK_EQ | tok == TOK_NE)) |
2383 (l == 5 & tok == '&') |
2384 (l == 6 & tok == '^') |
2385 (l == 7 & tok == '|') |
2386 (l == 8 & tok == TOK_LAND) |
2387 (l == 9 & tok == TOK_LOR)) {
2388 vpush();
2389 t = tok;
2390 next();
2391 sum(l);
2392 gen_op(t);
2397 /* only used if non constant */
2398 void eand()
2400 int t;
2402 sum(8);
2403 t = 0;
2404 while (1) {
2405 if (tok != TOK_LAND) {
2406 if (t) {
2407 t = gtst(1, t);
2408 vset(VT_JMPI, t);
2410 break;
2412 t = gtst(1, t);
2413 next();
2414 sum(8);
2418 void eor()
2420 int t;
2422 eand();
2423 t = 0;
2424 while (1) {
2425 if (tok != TOK_LOR) {
2426 if (t) {
2427 t = gtst(0, t);
2428 vset(VT_JMP, t);
2430 break;
2432 t = gtst(0, t);
2433 next();
2434 eand();
2438 /* XXX: better constant handling */
2439 void expr_eq()
2441 int t, u, c;
2443 if (const_wanted) {
2444 sum(10);
2445 if (tok == '?') {
2446 c = vc;
2447 next();
2448 expr();
2449 t = vc;
2450 skip(':');
2451 expr_eq();
2452 if (c)
2453 vc = t;
2455 } else {
2456 eor();
2457 if (tok == '?') {
2458 next();
2459 t = gtst(1, 0);
2460 expr();
2461 gv();
2462 skip(':');
2463 u = gjmp(0);
2464 gsym(t);
2465 expr_eq();
2466 gv();
2467 gsym(u);
2472 void expr()
2474 while (1) {
2475 expr_eq();
2476 if (tok != ',')
2477 break;
2478 next();
2482 int expr_const()
2484 int a;
2485 a = const_wanted;
2486 const_wanted = 1;
2487 expr_eq();
2488 if ((vt & (VT_CONST | VT_LVAL)) != VT_CONST)
2489 expect("constant");
2490 const_wanted = a;
2491 return vc;
2494 void block(int *bsym, int *csym, int *case_sym, int *def_sym, int case_reg)
2496 int a, b, c, d;
2497 Sym *s;
2499 if (tok == TOK_IF) {
2500 /* if test */
2501 next();
2502 skip('(');
2503 expr();
2504 skip(')');
2505 a = gtst(1, 0);
2506 block(bsym, csym, case_sym, def_sym, case_reg);
2507 c = tok;
2508 if (c == TOK_ELSE) {
2509 next();
2510 d = gjmp(0);
2511 gsym(a);
2512 block(bsym, csym, case_sym, def_sym, case_reg);
2513 gsym(d); /* patch else jmp */
2514 } else
2515 gsym(a);
2516 } else if (tok == TOK_WHILE) {
2517 next();
2518 d = ind;
2519 skip('(');
2520 expr();
2521 skip(')');
2522 a = gtst(1, 0);
2523 b = 0;
2524 block(&a, &b, case_sym, def_sym, case_reg);
2525 oad(0xe9, d - ind - 5); /* jmp */
2526 gsym(a);
2527 gsym_addr(b, d);
2528 } else if (tok == '{') {
2529 next();
2530 /* declarations */
2531 s = local_stack;
2532 decl(VT_LOCAL);
2533 while (tok != '}')
2534 block(bsym, csym, case_sym, def_sym, case_reg);
2535 /* pop locally defined symbols */
2536 sym_pop(&local_stack, s);
2537 next();
2538 } else if (tok == TOK_RETURN) {
2539 next();
2540 if (tok != ';') {
2541 expr();
2542 move_reg(0, gv());
2544 skip(';');
2545 rsym = gjmp(rsym); /* jmp */
2546 } else if (tok == TOK_BREAK) {
2547 /* compute jump */
2548 if (!bsym)
2549 error("cannot break");
2550 *bsym = gjmp(*bsym);
2551 next();
2552 skip(';');
2553 } else if (tok == TOK_CONTINUE) {
2554 /* compute jump */
2555 if (!csym)
2556 error("cannot continue");
2557 *csym = gjmp(*csym);
2558 next();
2559 skip(';');
2560 } else if (tok == TOK_FOR) {
2561 int e;
2562 next();
2563 skip('(');
2564 if (tok != ';')
2565 expr();
2566 skip(';');
2567 d = ind;
2568 c = ind;
2569 a = 0;
2570 b = 0;
2571 if (tok != ';') {
2572 expr();
2573 a = gtst(1, 0);
2575 skip(';');
2576 if (tok != ')') {
2577 e = gjmp(0);
2578 c = ind;
2579 expr();
2580 oad(0xe9, d - ind - 5); /* jmp */
2581 gsym(e);
2583 skip(')');
2584 block(&a, &b, case_sym, def_sym, case_reg);
2585 oad(0xe9, c - ind - 5); /* jmp */
2586 gsym(a);
2587 gsym_addr(b, c);
2588 } else
2589 if (tok == TOK_DO) {
2590 next();
2591 a = 0;
2592 b = 0;
2593 d = ind;
2594 block(&a, &b, case_sym, def_sym, case_reg);
2595 skip(TOK_WHILE);
2596 skip('(');
2597 gsym(b);
2598 expr();
2599 c = gtst(0, 0);
2600 gsym_addr(c, d);
2601 skip(')');
2602 gsym(a);
2603 } else
2604 if (tok == TOK_SWITCH) {
2605 next();
2606 skip('(');
2607 expr();
2608 case_reg = gv();
2609 skip(')');
2610 a = 0;
2611 b = 0;
2612 c = 0;
2613 block(&a, csym, &b, &c, case_reg);
2614 /* if no default, jmp after switch */
2615 if (c == 0)
2616 c = ind;
2617 /* default label */
2618 gsym_addr(b, c);
2619 /* break label */
2620 gsym(a);
2621 } else
2622 if (tok == TOK_CASE) {
2623 next();
2624 a = expr_const();
2625 if (!case_sym)
2626 expect("switch");
2627 gsym(*case_sym);
2628 vset(case_reg, 0);
2629 vpush();
2630 vset(VT_CONST, a);
2631 gen_op(TOK_EQ);
2632 *case_sym = gtst(1, 0);
2633 skip(':');
2634 block(bsym, csym, case_sym, def_sym, case_reg);
2635 } else
2636 if (tok == TOK_DEFAULT) {
2637 next();
2638 skip(':');
2639 if (!def_sym)
2640 expect("switch");
2641 if (*def_sym)
2642 error("too many 'default'");
2643 *def_sym = ind;
2644 block(bsym, csym, case_sym, def_sym, case_reg);
2645 } else
2646 if (tok == TOK_GOTO) {
2647 next();
2648 s = sym_find1(label_stack, tok);
2649 /* put forward definition if needed */
2650 if (!s)
2651 s = sym_push1(&label_stack, tok, VT_FORWARD, 0);
2652 /* label already defined */
2653 if (s->t & VT_FORWARD)
2654 s->c = gjmp(s->c); /* jmp xxx */
2655 else
2656 oad(0xe9, s->c - ind - 5); /* jmp xxx */
2657 next();
2658 skip(';');
2659 } else {
2660 b = tok;
2661 next();
2662 if (tok == ':') {
2663 next();
2664 /* label case */
2665 s = sym_find1(label_stack, b);
2666 if (s) {
2667 if (!(s->t & VT_FORWARD))
2668 error("multiple defined label");
2669 gsym(s->c);
2670 s->c = ind;
2671 s->t = 0;
2672 } else {
2673 sym_push1(&label_stack, b, 0, ind);
2675 block(bsym, csym, case_sym, def_sym, case_reg);
2676 } else {
2677 /* expression case: go backward of one token */
2678 /* XXX: currently incorrect if number/string/char */
2679 tok1 = tok;
2680 tok = b;
2681 if (tok != ';') {
2682 expr();
2684 skip(';');
2689 /* 'l' is VT_LOCAL or VT_CONST to define default storage type */
2690 void decl(l)
2692 int *a, t, b, size, align, v, u, n;
2693 Sym *sym;
2695 while (b = ist()) {
2696 if ((b & (VT_ENUM | VT_STRUCT)) && tok == ';') {
2697 /* we accept no variable after */
2698 next();
2699 continue;
2701 while (1) { /* iterate thru each declaration */
2702 t = typ(&v, b);
2703 if (tok == '{') {
2704 if (!(t & VT_FUNC))
2705 expect("function defintion");
2706 /* patch forward references */
2707 if ((sym = sym_find(v)) && (sym->t & VT_FORWARD)) {
2708 gsym(sym->c);
2709 sym->c = ind;
2710 sym->t = VT_CONST | VT_LVAL | t;
2711 } else {
2712 /* put function address */
2713 sym_push1(&global_stack, v, VT_CONST | VT_LVAL | t, ind);
2715 /* push a dummy symbol to enable local sym storage */
2716 sym_push1(&local_stack, 0, 0, 0);
2717 /* define parameters */
2718 sym = sym_find((unsigned)t >> VT_STRUCT_SHIFT);
2719 while (sym = sym->next)
2720 sym_push(sym->v & ~SYM_FIELD, sym->t, sym->c);
2721 loc = 0;
2722 o(0xe58955); /* push %ebp, mov %esp, %ebp */
2723 a = (int *)oad(0xec81, 0); /* sub $xxx, %esp */
2724 rsym = 0;
2725 block(0, 0, 0, 0, 0);
2726 gsym(rsym);
2727 o(0xc3c9); /* leave, ret */
2728 *a = (-loc + 3) & -4; /* align local size to word &
2729 save local variables */
2730 sym_pop(&label_stack, 0); /* reset label stack */
2731 sym_pop(&local_stack, 0); /* reset local stack */
2732 break;
2733 } else {
2734 if (b & VT_TYPEDEF) {
2735 /* save typedefed type */
2736 sym_push(v, t | VT_TYPEDEF, 0);
2737 } else if (t & VT_FUNC) {
2738 /* XXX: incorrect to flush, but needed while
2739 waiting for function prototypes */
2740 /* external function definition */
2741 external_func(v, t);
2742 } else {
2743 /* not lvalue if array */
2744 if (!(t & VT_ARRAY))
2745 t |= VT_LVAL;
2746 if (t & VT_EXTERN) {
2747 /* external variable */
2748 /* XXX: factorize with external function def */
2749 n = (int)dlsym(NULL, get_tok_str(v, 0));
2750 if (!n)
2751 error("unknown external variable");
2752 sym_push(v, VT_CONST | t, n);
2753 } else {
2754 u = l;
2755 if (t & VT_STATIC)
2756 u = VT_CONST;
2757 u |= t;
2758 size = type_size(t, &align);
2759 if (size < 0)
2760 error("invalid size");
2761 if ((u & VT_VALMASK) == VT_LOCAL) {
2762 /* allocate space down on the stack */
2763 loc = (loc - size) & -align;
2764 sym_push(v, u, loc);
2765 } else {
2766 /* allocate space up in the data space */
2767 glo = (glo + align - 1) & -align;
2768 sym_push(v, u, glo);
2769 glo += size;
2773 if (tok != ',') {
2774 skip(';');
2775 break;
2777 next();
2783 int main(int argc, char **argv)
2785 Sym *s;
2786 int (*t)();
2787 char *p, *r;
2788 int optind;
2790 include_paths[0] = "/usr/include";
2791 include_paths[1] = "/usr/lib/tcc";
2792 include_paths[2] = "/usr/local/lib/tcc";
2793 nb_include_paths = 3;
2795 /* add all tokens */
2796 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";
2797 while (*p) {
2798 r = p;
2799 while (*r++);
2800 tok_alloc(p, r - p - 1);
2801 p = r;
2804 optind = 1;
2805 while (1) {
2806 if (optind >= argc) {
2807 printf("usage: tcc [-Idir] infile [infile_arg...]\n");
2808 return 1;
2810 r = argv[optind];
2811 if (r[0] != '-')
2812 break;
2813 if (r[1] == 'I') {
2814 if (nb_include_paths >= INCLUDE_PATHS_MAX)
2815 error("too many include paths");
2816 include_paths[nb_include_paths++] = r + 2;
2817 } else {
2818 error("invalid option");
2820 optind++;
2823 filename = argv[optind];
2824 line_num = 1;
2825 file = fopen(filename, "r");
2826 if (!file) {
2827 perror(filename);
2828 exit(1);
2830 include_stack_ptr = include_stack;
2831 ifdef_stack_ptr = ifdef_stack;
2833 glo = (int)malloc(DATA_SIZE);
2834 memset((void *)glo, 0, DATA_SIZE);
2835 prog = (int)malloc(TEXT_SIZE);
2836 vstack_ptr = vstack;
2837 anon_sym = 1 << (31 - VT_STRUCT_SHIFT);
2838 ind = prog;
2839 inp();
2840 ch = '\n'; /* needed to parse correctly first preprocessor command */
2841 next();
2842 decl(VT_CONST);
2843 if (tok != -1)
2844 expect("declaration");
2845 #ifdef TEST
2847 FILE *f;
2848 f = fopen(v[1], "w");
2849 fwrite((void *)prog, 1, ind - prog, f);
2850 fclose(f);
2851 return 0;
2853 #else
2854 s = sym_find(TOK_MAIN);
2855 if (!s)
2856 error("main() not defined");
2857 t = s->c;
2858 return (*t)(argc - optind, argv + optind);
2859 #endif