diff options
Diffstat (limited to 'semantics.c')
-rw-r--r-- | semantics.c | 184 |
1 files changed, 139 insertions, 45 deletions
diff --git a/semantics.c b/semantics.c index ae0b0de..21559b7 100644 --- a/semantics.c +++ b/semantics.c @@ -6,6 +6,7 @@ #include "ast.h" #define NEW(type) ((type *)malloc(sizeof(type))) #define CHECK_TYPE(p, _type) assert(p->type == _type) +#define EXIT_ERROR(row, col) print_error(err_buff, NULL, row, col, 0) #ifdef CIBIC_DEBUG CTable_t ctable_create(Hashfunc_t hfunc, Printfunc_t pfunc) { @@ -24,6 +25,10 @@ CTable_t ctable_create(Hashfunc_t hfunc) { } #endif +extern void print_error(char *, char *, int, int, int); +extern char *load_line(int); +static char err_buff[MAX_ERROR_BUFF]; + void *ctable_lookup(CTable_t ct, const char *key) { unsigned int hv = ct->hfunc(key) % MAX_TABLE_SIZE; CTNode *p = ct->head[hv]; @@ -194,17 +199,19 @@ const char *ctable_ctype_print(void *type) { return buff; } -CVar_t cvar_create(const char *name, CType_t type) { +CVar_t cvar_create(const char *name, CType_t type, CNode *ast) { CVar_t cv = NEW(CVar); cv->name = name; cv->type = type; + cv->ast = ast; return cv; } -CType_t ctype_create(const char *name, int type) { +CType_t ctype_create(const char *name, int type, CNode *ast) { CType_t ct = NEW(CType); ct->name = name; ct->type = type; + ct->ast = ast; switch (type) { case CINT: ct->size = INT_SIZE; break; @@ -282,33 +289,104 @@ void ctype_print(CType_t ct) { } } +static CType_t type_merge(CType_t new, CScope_t scope) { + CType_t old; + if (cscope_push_type(scope, new)) + return new; + else + old = cscope_lookup_type(scope, new->name); + if (old->type != new->type) + { + sprintf(err_buff, "conflicting types of '%s'", new->name); + EXIT_ERROR(new->ast->loc.row, new->ast->loc.col); + } + if (!new->rec.fields) + return old; + if (old->rec.fields) + { + sprintf(err_buff, "redefinition of '%s'", new->name); + EXIT_ERROR(new->ast->loc.row, new->ast->loc.col); + } + /* complete the type */ + old->next = new->next; + old->rec.fields = new->rec.fields; + old->ast = new->ast; + free(new); + return old; +} + +int is_same_type(CType_t typea, CType_t typeb) { + if (typea == typeb) return 1; + if (typea->type != typeb->type) return 0; + switch (typea->type) + { + case CSTRUCT: case CUNION: + return typea == typeb; + case CARR: + if (typea->rec.arr.len != typeb->rec.arr.len) + return 0; + return is_same_type(typea->rec.arr.elem, + typeb->rec.arr.elem); + case CPTR: + return is_same_type(typea->rec.ref, + typeb->rec.ref); + case CFUNC: + { + CVar_t pa, pb; + for (pa = typea->rec.func.params, + pb = typeb->rec.func.params; pa && pb; + pa = pa->next, pb = pb->next) + if (!is_same_type(pa->type, pb->type)) + return 0; + if (pa || pb) + return 0; /* different number of parameters */ + break; + } + case CINT: case CCHAR: case CVOID: + ; + break; + } + return 1; +} + +static CVar_t var_merge(CVar_t new, CScope_t scope) { + CVar_t old; + if (cscope_push_var(scope, new)) + return new; + else + old = cscope_lookup_var(scope, new->name); + if (!is_same_type(old->type, new->type) || scope->lvl > 0) + { + sprintf(err_buff, "conflicting types of '%s'", new->name); + EXIT_ERROR(new->ast->loc.row, new->ast->loc.col); + } + free(new); + return old; +} + CTable_t semantics_fields(CNode *, CScope_t scope); CType_t semantics_type_spec(CNode *p, CScope_t scope) { CHECK_TYPE(p, TYPE_SPEC); CType_t type; switch (p->rec.subtype) { - case KW_VOID: type = ctype_create("", CVOID); break; - case KW_CHAR: type = ctype_create("", CCHAR); break; - case KW_INT: type = ctype_create("", CINT); break; + case KW_VOID: type = ctype_create("", CVOID, p); break; + case KW_CHAR: type = ctype_create("", CCHAR, p); break; + case KW_INT: type = ctype_create("", CINT, p); break; case KW_STRUCT: case KW_UNION: { CNode *id = p->chd, *fields = p->chd->next; type = ctype_create(id->type == NOP ? "" : id->rec.strval, - p->rec.subtype == KW_STRUCT ? CSTRUCT : CUNION); + p->rec.subtype == KW_STRUCT ? CSTRUCT : CUNION, + p); if (fields->type == NOP) - { - type = cscope_lookup_type(scope, id->rec.strval); - if (!type) puts("type not exist"); - } + type->rec.fields = NULL; /* incomplete type */ else - { type->rec.fields = semantics_fields(fields, scope); - if (id->type != NOP) - if (!cscope_push_type(scope, type)) - puts("fuck type"); - } + + if (id->type != NOP) + type = type_merge(type, scope); } break; default: assert(0); @@ -316,11 +394,12 @@ CType_t semantics_type_spec(CNode *p, CScope_t scope) { return type; } -CVar_t semantics_declr(CNode *, CType_t ); +CVar_t semantics_declr(CNode *, CType_t, CScope_t); CVar_t semantics_p_decl(CNode *p, CScope_t scope) { CHECK_TYPE(p, PLAIN_DECL); return semantics_declr(p->chd->next, - semantics_type_spec(p->chd, scope)); + semantics_type_spec(p->chd, scope), + scope); } CVar_t semantics_params(CNode *p, CScope_t scope) { @@ -334,7 +413,10 @@ CVar_t semantics_params(CNode *p, CScope_t scope) { CVar_t var = semantics_p_decl(p, scope); if (scope) /* params inside a function definition */ if (!cscope_push_var(scope, var)) - puts("fuck params"); + { + sprintf(err_buff, "redefinition of parameter '%s'", var->name); + EXIT_ERROR(var->ast->loc.row, var->ast->loc.col); + } var->next = params; params = var; } @@ -343,35 +425,38 @@ CVar_t semantics_params(CNode *p, CScope_t scope) { CVar_t semantics_p_declr(CNode *p, CType_t type_spec) { /* deal with pointer prefix */ - CNode *t; + CNode *t, *ast; CType_t tt, ptype; const char *name; if (p->type == ID) { ptype = type_spec; /* filled by type spec */ name = p->rec.strval; + ast = p; } else { - ptype = ctype_create("", CPTR); /* pointer */ + ptype = ctype_create("", CPTR, p); /* pointer */ for (t = p, tt = ptype;; t = t->chd) { if (t->chd->type == ID) { tt->rec.ref = type_spec; /* filled by type spec */ name = t->chd->rec.strval; + ast = t; break; } - tt->rec.ref = ctype_create("", CPTR); + tt->rec.ref = ctype_create("", CPTR, t); tt = tt->rec.ref; } } - return cvar_create(name, ptype); + return cvar_create(name, ptype, ast); } -CVar_t semantics_declr(CNode *p, CType_t type_spec) { +CVar_t semantics_declr(CNode *p, CType_t type_spec, CScope_t scope) { CType_t type; const char *name; + CNode *ast; if (p->type == ID || p->rec.subtype == '*') return semantics_p_declr(p, type_spec); switch (p->rec.subtype) @@ -379,12 +464,15 @@ CVar_t semantics_declr(CNode *p, CType_t type_spec) { case DECLR_FUNC: { CVar_t p_declr = semantics_p_declr(p->chd, type_spec); - type = ctype_create("", CFUNC); /* function declr */ - type->rec.func.params = semantics_params(p->chd->next, NULL); + type = ctype_create("", CFUNC, p); /* function declr */ + cscope_enter(scope); + type->rec.func.params = semantics_params(p->chd->next, scope); + cscope_exit(scope); /* incomplete type */ type->rec.func.local = NULL; type->rec.func.ret = p_declr->type; name = p_declr->name; + ast = p_declr->ast; free(p_declr); } break; @@ -392,7 +480,7 @@ CVar_t semantics_declr(CNode *p, CType_t type_spec) { { CNode *t; CType_t tt; - type = ctype_create("", CARR); /* array declr */ + type = ctype_create("", CARR, p); /* array declr */ for (t = p, tt = type;; t = t->chd) { /* TODO: range checking */ @@ -402,17 +490,18 @@ CVar_t semantics_declr(CNode *p, CType_t type_spec) { CVar_t p_declr = semantics_p_declr(t->chd, type_spec); tt->rec.arr.elem = p_declr->type; name = p_declr->name; + ast = p_declr->ast; free(p_declr); break; } - tt->rec.arr.elem = ctype_create("", CARR); + tt->rec.arr.elem = ctype_create("", CARR, t); tt = tt->rec.arr.elem; } } break; default: assert(0); } - return cvar_create(name, type); + return cvar_create(name, type, ast); } CTable_t semantics_fields(CNode *p, CScope_t scope) { @@ -427,10 +516,14 @@ CTable_t semantics_fields(CNode *p, CScope_t scope) { for (; declr; declr = declr->next) { CVar_t var = semantics_declr(declr, - semantics_type_spec(p->chd, scope)); + semantics_type_spec(p->chd, scope), + scope); /* TODO: conflicts report */ if (!ctable_insert(ct, var->name, var, 0)) - puts("fuck fields"); + { + sprintf(err_buff, "duplicate member '%s'", var->name); + EXIT_ERROR(var->ast->loc.row, var->ast->loc.col); + } } } return ct; @@ -454,15 +547,14 @@ CVar_t semantics_decl(CNode *p, CScope_t scope) { break; default: assert(0); } - if (init->type != NOP) + if (init->chd->type != NOP) { CNode *p; for (p = init->chd; p; p = p->next) { /* TODO: initializer checking */ - CVar_t var = semantics_declr(p->chd, type); - if (!cscope_push_var(scope, var)) - puts("fuck decl"); + CVar_t var = semantics_declr(p->chd, type, scope); + var = var_merge(var, scope); var->next = res; res = var; } @@ -546,17 +638,22 @@ CVar_t semantics_comp(CNode *p, CScope_t scope) { return res; } -CType_t semantics_func(CNode *p, CScope_t scope) { +CVar_t semantics_func(CNode *p, CScope_t scope) { CHECK_TYPE(p, FUNC_DEF); CNode *chd = p->chd->next; - CType_t func = ctype_create(chd->rec.strval, CFUNC); + CType_t func = ctype_create(chd->rec.strval, CFUNC, p); + CVar_t res; + chd = chd->next; func->rec.func.ret = semantics_type_spec(p->chd, scope); /* check return type */ cscope_enter(scope); /* enter into function local scope */ func->rec.func.params = semantics_params(chd, scope); /* check params */ func->rec.func.local = semantics_comp(chd->next, scope); /* check comp */ cscope_exit(scope); /* exit from local scope */ - return func; + res = cvar_create(func->name, func, p); + if (!cscope_push_var(scope, res)) + puts("fuck func name"); + return res; } void semantics_check_(CNode *p, CScope_t scope) { @@ -571,21 +668,18 @@ void semantics_check_(CNode *p, CScope_t scope) { void semantics_check(CNode *ast) { CScope_t scope = cscope_create(); /* add top-level basic types */ - cscope_push_type(scope, ctype_create("int", CINT)); - cscope_push_type(scope, ctype_create("char", CCHAR)); - cscope_push_type(scope, ctype_create("void", CVOID)); + cscope_push_type(scope, ctype_create("int", CINT, NULL)); + cscope_push_type(scope, ctype_create("char", CCHAR, NULL)); + cscope_push_type(scope, ctype_create("void", CVOID, NULL)); /* check all definitions and declarations */ for (ast = ast->chd; ast; ast = ast->next) { switch (ast->type) { case FUNC_DEF: - if (!cscope_push_type(scope, semantics_func(ast, scope))) - puts("fuck func"); - break; + semantics_func(ast, scope); break; case DECL: - semantics_decl(ast, scope); - break; + semantics_decl(ast, scope); break; default: assert(0); } } |