aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-02-05 23:51:26 +0900
committernsfisis <nsfisis@gmail.com>2026-02-06 00:01:34 +0900
commit3633f9a1f4f7638355beba85c53a2bb2ab0e3976 (patch)
tree58dd3231c5580d770defc2268ffe75dd87c11dec
parent0dcaa7de7208bbcd56624011a43bac66f5dee44b (diff)
downloadducc-3633f9a1f4f7638355beba85c53a2bb2ab0e3976.tar.gz
ducc-3633f9a1f4f7638355beba85c53a2bb2ab0e3976.tar.zst
ducc-3633f9a1f4f7638355beba85c53a2bb2ab0e3976.zip
feat: implement more complex initializer
-rw-r--r--src/codegen.c104
-rw-r--r--src/parse.c44
-rw-r--r--src/parse.h2
-rw-r--r--tests/variables.c13
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;