Files
l-language/src/driver/main.c
T
Serendipity f8c5e18188 fix: 技术债修复 — codegen malloc→arena + .codegraphignore
- codegen.c: VarEntry/FnEntry/ptypes 全部改用 arena_alloc,消除 malloc/free
- codegen_module 新增 Arena* 参数,main.c 传入主 arena
- 新增 .codegraphignore 排除 build/ 和 .codegraph/
- 基于 Codex 分析报告第7节技术债务
2026-06-05 00:37:54 +08:00

170 lines
5.2 KiB
C

#include "l_lang.h"
#include "lexer.h"
#include "parser.h"
#include "sema.h"
#include "codegen.h"
#include "error.h"
#include "arena.h"
#include <llvm-c/Core.h>
#include <llvm-c/TargetMachine.h>
#include <llvm-c/Target.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// 读取整个文件到内存
static char* read_file(const char* path, size_t* size) {
FILE* f = fopen(path, "rb");
if (!f) { fprintf(stderr, "无法打开文件: %s\n", path); return NULL; }
fseek(f, 0, SEEK_END);
*size = ftell(f);
fseek(f, 0, SEEK_SET);
char* buf = malloc(*size + 1);
if (!buf) { fclose(f); return NULL; }
fread(buf, 1, *size, f);
buf[*size] = '\0';
fclose(f);
return buf;
}
// 写入字符串到文件
static bool write_file(const char* path, const char* data) {
FILE* f = fopen(path, "w");
if (!f) return false;
fputs(data, f);
fclose(f);
return true;
}
int main(int argc, char** argv) {
const char* input = NULL;
const char* output = "a.exe";
bool emit_ir = false;
// 解析命令行参数
for (int i = 1; i < argc; i++) {
if (strcmp(argv[i], "--emit-ir") == 0) { emit_ir = true; }
else if (strcmp(argv[i], "-o") == 0 && i + 1 < argc) { output = argv[++i]; }
else if (argv[i][0] != '-') { input = argv[i]; }
}
if (!input) {
fprintf(stderr, "用法: l_lang <文件.l> [-o <输出>] [--emit-ir]\n");
return 1;
}
// 1. 读取源文件
size_t src_size;
char* source = read_file(input, &src_size);
if (!source) return 1;
// 2. 初始化
Arena arena = arena_create(8); // 8 MB
if (!arena.memory) { fprintf(stderr, "内存分配失败\n"); free(source); return 1; }
ErrorInfo error = {0};
ErrorList error_list; error_init(&error_list);
// 3. 词法分析
size_t token_count;
Token* tokens = lex(&arena, source, input, &token_count, &error);
if (!tokens) {
fprintf(stderr, "词法错误: %s:%d:%d: %s\n",
error.filename, error.line, error.col, error.message);
free(source); arena_destroy(&arena);
return 1;
}
// 4. 语法分析
AstNode* ast = parse(&arena, tokens, token_count, input, &error);
if (!ast) {
fprintf(stderr, "语法错误: %s:%d:%d: %s\n",
error.filename, error.line, error.col, error.message);
free(source); arena_destroy(&arena);
return 1;
}
// 5. 语义分析
sema_analyze(ast, &error_list, &arena);
if (error_list.count > 0) {
error_print(&error_list);
free(source); arena_destroy(&arena);
return 1;
}
// 6. LLVM IR 生成
const char* codegen_error = NULL;
LLVMModuleRef module = codegen_module(ast, &arena, "l_module", &codegen_error);
if (!module) {
fprintf(stderr, "IR 生成错误: %s\n", codegen_error);
free(source); arena_destroy(&arena);
return 1;
}
if (emit_ir) {
// 输出 LLVM IR 文本
char* ir = LLVMPrintModuleToString(module);
char ir_path[512];
snprintf(ir_path, sizeof(ir_path), "%s.ll", input);
write_file(ir_path, ir);
printf("IR 已输出到: %s\n", ir_path);
LLVMDisposeMessage(ir);
} else {
// 初始化 X86 目标(LLVM-C.lib 中没有 InitializeAll 系列符号)
LLVMInitializeX86TargetInfo();
LLVMInitializeX86Target();
LLVMInitializeX86TargetMC();
LLVMInitializeX86AsmPrinter();
LLVMInitializeX86AsmParser();
char* triple = LLVMGetDefaultTargetTriple();
LLVMTargetRef target;
char* target_error = NULL;
if (LLVMGetTargetFromTriple(triple, &target, &target_error)) {
fprintf(stderr, "目标平台错误: %s\n", target_error);
LLVMDisposeMessage(target_error); LLVMDisposeMessage(triple);
free(source); arena_destroy(&arena); LLVMDisposeModule(module);
return 1;
}
LLVMTargetMachineRef tm = LLVMCreateTargetMachine(
target, triple, "generic", "",
LLVMCodeGenLevelDefault, LLVMRelocDefault,
LLVMCodeModelDefault);
LLVMDisposeMessage(triple);
// 输出目标文件
char obj_path[512];
snprintf(obj_path, sizeof(obj_path), "%s.o", input);
char* obj_error = NULL;
if (LLVMTargetMachineEmitToFile(tm, module, obj_path,
LLVMObjectFile, &obj_error)) {
fprintf(stderr, "目标代码生成错误: %s\n", obj_error);
LLVMDisposeMessage(obj_error);
free(source); arena_destroy(&arena);
LLVMDisposeTargetMachine(tm); LLVMDisposeModule(module);
return 1;
}
// 调用 gcc 链接(MinGW 环境可用)
char cmd[1024];
snprintf(cmd, sizeof(cmd),
"gcc \"%s\" -o \"%s\"",
obj_path, output);
int ret = system(cmd);
if (ret != 0) {
fprintf(stderr, "链接失败 (exit code %d)\n", ret);
} else {
printf("编译成功: %s\n", output);
}
LLVMDisposeTargetMachine(tm);
}
// 清理
LLVMDisposeModule(module);
free(source);
arena_destroy(&arena);
return 0;
}