aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--TODO.rst3
-rw-r--r--ast.c2
-rw-r--r--ast.h1
-rw-r--r--cibic.y35
-rw-r--r--semantics.c47
-rw-r--r--testcases/cast.c3
-rw-r--r--testcases/cast2.c3
-rw-r--r--testcases/cast3.c3
-rw-r--r--testcases/fail10.c4
-rw-r--r--testcases/fail11.c4
-rw-r--r--testcases/fail8.c5
-rw-r--r--testcases/localfunc.c4
12 files changed, 82 insertions, 32 deletions
diff --git a/TODO.rst b/TODO.rst
index e2fbcc6..d896657 100644
--- a/TODO.rst
+++ b/TODO.rst
@@ -12,4 +12,5 @@ TODO
- Not Implemented:
- - Complex type name (to be in agreement with complex decl)
+ - complex type name (to be in agreement with complex decl) (almost done)
+ - initializer checking
diff --git a/ast.c b/ast.c
index 1b0d3b5..44952d8 100644
--- a/ast.c
+++ b/ast.c
@@ -231,7 +231,6 @@ char *cnode_debug_type_repr(CNode *ast) {
case DECL: type = "decl"; break;
case INIT_DECLR: type = "init_declr"; break;
case PLAIN_DECL: type = "p_decl"; break;
- case TYPE_NAME: type = "type_name"; break;
case COMP_STMTS: type = "blk_stmts"; break;
case COMP_DECLS: type = "blk_decls"; break;
case DECLRS: type = "declrs"; break;
@@ -331,6 +330,7 @@ char *cnode_debug_type_repr(CNode *ast) {
case DECLR_FUNC: type = "func"; break;
case DECLR_ARR: type = "arr"; break;
case '*': type = "*"; break;
+ case 0: type = "typename"; break;
default: assert(0);
}
}
diff --git a/ast.h b/ast.h
index 016b09b..c12e2b9 100644
--- a/ast.h
+++ b/ast.h
@@ -28,7 +28,6 @@ typedef struct CNode {
/* Expressions */
EXP,
- TYPE_NAME,
ID, /* identifier */
INT, /* INT_CONST */
CHAR,
diff --git a/cibic.y b/cibic.y
index 5d707b7..c4e45e2 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 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
+%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 abstract_declarator direct_abstract_declarator direct_abstract_declarator_opt abstract_declarator_opt
%start program
%%
program
@@ -290,8 +290,37 @@ cast_expression
$$ = cnode_add_loc(cnode_create_exp(EXP_CAST, 2, $2, $4), @$); }
type_name
- : type_specifier
- | type_name '*' { $$ = cnode_add_loc(cnode_create_exp('*', 1, $1), @$); }
+ : type_specifier abstract_declarator_opt {
+ $$ = cnode_add_loc(cnode_create_declr(0, 2, $1, $2), @$); }
+
+abstract_declarator_opt
+ : { $$ = cnode_create_nop(); }
+ | abstract_declarator
+
+abstract_declarator
+ : '*' { $$ = cnode_add_loc(cnode_create_declr('*', 1, cnode_create_nop()), @$); }
+ | '*' abstract_declarator { $$ = cnode_add_loc(cnode_create_declr('*', 1, $2), @$); }
+ | direct_abstract_declarator
+
+direct_abstract_declarator_opt
+ : { $$ = cnode_create_nop(); }
+ | direct_abstract_declarator
+
+direct_abstract_declarator
+ : '(' abstract_declarator ')' { $$ = $2; }
+ | direct_abstract_declarator '(' parameters ')' {
+ $$ = cnode_add_loc(cnode_create_declr(
+ DECLR_FUNC, 2, $1,
+ cnode_add_loc(cnode_list_wrap(PARAMS, $3), @3)), @$);
+ }
+ | '(' parameters ')' {
+ $$ = cnode_add_loc(cnode_create_declr(
+ DECLR_FUNC, 2, cnode_create_nop(),
+ cnode_add_loc(cnode_list_wrap(PARAMS, $2), @2)), @$);
+ }
+ | direct_abstract_declarator_opt '[' constant_expression ']' {
+ $$ = cnode_add_loc(cnode_create_declr(DECLR_ARR, 2, $1, $3), @$);
+ }
unary_expression
: postfix_expression
diff --git a/semantics.c b/semantics.c
index 68884ce..39ca0c1 100644
--- a/semantics.c
+++ b/semantics.c
@@ -493,7 +493,8 @@ CVar_t semantics_declr(CNode *p, CType_t type_spec, CScope_t scope, int func_chk
if (!func_chk) CHECK_CVOID(p->rec.strval, p);
return cvar_create(p->rec.strval, type_spec, p);
}
-
+ if (p->type == NOP) /* type name */
+ return cvar_create(NULL, type_spec, p);
switch (p->rec.subtype)
{
case DECLR_FUNC:
@@ -681,37 +682,30 @@ ExpType exp_check_aseq(ExpType lhs, ExpType rhs, CNode *ast) {
#define IS_INT(tt) ((tt) == CINT || (tt) == CCHAR)
#define IS_ARITH(tt) IS_INT(tt)
-#define IS_SCALAR(tt) (IS_ARITH(tt) || (tt) == CPTR || (tt) == CARR)
+#define IS_SCALAR(tt) (!((tt) == CUNION || (tt) == CSTRUCT))
-CType_t semantics_cast(CNode *p, CScope_t scope) {
- CNode *t, *ast;
- CType_t tt, type;
- if (p->type == TYPE_SPEC)
+CType_t semantics_typename(CNode *p, CScope_t scope) {
+ CVar_t var = semantics_declr(p->chd->next,
+ semantics_type_spec(p->chd, scope),
+ scope, 0);
+ CType_t type = var->type;
+ free(var);
+ if (!IS_SCALAR(type->type))
{
- type = semantics_type_spec(p, scope);
- ast = p;
+ sprintf(err_buff, "conversion to non-scalar type requested");
+ ERROR(p);
}
- else
+ if (type->type == CARR)
{
- type = ctype_create("", CPTR, p); /* pointer */
- for (t = p, tt = type;; t = t->chd)
- {
- if (t->chd->type == TYPE_SPEC)
- {
- tt->rec.ref = semantics_type_spec(t->chd, scope);
- ast = t;
- break;
- }
- tt->rec.ref = ctype_create("", CPTR, t);
- tt = tt->rec.ref;
- }
+ sprintf(err_buff, "cast specifies array type");
+ ERROR(p);
}
- if (!IS_SCALAR(type->type))
+ if (type->type == CFUNC)
{
- sprintf(err_buff, "conversion to non-scalar type requested");
- ERROR(ast);
+ sprintf(err_buff, "cast specifies function type");
+ ERROR(p);
}
- type->ast = ast;
+ type->ast = p;
return type;
}
@@ -1121,7 +1115,7 @@ ExpType semantics_exp(CNode *p, CScope_t scope) {
res = exp_check_arith(op1, op2, p);
break;
case EXP_CAST:
- res.type = semantics_cast(p->chd, scope);
+ res.type = semantics_typename(p->chd, scope);
res.lval = 0;
break;
case '&':
@@ -1395,6 +1389,7 @@ CVar_t semantics_func(CNode *p, CScope_t scope) {
funco->rec.func.body = res->type->rec.func.body;
free(res);
}
+ free(head);
return old;
}
diff --git a/testcases/cast.c b/testcases/cast.c
new file mode 100644
index 0000000..b441552
--- /dev/null
+++ b/testcases/cast.c
@@ -0,0 +1,3 @@
+int main() {
+ ((int (*)(int a))1)(1);
+}
diff --git a/testcases/cast2.c b/testcases/cast2.c
new file mode 100644
index 0000000..34b3484
--- /dev/null
+++ b/testcases/cast2.c
@@ -0,0 +1,3 @@
+int main() {
+ (int [3])1;
+}
diff --git a/testcases/cast3.c b/testcases/cast3.c
new file mode 100644
index 0000000..4500cb1
--- /dev/null
+++ b/testcases/cast3.c
@@ -0,0 +1,3 @@
+int main() {
+ (int ())1;
+}
diff --git a/testcases/fail10.c b/testcases/fail10.c
new file mode 100644
index 0000000..e287c6f
--- /dev/null
+++ b/testcases/fail10.c
@@ -0,0 +1,4 @@
+int main() {
+ int a[2][3];
+ a[1][3][3] = 3;
+}
diff --git a/testcases/fail11.c b/testcases/fail11.c
new file mode 100644
index 0000000..4aa213a
--- /dev/null
+++ b/testcases/fail11.c
@@ -0,0 +1,4 @@
+int main() {
+ int a[2][3];
+ a[1] = 3;
+}
diff --git a/testcases/fail8.c b/testcases/fail8.c
new file mode 100644
index 0000000..21efd5f
--- /dev/null
+++ b/testcases/fail8.c
@@ -0,0 +1,5 @@
+struct {
+ int f();
+};
+int main() {
+}
diff --git a/testcases/localfunc.c b/testcases/localfunc.c
new file mode 100644
index 0000000..8012c6f
--- /dev/null
+++ b/testcases/localfunc.c
@@ -0,0 +1,4 @@
+int f(int a);
+int main() {
+ int f(int a, int b);
+}