Merge branch 'master' of https://gitee.com/NUDT-compiler/nudt-compiler-cpp
This commit is contained in:
@@ -9,20 +9,17 @@
|
||||
#include "SysYLexer.h"
|
||||
#include "SysYParser.h"
|
||||
#include "antlr4-runtime.h"
|
||||
#include "utils/Log.h"
|
||||
|
||||
namespace {
|
||||
|
||||
bool HasParsePrefix(const std::string& msg) {
|
||||
return msg.rfind("[parse]", 0) == 0;
|
||||
}
|
||||
|
||||
class ParseErrorListener : public antlr4::BaseErrorListener {
|
||||
public:
|
||||
void syntaxError(antlr4::Recognizer* /*recognizer*/, antlr4::Token* /*offendingSymbol*/,
|
||||
size_t line, size_t charPositionInLine,
|
||||
const std::string& msg, std::exception_ptr /*e*/) override {
|
||||
throw std::runtime_error("[parse] 暂不支持的语法/词法 @" + std::to_string(line) + ":" +
|
||||
std::to_string(charPositionInLine) + " - " + msg);
|
||||
throw std::runtime_error(FormatErrorAt("parse", line, charPositionInLine,
|
||||
"暂不支持的语法/词法 - " + msg));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -31,7 +28,7 @@ class ParseErrorListener : public antlr4::BaseErrorListener {
|
||||
AntlrResult ParseFileWithAntlr(const std::string& path) {
|
||||
std::ifstream fin(path);
|
||||
if (!fin.is_open()) {
|
||||
throw std::runtime_error("[parse] 无法打开输入文件: " + path);
|
||||
throw std::runtime_error(FormatError("parse", "无法打开输入文件: " + path));
|
||||
}
|
||||
std::ostringstream ss;
|
||||
ss << fin.rdbuf();
|
||||
@@ -53,18 +50,18 @@ AntlrResult ParseFileWithAntlr(const std::string& path) {
|
||||
} catch (const std::exception& ex) {
|
||||
const std::string msg = ex.what();
|
||||
if (!msg.empty()) {
|
||||
if (HasParsePrefix(msg)) {
|
||||
if (HasErrorPrefix(msg, "parse")) {
|
||||
throw;
|
||||
}
|
||||
throw std::runtime_error("[parse] 暂不支持的语法/词法 - " + msg);
|
||||
throw std::runtime_error(
|
||||
FormatError("parse", "暂不支持的语法/词法 - " + msg));
|
||||
}
|
||||
if (auto* tok = parser->getCurrentToken()) {
|
||||
throw std::runtime_error("[parse] 暂不支持的语法/词法 @" +
|
||||
std::to_string(tok->getLine()) + ":" +
|
||||
std::to_string(tok->getCharPositionInLine()) +
|
||||
" near token '" + tok->getText() + "'");
|
||||
throw std::runtime_error(
|
||||
FormatErrorAt("parse", tok->getLine(), tok->getCharPositionInLine(),
|
||||
"暂不支持的语法/词法 near token '" + tok->getText() + "'"));
|
||||
}
|
||||
throw std::runtime_error("[parse] 暂不支持的语法/词法");
|
||||
throw std::runtime_error(FormatError("parse", "暂不支持的语法/词法"));
|
||||
}
|
||||
|
||||
AntlrResult result;
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include "SysYParser.h"
|
||||
#include "ir/IR.h"
|
||||
#include "utils/Log.h"
|
||||
|
||||
void IRGenImpl::GenBlock(SysYParser::BlockContext& block) {
|
||||
for (auto* item : block.blockItem()) {
|
||||
@@ -24,7 +25,7 @@ bool IRGenImpl::GenBlockItem(SysYParser::BlockItemContext& item) {
|
||||
if (item.stmt()) {
|
||||
return GenStmt(*item.stmt());
|
||||
}
|
||||
throw std::runtime_error("[irgen] 暂不支持的 blockItem 类型");
|
||||
throw std::runtime_error(FormatError("irgen", "暂不支持的语句或声明"));
|
||||
}
|
||||
|
||||
void IRGenImpl::GenDecl(SysYParser::DeclContext& decl) {
|
||||
@@ -32,12 +33,12 @@ void IRGenImpl::GenDecl(SysYParser::DeclContext& decl) {
|
||||
GenVarDecl(*decl.varDecl());
|
||||
return;
|
||||
}
|
||||
throw std::runtime_error("[irgen] 暂不支持的声明类型");
|
||||
throw std::runtime_error(FormatError("irgen", "暂不支持的声明类型"));
|
||||
}
|
||||
|
||||
void IRGenImpl::GenVarDecl(SysYParser::VarDeclContext& decl) {
|
||||
if (storage_map_.find(&decl) != storage_map_.end()) {
|
||||
throw std::runtime_error("[irgen] 声明重复生成存储槽位");
|
||||
throw std::runtime_error(FormatError("irgen", "声明重复生成存储槽位"));
|
||||
}
|
||||
auto* slot = builder_.CreateAllocaI32(module_.context().NextTemp());
|
||||
storage_map_[&decl] = slot;
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#include "irgen/IRGen.h"
|
||||
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "SysYParser.h"
|
||||
#include "ir/IR.h"
|
||||
#include "utils/Log.h"
|
||||
|
||||
std::unique_ptr<ir::Module> GenerateIR(SysYParser::CompUnitContext& tree,
|
||||
const SemanticContext& sema) {
|
||||
|
||||
@@ -4,10 +4,11 @@
|
||||
|
||||
#include "SysYParser.h"
|
||||
#include "ir/IR.h"
|
||||
#include "utils/Log.h"
|
||||
|
||||
ir::Value* IRGenImpl::GenExpr(SysYParser::ExpContext& expr) {
|
||||
if (!expr.addExp()) {
|
||||
throw std::runtime_error("[irgen] 非法表达式");
|
||||
throw std::runtime_error(FormatError("irgen", "非法表达式"));
|
||||
}
|
||||
return GenAddExpr(*expr.addExp());
|
||||
}
|
||||
@@ -16,7 +17,7 @@ ir::Value* IRGenImpl::GenAddExpr(SysYParser::AddExpContext& add) {
|
||||
// 当前表达式层次仍是最小实现,直接贴合 addExp -> primary 的语法形状。
|
||||
const auto& terms = add.primary();
|
||||
if (terms.empty()) {
|
||||
throw std::runtime_error("[irgen] 空加法表达式");
|
||||
throw std::runtime_error(FormatError("irgen", "空加法表达式"));
|
||||
}
|
||||
|
||||
ir::Value* acc = GenPrimary(*terms[0]);
|
||||
@@ -35,18 +36,20 @@ ir::Value* IRGenImpl::GenPrimary(SysYParser::PrimaryContext& primary) {
|
||||
if (primary.Ident()) {
|
||||
auto* decl = sema_.ResolveVarUse(&primary);
|
||||
if (!decl) {
|
||||
throw std::runtime_error("[irgen] 变量使用缺少语义绑定: " +
|
||||
primary.Ident()->getText());
|
||||
throw std::runtime_error(
|
||||
FormatError("irgen",
|
||||
"变量使用缺少语义绑定: " + primary.Ident()->getText()));
|
||||
}
|
||||
auto it = storage_map_.find(decl);
|
||||
if (it == storage_map_.end()) {
|
||||
throw std::runtime_error("[irgen] 变量声明缺少存储槽位: " +
|
||||
primary.Ident()->getText());
|
||||
throw std::runtime_error(
|
||||
FormatError("irgen",
|
||||
"变量声明缺少存储槽位: " + primary.Ident()->getText()));
|
||||
}
|
||||
return builder_.CreateLoad(it->second, module_.context().NextTemp());
|
||||
}
|
||||
if (primary.exp()) {
|
||||
return GenExpr(*primary.exp());
|
||||
}
|
||||
throw std::runtime_error("[irgen] 暂不支持的 primary 形式");
|
||||
throw std::runtime_error(FormatError("irgen", "暂不支持的表达式形式"));
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include "SysYParser.h"
|
||||
#include "ir/IR.h"
|
||||
#include "utils/Log.h"
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -11,8 +12,9 @@ void VerifyFunctionStructure(const ir::Function& func) {
|
||||
// 当前 IRGen 仍是单入口、顺序生成;这里在生成结束后补一层块终结校验。
|
||||
for (const auto& bb : func.blocks()) {
|
||||
if (!bb || !bb->HasTerminator()) {
|
||||
throw std::runtime_error("[irgen] 基本块未正确终结: " +
|
||||
(bb ? bb->name() : std::string("<null>")));
|
||||
throw std::runtime_error(
|
||||
FormatError("irgen", "基本块未正确终结: " +
|
||||
(bb ? bb->name() : std::string("<null>"))));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,17 +29,17 @@ IRGenImpl::IRGenImpl(ir::Module& module, const SemanticContext& sema)
|
||||
|
||||
void IRGenImpl::Gen(SysYParser::CompUnitContext& cu) {
|
||||
if (!cu.funcDef()) {
|
||||
throw std::runtime_error("[irgen] 缺少 main 定义");
|
||||
throw std::runtime_error(FormatError("irgen", "缺少 main 定义"));
|
||||
}
|
||||
GenFuncDef(*cu.funcDef());
|
||||
}
|
||||
|
||||
void IRGenImpl::GenFuncDef(SysYParser::FuncDefContext& func) {
|
||||
if (!func.block()) {
|
||||
throw std::runtime_error("[irgen] 函数体为空");
|
||||
throw std::runtime_error(FormatError("irgen", "函数体为空"));
|
||||
}
|
||||
if (!func.Ident()) {
|
||||
throw std::runtime_error("[irgen] 缺少函数名");
|
||||
throw std::runtime_error(FormatError("irgen", "缺少函数名"));
|
||||
}
|
||||
|
||||
func_ = module_.CreateFunction(
|
||||
|
||||
@@ -4,18 +4,19 @@
|
||||
|
||||
#include "SysYParser.h"
|
||||
#include "ir/IR.h"
|
||||
#include "utils/Log.h"
|
||||
|
||||
bool IRGenImpl::GenStmt(SysYParser::StmtContext& stmt) {
|
||||
if (stmt.returnStmt()) {
|
||||
GenReturnStmt(*stmt.returnStmt());
|
||||
return true;
|
||||
}
|
||||
throw std::runtime_error("[irgen] 暂不支持的语句类型");
|
||||
throw std::runtime_error(FormatError("irgen", "暂不支持的语句类型"));
|
||||
}
|
||||
|
||||
void IRGenImpl::GenReturnStmt(SysYParser::ReturnStmtContext& ret) {
|
||||
if (!ret.exp()) {
|
||||
throw std::runtime_error("[irgen] return 缺少表达式");
|
||||
throw std::runtime_error(FormatError("irgen", "return 缺少表达式"));
|
||||
}
|
||||
ir::Value* v = GenExpr(*ret.exp());
|
||||
builder_.CreateRet(v);
|
||||
|
||||
@@ -28,7 +28,7 @@ int main(int argc, char** argv) {
|
||||
|
||||
auto* comp_unit = dynamic_cast<SysYParser::CompUnitContext*>(antlr.tree);
|
||||
if (!comp_unit) {
|
||||
throw std::runtime_error("[main] 语法树根节点不是 compUnit");
|
||||
throw std::runtime_error(FormatError("main", "语法树根节点不是 compUnit"));
|
||||
}
|
||||
auto sema = RunSema(*comp_unit);
|
||||
|
||||
@@ -52,7 +52,7 @@ int main(int argc, char** argv) {
|
||||
mir::PrintAsm(*machine_func, std::cout);
|
||||
}
|
||||
} catch (const std::exception& ex) {
|
||||
std::cerr << "error: " << ex.what() << "\n";
|
||||
PrintException(std::cerr, ex);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
|
||||
#include "utils/Log.h"
|
||||
|
||||
namespace mir {
|
||||
namespace {
|
||||
|
||||
@@ -17,8 +19,7 @@ void RunFrameLowering(MachineFunction& function) {
|
||||
for (const auto& slot : function.frame_slots()) {
|
||||
cursor += slot.size;
|
||||
if (-cursor < -256) {
|
||||
throw std::runtime_error(
|
||||
"Lab3 MVP 后端暂不支持超过 64 个 i32 栈槽的函数");
|
||||
throw std::runtime_error(FormatError("mir", "暂不支持过大的栈帧"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <unordered_map>
|
||||
|
||||
#include "ir/IR.h"
|
||||
#include "utils/Log.h"
|
||||
|
||||
namespace mir {
|
||||
namespace {
|
||||
@@ -20,8 +21,8 @@ void EmitValueToReg(const ir::Value* value, PhysReg target,
|
||||
|
||||
auto it = slots.find(value);
|
||||
if (it == slots.end()) {
|
||||
throw std::runtime_error("Lab3 MVP 后端找不到值对应的栈槽: " +
|
||||
value->name());
|
||||
throw std::runtime_error(
|
||||
FormatError("mir", "找不到值对应的栈槽: " + value->name()));
|
||||
}
|
||||
|
||||
block.Append(Opcode::LoadStack,
|
||||
@@ -41,7 +42,8 @@ void LowerInstruction(const ir::Instruction& inst, MachineFunction& function,
|
||||
auto& store = static_cast<const ir::StoreInst&>(inst);
|
||||
auto dst = slots.find(store.ptr());
|
||||
if (dst == slots.end()) {
|
||||
throw std::runtime_error("Lab3 MVP 后端要求 store 目标必须来自 alloca");
|
||||
throw std::runtime_error(
|
||||
FormatError("mir", "暂不支持对非栈变量地址进行写入"));
|
||||
}
|
||||
EmitValueToReg(store.value(), PhysReg::W8, slots, block);
|
||||
block.Append(Opcode::StoreStack,
|
||||
@@ -52,7 +54,8 @@ void LowerInstruction(const ir::Instruction& inst, MachineFunction& function,
|
||||
auto& load = static_cast<const ir::LoadInst&>(inst);
|
||||
auto src = slots.find(load.ptr());
|
||||
if (src == slots.end()) {
|
||||
throw std::runtime_error("Lab3 MVP 后端要求 load 源必须来自 alloca");
|
||||
throw std::runtime_error(
|
||||
FormatError("mir", "暂不支持对非栈变量地址进行读取"));
|
||||
}
|
||||
int dst_slot = function.CreateFrameIndex();
|
||||
block.Append(Opcode::LoadStack,
|
||||
@@ -83,10 +86,10 @@ void LowerInstruction(const ir::Instruction& inst, MachineFunction& function,
|
||||
}
|
||||
case ir::Opcode::Sub:
|
||||
case ir::Opcode::Mul:
|
||||
throw std::runtime_error("Lab3 MVP 后端暂不支持 add 以外的二元运算");
|
||||
throw std::runtime_error(FormatError("mir", "暂不支持该二元运算"));
|
||||
}
|
||||
|
||||
throw std::runtime_error("Lab3 MVP 后端遇到未知 IR 指令");
|
||||
throw std::runtime_error(FormatError("mir", "暂不支持该 IR 指令"));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@@ -95,19 +98,19 @@ std::unique_ptr<MachineFunction> LowerToMIR(const ir::Module& module) {
|
||||
DefaultContext();
|
||||
|
||||
if (module.functions().size() != 1) {
|
||||
throw std::runtime_error("Lab3 MVP 后端只支持单函数 main");
|
||||
throw std::runtime_error(FormatError("mir", "暂不支持多个函数"));
|
||||
}
|
||||
|
||||
const auto& func = *module.functions().front();
|
||||
if (func.name() != "main") {
|
||||
throw std::runtime_error("Lab3 MVP 后端只支持 main 函数");
|
||||
throw std::runtime_error(FormatError("mir", "暂不支持非 main 函数"));
|
||||
}
|
||||
|
||||
auto machine_func = std::make_unique<MachineFunction>(func.name());
|
||||
ValueSlotMap slots;
|
||||
const auto* entry = func.entry();
|
||||
if (!entry) {
|
||||
throw std::runtime_error("IR 函数缺少入口基本块");
|
||||
throw std::runtime_error(FormatError("mir", "IR 函数缺少入口基本块"));
|
||||
}
|
||||
|
||||
for (const auto& inst : entry->instructions()) {
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include "utils/Log.h"
|
||||
|
||||
namespace mir {
|
||||
namespace {
|
||||
|
||||
@@ -24,7 +26,7 @@ void RunRegAlloc(MachineFunction& function) {
|
||||
for (const auto& inst : function.entry().instructions()) {
|
||||
for (const auto& operand : inst.operands()) {
|
||||
if (operand.kind() == Operand::Kind::Reg && !IsAllowedReg(operand.reg())) {
|
||||
throw std::runtime_error("Lab3 MVP 后端发现未预着色的寄存器");
|
||||
throw std::runtime_error(FormatError("mir", "寄存器分配失败"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <string>
|
||||
|
||||
#include "sem/SymbolTable.h"
|
||||
#include "utils/Log.h"
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -20,7 +21,7 @@ void CheckPrimary(SysYParser::PrimaryContext& primary,
|
||||
const std::string name = primary.Ident()->getText();
|
||||
auto* decl = table.Lookup(name);
|
||||
if (!decl) {
|
||||
throw std::runtime_error("[sema] 使用了未定义的变量: " + name);
|
||||
throw std::runtime_error(FormatError("sema", "使用了未定义的变量: " + name));
|
||||
}
|
||||
sema.BindVarUse(&primary, decl);
|
||||
return;
|
||||
@@ -31,13 +32,13 @@ void CheckPrimary(SysYParser::PrimaryContext& primary,
|
||||
return;
|
||||
}
|
||||
|
||||
throw std::runtime_error("[sema] 暂不支持的 primary 形式");
|
||||
throw std::runtime_error(FormatError("sema", "暂不支持的表达式形式"));
|
||||
}
|
||||
|
||||
void CheckExpr(SysYParser::ExpContext& exp, const SymbolTable& table,
|
||||
SemanticContext& sema) {
|
||||
if (!exp.addExp()) {
|
||||
throw std::runtime_error("[sema] 非法表达式");
|
||||
throw std::runtime_error(FormatError("sema", "非法表达式"));
|
||||
}
|
||||
const auto& terms = exp.addExp()->primary();
|
||||
for (auto* term : terms) {
|
||||
@@ -50,10 +51,10 @@ void CheckExpr(SysYParser::ExpContext& exp, const SymbolTable& table,
|
||||
SemanticContext RunSema(SysYParser::CompUnitContext& comp_unit) {
|
||||
auto* func = comp_unit.funcDef();
|
||||
if (!func || !func->block()) {
|
||||
throw std::runtime_error("[sema] 缺少 main 函数定义");
|
||||
throw std::runtime_error(FormatError("sema", "缺少 main 函数定义"));
|
||||
}
|
||||
if (!func->Ident() || func->Ident()->getText() != "main") {
|
||||
throw std::runtime_error("[sema] 入口函数必须命名为 main");
|
||||
throw std::runtime_error(FormatError("sema", "入口函数必须命名为 main"));
|
||||
}
|
||||
|
||||
SymbolTable table;
|
||||
@@ -62,7 +63,8 @@ SemanticContext RunSema(SysYParser::CompUnitContext& comp_unit) {
|
||||
|
||||
const auto& items = func->block()->blockItem();
|
||||
if (items.empty()) {
|
||||
throw std::runtime_error("[sema] main 函数不能为空,且必须以 return 结束");
|
||||
throw std::runtime_error(
|
||||
FormatError("sema", "main 函数不能为空,且必须以 return 结束"));
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < items.size(); ++i) {
|
||||
@@ -71,12 +73,13 @@ SemanticContext RunSema(SysYParser::CompUnitContext& comp_unit) {
|
||||
continue;
|
||||
}
|
||||
if (seen_return) {
|
||||
throw std::runtime_error("[sema] return 必须是 main 函数中的最后一条语句");
|
||||
throw std::runtime_error(
|
||||
FormatError("sema", "return 必须是 main 函数中的最后一条语句"));
|
||||
}
|
||||
if (auto* decl = item->decl() ? item->decl()->varDecl() : nullptr) {
|
||||
const std::string name = decl->Ident()->getText();
|
||||
if (table.Contains(name)) {
|
||||
throw std::runtime_error("[sema] 重复定义变量: " + name);
|
||||
throw std::runtime_error(FormatError("sema", "重复定义变量: " + name));
|
||||
}
|
||||
if (decl->exp()) {
|
||||
CheckExpr(*decl->exp(), table, sema);
|
||||
@@ -89,15 +92,16 @@ SemanticContext RunSema(SysYParser::CompUnitContext& comp_unit) {
|
||||
CheckExpr(*ret->exp(), table, sema);
|
||||
seen_return = true;
|
||||
if (i + 1 != items.size()) {
|
||||
throw std::runtime_error("[sema] return 必须是 main 函数中的最后一条语句");
|
||||
throw std::runtime_error(
|
||||
FormatError("sema", "return 必须是 main 函数中的最后一条语句"));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
throw std::runtime_error("[sema] 暂不支持的 blockItem 类型");
|
||||
throw std::runtime_error(FormatError("sema", "暂不支持的语句或声明"));
|
||||
}
|
||||
|
||||
if (!seen_return) {
|
||||
throw std::runtime_error("[sema] main 函数必须包含 return 语句");
|
||||
throw std::runtime_error(FormatError("sema", "main 函数必须包含 return 语句"));
|
||||
}
|
||||
|
||||
return sema;
|
||||
|
||||
@@ -5,17 +5,20 @@
|
||||
|
||||
#include "utils/CLI.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
|
||||
#include "utils/Log.h"
|
||||
|
||||
CLIOptions ParseCLI(int argc, char** argv) {
|
||||
CLIOptions opt;
|
||||
bool explicit_emit = false;
|
||||
|
||||
if (argc <= 1) {
|
||||
throw std::runtime_error(
|
||||
"用法: compiler [--help] [--emit-parse-tree] [--emit-ir] [--emit-asm] <input.sy>");
|
||||
throw std::runtime_error(FormatError(
|
||||
"cli",
|
||||
"用法: compiler [--help] [--emit-parse-tree] [--emit-ir] [--emit-asm] <input.sy>"));
|
||||
}
|
||||
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
@@ -59,23 +62,25 @@ CLIOptions ParseCLI(int argc, char** argv) {
|
||||
}
|
||||
|
||||
if (arg[0] == '-') {
|
||||
throw std::runtime_error(std::string("未知参数: ") + arg +
|
||||
"(使用 --help 查看用法)");
|
||||
throw std::runtime_error(
|
||||
FormatError("cli", std::string("未知参数: ") + arg +
|
||||
"(使用 --help 查看用法)"));
|
||||
}
|
||||
|
||||
if (!opt.input.empty()) {
|
||||
throw std::runtime_error(
|
||||
"参数过多:当前只支持 1 个输入文件(使用 --help 查看用法)");
|
||||
throw std::runtime_error(FormatError(
|
||||
"cli", "参数过多:当前只支持 1 个输入文件(使用 --help 查看用法)"));
|
||||
}
|
||||
opt.input = arg;
|
||||
}
|
||||
|
||||
if (opt.input.empty() && !opt.show_help) {
|
||||
throw std::runtime_error("缺少输入文件:请提供 <input.sy>(使用 --help 查看用法)");
|
||||
throw std::runtime_error(
|
||||
FormatError("cli", "缺少输入文件:请提供 <input.sy>(使用 --help 查看用法)"));
|
||||
}
|
||||
if (!opt.emit_parse_tree && !opt.emit_ir && !opt.emit_asm) {
|
||||
throw std::runtime_error(
|
||||
"未选择任何输出:请使用 --emit-parse-tree / --emit-ir / --emit-asm");
|
||||
throw std::runtime_error(FormatError(
|
||||
"cli", "未选择任何输出:请使用 --emit-parse-tree / --emit-ir / --emit-asm"));
|
||||
}
|
||||
return opt;
|
||||
}
|
||||
|
||||
@@ -5,6 +5,48 @@
|
||||
#include "utils/Log.h"
|
||||
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
|
||||
namespace {
|
||||
|
||||
bool IsCLIError(const std::string_view msg) {
|
||||
return HasErrorPrefix(msg, "cli");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void LogInfo(const std::string_view msg, std::ostream& os) {
|
||||
os << "[info] " << msg << "\n";
|
||||
}
|
||||
|
||||
void LogError(const std::string_view msg, std::ostream& os) {
|
||||
os << "[error] " << msg << "\n";
|
||||
}
|
||||
|
||||
std::string FormatError(const std::string_view stage,
|
||||
const std::string_view msg) {
|
||||
return "[" + std::string(stage) + "] " + std::string(msg);
|
||||
}
|
||||
|
||||
std::string FormatErrorAt(const std::string_view stage, const std::size_t line,
|
||||
const std::size_t column,
|
||||
const std::string_view msg) {
|
||||
return "[" + std::string(stage) + "] @" + std::to_string(line) + ":" +
|
||||
std::to_string(column) + " - " + std::string(msg);
|
||||
}
|
||||
|
||||
bool HasErrorPrefix(const std::string_view msg, const std::string_view stage) {
|
||||
const std::string prefix = "[" + std::string(stage) + "]";
|
||||
return msg.rfind(prefix, 0) == 0;
|
||||
}
|
||||
|
||||
void PrintException(std::ostream& os, const std::exception& ex) {
|
||||
LogError(ex.what(), os);
|
||||
if (IsCLIError(ex.what())) {
|
||||
os << "\n";
|
||||
PrintHelp(os);
|
||||
}
|
||||
}
|
||||
|
||||
void PrintHelp(std::ostream& os) {
|
||||
os << "SysY Compiler (课程实验最小可运行示例)\n"
|
||||
|
||||
@@ -1,11 +1,20 @@
|
||||
// 轻量日志接口。
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <exception>
|
||||
#include <iosfwd>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#define LOG_INFO(msg) std::cerr << "[info] " << msg << "\n"
|
||||
#define LOG_ERROR(msg) std::cerr << "[error] " << msg << "\n"
|
||||
void LogInfo(std::string_view msg, std::ostream& os);
|
||||
void LogError(std::string_view msg, std::ostream& os);
|
||||
|
||||
std::string FormatError(std::string_view stage, std::string_view msg);
|
||||
std::string FormatErrorAt(std::string_view stage, std::size_t line,
|
||||
std::size_t column, std::string_view msg);
|
||||
bool HasErrorPrefix(std::string_view msg, std::string_view stage);
|
||||
void PrintException(std::ostream& os, const std::exception& ex);
|
||||
|
||||
// 打印命令行帮助信息(用于 `compiler --help`)。
|
||||
void PrintHelp(std::ostream& os);
|
||||
|
||||
Reference in New Issue
Block a user