aboutsummaryrefslogtreecommitdiff
path: root/semantics.c
diff options
context:
space:
mode:
Diffstat (limited to 'semantics.c')
-rw-r--r--semantics.c148
1 files changed, 129 insertions, 19 deletions
diff --git a/semantics.c b/semantics.c
index ea64905..45571a0 100644
--- a/semantics.c
+++ b/semantics.c
@@ -69,8 +69,13 @@ static void warning_print(CNode *ast, const char *fmt, ...) {
}
const char *csymbol_getname(CSymbol_t sym) {
- return (sym->kind == CVAR) ?
- sym->rec.var->name : sym->rec.type->name;
+ switch (sym->kind)
+ {
+ case CVAR: return sym->rec.var->name;
+ case CTYPE: return sym->rec.type->name;
+ case CDEF: return sym->rec.def->name;
+ }
+ return NULL;
}
#ifdef CIBIC_DEBUG
@@ -195,6 +200,18 @@ int cscope_push_type(CScope_t cs, CType_t type, int nspace) {
return 1;
}
+int cscope_push_def(CScope_t cs, CDef_t def, int nspace) {
+ CSymbol_t p = NEW(CSymbol);
+ p->kind = CDEF;
+ p->rec.def = def;
+ if (!cscope_push(cs, p, nspace))
+ {
+ free(p);
+ return 0;
+ }
+ return 1;
+}
+
void cscope_enter(CScope_t cs) {
CSNode *np = NEW(CSNode);
np->next = cs->top;
@@ -273,10 +290,17 @@ unsigned int bkdr_hash(const char *str) {
const char *csymbol_print(void *csym) {
CSymbol_t p = (CSymbol_t)csym;
static char buff[MAX_DEBUG_PRINT_BUFF];
- if (p->kind == CVAR)
- sprintf(buff, "%s@%lx", p->rec.var->name, (size_t)p->rec.var);
- else
- sprintf(buff, "%s@%lx", p->rec.type->name, (size_t)p->rec.type);
+ switch (p->kind)
+ {
+ case CVAR:
+ sprintf(buff, "%s@%lx", p->rec.var->name, (size_t)p->rec.var);
+ break;
+ case CTYPE:
+ sprintf(buff, "%s@%lx", p->rec.type->name, (size_t)p->rec.type);
+ break;
+ case CDEF:
+ sprintf(buff, "%s@%lx", p->rec.def->name, (size_t)p->rec.def);
+ }
return buff;
}
@@ -316,6 +340,11 @@ void cvar_print(CVar_t cv) {
ctype_print(cv->type);
}
+void cdef_print(CDef_t cd) {
+ fprintf(stderr, "[def@%lx:%s]->", (size_t)cd, cd->name);
+ ctype_print(cd->type);
+}
+
void ctype_print(CType_t ct) {
switch (ct->type)
{
@@ -509,6 +538,14 @@ CType_t semantics_type_spec(CNode *p, CScope_t scope) {
type = struct_type_merge(type, scope);
}
break;
+ case USER_TYPE:
+ {
+ CHECK_TYPE(p->chd, ID);
+ CSymbol_t lu = cscope_lookup(scope, p->chd->rec.strval, NS_ID);
+ assert(lu && lu->kind == CDEF); /* parser guarantees this */
+ type = lu->rec.def->type;
+ }
+ break;
default: assert(0);
}
return type;
@@ -724,8 +761,25 @@ void semantics_initr(CNode *p, CScope_t scope, CType_t type) {
}
}
+void semantics_typedef(CNode *p, CType_t type, CScope_t scope) {
+ CNode *declr = p->chd->next;
+ for (p = declr->chd; p; p = p->next)
+ {
+ CVar_t var = semantics_declr(p, type, scope, 0);
+ CDef_t def = cdef_create(var->name, var->type, var->ast);
+ if (!cscope_push_def(scope, def, NS_ID))
+ {
+ CSymbol_t lu = cscope_lookup(scope, def->name, NS_ID);
+ if (lu->kind != CDEF)
+ ERROR((def->ast, "'%s' redeclared as different kind of symbol", def->name));
+ /* FIXME: `typedef int a()` is different from typedef `int a(int)` */
+ if (!is_same_type(lu->rec.type, def->type))
+ ERROR((def->ast, "conflicting types of '%s'", def->name));
+ }
+ }
+}
+
CVar_t semantics_decl(CNode *p, CScope_t scope) {
- CHECK_TYPE(p, DECL);
CNode *declr = p->chd->next;
CType_t type = semantics_type_spec(p->chd, scope);
CVar_t res = NULL;
@@ -736,6 +790,12 @@ CVar_t semantics_decl(CNode *p, CScope_t scope) {
cscope_push_type(scope, type, NS_TAG);
useful = 1;
}
+ if (p->type == TYPEDEF)
+ {
+ semantics_typedef(p, type, scope);
+ return NULL;
+ }
+ CHECK_TYPE(p, DECL);
if (declr->chd->type != NOP)
{
CNode *p;
@@ -746,18 +806,19 @@ CVar_t semantics_decl(CNode *p, CScope_t scope) {
if (var->type->type == CFUNC)
{
CType_t func = var->type;
+ CSymbol_t lu;
func->name = var->name;
+ if (initr->type == INITR)
+ ERROR((var->ast, "function '%s' is initialized like a variable", func->name));
if (!cscope_push_type(scope, func, NS_ID))
{
- CSymbol_t lu = cscope_lookup(scope, func->name, NS_ID);
+ lu = cscope_lookup(scope, func->name, NS_ID);
if (lu->kind != CTYPE)
ERROR((func->ast, "'%s' redeclared as different kind of symbol", func->name));
if (!is_same_type(lu->rec.type, func))
ERROR((func->ast, "conflicting types of '%s'", func->name));
type_merge(lu->rec.type, func);
}
- if (initr->type == INITR)
- ERROR((var->ast, "function '%s' is initialized like a variable", func->name));
}
else
{
@@ -1542,7 +1603,7 @@ void semantics_check(CNode *p) {
{
case FUNC_DEF:
semantics_func(p, scope); break;
- case DECL:
+ case DECL: case TYPEDEF:
semantics_decl(p, scope); break;
default: assert(0);
}
@@ -1555,22 +1616,71 @@ void semantics_check(CNode *p) {
for (p = scope->ids->head[i]; p; p = p->next)
{
CSymbol_t tp = (CSymbol_t)(p->val);
- if (tp->kind == CVAR)
- cvar_print(tp->rec.var);
- else
- ctype_print(tp->rec.type);
+ switch (tp->kind)
+ {
+ case CVAR: cvar_print(tp->rec.var); break;
+ case CTYPE: ctype_print(tp->rec.type); break;
+ case CDEF: cdef_print(tp->rec.def); break;
+ }
fprintf(stderr, "\n");
}
for (i = 0; i < MAX_TABLE_SIZE; i++)
for (p = scope->tags->head[i]; p; p = p->next)
{
CSymbol_t tp = (CSymbol_t)(p->val);
- if (tp->kind == CVAR)
- cvar_print(tp->rec.var);
- else
- ctype_print(tp->rec.type);
+ switch (tp->kind)
+ {
+ case CVAR: cvar_print(tp->rec.var); break;
+ case CTYPE: ctype_print(tp->rec.type); break;
+ case CDEF: cdef_print(tp->rec.def); break;
+ }
fprintf(stderr, "\n");
}
}
cnode_debug_print(ast_root, 1);
}
+
+static CScope_t typedef_scope;
+static enum {
+ NONE,
+ TYPEDEF_DECLR,
+ OTHER_DECLR
+} typedef_state;
+
+void cibic_init() {
+ typedef_scope = cscope_create();
+ typedef_state = NONE;
+}
+
+int is_identifier(const char *name) {
+ CSymbol_t lu;
+ /* the parser is reading declarators */
+ if (typedef_state == OTHER_DECLR) return 1;
+ /* the parser is reading typedef */
+ if (typedef_state == TYPEDEF_DECLR) return 1;
+ /* no info about name, assume it to be an id by default */
+ lu = cscope_lookup(typedef_scope, name, NS_ID);
+ if (!lu) return 1;
+ return lu->kind == CVAR;
+}
+
+void push(const char *name) {
+ if (typedef_state == TYPEDEF_DECLR)
+ cscope_push_type(typedef_scope, ctype_create(name, 0, NULL), NS_ID);
+ else
+ cscope_push_var(typedef_scope, cvar_create(name, NULL, NULL), NS_ID);
+}
+
+CDef_t cdef_create(const char *name, CType_t type, CNode *ast) {
+ CDef_t cd = NEW(CDef);
+ cd->name = name;
+ cd->type = type;
+ cd->ast = ast;
+ return cd;
+}
+
+void enter_block() { cscope_enter(typedef_scope); }
+void exit_block() { cscope_exit(typedef_scope); }
+void enter_typedef() { typedef_state = TYPEDEF_DECLR; }
+void enter_declr() { typedef_state = OTHER_DECLR; }
+void exit_declr() { typedef_state = NONE; }