aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTeddy <ted.sybil@gmail.com>2014-04-06 03:14:20 +0800
committerTeddy <ted.sybil@gmail.com>2014-04-06 03:14:20 +0800
commit228e587d52381b1c7f081f06e57873c92fe2964a (patch)
tree9d86808642fc8de1b6b46d9472822142469c03e3
parente1fd11de0bad5fa1a852b8fa497b572555448c5a (diff)
...
-rw-r--r--TODO.rst8
-rw-r--r--semantics.c26
-rwxr-xr-xtest_all.sh5
-rw-r--r--testcases/pass.c9
4 files changed, 40 insertions, 8 deletions
diff --git a/TODO.rst b/TODO.rst
index 0123e4b..ab69797 100644
--- a/TODO.rst
+++ b/TODO.rst
@@ -3,5 +3,9 @@ TODO
- More detailed checking in regex for:
- - char constant
- - string constant
+ - char constant (done)
+ - string constant (done)
+
+- Fix:
+
+ - local function declaration is not in a local scope
diff --git a/semantics.c b/semantics.c
index ed3cc47..00f956c 100644
--- a/semantics.c
+++ b/semantics.c
@@ -581,6 +581,11 @@ CTable_t semantics_fields(CNode *p, CScope_t scope) {
CVar_t var = semantics_declr(declr,
semantics_type_spec(p->chd, scope),
scope, 0);
+ if (var->type->type == CFUNC)
+ {
+ sprintf(err_buff, "field '%s' declared as a function", var->name);
+ ERROR(var->ast);
+ }
/* incomplete type checking */
if (!type_is_complete(var->type))
{
@@ -794,6 +799,8 @@ ExpType exp_check_deref(ExpType op1, CNode *ast) {
sprintf(err_buff, "invalid type argument of unary '*'");
ERROR(ast);
}
+ if (op1.type->rec.ref->type == CFUNC)
+ return op1;
op1.lval = 1; /* deref changes exp to lval */
if (!type_is_complete(op1.type = op1.type->rec.ref))
{
@@ -805,6 +812,9 @@ ExpType exp_check_deref(ExpType op1, CNode *ast) {
ExpType exp_check_ref(ExpType op1, CNode *ast) {
ExpType res;
+ CType_t t = op1.type;
+ if (t->type == CARR || (t->type == CPTR && t->rec.ref->type == CFUNC))
+ return op1;
if (!op1.lval)
{
sprintf(err_buff, "lvalue required as unary '&' operand");
@@ -935,7 +945,8 @@ ExpType exp_check_postfix(CNode *p, CScope_t scope) {
op1.lval = 1;
break;
case POSTFIX_CALL:
- if (t1 != CFUNC)
+ if (!((t1 == CFUNC) ||
+ (t1 == CPTR && op1.type->rec.ref->type == CFUNC)))
{
sprintf(err_buff, "called object is not a function");
ERROR(p);
@@ -943,7 +954,10 @@ ExpType exp_check_postfix(CNode *p, CScope_t scope) {
{
CNode *arg = post->chd->chd;
CType_t func = p->chd->ext.type;
- CVar_t param = func->rec.func.params;
+ CVar_t param;
+ /* pointer to function */
+ if (func->type == CPTR) func = func->rec.ref;
+ param = func->rec.func.params;
for (; arg && param;
arg = arg->next, param = param->next)
{
@@ -1026,6 +1040,12 @@ ExpType semantics_exp(CNode *p, CScope_t scope) {
}
res.type = p->ext.var->type;
res.lval = !(res.type->type == CARR || res.type->type == CFUNC);
+ if (res.type->type == CFUNC)
+ {
+ CType_t f = ctype_create("", CPTR, p);
+ f->rec.ref = res.type;
+ res.type = f;
+ }
break;
case INT:
res.type = basic_type_int;
@@ -1325,7 +1345,7 @@ CVar_t semantics_func(CNode *p, CScope_t scope) {
}
scope->func = func;
- cscope_enter(scope); /* enter function local scope */
+ cscope_enter(scope); /* enter function local scope */
{ /* 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 */
diff --git a/test_all.sh b/test_all.sh
index 28c26d4..cb2aa87 100755
--- a/test_all.sh
+++ b/test_all.sh
@@ -1,11 +1,12 @@
#! /bin/bash
-for file in test/*
+for file in testcases/*.c
do
gcc $file -o /dev/null &> /dev/null
gcc_ret="$?"
./cibic $file &> /dev/null
if [ $? -ne $gcc_ret ]; then
echo "Failed on $file"
- break
+ else
+ echo "ok $file"
fi
done
diff --git a/testcases/pass.c b/testcases/pass.c
index 835483e..ebcae0a 100644
--- a/testcases/pass.c
+++ b/testcases/pass.c
@@ -72,7 +72,14 @@ void comma() {
}
int complex_pointer() {
- int (*f(int ***e[10]))();
+ int (*g(int ***e[10]))();
+}
+
+int fp(int a, int b, int c) {
+ int (*f)(int a, int b, int c);
+ f = ****fp + 1;
+ (****f)(1, 2, 3);
+ f = &fp + 1;
}
struct Node n;