From 175b00181b627bec69f645d6d8fc880a2bdd3f81 Mon Sep 17 00:00:00 2001 From: nsfisis Date: Sat, 10 Jan 2026 11:03:51 +0900 Subject: feat: support global variables of char[] --- src/ast.c | 95 +++++++++++++++++++++++++++++++++++++++++++++++ src/ast.h | 2 + src/codegen.c | 21 +++++++---- tests/global_variables.c | 36 ++++++++++++++++++ tests/global_variables.sh | 39 ------------------- 5 files changed, 146 insertions(+), 47 deletions(-) create mode 100644 tests/global_variables.c delete mode 100644 tests/global_variables.sh diff --git a/src/ast.c b/src/ast.c index 59a2087..75aa7ee 100644 --- a/src/ast.c +++ b/src/ast.c @@ -182,6 +182,101 @@ int to_aligned(int n, int a) { return (n + a - 1) / a * a; } +const char* astnode_kind_stringify(AstNodeKind k) { + switch (k) { + case AstNodeKind_unknown: + return "unknown"; + case AstNodeKind_nop: + return "nop"; + case AstNodeKind_assign_expr: + return "assign_expr"; + case AstNodeKind_binary_expr: + return "binary_expr"; + case AstNodeKind_break_stmt: + return "break_stmt"; + case AstNodeKind_case_label: + return "case_label"; + case AstNodeKind_cast_expr: + return "cast_expr"; + case AstNodeKind_cond_expr: + return "cond_expr"; + case AstNodeKind_continue_stmt: + return "continue_stmt"; + case AstNodeKind_default_label: + return "default_label"; + case AstNodeKind_deref_expr: + return "deref_expr"; + case AstNodeKind_do_while_stmt: + return "do_while_stmt"; + case AstNodeKind_enum_def: + return "enum_def"; + case AstNodeKind_enum_member: + return "enum_member"; + case AstNodeKind_expr_stmt: + return "expr_stmt"; + case AstNodeKind_for_stmt: + return "for_stmt"; + case AstNodeKind_func: + return "func"; + case AstNodeKind_func_call: + return "func_call"; + case AstNodeKind_func_decl: + return "func_decl"; + case AstNodeKind_func_def: + return "func_def"; + case AstNodeKind_goto_stmt: + return "goto_stmt"; + case AstNodeKind_gvar: + return "gvar"; + case AstNodeKind_gvar_decl: + return "gvar_decl"; + case AstNodeKind_if_stmt: + return "if_stmt"; + case AstNodeKind_int_expr: + return "int_expr"; + case AstNodeKind_label_stmt: + return "label_stmt"; + case AstNodeKind_list: + return "list"; + case AstNodeKind_logical_expr: + return "logical_expr"; + case AstNodeKind_lvar: + return "lvar"; + case AstNodeKind_lvar_decl: + return "lvar_decl"; + case AstNodeKind_param: + return "param"; + case AstNodeKind_ref_expr: + return "ref_expr"; + case AstNodeKind_return_stmt: + return "return_stmt"; + case AstNodeKind_str_expr: + return "str_expr"; + case AstNodeKind_struct_decl: + return "struct_decl"; + case AstNodeKind_struct_def: + return "struct_def"; + case AstNodeKind_struct_member: + return "struct_member"; + case AstNodeKind_switch_stmt: + return "switch_stmt"; + case AstNodeKind_type: + return "type"; + case AstNodeKind_typedef_decl: + return "typedef_decl"; + case AstNodeKind_unary_expr: + return "unary_expr"; + case AstNodeKind_union_decl: + return "union_decl"; + case AstNodeKind_union_def: + return "union_def"; + case AstNodeKind_declarator: + return "declarator"; + default: + unreachable(); + } +} + AstNode* ast_new(AstNodeKind kind) { AstNode* ast = calloc(1, sizeof(AstNode)); ast->kind = kind; diff --git a/src/ast.h b/src/ast.h index 4ca2e1b..0339457 100644 --- a/src/ast.h +++ b/src/ast.h @@ -134,6 +134,8 @@ typedef enum { AstNodeKind_declarator, } AstNodeKind; +const char* astnode_kind_stringify(AstNodeKind k); + #define node_items __n1 #define node_len __i1 #define node_cap __i2 diff --git a/src/codegen.c b/src/codegen.c index 1c7abf7..be8acd7 100644 --- a/src/codegen.c +++ b/src/codegen.c @@ -469,18 +469,18 @@ static void codegen_func_call(CodeGen* g, AstNode* ast) { // Fetch from register save area fprintf(g->out, " mov rcx, QWORD PTR [rdi+16]\n"); // rcx = reg_save_area - fprintf(g->out, " movsx rdx, eax\n"); // rdx = gp_offset (sign-extended) - fprintf(g->out, " add rcx, rdx\n"); // rcx = reg_save_area + gp_offset - fprintf(g->out, " add eax, 8\n"); // gp_offset += 8 - fprintf(g->out, " mov DWORD PTR [rdi], eax\n"); // store updated gp_offset - fprintf(g->out, " mov rax, rcx\n"); // return pointer to argument + fprintf(g->out, " movsx rdx, eax\n"); // rdx = gp_offset (sign-extended) + fprintf(g->out, " add rcx, rdx\n"); // rcx = reg_save_area + gp_offset + fprintf(g->out, " add eax, 8\n"); // gp_offset += 8 + fprintf(g->out, " mov DWORD PTR [rdi], eax\n"); // store updated gp_offset + fprintf(g->out, " mov rax, rcx\n"); // return pointer to argument fprintf(g->out, " jmp .Lva_arg_end%d\n", label); // Fetch from overflow area (stack) fprintf(g->out, ".Lva_arg_overflow%d:\n", label); fprintf(g->out, " mov rcx, QWORD PTR [rdi+8]\n"); // rcx = overflow_arg_area - fprintf(g->out, " mov rax, rcx\n"); // return pointer to argument - fprintf(g->out, " add rcx, 8\n"); // overflow_arg_area += 8 + fprintf(g->out, " mov rax, rcx\n"); // return pointer to argument + fprintf(g->out, " add rcx, 8\n"); // overflow_arg_area += 8 fprintf(g->out, " mov QWORD PTR [rdi+8], rcx\n"); // store updated overflow_arg_area fprintf(g->out, ".Lva_arg_end%d:\n", label); @@ -903,6 +903,11 @@ void codegen(Program* prog, FILE* out) { } else { unimplemented(); } + } else if (var->ty->kind == TypeKind_array && var->ty->base->kind == TypeKind_char) { + if (var->node_expr->kind != AstNodeKind_str_expr) + unimplemented(); + const char* str = prog->str_literals[var->node_expr->node_idx - 1]; + fprintf(g->out, " %s: .string \"%s\"\n", var->name, str); } else { unimplemented(); } @@ -913,7 +918,7 @@ void codegen(Program* prog, FILE* out) { fprintf(g->out, ".text\n\n"); for (int i = 0; i < prog->funcs->node_len; ++i) { - AstNode* func = prog->funcs->node_items + i; + AstNode* func = &prog->funcs->node_items[i]; codegen_func(g, func); } } diff --git a/tests/global_variables.c b/tests/global_variables.c new file mode 100644 index 0000000..20e0a64 --- /dev/null +++ b/tests/global_variables.c @@ -0,0 +1,36 @@ +#include + +int printf(const char*, ...); +int strcmp(const char*, const char*); + +int a; +int* b = &a; +int c[10]; +int* d = c; +int e, *f = e, g[10], *h = g; + +char i = 42; +short j = 123; +int k = 999; + +char l[6] = "hello"; + +int main() { + *b = 123; + ASSERT_EQ(123, a); + + d[2] = 42; + ASSERT_EQ(42, c[2]); + + *f = 456; + ASSERT_EQ(456, e); + + h[5] = 789; + ASSERT_EQ(789, g[5]); + + ASSERT_EQ(42, i); + ASSERT_EQ(123, j); + ASSERT_EQ(999, k); + + ASSERT_EQ(0, strcmp("hello", l)); +} diff --git a/tests/global_variables.sh b/tests/global_variables.sh deleted file mode 100644 index fac386d..0000000 --- a/tests/global_variables.sh +++ /dev/null @@ -1,39 +0,0 @@ -cat <<'EOF' > expected -42 123 999 -EOF - -test_diff <<'EOF' -int printf(); - -char a = 42; -short b = 123; -int c = 999; - -int main() { - printf("%d %d %d\n", a, b, c); -} -EOF - -test_exit_code 0 <<'EOF' -#include - -int a; -int* b = &a; -int c[10]; -int* d = c; -int e, *f = e, g[10], *h = g; - -int main() { - *b = 123; - ASSERT_EQ(123, a); - - d[2] = 42; - ASSERT_EQ(42, c[2]); - - *f = 456; - ASSERT_EQ(456, e); - - h[5] = 789; - ASSERT_EQ(789, g[5]); -} -EOF -- cgit v1.2.3-70-g09d2