feat: 支持比赛要求的CLI格式 (-S -o -O1)

- 添加 -S 参数生成汇编文件
- 添加 -o 参数指定输出文件路径
- 添加 -O1/-O2/-O3 优化级别支持
- 默认行为:未指定输出模式时默认生成汇编
- 兼容旧格式 (--emit-asm, --emit-ir 等)
zhm
安峻邑 2 weeks ago
parent 6cf5f20ba8
commit 880fd01d51

@ -1,15 +1,17 @@
// 简易命令行解析:支持帮助、输入文件与输出阶段选择。
// 命令行解析:支持比赛要求的 -S -o -O1 格式
#pragma once
#include <string>
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);

@ -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

@ -1,6 +1,8 @@
#include <exception>
#include <fstream>
#include <iostream>
#include <stdexcept>
#include <sstream>
#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<SysYParser::CompUnitContext *>(antlr.tree);
if (!comp_unit)
{
throw std::runtime_error(FormatError("main", "语法树根节点不是 compUnit"));
auto* comp_unit =
dynamic_cast<SysYParser::CompUnitContext*>(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;
}
}

@ -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] <input.sy>"));
"用法: compiler [-S] [-o output.s] [-O|-O1|-O2|-O3] <input.sy>"));
}
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 <file>: 指定输出文件
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", "缺少输入文件:请提供 <input.sy>(使用 --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;
}

Loading…
Cancel
Save