#include "l_lang.h" #include "lexer.h" #include "parser.h" #include "sema.h" #include "codegen.h" #include "error.h" #include "arena.h" #include #include #include #include #include #include // 读取整个文件到内存 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; }