fix: str+str 运行时拼接 — malloc + strlen + memcpy
- codegen: 声明 CRT 的 malloc/strlen/memcpy
- str+str 拼接: strlen(l)+strlen(r)+1 → malloc → memcpy×2 → 返回指针
- 新增集成测试 08_str_concat.l ("Hello, " + "World!" → "Hello, World!")
- 修复自报告 §5-6 字符串拼接不工作的 bug
This commit is contained in:
+60
-2
@@ -31,6 +31,10 @@ typedef struct {
|
||||
// printf 运行时支持(内置 print 函数委托给 printf)
|
||||
LLVMValueRef printf_fn;
|
||||
LLVMTypeRef printf_ty;
|
||||
// 字符串拼接运行时支持
|
||||
LLVMValueRef malloc_fn;
|
||||
LLVMValueRef strlen_fn;
|
||||
LLVMValueRef memcpy_fn;
|
||||
} CgCtx;
|
||||
|
||||
// === 类型映射(需要 Context)===
|
||||
@@ -124,8 +128,39 @@ static LLVMValueRef codegen_expr(CgCtx* ctx, AstNode* node) {
|
||||
LLVMValueRef r = codegen_expr(ctx, node->as.binary.right);
|
||||
if (!l || !r) return NULL;
|
||||
|
||||
// 字符串拼接:暂不支持运行时拼接,直接返回左操作数
|
||||
if (node->type.kind == TYPE_STR) return l;
|
||||
// 字符串拼接:alloc 栈缓冲区,strcpy + strcat
|
||||
if (node->type.kind == TYPE_STR) {
|
||||
// strlen(left)
|
||||
LLVMValueRef len_l = LLVMBuildCall2(ctx->builder,
|
||||
LLVMGlobalGetValueType(ctx->strlen_fn), ctx->strlen_fn,
|
||||
(LLVMValueRef[]){l}, 1, "strlen_l");
|
||||
// strlen(right)
|
||||
LLVMValueRef len_r = LLVMBuildCall2(ctx->builder,
|
||||
LLVMGlobalGetValueType(ctx->strlen_fn), ctx->strlen_fn,
|
||||
(LLVMValueRef[]){r}, 1, "strlen_r");
|
||||
// total = len_l + len_r + 1
|
||||
LLVMValueRef total = LLVMBuildAdd(ctx->builder, len_l, len_r, "total");
|
||||
total = LLVMBuildAdd(ctx->builder, total,
|
||||
LLVMConstInt(LLVMInt64TypeInContext(ctx->context), 1, false), "total_1");
|
||||
// char* buf = malloc(total)
|
||||
LLVMValueRef buf = LLVMBuildCall2(ctx->builder,
|
||||
LLVMGlobalGetValueType(ctx->malloc_fn), ctx->malloc_fn,
|
||||
(LLVMValueRef[]){total}, 1, "str_buf");
|
||||
// memcpy(buf, left, len_l)
|
||||
LLVMBuildCall2(ctx->builder,
|
||||
LLVMGlobalGetValueType(ctx->memcpy_fn), ctx->memcpy_fn,
|
||||
(LLVMValueRef[]){buf, l, len_l}, 3, "");
|
||||
// memcpy(buf + len_l, right, len_r + 1) -- includes null terminator
|
||||
LLVMValueRef offset_ptr = LLVMBuildGEP2(ctx->builder,
|
||||
LLVMInt8TypeInContext(ctx->context), buf,
|
||||
(LLVMValueRef[]){len_l}, 1, "offset");
|
||||
LLVMValueRef len_r1 = LLVMBuildAdd(ctx->builder, len_r,
|
||||
LLVMConstInt(LLVMInt64TypeInContext(ctx->context), 1, false), "len_r1");
|
||||
LLVMBuildCall2(ctx->builder,
|
||||
LLVMGlobalGetValueType(ctx->memcpy_fn), ctx->memcpy_fn,
|
||||
(LLVMValueRef[]){offset_ptr, r, len_r1}, 3, "");
|
||||
return buf;
|
||||
}
|
||||
|
||||
bool is_float = (node->type.kind == TYPE_F64);
|
||||
|
||||
@@ -352,6 +387,29 @@ LLVMModuleRef codegen_module(AstNode* ast, Arena* codegen_arena,
|
||||
LLVMInt32TypeInContext(ctx.context), printf_param_types, 1, true);
|
||||
ctx.printf_fn = LLVMAddFunction(ctx.module, "printf", ctx.printf_ty);
|
||||
|
||||
// 声明 malloc: void* malloc(size_t)
|
||||
LLVMTypeRef malloc_args[] = { LLVMInt64TypeInContext(ctx.context) };
|
||||
LLVMTypeRef malloc_ty = LLVMFunctionType(
|
||||
LLVMPointerType(LLVMInt8TypeInContext(ctx.context), 0), malloc_args, 1, false);
|
||||
ctx.malloc_fn = LLVMAddFunction(ctx.module, "malloc", malloc_ty);
|
||||
|
||||
// 声明 strlen: size_t strlen(const char*)
|
||||
LLVMTypeRef strlen_args[] = { LLVMPointerType(LLVMInt8TypeInContext(ctx.context), 0) };
|
||||
LLVMTypeRef strlen_ty = LLVMFunctionType(
|
||||
LLVMInt64TypeInContext(ctx.context), strlen_args, 1, false);
|
||||
ctx.strlen_fn = LLVMAddFunction(ctx.module, "strlen", strlen_ty);
|
||||
|
||||
// 声明 memcpy: void* memcpy(void*, const void*, size_t)
|
||||
LLVMTypeRef memcpy_args[] = {
|
||||
LLVMPointerType(LLVMInt8TypeInContext(ctx.context), 0),
|
||||
LLVMPointerType(LLVMInt8TypeInContext(ctx.context), 0),
|
||||
LLVMInt64TypeInContext(ctx.context),
|
||||
};
|
||||
LLVMTypeRef memcpy_ty = LLVMFunctionType(
|
||||
LLVMPointerType(LLVMInt8TypeInContext(ctx.context), 0),
|
||||
memcpy_args, 3, false);
|
||||
ctx.memcpy_fn = LLVMAddFunction(ctx.module, "memcpy", memcpy_ty);
|
||||
|
||||
// 第一遍:声明所有 L 函数
|
||||
for (size_t i = 0; i < ast->as.program.fn_count; i++) {
|
||||
AstNode* fn = ast->as.program.functions[i];
|
||||
|
||||
Reference in New Issue
Block a user