diff options
| author | nsfisis <nsfisis@gmail.com> | 2026-02-07 10:12:57 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2026-02-07 10:12:57 +0900 |
| commit | 0034f84a38e8cb41a753d2def1daccd14bbfd552 (patch) | |
| tree | 6e734a8450c7f7fece5eda4c33ff72bc6ab277fb | |
| parent | 107c517b22e88d760c375a4b9da6dffd6da26d85 (diff) | |
| download | ducc-0034f84a38e8cb41a753d2def1daccd14bbfd552.tar.gz ducc-0034f84a38e8cb41a753d2def1daccd14bbfd552.tar.zst ducc-0034f84a38e8cb41a753d2def1daccd14bbfd552.zip | |
feat: implement global variables referencing string literals
| -rw-r--r-- | src/codegen.c | 31 | ||||
| -rw-r--r-- | src/parse.c | 85 | ||||
| -rw-r--r-- | src/parse.h | 33 | ||||
| -rw-r--r-- | tests/variables.c | 15 |
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; |
