From 704d61357c6556d917da386e57c7a2743f03902f Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 29 Oct 2001 23:23:01 +0000 Subject: [PATCH] clarified function types - added extern / static - added unsigned and invalid type parsing --- tcc.c | 316 +++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 225 insertions(+), 91 deletions(-) diff --git a/tcc.c b/tcc.c index 6bc1e58..98d35e3 100644 --- a/tcc.c +++ b/tcc.c @@ -19,7 +19,7 @@ int tok, *vac, *vat, *lsym, rsym, prog, ind, loc, glo, file, vt, vc, *macro_stack, *macro_stack_ptr, line_num; -char *idtable, *idptr, *idlast, *filename; +char *idtable, *idptr, *filename; /* The current value can be: */ #define VT_CONST 0x0002 /* constant in vc */ @@ -49,30 +49,55 @@ char *idtable, *idptr, *idlast, *filename; * otherwise integer type is assumed. * */ -#define VT_BYTE 0x00001 /* byte pointer. HARDCODED VALUE */ -#define VT_PTRMASK 0x00f00 /* pointer mask */ -#define VT_PTRINC 0x00100 /* pointer increment */ -#define VT_FUNC 0x01000 /* function type */ -#define VT_TYPE 0x01f01 /* type mask */ - -#define VT_TYPEN 0xffffe0fe /* ~VT_TYPE */ +#define VT_BYTE 0x00001 /* byte pointer. 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_EXTERN 0x08000 /* extern definition */ +#define VT_STATIC 0x10000 /* static variable */ + /* Special infos */ -#define VT_DEFINE 0x02000 /* special value for #defined symbols */ +#define VT_DEFINE 0x80000 /* special value for #defined symbols */ /* token values */ -#define TOK_INT 256 -#define TOK_VOID 257 -#define TOK_CHAR 258 -#define TOK_IF 259 -#define TOK_ELSE 260 -#define TOK_WHILE 261 -#define TOK_BREAK 262 -#define TOK_RETURN 263 -#define TOK_DEFINE 264 -#define TOK_MAIN 265 -#define TOK_FOR 266 +#define TOK_INT 256 +#define TOK_VOID 257 +#define TOK_CHAR 258 +#define TOK_IF 259 +#define TOK_ELSE 260 +#define TOK_WHILE 261 +#define TOK_BREAK 262 +#define TOK_RETURN 263 +#define TOK_DEFINE 264 +#define TOK_MAIN 265 +#define TOK_FOR 266 +#define TOK_EXTERN 267 +#define TOK_STATIC 268 +#define TOK_UNSIGNED 269 +#define TOK_GOTO 270 +#define TOK_DO 271 +#define TOK_CONTINUE 272 +#define TOK_SWITCH 273 +#define TOK_CASE 274 + +/* ignored types Must have contiguous values */ +#define TOK_CONST 271 +#define TOK_LONG 276 +#define TOK_REGISTER 277 +#define TOK_SIGNED 278 + +/* unsupported types. Must have contiguous values */ +#define TOK_FLOAT 279 +#define TOK_DOUBLE 280 +#define TOK_STRUCT 281 +#define TOK_UNION 282 +#define TOK_TYPEDEF 283 #define TOK_EQ 0x94 /* warning: depend on asm code */ #define TOK_NE 0x95 /* warning: depend on asm code */ @@ -166,6 +191,21 @@ void test_lvalue() #endif +char *get_tok_str(int v) +{ + int t; + char *p; + p = idtable; + t = 256; + while (t != v) { + if (p >= idptr) + return 0; + while (*p++); + t++; + } + return p; +} + void next() { int c, v; @@ -226,7 +266,6 @@ void next() } if (isid(c)) { q = idptr; - idlast = q; while(isid(c) | isnum(c)) { *q++ = c; c = inp(); @@ -328,6 +367,7 @@ void vset(t, v) } /* generate a value in eax from vt and vc */ +/* XXX: generate correct pointer for forward references to functions */ void gv() { #ifndef TINY @@ -402,15 +442,23 @@ int gtst(inv, t) return t; } -/* return the size in bytes of a given type */ int type_size(t) { - if ((t & VT_PTRMASK) > VT_PTRINC | (t & VT_TYPE) == VT_PTRINC) + if ((t & VT_PTRMASK) >= VT_PTRINC | (t & VT_TYPE) == 0) return 4; else return 1; } +/* return the number size in bytes of a given type */ +int incr_value(t) +{ + if ((t & VT_PTRMASK) >= VT_PTRINC) + return type_size(t - VT_PTRINC); + else + return 1; +} + #define POST_ADD 0x1000 #define PRE_ADD 0 @@ -422,12 +470,13 @@ void inc(a, c) gv(); o(0x018bc189); /* movl %eax, %ecx ; mov (%ecx), %eax */ o(0x408d | a); /* leal x(%eax), %eax/%edx */ - g((c - TOK_MID) * type_size(vt)); + g((c - TOK_MID) * incr_value(vt)); o(0x0189 | a); /* mov %eax/%edx, (%ecx) */ } /* XXX: handle ptr sub and 'int + ptr' case (only 'ptr + int' handled) */ /* XXX: handle constant propagation (need to track live eax) */ +/* XXX: handle unsigned propagation */ void gen_op(op, l) { int t; @@ -445,7 +494,7 @@ void gen_op(op, l) o(0x59); /* pop %ecx */ if (op == '+' | op == '-') { /* XXX: incorrect for short (futur!) */ - if (type_size(t) == 4) + if (incr_value(t) == 4) o(0x02e0c1); /* shl $2, %eax */ if (op == '-') o(0xd8f7); /* neg %eax */ @@ -461,16 +510,23 @@ void gen_op(op, l) o(0xc1af0f); /* imul %ecx, %eax */ #ifndef TINY else if (op == TOK_SHL | op == TOK_SHR) { - o(0xd391); /* xchg %ecx, %eax, shl/sar %cl, %eax */ + o(0xd391); /* xchg %ecx, %eax, shl/shr/sar %cl, %eax */ if (op == TOK_SHL) o(0xe0); + else if (t & VT_UNSIGNED) + o(0xe8); else o(0xf8); } #endif else if (op == '/' | op == '%') { o(0x91); /* xchg %ecx, %eax */ - o(0xf9f799); /* cltd, idiv %ecx, %eax */ + if (t & VT_UNSIGNED) { + o(0xd231); /* xor %edx, %edx */ + o(0xf1f7); /* div %ecx, %eax */ + } else { + o(0xf9f799); /* cltd, idiv %ecx, %eax */ + } if (op == '%') o(0x92); /* xchg %edx, %eax */ } else { @@ -486,19 +542,33 @@ void gen_op(op, l) int ist() { int t; - - if (tok == TOK_INT | tok == TOK_CHAR | tok == TOK_VOID) { - t = tok; + t = 0; + while(1) { + 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_TYPEDEF) { + error("unsupported type"); + } else if (tok == TOK_EXTERN) { + t |= VT_EXTERN; + } else if (tok == TOK_STATIC) { + t |= VT_STATIC; + } else if (tok == TOK_UNSIGNED) { + t |= VT_UNSIGNED; + } else { + break; + } next(); - return (t != TOK_INT) | 2; - } else { - return 0; + t |= 2; } + return t; } /* Read a type declaration (except basic type), and return the type. If v is true, then also put variable name in 'vc' */ -int typ(v,t) +int typ(int *v, int t, int *array_size_ptr) { int u, p, n; @@ -512,46 +582,80 @@ int typ(v,t) /* XXX: incorrect if abstract type for functions (e.g. 'int ()') */ if (tok == '(') { next(); - u = typ(v, 0); + u = typ(v, 0, 0); skip(')'); } else { u = 0; /* type identifier */ if (v) { - vc = tok; + *v = tok; next(); } } - /* function declaration */ - if (tok == '(') { - next(); - p = 4; - n = vc; /* must save vc there */ - while (tok != ')') { - /* read param name and compute offset */ + while(1) { + if (tok == '(') { + /* function declaration */ + next(); + p = 4; + while (tok != ')') { + /* read param name and compute offset */ if (t = ist()) - t = typ(1, t); /* XXX: should accept both arg/non arg if v == 0 */ + t = typ(&n, t, 0); /* XXX: should accept both arg/non arg if v == 0 */ else { - vc = tok; + n = tok; t = 0; next(); } p = p + 4; - vat[vc] = VT_LOCAL | VT_LVAL | t; - vac[vc] = p; + vat[n] = VT_LOCAL | VT_LVAL | t; + vac[n] = p; if (tok == ',') next(); - } - next(); /* skip ')' */ - vc = n; - if (u) - t = u + VT_BYTE; - else - t = t | VT_FUNC; + } + next(); /* skip ')' */ + if (u) + t = u + VT_BYTE; + else + t = t | VT_FUNC; + } else if (tok == '[') { + /* array definition */ + if (t & VT_ARRAY) + error("multi dimension arrays not supported"); + next(); + vc = 0; + if (tok != ']') { + expr(); + if (array_size_ptr) + *array_size_ptr = vc; + } + if ((vt & (VT_CONST | VT_LVAL)) != VT_CONST | + (vc <= 0 & array_size_ptr != 0)) + error("invalid array size"); + skip(']'); + t = (t + VT_PTRINC) | VT_ARRAY; + } else + break; } return t; } +/* define a new external reference to a function 'v' of type 'u' */ +void external_func(v, u) +{ + int t, n; + t = vat[v]; + if (t == 0) { + 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 */ + } else { + vat[v] = u | VT_CONST | VT_LVAL; /* int f() */ + vac[v] = n; + } + } +} + /* read a number in base b */ int getn(c, b) { @@ -631,20 +735,18 @@ void unary() vset(VT_CONST | VT_PTRINC | VT_BYTE, glo); while (tok == '\"') { while((n = inp()) != 34) { - *(char *)glo = getq(n); - glo++; + *(char *)glo++ = getq(n); } next(); } - *(char *)glo = 0; - glo = (glo + 4) & -4; /* align heap */ + *(char *)glo++ = 0; } else { t = tok; next(); if (t == '(') { /* cast ? */ if (t = ist()) { - ft = typ(0, t); + ft = typ(0, t, 0); skip(')'); unary(); vt = (vt & VT_TYPEN) | ft; @@ -700,15 +802,17 @@ void unary() } } else { - vset(vat[t], vac[t]); - /* forward reference or external reference ? */ - if (vt == 0) { - n = dlsym(0, idlast); - if (n == 0) - vset(VT_CONST | VT_FORWARD | VT_LVAL, vac + t); - else - vset(VT_CONST | VT_LVAL, n); + if (vat[t] == 0) { + if (tok != '(') + error("undefined symbol"); + /* for simple function calls, we tolerate undeclared + external reference */ + external_func(t, VT_FUNC); /* int() function */ } + vset(vat[t], vac[t]); + /* if forward reference, we must point to vac[t] */ + if (vt & VT_FORWARD) + vc = t; } } @@ -764,18 +868,20 @@ void unary() } if (ft & VT_CONST) { /* forward reference */ - if (ft & VT_FORWARD) - *(int *)fc = psym(0xe8, *(int *)fc); - else + 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); } else { oad(0x2494ff, t); /* call *xxx(%esp) */ t = t + 4; + /* return value is variable, int */ + vt = VT_VAR; } if (t) oad(0xc481, t); - /* return value is variable, int */ - vt = VT_VAR; } } @@ -1005,22 +1111,22 @@ void block() } } -/* 'l' is true if local declarations */ +/* 'l' is VT_LOCAL or VT_CONST to define default storage type */ void decl(l) { - int *a, t, b; + int *a, t, b, s, align, v, u, n; while (b = ist()) { while (1) { /* iterate thru each declaration */ - vt = typ(1, b); + s = 1; + t = typ(&v, b, &s); if (tok == '{') { - /* patch forward references (XXX: does not work for - function pointers) */ - if (vat[vc] == 0) - gsym(vac[vc]); + /* patch forward references */ + if (vat[v] & VT_FORWARD) + gsym(vac[v]); /* put function address */ - vat[vc] = VT_CONST | VT_LVAL | vt; - vac[vc] = ind; + vat[v] = VT_CONST | VT_LVAL | t; + vac[v] = ind; loc = 0; o(0xe58955); /* push %ebp, mov %esp, %ebp */ a = oad(0xec81, 0); /* sub $xxx, %esp */ @@ -1028,17 +1134,44 @@ void decl(l) block(); gsym(rsym); o(0xc3c9); /* leave, ret */ - *a = loc; /* save local variables */ + *a = (-loc + 3) & -4; /* align local size to word & + save local variables */ break; } else { - /* variable */ - vat[vc] = l | VT_LVAL | vt; - if (l == VT_LOCAL) { - loc = loc + 4; - vac[vc] = -loc; + if (t & VT_FUNC) { + /* external function definition */ + external_func(v, t); } else { - vac[vc] = glo; - glo = glo + 4; + /* not lvalue if array */ + if (!(t & VT_ARRAY)) + t |= VT_LVAL; + if (t & VT_EXTERN) { + /* external variable */ + n = dlsym(NULL, get_tok_str(v)); + if (!n) + error("unknown external variable"); + vat[v] = VT_CONST | t; + vac[v] = n; + } else { + u = l; + if (t & VT_STATIC) + u = VT_CONST; + vat[v] = u | t; + if (t & VT_ARRAY) + t -= VT_PTRINC; + align = type_size(t); + s *= align; + if (u == VT_LOCAL) { + /* allocate space down on the stack */ + loc = (loc - s) & -align; + vac[v] = loc; + } else { + /* allocate space up in the data space */ + glo = (glo + align - 1) & -align; + vac[v] = glo; + glo += s; + } + } } if (tok != ',') { skip(';'); @@ -1074,8 +1207,9 @@ int main(int c, char **v) idptr = idtable + 53; #else memcpy(idtable, - "int\0void\0char\0if\0else\0while\0break\0return\0define\0main\0for", 57); - idptr = idtable + 57; + "int\0void\0char\0if\0else\0while\0break\0return\0define\0main\0for\0extern\0static\0unsigned\0goto\0do\0continue\0switch\0case\0const\0long\0register\0signed\0float\0double\0struct\0union\0typedef", 170); + + idptr = idtable + 170; #endif glo = malloc(DATA_SIZE); prog = malloc(TEXT_SIZE);