added function prototypes and correct recursive type parsing
This commit is contained in:
parent
aca442913c
commit
b0bdbb14ef
1 changed files with 98 additions and 38 deletions
136
tcc.c
136
tcc.c
|
@ -41,8 +41,12 @@ typedef struct Sym {
|
||||||
#define SYM_STRUCT 0x40000000 /* struct/union/enum symbol space */
|
#define SYM_STRUCT 0x40000000 /* struct/union/enum symbol space */
|
||||||
#define SYM_FIELD 0x20000000 /* struct/union field symbol space */
|
#define SYM_FIELD 0x20000000 /* struct/union field symbol space */
|
||||||
|
|
||||||
|
#define FUNC_NEW 1 /* ansi function prototype */
|
||||||
|
#define FUNC_OLD 2 /* old function prototype */
|
||||||
|
#define FUNC_ELLIPSIS 3 /* ansi function prototype with ... */
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
FILE *file; /* stdio file */
|
FILE *file;
|
||||||
char *filename;
|
char *filename;
|
||||||
int line_num;
|
int line_num;
|
||||||
} IncludeFile;
|
} IncludeFile;
|
||||||
|
@ -139,12 +143,17 @@ IncludeFile include_stack[INCLUDE_STACK_SIZE], *include_stack_ptr;
|
||||||
#define TOK_SIZEOF 289
|
#define TOK_SIZEOF 289
|
||||||
#define TOK_INCLUDE 290
|
#define TOK_INCLUDE 290
|
||||||
|
|
||||||
#define TOK_EQ 0x94 /* warning: depend on asm code */
|
/* warning: the following compare tokens depend on i386 asm code */
|
||||||
#define TOK_NE 0x95 /* warning: depend on asm code */
|
#define TOK_ULT 0x92
|
||||||
#define TOK_LT 0x9c /* warning: depend on asm code */
|
#define TOK_UGE 0x93
|
||||||
#define TOK_GE 0x9d /* warning: depend on asm code */
|
#define TOK_EQ 0x94
|
||||||
#define TOK_LE 0x9e /* warning: depend on asm code */
|
#define TOK_NE 0x95
|
||||||
#define TOK_GT 0x9f /* warning: depend on asm code */
|
#define TOK_ULE 0x96
|
||||||
|
#define TOK_UGT 0x97
|
||||||
|
#define TOK_LT 0x9c
|
||||||
|
#define TOK_GE 0x9d
|
||||||
|
#define TOK_LE 0x9e
|
||||||
|
#define TOK_GT 0x9f
|
||||||
|
|
||||||
#define TOK_LAND 0xa0
|
#define TOK_LAND 0xa0
|
||||||
#define TOK_LOR 0xa1
|
#define TOK_LOR 0xa1
|
||||||
|
@ -197,28 +206,41 @@ int isnum(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef TINY
|
#ifndef TINY
|
||||||
|
|
||||||
|
void printline()
|
||||||
|
{
|
||||||
|
IncludeFile *f;
|
||||||
|
for(f = include_stack; f < include_stack_ptr; f++)
|
||||||
|
printf("In file included from %s:%d:\n", f->filename, f->line_num);
|
||||||
|
printf("%s:%d: ", filename, line_num);
|
||||||
|
}
|
||||||
|
|
||||||
/* XXX: use stderr ? */
|
/* XXX: use stderr ? */
|
||||||
void error(char *msg)
|
void error(char *msg)
|
||||||
{
|
{
|
||||||
printf("%s:%d: %s\n", filename, line_num, msg);
|
printline();
|
||||||
|
printf("%s\n", msg);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void expect(char *msg)
|
void expect(char *msg)
|
||||||
{
|
{
|
||||||
printf("%s:%d: %s expected\n", filename, line_num, msg);
|
printline();
|
||||||
|
printf("%s expected\n", msg);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void warning(char *msg)
|
void warning(char *msg)
|
||||||
{
|
{
|
||||||
printf("%s:%d: warning: %s\n", filename, line_num, msg);
|
printline();
|
||||||
|
printf("warning: %s\n", msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void skip(c)
|
void skip(c)
|
||||||
{
|
{
|
||||||
if (tok != c) {
|
if (tok != c) {
|
||||||
printf("%s:%d: '%c' expected\n", filename, line_num, c);
|
printline();
|
||||||
|
printf("'%c' expected\n", c);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
next();
|
next();
|
||||||
|
@ -1106,6 +1128,14 @@ void gen_op(op)
|
||||||
op = TOK_UDIV;
|
op = TOK_UDIV;
|
||||||
else if (op == '%')
|
else if (op == '%')
|
||||||
op = TOK_UMOD;
|
op = TOK_UMOD;
|
||||||
|
else if (op == TOK_LT)
|
||||||
|
op = TOK_ULT;
|
||||||
|
else if (op == TOK_GT)
|
||||||
|
op = TOK_UGT;
|
||||||
|
else if (op == TOK_LE)
|
||||||
|
op = TOK_ULE;
|
||||||
|
else if (op == TOK_GE)
|
||||||
|
op = TOK_UGE;
|
||||||
}
|
}
|
||||||
gen_opc(op);
|
gen_opc(op);
|
||||||
}
|
}
|
||||||
|
@ -1335,31 +1365,31 @@ int ist()
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
int post_type(u, t)
|
int post_type(t)
|
||||||
{
|
{
|
||||||
int p, n, pt, l;
|
int p, n, pt, l, a;
|
||||||
|
Sym *last, *s;
|
||||||
|
|
||||||
if (tok == '(') {
|
if (tok == '(') {
|
||||||
/* function declaration */
|
/* function declaration */
|
||||||
next();
|
next();
|
||||||
/* push a dummy symbol to force local symbol stack usage */
|
a = 4;
|
||||||
sym_push1(&local_stack, 0, 0, 0);
|
|
||||||
p = 4;
|
|
||||||
l = 0;
|
l = 0;
|
||||||
|
last = NULL;
|
||||||
while (tok != ')') {
|
while (tok != ')') {
|
||||||
/* read param name and compute offset */
|
/* read param name and compute offset */
|
||||||
if (l != 2) {
|
if (l != FUNC_OLD) {
|
||||||
if (!(pt = ist())) {
|
if (!(pt = ist())) {
|
||||||
if (l) {
|
if (l) {
|
||||||
error("invalid type");
|
error("invalid type");
|
||||||
} else {
|
} else {
|
||||||
l = 2;
|
l = FUNC_OLD;
|
||||||
goto old_proto;
|
goto old_proto;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (pt & VT_VOID && tok == ')')
|
if (pt & VT_VOID && tok == ')')
|
||||||
break;
|
break;
|
||||||
l = 1;
|
l = FUNC_NEW;
|
||||||
pt = typ(&n, pt); /* XXX: should accept
|
pt = typ(&n, pt); /* XXX: should accept
|
||||||
both arg/non arg if v == 0 */
|
both arg/non arg if v == 0 */
|
||||||
} else {
|
} else {
|
||||||
|
@ -1370,23 +1400,27 @@ int post_type(u, t)
|
||||||
}
|
}
|
||||||
/* array must be transformed to pointer according to ANSI C */
|
/* array must be transformed to pointer according to ANSI C */
|
||||||
pt &= ~VT_ARRAY;
|
pt &= ~VT_ARRAY;
|
||||||
p = p + 4;
|
/* XXX: size will be different someday */
|
||||||
sym_push(n, VT_LOCAL | VT_LVAL | pt, p);
|
a = a + 4;
|
||||||
|
s = sym_push(n | SYM_FIELD, VT_LOCAL | VT_LVAL | pt, a);
|
||||||
|
s->next = last;
|
||||||
|
last = s;
|
||||||
if (tok == ',') {
|
if (tok == ',') {
|
||||||
next();
|
next();
|
||||||
if (l == 1 && tok == TOK_DOTS) {
|
if (l == FUNC_NEW && tok == TOK_DOTS) {
|
||||||
|
l = FUNC_ELLIPSIS;
|
||||||
next();
|
next();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
skip(')');
|
skip(')');
|
||||||
t = post_type(0, t); /* XXX: may be incorrect */
|
t = post_type(t);
|
||||||
/* transform function pointer to 'char *' */
|
/* we push a anonymous symbol which will contain the function prototype */
|
||||||
if (u)
|
p = anon_sym++;
|
||||||
t = u + VT_BYTE;
|
s = sym_push(p, t, l);
|
||||||
else
|
s->next = last;
|
||||||
t = t | VT_FUNC;
|
t = VT_FUNC | (p << VT_STRUCT_SHIFT);
|
||||||
} else if (tok == '[') {
|
} else if (tok == '[') {
|
||||||
/* array definition */
|
/* array definition */
|
||||||
next();
|
next();
|
||||||
|
@ -1398,7 +1432,7 @@ int post_type(u, t)
|
||||||
}
|
}
|
||||||
skip(']');
|
skip(']');
|
||||||
/* parse next post type */
|
/* parse next post type */
|
||||||
t = post_type(u, t);
|
t = post_type(t);
|
||||||
|
|
||||||
/* we push a anonymous symbol which will contain the array
|
/* we push a anonymous symbol which will contain the array
|
||||||
element type */
|
element type */
|
||||||
|
@ -1413,7 +1447,8 @@ int post_type(u, t)
|
||||||
type. If v is true, then also put variable name in 'vc' */
|
type. If v is true, then also put variable name in 'vc' */
|
||||||
int typ(int *v, int t)
|
int typ(int *v, int t)
|
||||||
{
|
{
|
||||||
int u;
|
int u, p;
|
||||||
|
Sym *s;
|
||||||
|
|
||||||
t = t & -3; /* suppress the ored '2' */
|
t = t & -3; /* suppress the ored '2' */
|
||||||
while (tok == '*') {
|
while (tok == '*') {
|
||||||
|
@ -1435,13 +1470,26 @@ int typ(int *v, int t)
|
||||||
next();
|
next();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return post_type(u, t);
|
/* append t at the end of u */
|
||||||
|
t = post_type(t);
|
||||||
|
if (!u)
|
||||||
|
return t;
|
||||||
|
p = u;
|
||||||
|
while(1) {
|
||||||
|
s = sym_find((unsigned)p >> VT_STRUCT_SHIFT);
|
||||||
|
p = s->t;
|
||||||
|
if (!p) {
|
||||||
|
s->t = t;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return u;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* define a new external reference to a function 'v' of type 'u' */
|
/* define a new external reference to a function 'v' of type 'u' */
|
||||||
Sym *external_func(v, u)
|
Sym *external_func(v, u)
|
||||||
{
|
{
|
||||||
int t, n;
|
int t, n, p;
|
||||||
Sym *s;
|
Sym *s;
|
||||||
s = sym_find(v);
|
s = sym_find(v);
|
||||||
if (!s) {
|
if (!s) {
|
||||||
|
@ -1589,7 +1637,10 @@ void unary()
|
||||||
error("undefined symbol");
|
error("undefined symbol");
|
||||||
/* for simple function calls, we tolerate undeclared
|
/* for simple function calls, we tolerate undeclared
|
||||||
external reference */
|
external reference */
|
||||||
s = external_func(t, VT_FUNC); /* int() function */
|
p = anon_sym++;
|
||||||
|
sym_push1(&global_stack, p, 0, FUNC_OLD);
|
||||||
|
/* int() function */
|
||||||
|
s = external_func(t, VT_FUNC | (p << VT_STRUCT_SHIFT));
|
||||||
}
|
}
|
||||||
vset(s->t, s->c);
|
vset(s->t, s->c);
|
||||||
/* if forward reference, we must point to s->c */
|
/* if forward reference, we must point to s->c */
|
||||||
|
@ -1678,16 +1729,15 @@ void unary()
|
||||||
*(int *)fc = psym(0xe8, *(int *)fc);
|
*(int *)fc = psym(0xe8, *(int *)fc);
|
||||||
} else
|
} else
|
||||||
oad(0xe8, fc - ind - 5);
|
oad(0xe8, fc - ind - 5);
|
||||||
/* return value is %eax, and take type from function proto */
|
|
||||||
vt = 0 | (ft & VT_TYPE & VT_FUNCN);
|
|
||||||
} else {
|
} else {
|
||||||
oad(0x2494ff, t); /* call *xxx(%esp) */
|
oad(0x2494ff, t); /* call *xxx(%esp) */
|
||||||
t = t + 4;
|
t = t + 4;
|
||||||
/* return value is %eax, integer */
|
|
||||||
vt = 0;
|
|
||||||
}
|
}
|
||||||
if (t)
|
if (t)
|
||||||
oad(0xc481, t);
|
oad(0xc481, t);
|
||||||
|
/* get return type */
|
||||||
|
s = sym_find((unsigned)ft >> VT_STRUCT_SHIFT);
|
||||||
|
vt = s->t | 0; /* return register is eax */
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1732,7 +1782,8 @@ void sum(l)
|
||||||
while ((l == 0 & (tok == '*' | tok == '/' | tok == '%')) |
|
while ((l == 0 & (tok == '*' | tok == '/' | tok == '%')) |
|
||||||
(l == 1 & (tok == '+' | tok == '-')) |
|
(l == 1 & (tok == '+' | tok == '-')) |
|
||||||
(l == 2 & (tok == TOK_SHL | tok == TOK_SAR)) |
|
(l == 2 & (tok == TOK_SHL | tok == TOK_SAR)) |
|
||||||
(l == 3 & (tok >= TOK_LT & tok <= TOK_GT)) |
|
(l == 3 & ((tok >= TOK_ULE & tok <= TOK_GT) |
|
||||||
|
tok == TOK_ULT | tok == TOK_UGE)) |
|
||||||
(l == 4 & (tok == TOK_EQ | tok == TOK_NE)) |
|
(l == 4 & (tok == TOK_EQ | tok == TOK_NE)) |
|
||||||
(l == 5 & tok == '&') |
|
(l == 5 & tok == '&') |
|
||||||
(l == 6 & tok == '^') |
|
(l == 6 & tok == '^') |
|
||||||
|
@ -2037,6 +2088,8 @@ void decl(l)
|
||||||
while (1) { /* iterate thru each declaration */
|
while (1) { /* iterate thru each declaration */
|
||||||
t = typ(&v, b);
|
t = typ(&v, b);
|
||||||
if (tok == '{') {
|
if (tok == '{') {
|
||||||
|
if (!(t & VT_FUNC))
|
||||||
|
expect("function defintion");
|
||||||
/* patch forward references */
|
/* patch forward references */
|
||||||
if ((sym = sym_find(v)) && (sym->t & VT_FORWARD)) {
|
if ((sym = sym_find(v)) && (sym->t & VT_FORWARD)) {
|
||||||
gsym(sym->c);
|
gsym(sym->c);
|
||||||
|
@ -2046,6 +2099,13 @@ void decl(l)
|
||||||
/* put function address */
|
/* put function address */
|
||||||
sym_push1(&global_stack, v, VT_CONST | VT_LVAL | t, ind);
|
sym_push1(&global_stack, v, VT_CONST | VT_LVAL | t, ind);
|
||||||
}
|
}
|
||||||
|
/* push a dummy symbol to enable local sym storage */
|
||||||
|
sym_push1(&local_stack, 0, 0, 0);
|
||||||
|
/* define parameters */
|
||||||
|
sym = sym_find((unsigned)t >> VT_STRUCT_SHIFT);
|
||||||
|
while (sym = sym->next) {
|
||||||
|
sym_push(sym->v & ~SYM_FIELD, sym->t, sym->c);
|
||||||
|
}
|
||||||
loc = 0;
|
loc = 0;
|
||||||
o(0xe58955); /* push %ebp, mov %esp, %ebp */
|
o(0xe58955); /* push %ebp, mov %esp, %ebp */
|
||||||
a = (int *)oad(0xec81, 0); /* sub $xxx, %esp */
|
a = (int *)oad(0xec81, 0); /* sub $xxx, %esp */
|
||||||
|
|
Loading…
Reference in a new issue