diff options
| author | nsfisis <nsfisis@gmail.com> | 2025-07-21 20:48:01 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2025-08-15 10:04:32 +0900 |
| commit | 0c9dc7318361c93e837c8f4bc5c29869076c36cd (patch) | |
| tree | a0998f947324fb42885338d0bd729d02d4309f40 | |
| parent | 1c48d0fe728c263bbe946a5d3adebaa29323ddff (diff) | |
| download | ducc-0c9dc7318361c93e837c8f4bc5c29869076c36cd.tar.gz ducc-0c9dc7318361c93e837c8f4bc5c29869076c36cd.tar.zst ducc-0c9dc7318361c93e837c8f4bc5c29869076c36cd.zip | |
feat: implement va_*() functions
| -rw-r--r-- | codegen.c | 25 | ||||
| -rw-r--r-- | common.c | 8 | ||||
| -rw-r--r-- | justfile | 2 | ||||
| -rw-r--r-- | parse.c | 9 | ||||
| -rw-r--r-- | preprocess.c | 88 | ||||
| -rw-r--r-- | std.h | 31 | ||||
| -rw-r--r-- | tests/063.sh | 52 | ||||
| -rw-r--r-- | tokenize.c | 7 |
8 files changed, 175 insertions, 47 deletions
@@ -209,8 +209,31 @@ void codegen_assign_expr(CodeGen* g, AstNode* ast) { void codegen_func_call(CodeGen* g, AstNode* ast) { String* func_name = &ast->name; - AstNode* args = ast->node_args; int i; + + if (string_equals_cstr(func_name, "va_start")) { + printf(" # va_start BEGIN\n"); + for (i = 0; i < 6; ++i) { + printf(" mov rax, %s\n", param_reg(i)); + printf(" mov [rbp-%d], rax\n", 8 + (LVAR_MAX - 4 - i) * 8); + } + AstNode* va_list_args = ast->node_args->node_items; + codegen_expr(g, va_list_args, GenMode_lval); + printf(" pop rdi\n"); + printf(" mov rax, rbp\n"); + printf(" sub rax, %d\n", 8 + (LVAR_MAX - 1) * 8); + printf(" mov [rdi], rax\n"); + printf(" mov DWORD PTR [rax], 8\n"); + printf(" mov DWORD PTR [rax+4], 0\n"); + printf(" mov QWORD PTR [rax+8], 0\n"); + printf(" mov rdi, rbp\n"); + printf(" sub rdi, %d\n", 8 + (LVAR_MAX - 4) * 8); + printf(" mov QWORD PTR [rax+16], rdi\n"); + printf(" # va_start END\n"); + return; + } + + AstNode* args = ast->node_args; for (i = 0; i < args->node_len; ++i) { AstNode* arg = args->node_items + i; codegen_expr(g, arg, GenMode_rval); @@ -1,5 +1,9 @@ -void fatal_error(const char* msg) { - fprintf(stderr, "%s\n", msg); +void fatal_error(const char* msg, ...) { + va_list args; + va_start(args, msg); + vfprintf(stderr, msg, args); + va_end(args); + fprintf(stderr, "\n"); exit(1); } @@ -3,7 +3,7 @@ all: build build N="1": #!/usr/bin/env bash if [[ {{N}} = 1 ]]; then - gcc -g -O0 -o ducc main.c + gcc -Wno-builtin-declaration-mismatch -g -O0 -o ducc main.c else if [[ {{N}} = 2 ]]; then prev="" @@ -47,6 +47,13 @@ Parser* parser_new(Token* tokens) { p->enums = calloc(16, sizeof(AstNode)); p->typedefs = calloc(64, sizeof(AstNode)); p->str_literals = calloc(1024, sizeof(char*)); + + p->funcs[p->n_funcs].name.data = "va_start"; + p->funcs[p->n_funcs].name.len = strlen("va_start"); + p->funcs[p->n_funcs].ty = calloc(1, sizeof(Type)); + p->funcs[p->n_funcs].ty->kind = TypeKind_void; + ++p->n_funcs; + return p; } @@ -174,7 +181,7 @@ AstNode* parse_primary_expr(Parser* p) { e = parse_expr(p); expect(p, TokenKind_paren_r); return e; - } else if (t->kind == TokenKind_ident) { + } else if (t->kind == TokenKind_ident || t->kind == TokenKind_va_start) { String* name = &t->raw; if (peek_token(p)->kind == TokenKind_paren_l) { diff --git a/preprocess.c b/preprocess.c index 205e2bd..0a577a2 100644 --- a/preprocess.c +++ b/preprocess.c @@ -346,35 +346,48 @@ void process_pp_directives(Preprocessor* pp) { PpToken* tok2 = tok + 1; while (tok2->kind != PpTokenKind_eof && tok2->kind == PpTokenKind_whitespace) ++tok2; - if (tok2->kind == PpTokenKind_identifier && string_equals_cstr(&tok2->raw, "define")) { + if (tok2->kind == PpTokenKind_identifier && string_equals_cstr(&tok2->raw, "endif")) { + ++tok2; + pp->skip_pp_tokens = 0; + // Remove #endif directive. + while (tok != tok2) { + tok->kind = PpTokenKind_whitespace; + tok->raw.len = 0; + tok->raw.data = NULL; + ++tok; + } + } else if (tok2->kind == PpTokenKind_identifier && string_equals_cstr(&tok2->raw, "else")) { + ++tok2; + pp->skip_pp_tokens = 1 - pp->skip_pp_tokens; + // Remove #else directive. + while (tok != tok2) { + tok->kind = PpTokenKind_whitespace; + tok->raw.len = 0; + tok->raw.data = NULL; + ++tok; + } + } else if (tok2->kind == PpTokenKind_identifier && string_equals_cstr(&tok2->raw, "ifdef")) { ++tok2; while (tok2->kind != PpTokenKind_eof && tok2->kind == PpTokenKind_whitespace) ++tok2; if (tok2->kind == PpTokenKind_identifier) { - PpToken* define_name = tok2; + // Process #ifdef directive. + PpToken* name = tok2; ++tok2; - while (tok2->kind != PpTokenKind_eof && tok2->kind == PpTokenKind_whitespace) - ++tok2; - if (tok2->kind == PpTokenKind_identifier || tok2->kind == PpTokenKind_pp_number) { - define_dest = tok2; - PpDefine* pp_define = pp->pp_defines->data + pp->pp_defines->len; - pp_define->name.len = define_name->raw.len; - pp_define->name.data = define_name->raw.data; - pp_define->tokens = calloc(1, sizeof(PpToken)); - pp_define->tokens[0].kind = define_dest->kind; - pp_define->tokens[0].raw.len = define_dest->raw.len; - pp_define->tokens[0].raw.data = define_dest->raw.data; - ++pp->pp_defines->len; - } + pp->skip_pp_tokens = find_pp_define(pp, &name->raw) == -1; } - // Remove #define directive. - while (tok != tok2 + 1) { + // Remove #ifdef directive. + while (tok != tok2) { tok->kind = PpTokenKind_whitespace; tok->raw.len = 0; tok->raw.data = NULL; ++tok; } + } else if (skip_pp_tokens(pp)) { + tok->kind = PpTokenKind_whitespace; + tok->raw.len = 0; + tok->raw.data = NULL; } else if (tok2->kind == PpTokenKind_identifier && string_equals_cstr(&tok2->raw, "include")) { ++tok2; while (tok2->kind != PpTokenKind_eof && tok2->kind == PpTokenKind_whitespace) @@ -422,38 +435,29 @@ void process_pp_directives(Preprocessor* pp) { pp->n_pp_tokens += n_include_pp_tokens; } - } else if (tok2->kind == PpTokenKind_identifier && string_equals_cstr(&tok2->raw, "ifdef")) { + } else if (tok2->kind == PpTokenKind_identifier && string_equals_cstr(&tok2->raw, "define")) { ++tok2; while (tok2->kind != PpTokenKind_eof && tok2->kind == PpTokenKind_whitespace) ++tok2; if (tok2->kind == PpTokenKind_identifier) { - // Process #ifdef directive. - PpToken* name = tok2; + PpToken* define_name = tok2; ++tok2; + while (tok2->kind != PpTokenKind_eof && tok2->kind == PpTokenKind_whitespace) + ++tok2; + if (tok2->kind == PpTokenKind_identifier || tok2->kind == PpTokenKind_pp_number) { + define_dest = tok2; - pp->skip_pp_tokens = find_pp_define(pp, &name->raw) == -1; - } - // Remove #ifdef directive. - while (tok != tok2 + 1) { - tok->kind = PpTokenKind_whitespace; - tok->raw.len = 0; - tok->raw.data = NULL; - ++tok; - } - } else if (tok2->kind == PpTokenKind_identifier && string_equals_cstr(&tok2->raw, "endif")) { - ++tok2; - pp->skip_pp_tokens = 0; - // Remove #endif directive. - while (tok != tok2 + 1) { - tok->kind = PpTokenKind_whitespace; - tok->raw.len = 0; - tok->raw.data = NULL; - ++tok; + PpDefine* pp_define = pp->pp_defines->data + pp->pp_defines->len; + pp_define->name.len = define_name->raw.len; + pp_define->name.data = define_name->raw.data; + pp_define->tokens = calloc(1, sizeof(PpToken)); + pp_define->tokens[0].kind = define_dest->kind; + pp_define->tokens[0].raw.len = define_dest->raw.len; + pp_define->tokens[0].raw.data = define_dest->raw.data; + ++pp->pp_defines->len; + } } - } else if (tok2->kind == PpTokenKind_identifier && string_equals_cstr(&tok2->raw, "else")) { - ++tok2; - pp->skip_pp_tokens = 1 - pp->skip_pp_tokens; - // Remove #else directive. + // Remove #define directive. while (tok != tok2 + 1) { tok->kind = PpTokenKind_whitespace; tok->raw.len = 0; @@ -29,3 +29,34 @@ int strncmp(const char*, const char*, size_t); char* strstr(const char*, const char*); #define NULL 0 + +#ifdef __ducc__ + +// System V Application Binary Interface +// AMD64 Architecture Processor Supplement +// (With LP64 and ILP32 Programming Models) +// Version 1.0 +// Figure 3.34: va_list Type Declaration +struct __va_list__ { + // unsigned int gp_offset; + // unsigned int fp_offset; + int gp_offset; + int fp_offset; + void* overflow_arg_area; + void* reg_save_area; +}; +// ducc currently does not support array type. +// typedef struct __va_list__ va_list[1]; +typedef struct __va_list__* va_list; + +// va_start() is currently implemented as a special form due to the limitation of #define macro. +void va_end(va_list args) { +} + +#else + +#include <stdarg.h> + +#endif + +int vfprintf(FILE*, const char*, va_list); diff --git a/tests/063.sh b/tests/063.sh new file mode 100644 index 0000000..f5f9505 --- /dev/null +++ b/tests/063.sh @@ -0,0 +1,52 @@ +set -e + +cat <<'EOF' > expected +123 +456 789 +EOF + +bash ../../test_diff.sh <<'EOF' +int fprintf(); + +// System V Application Binary Interface +// AMD64 Architecture Processor Supplement +// (With LP64 and ILP32 Programming Models) +// Version 1.0 +// Figure 3.34: va_list Type Declaration +struct __va_list__ { + // unsigned int gp_offset; + // unsigned int fp_offset; + int gp_offset; + int fp_offset; + void* overflow_arg_area; + void* reg_save_area; +}; +// ducc currently does not support array type. +// typedef struct __va_list__ va_list[1]; +typedef struct __va_list__* va_list; + +// va_start() is currently implemented as a special form due to the limitation of #define macro. +void va_end(va_list args) { +} + +struct FILE; +typedef struct FILE FILE; + +extern FILE* stdout; + +int vfprintf(FILE*, const char*, va_list); + +void fatal_error(const char* msg, ...) { + va_list args; + va_start(args, msg); + vfprintf(stdout, msg, args); + va_end(args); + fprintf(stdout, "\n"); +} + +int main() { + fatal_error("%d", 123); + fatal_error("%d %d", 456, 789); + return 0; +} +EOF @@ -53,6 +53,9 @@ enum TokenKind { TokenKind_semicolon, TokenKind_slash, TokenKind_star, + + // va_start() is currently implemented as a special form due to the current limitation of #define macro. + TokenKind_va_start, }; typedef enum TokenKind TokenKind; @@ -169,6 +172,8 @@ const char* token_kind_stringify(TokenKind k) { return "/"; else if (k == TokenKind_star) return "*"; + else if (k == TokenKind_va_start) + return "va_start"; else unreachable(); } @@ -247,6 +252,8 @@ void tokenize_all(Lexer* l) { tok->kind = TokenKind_keyword_void; } else if (string_equals_cstr(&pp_tok->raw, "while")) { tok->kind = TokenKind_keyword_while; + } else if (string_equals_cstr(&pp_tok->raw, "va_start")) { + tok->kind = TokenKind_va_start; } else { tok->kind = TokenKind_ident; } |
