aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTeddy <ted.sybil@gmail.com>2014-04-04 20:34:44 +0800
committerTeddy <ted.sybil@gmail.com>2014-04-04 20:34:44 +0800
commitca9650190643302b8af46b106230fda877407f07 (patch)
treeea161a1b38ad25d059adecba623e36fafe28b8b7
parentbf77f3bad51ef61f660514b6f72bcd8b68f25154 (diff)
working on type checking
-rw-r--r--ast.h2
-rw-r--r--const.h1
-rw-r--r--main.c31
-rw-r--r--semantics.c184
-rw-r--r--semantics.h6
5 files changed, 159 insertions, 65 deletions
diff --git a/ast.h b/ast.h
index 55a0e8a..bdae049 100644
--- a/ast.h
+++ b/ast.h
@@ -51,7 +51,7 @@ typedef struct CNode {
} ext;
struct CNode *chd, *next;
/* For error reporting */
- struct Location {
+ struct {
int row, col;
} loc;
} CNode;
diff --git a/const.h b/const.h
index 26f05fa..fab99d9 100644
--- a/const.h
+++ b/const.h
@@ -21,5 +21,6 @@
#define MAX_DEBUG_PRINT_BUFF 1024
#define MAX_DEBUG_PRINT_LVL 1024
#define MAX_TABLE_SIZE 1021
+#define MAX_ERROR_BUFF 1024
#define INT_SIZE 4
#define CHAR_SIZE 1
diff --git a/main.c b/main.c
index ff70bf9..421f30d 100644
--- a/main.c
+++ b/main.c
@@ -15,17 +15,22 @@ int yywrap() {
return 1;
}
-void print_error(char *err_msg, int row, int col) {
+void print_error(char *err_msg, char *lb, int row, int col, int warn) {
*lptr = '\0';
- fprintf(stderr, "%d:%d: %s\n%s\n",
- row, col, err_msg, linebuff);
- while (--col) putchar(' ');
- puts("^");
+ fprintf(stderr, "%d:%d: %s: %s\n",
+ row, col, warn ? "warning" : "error", err_msg);
+ if (lb)
+ {
+ fprintf(stderr, "%s\n", lb);
+ while (--col) fprintf(stderr, "%c", ' ');
+ fprintf(stderr, "^\n");
+ }
+ if (!warn) exit(1);
}
int yyerror(char *err_msg) {
- print_error(err_msg,
- yylloc.first_line, yylloc.first_column);
+ print_error(err_msg, linebuff,
+ yylloc.first_line, yylloc.first_column, 0);
return 0;
}
@@ -35,20 +40,12 @@ void print_ast() {
else
fprintf(stderr, "AST for stdin\n");
yyparse();
- if (ast_root)
- {
- cnode_debug_print(ast_root, 1);
- }
- else exit(1);
+ cnode_debug_print(ast_root, 1);
}
void print_sem() {
yyparse();
- if (ast_root)
- {
- semantics_check(ast_root);
- }
- else exit(1);
+ semantics_check(ast_root);
}
void print_help() {
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);
}
}
diff --git a/semantics.h b/semantics.h
index 46f9a41..dfbf7b7 100644
--- a/semantics.h
+++ b/semantics.h
@@ -12,10 +12,11 @@ typedef struct CVar{
struct CVar *next; /* next in the linked list */
struct CType *type;
int offset;
+ CNode *ast;
} CVar;
typedef CVar *CVar_t;
-CVar_t cvar_create(const char *name, struct CType *type);
+CVar_t cvar_create(const char *name, struct CType *type, CNode *ast);
void cvar_print(CVar_t cv);
typedef struct CType {
@@ -45,10 +46,11 @@ typedef struct CType {
} func; /* for a function */
} rec;
int size; /* memory footprint */
+ CNode *ast;
} CType;
typedef CType *CType_t;
-CType_t ctype_create(const char *name, int type);
+CType_t ctype_create(const char *name, int type, CNode *ast);
void ctype_debug_print(CType_t ct);
typedef unsigned int (*Hashfunc_t) (const char *);