diff options
| author | nsfisis <nsfisis@gmail.com> | 2026-02-05 23:51:26 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2026-02-06 00:01:34 +0900 |
| commit | 3633f9a1f4f7638355beba85c53a2bb2ab0e3976 (patch) | |
| tree | 58dd3231c5580d770defc2268ffe75dd87c11dec | |
| parent | 0dcaa7de7208bbcd56624011a43bac66f5dee44b (diff) | |
| download | ducc-3633f9a1f4f7638355beba85c53a2bb2ab0e3976.tar.gz ducc-3633f9a1f4f7638355beba85c53a2bb2ab0e3976.tar.zst ducc-3633f9a1f4f7638355beba85c53a2bb2ab0e3976.zip | |
feat: implement more complex initializer
| -rw-r--r-- | src/codegen.c | 104 | ||||
| -rw-r--r-- | src/parse.c | 44 | ||||
| -rw-r--r-- | src/parse.h | 2 | ||||
| -rw-r--r-- | tests/variables.c | 13 |
4 files changed, 103 insertions, 60 deletions
diff --git a/src/codegen.c b/src/codegen.c index 2247c6c..b19dc25 100644 --- a/src/codegen.c +++ b/src/codegen.c @@ -2,6 +2,7 @@ #include <stdlib.h> #include <string.h> #include "common.h" +#include "parse.h" #include "preprocess.h" typedef enum { @@ -10,6 +11,7 @@ typedef enum { } GenMode; typedef struct { + Program* prog; FILE* out; int next_label; int* loop_labels; @@ -17,8 +19,9 @@ typedef struct { int switch_label; } CodeGen; -static CodeGen* codegen_new(FILE* out) { +static CodeGen* codegen_new(Program* prog, FILE* out) { CodeGen* g = calloc(1, sizeof(CodeGen)); + g->prog = prog; g->out = out; g->next_label = 1; g->loop_labels = calloc(1024, sizeof(int)); @@ -816,8 +819,46 @@ static void codegen_func(CodeGen* g, AstNode* ast) { g->current_func = NULL; } + +static void codegen_global_var(CodeGen* g, AstNode* var) { + fprintf(g->out, " %s:\n", var->as.gvar_decl->name); + if (!var->as.gvar_decl->expr) { + fprintf(g->out, " .zero %d\n", type_sizeof(var->ty)); + return; + } + + if (var->ty->kind == TypeKind_ptr) { + if (var->as.gvar_decl->expr->kind == AstNodeKind_ref_expr) { + if (var->as.gvar_decl->expr->as.ref_expr->operand->kind != AstNodeKind_gvar) { + unimplemented(); + } + fprintf(g->out, " .quad %s\n", var->as.gvar_decl->expr->as.ref_expr->operand->as.gvar->name); + } else if (var->as.gvar_decl->expr->kind == AstNodeKind_gvar) { + fprintf(g->out, " .quad %s\n", var->as.gvar_decl->expr->as.gvar->name); + } else { + unimplemented(); + } + return; + } + if (var->ty->kind == TypeKind_array && var->as.gvar_decl->expr->kind == AstNodeKind_str_expr) { + const char* str = g->prog->str_literals[var->as.gvar_decl->expr->as.str_expr->idx - 1]; + fprintf(g->out, " .string \"%s\"\n", str); + return; + } + + StrBuilder* data_buf = calloc(1, sizeof(StrBuilder)); + strbuilder_init(data_buf); + strbuilder_reserve(data_buf, type_sizeof(var->ty)); + + eval_init_expr(data_buf, var->as.gvar_decl->expr, var->ty); + + for (size_t i = 0; i < data_buf->len; ++i) { + fprintf(g->out, " .byte %d\n", (int)data_buf->buf[i]); + } +} + void codegen(Program* prog, FILE* out) { - CodeGen* g = codegen_new(out); + CodeGen* g = codegen_new(prog, out); fprintf(g->out, ".intel_syntax noprefix\n\n"); @@ -833,64 +874,7 @@ void codegen(Program* prog, FILE* out) { fprintf(g->out, ".data\n\n"); for (int i = 0; i < prog->vars->as.list->len; ++i) { - AstNode* var = prog->vars->as.list->items + i; - fprintf(g->out, " %s:\n", var->as.gvar_decl->name); - if (var->as.gvar_decl->expr) { - if (type_sizeof(var->ty) == 1) { - if (var->as.gvar_decl->expr->kind != AstNodeKind_int_expr) - unimplemented(); - fprintf(g->out, " .byte %d\n", var->as.gvar_decl->expr->as.int_expr->value); - } else if (type_sizeof(var->ty) == 2) { - if (var->as.gvar_decl->expr->kind != AstNodeKind_int_expr) - unimplemented(); - fprintf(g->out, " .word %d\n", var->as.gvar_decl->expr->as.int_expr->value); - } else if (type_sizeof(var->ty) == 4) { - if (var->as.gvar_decl->expr->kind != AstNodeKind_int_expr) - unimplemented(); - fprintf(g->out, " .long %d\n", var->as.gvar_decl->expr->as.int_expr->value); - } else if (var->ty->kind == TypeKind_ptr) { - if (var->as.gvar_decl->expr->kind == AstNodeKind_ref_expr) { - if (var->as.gvar_decl->expr->as.ref_expr->operand->kind != AstNodeKind_gvar) { - unimplemented(); - } - fprintf(g->out, " .quad %s\n", var->as.gvar_decl->expr->as.ref_expr->operand->as.gvar->name); - } else if (var->as.gvar_decl->expr->kind == AstNodeKind_gvar) { - fprintf(g->out, " .quad %s\n", var->as.gvar_decl->expr->as.gvar->name); - } else { - unimplemented(); - } - } else if (var->ty->kind == TypeKind_array) { - if (var->as.gvar_decl->expr->kind == AstNodeKind_str_expr) { - const char* str = prog->str_literals[var->as.gvar_decl->expr->as.str_expr->idx - 1]; - fprintf(g->out, " .string \"%s\"\n", str); - } else if (var->as.gvar_decl->expr->kind == AstNodeKind_array_initializer) { - AstNode* init = var->as.gvar_decl->expr->as.array_initializer->list; - int elem_size = type_sizeof(var->ty->base); - const char* directive; - if (elem_size == 1) { - directive = ".byte"; - } else if (elem_size == 2) { - directive = ".word"; - } else if (elem_size == 4) { - directive = ".long"; - } else { - unimplemented(); - } - for (int j = 0; j < init->as.list->len; ++j) { - AstNode* elem = &init->as.list->items[j]; - if (elem->kind != AstNodeKind_int_expr) - unimplemented(); - fprintf(g->out, " %s %d\n", directive, elem->as.int_expr->value); - } - } else { - unimplemented(); - } - } else { - unimplemented(); - } - } else { - fprintf(g->out, " .zero %d\n", type_sizeof(var->ty)); - } + codegen_global_var(g, &prog->vars->as.list->items[i]); } fprintf(g->out, ".text\n\n"); diff --git a/src/parse.c b/src/parse.c index 629a39f..4a36d6d 100644 --- a/src/parse.c +++ b/src/parse.c @@ -1346,6 +1346,12 @@ static void declare_func_or_var(Parser* p, AstNode* decl) { decl->ty->storage_class = base_ty->storage_class; base_ty->storage_class = StorageClass_unspecified; + // TODO: refactor + if (decl->ty->kind == TypeKind_array && decl->ty->array_size == -1 && decl->as.declarator && + decl->as.declarator->init && decl->as.declarator->init->kind == AstNodeKind_array_initializer) { + decl->ty->array_size = decl->as.declarator->init->as.array_initializer->list->as.list->len; + } + GlobalVar* gvar = gvars_push_new(&p->gvars); gvar->name = name; gvar->ty = decl->ty; @@ -2689,3 +2695,41 @@ bool pp_eval_constant_expr(TokenArray* pp_tokens) { AstNode* e = parse_constant_expr(p); return eval(e) != 0; } + +void eval_init_expr(StrBuilder* buf, AstNode* expr, Type* ty) { + if (expr->kind == AstNodeKind_array_initializer) { + AstNode* list = expr->as.array_initializer->list; + if (ty->kind == TypeKind_array) { + for (int i = 0; i < list->as.list->len; ++i) { + eval_init_expr(buf, &list->as.list->items[i], ty->base); + } + } else if (ty->kind == TypeKind_struct) { + AstNode* def = &ty->ref.defs->as.list->items[ty->ref.index]; + AstNode* members = def->as.struct_def->members; + int offset = 0; + for (int i = 0; i < list->as.list->len; ++i) { + AstNode* member = &members->as.list->items[i]; + int align = type_alignof(member->ty); + int aligned_offset = to_aligned(offset, align); + for (int p = offset; p < aligned_offset; ++p) { + strbuilder_append_char(buf, 0); + } + offset = aligned_offset; + eval_init_expr(buf, &list->as.list->items[i], member->ty); + offset += type_sizeof(member->ty); + } + int total = type_sizeof(ty); + for (int p = offset; p < total; ++p) { + strbuilder_append_char(buf, 0); + } + } else { + unimplemented(); + } + } else { + int value = eval(expr); + int size = type_sizeof(ty); + for (int i = 0; i < size; ++i) { + strbuilder_append_char(buf, (value >> (i * 8)) & 0xff); + } + } +} diff --git a/src/parse.h b/src/parse.h index 7649575..17ffe2c 100644 --- a/src/parse.h +++ b/src/parse.h @@ -2,9 +2,11 @@ #define DUCC_PARSE_H #include "ast.h" +#include "common.h" #include "preprocess.h" Program* parse(TokenArray* tokens); bool pp_eval_constant_expr(TokenArray* pp_tokens); +void eval_init_expr(StrBuilder* buf, AstNode* expr, Type* ty); #endif diff --git a/tests/variables.c b/tests/variables.c index 0be59a3..9ba505e 100644 --- a/tests/variables.c +++ b/tests/variables.c @@ -20,6 +20,14 @@ char arr1[3] = {65, 66, 67}; short arr2[3] = {10, 20, 30}; int arr3[3] = {1, 2, 3}; +struct S { + int x, y; +}; +struct S arr4[] = { + {1, 2}, + {3, 4}, +}; + int main() { // global variables *g_b = 123; @@ -52,6 +60,11 @@ int main() { ASSERT_EQ(2, arr3[1]); ASSERT_EQ(3, arr3[2]); + ASSERT_EQ(1, arr4[0].x); + ASSERT_EQ(2, arr4[0].y); + ASSERT_EQ(3, arr4[1].x); + ASSERT_EQ(4, arr4[1].y); + // local variables int foo; foo = 42; |
