diff options
-rw-r--r-- | ast.c | 12 | ||||
-rw-r--r-- | ast.h | 2 | ||||
-rw-r--r-- | cibic.y | 33 | ||||
-rw-r--r-- | main.c | 2 | ||||
-rw-r--r-- | semantics.c | 158 | ||||
-rw-r--r-- | testcases/pass.c | 4 |
6 files changed, 80 insertions, 131 deletions
@@ -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; @@ -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); @@ -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 @@ -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 */ |