diff options
| author | nsfisis <nsfisis@gmail.com> | 2026-02-07 15:42:00 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2026-02-07 17:33:55 +0900 |
| commit | cdddf2422553f1f21c8d2c57cd382b8362dc80fb (patch) | |
| tree | 3053026498552aecda2e4889c8455298ad70c8cb /src/parse.c | |
| parent | e1042a6373773830297dfd5718938c12f21ae624 (diff) | |
| download | ducc-cdddf2422553f1f21c8d2c57cd382b8362dc80fb.tar.gz ducc-cdddf2422553f1f21c8d2c57cd382b8362dc80fb.tar.zst ducc-cdddf2422553f1f21c8d2c57cd382b8362dc80fb.zip | |
feat: support function calls via function pointers
The two-pass parsing of function pointer declaration is referenced from chibicc:
https://github.com/rui314/chibicc
Diffstat (limited to 'src/parse.c')
| -rw-r--r-- | src/parse.c | 42 |
1 files changed, 32 insertions, 10 deletions
diff --git a/src/parse.c b/src/parse.c index 6443de2..9083ecc 100644 --- a/src/parse.c +++ b/src/parse.c @@ -637,14 +637,6 @@ static AstNode* parse_primary_expr(Parser* p) { } else if (t->kind == TokenKind_ident) { const char* name = t->value.string; - if (peek_token(p)->kind == TokenKind_paren_l) { - int func_idx = find_func(p, name); - if (func_idx == -1) { - fatal_error("%s:%d: undefined function: %s", t->loc.filename, t->loc.line, name); - } - return ast_new_func_call(name, p->funcs.data[func_idx].ty->result); - } - int lvar_idx = find_lvar(p, name); if (lvar_idx == -1) { int gvar_idx = find_gvar(p, name); @@ -695,7 +687,12 @@ static AstNode* parse_postfix_expr(Parser* p) { if (consume_token_if(p, TokenKind_paren_l)) { AstNode* args = parse_argument_expr_list(p); expect(p, TokenKind_paren_r); - ret->as.func_call->args = args; + ret = ast_new_func_call(ret, args); + Type* func_type = ret->as.func_call->func->ty; + if (func_type->kind == TypeKind_ptr) { + func_type = func_type->base; + } + ret->ty = func_type->result; } else if (consume_token_if(p, TokenKind_bracket_l)) { AstNode* idx = parse_expr(p); expect(p, TokenKind_bracket_r); @@ -758,7 +755,12 @@ static AstNode* parse_unary_expr(Parser* p) { return ast_new_ref_expr(operand); } else if (consume_token_if(p, TokenKind_star)) { AstNode* operand = parse_cast_expr(p); - return ast_new_deref_expr(operand); + if (operand->ty->kind == TypeKind_func) { + // dereference operator against function pointers are no-op. + return operand; + } else { + return ast_new_deref_expr(operand); + } } else if (consume_token_if(p, TokenKind_plusplus)) { AstNode* operand = parse_unary_expr(p); return ast_new_assign_add_expr(operand, ast_new_int(1)); @@ -1228,8 +1230,28 @@ static AstNode* parse_direct_declarator(Parser* p, Type* ty) { decl = ast_new_declarator(parse_ident(p)->value.string, ty); } else if (peek_token(p)->kind == TokenKind_paren_l && !is_type_token(p, peek_token2(p))) { next_token(p); + // 1st pass: skip content inside parentheses. + int saved_pos = p->pos; + Type* dummy = type_new(TypeKind_void); + parse_declarator(p, dummy); + expect(p, TokenKind_paren_r); + // Parse suffixes. + while (1) { + if (peek_token(p)->kind == TokenKind_bracket_l) { + ty = parse_array_declarator_suffix(p, ty); + } else if (peek_token(p)->kind == TokenKind_paren_l) { + ty = parse_function_declarator_suffix(p, ty); + } else { + break; + } + } + // 2nd pass: re-parse inner content. + int end_pos = p->pos; + p->pos = saved_pos; decl = parse_declarator(p, ty); expect(p, TokenKind_paren_r); + p->pos = end_pos; + return ast_new_declarator(decl->as.declarator->name, decl->ty); } else { decl = ast_new_declarator(NULL, ty); } |
