From 1b208f7f0a3b7d6b72c2a431d9fcd6e18fe76f5d Mon Sep 17 00:00:00 2001 From: nsfisis Date: Sun, 28 Sep 2025 15:24:28 +0900 Subject: feat: support using function as a value --- src/ast.h | 1 + src/codegen.c | 7 +++++++ src/parse.c | 9 ++++++++- tests/test_function_pointers.sh | 18 +++++++++++++++--- 4 files changed, 31 insertions(+), 4 deletions(-) diff --git a/src/ast.h b/src/ast.h index 5f4367d..c5171d7 100644 --- a/src/ast.h +++ b/src/ast.h @@ -102,6 +102,7 @@ typedef enum { AstNodeKind_enum_member, AstNodeKind_expr_stmt, AstNodeKind_for_stmt, + AstNodeKind_func, AstNodeKind_func_call, AstNodeKind_func_decl, AstNodeKind_func_def, diff --git a/src/codegen.c b/src/codegen.c index 36f854d..34f6c23 100644 --- a/src/codegen.c +++ b/src/codegen.c @@ -439,6 +439,11 @@ static void codegen_gvar(CodeGen* g, AstNode* ast, GenMode gen_mode) { } } +static void codegen_func_ref(CodeGen* g, AstNode* ast) { + fprintf(g->out, " lea rax, %s[rip]\n", ast->name); + fprintf(g->out, " push rax\n"); +} + static void codegen_composite_expr(CodeGen* g, AstNode* ast) { // Standard C does not have composite expression, but ducc internally has. for (int i = 0; i < ast->node_len; ++i) { @@ -478,6 +483,8 @@ static void codegen_expr(CodeGen* g, AstNode* ast, GenMode gen_mode) { codegen_lvar(g, ast, gen_mode); } else if (ast->kind == AstNodeKind_gvar) { codegen_gvar(g, ast, gen_mode); + } else if (ast->kind == AstNodeKind_func) { + codegen_func_ref(g, ast); } else if (ast->kind == AstNodeKind_list) { codegen_composite_expr(g, ast); } else { diff --git a/src/parse.c b/src/parse.c index dbbb61d..80c7aac 100644 --- a/src/parse.c +++ b/src/parse.c @@ -406,7 +406,14 @@ static AstNode* parse_primary_expr(Parser* p) { if (gvar_idx == -1) { int enum_member_idx = find_enum_member(p, name); if (enum_member_idx == -1) { - fatal_error("undefined variable: %s", name); + int func_idx = find_func(p, name); + if (func_idx == -1) { + fatal_error("undefined variable: %s", name); + } + AstNode* e = ast_new(AstNodeKind_func); + e->name = name; + e->ty = p->funcs.data[func_idx].ty; + return e; } int enum_idx = enum_member_idx / 1000; int n = enum_member_idx % 1000; diff --git a/tests/test_function_pointers.sh b/tests/test_function_pointers.sh index c97a087..cddc623 100644 --- a/tests/test_function_pointers.sh +++ b/tests/test_function_pointers.sh @@ -1,12 +1,24 @@ cat <<'EOF' > expected +a +h +g EOF test_diff <<'EOF' -int* f(int a); -int (*f)(int a); +int* f1(int a); +int (*f2)(int a); extern int atexit (void (*) (void)); extern int atexit (void (*fn) (void)); -int main() {} +int printf(const char*, ...); + +void g() { printf("g\n"); } +void h() { printf("h\n"); } + +int main() { + atexit(g); + atexit(h); + printf("a\n"); +} EOF -- cgit v1.2.3-70-g09d2