From 880fd01d51ea3fe76b3ccfce2aa109b8b658d420 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=89=E5=B3=BB=E9=82=91?= <2294450067@qq.com> Date: Mon, 11 May 2026 09:10:49 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=94=AF=E6=8C=81=E6=AF=94=E8=B5=9B?= =?UTF-8?q?=E8=A6=81=E6=B1=82=E7=9A=84CLI=E6=A0=BC=E5=BC=8F=20(-S=20-o=20-?= =?UTF-8?q?O1)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 添加 -S 参数生成汇编文件 - 添加 -o 参数指定输出文件路径 - 添加 -O1/-O2/-O3 优化级别支持 - 默认行为:未指定输出模式时默认生成汇编 - 兼容旧格式 (--emit-asm, --emit-ir 等) --- include/utils/CLI.h | 8 ++-- src/ir/passes/PassManager.cpp | 18 ++++++++ src/main.cpp | 78 ++++++++++++++++++++--------------- src/utils/CLI.cpp | 58 +++++++++++++++++++++++--- 4 files changed, 120 insertions(+), 42 deletions(-) diff --git a/include/utils/CLI.h b/include/utils/CLI.h index 4c184a4a..a06106b6 100644 --- a/include/utils/CLI.h +++ b/include/utils/CLI.h @@ -1,15 +1,17 @@ -// 简易命令行解析:支持帮助、输入文件与输出阶段选择。 +// 命令行解析:支持比赛要求的 -S -o -O1 格式 #pragma once #include struct CLIOptions { std::string input; + std::string output; // -o 指定的输出文件路径 bool emit_parse_tree = false; - bool emit_ir = true; + bool emit_ir = false; bool emit_asm = false; bool show_help = false; - bool optimize = false; + bool optimize = false; // -O 或 -O1 + int opt_level = 0; // 优化级别: 0, 1, 2, 3 }; CLIOptions ParseCLI(int argc, char** argv); diff --git a/src/ir/passes/PassManager.cpp b/src/ir/passes/PassManager.cpp index 34ea284e..5e54191c 100644 --- a/src/ir/passes/PassManager.cpp +++ b/src/ir/passes/PassManager.cpp @@ -62,4 +62,22 @@ class PassManagerModule { Module* module_; }; +// 简化版 PassManager,提供单个函数接口 +class PassManager { + public: + PassManager() = default; + + void RunScalarOptimizationPasses(Module* module) { + if (!module) return; + + RunMem2Reg(*module); + + RunConstFold(*module); + RunDCE(*module); + RunCFGSimplify(*module); + } + + private: +}; + } // namespace ir diff --git a/src/main.cpp b/src/main.cpp index a81497e2..ce4e0d7b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,6 +1,8 @@ #include +#include #include #include +#include #include "frontend/AntlrDriver.h" #include "frontend/SyntaxTreePrinter.h" @@ -14,75 +16,83 @@ #include "utils/CLI.h" #include "utils/Log.h" -int main(int argc, char **argv) -{ - try - { +int main(int argc, char** argv) { + try { auto opts = ParseCLI(argc, argv); - if (opts.show_help) - { + if (opts.show_help) { PrintHelp(std::cout); return 0; } auto antlr = ParseFileWithAntlr(opts.input); bool need_blank_line = false; - if (opts.emit_parse_tree) - { + if (opts.emit_parse_tree) { PrintSyntaxTree(antlr.tree, antlr.parser.get(), std::cout); need_blank_line = true; } #if !COMPILER_PARSE_ONLY - auto *comp_unit = dynamic_cast(antlr.tree); - if (!comp_unit) - { - throw std::runtime_error(FormatError("main", "语法树根节点不是 compUnit")); + auto* comp_unit = + dynamic_cast(antlr.tree); + if (!comp_unit) { + throw std::runtime_error( + FormatError("main", "语法树根节点不是 compUnit")); } auto sema = RunSema(*comp_unit); auto module = GenerateIR(*comp_unit, sema); + // 执行优化(如果启用) if (opts.optimize) { - ir::PassManagerModule pass_manager(module.get()); - pass_manager.Run(); - } - - if (opts.emit_ir) { - ir::IRPrinter printer; - if (need_blank_line) { - std::cout << "\n"; - } - printer.Print(*module, std::cout); - need_blank_line = true; + ir::PassManager pass_manager; + pass_manager.RunScalarOptimizationPasses(module.get()); } - if (opts.emit_asm) - { + // 汇编输出到文件或标准输出 + if (opts.emit_asm) { auto machine_module = mir::LowerModuleToMIR(*module); mir::RunRegAlloc(*machine_module); mir::RunFrameLowering(*machine_module); mir::RunPeephole(*machine_module); - if (need_blank_line) - { + std::ostringstream asm_ss; + mir::PrintAsm(*machine_module, asm_ss); + + if (!opts.output.empty()) { + // 写入指定文件(-o 参数) + std::ofstream ofs(opts.output); + if (!ofs) { + throw std::runtime_error(FormatError("main", std::string("无法打开输出文件: ") + opts.output)); + } + ofs << asm_ss.str(); + ofs.close(); + } else { + // 输出到标准输出 + if (need_blank_line) { + std::cout << "\n"; + } + std::cout << asm_ss.str(); + } + } + + if (opts.emit_ir) { + ir::IRPrinter printer; + if (need_blank_line) { std::cout << "\n"; } - mir::PrintAsm(*machine_module, std::cout); + printer.Print(*module, std::cout); + need_blank_line = true; } #else - if (opts.emit_ir || opts.emit_asm) - { + if (opts.emit_ir || opts.emit_asm) { throw std::runtime_error( FormatError("main", "当前为 parse-only 构建;IR/汇编输出已禁用")); } #endif - } - catch (const std::exception &ex) - { + } catch (const std::exception& ex) { PrintException(std::cerr, ex); return 1; } return 0; -} \ No newline at end of file +} diff --git a/src/utils/CLI.cpp b/src/utils/CLI.cpp index 8fb107b3..3a2e42ad 100644 --- a/src/utils/CLI.cpp +++ b/src/utils/CLI.cpp @@ -1,4 +1,6 @@ -// 解析帮助、输入文件和输出阶段选项。 +// 解析命令行参数,支持比赛要求的格式: +// compiler -S -o testcase.s testcase.sy +// compiler -S -o testcase.s testcase.sy -O1 #include "utils/CLI.h" @@ -15,21 +17,64 @@ CLIOptions ParseCLI(int argc, char** argv) { if (argc <= 1) { throw std::runtime_error(FormatError( "cli", - "用法: compiler [--help] [--emit-parse-tree] [--emit-ir] [--emit-asm] [-O] ")); + "用法: compiler [-S] [-o output.s] [-O|-O1|-O2|-O3] ")); } for (int i = 1; i < argc; ++i) { const char* arg = argv[i]; + + // 帮助 if (std::strcmp(arg, "-h") == 0 || std::strcmp(arg, "--help") == 0) { opt.show_help = true; return opt; } - if (std::strcmp(arg, "-O") == 0 || std::strcmp(arg, "--optimize") == 0) { + // -S: 生成汇编(比赛要求) + if (std::strcmp(arg, "-S") == 0) { + if (!explicit_emit) { + opt.emit_parse_tree = false; + opt.emit_ir = false; + opt.emit_asm = false; + explicit_emit = true; + } + opt.emit_asm = true; + continue; + } + + // -o : 指定输出文件 + if (std::strcmp(arg, "-o") == 0) { + if (i + 1 < argc) { + opt.output = argv[++i]; + } else { + throw std::runtime_error(FormatError("cli", "-o 需要指定输出文件")); + } + continue; + } + + // 优化级别: -O, -O1, -O2, -O3 + if (std::strncmp(arg, "-O", 2) == 0) { opt.optimize = true; + if (arg[2] == '\0') { + opt.opt_level = 1; // -O 默认为 O1 + } else { + int level = 0; + try { + level = std::stoi(arg + 2); + } catch (...) { + level = 1; + } + opt.opt_level = level; + } continue; } + if (std::strcmp(arg, "--optimize") == 0) { + opt.optimize = true; + opt.opt_level = 1; + continue; + } + + // 兼容旧格式 if (std::strcmp(arg, "--emit-parse-tree") == 0) { if (!explicit_emit) { opt.emit_parse_tree = false; @@ -80,9 +125,12 @@ CLIOptions ParseCLI(int argc, char** argv) { throw std::runtime_error( FormatError("cli", "缺少输入文件:请提供 (使用 --help 查看用法)")); } + + // 如果没有指定任何输出模式,默认生成汇编(比赛场景) if (!opt.emit_parse_tree && !opt.emit_ir && !opt.emit_asm) { - throw std::runtime_error(FormatError( - "cli", "未选择任何输出:请使用 --emit-parse-tree / --emit-ir / --emit-asm")); + opt.emit_asm = true; + explicit_emit = true; } + return opt; }