From ad4582dfc2bb0c50d6972881ed845a473c40ca71 Mon Sep 17 00:00:00 2001 From: Teddy Date: Sat, 12 Apr 2014 11:09:27 +0800 Subject: fix bugs in function declaration & prototype --- TODO.rst | 1 + semantics.c | 71 +++++++++++++++++++++++++++++++++++++------------------- semantics.h | 1 + testcases/pass.c | 3 +++ 4 files changed, 52 insertions(+), 24 deletions(-) diff --git a/TODO.rst b/TODO.rst index 0495efd..3898fd0 100644 --- a/TODO.rst +++ b/TODO.rst @@ -17,6 +17,7 @@ TODO - pointer may **allow incomplete** type (done) - calculate type memory footprint at proper time - function to 'pointer to function' conversion (according the std 6.3.2/4) (done) + - vague var table management - Not Implemented: diff --git a/semantics.c b/semantics.c index f918437..d2970a3 100644 --- a/semantics.c +++ b/semantics.c @@ -390,6 +390,27 @@ static CType_t struct_type_merge(CType_t new, CScope_t scope) { return old; } +static void type_merge(CType_t old, CType_t new) { + /* assume old and new are the same type */ + assert(old->type == new->type); + switch (old->type) + { + case CINT: case CCHAR: case CPTR: + case CUNION: case CSTRUCT: + break; + case CFUNC: + if (new->rec.func.params) + old->rec.func.params = new->rec.func.params; + if (new->rec.func.body) + { + old->rec.func.local = new->rec.func.local; + old->rec.func.body = new->rec.func.body; + } + break; + default: assert(0); + } +} + int is_same_type(CType_t typea, CType_t typeb) { if (typea == typeb) return 1; if (typea->type != typeb->type) return 0; @@ -405,13 +426,12 @@ int is_same_type(CType_t typea, CType_t typeb) { return is_same_type(typea->rec.ref, typeb->rec.ref); case CFUNC: { - CVar_t pa, pb; - if ((typea->rec.func.params || typea->rec.func.body) && - (typeb->rec.func.params || typeb->rec.func.body)) + CVar_t pa = typea->rec.func.params, + pb = typeb->rec.func.params; + if ((pa || typea->rec.func.body) && + (pb || typeb->rec.func.body)) { - for (pa = typea->rec.func.params, - pb = typeb->rec.func.params; pa && pb; - pa = pa->next, pb = pb->next) + for (;pa && pb; pa = pa->next, pb = pb->next) if (!is_same_type(pa->type, pb->type)) return 0; if (pa || pb) @@ -432,8 +452,11 @@ static CVar_t var_merge(CVar_t new, CScope_t scope) { return new; else old = cscope_lookup_var(scope, new->name); - if (!is_same_type(old->type, new->type) || scope->lvl > 0) + if (!is_same_type(old->type, new->type)) ERROR((new->ast, "conflicting types of '%s'", new->name)); + else if (scope->lvl > 0) + ERROR((new->ast, "redeclaration of '%s' with no linkage", new->name)); + type_merge(old->type, new->type); free(new); return old; } @@ -1390,6 +1413,7 @@ CVar_t semantics_func(CNode *p, CScope_t scope) { ERROR((func->rec.func.ret->ast, "return type is an incomplete type")); scope->func = func; + func->rec.func.body = p->chd->next->next; cscope_enter(scope); /* enter function local scope */ { /* Note: here is a dirty hack to forcibly push function definition to the global scope, while all the types specified in parameters retain in local scope. @@ -1398,8 +1422,24 @@ CVar_t semantics_func(CNode *p, CScope_t scope) { CVar_t var; scope->top = ntop->next; scope->lvl--; + if (cscope_push_var(scope, res)) old = res; + if (!old) + { + old = cscope_lookup_var(scope, res->name); + funco = old->type; + if (funco->type != CFUNC) + ERROR((res->ast, "conflicting types of '%s'", res->name)); + else if (funco->rec.func.body) + ERROR((res->ast, "redefintion of function '%s'", res->name)); + else if (!is_same_type(funco, res->type)) + ERROR((res->ast, "function defintion does not match the prototype")); + type_merge(old->type, res->type); + free(res); + } + free(head); + scope->top = ntop; scope->lvl++; @@ -1411,25 +1451,8 @@ CVar_t semantics_func(CNode *p, CScope_t scope) { } } func->rec.func.local = semantics_comp(p->chd->next->next, scope); /* check comp */ - func->rec.func.body = p->chd->next->next; cscope_exit(scope); /* exit from local scope */ - if (!old) - { - old = cscope_lookup_var(scope, res->name); - funco = old->type; - if (funco->type != CFUNC) - ERROR((res->ast, "conflicting types of '%s'", res->name)); - else if (funco->rec.func.body) - ERROR((res->ast, "redefintion of function '%s'", res->name)); - else if (!is_same_type(funco, res->type)) - ERROR((res->ast, "function defintion does not match the prototype")); - funco->rec.func.params = res->type->rec.func.params; - funco->rec.func.local = res->type->rec.func.local; - funco->rec.func.body = res->type->rec.func.body; - free(res); - } - free(head); return old; } diff --git a/semantics.h b/semantics.h index cf3666a..4c3b892 100644 --- a/semantics.h +++ b/semantics.h @@ -115,6 +115,7 @@ struct CScope { CSNode *top; CTable_t tvar; CTable_t ttype; + CTable_t ext_link; }; typedef struct ExpType { diff --git a/testcases/pass.c b/testcases/pass.c index a1d3705..bf995ac 100644 --- a/testcases/pass.c +++ b/testcases/pass.c @@ -106,6 +106,9 @@ void local_decl() { struct Node n; struct Node {int x, y;} n; /* global forward declaration is ok */ +int again; +int again; + int main() { n.x = 1; n.y = 2; -- cgit v1.2.3