aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTeddy <ted.sybil@gmail.com>2014-04-12 11:09:27 +0800
committerTeddy <ted.sybil@gmail.com>2014-04-12 11:09:27 +0800
commitad4582dfc2bb0c50d6972881ed845a473c40ca71 (patch)
tree1d41ed222e8205a2fd16a507e3721095b4acf48f
parent34495ef7b97f3220462c974f06f1cd9c652f2a03 (diff)
fix bugs in function declaration & prototype
-rw-r--r--TODO.rst1
-rw-r--r--semantics.c71
-rw-r--r--semantics.h1
-rw-r--r--testcases/pass.c3
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;