From f3d01023768aa79a53bd960fbf8a80bd507d1292 Mon Sep 17 00:00:00 2001 From: Lane0218 Date: Thu, 12 Mar 2026 10:52:55 +0800 Subject: [PATCH] =?UTF-8?q?docs(doc):=20=E6=B8=85=E7=90=86=E5=86=97?= =?UTF-8?q?=E4=BD=99=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/reference-README.md | 143 -------------------- doc/目录结构设计.md | 271 -------------------------------------- test/run_tests.sh | 206 ----------------------------- 3 files changed, 620 deletions(-) delete mode 100644 doc/reference-README.md delete mode 100644 doc/目录结构设计.md delete mode 100755 test/run_tests.sh diff --git a/doc/reference-README.md b/doc/reference-README.md deleted file mode 100644 index 8505009..0000000 --- a/doc/reference-README.md +++ /dev/null @@ -1,143 +0,0 @@ -# SysY Compiler - -用于实现SysY编译器的代码框架。 - -## Getting Started - -建议使用Ubuntu 22.04系统,原生版本与WSL版本均可。 - -[Ubuntu下载与安装说明](https://ubuntu.com/download/desktop) - -[WSL Ubuntu安装说明](https://learn.microsoft.com/en-us/windows/wsl/install) - -SysY编译器前端基于[ANTLR](https://www.antlr.org/index.html)工具实现,本仓库已经包含ANTLR 4.9.3版本的可执行程序与C++运行时库,但编译ANTLR运行时库存在一些依赖,需要提前安装。 - -```bash -sudo apt update -sudo apt install -y uuid-dev libutfcpp-dev pkg-config make git cmake openjdk-11-jre -``` - -依赖安装完成后,可以开始构建SysY编译器(构建过程包含了ANTLR运行时库的构建)。 - -```bash -git clone https://gitee.com/xsu1989/sysy.git -cd sysy -cmake -S . -B build -cmake --build build -``` - -构建完成后,可以运行一个小的测试用例。该测试将逗号分隔的整数或字符串列表进行格式化后重新输出,即将相邻参数之间的分隔统一调整为逗号外加一个空格。 - -```bash -cat /test/funcrparams.sysy -# -> 1,0xa , 011, "hellow" -./build/bin/sysyc test/funcrparams.sy -# -> 1, 0xa, 011, "hellow" -``` - -## Documentation - -[ANTLR手册](doc/The%20Definitive%20ANTLR%204%20Reference.pdf) - -[SysY语言规范](doc/sysy-2022-spec.pdf) - -[SysY运行时库](doc/sysy-2022-runtime.pdf) - -## 实验1:用ANTLR实现SysY词法/语法分析器 - -当前的代码框架已经部署好了编译环境,同学们可专注于程序开发。 - -在实验1中,同学们需要完成的任务包括 - -- 参照SysY语言规范,修改`src/SysY.g4`文件,实现SysY词法/语法的完整定义 -- 修改任意代码后需要重新执行`cmake --build build`命令重新构建项目,ANTLR工具会从`SysY.g4`生成词法/语法分析器,生成的文件位于`./build/src`目录 -- (进阶内容)修改`src/ASTPrinter.h`与`src/ASTPrinter.cpp`,实现从AST输出源程序,但输出的源程序是经过格式化的 - -## 实验2:生成中间表示 - -exp2分支为大家准备好了进行实验2的基本代码框架,包括 - -- IR相关数据结构的定义:`src/IR.h` -- 创建IR对象的工具类`src/IRBuilder.h` -- IR生成器的示例代码`src/SysYIRGenerator.h` - -在实验2中,同学们需要完成的任务包括 - -- 熟悉掌握IR定义与相关数据结构 -- 从语法树生成IR -请同学们仔细阅读代码学习IR的定义。 - - -## 实验3:从SysY IR 生成ARMv7汇编代码 -### 后端相关源码 -当前ref2分支为ARMv7后端代码实验,已经包含了后端代码生成的代码框架,包含 - -- 后端生成代码源文件`src/backend/codegen.cpp` -- 后端生成代码头文件`src/backend/codegen.hpp` - -本实验需要基于以上两个源文件添加ARMv7后端生成代码(也可以按照自己的设计重头编写整个后端生成代码),完成这两个源文件中所有空函数的实现.不局限于本实验提供的后端代码框架,自由设计自己的ARMv7后端实现. - -### 后端代码的编译与运行 -本实验也修改了驱动代码sysyc.cpp, sysyc.cpp可以调用后端生成的最顶层函数接口code_gen().该函数会逐层调用各层级的代码生产函数并最终生成ARMv7汇编代码并打印至屏幕.通过下列命令编译 -```bash -cmake -S . -B build -cmake --build build -``` -通过下列命令运行编译产生的sysyc -```bash -./sysyc 01_add.sy -``` -或者通过下列命令只生成SysY IR代码 -```bash -./sysyc 01_add.sy ir -``` -### 测试 -本实验提供了两个sysy源文件用于测试,分别是位于sysy-backend/test的01_add.sy 11_add2.sy; 当完成sysyc的编译器后端后,可以通过sysy-backend/test下的Makefile文件编译生成测试程序的可执行二进制. - -#### 在x86平台编译运行测试代码 -##### 下载并配置ARMv7交叉编译器工具链 -在[Arm GNU Toolchain](https://developer.arm.com/downloads/-/arm-gnu-toolchain-downloads)下载安装交叉编译工具链,并设置环境变量PATH来使用交叉编译工具链 -```bash -export PATH=${your_arm-gnu-toolchain_path}/bin:$PATH; -``` -##### 安装qemu模拟器 -```bash -sudo apt update -sudo apt install qemu-system-arm qemu-user -``` -##### 编译测试程序 -使用如下命令调用完成后端实现的sysyc生成ARMv7汇编代码,并调用ARMv7交叉编译工具链汇编并连接生成可执行文件. -```bash -cd test -../build/bin/sysyc 01_add.sy > 01_add.s -arm-none-linux-gnueabihf-gcc 01_add.s -o 01_add.out -static #注意使用-static选项来静态链接 -``` - -##### 使用qemu-arm模拟运行测试程序 -```bash -cd test -qemu-arm ./01_add.out -echo $? #查看测试程序返回值 -``` - -##### 使用makefile编译与运行 -```bash -cd test -make all -r #利用sysyc编译两个测试程序 -make run -r #使用qemu-arm模拟运行两个测试程序 -``` -#### 在树莓派上编译运行测试代码 -参见'Raspberry.pptx'设置树莓派的编译运行环境,也可以在自己的x86电脑上利用ARMv7交叉编译工具链来编译测试程序, 将编译产生的可执行文件上传到树莓派上运行. - - -### 交叉编译器生成汇编代码 -可以通过如下的命令让交叉编译器生成汇编代码,以参考gcc后端的编译行为. -```bash -cd test -cp 01_add.sy 01_add.c # 修改代码后缀名 -arm-none-linux-gnueabihf-gcc 01_add.c -O0 -S -o 01_add.S #O0编译优化 -``` -请自己构造一些简单的c程序,阅读交叉编译器编译产生的汇编代码来理解ARMv7汇编代码与编译器后端行为. - -### 参考文档 -参见doc/backend/下的ARMv7相关文档 \ No newline at end of file diff --git a/doc/目录结构设计.md b/doc/目录结构设计.md deleted file mode 100644 index 016f664..0000000 --- a/doc/目录结构设计.md +++ /dev/null @@ -1,271 +0,0 @@ -# SysY 编译器目录结构设计 - -## 1. 编译流程图 - -```text -[ 前端 Frontend ] - C 源代码 - ↓ - Lexer / Parser(ANTLR) - ↓ - 语法树构建 + 语义分析(Sema) - ↓ - 语法树(附加语义信息) - -[ 中端 Middle-end ] - 语法树 - ↓ - IR 构建(平台无关 IR,LLVM 风格) - ↓ - IR 优化(ConstFold / DCE / mem2reg 等,可选) - ↓ - 优化后的 IR - -[ 后端 Backend(ARMv8-A / AArch64)] - IR - ↓ - IR → MIR(AArch64 指令 + 虚拟寄存器) ← 指令选择 - ↓ - MIR → MIR(AArch64 指令 + 物理寄存器) ← 寄存器分配(含 spill/reload) - ↓ - 栈帧构建 / Prologue / Epilogue 插入 ← FrameLowering - ↓ - MIR(最终机器指令) - ↓ - 汇编打印 - ↓ - ARMv8-A 汇编(.s) -``` - -## 2. 目录结构 - -```text -. -├── CMakeLists.txt -├── README.md -├── .gitignore -├── src/ -│ ├── CMakeLists.txt -│ ├── main.cpp -│ ├── antlr4/ -│ │ └── SysY.g4 -│ ├── frontend/ -│ │ ├── AntlrDriver.cpp -│ │ └── SyntaxTreePrinter.cpp -│ ├── sem/ -│ │ ├── Sema.cpp -│ │ ├── SymbolTable.cpp -│ │ └── ConstEval.cpp -│ ├── irgen/ -│ │ ├── CMakeLists.txt -│ │ ├── IRGenDriver.cpp -│ │ ├── IRGenFunc.cpp -│ │ ├── IRGenStmt.cpp -│ │ ├── IRGenExp.cpp -│ │ └── IRGenDecl.cpp -│ ├── ir/ -│ │ ├── Context.cpp -│ │ ├── Module.cpp -│ │ ├── Function.cpp -│ │ ├── BasicBlock.cpp -│ │ ├── Type.cpp -│ │ ├── Value.cpp -│ │ ├── Instruction.cpp -│ │ ├── IRBuilder.cpp -│ │ ├── IRPrinter.cpp -│ │ ├── analysis/ -│ │ │ ├── DominatorTree.cpp -│ │ │ └── LoopInfo.cpp -│ │ └── passes/ -│ │ ├── PassManager.cpp -│ │ ├── Mem2Reg.cpp -│ │ ├── ConstFold.cpp -│ │ ├── DCE.cpp -│ │ └── CFGSimplify.cpp -│ ├── mir/ -│ │ ├── MIRContext.cpp -│ │ ├── MIRFunction.cpp -│ │ ├── MIRBasicBlock.cpp -│ │ ├── MIRInstr.cpp -│ │ ├── Register.cpp -│ │ ├── Lowering.cpp -│ │ ├── RegAlloc.cpp -│ │ ├── FrameLowering.cpp -│ │ ├── AsmPrinter.cpp -│ │ └── passes/ -│ │ ├── PassManager.cpp -│ │ └── Peephole.cpp -│ └── utils/ -│ ├── Log.cpp -│ └── CLI.cpp -├── include/ -│ ├── frontend/ -│ ├── sem/ -│ ├── irgen/ -│ ├── ir/ -│ ├── mir/ -│ └── utils/ -├── sylib/ -│ ├── sylib.c -│ └── sylib.h -└── test/ - ├── test_case/ - ├── test_result/ - └── run_tests.sh -``` - -## 3. 文件功能说明 - -### 3.1 顶层文件 - -- `CMakeLists.txt` - - 工程构建入口:配置编译器、添加子目录、链接生成最终可执行文件。 - - 负责集成 ANTLR runtime(通过系统依赖或第三方源码),并将“ANTLR 生成代码所在的构建目录”加入编译。 -- `README.md` - - 实验/工程说明:依赖环境、构建方式、测试脚本用法、ANTLR 生成命令(写在文档中,不提供脚本)。 -- `.gitignore` - - 忽略构建产物(如 `build/`)、ANTLR 自动生成文件、`test/test_result/` 等输出目录。 - -### 3.2 `src/`:实现代码 - -#### 3.2.1 入口与构建 - -- `src/CMakeLists.txt` - - `src/` 子目录构建脚本:编译各子模块源文件,生成静态库/目标并链接到最终可执行文件。 -- `src/main.cpp` - - 编译器入口:解析命令行参数、驱动完整流水线(Frontend → Middle-end → Backend)。 - - 负责把不同阶段产物输出为文件(如输出 `.ll` / `.s` 的开关可在此集中实现)。 - -#### 3.2.2 `src/antlr4/`:SysY 文法(只提交 `.g4`) - -- `src/antlr4/SysY.g4` - - SysY 语法定义(lexer + parser rules),为 ANTLR 生成 C++ lexer/parser 提供输入。 - -- ANTLR 自动生成文件位置约定:该工程采用工程化方式:ANTLR 生成文件**不进入仓库**,统一放到构建目录,例如: - - `build/generated/antlr4/` - -- 典型生成物包括(随生成选项略有差异): - - `SysYLexer.cpp/.h` - - `SysYParser.cpp/.h` - - `SysYBaseVisitor.cpp/.h`、`SysYVisitor.cpp/.h` - - `*.tokens`、`*.interp` - -#### 3.2.3 `src/frontend/`:语法解析与语法树输出 - -- `src/frontend/AntlrDriver.cpp` - - 读取源代码并调用解析流程,得到语法树。 - - 由于语法正确性由测试保证,该模块只需提供“可用的解析入口”,不需要实现复杂的语法错误报告体系。 -- `src/frontend/SyntaxTreePrinter.cpp` - - 语法树调试打印:用于验证语法规则与前端解析行为是否符合预期。 - -#### 3.2.4 `src/sem/`:语义分析(Sema) - -- `src/sem/Sema.cpp` - - 语义分析主流程:符号解析、类型检查、控制流规则检查、必要的隐式转换插入/记录等。 - - 在语法树基础上完成语义检查,并为后续 IR 生成提供约束。 -- `src/sem/SymbolTable.cpp` - - 符号表与作用域管理:支持嵌套作用域、变量/函数/参数/常量的注册与查找。 -- `src/sem/ConstEval.cpp` - - 常量求值:用于数组维度、全局初始化、`const` 表达式等需要编译期计算的场景。 - -#### 3.2.5 `src/irgen/`:语法树 → IR(平台无关,LLVM 风格) - -- `src/irgen/IRGenDriver.cpp` - - 驱动语法树遍历,调度各子模块完成翻译。 -- `src/irgen/IRGenFunc.cpp` - - 函数翻译:函数定义、参数列表与返回值翻译;创建对应 IR 函数对象。 -- `src/irgen/IRGenStmt.cpp` - - 语句翻译:if/while/return 等控制流构造,生成基本块与分支。 -- `src/irgen/IRGenExp.cpp` - - 表达式翻译:算术运算、比较、逻辑运算、函数调用等ir指令生成。 -- `src/irgen/IRGenDecl.cpp` - - 声明翻译:处理全局变量、局部变量、数组初始化与空间分配等。 - -#### 3.2.6 `src/ir/`:LLVM 风格 IR 核心 - -- `src/ir/Context.cpp` - - IR 上下文:管理类型/常量创建与复用、字符串/符号等公共资源。 -- `src/ir/Module.cpp` - - Module 容器:保存全局变量、函数列表、目标信息(如需要)、符号表等。 -- `src/ir/Function.cpp` - - Function 容器:参数、基本块列表、属性/元信息等。 -- `src/ir/BasicBlock.cpp` - - 基本块表示:指令序列、前驱/后继关系(显式或可计算)。 -- `src/ir/Type.cpp` - - IR 类型系统:`i32/f32/void`、指针、数组、函数类型等(按 SysY 支持范围裁剪)。 -- `src/ir/Value.cpp` - - SSA 值体系:常量、参数、指令结果等统一抽象。 -- `src/ir/Instruction.cpp` - - 指令体系:二元运算、比较、load/store、call、br/condbr、ret、phi、alloca 等(按需求逐步补齐)。 -- `src/ir/IRBuilder.cpp` - - IR 构建工具:集中管理插入点与指令创建,降低 IRGen 复杂度。 -- `src/ir/IRPrinter.cpp` - - IR 文本输出:打印为 `.ll` 风格文本,支撑调试与测试对比。 -- `src/ir/analysis/DominatorTree.cpp` - - 支配树分析:为 `mem2reg`、部分 CFG 优化与循环分析提供基础能力。 -- `src/ir/analysis/LoopInfo.cpp` - - 循环分析:识别循环结构,为后续优化(可选)提供信息。 -- `src/ir/passes/PassManager.cpp` - - IR pass 管理:按优化级别组织 pipeline,并统一运行与统计。 -- `src/ir/passes/Mem2Reg.cpp` - - SSA 构造关键 pass:将局部变量的 `alloca/load/store` 提升为 SSA(插入 PHI)。 -- `src/ir/passes/ConstFold.cpp` - - IR 常量折叠:简化可判定的常量表达与常量控制流分支(按实现范围裁剪)。 -- `src/ir/passes/DCE.cpp` - - 死代码删除:删除无用指令与无用块(与 CFG 简化配合)。 -- `src/ir/passes/CFGSimplify.cpp` - - CFG 简化:删除不可达块、合并空块、简化分支等。 - -#### 3.2.7 `src/mir/`:Machine IR - -- `src/mir/MIRContext.cpp` - - MIR 上下文:保存目标约束、指令集信息等。 -- `src/mir/MIRFunction.cpp` - - 机器函数:包含机器基本块、栈帧信息、虚拟/物理寄存器管理等。 -- `src/mir/MIRBasicBlock.cpp` - - 机器基本块:机器指令列表与 CFG 信息。 -- `src/mir/MIRInstr.cpp` - - 机器指令:opcode + operands(寄存器/立即数/栈槽/符号/标签等)。 -- `src/mir/Register.cpp` - - 寄存器表示:区分虚拟寄存器与物理寄存器,提供编号/属性等。 - - 寄存器类(RegClass):GPR/FPR 等分类与可分配集合描述(供 RA 使用)。 -- `src/mir/Lowering.cpp` - - IR → MIR:从平台无关 IR 生成 AArch64 指令的 MIR(在此完成指令选择),初始使用虚拟寄存器。 -- `src/mir/RegAlloc.cpp` - - 寄存器分配主入口:将虚拟寄存器分配到物理寄存器,并驱动 spill/reload 等后续处理。 -- `src/mir/FrameLowering.cpp` - - 栈帧布局与序言尾声:根据寄存器分配阶段记录的栈槽需求计算栈大小与对齐,插入 prologue/epilogue,保存/恢复 callee-saved 等。 -- `src/mir/AsmPrinter.cpp` - - 汇编打印:将最终机器指令 MIR 打印为 ARMv8-A 汇编 `.s`。 -- `src/mir/passes/PassManager.cpp` - - MIR pass 管理:组织后端 pass 的运行顺序(PreRA/PostRA/PEI 等阶段)。 -- `src/mir/passes/Peephole.cpp` - - 窥孔优化:删除冗余 move、合并常见指令模式,提升最终汇编质量。 - -#### 3.2.8 `src/utils/`:日志与命令行 - -- `src/utils/Log.cpp` - - 日志输出:统一调试信息、阶段信息与错误信息输出。 -- `src/utils/CLI.cpp` - - 命令行参数解析:输入/输出路径、输出类型(IR/MIR/ASM)、优化级别等。 - -### 3.3 `include/`:头文件目录 - -`include/` 目录与 `src/` 分层保持一致,用于放置对外可复用的头文件(具体头文件列表按实现新增)。 - -### 3.4 `sylib/`:SysY 运行库 - -- `sylib/sylib.c` - - SysY 运行库实现(按实验/评测规范提供 I/O 等函数)。 -- `sylib/sylib.h` - - 运行库头文件声明(供编译器生成 `call` 时引用,或用于链接阶段)。 - -### 3.5 `test/`:测试 - -- `test/test_case/` - - 测试输入目录:存放 `*.sy` 测试用例(可选搭配 `*.in` 作为 stdin 输入)。 -- `test/test_result/` - - 测试输出目录:由测试脚本生成 `.ll/.s`、运行输出、diff 结果与日志等。 - - 建议通过 `.gitignore` 忽略,不纳入版本管理。 -- `test/run_tests.sh` - - Bash 测试脚本:批量编译 `test_case/`,将产物写入 `test_result/`,并汇总通过/失败信息。 diff --git a/test/run_tests.sh b/test/run_tests.sh deleted file mode 100755 index 377f001..0000000 --- a/test/run_tests.sh +++ /dev/null @@ -1,206 +0,0 @@ -#!/usr/bin/env bash - -set -uo pipefail - -repo_root=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd) -cd "$repo_root" - -cases_dir="test/test_case" -result_root="test/test_result/run_tests" -asm_dir="$result_root/asm" -compiler="./build/bin/compiler" -cross_gcc="aarch64-linux-gnu-gcc" -qemu_bin="qemu-aarch64" -qemu_sysroot="/usr/aarch64-linux-gnu" - -usage() { - cat <<'EOF' -用法: ./test/run_tests.sh [case ...] - -参数: - case 可选。支持以下两种写法: - - test/test_case/foo.sy - - foo (自动解析为 test/test_case/foo.sy) - -行为: - - 批量编译 test/test_case/*.sy 为 AArch64 汇编并链接可执行文件 - - 若存在同名 .in,则将其作为标准输入喂给程序 - - 采集程序标准输出,并将退出码追加为最后一行 - - 与同名 .out 做精确 diff,比对结果写入 test/test_result/run_tests/ -EOF -} - -require_tool() { - local tool=$1 - if ! command -v "$tool" >/dev/null 2>&1; then - echo "未找到依赖工具: $tool" >&2 - exit 1 - fi -} - -resolve_case() { - local arg=$1 - if [[ -f "$arg" ]]; then - printf '%s\n' "$arg" - return 0 - fi - if [[ -f "$cases_dir/$arg.sy" ]]; then - printf '%s\n' "$cases_dir/$arg.sy" - return 0 - fi - return 1 -} - -append_exit_code() { - local stdout_file=$1 - local actual_file=$2 - local status=$3 - - : > "$actual_file" - if [[ -f "$stdout_file" ]]; then - cat "$stdout_file" >> "$actual_file" - if [[ -s "$stdout_file" ]]; then - local last_byte - last_byte=$(tail -c 1 "$stdout_file" | od -An -t x1 | tr -d ' \n') - if [[ "$last_byte" != "0a" ]]; then - printf '\n' >> "$actual_file" - fi - fi - fi - printf '%s\n' "$status" >> "$actual_file" -} - -run_case() { - local input_sy=$1 - local base stem expected input_txt case_dir asm_file exe_file - local compile_log link_log stderr_log stdout_log actual_out diff_log - local status - - base=$(basename "$input_sy") - stem=${base%.sy} - expected="${input_sy%.sy}.out" - input_txt="${input_sy%.sy}.in" - - case_dir="$result_root/$stem" - asm_file="$asm_dir/$stem.s" - exe_file="$asm_dir/$stem" - compile_log="$case_dir/compiler.log" - link_log="$case_dir/link.log" - stderr_log="$case_dir/stderr.log" - stdout_log="$case_dir/stdout.log" - actual_out="$case_dir/actual.out" - diff_log="$case_dir/diff.log" - - rm -rf "$case_dir" - mkdir -p "$case_dir" - rm -f "$asm_file" "$exe_file" - - if [[ ! -f "$expected" ]]; then - echo "[FAIL] $stem: 缺少预期输出文件 $expected" - ((missing_expected_count += 1)) - failed_cases+=("$stem") - return - fi - - if ! "$compiler" --emit-asm "$input_sy" >"$asm_file" 2>"$compile_log"; then - echo "[FAIL] $stem: 编译失败,详见 $compile_log" - ((compile_fail_count += 1)) - failed_cases+=("$stem") - return - fi - - if ! "$cross_gcc" "$asm_file" -o "$exe_file" >"$link_log" 2>&1; then - echo "[FAIL] $stem: 链接失败,详见 $link_log" - ((link_fail_count += 1)) - failed_cases+=("$stem") - return - fi - - : > "$stdout_log" - : > "$stderr_log" - if [[ -f "$input_txt" ]]; then - "$qemu_bin" -L "$qemu_sysroot" "$exe_file" <"$input_txt" >"$stdout_log" 2>"$stderr_log" - status=$? - else - "$qemu_bin" -L "$qemu_sysroot" "$exe_file" >"$stdout_log" 2>"$stderr_log" - status=$? - fi - - append_exit_code "$stdout_log" "$actual_out" "$status" - - if diff -u "$expected" "$actual_out" >"$diff_log"; then - rm -f "$diff_log" - echo "[PASS] $stem" - ((pass_count += 1)) - else - echo "[FAIL] $stem: 输出不匹配,详见 $diff_log" - ((diff_fail_count += 1)) - failed_cases+=("$stem") - fi -} - -if [[ ${1:-} == "-h" || ${1:-} == "--help" ]]; then - usage - exit 0 -fi - -if [[ ! -x "$compiler" ]]; then - echo "未找到编译器: $compiler ,请先构建。" >&2 - exit 1 -fi - -require_tool "$cross_gcc" -require_tool "$qemu_bin" - -mkdir -p "$asm_dir" - -declare -a cases=() -declare -a failed_cases=() - -if [[ $# -gt 0 ]]; then - for arg in "$@"; do - if ! resolved=$(resolve_case "$arg"); then - echo "未找到测试用例: $arg" >&2 - exit 1 - fi - cases+=("$resolved") - done -else - while IFS= read -r -d '' file; do - cases+=("$file") - done < <(find "$cases_dir" -maxdepth 1 -type f -name '*.sy' -print0 | sort -z) -fi - -if [[ ${#cases[@]} -eq 0 ]]; then - echo "未找到任何 .sy 测试用例。" >&2 - exit 1 -fi - -pass_count=0 -compile_fail_count=0 -link_fail_count=0 -diff_fail_count=0 -missing_expected_count=0 - -for case_path in "${cases[@]}"; do - run_case "$case_path" -done - -total_count=${#cases[@]} -fail_count=$((compile_fail_count + link_fail_count + diff_fail_count + missing_expected_count)) - -echo -echo "测试完成: $total_count 个用例" -echo "通过: $pass_count" -echo "失败: $fail_count" -echo " 编译失败: $compile_fail_count" -echo " 链接失败: $link_fail_count" -echo " 输出不匹配: $diff_fail_count" -echo " 缺少预期输出: $missing_expected_count" - -if [[ ${#failed_cases[@]} -gt 0 ]]; then - echo "失败用例: ${failed_cases[*]}" - exit 1 -fi - -exit 0