diff --git a/src/frontend/AntlrDriver.cpp b/src/frontend/AntlrDriver.cpp index 6a93e90..ee3c98c 100644 --- a/src/frontend/AntlrDriver.cpp +++ b/src/frontend/AntlrDriver.cpp @@ -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; diff --git a/src/main.cpp b/src/main.cpp index da355f6..fafc646 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -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; diff --git a/src/utils/CLI.cpp b/src/utils/CLI.cpp index 571750e..da8c2ba 100644 --- a/src/utils/CLI.cpp +++ b/src/utils/CLI.cpp @@ -5,17 +5,20 @@ #include "utils/CLI.h" +#include #include #include -#include + +#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] "); + throw std::runtime_error(FormatError( + "cli", + "用法: compiler [--help] [--emit-parse-tree] [--emit-ir] [--emit-asm] ")); } 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("缺少输入文件:请提供 (使用 --help 查看用法)"); + throw std::runtime_error( + FormatError("cli", "缺少输入文件:请提供 (使用 --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; } diff --git a/src/utils/Log.cpp b/src/utils/Log.cpp index 6f32e80..f5852f8 100644 --- a/src/utils/Log.cpp +++ b/src/utils/Log.cpp @@ -5,6 +5,48 @@ #include "utils/Log.h" #include +#include + +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" diff --git a/src/utils/Log.h b/src/utils/Log.h index ac15b2c..303f1a1 100644 --- a/src/utils/Log.h +++ b/src/utils/Log.h @@ -1,11 +1,20 @@ // 轻量日志接口。 #pragma once +#include +#include #include -#include +#include +#include -#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);