aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTeddy <ted.sybil@gmail.com>2014-04-06 02:17:58 +0800
committerTeddy <ted.sybil@gmail.com>2014-04-06 02:17:58 +0800
commite1fd11de0bad5fa1a852b8fa497b572555448c5a (patch)
treed98caebc238b8f7ab6a7804c9f03d0d6c374b31d
parentcf59bbeb4d738688837f858c5ddc6c152ecc6dbe (diff)
complex pointer support
-rw-r--r--ast.c12
-rw-r--r--ast.h2
-rw-r--r--cibic.y33
-rw-r--r--main.c2
-rw-r--r--semantics.c158
-rw-r--r--testcases/pass.c4
6 files changed, 80 insertions, 131 deletions
diff --git a/ast.c b/ast.c
index e73fdb8..1b0d3b5 100644
--- a/ast.c
+++ b/ast.c
@@ -156,20 +156,18 @@ CNode *cnode_create_decl(CNode *type, CNode *init_declrs) {
return decl;
}
-CNode *cnode_create_func(CNode *type, CNode *plain_decl, CNode *params, CNode *stmt) {
+CNode *cnode_create_func(CNode *type, CNode *declr, CNode *stmt) {
CNode *func = NEW_CNODE;
#ifdef CIBIC_DEBUG
assert(type->next == NULL);
- assert(plain_decl->next == NULL);
- assert(params->next == NULL);
+ assert(declr->next == NULL);
assert(stmt->next == NULL);
#endif
func->type = FUNC_DEF;
func->next = NULL;
func->chd = stmt;
- stmt->next = params;
- params->next = plain_decl;
- plain_decl->next = type;
+ stmt->next = declr;
+ declr->next = type;
return func;
}
@@ -227,7 +225,7 @@ char *cnode_debug_type_repr(CNode *ast) {
switch (ast->type)
{
case PROG: type = "prog"; break;
- case FUNC_DEF: type = "func"; break;
+ case FUNC_DEF: type = "func_def"; break;
case DECLS: type = "prg_decls"; break;
case FUNCS: type = "prg_funcs"; break;
case DECL: type = "decl"; break;
diff --git a/ast.h b/ast.h
index 5176cca..016b09b 100644
--- a/ast.h
+++ b/ast.h
@@ -70,7 +70,7 @@ CNode *cnode_create_stmt(int stmt_type, int pnum, ...);
CNode *cnode_create_initr(int initr_type, CNode *body);
CNode *cnode_create_decl(CNode *type, CNode *init_declrs);
-CNode *cnode_create_func(CNode *type, CNode *plain_decl, CNode *params, CNode *stmt);
+CNode *cnode_create_func(CNode *type, CNode *declr, CNode *stmt);
CNode *cnode_create_init_declr(CNode *declr, CNode *initr);
CNode *cnode_create_struct_field(CNode *type_spec, CNode *declrs);
CNode *cnode_create_plain_decl(CNode *type_spec, CNode *declr);
diff --git a/cibic.y b/cibic.y
index 06e5727..cfc26df 100644
--- a/cibic.y
+++ b/cibic.y
@@ -19,7 +19,7 @@
%type<intval> INT_CONST
%type<strval> IDENTIFIER STR_CONST CHAR_CONST
%type<intval> additive_operator assignment_operator equality_operator multiplicative_operator relational_operator shift_operator struct_or_union unary_operator
-%type<cnode> additive_expression and_expression arguments array_initializer assignment_expression cast_expression comp_decls compound_statement comp_stmts constant_expression declaration declarator declarator_array declarators equality_expression exclusive_or_expression expression expression_statement function_definition identifier inclusive_or_expression init_declarator init_declarators initializer iteration_statement jump_statement logical_and_expression logical_or_expression multiplicative_expression optional_exp parameters plain_declaration plain_declarator postfix postfix_expression primary_expression prog_list program relational_expression selection_statement shift_expression statement struct_field struct_fields type_name type_specifier unary_expression
+%type<cnode> additive_expression and_expression arguments array_initializer assignment_expression cast_expression comp_decls compound_statement comp_stmts constant_expression declaration declarator declarators equality_expression exclusive_or_expression expression expression_statement function_definition identifier inclusive_or_expression init_declarator init_declarators initializer iteration_statement jump_statement logical_and_expression logical_or_expression multiplicative_expression optional_exp parameters plain_declaration direct_declarator postfix postfix_expression primary_expression prog_list program relational_expression selection_statement shift_expression statement struct_field struct_fields type_name type_specifier unary_expression
%start program
%%
program
@@ -44,15 +44,8 @@ declaration
}
function_definition
- : type_specifier plain_declarator '(' parameters ')' compound_statement {
- $$ = cnode_add_loc(cnode_create_func(
- $1, $2, cnode_add_loc(
- cnode_list_wrap(PARAMS, $4), @4), $6), @$);
- }
- | type_specifier plain_declarator '(' ')' compound_statement {
- $$ = cnode_add_loc(cnode_create_func(
- $1, $2,
- cnode_list_wrap(PARAMS, cnode_create_nop()), $5), @$);
+ : type_specifier declarator compound_statement {
+ $$ = cnode_add_loc(cnode_create_func($1, $2, $3), @$);
}
parameters
@@ -111,28 +104,26 @@ struct_or_union
plain_declaration
: type_specifier declarator { $$ = cnode_add_loc(cnode_create_plain_decl($1, $2), @$); }
-declarator
- : plain_declarator '(' ')' {
+direct_declarator
+ : identifier
+ | '(' declarator ')' { $$ = $2; }
+ | direct_declarator '(' ')' {
$$ = cnode_add_loc(cnode_create_declr(
DECLR_FUNC, 2, $1,
cnode_list_wrap(PARAMS, cnode_create_nop())), @$);
}
- | plain_declarator '(' parameters ')' {
+ | direct_declarator '(' parameters ')' {
$$ = cnode_add_loc(cnode_create_declr(
DECLR_FUNC, 2, $1,
cnode_add_loc(cnode_list_wrap(PARAMS, $3), @3)), @$);
}
- | declarator_array
-
-declarator_array
- : plain_declarator
- | declarator_array '[' constant_expression ']' {
+ | direct_declarator '[' constant_expression ']' {
$$ = cnode_add_loc(cnode_create_declr(DECLR_ARR, 2, $1, $3), @$);
}
-plain_declarator
- : identifier
- | '*' plain_declarator {
+declarator
+ : direct_declarator
+ | '*' declarator {
$$ = cnode_add_loc(cnode_create_declr('*', 1, $2), @$); }
statement
diff --git a/main.c b/main.c
index 2e7417b..dafcf29 100644
--- a/main.c
+++ b/main.c
@@ -46,7 +46,7 @@ void print_ast() {
void print_sem() {
yyparse();
semantics_check(ast_root);
- cnode_debug_print(ast_root, 1);
+/* cnode_debug_print(ast_root, 1); */
}
void print_help() {
diff --git a/semantics.c b/semantics.c
index aa97c6b..ed3cc47 100644
--- a/semantics.c
+++ b/semantics.c
@@ -345,19 +345,8 @@ static CType_t struct_type_merge(CType_t new, CScope_t scope) {
return old;
}
-int is_same_type(CType_t typea, CType_t typeb, int arr2ptr) {
+int is_same_type(CType_t typea, CType_t typeb) {
if (typea == typeb) return 1;
- if (arr2ptr)
- do {
- int ta = typea->type, tb = typeb->type;
- if (ta == CPTR) typea = typea->rec.ref;
- else if (ta == CARR) typea = typea->rec.arr.elem;
- else break;
- if (tb == CPTR) typeb = typeb->rec.ref;
- else if (tb == CARR) typeb = typeb->rec.arr.elem;
- else break;
- return is_same_type(typea, typeb, 0);
- } while (0);
if (typea->type != typeb->type) return 0;
switch (typea->type)
{
@@ -366,23 +355,20 @@ int is_same_type(CType_t typea, CType_t typeb, int arr2ptr) {
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, 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, 0);
+ 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, 0))
+ if (!is_same_type(pa->type, pb->type))
return 0;
if (pa || pb)
return 0; /* different number of parameters */
- return is_same_type(typea->rec.func.ret,
- typeb->rec.func.ret, 0);
+ return is_same_type(typea->rec.func.ret, typeb->rec.func.ret);
}
case CINT: case CCHAR: case CVOID:
;
@@ -397,7 +383,7 @@ 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, 0) || scope->lvl > 0)
+ if (!is_same_type(old->type, new->type) || scope->lvl > 0)
{
sprintf(err_buff, "conflicting types of '%s'", new->name);
ERROR(new->ast);
@@ -451,12 +437,12 @@ int type_is_complete(CType_t type) {
return 1;
}
-CVar_t semantics_declr(CNode *, CType_t, CScope_t);
+CVar_t semantics_declr(CNode *, CType_t, CScope_t, int);
CVar_t semantics_p_decl(CNode *p, CScope_t scope) {
CHECK_TYPE(p, PLAIN_DECL);
CVar_t var = semantics_declr(p->chd->next,
semantics_type_spec(p->chd, scope),
- scope);
+ scope, 0);
if (!type_is_complete(var->type))
{
sprintf(err_buff, "parameter '%s' has incomplete type", var->name);
@@ -526,87 +512,59 @@ do { \
ERROR(ast); \
} while (0)
-CVar_t semantics_p_declr(CNode *p, CType_t type_spec, int func_def) {
- /* deal with pointer prefix */
- CNode *t, *ast;
- CType_t tt, ptype;
- const char *name;
+CVar_t semantics_declr(CNode *p, CType_t type_spec, CScope_t scope, int func_chk) {
+ CVar_t type;
if (p->type == ID)
{
- ptype = type_spec; /* filled by type spec */
- name = p->rec.strval;
- ast = p;
- if (!func_def) CHECK_CVOID(name, ast);
- }
- else
- {
- 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, t);
- tt = tt->rec.ref;
- }
+ if (!func_chk) CHECK_CVOID(p->rec.strval, p);
+ return cvar_create(p->rec.strval, type_spec, p);
}
- return cvar_create(name, ptype, ast);
-}
-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, 0);
switch (p->rec.subtype)
{
case DECLR_FUNC:
{
- CVar_t p_declr = semantics_p_declr(p->chd, type_spec, 1);
- type = ctype_create("", CFUNC, p); /* function declr */
+ CType_t func = ctype_create("", CFUNC, p); /* function declr */
cscope_enter(scope);
- type->rec.func.params = semantics_params(p->chd->next, scope);
+ func->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;
- type->rec.func.body = NULL; /* not a definition */
- name = p_declr->name;
- ast = p_declr->ast;
- free(p_declr);
+ func->rec.func.local = NULL;
+ func->rec.func.ret = type_spec;
+ func->rec.func.body = NULL; /* not a definition */
+ type = semantics_declr(p->chd, func, scope, 1);
+ if (type_spec->type == CARR)
+ {
+ sprintf(err_buff, "'%s' declared as function returning an array",
+ type->name);
+ ERROR(p);
+ }
+ if (type_spec->type == CFUNC)
+ {
+ sprintf(err_buff, "'%s' declared as function returing a function",
+ type->name);
+ ERROR(p);
+ }
}
break;
case DECLR_ARR:
{
- CNode *t;
- CType_t tt;
- type = ctype_create("", CARR, p); /* array declr */
- for (t = p, tt = type;; t = t->chd)
- {
- /* TODO: range checking */
- tt->rec.arr.len = t->chd->next->rec.intval; /* array length */
- if (t->chd->type == ID || t->chd->rec.subtype == '*')
- {
- CVar_t p_declr = semantics_p_declr(t->chd, type_spec, 0);
- 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, t);
- tt = tt->rec.arr.elem;
- }
+ CType_t arr = ctype_create("", CARR, p); /* array declr */
+ arr->rec.arr.elem = type_spec;
+ arr->rec.arr.len = p->chd->next->rec.intval;
+ type = semantics_declr(p->chd, arr, scope, 0);
+ }
+ break;
+ case '*':
+ {
+ CType_t ptr = ctype_create("", CPTR, p); /* pointer */
+ ptr->rec.ref = type_spec;
+ type = semantics_declr(p->chd, ptr, scope, 0);
}
break;
default: assert(0);
}
- return cvar_create(name, type, ast);
+ return type;
}
CTable_t semantics_fields(CNode *p, CScope_t scope) {
@@ -621,8 +579,8 @@ 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),
- scope);
+ semantics_type_spec(p->chd, scope),
+ scope, 0);
/* incomplete type checking */
if (!type_is_complete(var->type))
{
@@ -657,7 +615,7 @@ CVar_t semantics_decl(CNode *p, CScope_t scope) {
for (p = init->chd; p; p = p->next)
{
/* TODO: initializer checking */
- CVar_t var = semantics_declr(p->chd, type, scope);
+ CVar_t var = semantics_declr(p->chd, type, scope, 0);
if (scope->lvl && !type_is_complete(var->type))
{
sprintf(err_buff, "storage size of '%s' isn’t known", var->name);
@@ -698,7 +656,7 @@ void exp_check_aseq_(CType_t lhs, CType_t rhs, CNode *ast) {
switch (lhs->type)
{
case CSTRUCT: case CUNION:
- if (!is_same_type(lhs, rhs, 0))
+ if (!is_same_type(lhs, rhs))
INCOMP_TYPE(ast);
break;
case CARR: case CFUNC: /* constant */
@@ -720,7 +678,7 @@ void exp_check_aseq_(CType_t lhs, CType_t rhs, CNode *ast) {
switch (rhs->type)
{
case CPTR: case CARR:
- if (!is_same_type(lhs->rec.ref, rhs->rec.ref, 1))
+ if (!is_same_type(lhs->rec.ref, rhs->rec.ref))
{
sprintf(err_buff, "assignment from incompatible pointer type");
WARNING(ast);
@@ -940,7 +898,7 @@ ExpType exp_check_equality(ExpType op1, ExpType op2, CNode *ast) {
}
if (t1 == CPTR && t2 == CPTR)
{
- if (!is_same_type(op1.type->rec.ref, op2.type->rec.ref, 0))
+ if (!is_same_type(op1.type->rec.ref, op2.type->rec.ref))
{
sprintf(err_buff, "comparison of distinct pointer types lacks a cast");
WARNING(ast);
@@ -1354,22 +1312,20 @@ CVar_t semantics_comp(CNode *p, CScope_t scope) {
CVar_t semantics_func(CNode *p, CScope_t scope) {
CHECK_TYPE(p, FUNC_DEF);
- CVar_t head = semantics_p_declr(p->chd->next, semantics_type_spec(p->chd, scope), 1);
- CType_t func = ctype_create(head->name, CFUNC, p), funco;
+ CVar_t head = semantics_declr(p->chd->next,
+ semantics_type_spec(p->chd, scope),
+ scope, 0);
+ CType_t func = head->type, funco;
CVar_t res = cvar_create(head->name, func, p), old = NULL;
- CNode *chd = p->chd->next->next;
- func->rec.func.ret = head->type;
- /* check return type */
- if (!type_is_complete(head->type))
+ if (!type_is_complete(func->rec.func.ret))
{
sprintf(err_buff, "return type is an incomplete type");
- ERROR(p->chd);
+ ERROR(func->rec.func.ret->ast);
}
scope->func = func;
cscope_enter(scope); /* enter function local scope */
- func->rec.func.params = semantics_params(chd, scope); /* check params */
{ /* 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.
The key point is to make sure semantics_params does not push any var */
@@ -1385,8 +1341,8 @@ CVar_t semantics_func(CNode *p, CScope_t scope) {
for (p = func->rec.func.params; p; p = p->next)
cscope_push_var(scope, p);
}
- func->rec.func.local = semantics_comp(chd->next, scope); /* check comp */
- func->rec.func.body = chd->next;
+ 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)
@@ -1403,7 +1359,7 @@ CVar_t semantics_func(CNode *p, CScope_t scope) {
sprintf(err_buff, "redefintion of function '%s'", res->name);
ERROR(res->ast);
}
- else if (!is_same_type(funco, res->type, 0))
+ else if (!is_same_type(funco, res->type))
{
sprintf(err_buff, "function defintion does not match the prototype");
ERROR(res->ast);
diff --git a/testcases/pass.c b/testcases/pass.c
index b219178..835483e 100644
--- a/testcases/pass.c
+++ b/testcases/pass.c
@@ -71,6 +71,10 @@ void comma() {
(b++, a++) * 3;
}
+int complex_pointer() {
+ int (*f(int ***e[10]))();
+}
+
struct Node n;
struct Node {int x, y;} n;
/* global forward declaration is ok */