refactor(dev): unify compiler error logging
This commit is contained in:
@@ -9,20 +9,17 @@
|
|||||||
#include "SysYLexer.h"
|
#include "SysYLexer.h"
|
||||||
#include "SysYParser.h"
|
#include "SysYParser.h"
|
||||||
#include "antlr4-runtime.h"
|
#include "antlr4-runtime.h"
|
||||||
|
#include "utils/Log.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
bool HasParsePrefix(const std::string& msg) {
|
|
||||||
return msg.rfind("[parse]", 0) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
class ParseErrorListener : public antlr4::BaseErrorListener {
|
class ParseErrorListener : public antlr4::BaseErrorListener {
|
||||||
public:
|
public:
|
||||||
void syntaxError(antlr4::Recognizer* /*recognizer*/, antlr4::Token* /*offendingSymbol*/,
|
void syntaxError(antlr4::Recognizer* /*recognizer*/, antlr4::Token* /*offendingSymbol*/,
|
||||||
size_t line, size_t charPositionInLine,
|
size_t line, size_t charPositionInLine,
|
||||||
const std::string& msg, std::exception_ptr /*e*/) override {
|
const std::string& msg, std::exception_ptr /*e*/) override {
|
||||||
throw std::runtime_error("[parse] 暂不支持的语法/词法 @" + std::to_string(line) + ":" +
|
throw std::runtime_error(FormatErrorAt("parse", line, charPositionInLine,
|
||||||
std::to_string(charPositionInLine) + " - " + msg);
|
"暂不支持的语法/词法 - " + msg));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -31,7 +28,7 @@ class ParseErrorListener : public antlr4::BaseErrorListener {
|
|||||||
AntlrResult ParseFileWithAntlr(const std::string& path) {
|
AntlrResult ParseFileWithAntlr(const std::string& path) {
|
||||||
std::ifstream fin(path);
|
std::ifstream fin(path);
|
||||||
if (!fin.is_open()) {
|
if (!fin.is_open()) {
|
||||||
throw std::runtime_error("[parse] 无法打开输入文件: " + path);
|
throw std::runtime_error(FormatError("parse", "无法打开输入文件: " + path));
|
||||||
}
|
}
|
||||||
std::ostringstream ss;
|
std::ostringstream ss;
|
||||||
ss << fin.rdbuf();
|
ss << fin.rdbuf();
|
||||||
@@ -53,18 +50,18 @@ AntlrResult ParseFileWithAntlr(const std::string& path) {
|
|||||||
} catch (const std::exception& ex) {
|
} catch (const std::exception& ex) {
|
||||||
const std::string msg = ex.what();
|
const std::string msg = ex.what();
|
||||||
if (!msg.empty()) {
|
if (!msg.empty()) {
|
||||||
if (HasParsePrefix(msg)) {
|
if (HasErrorPrefix(msg, "parse")) {
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
throw std::runtime_error("[parse] 暂不支持的语法/词法 - " + msg);
|
throw std::runtime_error(
|
||||||
|
FormatError("parse", "暂不支持的语法/词法 - " + msg));
|
||||||
}
|
}
|
||||||
if (auto* tok = parser->getCurrentToken()) {
|
if (auto* tok = parser->getCurrentToken()) {
|
||||||
throw std::runtime_error("[parse] 暂不支持的语法/词法 @" +
|
throw std::runtime_error(
|
||||||
std::to_string(tok->getLine()) + ":" +
|
FormatErrorAt("parse", tok->getLine(), tok->getCharPositionInLine(),
|
||||||
std::to_string(tok->getCharPositionInLine()) +
|
"暂不支持的语法/词法 near token '" + tok->getText() + "'"));
|
||||||
" near token '" + tok->getText() + "'");
|
|
||||||
}
|
}
|
||||||
throw std::runtime_error("[parse] 暂不支持的语法/词法");
|
throw std::runtime_error(FormatError("parse", "暂不支持的语法/词法"));
|
||||||
}
|
}
|
||||||
|
|
||||||
AntlrResult result;
|
AntlrResult result;
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ int main(int argc, char** argv) {
|
|||||||
mir::PrintAsm(*machine_func, std::cout);
|
mir::PrintAsm(*machine_func, std::cout);
|
||||||
}
|
}
|
||||||
} catch (const std::exception& ex) {
|
} catch (const std::exception& ex) {
|
||||||
std::cerr << "error: " << ex.what() << "\n";
|
PrintException(std::cerr, ex);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -5,17 +5,20 @@
|
|||||||
|
|
||||||
#include "utils/CLI.h"
|
#include "utils/CLI.h"
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <cstring>
|
|
||||||
|
#include "utils/Log.h"
|
||||||
|
|
||||||
CLIOptions ParseCLI(int argc, char** argv) {
|
CLIOptions ParseCLI(int argc, char** argv) {
|
||||||
CLIOptions opt;
|
CLIOptions opt;
|
||||||
bool explicit_emit = false;
|
bool explicit_emit = false;
|
||||||
|
|
||||||
if (argc <= 1) {
|
if (argc <= 1) {
|
||||||
throw std::runtime_error(
|
throw std::runtime_error(FormatError(
|
||||||
"用法: compiler [--help] [--emit-parse-tree] [--emit-ir] [--emit-asm] <input.sy>");
|
"cli",
|
||||||
|
"用法: compiler [--help] [--emit-parse-tree] [--emit-ir] [--emit-asm] <input.sy>"));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 1; i < argc; ++i) {
|
for (int i = 1; i < argc; ++i) {
|
||||||
@@ -59,23 +62,25 @@ CLIOptions ParseCLI(int argc, char** argv) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (arg[0] == '-') {
|
if (arg[0] == '-') {
|
||||||
throw std::runtime_error(std::string("未知参数: ") + arg +
|
throw std::runtime_error(
|
||||||
"(使用 --help 查看用法)");
|
FormatError("cli", std::string("未知参数: ") + arg +
|
||||||
|
"(使用 --help 查看用法)"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!opt.input.empty()) {
|
if (!opt.input.empty()) {
|
||||||
throw std::runtime_error(
|
throw std::runtime_error(FormatError(
|
||||||
"参数过多:当前只支持 1 个输入文件(使用 --help 查看用法)");
|
"cli", "参数过多:当前只支持 1 个输入文件(使用 --help 查看用法)"));
|
||||||
}
|
}
|
||||||
opt.input = arg;
|
opt.input = arg;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opt.input.empty() && !opt.show_help) {
|
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) {
|
if (!opt.emit_parse_tree && !opt.emit_ir && !opt.emit_asm) {
|
||||||
throw std::runtime_error(
|
throw std::runtime_error(FormatError(
|
||||||
"未选择任何输出:请使用 --emit-parse-tree / --emit-ir / --emit-asm");
|
"cli", "未选择任何输出:请使用 --emit-parse-tree / --emit-ir / --emit-asm"));
|
||||||
}
|
}
|
||||||
return opt;
|
return opt;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,48 @@
|
|||||||
#include "utils/Log.h"
|
#include "utils/Log.h"
|
||||||
|
|
||||||
#include <ostream>
|
#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) {
|
void PrintHelp(std::ostream& os) {
|
||||||
os << "SysY Compiler (课程实验最小可运行示例)\n"
|
os << "SysY Compiler (课程实验最小可运行示例)\n"
|
||||||
|
|||||||
@@ -1,11 +1,20 @@
|
|||||||
// 轻量日志接口。
|
// 轻量日志接口。
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <exception>
|
||||||
#include <iosfwd>
|
#include <iosfwd>
|
||||||
#include <iostream>
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
#define LOG_INFO(msg) std::cerr << "[info] " << msg << "\n"
|
void LogInfo(std::string_view msg, std::ostream& os);
|
||||||
#define LOG_ERROR(msg) std::cerr << "[error] " << msg << "\n"
|
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`)。
|
// 打印命令行帮助信息(用于 `compiler --help`)。
|
||||||
void PrintHelp(std::ostream& os);
|
void PrintHelp(std::ostream& os);
|
||||||
|
|||||||
Reference in New Issue
Block a user