added union/struct + correct local symbols

This commit is contained in:
bellard 2001-11-01 14:48:10 +00:00
parent b15f269fbe
commit 946b600ddd

484
tcc.c
View file

@ -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 <stdio.h> #include <stdio.h>
#define TEXT_SIZE 20000 #define TEXT_SIZE 20000
@ -5,9 +24,19 @@
#define SYM_TABLE_SIZE 10000 #define SYM_TABLE_SIZE 10000
#define VAR_TABLE_SIZE 4096 #define VAR_TABLE_SIZE 4096
/* vac: offset of variables /* symbol management */
vat: type of variables typedef struct Sym {
loc : local variable index 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 glo : global variable index
parm : parameter variable index parm : parameter variable index
ind : output code ptr ind : output code ptr
@ -15,10 +44,12 @@
prog: output code prog: output code
astk: arg position stack astk: arg position stack
*/ */
int tok, tok1, *vac, *vat, rsym, void *file;
prog, ind, loc, glo, file, vt, int tok, tok1, rsym,
prog, ind, loc, glo, vt,
vc, *macro_stack, *macro_stack_ptr, line_num; vc, *macro_stack, *macro_stack_ptr, line_num;
char *idtable, *idptr, *filename; char *idtable, *idptr, *filename;
Sym *define_stack, *global_stack, *local_stack, *label_stack;
/* The current value can be: */ /* The current value can be: */
#define VT_CONST 0x0002 /* constant in vc */ #define VT_CONST 0x0002 /* constant in vc */
@ -43,29 +74,30 @@ char *idtable, *idptr, *filename;
* Basic types: * Basic types:
* *
* VT_BYTE indicate a char * VT_BYTE indicate a char
* * VT_UNSIGNED indicates unsigned type
* *
* otherwise integer type is assumed. * 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_PTRMASK 0x00f00 /* pointer mask */
#define VT_PTRINC 0x00100 /* pointer increment */ #define VT_PTRINC 0x00100 /* pointer increment */
#define VT_FUNC 0x01000 /* function type */ #define VT_FUNC 0x01000 /* function type */
#define VT_UNSIGNED 0x02000 /* unsigned type */ #define VT_UNSIGNED 0x02000 /* unsigned type */
#define VT_ARRAY 0x04000 /* array type (only used in parsing) */ #define VT_ARRAY 0x04000 /* array type (only used in parsing) */
#define VT_TYPE 0x07f01 /* type mask */ #define VT_TYPE 0xffffff01 /* type mask */
#define VT_TYPEN 0xffff80fe /* ~VT_TYPE */ #define VT_TYPEN 0x000000fe /* ~VT_TYPE */
#define VT_FUNCN -4097 #define VT_FUNCN -4097 /* ~VT_FUNC */
#define VT_EXTERN 0x08000 /* extern definition */ #define VT_EXTERN 0x008000 /* extern definition */
#define VT_STATIC 0x10000 /* static variable */ #define VT_STATIC 0x010000 /* static variable */
/* Special infos */ /* Special infos */
#define VT_LABEL 0x40000 /* goto label symbol */ #define VT_ENUM 0x020000 /* enum definition */
#define VT_DEFINE 0x80000 /* special value for #defined symbols */ #define VT_STRUCT 0x040000 /* struct/union definition */
#define VT_ENUM 0x100000 /* enum definition */ #define VT_TYPEDEF 0x080000 /* typedef definition */
#define VT_TYPEDEF 0x200000 /* typedef definition */ #define VT_STRUCT_SHIFT 20 /* structure/enum name shift (12 bits lefts) */
/* token values */ /* token values */
#define TOK_INT 256 #define TOK_INT 256
@ -95,12 +127,11 @@ char *idtable, *idptr, *filename;
#define TOK_REGISTER 278 #define TOK_REGISTER 278
#define TOK_SIGNED 279 #define TOK_SIGNED 279
/* unsupported types. Must have contiguous values */ #define TOK_FLOAT 280 /* unsupported */
#define TOK_FLOAT 280 #define TOK_DOUBLE 281 /* unsupported */
#define TOK_DOUBLE 281
#define TOK_STRUCT 282 #define TOK_STRUCT 282
#define TOK_UNION 283 #define TOK_UNION 283
#define TOK_TYPEDEF 284 #define TOK_TYPEDEF 284
#define TOK_DEFAULT 285 #define TOK_DEFAULT 285
#define TOK_ENUM 286 #define TOK_ENUM 286
@ -118,6 +149,7 @@ char *idtable, *idptr, *filename;
#define TOK_DEC 0xa2 #define TOK_DEC 0xa2
#define TOK_MID 0xa3 /* inc/dec, to void constant */ #define TOK_MID 0xa3 /* inc/dec, to void constant */
#define TOK_INC 0xa4 #define TOK_INC 0xa4
#define TOK_ARROW 0xa7
#define TOK_SHL 0x01 #define TOK_SHL 0x01
#define TOK_SHR 0x02 #define TOK_SHR 0x02
@ -136,8 +168,15 @@ char *idtable, *idptr, *filename;
#ifdef TINY #ifdef TINY
#define expr_eq() expr() #define expr_eq() expr()
#else
void sum();
void next();
void expr_eq();
void expr();
void decl();
#endif #endif
int inp() int inp()
{ {
#if 0 #if 0
@ -170,6 +209,12 @@ void error(char *msg)
exit(1); exit(1);
} }
void expect(char *msg)
{
printf("%s:%d: %s expected\n", filename, line_num, msg);
exit(1);
}
void warning(char *msg) void warning(char *msg)
{ {
printf("%s:%d: warning: %s\n", filename, line_num, msg); printf("%s:%d: warning: %s\n", filename, line_num, msg);
@ -187,7 +232,7 @@ void skip(c)
void test_lvalue() void test_lvalue()
{ {
if (!(vt & VT_LVAL)) if (!(vt & VT_LVAL))
error("lvalue expected\n"); expect("lvalue");
} }
#else #else
@ -212,10 +257,74 @@ char *get_tok_str(int v)
return p; 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() void next()
{ {
int c, v; int c, v;
char *q, *p; char *q, *p;
Sym *s;
/* special 'ungettok' case for label parsing */ /* special 'ungettok' case for label parsing */
if (tok1) { if (tok1) {
@ -260,8 +369,7 @@ void next()
if (tok == TOK_DEFINE) { if (tok == TOK_DEFINE) {
next(); next();
/* now tok is the macro symbol */ /* now tok is the macro symbol */
vat[tok] = VT_DEFINE; sym_push1(&define_stack, tok, 0, ftell(file));
vac[tok] = ftell(file);
} }
/* ignore preprocessor or shell */ /* ignore preprocessor or shell */
while (c != '\n') while (c != '\n')
@ -297,16 +405,16 @@ void next()
if (p == idptr) if (p == idptr)
idptr = q; idptr = q;
/* eval defines */ /* eval defines */
if (vat[tok] & VT_DEFINE) { if (s = sym_find1(define_stack, tok)) {
*macro_stack_ptr++ = ftell(file); *macro_stack_ptr++ = ftell(file);
fseek(file, vac[tok], 0); fseek(file, s->c, 0);
next(); next();
} }
} else { } else {
#ifdef TINY #ifdef TINY
q = "<=\236>=\235!=\225++\244--\242==\224"; q = "<=\236>=\235!=\225++\244--\242==\224";
#else #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 #endif
/* two chars */ /* two chars */
v = inp(); v = inp();
@ -460,19 +568,35 @@ int gtst(inv, t)
return 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; 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 1;
} }
}
/* return the number size in bytes of a given type */ /* return the number size in bytes of a given type */
int incr_value(t) int incr_value(t)
{ {
int a;
if ((t & VT_PTRMASK) >= VT_PTRINC) if ((t & VT_PTRMASK) >= VT_PTRINC)
return type_size(t - VT_PTRINC); return type_size(t - VT_PTRINC, &a);
else else
return 1; return 1;
} }
@ -557,10 +681,95 @@ int expr_const()
{ {
expr_eq(); expr_eq();
if ((vt & (VT_CONST | VT_LVAL)) != VT_CONST) if ((vt & (VT_CONST | VT_LVAL)) != VT_CONST)
error("constant expected"); expect("constant");
return vc; 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 /* return 0 if no type declaration. otherwise, return the basic type
and skip it. and skip it.
XXX: A '2' is ored to ensure non zero return if int type. XXX: A '2' is ored to ensure non zero return if int type.
@ -568,41 +777,25 @@ int expr_const()
int ist() int ist()
{ {
int t, n, v; int t, n, v;
Sym *s;
t = 0; t = 0;
while(1) { while(1) {
#ifndef TINY
if (tok == TOK_ENUM) { if (tok == TOK_ENUM) {
next(); t = struct_decl(VT_ENUM);
if (tok != '{') } else if (tok == TOK_STRUCT || tok == TOK_UNION) {
next(); t = struct_decl(VT_STRUCT);
if (tok == '{') { } else
next(); #endif
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 {
if (tok == TOK_CHAR | tok == TOK_VOID) { if (tok == TOK_CHAR | tok == TOK_VOID) {
t |= VT_BYTE; t |= VT_BYTE;
} else if (tok == TOK_INT | } else if (tok == TOK_INT |
(tok >= TOK_CONST & tok <= TOK_SIGNED)) { (tok >= TOK_CONST & tok <= TOK_SIGNED)) {
/* ignored types */ /* ignored types */
} else if (tok >= TOK_FLOAT & tok <= TOK_UNION) { } else if (tok == TOK_FLOAT & tok == TOK_DOUBLE) {
error("unsupported type"); error("floats not supported");
} else if (tok == TOK_EXTERN) { } else if (tok == TOK_EXTERN) {
t |= VT_EXTERN; t |= VT_EXTERN;
} else if (tok == TOK_STATIC) { } else if (tok == TOK_STATIC) {
@ -612,10 +805,10 @@ int ist()
} else if (tok == TOK_TYPEDEF) { } else if (tok == TOK_TYPEDEF) {
t |= VT_TYPEDEF; t |= VT_TYPEDEF;
} else { } else {
v = vat[tok]; s = sym_find(tok);
if (!(v & VT_TYPEDEF)) if (!s || !(s->t & VT_TYPEDEF))
break; break;
t = v & ~VT_TYPEDEF; t = s->t & ~VT_TYPEDEF;
} }
next(); next();
} }
@ -654,6 +847,8 @@ int typ(int *v, int t, int *array_size_ptr)
if (tok == '(') { if (tok == '(') {
/* function declaration */ /* function declaration */
next(); next();
/* push a dummy symbol to force local symbol stack usage */
sym_push1(&local_stack, 0, 0, 0);
p = 4; p = 4;
while (tok != ')') { while (tok != ')') {
/* read param name and compute offset */ /* read param name and compute offset */
@ -665,8 +860,7 @@ int typ(int *v, int t, int *array_size_ptr)
next(); next();
} }
p = p + 4; p = p + 4;
vat[n] = VT_LOCAL | VT_LVAL | t; sym_push(n, VT_LOCAL | VT_LVAL | t, p);
vac[n] = p;
if (tok == ',') if (tok == ',')
next(); next();
} }
@ -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' */ /* 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; int t, n;
t = vat[v]; Sym *s;
if (t == 0) { s = sym_find(v);
if (!s) {
n = dlsym(0, get_tok_str(v)); n = dlsym(0, get_tok_str(v));
if (n == 0) { if (n == 0) {
vat[v] = u | VT_CONST | VT_LVAL | VT_FORWARD; /* used to generate symbol list */
vac[v] = 0; /* used to generate symbol list */ s = sym_push1(&global_stack,
v, u | VT_CONST | VT_LVAL | VT_FORWARD, 0);
} else { } else {
vat[v] = u | VT_CONST | VT_LVAL; /* int f() */ /* int f() */
vac[v] = n; s = sym_push1(&global_stack,
v, u | VT_CONST | VT_LVAL, n);
} }
} }
return s;
} }
/* read a number in base b */ /* read a number in base b */
@ -762,6 +960,7 @@ int getq(n)
void unary() void unary()
{ {
int n, t, ft, fc, p; int n, t, ft, fc, p;
Sym *s;
if (isnum(tok)) { if (isnum(tok)) {
/* number */ /* number */
@ -817,7 +1016,7 @@ void unary()
gv(); gv();
#ifndef TINY #ifndef TINY
if (!(vt & VT_PTRMASK)) if (!(vt & VT_PTRMASK))
error("pointer expected"); expect("pointer");
#endif #endif
vt = (vt - VT_PTRINC) | VT_LVAL; vt = (vt - VT_PTRINC) | VT_LVAL;
} else if (t == '&') { } else if (t == '&') {
@ -859,36 +1058,62 @@ void unary()
} }
} else } else
{ {
if (vat[t] == 0) { s = sym_find(t);
if (!s) {
if (tok != '(') if (tok != '(')
error("undefined symbol"); error("undefined symbol");
/* for simple function calls, we tolerate undeclared /* for simple function calls, we tolerate undeclared
external reference */ external reference */
external_func(t, VT_FUNC); /* int() function */ s = external_func(t, VT_FUNC); /* int() function */
} }
vset(vat[t], vac[t]); vset(s->t, s->c);
/* if forward reference, we must point to vac[t] */ /* if forward reference, we must point to s->c */
if (vt & VT_FORWARD) if (vt & VT_FORWARD)
vc = t; vc = (int)&s->c;
} }
} }
/* post operations */ /* post operations */
while (1) {
if (tok == TOK_INC | tok == TOK_DEC) { if (tok == TOK_INC | tok == TOK_DEC) {
inc(POST_ADD, tok); inc(POST_ADD, tok);
next(); next();
} else } else if (tok == '.' | tok == TOK_ARROW) {
if (tok == '[') { /* 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 #ifndef TINY
if (!(vt & VT_PTRMASK)) if (!(vt & VT_PTRMASK))
error("pointer expected"); expect("pointer");
#endif #endif
gen_op('+', -1); gen_op('+', -1);
/* dereference pointer */ /* dereference pointer */
vt = (vt - VT_PTRINC) | VT_LVAL; vt = (vt - VT_PTRINC) | VT_LVAL;
skip(']'); skip(']');
} else } else if (tok == '(') {
if (tok == '(') {
/* function call */ /* function call */
/* lvalue is implied */ /* lvalue is implied */
vt = vt & VT_LVALN; vt = vt & VT_LVALN;
@ -926,7 +1151,7 @@ void unary()
if (ft & VT_CONST) { if (ft & VT_CONST) {
/* forward reference */ /* forward reference */
if (ft & VT_FORWARD) { if (ft & VT_FORWARD) {
vac[fc] = psym(0xe8, vac[fc]); *(int *)fc = psym(0xe8, *(int *)fc);
} else } else
oad(0xe8, fc - ind - 5); oad(0xe8, fc - ind - 5);
/* return value is variable, and take type from function proto */ /* return value is variable, and take type from function proto */
@ -939,6 +1164,9 @@ void unary()
} }
if (t) if (t)
oad(0xc481, t); oad(0xc481, t);
} else {
break;
}
} }
} }
@ -1082,6 +1310,7 @@ void expr()
void block(int *bsym, int *csym, int *case_sym, int *def_sym) void block(int *bsym, int *csym, int *case_sym, int *def_sym)
{ {
int a, b, c, d; int a, b, c, d;
Sym *s;
if (tok == TOK_IF) { if (tok == TOK_IF) {
/* if test */ /* if test */
@ -1115,9 +1344,12 @@ void block(int *bsym, int *csym, int *case_sym, int *def_sym)
} else if (tok == '{') { } else if (tok == '{') {
next(); next();
/* declarations */ /* declarations */
s = local_stack;
decl(VT_LOCAL); decl(VT_LOCAL);
while (tok != '}') while (tok != '}')
block(bsym, csym, case_sym, def_sym); block(bsym, csym, case_sym, def_sym);
/* pop locally defined symbols */
sym_pop(&local_stack, s);
next(); next();
} else if (tok == TOK_RETURN) { } else if (tok == TOK_RETURN) {
next(); next();
@ -1209,7 +1441,7 @@ void block(int *bsym, int *csym, int *case_sym, int *def_sym)
next(); next();
a = expr_const(); a = expr_const();
if (!case_sym) if (!case_sym)
error("switch expected"); expect("switch");
gsym(*case_sym); gsym(*case_sym);
oad(0x3d, a); /* cmp $xxx, %eax */ oad(0x3d, a); /* cmp $xxx, %eax */
*case_sym = psym(0x850f, 0); /* jne xxx */ *case_sym = psym(0x850f, 0); /* jne xxx */
@ -1220,7 +1452,7 @@ void block(int *bsym, int *csym, int *case_sym, int *def_sym)
next(); next();
skip(':'); skip(':');
if (!def_sym) if (!def_sym)
error("switch expected"); expect("switch");
if (*def_sym) if (*def_sym)
error("too many 'default'"); error("too many 'default'");
*def_sym = ind; *def_sym = ind;
@ -1228,19 +1460,15 @@ void block(int *bsym, int *csym, int *case_sym, int *def_sym)
} else } else
if (tok == TOK_GOTO) { if (tok == TOK_GOTO) {
next(); next();
a = vat[tok]; s = sym_find1(label_stack, tok);
if (a == 0) { /* put forward definition if needed */
/* put forward definition */ if (!s)
a = VT_LABEL | VT_FORWARD; s = sym_push1(&label_stack, tok, VT_FORWARD, 0);
vat[tok] = a;
vac[tok] = 0;
} else if (!(a & VT_LABEL))
error("invalid label name");
/* label already defined */ /* label already defined */
if (a & VT_FORWARD) if (s->t & VT_FORWARD)
vac[tok] = psym(0xe9, vac[tok]); /* jmp xxx */ s->c = psym(0xe9, s->c); /* jmp xxx */
else else
oad(0xe9, vac[tok] - ind - 5); /* jmp xxx */ oad(0xe9, s->c - ind - 5); /* jmp xxx */
next(); next();
skip(';'); skip(';');
} else } else
@ -1251,16 +1479,16 @@ void block(int *bsym, int *csym, int *case_sym, int *def_sym)
if (tok == ':') { if (tok == ':') {
next(); next();
/* label case */ /* label case */
a = vat[b]; s = sym_find1(label_stack, b);
if (a != 0) { if (s) {
if (!(a & VT_LABEL)) if (!(s->t & VT_FORWARD))
error("invalid label name");
else if (!(a & VT_FORWARD))
error("multiple defined label"); 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); block(bsym, csym, case_sym, def_sym);
} else { } else {
/* expression case: go backward of one token */ /* 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) void decl(l)
{ {
int *a, t, b, s, align, v, u, n; int *a, t, b, s, align, v, u, n;
Sym *sym, *slocal;
while (b = ist()) { while (b = ist()) {
if ((b & VT_ENUM) && tok == ';') { if ((b & (VT_ENUM | VT_STRUCT)) && tok == ';') {
/* we accept no variable after */ /* we accept no variable after */
next(); next();
continue; continue;
} }
while (1) { /* iterate thru each declaration */ while (1) { /* iterate thru each declaration */
s = 1; s = 1;
slocal = local_stack; /* save local stack position, to restore it */
t = typ(&v, b, &s); t = typ(&v, b, &s);
if (tok == '{') { if (tok == '{') {
/* patch forward references */ /* patch forward references */
if (vat[v] & VT_FORWARD) if ((sym = sym_find(v)) && (sym->t & VT_FORWARD)) {
gsym(vac[v]); gsym(sym->c);
sym->c = ind;
sym->t = VT_CONST | VT_LVAL | t;
} else {
/* put function address */ /* put function address */
vat[v] = VT_CONST | VT_LVAL | t; sym_push1(&global_stack, v, VT_CONST | VT_LVAL | t, ind);
vac[v] = ind; }
loc = 0; loc = 0;
o(0xe58955); /* push %ebp, mov %esp, %ebp */ o(0xe58955); /* push %ebp, mov %esp, %ebp */
a = oad(0xec81, 0); /* sub $xxx, %esp */ a = (int *)oad(0xec81, 0); /* sub $xxx, %esp */
rsym = 0; rsym = 0;
block(0, 0, 0, 0); block(0, 0, 0, 0);
gsym(rsym); gsym(rsym);
o(0xc3c9); /* leave, ret */ o(0xc3c9); /* leave, ret */
*a = (-loc + 3) & -4; /* align local size to word & *a = (-loc + 3) & -4; /* align local size to word &
save local variables */ save local variables */
sym_pop(&label_stack, 0); /* reset label stack */
sym_pop(&local_stack, 0); /* reset local stack */
break; break;
} else { } else {
/* reset local stack (needed because of dummy function
parameters */
sym_pop(&local_stack, slocal);
if (t & VT_TYPEDEF) { if (t & VT_TYPEDEF) {
vat[v] = t; /* save typedefed type */ /* save typedefed type */
sym_push(v, t, 0);
} else if (t & VT_FUNC) { } else if (t & VT_FUNC) {
/* external function definition */ /* external function definition */
external_func(v, t); external_func(v, t);
@ -1319,28 +1557,28 @@ void decl(l)
t |= VT_LVAL; t |= VT_LVAL;
if (t & VT_EXTERN) { if (t & VT_EXTERN) {
/* external variable */ /* external variable */
/* XXX: factorize with external function def */
n = dlsym(NULL, get_tok_str(v)); n = dlsym(NULL, get_tok_str(v));
if (!n) if (!n)
error("unknown external variable"); error("unknown external variable");
vat[v] = VT_CONST | t; sym_push(v, VT_CONST | t, n);
vac[v] = n;
} else { } else {
u = l; u = l;
if (t & VT_STATIC) if (t & VT_STATIC)
u = VT_CONST; u = VT_CONST;
vat[v] = u | t; u |= t;
if (t & VT_ARRAY) if (t & VT_ARRAY)
t -= VT_PTRINC; t -= VT_PTRINC;
align = type_size(t); align = type_size(t, &align);
s *= align; s *= align;
if (u == VT_LOCAL) { if (u & VT_LOCAL) {
/* allocate space down on the stack */ /* allocate space down on the stack */
loc = (loc - s) & -align; loc = (loc - s) & -align;
vac[v] = loc; sym_push(v, u, loc);
} else { } else {
/* allocate space up in the data space */ /* allocate space up in the data space */
glo = (glo + align - 1) & -align; glo = (glo + align - 1) & -align;
vac[v] = glo; sym_push(v, u, glo);
glo += s; glo += s;
} }
} }
@ -1357,6 +1595,7 @@ void decl(l)
int main(int c, char **v) int main(int c, char **v)
{ {
Sym *s;
int (*t)(); int (*t)();
if (c < 2) { if (c < 2) {
printf("usage: tc src\n"); printf("usage: tc src\n");
@ -1384,8 +1623,6 @@ int main(int c, char **v)
#endif #endif
glo = malloc(DATA_SIZE); glo = malloc(DATA_SIZE);
prog = malloc(TEXT_SIZE); prog = malloc(TEXT_SIZE);
vac = malloc(VAR_TABLE_SIZE);
vat = malloc(VAR_TABLE_SIZE);
macro_stack = malloc(256); macro_stack = malloc(256);
macro_stack_ptr = macro_stack; macro_stack_ptr = macro_stack;
ind = prog; ind = prog;
@ -1401,11 +1638,10 @@ int main(int c, char **v)
return 0; return 0;
} }
#else #else
t = vac[TOK_MAIN]; s = sym_find(TOK_MAIN);
#ifndef TINY if (!s)
if (!t)
error("main() not defined"); error("main() not defined");
#endif t = s->c;
return (*t)(c - 1, v); return (*t)(c - 1, v);
#endif #endif
} }