aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-02-07 10:12:57 +0900
committernsfisis <nsfisis@gmail.com>2026-02-07 10:12:57 +0900
commit0034f84a38e8cb41a753d2def1daccd14bbfd552 (patch)
tree6e734a8450c7f7fece5eda4c33ff72bc6ab277fb
parent107c517b22e88d760c375a4b9da6dffd6da26d85 (diff)
downloadducc-0034f84a38e8cb41a753d2def1daccd14bbfd552.tar.gz
ducc-0034f84a38e8cb41a753d2def1daccd14bbfd552.tar.zst
ducc-0034f84a38e8cb41a753d2def1daccd14bbfd552.zip
feat: implement global variables referencing string literals
-rw-r--r--src/codegen.c31
-rw-r--r--src/parse.c85
-rw-r--r--src/parse.h33
-rw-r--r--tests/variables.c15
4 files changed, 131 insertions, 33 deletions
diff --git a/src/codegen.c b/src/codegen.c
index b19dc25..4eb2042 100644
--- a/src/codegen.c
+++ b/src/codegen.c
@@ -819,7 +819,6 @@ 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) {
@@ -827,33 +826,23 @@ static void codegen_global_var(CodeGen* g, AstNode* var) {
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);
+ InitData* data = eval_init_expr(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]);
+ for (size_t i = 0; i < data->len; ++i) {
+ InitDataBlock* block = &data->blocks[i];
+ if (block->kind == InitDataBlockKind_addr) {
+ fprintf(g->out, " .quad %s\n", block->as.addr.label);
+ } else {
+ for (size_t j = 0; j < block->as.bytes.len; ++j) {
+ fprintf(g->out, " .byte %d\n", block->as.bytes.buf[j]);
+ }
+ }
}
}
diff --git a/src/parse.c b/src/parse.c
index 4a36d6d..1b5db5b 100644
--- a/src/parse.c
+++ b/src/parse.c
@@ -2696,12 +2696,60 @@ bool pp_eval_constant_expr(TokenArray* pp_tokens) {
return eval(e) != 0;
}
-void eval_init_expr(StrBuilder* buf, AstNode* expr, Type* ty) {
+static InitData* initdata_new() {
+ InitData* init_data = calloc(1, sizeof(InitData));
+ init_data->len = 0;
+ init_data->capacity = 1;
+ init_data->blocks = calloc(init_data->capacity, sizeof(InitDataBlock));
+ return init_data;
+}
+
+static void initdata_reserve(InitData* init_data, size_t size) {
+ if (size <= init_data->capacity)
+ return;
+ while (init_data->capacity < size) {
+ init_data->capacity *= 2;
+ }
+ init_data->blocks = realloc(init_data->blocks, init_data->capacity * sizeof(InitDataBlock));
+ memset(init_data->blocks + init_data->len, 0, (init_data->capacity - init_data->len) * sizeof(InitDataBlock));
+}
+
+static InitDataBlock* initdata_push_new(InitData* init_data) {
+ initdata_reserve(init_data, init_data->len + 1);
+ return &init_data->blocks[init_data->len++];
+}
+
+static void initdata_append_addr(InitData* buf, const char* label) {
+ InitDataBlock* block = initdata_push_new(buf);
+ block->kind = InitDataBlockKind_addr;
+ block->as.addr.label = label;
+}
+
+static void initdata_append_zeros(InitData* buf, size_t len) {
+ if (len == 0)
+ return;
+ char* data = calloc(len, sizeof(char));
+ InitDataBlock* block = initdata_push_new(buf);
+ block->kind = InitDataBlockKind_bytes;
+ block->as.bytes.len = len;
+ block->as.bytes.buf = data;
+}
+
+static void initdata_append_bytes(InitData* buf, const char* data, size_t len) {
+ char* copy = calloc(len, sizeof(char));
+ memcpy(copy, data, len);
+ InitDataBlock* block = initdata_push_new(buf);
+ block->kind = InitDataBlockKind_bytes;
+ block->as.bytes.len = len;
+ block->as.bytes.buf = copy;
+}
+
+static void do_eval_init_expr(InitData* 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);
+ do_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];
@@ -2711,25 +2759,44 @@ void eval_init_expr(StrBuilder* buf, AstNode* expr, Type* ty) {
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);
- }
+ initdata_append_zeros(buf, aligned_offset - offset); // padding
offset = aligned_offset;
- eval_init_expr(buf, &list->as.list->items[i], member->ty);
+ do_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);
+ initdata_append_zeros(buf, total - offset); // padding
+ } else {
+ unimplemented();
+ }
+ } else if (ty->kind == TypeKind_ptr) {
+ if (expr->kind == AstNodeKind_str_expr) {
+ char label[32];
+ sprintf(label, ".Lstr__%d", expr->as.str_expr->idx);
+ initdata_append_addr(buf, strdup(label));
+ } else if (expr->kind == AstNodeKind_ref_expr) {
+ if (expr->as.ref_expr->operand->kind != AstNodeKind_gvar) {
+ unimplemented();
}
+ initdata_append_addr(buf, expr->as.ref_expr->operand->as.gvar->name);
+ } else if (expr->kind == AstNodeKind_gvar) {
+ initdata_append_addr(buf, expr->as.gvar->name);
} else {
unimplemented();
}
} else {
int value = eval(expr);
int size = type_sizeof(ty);
+ char bytes[8];
for (int i = 0; i < size; ++i) {
- strbuilder_append_char(buf, (value >> (i * 8)) & 0xff);
+ bytes[i] = (value >> (i * 8)) & 0xff;
}
+ initdata_append_bytes(buf, bytes, size);
}
}
+
+InitData* eval_init_expr(AstNode* expr, Type* ty) {
+ InitData* buf = initdata_new();
+ do_eval_init_expr(buf, expr, ty);
+ return buf;
+}
diff --git a/src/parse.h b/src/parse.h
index 17ffe2c..d5a443c 100644
--- a/src/parse.h
+++ b/src/parse.h
@@ -7,6 +7,37 @@
Program* parse(TokenArray* tokens);
bool pp_eval_constant_expr(TokenArray* pp_tokens);
-void eval_init_expr(StrBuilder* buf, AstNode* expr, Type* ty);
+
+typedef enum {
+ InitDataBlockKind_addr,
+ InitDataBlockKind_bytes,
+} InitDataBlockKind;
+
+// Static address to global variable or ROM area.
+typedef struct {
+ const char* label;
+} InitDataBlockAddr;
+
+// Static byte array.
+typedef struct {
+ size_t len;
+ const char* buf;
+} InitDataBlockBytes;
+
+typedef struct {
+ InitDataBlockKind kind;
+ union {
+ InitDataBlockAddr addr;
+ InitDataBlockBytes bytes;
+ } as;
+} InitDataBlock;
+
+typedef struct {
+ size_t len;
+ size_t capacity;
+ InitDataBlock* blocks;
+} InitData;
+
+InitData* eval_init_expr(AstNode* expr, Type* ty);
#endif
diff --git a/tests/variables.c b/tests/variables.c
index 5f09074..2ba28d1 100644
--- a/tests/variables.c
+++ b/tests/variables.c
@@ -19,14 +19,22 @@ char arr1[3] = {65, 66, 67};
short arr2[3] = {10, 20, 30};
int arr3[3] = {1, 2, 3};
-struct S {
+struct S1 {
int x, y;
};
-struct S arr4[] = {
+struct S1 arr4[] = {
{1, 2},
{3, 4},
};
+struct S2 {
+ const char* x;
+};
+struct S2 arr5[] = {
+ {"foo"},
+ {"bar"},
+};
+
int main() {
// global variables
*g_b = 123;
@@ -64,6 +72,9 @@ int main() {
ASSERT_EQ(3, arr4[1].x);
ASSERT_EQ(4, arr4[1].y);
+ ASSERT_EQ_STR("foo", arr5[0].x);
+ ASSERT_EQ_STR("bar", arr5[1].x);
+
// local variables
int foo;
foo = 42;