From a3b5018a170cb8c6d3c2f50907dd2aeb3e87789f Mon Sep 17 00:00:00 2001 From: Lane0218 Date: Wed, 11 Mar 2026 21:06:27 +0800 Subject: [PATCH 1/5] =?UTF-8?q?refactor(test):=20=E7=AE=80=E5=8C=96?= =?UTF-8?q?=E9=AA=8C=E8=AF=81=E8=84=9A=E6=9C=AC=E5=91=BD=E5=90=8D=E5=B9=B6?= =?UTF-8?q?=E7=BB=9F=E4=B8=80=E6=B5=8B=E8=AF=95=E8=BE=93=E5=87=BA=E7=9B=AE?= =?UTF-8?q?=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 ++-- doc/Lab2-中间表示生成.md | 2 +- doc/Lab3-指令选择与汇编生成.md | 4 ++-- doc/Lab4-寄存器分配.md | 4 ++-- doc/Lab5-基本标量优化.md | 4 ++-- doc/Lab6-并行与循环优化.md | 6 ++---- scripts/{verify_asm_with_qemu.sh => verify_asm.sh} | 4 ++-- scripts/{verify_ir_with_llvm.sh => verify_ir.sh} | 6 +++--- 8 files changed, 16 insertions(+), 18 deletions(-) rename scripts/{verify_asm_with_qemu.sh => verify_asm.sh} (96%) rename scripts/{verify_ir_with_llvm.sh => verify_ir.sh} (91%) diff --git a/README.md b/README.md index 896f5a5..b59a4f0 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ sudo apt install -y build-essential cmake git openjdk-11-jre ### 2.3 安装 LLVM 工具链 -`scripts/verify_ir_with_llvm.sh` 在 `--run` 模式下会调用 LLVM 工具链(`llc` 与 `clang`)将生成的 IR 编译并运行。 +`scripts/verify_ir.sh` 在 `--run` 模式下会调用 LLVM 工具链(`llc` 与 `clang`)将生成的 IR 编译并运行。 ```bash sudo apt update @@ -91,7 +91,7 @@ cmake --build build -j "$(nproc)" 跑完整编译流程自检:从 SysY 源码生成 AArch64 汇编,完成汇编、链接,并在 QEMU 下运行结果程序: ```bash -./scripts/verify_asm_with_qemu.sh test/test_case/simple_add.sy out/asm --run +./scripts/verify_asm.sh test/test_case/simple_add.sy test/test_result/asm --run ``` 如果最终看到 `退出码: 3`,说明当前最小子集示例 `return a + b` 的完整链路已经跑通。 diff --git a/doc/Lab2-中间表示生成.md b/doc/Lab2-中间表示生成.md index 9da0950..d358b43 100644 --- a/doc/Lab2-中间表示生成.md +++ b/doc/Lab2-中间表示生成.md @@ -85,5 +85,5 @@ cmake --build build -j "$(nproc)" ```bash -./scripts/verify_ir_with_llvm.sh test/test_case/simple_add.sy out/ir --run +./scripts/verify_ir.sh test/test_case/simple_add.sy test/test_result/ir --run ``` diff --git a/doc/Lab3-指令选择与汇编生成.md b/doc/Lab3-指令选择与汇编生成.md index f0ec7ac..5f9623f 100644 --- a/doc/Lab3-指令选择与汇编生成.md +++ b/doc/Lab3-指令选择与汇编生成.md @@ -49,7 +49,7 @@ Lab3 的目标是在该示例基础上扩展后端语义覆盖范围,逐步把 2. 视实现需要可能修改 - `src/main.cpp`(当需要调整输出阶段行为时) - `src/utils/CLI.cpp`(当需要扩展后端相关命令行选项时) - - `scripts/verify_asm_with_qemu.sh`(当需要扩展统一验证脚本时) + - `scripts/verify_asm.sh`(当需要扩展统一验证脚本时) ## 5. 当前最小示例实现说明 @@ -82,7 +82,7 @@ cmake --build build -j "$(nproc)" 推荐使用统一脚本验证 “源码 -> 汇编 -> 可执行程序” 整体链路,用于验证后端代码生成的正确性: ```bash -./scripts/verify_asm_with_qemu.sh test/test_case/simple_add.sy out/asm --run +./scripts/verify_asm.sh test/test_case/simple_add.sy test/test_result/asm --run ``` 若最终输出 `退出码: 3`,说明当前最小子集示例 `return a + b` 的完整后端链路已经跑通。 diff --git a/doc/Lab4-寄存器分配.md b/doc/Lab4-寄存器分配.md index 125c495..b4ce88f 100644 --- a/doc/Lab4-寄存器分配.md +++ b/doc/Lab4-寄存器分配.md @@ -61,7 +61,7 @@ Lab4 的目标是在 Lab3 示例基础上,把“固定寄存器 + 栈槽”的 - `src/mir/MIRBasicBlock.cpp`(当需要扩展基本块级活跃性或辅助接口时) - `src/main.cpp`(当需要调整后端阶段行为时) - `src/utils/CLI.cpp`(当需要扩展后端调试相关命令行选项时) - - `scripts/verify_asm_with_qemu.sh`(当需要扩展统一验证脚本时) + - `scripts/verify_asm.sh`(当需要扩展统一验证脚本时) ## 5. 当前最小示例实现说明 @@ -138,7 +138,7 @@ cmake --build build -j "$(nproc)" 推荐继续使用统一脚本验证 “源码 -> 汇编 -> 可执行程序” 整体链路,用于做最小回归: ```bash -./scripts/verify_asm_with_qemu.sh test/test_case/simple_add.sy out/asm --run +./scripts/verify_asm.sh test/test_case/simple_add.sy test/test_result/asm --run ``` 建议在功能回归之外,再观察优化前后汇编输出差异。可按自己的实现方式保留调试日志、优化开关,或直接对比生成的汇编文本,重点关注: diff --git a/doc/Lab5-基本标量优化.md b/doc/Lab5-基本标量优化.md index 643c4cc..bb71eec 100644 --- a/doc/Lab5-基本标量优化.md +++ b/doc/Lab5-基本标量优化.md @@ -210,8 +210,8 @@ cmake --build build -j "$(nproc)" ### 8.2 语义回归 ```bash -./scripts/verify_ir_with_llvm.sh test/test_case/simple_add.sy out/ir --run -./scripts/verify_asm_with_qemu.sh test/test_case/simple_add.sy out/asm --run +./scripts/verify_ir.sh test/test_case/simple_add.sy test/test_result/ir --run +./scripts/verify_asm.sh test/test_case/simple_add.sy test/test_result/asm --run ``` 目标:优化后程序行为与优化前保持一致。 diff --git a/doc/Lab6-并行与循环优化.md b/doc/Lab6-并行与循环优化.md index aca7b60..ef86ed9 100644 --- a/doc/Lab6-并行与循环优化.md +++ b/doc/Lab6-并行与循环优化.md @@ -157,8 +157,8 @@ cmake --build build -j "$(nproc)" ### 9.1 功能回归 ```bash -./scripts/verify_ir_with_llvm.sh test/test_case/simple_add.sy out/ir --run -./scripts/verify_asm_with_qemu.sh test/test_case/simple_add.sy out/asm --run +./scripts/verify_ir.sh test/test_case/simple_add.sy test/test_result/ir --run +./scripts/verify_asm.sh test/test_case/simple_add.sy test/test_result/asm --run ``` ### 9.2 优化效果对比(示例) @@ -170,5 +170,3 @@ cmake --build build -j "$(nproc)" ``` --- - - diff --git a/scripts/verify_asm_with_qemu.sh b/scripts/verify_asm.sh similarity index 96% rename from scripts/verify_asm_with_qemu.sh rename to scripts/verify_asm.sh index f50744b..3bfeb23 100755 --- a/scripts/verify_asm_with_qemu.sh +++ b/scripts/verify_asm.sh @@ -8,7 +8,7 @@ if [[ $# -lt 1 || $# -gt 3 ]]; then fi input=$1 -out_dir="out/asm" +out_dir="test/test_result/asm" run_exec=false shift @@ -44,7 +44,7 @@ mkdir -p "$out_dir" base=$(basename "$input") stem=${base%.sy} asm_file="$out_dir/$stem.s" -exe="$out_dir/$stem.exe" +exe="$out_dir/$stem" "$compiler" --emit-asm "$input" > "$asm_file" echo "汇编已生成: $asm_file" diff --git a/scripts/verify_ir_with_llvm.sh b/scripts/verify_ir.sh similarity index 91% rename from scripts/verify_ir_with_llvm.sh rename to scripts/verify_ir.sh index 830982a..2674e54 100755 --- a/scripts/verify_ir_with_llvm.sh +++ b/scripts/verify_ir.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash -# ./scripts/verify_ir_with_llvm.sh test/test_case/simple_add.sy --run +# ./scripts/verify_ir.sh test/test_case/simple_add.sy --run set -euo pipefail @@ -9,7 +9,7 @@ if [[ $# -lt 1 || $# -gt 3 ]]; then fi input=$1 -out_dir="out/ir" +out_dir="test/test_result/ir" run_exec=false shift @@ -53,7 +53,7 @@ if [[ "$run_exec" == true ]]; then exit 1 fi obj="$out_dir/$stem.o" - exe="$out_dir/$stem.exe" + exe="$out_dir/$stem" llc -filetype=obj "$out_file" -o "$obj" clang "$obj" -o "$exe" echo "运行 $exe ..." From d8d506e46a06e1e47204e791820944b666c4965e Mon Sep 17 00:00:00 2001 From: Lane0218 Date: Wed, 11 Mar 2026 21:06:33 +0800 Subject: [PATCH 2/5] =?UTF-8?q?chore(dev):=20=E7=A7=BB=E9=99=A4=E6=9C=AC?= =?UTF-8?q?=E5=9C=B0=20git=20=E6=8F=90=E4=BA=A4=E8=BE=85=E5=8A=A9=E8=84=9A?= =?UTF-8?q?=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .codex/skills/git-submit/SKILL.md | 95 ---------------------- .githooks/commit-msg | 126 ------------------------------ scripts/setup-git-hooks.sh | 30 ------- 3 files changed, 251 deletions(-) delete mode 100644 .codex/skills/git-submit/SKILL.md delete mode 100755 .githooks/commit-msg delete mode 100755 scripts/setup-git-hooks.sh diff --git a/.codex/skills/git-submit/SKILL.md b/.codex/skills/git-submit/SKILL.md deleted file mode 100644 index 555a93e..0000000 --- a/.codex/skills/git-submit/SKILL.md +++ /dev/null @@ -1,95 +0,0 @@ ---- -name: git-submit -description: 执行 Git 提交和推送工作流 ---- - -# Git 提交/推送工作流(Codex CLI) - -当用户明确要求提交/推送时使用。 - -## 操作流程 - -### 1)检查当前状态(不需要用户确认) - -- 查看分支/干净程度:`git status -sb` -- 查看变更概要:`git diff --stat` - -如发现明显问题,优先在提交前处理: - -- 误把生成物/大文件加入:先移除或补 `.gitignore` -- 变更跨度过大:提醒用户是否需要拆分提交 - -### 2)起草提交信息(中文;默认不需要用户确认) - -根据对话历史和修改的文件信息,按下方规范直接生成提交信息并继续执行后续流程。 - -- 如果用户已经明确给出提交信息,直接使用用户提供的版本 -- 如果用户没有指定提交信息,按下方规范自动生成最合适的一条 -- **不要**为了 commit message 再额外等待用户确认,除非用户明确要求先看 message 再提交 - -#### Git Commit Message 规范 - -##### 1)格式 - -```text -(): -``` - -说明: - -- ``:提交类型(必填) -- ``:影响范围/模块(必填) -- ``:一句话说明“做了什么”(必填) - ---- - -##### 2)type 列表 - -统一使用小写: - -| type | 含义 | -|---|---| -| `feat` | 新功能 | -| `fix` | 修复 bug | -| `docs` | 文档变更 | -| `style` | 仅格式/风格(不改语义) | -| `refactor` | 重构(不改变外部行为) | -| `perf` | 性能优化 | -| `test` | 测试相关 | -| `build` | 构建系统 | -| `ci` | CI 相关 | -| `chore` | 杂项维护 | -| `revert` | 回滚提交 | - ---- - -##### 3)scope 列表 - -建议从以下范围中选择(保持一致即可): - -| scope | 含义 | -|---|---| -| `frontend` | 前端(ANTLR 驱动、AST 构建入口等) | -| `ast` | AST 相关 | -| `sema` | 语义分析(符号表、常量求值等) | -| `ir` | IR 核心结构 | -| `irgen` | AST → IR 生成 | -| `mir` | Machine IR(指令选择、寄存器分配、栈帧等) | -| `backend` | 后端目标相关(如需要可细化 `aarch64`) | -| `antlr` | 语法文件/ANTLR 相关 | -| `build` | 构建配置 | -| `test` | 测试 | -| `doc` | 文档 | -| `misc` | 其他无法归类但需要说明的范围 | - -提交信息示例: - -```text -refactor(irgen): 简化 AST → IR 构建流程 -``` - -### 3)后续流程(均不需要用户确认) - -- 暂存所有改动:`git add -A` -- 单行摘要:`git commit -m "(): "`,需要补充说明时用多行:`git commit -m "" -m "" -m ""` -- 推送:`git push`,推送完成后立即停止,不要再运行其他命令 diff --git a/.githooks/commit-msg b/.githooks/commit-msg deleted file mode 100755 index f54edfc..0000000 --- a/.githooks/commit-msg +++ /dev/null @@ -1,126 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -msg_file="${1:-}" - -if [[ -z "${msg_file}" || ! -f "${msg_file}" ]]; then - echo "错误:未找到提交信息文件(commit-msg hook 未收到有效参数)。" >&2 - exit 1 -fi - -# 读取第一条“有效提交信息”(跳过空行与注释行),并兼容 CRLF。 -first_line="$( - awk ' - { - sub(/\r$/, "") - if ($0 ~ /^[[:space:]]*#/) next - if ($0 ~ /^[[:space:]]*$/) next - print - exit - } - ' "${msg_file}" -)" - -allowed_types=( - feat fix docs style refactor perf test build ci chore revert -) - -allowed_scopes=( - frontend ast sema ir irgen mir backend antlr build test doc dev -) - -print_allowed() { - local IFS="|" - echo "允许的 type:${allowed_types[*]}" >&2 - echo "允许的 scope:${allowed_scopes[*]}" >&2 -} - -fail() { - local reason="$1" - local extra="${2:-}" - - echo "错误:提交信息不符合规范:${reason}" >&2 - echo "" >&2 - echo "当前提交信息:" >&2 - echo " ${first_line}" >&2 - echo "" >&2 - echo "规范格式:" >&2 - echo " (): " >&2 - echo "" >&2 - echo "注意:" >&2 - echo " 1) 冒号必须是英文 ':'(不是中文 ':')。" >&2 - echo " 2) 冒号后必须严格跟 1 个空格(': ')。" >&2 - echo "" >&2 - print_allowed - echo "" >&2 - echo "示例:" >&2 - echo " feat(irgen): add constant folding" >&2 - echo " fix(sema): handle null symbol" >&2 - echo " docs(doc): update build instructions" >&2 - if [[ -n "${extra}" ]]; then - echo "" >&2 - echo "${extra}" >&2 - fi - echo "" >&2 - echo "参考文档:doc/Git Commit Message 规范.md" >&2 - exit 1 -} - -if [[ -z "${first_line}" ]]; then - fail "提交信息为空(第一行不能为空)。" -fi - -# 允许 merge 提交信息(如:git merge 默认生成的 message)。 -if [[ "${first_line}" == "Merge "* ]]; then - exit 0 -fi - -# 允许 fixup!/squash!(用于 rebase --autosquash 等流程)。 -if [[ "${first_line}" == "fixup!"* || "${first_line}" == "squash!"* ]]; then - exit 0 -fi - -# 先做一些常见错误的定向提示。 -if [[ "${first_line}" == *":"* ]]; then - fail "检测到中文冒号 ':'。" "请把中文冒号替换为英文冒号 ':',并确保冒号后有且仅有 1 个空格。" -fi - -if [[ "${first_line}" =~ ^[A-Za-z]+\([A-Za-z]+\):[^[:space:]].*$ ]]; then - fail "冒号后缺少空格。" "正确写法应为 ': '(英文冒号 + 1 个空格)。" -fi - -if [[ "${first_line}" =~ ^[A-Za-z]+\([A-Za-z]+\):[[:space:]]{2,}.*$ ]]; then - fail "冒号后空格数量不正确(多于 1 个空格)。" "请确保冒号后严格是 1 个空格(': ')。" -fi - -type="" -scope="" -subject="" - -if [[ "${first_line}" =~ ^([A-Za-z]+)\(([A-Za-z]+)\):\ (.+)$ ]]; then - type="${BASH_REMATCH[1]}" - scope="${BASH_REMATCH[2]}" - subject="${BASH_REMATCH[3]}" -else - fail "格式不正确。" "请按 '(): ' 格式填写。" -fi - -if [[ "${subject}" =~ ^[[:space:]] ]]; then - fail "冒号后的空格数量不正确(多于 1 个空格)。" "请确保冒号后严格是 1 个空格(': ')。" -fi - -case "${type}" in - feat | fix | docs | style | refactor | perf | test | build | ci | chore | revert) ;; - *) - fail "type 不合法:${type}" "请使用允许的 type(小写)。" - ;; -esac - -case "${scope}" in - frontend | ast | sema | ir | irgen | mir | backend | antlr | build | test | doc | dev) ;; - *) - fail "scope 不合法:${scope}" "请使用允许的 scope(严格限制)。" - ;; -esac - -exit 0 diff --git a/scripts/setup-git-hooks.sh b/scripts/setup-git-hooks.sh deleted file mode 100755 index 86503d3..0000000 --- a/scripts/setup-git-hooks.sh +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -repo_root="$(git rev-parse --show-toplevel 2>/dev/null || true)" -if [[ -z "${repo_root}" ]]; then - echo "错误:当前目录不是 Git 仓库,无法配置 hooks。" >&2 - exit 1 -fi - -cd "${repo_root}" - -hooks_dir=".githooks" -if [[ ! -d "${hooks_dir}" ]]; then - echo "错误:未找到 ${hooks_dir} 目录,请确认仓库已包含 hooks 文件。" >&2 - exit 1 -fi - -git config core.hooksPath "${hooks_dir}" - -echo "已启用本仓库 Git hooks:" >&2 -echo " core.hooksPath=${hooks_dir}" >&2 -echo "" >&2 -echo "现在执行 git commit 时会校验提交信息是否符合:" >&2 -echo " doc/Git Commit Message 规范.md" >&2 -echo "" >&2 -echo "查看当前配置:" >&2 -echo " git config --get core.hooksPath" >&2 -echo "" >&2 -echo "如需取消(恢复默认 .git/hooks): " >&2 -echo " git config --unset core.hooksPath" >&2 From f9fde30d120a3feaf4c7cee721f8d668fafeb3c3 Mon Sep 17 00:00:00 2001 From: Lane0218 Date: Wed, 11 Mar 2026 21:06:38 +0800 Subject: [PATCH 3/5] =?UTF-8?q?docs(doc):=20=E5=88=A0=E9=99=A4=E5=B9=B6?= =?UTF-8?q?=E8=A1=8C=E7=BC=96=E8=AF=91=E8=AF=BE=E7=A8=8B=E5=AE=9E=E9=AA=8C?= =?UTF-8?q?=E9=99=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/并行编译课程实验.xlsx | Bin 10294 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 doc/并行编译课程实验.xlsx diff --git a/doc/并行编译课程实验.xlsx b/doc/并行编译课程实验.xlsx deleted file mode 100644 index b6bd13337bfc0ae276d597747d78c07eb2bcbf52..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10294 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 Date: Wed, 11 Mar 2026 21:25:07 +0800 Subject: [PATCH 4/5] refactor(dev): unify compiler error logging --- src/frontend/AntlrDriver.cpp | 25 ++++++++++----------- src/main.cpp | 2 +- src/utils/CLI.cpp | 25 ++++++++++++--------- src/utils/Log.cpp | 42 ++++++++++++++++++++++++++++++++++++ src/utils/Log.h | 15 ++++++++++--- 5 files changed, 81 insertions(+), 28 deletions(-) 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); From e9d7b4a058912ba5087f467cb97d87ac44b6d728 Mon Sep 17 00:00:00 2001 From: Lane0218 Date: Wed, 11 Mar 2026 21:42:33 +0800 Subject: [PATCH 5/5] refactor(dev): unify user-facing diagnostics --- src/irgen/IRGenDecl.cpp | 7 ++++--- src/irgen/IRGenDriver.cpp | 5 +++-- src/irgen/IRGenExp.cpp | 9 +++++---- src/irgen/IRGenFunc.cpp | 12 +++++++----- src/irgen/IRGenStmt.cpp | 5 +++-- src/main.cpp | 2 +- src/mir/FrameLowering.cpp | 5 +++-- src/mir/Lowering.cpp | 21 ++++++++++++--------- src/mir/RegAlloc.cpp | 4 +++- src/sem/Sema.cpp | 26 +++++++++++++++----------- 10 files changed, 56 insertions(+), 40 deletions(-) diff --git a/src/irgen/IRGenDecl.cpp b/src/irgen/IRGenDecl.cpp index 948c72f..931f023 100644 --- a/src/irgen/IRGenDecl.cpp +++ b/src/irgen/IRGenDecl.cpp @@ -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,13 +33,13 @@ 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) { const std::string name = decl.Ident()->getText(); if (locals_.find(name) != locals_.end()) { - throw std::runtime_error("[irgen] 重复定义变量: " + name); + throw std::runtime_error(FormatError("irgen", "重复定义变量: " + name)); } auto* slot = builder_.CreateAllocaI32(ir::DefaultContext().NextTemp()); locals_[name] = slot; diff --git a/src/irgen/IRGenDriver.cpp b/src/irgen/IRGenDriver.cpp index 014b60a..0db686b 100644 --- a/src/irgen/IRGenDriver.cpp +++ b/src/irgen/IRGenDriver.cpp @@ -6,15 +6,16 @@ #include "SysYParser.h" #include "antlr4-runtime.h" #include "ir/IR.h" +#include "utils/Log.h" std::unique_ptr GenerateIR(antlr4::tree::ParseTree* tree) { if (!tree) { - throw std::runtime_error("[irgen] 语法树为空"); + throw std::runtime_error(FormatError("irgen", "语法树为空")); } auto* cu = dynamic_cast(tree); if (!cu) { - throw std::runtime_error("[irgen] 语法树根节点不是 compUnit"); + throw std::runtime_error(FormatError("irgen", "语法树根节点不是 compUnit")); } auto module = std::make_unique(); diff --git a/src/irgen/IRGenExp.cpp b/src/irgen/IRGenExp.cpp index e62ca91..62e13a9 100644 --- a/src/irgen/IRGenExp.cpp +++ b/src/irgen/IRGenExp.cpp @@ -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]); @@ -36,12 +37,12 @@ ir::Value* IRGenImpl::GenPrimary(SysYParser::PrimaryContext& primary) { const std::string name = primary.Ident()->getText(); auto it = locals_.find(name); if (it == locals_.end()) { - throw std::runtime_error("[irgen] 变量未找到: " + name); + throw std::runtime_error(FormatError("irgen", "变量未找到: " + name)); } return builder_.CreateLoad(it->second, ir::DefaultContext().NextTemp()); } if (primary.exp()) { return GenExpr(*primary.exp()); } - throw std::runtime_error("[irgen] 暂不支持的 primary 形式"); + throw std::runtime_error(FormatError("irgen", "暂不支持的表达式形式")); } diff --git a/src/irgen/IRGenFunc.cpp b/src/irgen/IRGenFunc.cpp index 4c0500a..a58086b 100644 --- a/src/irgen/IRGenFunc.cpp +++ b/src/irgen/IRGenFunc.cpp @@ -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(""))); + throw std::runtime_error( + FormatError("irgen", "基本块未正确终结: " + + (bb ? bb->name() : std::string("")))); } } } @@ -24,17 +26,17 @@ IRGenImpl::IRGenImpl(ir::Module& module) 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(func.Ident()->getText(), ir::Type::Int32()); diff --git a/src/irgen/IRGenStmt.cpp b/src/irgen/IRGenStmt.cpp index 9b63daa..67ce213 100644 --- a/src/irgen/IRGenStmt.cpp +++ b/src/irgen/IRGenStmt.cpp @@ -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); diff --git a/src/main.cpp b/src/main.cpp index fafc646..cbb4fc9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -28,7 +28,7 @@ int main(int argc, char** argv) { auto* comp_unit = dynamic_cast(antlr.tree); if (!comp_unit) { - throw std::runtime_error("[main] 语法树根节点不是 compUnit"); + throw std::runtime_error(FormatError("main", "语法树根节点不是 compUnit")); } RunSema(*comp_unit); diff --git a/src/mir/FrameLowering.cpp b/src/mir/FrameLowering.cpp index e6ad9c9..bdf05fc 100644 --- a/src/mir/FrameLowering.cpp +++ b/src/mir/FrameLowering.cpp @@ -3,6 +3,8 @@ #include #include +#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", "暂不支持过大的栈帧")); } } diff --git a/src/mir/Lowering.cpp b/src/mir/Lowering.cpp index 8b99276..636e6ea 100644 --- a/src/mir/Lowering.cpp +++ b/src/mir/Lowering.cpp @@ -4,6 +4,7 @@ #include #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(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(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 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(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()) { diff --git a/src/mir/RegAlloc.cpp b/src/mir/RegAlloc.cpp index e9f083f..9262af1 100644 --- a/src/mir/RegAlloc.cpp +++ b/src/mir/RegAlloc.cpp @@ -2,6 +2,8 @@ #include +#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", "寄存器分配失败")); } } } diff --git a/src/sem/Sema.cpp b/src/sem/Sema.cpp index d64d9f0..cdc797d 100644 --- a/src/sem/Sema.cpp +++ b/src/sem/Sema.cpp @@ -4,6 +4,7 @@ #include #include "sem/SymbolTable.h" +#include "utils/Log.h" namespace { @@ -18,7 +19,7 @@ void CheckPrimary(SysYParser::PrimaryContext& primary, if (primary.Ident()) { const std::string name = primary.Ident()->getText(); if (!table.Contains(name)) { - throw std::runtime_error("[sema] 使用了未定义的变量: " + name); + throw std::runtime_error(FormatError("sema", "使用了未定义的变量: " + name)); } return; } @@ -28,12 +29,12 @@ 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) { if (!exp.addExp()) { - throw std::runtime_error("[sema] 非法表达式"); + throw std::runtime_error(FormatError("sema", "非法表达式")); } const auto& terms = exp.addExp()->primary(); for (auto* term : terms) { @@ -46,10 +47,10 @@ void CheckExpr(SysYParser::ExpContext& exp, const SymbolTable& table) { void 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; @@ -57,7 +58,8 @@ void 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) { @@ -66,12 +68,13 @@ void 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); @@ -84,14 +87,15 @@ void RunSema(SysYParser::CompUnitContext& comp_unit) { CheckExpr(*ret->exp(), table); 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 语句")); } }