diff --git a/doc/lab2剩余任务分工.md b/doc/lab2剩余任务分工.md index 9ba8abb..70e63de 100644 --- a/doc/lab2剩余任务分工.md +++ b/doc/lab2剩余任务分工.md @@ -1,4 +1,4 @@ -### 人员 1:基础表达式与赋值支持(lc) +### 人员 1:基础表达式与赋值支持(lc,已完成) - 任务 1.1:支持更多二元运算符(Sub, Mul, Div, Mod) - 任务 1.2:支持一元运算符(正负号) @@ -19,3 +19,52 @@ - 任务 3.3:支持函数调用生成 - 任务 3.4:支持 const 常量声明 +
+ +
+ +## 人员 1 完成情况详细说明(更新于 2026-03-30) + +### ✅ 已完成任务 + +人员 1 已完整实现 Lab2 IR 生成的基础功能模块,包括: + +1. **二元运算符**(任务 1.1) + - 实现 `Sub`, `Mul`, `Div`, `Mod` 四种运算符 + - 修改文件:`include/ir/IR.h`, `src/ir/IRBuilder.cpp`, `src/ir/IRPrinter.cpp`, `src/irgen/IRGenExp.cpp` +2. **一元运算符**(任务 1.2) + - 实现正负号运算符(`+`, `-`) + - 新增 `UnaryInst` 类支持一元指令 + - 负号生成 `sub 0, x` 指令(LLVM IR 标准形式) +3. **赋值表达式**(任务 1.3) + - 实现变量赋值语句的 IR 生成 + - 修改文件:`src/irgen/IRGenStmt.cpp` +4. **多变量声明**(任务 1.4) + - 支持逗号分隔的变量声明(如 `int a, b, c;`) + - 支持带初始化的多变量声明(如 `int a = 1, b = 2;`) + +### 🧪 测试验证 + +- **Lab1 语法分析**:✅ 通过(10/11 functional 测试,1 个数组测试超出范围) +- **Lab2 语义分析**:✅ 通过(6 正例 + 4 反例) +- **IR 生成测试**:✅ 通过(7/7 自定义测试用例) + - 测试脚本:`./scripts/test_lab2_ir1.sh` + - 测试用例目录:`test/test_case/irgen_lab1_4/` + +### 📝 代码质量 + +- 所有修改已通过编译测试 +- 未影响原有 Lab1 和 Lab2 Sema 功能 +- 代码风格与项目保持一致 +- 关键函数添加了注释说明 + +### 🔄 协作接口 + +人员 1 的实现为后续任务提供了以下接口: + +- **表达式生成**:`visitAddExp`, `visitMulExp`, `visitUnaryExp` +- **语句生成**:`visitStmt`(支持赋值和 return) +- **变量管理**:`storage_map_` 维护变量名到栈槽位的映射 +- **IR 构建**:`IRBuilder::CreateBinary`, `IRBuilder::CreateNeg`, `IRBuilder::CreateStore` + +后续人员可以在此基础上扩展更复杂的功能(控制流、函数调用等)。 diff --git a/scripts/test_lab2_ir1.sh b/scripts/test_lab2_ir1.sh new file mode 100755 index 0000000..65f9c3f --- /dev/null +++ b/scripts/test_lab2_ir1.sh @@ -0,0 +1,157 @@ +#!/usr/bin/env bash +# 测试 Lab2 IR 生成 - 人员 1 的任务 +# 测试内容: +# - 任务 1.1: 支持更多二元运算符(Sub, Mul, Div, Mod) +# - 任务 1.2: 支持一元运算符(正负号) +# - 任务 1.3: 支持赋值表达式 +# - 任务 1.4: 支持逗号分隔的多个变量声明 + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(dirname "$SCRIPT_DIR")" +COMPILER="$PROJECT_ROOT/build/bin/compiler" +TEST_DIR="$PROJECT_ROOT/test/test_case/irgen_lab1_4" +RESULT_DIR="$PROJECT_ROOT/test/test_result/lab2_ir1" + +# 颜色输出 +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +echo "=========================================" +echo "Lab2 IR 生成测试 - 部分任务验证" +echo "=========================================" +echo "" + +# 检查编译器是否存在 +if [[ ! -x "$COMPILER" ]]; then + echo -e "${RED}错误:编译器不存在或不可执行:$COMPILER${NC}" + echo "请先运行:cmake --build build" + exit 1 +fi + +# 检查测试目录是否存在 +if [[ ! -d "$TEST_DIR" ]]; then + echo -e "${RED}错误:测试目录不存在:$TEST_DIR${NC}" + exit 1 +fi + +# 创建结果目录 +mkdir -p "$RESULT_DIR" + +# 统计 +total=0 +passed=0 +failed=0 + +# 测试函数 +run_test() { + local input=$1 + local basename=$(basename "$input" .sy) + local expected_out="$TEST_DIR/$basename.out" + local actual_out="$RESULT_DIR/$basename.actual.out" + local ll_file="$RESULT_DIR/$basename.ll" + + ((total++)) || true + + echo -n "测试 $basename ... " + + # 生成 IR + if ! "$COMPILER" --emit-ir "$input" > "$ll_file" 2>&1; then + echo -e "${RED}IR 生成失败${NC}" + ((failed++)) || true + return 1 + fi + + # 如果需要运行并比对输出 + if [[ -f "$expected_out" ]]; then + # 编译并运行 + local exe_file="$RESULT_DIR/$basename" + if ! llc -O0 -filetype=obj "$ll_file" -o "$RESULT_DIR/$basename.o" 2>/dev/null; then + echo -e "${YELLOW}LLVM 编译失败 (llc)${NC}" + cat "$ll_file" + ((failed++)) || true + return 1 + fi + + if ! clang "$RESULT_DIR/$basename.o" -o "$exe_file" 2>/dev/null; then + echo -e "${YELLOW}链接失败 (clang)${NC}" + ((failed++)) || true + return 1 + fi + + # 运行程序,捕获返回值(低 8 位) + local exit_code=0 + "$exe_file" > "$actual_out" 2>&1 || exit_code=$? + + # 处理返回值(LLVM/AArch64 返回的是 8 位无符号整数) + if [[ $exit_code -gt 127 ]]; then + # 转换为有符号整数 + exit_code=$((exit_code - 256)) + fi + echo "$exit_code" > "$actual_out" + + # 比对输出 + if diff -q "$expected_out" "$actual_out" > /dev/null 2>&1; then + echo -e "${GREEN}✓ 通过${NC}" + ((passed++)) || true + return 0 + else + echo -e "${RED}✗ 输出不匹配${NC}" + echo " 期望:$(cat "$expected_out")" + echo " 实际:$(cat "$actual_out")" + ((failed++)) || true + return 1 + fi + else + # 没有期望输出,只检查 IR 生成 + echo -e "${GREEN}✓ IR 生成成功${NC}" + ((passed++)) || true + return 0 + fi +} + +# 查找所有测试用例 +test_files=() +while IFS= read -r -d '' file; do + test_files+=("$file") +done < <(find "$TEST_DIR" -name "*.sy" -type f -print0 | sort -z) + +if [[ ${#test_files[@]} -eq 0 ]]; then + echo -e "${RED}未找到测试用例:$TEST_DIR${NC}" + exit 1 +fi + +echo "找到 ${#test_files[@]} 个测试用例" +echo "" + +# 运行所有测试 +for test_file in "${test_files[@]}"; do + run_test "$test_file" || true +done + +# 输出统计 +echo "" +echo "=========================================" +echo "测试结果统计" +echo "=========================================" +echo -e "总数:$total" +echo -e "通过:${GREEN}$passed${NC}" +echo -e "失败:${RED}$failed${NC}" +echo "" + +if [[ $failed -eq 0 ]]; then + echo -e "${GREEN}✓ 所有测试通过!${NC}" + echo "" + echo "测试覆盖:" + echo " ✓ 任务 1.1: 二元运算符(Sub, Mul, Div, Mod)" + echo " ✓ 任务 1.2: 一元运算符(正负号)" + echo " ✓ 任务 1.3: 赋值表达式" + echo " ✓ 任务 1.4: 逗号分隔的多变量声明" + exit 0 +else + echo -e "${RED}✗ 有 $failed 个测试失败${NC}" + exit 1 +fi diff --git a/scripts/test_lab2_sema.sh b/scripts/test_lab2_sema.sh old mode 100644 new mode 100755 diff --git a/test/test_case/irgen_lab1_4/01_simple_add.out b/test/test_case/irgen_lab1_4/01_simple_add.out new file mode 100644 index 0000000..00750ed --- /dev/null +++ b/test/test_case/irgen_lab1_4/01_simple_add.out @@ -0,0 +1 @@ +3 diff --git a/test/test_case/irgen_lab1_4/01_simple_add.sy b/test/test_case/irgen_lab1_4/01_simple_add.sy new file mode 100644 index 0000000..8b5f091 --- /dev/null +++ b/test/test_case/irgen_lab1_4/01_simple_add.sy @@ -0,0 +1,6 @@ +// 测试:简单加法 +int main() { + int a = 1; + int b = 2; + return a + b; +} diff --git a/test/test_case/irgen_lab1_4/02_sub_mul.out b/test/test_case/irgen_lab1_4/02_sub_mul.out new file mode 100644 index 0000000..81b5c5d --- /dev/null +++ b/test/test_case/irgen_lab1_4/02_sub_mul.out @@ -0,0 +1 @@ +37 diff --git a/test/test_case/irgen_lab1_4/02_sub_mul.sy b/test/test_case/irgen_lab1_4/02_sub_mul.sy new file mode 100644 index 0000000..8ddeca9 --- /dev/null +++ b/test/test_case/irgen_lab1_4/02_sub_mul.sy @@ -0,0 +1,8 @@ +// 测试:减法和乘法 +int main() { + int a = 10; + int b = 3; + int c = a - b; + int d = a * b; + return c + d; +} diff --git a/test/test_case/irgen_lab1_4/03_div_mod.out b/test/test_case/irgen_lab1_4/03_div_mod.out new file mode 100644 index 0000000..7ed6ff8 --- /dev/null +++ b/test/test_case/irgen_lab1_4/03_div_mod.out @@ -0,0 +1 @@ +5 diff --git a/test/test_case/irgen_lab1_4/03_div_mod.sy b/test/test_case/irgen_lab1_4/03_div_mod.sy new file mode 100644 index 0000000..beefc9e --- /dev/null +++ b/test/test_case/irgen_lab1_4/03_div_mod.sy @@ -0,0 +1,8 @@ +// 测试:除法和取模 +int main() { + int a = 20; + int b = 6; + int c = a / b; + int d = a % b; + return c + d; +} diff --git a/test/test_case/irgen_lab1_4/04_unary.out b/test/test_case/irgen_lab1_4/04_unary.out new file mode 100644 index 0000000..7ed6ff8 --- /dev/null +++ b/test/test_case/irgen_lab1_4/04_unary.out @@ -0,0 +1 @@ +5 diff --git a/test/test_case/irgen_lab1_4/04_unary.sy b/test/test_case/irgen_lab1_4/04_unary.sy new file mode 100644 index 0000000..c36c5e1 --- /dev/null +++ b/test/test_case/irgen_lab1_4/04_unary.sy @@ -0,0 +1,7 @@ +// 测试:一元运算符(正负号) +int main() { + int a = 5; + int b = -a; + int c = +10; + return b + c; +} diff --git a/test/test_case/irgen_lab1_4/05_assign.out b/test/test_case/irgen_lab1_4/05_assign.out new file mode 100644 index 0000000..209e3ef --- /dev/null +++ b/test/test_case/irgen_lab1_4/05_assign.out @@ -0,0 +1 @@ +20 diff --git a/test/test_case/irgen_lab1_4/05_assign.sy b/test/test_case/irgen_lab1_4/05_assign.sy new file mode 100644 index 0000000..5e1eae2 --- /dev/null +++ b/test/test_case/irgen_lab1_4/05_assign.sy @@ -0,0 +1,7 @@ +// 测试:赋值表达式 +int main() { + int a = 10; + int b = 20; + a = b; + return a; +} diff --git a/test/test_case/irgen_lab1_4/06_multi_decl.out b/test/test_case/irgen_lab1_4/06_multi_decl.out new file mode 100644 index 0000000..1e8b314 --- /dev/null +++ b/test/test_case/irgen_lab1_4/06_multi_decl.out @@ -0,0 +1 @@ +6 diff --git a/test/test_case/irgen_lab1_4/06_multi_decl.sy b/test/test_case/irgen_lab1_4/06_multi_decl.sy new file mode 100644 index 0000000..fa95159 --- /dev/null +++ b/test/test_case/irgen_lab1_4/06_multi_decl.sy @@ -0,0 +1,5 @@ +// 测试:逗号分隔的多变量声明 +int main() { + int a = 1, b = 2, c = 3; + return a + b + c; +} diff --git a/test/test_case/irgen_lab1_4/07_comprehensive.out b/test/test_case/irgen_lab1_4/07_comprehensive.out new file mode 100644 index 0000000..81b5c5d --- /dev/null +++ b/test/test_case/irgen_lab1_4/07_comprehensive.out @@ -0,0 +1 @@ +37 diff --git a/test/test_case/irgen_lab1_4/07_comprehensive.sy b/test/test_case/irgen_lab1_4/07_comprehensive.sy new file mode 100644 index 0000000..753aeae --- /dev/null +++ b/test/test_case/irgen_lab1_4/07_comprehensive.sy @@ -0,0 +1,14 @@ +// 测试:综合测试(所有功能) +int main() { + int a = 10, b = 5; + int c = a + b; + int d = a - b; + int e = a * 2; + int f = a / b; + int g = a % b; + int h = -c; + int i = +d; + a = b + c; + b = d + e; + return a + b + f + g + h + i; +}