refactor: sema.c + codegen.c 拆分,全部源文件 <800 行

sema.c 1129行 → sema.c 499行 + typeck.c 629行 + sema_internal.h 51行
  - typeck.c: 表达式类型检查 (10个analyze_*函数) + 泛型单态化 + 类型关系
  - sema.c: analyze_node + sema_analyze

codegen.c 947行 → codegen.c 453行 + cg_expr.c 440行 + codegen_internal.h 83行
  - cg_expr.c: LLVM表达式生成 + 类型映射 (to_llvm_type/coerce_int/type_info_to_llvm)
  - codegen.c: 语句生成 + 模块入口 + 符号表 + 内存清理

全部核心源文件 <800 行限制: parser(662+498), sema(499+629), codegen(453+440)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-06-06 19:26:54 +08:00
parent 90d081c3fd
commit 6d1db585c4
6 changed files with 1216 additions and 1137 deletions
+440
View File
@@ -0,0 +1,440 @@
#include "codegen_internal.h"
LLVMTypeRef to_llvm_type(CgCtx* ctx, TypeKind kind) {
switch (kind) {
case TYPE_I32: return LLVMInt32TypeInContext(ctx->context);
case TYPE_I64: return LLVMInt64TypeInContext(ctx->context);
case TYPE_U64: return LLVMInt64TypeInContext(ctx->context);
case TYPE_F64: return LLVMDoubleTypeInContext(ctx->context);
case TYPE_BOOL: return LLVMInt1TypeInContext(ctx->context);
case TYPE_CHAR: return LLVMInt8TypeInContext(ctx->context);
case TYPE_STR: return LLVMPointerType(LLVMInt8TypeInContext(ctx->context), 0);
case TYPE_STRUCT:
case TYPE_ENUM: {
// tagged union: { i64 tag, i64 payload }
LLVMTypeRef fields[] = { LLVMInt64TypeInContext(ctx->context),
LLVMInt64TypeInContext(ctx->context) };
return LLVMStructTypeInContext(ctx->context, fields, 2, false);
}
case TYPE_UNKNOWN:
case TYPE_ERROR:
default: return LLVMVoidTypeInContext(ctx->context);
}
}
LLVMValueRef to_llvm_const(LLVMTypeRef ty, AstNode* lit) {
switch (lit->as.literal.lit_type) {
case TYPE_I32:
case TYPE_I64: return LLVMConstInt(ty, (unsigned long long)lit->as.literal.i64_val, true);
case TYPE_U64: return LLVMConstInt(ty, (unsigned long long)lit->as.literal.i64_val, false);
case TYPE_CHAR: return LLVMConstInt(ty, (unsigned long long)lit->as.literal.i64_val, false);
case TYPE_F64: return LLVMConstReal(ty, lit->as.literal.f64_val);
case TYPE_BOOL: return LLVMConstInt(ty, lit->as.literal.bool_val ? 1 : 0, false);
default: return NULL;
}
}
LLVMValueRef coerce_int(CgCtx* ctx, LLVMValueRef val,
LLVMTypeRef from_ty, LLVMTypeRef to_ty) {
if (from_ty == to_ty) return val;
int from_w = LLVMGetIntTypeWidth(from_ty);
int to_w = LLVMGetIntTypeWidth(to_ty);
if (from_w < to_w)
return LLVMBuildSExt(ctx->builder, val, to_ty, "sext");
else
return LLVMBuildTrunc(ctx->builder, val, to_ty, "trunc");
}
// 从 TypeInfo 生成 LLVM 类型(支持数组、结构体等复合类型)
LLVMTypeRef type_info_to_llvm(CgCtx* ctx, const TypeInfo* ti) {
switch (ti->kind) {
case TYPE_ARRAY: {
TypeInfo elem = { .kind = ti->element_type, .struct_name = ti->element_struct_name };
LLVMTypeRef elem_ty = type_info_to_llvm(ctx, &elem);
return LLVMArrayType(elem_ty, (unsigned)ti->array_size);
}
case TYPE_STRUCT:
if (ti->struct_name) {
LLVMTypeRef st = find_struct_type(ctx, ti->struct_name);
if (st) return st;
}
return LLVMVoidTypeInContext(ctx->context);
case TYPE_ENUM: {
LLVMTypeRef f[] = { LLVMInt64TypeInContext(ctx->context),
LLVMInt64TypeInContext(ctx->context) };
return LLVMStructTypeInContext(ctx->context, f, 2, false);
}
default:
return to_llvm_type(ctx, ti->kind);
}
}
// === 向前声明 ===
LLVMValueRef codegen_expr(CgCtx* ctx, AstNode* node);
void codegen_stmt(CgCtx* ctx, AstNode* node);
LLVMValueRef codegen_expr(CgCtx* ctx, AstNode* node) {
if (!node) return NULL;
switch (node->kind) {
case AST_LITERAL_EXPR:
if (node->type.kind == TYPE_STR) {
return LLVMBuildGlobalStringPtr(ctx->builder, node->as.literal.str_val, "str");
}
return to_llvm_const(to_llvm_type(ctx, node->type.kind), node);
case AST_IDENT_EXPR: {
LLVMValueRef ptr = find_var(ctx, node->as.ident.name);
if (!ptr) return NULL;
LLVMTypeRef load_ty = type_info_to_llvm(ctx, &node->type);
return LLVMBuildLoad2(ctx->builder, load_ty, ptr, "load");
}
case AST_UNARY_EXPR: {
LLVMValueRef operand = codegen_expr(ctx, node->as.unary.operand);
if (!operand) return NULL;
if (node->as.unary.op == OP_NEG) {
if (node->type.kind == TYPE_F64)
return LLVMBuildFNeg(ctx->builder, operand, "fneg");
else
return LLVMBuildNeg(ctx->builder, operand, "ineg");
} else {
return LLVMBuildNot(ctx->builder, operand, "not");
}
}
case AST_BINARY_EXPR: {
LLVMValueRef l = codegen_expr(ctx, node->as.binary.left);
LLVMValueRef r = codegen_expr(ctx, node->as.binary.right);
if (!l || !r) return NULL;
// 字符串拼接: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);
switch (node->as.binary.op) {
case OP_ADD:
return is_float ? LLVMBuildFAdd(ctx->builder, l, r, "fadd")
: LLVMBuildAdd(ctx->builder, l, r, "iadd");
case OP_SUB:
return is_float ? LLVMBuildFSub(ctx->builder, l, r, "fsub")
: LLVMBuildSub(ctx->builder, l, r, "isub");
case OP_MUL:
return is_float ? LLVMBuildFMul(ctx->builder, l, r, "fmul")
: LLVMBuildMul(ctx->builder, l, r, "imul");
case OP_DIV:
return is_float ? LLVMBuildFDiv(ctx->builder, l, r, "fdiv")
: LLVMBuildSDiv(ctx->builder, l, r, "sdiv");
case OP_MOD:
return LLVMBuildSRem(ctx->builder, l, r, "srem");
case OP_EQ:
case OP_NE:
case OP_LT:
case OP_GT:
case OP_LE:
case OP_GE: {
// 枚举比较: 提取 tag 字段再比较
LLVMValueRef cl = l, cr = r;
if (node->as.binary.left->type.kind == TYPE_ENUM) {
cl = LLVMBuildExtractValue(ctx->builder, l, 0, "enum_tag_l");
}
if (node->as.binary.right->type.kind == TYPE_ENUM) {
cr = LLVMBuildExtractValue(ctx->builder, r, 0, "enum_tag_r");
}
LLVMIntPredicate pred;
switch (node->as.binary.op) {
case OP_EQ: pred = LLVMIntEQ; break;
case OP_NE: pred = LLVMIntNE; break;
case OP_LT: pred = LLVMIntSLT; break;
case OP_GT: pred = LLVMIntSGT; break;
case OP_LE: pred = LLVMIntSLE; break;
case OP_GE: pred = LLVMIntSGE; break;
default: return NULL;
}
if (is_float)
return LLVMBuildFCmp(ctx->builder, pred == LLVMIntEQ ? LLVMRealOEQ :
pred == LLVMIntNE ? LLVMRealONE : pred == LLVMIntSLT ? LLVMRealOLT :
pred == LLVMIntSGT ? LLVMRealOGT : pred == LLVMIntSLE ? LLVMRealOLE :
LLVMRealOGE, cl, cr, "fcmp");
return LLVMBuildICmp(ctx->builder, pred, cl, cr, "icmp");
}
case OP_AND:
return LLVMBuildAnd(ctx->builder, l, r, "and");
case OP_OR:
return LLVMBuildOr(ctx->builder, l, r, "or");
default:
return NULL;
}
}
case AST_CALL_EXPR: {
// === 内置 print 函数:委托给 printf ===
if (strcmp(node->as.call.name, "print_i64") == 0) {
LLVMValueRef arg = codegen_expr(ctx, node->as.call.args[0]);
if (!arg) return NULL;
// 枚举类型: 提取 tag 字段
if (node->as.call.args[0]->type.kind == TYPE_ENUM)
arg = LLVMBuildExtractValue(ctx->builder, arg, 0, "tag");
LLVMTypeRef i64_ty = LLVMInt64TypeInContext(ctx->context);
arg = coerce_int(ctx, arg, LLVMTypeOf(arg), i64_ty);
LLVMValueRef fmt = LLVMBuildGlobalStringPtr(ctx->builder, "%lld\n", "fmt_i64");
LLVMValueRef printf_args[] = { fmt, arg };
return LLVMBuildCall2(ctx->builder, ctx->printf_ty, ctx->printf_fn,
printf_args, 2, "");
}
if (strcmp(node->as.call.name, "print_f64") == 0) {
LLVMValueRef arg = codegen_expr(ctx, node->as.call.args[0]);
if (!arg) return NULL;
LLVMValueRef fmt = LLVMBuildGlobalStringPtr(ctx->builder, "%f\n", "fmt_f64");
LLVMValueRef printf_args[] = { fmt, arg };
return LLVMBuildCall2(ctx->builder, ctx->printf_ty, ctx->printf_fn,
printf_args, 2, "");
}
if (strcmp(node->as.call.name, "print_bool") == 0) {
LLVMValueRef arg = codegen_expr(ctx, node->as.call.args[0]);
if (!arg) return NULL;
// 将 bool 转为字符串:通过 select 在 "true\n" 和 "false\n" 之间选择
LLVMValueRef c = LLVMBuildICmp(ctx->builder, LLVMIntEQ, arg,
LLVMConstInt(LLVMInt1TypeInContext(ctx->context), 1, false), "bool_cmp");
LLVMValueRef true_str = LLVMBuildGlobalStringPtr(ctx->builder, "true\n", "true_str");
LLVMValueRef false_str = LLVMBuildGlobalStringPtr(ctx->builder, "false\n", "false_str");
LLVMValueRef selected = LLVMBuildSelect(ctx->builder, c, true_str, false_str, "bool_sel");
return LLVMBuildCall2(ctx->builder, ctx->printf_ty, ctx->printf_fn,
(LLVMValueRef[]){selected}, 1, "");
}
if (strcmp(node->as.call.name, "print_str") == 0) {
LLVMValueRef arg = codegen_expr(ctx, node->as.call.args[0]);
if (!arg) return NULL;
LLVMValueRef fmt = LLVMBuildGlobalStringPtr(ctx->builder, "%s\n", "fmt_str");
LLVMValueRef printf_args[] = { fmt, arg };
return LLVMBuildCall2(ctx->builder, ctx->printf_ty, ctx->printf_fn,
printf_args, 2, "");
}
// === 常规函数调用 ===
LLVMValueRef fn = find_fn(ctx, node->as.call.name);
if (!fn) return NULL;
LLVMValueRef args[16];
if (node->as.call.arg_count > 16) { ctx->error = "函数参数过多(最多16)"; return NULL; }
for (size_t i = 0; i < node->as.call.arg_count; i++) {
args[i] = codegen_expr(ctx, node->as.call.args[i]);
if (!args[i]) return NULL;
}
LLVMTypeRef fn_ty = LLVMGlobalGetValueType(fn);
LLVMTypeRef ret_ty = LLVMGetReturnType(fn_ty);
return LLVMBuildCall2(ctx->builder, fn_ty, fn,
args, (unsigned)node->as.call.arg_count,
ret_ty == LLVMVoidTypeInContext(ctx->context) ? "" : "call");
}
// === 结构体字段访问: p.x ===
case AST_FIELD_ACCESS: {
// 对对象求值(返回的是 struct 值)
LLVMValueRef struct_val = codegen_expr(ctx, node->as.field_access.object);
if (!struct_val) return NULL;
int field_idx = node->as.field_access.field_index;
if (field_idx < 0) return NULL; // sema 应当已经设置
// 用 extractvalue 从结构体值中提取字段
return LLVMBuildExtractValue(ctx->builder, struct_val,
(unsigned)field_idx, node->as.field_access.field);
}
// === 结构体初始化: Point { x: 10, y: 20 } ===
case AST_STRUCT_INIT: {
const char* st_name = node->as.struct_init.type_name;
LLVMTypeRef struct_ty = find_struct_type(ctx, st_name);
if (!struct_ty) return NULL;
// alloca 分配结构体空间
LLVMValueRef alloca = LLVMBuildAlloca(ctx->builder, struct_ty, "struct_init");
// 获取结构体字段名列表(从 struct_table 或从 AST 中)
// 对每个 init 字段,找到它在结构体中的索引并 store
for (size_t i = 0; i < node->as.struct_init.field_count; i++) {
AstNode* fval = node->as.struct_init.field_values[i];
LLVMValueRef val = codegen_expr(ctx, fval);
if (!val) return NULL;
// 获取字段指针: GEP struct_ty, alloca, 0, i
LLVMValueRef indices[] = {
LLVMConstInt(LLVMInt32TypeInContext(ctx->context), 0, false),
LLVMConstInt(LLVMInt32TypeInContext(ctx->context), (unsigned long long)i, false)
};
LLVMValueRef field_ptr = LLVMBuildGEP2(ctx->builder, struct_ty, alloca,
indices, 2, "field_ptr");
LLVMBuildStore(ctx->builder, val, field_ptr);
}
// 加载整个结构体值
return LLVMBuildLoad2(ctx->builder, struct_ty, alloca, "struct_val");
}
case AST_ENUM_VARIANT: {
// tagged union: { tag, payload }
LLVMValueRef tag = LLVMConstInt(LLVMInt64TypeInContext(ctx->context),
(unsigned long long)node->as.enum_variant.variant_index, true);
LLVMValueRef payload = LLVMConstInt(LLVMInt64TypeInContext(ctx->context), 0, true);
if (node->as.enum_variant.payload) {
LLVMValueRef pv = codegen_expr(ctx, node->as.enum_variant.payload);
if (pv) {
// 将 payload 强制转换为 i64
LLVMTypeRef pv_ty = LLVMTypeOf(pv);
LLVMTypeRef i64_ty = LLVMInt64TypeInContext(ctx->context);
if (pv_ty != i64_ty && LLVMGetTypeKind(pv_ty) == LLVMIntegerTypeKind)
pv = coerce_int(ctx, pv, pv_ty, i64_ty);
payload = pv;
}
}
LLVMValueRef fields[] = { tag, payload };
return LLVMConstStruct(fields, 2, false);
}
case AST_METHOD_CALL: {
const char* struct_name = node->as.method_call.receiver->type.struct_name;
char mangled[256];
// 若 method_name 已含 $trait 方法,sema 已设置全限定名),直接用
if (strchr(node->as.method_call.method_name, '$'))
snprintf(mangled, sizeof(mangled), "%s", node->as.method_call.method_name);
else
snprintf(mangled, sizeof(mangled), "%s$%s", struct_name,
node->as.method_call.method_name);
LLVMValueRef fn = find_fn(ctx, mangled);
if (!fn) return NULL;
// 参数列表: [receiver, 用户参数...]
if (node->as.method_call.arg_count + 1 > 16) { ctx->error = "方法参数过多(最多15)"; return NULL; }
LLVMValueRef args[16];
args[0] = codegen_expr(ctx, node->as.method_call.receiver);
if (!args[0]) return NULL;
for (size_t i = 0; i < node->as.method_call.arg_count; i++) {
args[i + 1] = codegen_expr(ctx, node->as.method_call.args[i]);
if (!args[i + 1]) return NULL;
}
LLVMTypeRef fn_ty = LLVMGlobalGetValueType(fn);
LLVMTypeRef ret_ty = LLVMGetReturnType(fn_ty);
return LLVMBuildCall2(ctx->builder, fn_ty, fn, args,
(unsigned)(node->as.method_call.arg_count + 1),
ret_ty == LLVMVoidTypeInContext(ctx->context) ? "" : "method_call");
}
case AST_INDEX_EXPR: {
// 获取数组变量的指针
AstNode* arr_node = node->as.index_expr.array;
LLVMValueRef arr_ptr = NULL;
LLVMTypeRef arr_gp_type = NULL;
if (arr_node->kind == AST_IDENT_EXPR) {
arr_ptr = find_var(ctx, arr_node->as.ident.name);
// 从变量表获取数组类型用于 GEP
for (VarEntry* e = ctx->var_table; e; e = e->next) {
if (strcmp(e->name, arr_node->as.ident.name) == 0) {
arr_gp_type = e->alloca_type; break;
}
}
}
if (!arr_ptr || !arr_gp_type) return NULL;
// 生成索引值
LLVMValueRef idx_val = codegen_expr(ctx, node->as.index_expr.index);
if (!idx_val) return NULL;
// GEP 索引必须是 i32,但 L 使用 i64。截断。
LLVMValueRef idx_i32 = LLVMBuildTrunc(ctx->builder, idx_val,
LLVMInt32TypeInContext(ctx->context), "idx32");
LLVMValueRef indices[] = {
LLVMConstInt(LLVMInt32TypeInContext(ctx->context), 0, false),
idx_i32
};
LLVMValueRef elem_ptr = LLVMBuildGEP2(ctx->builder, arr_gp_type, arr_ptr, indices, 2, "arr_elem");
LLVMTypeRef elem_load_ty;
if (node->type.kind == TYPE_STRUCT && node->type.struct_name) {
elem_load_ty = find_struct_type(ctx, node->type.struct_name);
if (!elem_load_ty) elem_load_ty = to_llvm_type(ctx, node->type.kind);
} else {
elem_load_ty = type_info_to_llvm(ctx, &node->type);
}
return LLVMBuildLoad2(ctx->builder, elem_load_ty, elem_ptr, "arr_load");
}
// 块表达式: { stmt*; expr } → 最后表达式的值
case AST_BLOCK: {
LLVMValueRef result = NULL;
for (size_t i = 0; i < node->as.block.stmt_count; i++) {
AstNode* stmt = node->as.block.stmts[i];
bool is_last = (i == node->as.block.stmt_count - 1);
if (is_last && stmt->kind == AST_EXPR_STMT && node->type.kind != TYPE_VOID) {
result = codegen_expr(ctx, stmt->as.expr_stmt.expr);
} else {
codegen_stmt(ctx, stmt);
}
}
return result;
}
// if 表达式: if cond { a } else { b }
case AST_IF_STMT: {
if (node->type.kind == TYPE_VOID) { codegen_stmt(ctx, node); return NULL; }
LLVMValueRef cond_val = codegen_expr(ctx, node->as.if_stmt.cond);
if (!cond_val) return NULL;
LLVMTypeRef res_ty = type_info_to_llvm(ctx, &node->type);
LLVMValueRef alloca = LLVMBuildAlloca(ctx->builder, res_ty, "if_res");
LLVMValueRef func = LLVMGetBasicBlockParent(LLVMGetInsertBlock(ctx->builder));
LLVMBasicBlockRef then_bb = LLVMAppendBasicBlockInContext(ctx->context, func, "then");
LLVMBasicBlockRef else_bb = LLVMAppendBasicBlockInContext(ctx->context, func, "else");
LLVMBasicBlockRef merge_bb = LLVMAppendBasicBlockInContext(ctx->context, func, "if_merge");
LLVMBuildCondBr(ctx->builder, cond_val, then_bb, else_bb);
LLVMPositionBuilderAtEnd(ctx->builder, then_bb);
LLVMValueRef then_val = codegen_expr(ctx, node->as.if_stmt.then_block);
if (then_val) LLVMBuildStore(ctx->builder, then_val, alloca);
LLVMBuildBr(ctx->builder, merge_bb);
LLVMPositionBuilderAtEnd(ctx->builder, else_bb);
LLVMValueRef else_val = codegen_expr(ctx, node->as.if_stmt.else_block);
if (else_val) LLVMBuildStore(ctx->builder, else_val, alloca);
LLVMBuildBr(ctx->builder, merge_bb);
LLVMPositionBuilderAtEnd(ctx->builder, merge_bb);
return LLVMBuildLoad2(ctx->builder, res_ty, alloca, "if_val");
}
default:
return NULL;
}
}
+11 -505
View File
@@ -1,104 +1,15 @@
#include "codegen.h"
#include <llvm-c/Analysis.h>
#include <llvm-c/Types.h>
#include <string.h>
#include <stdio.h>
#include "codegen_internal.h"
// === 递归深度限制
static int codegen_depth = 0;
#define MAX_CODEGEN_DEPTH 1000
// === 内部状态 ===
typedef struct VarEntry {
const char* name;
LLVMValueRef alloca;
LLVMTypeRef alloca_type; // 分配的类型(GEP 需要)
struct VarEntry* next;
} VarEntry;
typedef struct FnEntry {
const char* name;
LLVMValueRef fn;
TypeKind ret;
TypeKind* params;
size_t pc;
struct FnEntry* next;
} FnEntry;
// 结构体类型映射
typedef struct StructTypeEntry {
const char* name;
LLVMTypeRef llvm_type;
size_t field_count;
struct StructTypeEntry* next;
} StructTypeEntry;
typedef struct {
Arena* arena; // 代码生成阶段分配器
LLVMContextRef context; // LLVM 19+ 需要显式 Context
LLVMModuleRef module;
LLVMBuilderRef builder;
VarEntry* var_table;
const char* error;
FnEntry* fn_table;
StructTypeEntry* struct_table;
// printf 运行时支持(内置 print 函数委托给 printf
LLVMValueRef printf_fn;
LLVMTypeRef printf_ty;
// 字符串拼接运行时支持
LLVMValueRef malloc_fn;
LLVMValueRef free_fn; // auto-free 需要 free()
LLVMValueRef strlen_fn;
LLVMValueRef memcpy_fn;
// 自动内存管理: 追踪需要 free 的 str alloca
LLVMValueRef* cleanup_list;
size_t cleanup_count;
size_t cleanup_cap;
} CgCtx;
// === 类型映射(需要 Context===
static LLVMTypeRef to_llvm_type(CgCtx* ctx, TypeKind kind) {
switch (kind) {
case TYPE_I32: return LLVMInt32TypeInContext(ctx->context);
case TYPE_I64: return LLVMInt64TypeInContext(ctx->context);
case TYPE_U64: return LLVMInt64TypeInContext(ctx->context);
case TYPE_F64: return LLVMDoubleTypeInContext(ctx->context);
case TYPE_BOOL: return LLVMInt1TypeInContext(ctx->context);
case TYPE_CHAR: return LLVMInt8TypeInContext(ctx->context);
case TYPE_STR: return LLVMPointerType(LLVMInt8TypeInContext(ctx->context), 0);
case TYPE_STRUCT:
case TYPE_ENUM: {
// tagged union: { i64 tag, i64 payload }
LLVMTypeRef fields[] = { LLVMInt64TypeInContext(ctx->context),
LLVMInt64TypeInContext(ctx->context) };
return LLVMStructTypeInContext(ctx->context, fields, 2, false);
}
case TYPE_UNKNOWN:
case TYPE_ERROR:
default: return LLVMVoidTypeInContext(ctx->context);
}
}
static LLVMValueRef to_llvm_const(LLVMTypeRef ty, AstNode* lit) {
switch (lit->as.literal.lit_type) {
case TYPE_I32:
case TYPE_I64: return LLVMConstInt(ty, (unsigned long long)lit->as.literal.i64_val, true);
case TYPE_U64: return LLVMConstInt(ty, (unsigned long long)lit->as.literal.i64_val, false);
case TYPE_CHAR: return LLVMConstInt(ty, (unsigned long long)lit->as.literal.i64_val, false);
case TYPE_F64: return LLVMConstReal(ty, lit->as.literal.f64_val);
case TYPE_BOOL: return LLVMConstInt(ty, lit->as.literal.bool_val ? 1 : 0, false);
default: return NULL;
}
}
int codegen_depth = 0;
// === 变量表 ===
static LLVMValueRef find_var(CgCtx* ctx, const char* name) {
LLVMValueRef find_var(CgCtx* ctx, const char* name) {
for (VarEntry* e = ctx->var_table; e; e = e->next)
if (strcmp(e->name, name) == 0) return e->alloca;
return NULL;
}
static void add_var(CgCtx* ctx, const char* name, LLVMValueRef alloca, LLVMTypeRef alloca_type) {
void add_var(CgCtx* ctx, const char* name, LLVMValueRef alloca, LLVMTypeRef alloca_type) {
VarEntry* e = arena_alloc(ctx->arena, sizeof(*e));
if (!e) return;
e->name = name; e->alloca = alloca; e->alloca_type = alloca_type; e->next = ctx->var_table;
@@ -106,13 +17,13 @@ static void add_var(CgCtx* ctx, const char* name, LLVMValueRef alloca, LLVMTypeR
}
// === 函数表 ===
static LLVMValueRef find_fn(CgCtx* ctx, const char* name) {
LLVMValueRef find_fn(CgCtx* ctx, const char* name) {
for (FnEntry* e = ctx->fn_table; e; e = e->next)
if (strcmp(e->name, name) == 0) return e->fn;
return NULL;
}
static void add_fn(CgCtx* ctx, const char* name, LLVMValueRef fn) {
void add_fn(CgCtx* ctx, const char* name, LLVMValueRef fn) {
FnEntry* e = arena_alloc(ctx->arena, sizeof(*e));
if (!e) return;
e->name = name; e->fn = fn;
@@ -124,7 +35,7 @@ static void add_fn(CgCtx* ctx, const char* name, LLVMValueRef fn) {
}
// === 结构体类型表 ===
static void add_struct_type(CgCtx* ctx, const char* name, LLVMTypeRef ty, size_t fc) {
void add_struct_type(CgCtx* ctx, const char* name, LLVMTypeRef ty, size_t fc) {
StructTypeEntry* e = arena_alloc(ctx->arena, sizeof(*e));
if (!e) return;
e->name = name; e->llvm_type = ty; e->field_count = fc;
@@ -132,420 +43,15 @@ static void add_struct_type(CgCtx* ctx, const char* name, LLVMTypeRef ty, size_t
ctx->struct_table = e;
}
static LLVMTypeRef find_struct_type(CgCtx* ctx, const char* name) {
LLVMTypeRef find_struct_type(CgCtx* ctx, const char* name) {
for (StructTypeEntry* e = ctx->struct_table; e; e = e->next)
if (strcmp(e->name, name) == 0) return e->llvm_type;
return NULL;
}
// 将整数值强制转换到目标 LLVM 类型(sext/zext/trunc
static LLVMValueRef coerce_int(CgCtx* ctx, LLVMValueRef val,
LLVMTypeRef from_ty, LLVMTypeRef to_ty) {
if (from_ty == to_ty) return val;
int from_w = LLVMGetIntTypeWidth(from_ty);
int to_w = LLVMGetIntTypeWidth(to_ty);
if (from_w < to_w)
return LLVMBuildSExt(ctx->builder, val, to_ty, "sext");
else
return LLVMBuildTrunc(ctx->builder, val, to_ty, "trunc");
}
// 从 TypeInfo 生成 LLVM 类型(支持数组、结构体等复合类型)
static LLVMTypeRef type_info_to_llvm(CgCtx* ctx, const TypeInfo* ti) {
switch (ti->kind) {
case TYPE_ARRAY: {
TypeInfo elem = { .kind = ti->element_type, .struct_name = ti->element_struct_name };
LLVMTypeRef elem_ty = type_info_to_llvm(ctx, &elem);
return LLVMArrayType(elem_ty, (unsigned)ti->array_size);
}
case TYPE_STRUCT:
if (ti->struct_name) {
LLVMTypeRef st = find_struct_type(ctx, ti->struct_name);
if (st) return st;
}
return LLVMVoidTypeInContext(ctx->context);
case TYPE_ENUM: {
LLVMTypeRef f[] = { LLVMInt64TypeInContext(ctx->context),
LLVMInt64TypeInContext(ctx->context) };
return LLVMStructTypeInContext(ctx->context, f, 2, false);
}
default:
return to_llvm_type(ctx, ti->kind);
}
}
// === 向前声明 ===
static LLVMValueRef codegen_expr(CgCtx* ctx, AstNode* node);
static void codegen_stmt(CgCtx* ctx, AstNode* node);
// === 表达式代码生成 ===
static LLVMValueRef codegen_expr(CgCtx* ctx, AstNode* node) {
if (!node) return NULL;
switch (node->kind) {
case AST_LITERAL_EXPR:
if (node->type.kind == TYPE_STR) {
return LLVMBuildGlobalStringPtr(ctx->builder, node->as.literal.str_val, "str");
}
return to_llvm_const(to_llvm_type(ctx, node->type.kind), node);
case AST_IDENT_EXPR: {
LLVMValueRef ptr = find_var(ctx, node->as.ident.name);
if (!ptr) return NULL;
LLVMTypeRef load_ty = type_info_to_llvm(ctx, &node->type);
return LLVMBuildLoad2(ctx->builder, load_ty, ptr, "load");
}
case AST_UNARY_EXPR: {
LLVMValueRef operand = codegen_expr(ctx, node->as.unary.operand);
if (!operand) return NULL;
if (node->as.unary.op == OP_NEG) {
if (node->type.kind == TYPE_F64)
return LLVMBuildFNeg(ctx->builder, operand, "fneg");
else
return LLVMBuildNeg(ctx->builder, operand, "ineg");
} else {
return LLVMBuildNot(ctx->builder, operand, "not");
}
}
case AST_BINARY_EXPR: {
LLVMValueRef l = codegen_expr(ctx, node->as.binary.left);
LLVMValueRef r = codegen_expr(ctx, node->as.binary.right);
if (!l || !r) return NULL;
// 字符串拼接: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);
switch (node->as.binary.op) {
case OP_ADD:
return is_float ? LLVMBuildFAdd(ctx->builder, l, r, "fadd")
: LLVMBuildAdd(ctx->builder, l, r, "iadd");
case OP_SUB:
return is_float ? LLVMBuildFSub(ctx->builder, l, r, "fsub")
: LLVMBuildSub(ctx->builder, l, r, "isub");
case OP_MUL:
return is_float ? LLVMBuildFMul(ctx->builder, l, r, "fmul")
: LLVMBuildMul(ctx->builder, l, r, "imul");
case OP_DIV:
return is_float ? LLVMBuildFDiv(ctx->builder, l, r, "fdiv")
: LLVMBuildSDiv(ctx->builder, l, r, "sdiv");
case OP_MOD:
return LLVMBuildSRem(ctx->builder, l, r, "srem");
case OP_EQ:
case OP_NE:
case OP_LT:
case OP_GT:
case OP_LE:
case OP_GE: {
// 枚举比较: 提取 tag 字段再比较
LLVMValueRef cl = l, cr = r;
if (node->as.binary.left->type.kind == TYPE_ENUM) {
cl = LLVMBuildExtractValue(ctx->builder, l, 0, "enum_tag_l");
}
if (node->as.binary.right->type.kind == TYPE_ENUM) {
cr = LLVMBuildExtractValue(ctx->builder, r, 0, "enum_tag_r");
}
LLVMIntPredicate pred;
switch (node->as.binary.op) {
case OP_EQ: pred = LLVMIntEQ; break;
case OP_NE: pred = LLVMIntNE; break;
case OP_LT: pred = LLVMIntSLT; break;
case OP_GT: pred = LLVMIntSGT; break;
case OP_LE: pred = LLVMIntSLE; break;
case OP_GE: pred = LLVMIntSGE; break;
default: return NULL;
}
if (is_float)
return LLVMBuildFCmp(ctx->builder, pred == LLVMIntEQ ? LLVMRealOEQ :
pred == LLVMIntNE ? LLVMRealONE : pred == LLVMIntSLT ? LLVMRealOLT :
pred == LLVMIntSGT ? LLVMRealOGT : pred == LLVMIntSLE ? LLVMRealOLE :
LLVMRealOGE, cl, cr, "fcmp");
return LLVMBuildICmp(ctx->builder, pred, cl, cr, "icmp");
}
case OP_AND:
return LLVMBuildAnd(ctx->builder, l, r, "and");
case OP_OR:
return LLVMBuildOr(ctx->builder, l, r, "or");
default:
return NULL;
}
}
case AST_CALL_EXPR: {
// === 内置 print 函数:委托给 printf ===
if (strcmp(node->as.call.name, "print_i64") == 0) {
LLVMValueRef arg = codegen_expr(ctx, node->as.call.args[0]);
if (!arg) return NULL;
// 枚举类型: 提取 tag 字段
if (node->as.call.args[0]->type.kind == TYPE_ENUM)
arg = LLVMBuildExtractValue(ctx->builder, arg, 0, "tag");
LLVMTypeRef i64_ty = LLVMInt64TypeInContext(ctx->context);
arg = coerce_int(ctx, arg, LLVMTypeOf(arg), i64_ty);
LLVMValueRef fmt = LLVMBuildGlobalStringPtr(ctx->builder, "%lld\n", "fmt_i64");
LLVMValueRef printf_args[] = { fmt, arg };
return LLVMBuildCall2(ctx->builder, ctx->printf_ty, ctx->printf_fn,
printf_args, 2, "");
}
if (strcmp(node->as.call.name, "print_f64") == 0) {
LLVMValueRef arg = codegen_expr(ctx, node->as.call.args[0]);
if (!arg) return NULL;
LLVMValueRef fmt = LLVMBuildGlobalStringPtr(ctx->builder, "%f\n", "fmt_f64");
LLVMValueRef printf_args[] = { fmt, arg };
return LLVMBuildCall2(ctx->builder, ctx->printf_ty, ctx->printf_fn,
printf_args, 2, "");
}
if (strcmp(node->as.call.name, "print_bool") == 0) {
LLVMValueRef arg = codegen_expr(ctx, node->as.call.args[0]);
if (!arg) return NULL;
// 将 bool 转为字符串:通过 select 在 "true\n" 和 "false\n" 之间选择
LLVMValueRef c = LLVMBuildICmp(ctx->builder, LLVMIntEQ, arg,
LLVMConstInt(LLVMInt1TypeInContext(ctx->context), 1, false), "bool_cmp");
LLVMValueRef true_str = LLVMBuildGlobalStringPtr(ctx->builder, "true\n", "true_str");
LLVMValueRef false_str = LLVMBuildGlobalStringPtr(ctx->builder, "false\n", "false_str");
LLVMValueRef selected = LLVMBuildSelect(ctx->builder, c, true_str, false_str, "bool_sel");
return LLVMBuildCall2(ctx->builder, ctx->printf_ty, ctx->printf_fn,
(LLVMValueRef[]){selected}, 1, "");
}
if (strcmp(node->as.call.name, "print_str") == 0) {
LLVMValueRef arg = codegen_expr(ctx, node->as.call.args[0]);
if (!arg) return NULL;
LLVMValueRef fmt = LLVMBuildGlobalStringPtr(ctx->builder, "%s\n", "fmt_str");
LLVMValueRef printf_args[] = { fmt, arg };
return LLVMBuildCall2(ctx->builder, ctx->printf_ty, ctx->printf_fn,
printf_args, 2, "");
}
// === 常规函数调用 ===
LLVMValueRef fn = find_fn(ctx, node->as.call.name);
if (!fn) return NULL;
LLVMValueRef args[16];
if (node->as.call.arg_count > 16) { ctx->error = "函数参数过多(最多16)"; return NULL; }
for (size_t i = 0; i < node->as.call.arg_count; i++) {
args[i] = codegen_expr(ctx, node->as.call.args[i]);
if (!args[i]) return NULL;
}
LLVMTypeRef fn_ty = LLVMGlobalGetValueType(fn);
LLVMTypeRef ret_ty = LLVMGetReturnType(fn_ty);
return LLVMBuildCall2(ctx->builder, fn_ty, fn,
args, (unsigned)node->as.call.arg_count,
ret_ty == LLVMVoidTypeInContext(ctx->context) ? "" : "call");
}
// === 结构体字段访问: p.x ===
case AST_FIELD_ACCESS: {
// 对对象求值(返回的是 struct 值)
LLVMValueRef struct_val = codegen_expr(ctx, node->as.field_access.object);
if (!struct_val) return NULL;
int field_idx = node->as.field_access.field_index;
if (field_idx < 0) return NULL; // sema 应当已经设置
// 用 extractvalue 从结构体值中提取字段
return LLVMBuildExtractValue(ctx->builder, struct_val,
(unsigned)field_idx, node->as.field_access.field);
}
// === 结构体初始化: Point { x: 10, y: 20 } ===
case AST_STRUCT_INIT: {
const char* st_name = node->as.struct_init.type_name;
LLVMTypeRef struct_ty = find_struct_type(ctx, st_name);
if (!struct_ty) return NULL;
// alloca 分配结构体空间
LLVMValueRef alloca = LLVMBuildAlloca(ctx->builder, struct_ty, "struct_init");
// 获取结构体字段名列表(从 struct_table 或从 AST 中)
// 对每个 init 字段,找到它在结构体中的索引并 store
for (size_t i = 0; i < node->as.struct_init.field_count; i++) {
AstNode* fval = node->as.struct_init.field_values[i];
LLVMValueRef val = codegen_expr(ctx, fval);
if (!val) return NULL;
// 获取字段指针: GEP struct_ty, alloca, 0, i
LLVMValueRef indices[] = {
LLVMConstInt(LLVMInt32TypeInContext(ctx->context), 0, false),
LLVMConstInt(LLVMInt32TypeInContext(ctx->context), (unsigned long long)i, false)
};
LLVMValueRef field_ptr = LLVMBuildGEP2(ctx->builder, struct_ty, alloca,
indices, 2, "field_ptr");
LLVMBuildStore(ctx->builder, val, field_ptr);
}
// 加载整个结构体值
return LLVMBuildLoad2(ctx->builder, struct_ty, alloca, "struct_val");
}
case AST_ENUM_VARIANT: {
// tagged union: { tag, payload }
LLVMValueRef tag = LLVMConstInt(LLVMInt64TypeInContext(ctx->context),
(unsigned long long)node->as.enum_variant.variant_index, true);
LLVMValueRef payload = LLVMConstInt(LLVMInt64TypeInContext(ctx->context), 0, true);
if (node->as.enum_variant.payload) {
LLVMValueRef pv = codegen_expr(ctx, node->as.enum_variant.payload);
if (pv) {
// 将 payload 强制转换为 i64
LLVMTypeRef pv_ty = LLVMTypeOf(pv);
LLVMTypeRef i64_ty = LLVMInt64TypeInContext(ctx->context);
if (pv_ty != i64_ty && LLVMGetTypeKind(pv_ty) == LLVMIntegerTypeKind)
pv = coerce_int(ctx, pv, pv_ty, i64_ty);
payload = pv;
}
}
LLVMValueRef fields[] = { tag, payload };
return LLVMConstStruct(fields, 2, false);
}
case AST_METHOD_CALL: {
const char* struct_name = node->as.method_call.receiver->type.struct_name;
char mangled[256];
// 若 method_name 已含 $trait 方法,sema 已设置全限定名),直接用
if (strchr(node->as.method_call.method_name, '$'))
snprintf(mangled, sizeof(mangled), "%s", node->as.method_call.method_name);
else
snprintf(mangled, sizeof(mangled), "%s$%s", struct_name,
node->as.method_call.method_name);
LLVMValueRef fn = find_fn(ctx, mangled);
if (!fn) return NULL;
// 参数列表: [receiver, 用户参数...]
if (node->as.method_call.arg_count + 1 > 16) { ctx->error = "方法参数过多(最多15)"; return NULL; }
LLVMValueRef args[16];
args[0] = codegen_expr(ctx, node->as.method_call.receiver);
if (!args[0]) return NULL;
for (size_t i = 0; i < node->as.method_call.arg_count; i++) {
args[i + 1] = codegen_expr(ctx, node->as.method_call.args[i]);
if (!args[i + 1]) return NULL;
}
LLVMTypeRef fn_ty = LLVMGlobalGetValueType(fn);
LLVMTypeRef ret_ty = LLVMGetReturnType(fn_ty);
return LLVMBuildCall2(ctx->builder, fn_ty, fn, args,
(unsigned)(node->as.method_call.arg_count + 1),
ret_ty == LLVMVoidTypeInContext(ctx->context) ? "" : "method_call");
}
case AST_INDEX_EXPR: {
// 获取数组变量的指针
AstNode* arr_node = node->as.index_expr.array;
LLVMValueRef arr_ptr = NULL;
LLVMTypeRef arr_gp_type = NULL;
if (arr_node->kind == AST_IDENT_EXPR) {
arr_ptr = find_var(ctx, arr_node->as.ident.name);
// 从变量表获取数组类型用于 GEP
for (VarEntry* e = ctx->var_table; e; e = e->next) {
if (strcmp(e->name, arr_node->as.ident.name) == 0) {
arr_gp_type = e->alloca_type; break;
}
}
}
if (!arr_ptr || !arr_gp_type) return NULL;
// 生成索引值
LLVMValueRef idx_val = codegen_expr(ctx, node->as.index_expr.index);
if (!idx_val) return NULL;
// GEP 索引必须是 i32,但 L 使用 i64。截断。
LLVMValueRef idx_i32 = LLVMBuildTrunc(ctx->builder, idx_val,
LLVMInt32TypeInContext(ctx->context), "idx32");
LLVMValueRef indices[] = {
LLVMConstInt(LLVMInt32TypeInContext(ctx->context), 0, false),
idx_i32
};
LLVMValueRef elem_ptr = LLVMBuildGEP2(ctx->builder, arr_gp_type, arr_ptr, indices, 2, "arr_elem");
LLVMTypeRef elem_load_ty;
if (node->type.kind == TYPE_STRUCT && node->type.struct_name) {
elem_load_ty = find_struct_type(ctx, node->type.struct_name);
if (!elem_load_ty) elem_load_ty = to_llvm_type(ctx, node->type.kind);
} else {
elem_load_ty = type_info_to_llvm(ctx, &node->type);
}
return LLVMBuildLoad2(ctx->builder, elem_load_ty, elem_ptr, "arr_load");
}
// 块表达式: { stmt*; expr } → 最后表达式的值
case AST_BLOCK: {
LLVMValueRef result = NULL;
for (size_t i = 0; i < node->as.block.stmt_count; i++) {
AstNode* stmt = node->as.block.stmts[i];
bool is_last = (i == node->as.block.stmt_count - 1);
if (is_last && stmt->kind == AST_EXPR_STMT && node->type.kind != TYPE_VOID) {
result = codegen_expr(ctx, stmt->as.expr_stmt.expr);
} else {
codegen_stmt(ctx, stmt);
}
}
return result;
}
// if 表达式: if cond { a } else { b }
case AST_IF_STMT: {
if (node->type.kind == TYPE_VOID) { codegen_stmt(ctx, node); return NULL; }
LLVMValueRef cond_val = codegen_expr(ctx, node->as.if_stmt.cond);
if (!cond_val) return NULL;
LLVMTypeRef res_ty = type_info_to_llvm(ctx, &node->type);
LLVMValueRef alloca = LLVMBuildAlloca(ctx->builder, res_ty, "if_res");
LLVMValueRef func = LLVMGetBasicBlockParent(LLVMGetInsertBlock(ctx->builder));
LLVMBasicBlockRef then_bb = LLVMAppendBasicBlockInContext(ctx->context, func, "then");
LLVMBasicBlockRef else_bb = LLVMAppendBasicBlockInContext(ctx->context, func, "else");
LLVMBasicBlockRef merge_bb = LLVMAppendBasicBlockInContext(ctx->context, func, "if_merge");
LLVMBuildCondBr(ctx->builder, cond_val, then_bb, else_bb);
LLVMPositionBuilderAtEnd(ctx->builder, then_bb);
LLVMValueRef then_val = codegen_expr(ctx, node->as.if_stmt.then_block);
if (then_val) LLVMBuildStore(ctx->builder, then_val, alloca);
LLVMBuildBr(ctx->builder, merge_bb);
LLVMPositionBuilderAtEnd(ctx->builder, else_bb);
LLVMValueRef else_val = codegen_expr(ctx, node->as.if_stmt.else_block);
if (else_val) LLVMBuildStore(ctx->builder, else_val, alloca);
LLVMBuildBr(ctx->builder, merge_bb);
LLVMPositionBuilderAtEnd(ctx->builder, merge_bb);
return LLVMBuildLoad2(ctx->builder, res_ty, alloca, "if_val");
}
default:
return NULL;
}
}
// === 自动内存管理: 作用域退出时释放 str 堆分配 ===
static void cleanup_add(CgCtx* ctx, LLVMValueRef alloca) {
void cleanup_add(CgCtx* ctx, LLVMValueRef alloca) {
if (ctx->cleanup_count >= ctx->cleanup_cap) {
size_t new_cap = ctx->cleanup_cap ? ctx->cleanup_cap * 2 : 16;
LLVMValueRef* new_list = arena_alloc(ctx->arena, new_cap * sizeof(LLVMValueRef));
@@ -559,7 +65,7 @@ static void cleanup_add(CgCtx* ctx, LLVMValueRef alloca) {
}
// 释放从 mark 位置开始的所有 str 变量
static void cleanup_emit(CgCtx* ctx, size_t from_mark) {
void cleanup_emit(CgCtx* ctx, size_t from_mark) {
for (size_t j = from_mark; j < ctx->cleanup_count; j++) {
LLVMValueRef ptr = ctx->cleanup_list[j];
LLVMValueRef val = LLVMBuildLoad2(ctx->builder,
@@ -572,7 +78,7 @@ static void cleanup_emit(CgCtx* ctx, size_t from_mark) {
}
// === 语句代码生成 ===
static void codegen_stmt(CgCtx* ctx, AstNode* node) {
void codegen_stmt(CgCtx* ctx, AstNode* node) {
if (!node) return;
switch (node->kind) {
+83
View File
@@ -0,0 +1,83 @@
#ifndef CODEGEN_INTERNAL_H
#define CODEGEN_INTERNAL_H
#include "codegen.h"
#include "ast.h"
#include "arena.h"
#include "l_lang.h"
#include <llvm-c/Analysis.h>
#include <llvm-c/Types.h>
#include <string.h>
#include <stdio.h>
// 递归深度限制
extern int codegen_depth;
#define MAX_CODEGEN_DEPTH 1000
// === 内部状态 ===
typedef struct VarEntry {
const char* name;
LLVMValueRef alloca;
LLVMTypeRef alloca_type;
struct VarEntry* next;
} VarEntry;
typedef struct FnEntry {
const char* name;
LLVMValueRef fn;
TypeKind ret;
TypeKind* params;
size_t pc;
struct FnEntry* next;
} FnEntry;
typedef struct StructTypeEntry {
const char* name;
LLVMTypeRef llvm_type;
size_t field_count;
struct StructTypeEntry* next;
} StructTypeEntry;
typedef struct {
Arena* arena;
LLVMContextRef context;
LLVMModuleRef module;
LLVMBuilderRef builder;
VarEntry* var_table;
const char* error;
FnEntry* fn_table;
StructTypeEntry* struct_table;
LLVMValueRef printf_fn;
LLVMTypeRef printf_ty;
LLVMValueRef malloc_fn;
LLVMValueRef free_fn;
LLVMValueRef strlen_fn;
LLVMValueRef memcpy_fn;
LLVMValueRef* cleanup_list;
size_t cleanup_count;
size_t cleanup_cap;
} CgCtx;
// === 类型映射 ===
LLVMTypeRef to_llvm_type(CgCtx* ctx, TypeKind kind);
LLVMValueRef to_llvm_const(LLVMTypeRef ty, AstNode* lit);
LLVMTypeRef type_info_to_llvm(CgCtx* ctx, const TypeInfo* ti);
LLVMValueRef coerce_int(CgCtx* ctx, LLVMValueRef val, LLVMTypeRef from_ty, LLVMTypeRef to_ty);
// === 表操作 ===
LLVMValueRef find_var(CgCtx* ctx, const char* name);
void add_var(CgCtx* ctx, const char* name, LLVMValueRef alloca, LLVMTypeRef alloca_type);
LLVMValueRef find_fn(CgCtx* ctx, const char* name);
void add_fn(CgCtx* ctx, const char* name, LLVMValueRef fn);
void add_struct_type(CgCtx* ctx, const char* name, LLVMTypeRef ty, size_t fc);
LLVMTypeRef find_struct_type(CgCtx* ctx, const char* name);
// === 内存清理 ===
void cleanup_add(CgCtx* ctx, LLVMValueRef alloca);
void cleanup_emit(CgCtx* ctx, size_t from_mark);
// === 代码生成函数 ===
LLVMValueRef codegen_expr(CgCtx* ctx, AstNode* node);
void codegen_stmt(CgCtx* ctx, AstNode* node);
#endif