From 946b600ddd829039770636007a4491f999a68ef5 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 1 Nov 2001 14:48:10 +0000 Subject: [PATCH] added union/struct + correct local symbols --- tcc.c | 624 ++++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 430 insertions(+), 194 deletions(-) diff --git a/tcc.c b/tcc.c index fd75f2bb..e2085aa1 100644 --- a/tcc.c +++ b/tcc.c @@ -1,3 +1,22 @@ +/* + * TCC - Tiny C Compiler + * + * Copyright (c) 2001 Fabrice Bellard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ #include #define TEXT_SIZE 20000 @@ -5,9 +24,19 @@ #define SYM_TABLE_SIZE 10000 #define VAR_TABLE_SIZE 4096 -/* vac: offset of variables - vat: type of variables - loc : local variable index +/* symbol management */ +typedef struct Sym { + int v; /* symbol token */ + int t; /* associated type */ + int c; /* associated number */ + struct Sym *next; /* next related symbol */ + struct Sym *prev; /* prev symbol in stack */ +} Sym; + +#define SYM_STRUCT 0x40000000 /* struct/union/enum symbol space */ +#define SYM_FIELD 0x20000000 /* struct/union field symbol space */ + +/* loc : local variable index glo : global variable index parm : parameter variable index ind : output code ptr @@ -15,10 +44,12 @@ prog: output code astk: arg position stack */ -int tok, tok1, *vac, *vat, rsym, - prog, ind, loc, glo, file, vt, +void *file; +int tok, tok1, rsym, + prog, ind, loc, glo, vt, vc, *macro_stack, *macro_stack_ptr, line_num; char *idtable, *idptr, *filename; +Sym *define_stack, *global_stack, *local_stack, *label_stack; /* The current value can be: */ #define VT_CONST 0x0002 /* constant in vc */ @@ -43,29 +74,30 @@ char *idtable, *idptr, *filename; * Basic types: * * VT_BYTE indicate a char - * + * VT_UNSIGNED indicates unsigned type * * otherwise integer type is assumed. - * */ + * + */ -#define VT_BYTE 0x00001 /* byte pointer. HARDCODED VALUE */ +#define VT_BYTE 0x00001 /* byte type, HARDCODED VALUE */ #define VT_PTRMASK 0x00f00 /* pointer mask */ #define VT_PTRINC 0x00100 /* pointer increment */ #define VT_FUNC 0x01000 /* function type */ #define VT_UNSIGNED 0x02000 /* unsigned type */ #define VT_ARRAY 0x04000 /* array type (only used in parsing) */ -#define VT_TYPE 0x07f01 /* type mask */ -#define VT_TYPEN 0xffff80fe /* ~VT_TYPE */ -#define VT_FUNCN -4097 +#define VT_TYPE 0xffffff01 /* type mask */ +#define VT_TYPEN 0x000000fe /* ~VT_TYPE */ +#define VT_FUNCN -4097 /* ~VT_FUNC */ -#define VT_EXTERN 0x08000 /* extern definition */ -#define VT_STATIC 0x10000 /* static variable */ +#define VT_EXTERN 0x008000 /* extern definition */ +#define VT_STATIC 0x010000 /* static variable */ /* Special infos */ -#define VT_LABEL 0x40000 /* goto label symbol */ -#define VT_DEFINE 0x80000 /* special value for #defined symbols */ -#define VT_ENUM 0x100000 /* enum definition */ -#define VT_TYPEDEF 0x200000 /* typedef definition */ +#define VT_ENUM 0x020000 /* enum definition */ +#define VT_STRUCT 0x040000 /* struct/union definition */ +#define VT_TYPEDEF 0x080000 /* typedef definition */ +#define VT_STRUCT_SHIFT 20 /* structure/enum name shift (12 bits lefts) */ /* token values */ #define TOK_INT 256 @@ -95,12 +127,11 @@ char *idtable, *idptr, *filename; #define TOK_REGISTER 278 #define TOK_SIGNED 279 -/* unsupported types. Must have contiguous values */ -#define TOK_FLOAT 280 -#define TOK_DOUBLE 281 +#define TOK_FLOAT 280 /* unsupported */ +#define TOK_DOUBLE 281 /* unsupported */ + #define TOK_STRUCT 282 #define TOK_UNION 283 - #define TOK_TYPEDEF 284 #define TOK_DEFAULT 285 #define TOK_ENUM 286 @@ -115,12 +146,13 @@ char *idtable, *idptr, *filename; #define TOK_LAND 0xa0 #define TOK_LOR 0xa1 -#define TOK_DEC 0xa2 -#define TOK_MID 0xa3 /* inc/dec, to void constant */ -#define TOK_INC 0xa4 +#define TOK_DEC 0xa2 +#define TOK_MID 0xa3 /* inc/dec, to void constant */ +#define TOK_INC 0xa4 +#define TOK_ARROW 0xa7 -#define TOK_SHL 0x01 -#define TOK_SHR 0x02 +#define TOK_SHL 0x01 +#define TOK_SHR 0x02 /* assignement operators : normal operator or 0x80 */ #define TOK_A_MOD 0xa5 @@ -136,8 +168,15 @@ char *idtable, *idptr, *filename; #ifdef TINY #define expr_eq() expr() +#else +void sum(); +void next(); +void expr_eq(); +void expr(); +void decl(); #endif + int inp() { #if 0 @@ -170,6 +209,12 @@ void error(char *msg) exit(1); } +void expect(char *msg) +{ + printf("%s:%d: %s expected\n", filename, line_num, msg); + exit(1); +} + void warning(char *msg) { printf("%s:%d: warning: %s\n", filename, line_num, msg); @@ -187,7 +232,7 @@ void skip(c) void test_lvalue() { if (!(vt & VT_LVAL)) - error("lvalue expected\n"); + expect("lvalue"); } #else @@ -212,10 +257,74 @@ char *get_tok_str(int v) return p; } +/* find a symbol and return its associated structure. 's' is the top + of the symbol stack */ +Sym *sym_find1(Sym *s, int v) +{ + while (s) { + if (s->v == v) + return s; + s = s->prev; + } + return 0; +} + +Sym *sym_push1(Sym **ps, int v, int t, int c) +{ + Sym *s; + s = malloc(sizeof(Sym)); + if (!s) + error("memory full"); + s->v = v; + s->t = t; + s->c = c; + s->next = 0; + s->prev = *ps; + *ps = s; + return s; +} + +/* find a symbol in the right symbol space */ +Sym *sym_find(int v) +{ + Sym *s; + s = sym_find1(local_stack, v); + if (!s) + s = sym_find1(global_stack, v); + return s; +} + +/* push a given symbol on the symbol stack */ +Sym *sym_push(int v, int t, int c) +{ + // printf("sym_push: %s type=%x\n", get_tok_str(v), t); + if (local_stack) + return sym_push1(&local_stack, v, t, c); + else + return sym_push1(&global_stack, v, t, c); +} + +/* pop symbols until top reaches 'b' */ +void sym_pop(Sym **ps, Sym *b) +{ + Sym *s, *ss; + + s = *ps; + while(s != b) { + ss = s->prev; + // printf("sym_pop: %s type=%x\n", get_tok_str(s->v), s->t); + free(s); + s = ss; + } + *ps = b; +} + + void next() { int c, v; char *q, *p; + Sym *s; /* special 'ungettok' case for label parsing */ if (tok1) { @@ -260,8 +369,7 @@ void next() if (tok == TOK_DEFINE) { next(); /* now tok is the macro symbol */ - vat[tok] = VT_DEFINE; - vac[tok] = ftell(file); + sym_push1(&define_stack, tok, 0, ftell(file)); } /* ignore preprocessor or shell */ while (c != '\n') @@ -297,16 +405,16 @@ void next() if (p == idptr) idptr = q; /* eval defines */ - if (vat[tok] & VT_DEFINE) { + if (s = sym_find1(define_stack, tok)) { *macro_stack_ptr++ = ftell(file); - fseek(file, vac[tok], 0); + fseek(file, s->c, 0); next(); } } else { #ifdef TINY q = "<=\236>=\235!=\225++\244--\242==\224"; #else - q = "<=\236>=\235!=\225&&\240||\241++\244--\242==\224<<\1>>\2+=\253-=\255*=\252/=\257%=\245&=\246^=\336|=\374"; + q = "<=\236>=\235!=\225&&\240||\241++\244--\242==\224<<\1>>\2+=\253-=\255*=\252/=\257%=\245&=\246^=\336|=\374->\247"; #endif /* two chars */ v = inp(); @@ -460,19 +568,35 @@ int gtst(inv, t) return t; } -int type_size(t) +/* return type size. Put alignment at 'a' */ +int type_size(int t, int *a) { - if ((t & VT_PTRMASK) >= VT_PTRINC | (t & VT_TYPE) == 0) + Sym *s; + + /* int, enum or pointer */ + if ((t & VT_PTRMASK) >= VT_PTRINC | + (t & VT_TYPE) == 0 | + (t & VT_ENUM)) { + *a = 4; return 4; - else + } else if (t & VT_STRUCT) { + /* struct/union */ + s = sym_find(((unsigned)t >> VT_STRUCT_SHIFT) | SYM_STRUCT); + *a = 4; /* XXX: cannot store it yet. Doing that is safe */ + return s->c; + } else { + *a = 1; return 1; + } } /* return the number size in bytes of a given type */ int incr_value(t) { + int a; + if ((t & VT_PTRMASK) >= VT_PTRINC) - return type_size(t - VT_PTRINC); + return type_size(t - VT_PTRINC, &a); else return 1; } @@ -557,10 +681,95 @@ int expr_const() { expr_eq(); if ((vt & (VT_CONST | VT_LVAL)) != VT_CONST) - error("constant expected"); + expect("constant"); return vc; } +#ifndef TINY + +/* enum/struct/union declaration */ +int struct_decl(u) +{ + int a, t, b, v, size, align, maxalign, c; + Sym *slast, *s, *ss; + + a = tok; /* save decl type */ + next(); + v = 0; + if (tok != '{') { + v = tok; + next(); + /* struct already defined ? return it */ + /* XXX: check consistency */ + if (s = sym_find(v | SYM_STRUCT)) { + if (s->t != a) + error("invalid type"); + u = u | (v << VT_STRUCT_SHIFT); + return u; + } + } + s = sym_push(v | SYM_STRUCT, a, 0); + /* put struct/union/enum name in type */ + u = u | (v << VT_STRUCT_SHIFT); + + if (tok == '{') { + next(); + /* cannot be empty */ + c = 0; + maxalign = 0; + slast = 0; + while (1) { + if (a == TOK_ENUM) { + v = tok; + next(); + if (tok == '=') { + next(); + c = expr_const(); + } + sym_push(v, VT_CONST, c); + if (tok == ',') + next(); + c++; + } else { + b = ist(); + while (1) { + t = typ(&v, b, &size); + if (t & (VT_FUNC | VT_TYPEDEF)) + error("invalid type"); + /* XXX: align & correct type size */ + v |= SYM_FIELD; + size = type_size(t, &align); + if (a == TOK_STRUCT) { + c = (c + align - 1) & -align; + ss = sym_push(v, t, c); + c += size; + } else { + ss = sym_push(v, t, 0); + if (size > c) + c = size; + } + if (align > maxalign) + maxalign = align; + ss->next = slast; + slast = ss; + if (tok == ';' || tok == -1) + break; + skip(','); + } + skip(';'); + } + if (tok == '}') + break; + } + skip('}'); + s->next = slast; + /* size for struct/union, dummy for enum */ + s->c = (c + maxalign - 1) & -maxalign; + } + return u; +} +#endif + /* return 0 if no type declaration. otherwise, return the basic type and skip it. XXX: A '2' is ored to ensure non zero return if int type. @@ -568,41 +777,25 @@ int expr_const() int ist() { int t, n, v; + Sym *s; t = 0; while(1) { +#ifndef TINY if (tok == TOK_ENUM) { - next(); - if (tok != '{') - next(); - if (tok == '{') { - next(); - n = 0; - while (tok != '}' & tok != -1) { - v = tok; - next(); - if (tok == '=') { - next(); - n = expr_const(); - } - vat[v] = VT_CONST; - vac[v] = n; - if (tok != ',') - break; - next(); - n++; - } - skip('}'); - } - t |= VT_ENUM; - } else { + t = struct_decl(VT_ENUM); + } else if (tok == TOK_STRUCT || tok == TOK_UNION) { + t = struct_decl(VT_STRUCT); + } else +#endif + { if (tok == TOK_CHAR | tok == TOK_VOID) { t |= VT_BYTE; } else if (tok == TOK_INT | (tok >= TOK_CONST & tok <= TOK_SIGNED)) { /* ignored types */ - } else if (tok >= TOK_FLOAT & tok <= TOK_UNION) { - error("unsupported type"); + } else if (tok == TOK_FLOAT & tok == TOK_DOUBLE) { + error("floats not supported"); } else if (tok == TOK_EXTERN) { t |= VT_EXTERN; } else if (tok == TOK_STATIC) { @@ -612,10 +805,10 @@ int ist() } else if (tok == TOK_TYPEDEF) { t |= VT_TYPEDEF; } else { - v = vat[tok]; - if (!(v & VT_TYPEDEF)) + s = sym_find(tok); + if (!s || !(s->t & VT_TYPEDEF)) break; - t = v & ~VT_TYPEDEF; + t = s->t & ~VT_TYPEDEF; } next(); } @@ -654,21 +847,22 @@ int typ(int *v, int t, int *array_size_ptr) if (tok == '(') { /* function declaration */ next(); + /* push a dummy symbol to force local symbol stack usage */ + sym_push1(&local_stack, 0, 0, 0); p = 4; while (tok != ')') { /* read param name and compute offset */ - if (t = ist()) - t = typ(&n, t, 0); /* XXX: should accept both arg/non arg if v == 0 */ - else { - n = tok; - t = 0; - next(); - } - p = p + 4; - vat[n] = VT_LOCAL | VT_LVAL | t; - vac[n] = p; - if (tok == ',') - next(); + if (t = ist()) + t = typ(&n, t, 0); /* XXX: should accept both arg/non arg if v == 0 */ + else { + n = tok; + t = 0; + next(); + } + p = p + 4; + sym_push(n, VT_LOCAL | VT_LVAL | t, p); + if (tok == ',') + next(); } next(); /* skip ')' */ if (u) @@ -697,20 +891,24 @@ int typ(int *v, int t, int *array_size_ptr) } /* define a new external reference to a function 'v' of type 'u' */ -void external_func(v, u) +Sym *external_func(v, u) { int t, n; - t = vat[v]; - if (t == 0) { + Sym *s; + s = sym_find(v); + if (!s) { n = dlsym(0, get_tok_str(v)); if (n == 0) { - vat[v] = u | VT_CONST | VT_LVAL | VT_FORWARD; - vac[v] = 0; /* used to generate symbol list */ + /* used to generate symbol list */ + s = sym_push1(&global_stack, + v, u | VT_CONST | VT_LVAL | VT_FORWARD, 0); } else { - vat[v] = u | VT_CONST | VT_LVAL; /* int f() */ - vac[v] = n; + /* int f() */ + s = sym_push1(&global_stack, + v, u | VT_CONST | VT_LVAL, n); } } + return s; } /* read a number in base b */ @@ -762,6 +960,7 @@ int getq(n) void unary() { int n, t, ft, fc, p; + Sym *s; if (isnum(tok)) { /* number */ @@ -817,7 +1016,7 @@ void unary() gv(); #ifndef TINY if (!(vt & VT_PTRMASK)) - error("pointer expected"); + expect("pointer"); #endif vt = (vt - VT_PTRINC) | VT_LVAL; } else if (t == '&') { @@ -859,86 +1058,115 @@ void unary() } } else { - if (vat[t] == 0) { + s = sym_find(t); + if (!s) { if (tok != '(') error("undefined symbol"); /* for simple function calls, we tolerate undeclared external reference */ - external_func(t, VT_FUNC); /* int() function */ + s = external_func(t, VT_FUNC); /* int() function */ } - vset(vat[t], vac[t]); - /* if forward reference, we must point to vac[t] */ + vset(s->t, s->c); + /* if forward reference, we must point to s->c */ if (vt & VT_FORWARD) - vc = t; + vc = (int)&s->c; } } /* post operations */ - if (tok == TOK_INC | tok == TOK_DEC) { - inc(POST_ADD, tok); - next(); - } else - if (tok == '[') { + while (1) { + if (tok == TOK_INC | tok == TOK_DEC) { + inc(POST_ADD, tok); + next(); + } else if (tok == '.' | tok == TOK_ARROW) { + /* field */ + if (tok == '.') { + test_lvalue(); + vt = (vt & VT_LVALN) + VT_PTRINC; + } + next(); + /* expect pointer on structure */ + if (!(vt & VT_STRUCT) || (vt & VT_PTRMASK) == 0) + expect("struct or union"); + s = sym_find(((unsigned)vt >> VT_STRUCT_SHIFT) | SYM_STRUCT); + /* find field */ + tok |= SYM_FIELD; + while (s = s->next) { + if (s->v == tok) + break; + } + if (!s) + error("field not found"); + /* add field offset to pointer */ + gv(); + if (s->c) + oad(0x05, s->c); + /* change type to field type, and set to lvalue */ + vt = (vt & VT_TYPEN) | VT_LVAL | s->t; + next(); + } else if (tok == '[') { #ifndef TINY - if (!(vt & VT_PTRMASK)) - error("pointer expected"); + if (!(vt & VT_PTRMASK)) + expect("pointer"); #endif - gen_op('+', -1); - /* dereference pointer */ - vt = (vt - VT_PTRINC) | VT_LVAL; - skip(']'); - } else - if (tok == '(') { - /* function call */ - /* lvalue is implied */ - vt = vt & VT_LVALN; - if ((vt & VT_CONST) == 0) { - /* evaluate function address */ - gv(); - o(0x50); /* push %eax */ - } - ft = vt; - fc = vc; + gen_op('+', -1); + /* dereference pointer */ + vt = (vt - VT_PTRINC) | VT_LVAL; + skip(']'); + } else if (tok == '(') { + /* function call */ + /* lvalue is implied */ + vt = vt & VT_LVALN; + if ((vt & VT_CONST) == 0) { + /* evaluate function address */ + gv(); + o(0x50); /* push %eax */ + } + ft = vt; + fc = vc; - next(); - t = 0; - while (tok != ')') { - t = t + 4; - expr_eq(); - gv(); - o(0x50); /* push %eax */ - if (tok == ',') - next(); - } - skip(')'); - /* horrible, but needed : convert to native ordering (could - parse parameters in reverse order, but would cost more - code) */ - n = 0; - p = t - 4; - while (n < p) { - oad(0x24848b, p); /* mov x(%esp,1), %eax */ - oad(0x248487, n); /* xchg x(%esp,1), %eax */ - oad(0x248489, p); /* mov %eax, x(%esp,1) */ - n = n + 4; - p = p - 4; - } - if (ft & VT_CONST) { - /* forward reference */ - if (ft & VT_FORWARD) { - vac[fc] = psym(0xe8, vac[fc]); - } else - oad(0xe8, fc - ind - 5); - /* return value is variable, and take type from function proto */ - vt = VT_VAR | (ft & VT_TYPE & VT_FUNCN); + next(); + t = 0; + while (tok != ')') { + t = t + 4; + expr_eq(); + gv(); + o(0x50); /* push %eax */ + if (tok == ',') + next(); + } + skip(')'); + /* horrible, but needed : convert to native ordering (could + parse parameters in reverse order, but would cost more + code) */ + n = 0; + p = t - 4; + while (n < p) { + oad(0x24848b, p); /* mov x(%esp,1), %eax */ + oad(0x248487, n); /* xchg x(%esp,1), %eax */ + oad(0x248489, p); /* mov %eax, x(%esp,1) */ + n = n + 4; + p = p - 4; + } + if (ft & VT_CONST) { + /* forward reference */ + if (ft & VT_FORWARD) { + *(int *)fc = psym(0xe8, *(int *)fc); + } else + oad(0xe8, fc - ind - 5); + /* return value is variable, and take type from function proto */ + vt = VT_VAR | (ft & VT_TYPE & VT_FUNCN); + } else { + oad(0x2494ff, t); /* call *xxx(%esp) */ + t = t + 4; + /* return value is variable, int */ + vt = VT_VAR; + } + if (t) + oad(0xc481, t); } else { - oad(0x2494ff, t); /* call *xxx(%esp) */ - t = t + 4; - /* return value is variable, int */ - vt = VT_VAR; + break; } - if (t) - oad(0xc481, t); } } @@ -1082,6 +1310,7 @@ void expr() void block(int *bsym, int *csym, int *case_sym, int *def_sym) { int a, b, c, d; + Sym *s; if (tok == TOK_IF) { /* if test */ @@ -1115,9 +1344,12 @@ void block(int *bsym, int *csym, int *case_sym, int *def_sym) } else if (tok == '{') { next(); /* declarations */ + s = local_stack; decl(VT_LOCAL); while (tok != '}') block(bsym, csym, case_sym, def_sym); + /* pop locally defined symbols */ + sym_pop(&local_stack, s); next(); } else if (tok == TOK_RETURN) { next(); @@ -1209,7 +1441,7 @@ void block(int *bsym, int *csym, int *case_sym, int *def_sym) next(); a = expr_const(); if (!case_sym) - error("switch expected"); + expect("switch"); gsym(*case_sym); oad(0x3d, a); /* cmp $xxx, %eax */ *case_sym = psym(0x850f, 0); /* jne xxx */ @@ -1220,7 +1452,7 @@ void block(int *bsym, int *csym, int *case_sym, int *def_sym) next(); skip(':'); if (!def_sym) - error("switch expected"); + expect("switch"); if (*def_sym) error("too many 'default'"); *def_sym = ind; @@ -1228,19 +1460,15 @@ void block(int *bsym, int *csym, int *case_sym, int *def_sym) } else if (tok == TOK_GOTO) { next(); - a = vat[tok]; - if (a == 0) { - /* put forward definition */ - a = VT_LABEL | VT_FORWARD; - vat[tok] = a; - vac[tok] = 0; - } else if (!(a & VT_LABEL)) - error("invalid label name"); + s = sym_find1(label_stack, tok); + /* put forward definition if needed */ + if (!s) + s = sym_push1(&label_stack, tok, VT_FORWARD, 0); /* label already defined */ - if (a & VT_FORWARD) - vac[tok] = psym(0xe9, vac[tok]); /* jmp xxx */ + if (s->t & VT_FORWARD) + s->c = psym(0xe9, s->c); /* jmp xxx */ else - oad(0xe9, vac[tok] - ind - 5); /* jmp xxx */ + oad(0xe9, s->c - ind - 5); /* jmp xxx */ next(); skip(';'); } else @@ -1251,16 +1479,16 @@ void block(int *bsym, int *csym, int *case_sym, int *def_sym) if (tok == ':') { next(); /* label case */ - a = vat[b]; - if (a != 0) { - if (!(a & VT_LABEL)) - error("invalid label name"); - else if (!(a & VT_FORWARD)) + s = sym_find1(label_stack, b); + if (s) { + if (!(s->t & VT_FORWARD)) error("multiple defined label"); - gsym(vac[b]); + gsym(s->c); + s->c = ind; + s->t = 0; + } else { + sym_push1(&label_stack, b, 0, ind); } - vac[b] = ind; - vat[b] = VT_LABEL; block(bsym, csym, case_sym, def_sym); } else { /* expression case: go backward of one token */ @@ -1279,37 +1507,47 @@ void block(int *bsym, int *csym, int *case_sym, int *def_sym) void decl(l) { int *a, t, b, s, align, v, u, n; + Sym *sym, *slocal; while (b = ist()) { - if ((b & VT_ENUM) && tok == ';') { + if ((b & (VT_ENUM | VT_STRUCT)) && tok == ';') { /* we accept no variable after */ next(); continue; } - while (1) { /* iterate thru each declaration */ s = 1; + slocal = local_stack; /* save local stack position, to restore it */ t = typ(&v, b, &s); if (tok == '{') { /* patch forward references */ - if (vat[v] & VT_FORWARD) - gsym(vac[v]); - /* put function address */ - vat[v] = VT_CONST | VT_LVAL | t; - vac[v] = ind; + if ((sym = sym_find(v)) && (sym->t & VT_FORWARD)) { + gsym(sym->c); + sym->c = ind; + sym->t = VT_CONST | VT_LVAL | t; + } else { + /* put function address */ + sym_push1(&global_stack, v, VT_CONST | VT_LVAL | t, ind); + } loc = 0; o(0xe58955); /* push %ebp, mov %esp, %ebp */ - a = oad(0xec81, 0); /* sub $xxx, %esp */ + a = (int *)oad(0xec81, 0); /* sub $xxx, %esp */ rsym = 0; block(0, 0, 0, 0); gsym(rsym); o(0xc3c9); /* leave, ret */ *a = (-loc + 3) & -4; /* align local size to word & save local variables */ + sym_pop(&label_stack, 0); /* reset label stack */ + sym_pop(&local_stack, 0); /* reset local stack */ break; } else { + /* reset local stack (needed because of dummy function + parameters */ + sym_pop(&local_stack, slocal); if (t & VT_TYPEDEF) { - vat[v] = t; /* save typedefed type */ + /* save typedefed type */ + sym_push(v, t, 0); } else if (t & VT_FUNC) { /* external function definition */ external_func(v, t); @@ -1319,28 +1557,28 @@ void decl(l) t |= VT_LVAL; if (t & VT_EXTERN) { /* external variable */ + /* XXX: factorize with external function def */ n = dlsym(NULL, get_tok_str(v)); if (!n) error("unknown external variable"); - vat[v] = VT_CONST | t; - vac[v] = n; + sym_push(v, VT_CONST | t, n); } else { u = l; if (t & VT_STATIC) u = VT_CONST; - vat[v] = u | t; + u |= t; if (t & VT_ARRAY) t -= VT_PTRINC; - align = type_size(t); + align = type_size(t, &align); s *= align; - if (u == VT_LOCAL) { + if (u & VT_LOCAL) { /* allocate space down on the stack */ loc = (loc - s) & -align; - vac[v] = loc; + sym_push(v, u, loc); } else { /* allocate space up in the data space */ glo = (glo + align - 1) & -align; - vac[v] = glo; + sym_push(v, u, glo); glo += s; } } @@ -1357,6 +1595,7 @@ void decl(l) int main(int c, char **v) { + Sym *s; int (*t)(); if (c < 2) { printf("usage: tc src\n"); @@ -1384,8 +1623,6 @@ int main(int c, char **v) #endif glo = malloc(DATA_SIZE); prog = malloc(TEXT_SIZE); - vac = malloc(VAR_TABLE_SIZE); - vat = malloc(VAR_TABLE_SIZE); macro_stack = malloc(256); macro_stack_ptr = macro_stack; ind = prog; @@ -1401,11 +1638,10 @@ int main(int c, char **v) return 0; } #else - t = vac[TOK_MAIN]; -#ifndef TINY - if (!t) + s = sym_find(TOK_MAIN); + if (!s) error("main() not defined"); -#endif + t = s->c; return (*t)(c - 1, v); #endif }