docs(doc): 完善Lab2实验说明与LLVM验证脚本说明
This commit is contained in:
@@ -33,7 +33,7 @@ sudo apt install -y build-essential cmake git openjdk-11-jre
|
|||||||
|
|
||||||
### 2.3 安装 LLVM 工具链
|
### 2.3 安装 LLVM 工具链
|
||||||
|
|
||||||
`scripts/gen_ir.sh` 在 `--run` 模式下会调用 LLVM 工具链(`llc` 与 `clang`)将生成的 IR 编译并运行。
|
`scripts/verify_ir_with_llvm.sh` 在 `--run` 模式下会调用 LLVM 工具链(`llc` 与 `clang`)将生成的 IR 编译并运行。
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo apt update
|
sudo apt update
|
||||||
@@ -91,5 +91,7 @@ cmake --build build -j "$(nproc)"
|
|||||||
(可选)生成 IR 并验证 LLVM 工具链是否可用:
|
(可选)生成 IR 并验证 LLVM 工具链是否可用:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
./scripts/gen_ir.sh test/test_case/simple_add.sy out/ir --run
|
./scripts/verify_ir_with_llvm.sh test/test_case/simple_add.sy out/ir --run
|
||||||
```
|
```
|
||||||
|
|
||||||
|
兼容说明:`scripts/gen_ir.sh` 仍可使用,但作为兼容入口会转调 `verify_ir_with_llvm.sh`。
|
||||||
|
|||||||
84
doc/Lab2-AST到IR实验说明.md
Normal file
84
doc/Lab2-AST到IR实验说明.md
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
# Lab2:从 AST 生成中间表示(IR)
|
||||||
|
|
||||||
|
## 1. 本实验定位
|
||||||
|
|
||||||
|
本仓库当前提供了一个“最小可运行”的 AST -> IR 示例链路。
|
||||||
|
Lab2 的目标是在该示例基础上扩展语义覆盖范围,逐步把更多 SysY 语法正确翻译为 IR。
|
||||||
|
|
||||||
|
## 2. Lab2 要求
|
||||||
|
|
||||||
|
需要同学完成:
|
||||||
|
|
||||||
|
1. 熟悉 IR 相关数据结构与构建接口。
|
||||||
|
2. 理解当前 AST -> IR 的最小实现流程。
|
||||||
|
3. 在现有框架上扩展 IR 生成能力,使其覆盖课程要求的Sysy语法。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## 3. 当前代码框架(与 Lab2 直接相关)
|
||||||
|
|
||||||
|
1. IR 定义与打印
|
||||||
|
- `src/ir/IR.h`
|
||||||
|
- `src/ir/IRBuilder.cpp`
|
||||||
|
- `src/ir/IRPrinter.cpp`
|
||||||
|
|
||||||
|
2. AST -> IR 生成器
|
||||||
|
- `src/irgen/IRGen.h`
|
||||||
|
- `src/irgen/IRGenDriver.cpp`
|
||||||
|
- `src/irgen/IRGenFunc.cpp`
|
||||||
|
- `src/irgen/IRGenDecl.cpp`
|
||||||
|
- `src/irgen/IRGenStmt.cpp`
|
||||||
|
- `src/irgen/IRGenExp.cpp`
|
||||||
|
|
||||||
|
3. 入口流程
|
||||||
|
- `src/main.cpp`
|
||||||
|
|
||||||
|
## 4. Lab2 需要补充的内容
|
||||||
|
|
||||||
|
1. 必须修改的文件
|
||||||
|
- `src/irgen/IRGenDecl.cpp`
|
||||||
|
- `src/irgen/IRGenStmt.cpp`
|
||||||
|
- `src/irgen/IRGenExp.cpp`
|
||||||
|
- `src/ir/IR.h`(当现有 IR 指令/类型不够用时)
|
||||||
|
- `src/ir/IRBuilder.cpp`(当需要新增构建接口时)
|
||||||
|
- `src/ir/IRPrinter.cpp`(新增 IR 指令后补齐打印)
|
||||||
|
- `src/irgen/IRGen.h`(当需要扩展状态或辅助接口)
|
||||||
|
|
||||||
|
2. 视实现需要可能修改
|
||||||
|
- `src/main.cpp`(当需要调整输出阶段行为)
|
||||||
|
- `src/sem/*`(当新增语法依赖更多语义信息)
|
||||||
|
|
||||||
|
## 5. 当前最小示例实现说明
|
||||||
|
|
||||||
|
当前 AST -> IR 仅覆盖最小子集:
|
||||||
|
|
||||||
|
1. 常量整数、变量引用、二元加法表达式。
|
||||||
|
2. 局部变量声明(当前采用 LLVM 前端常见的 `alloca/load/store` 内存模型)。
|
||||||
|
3. `return` 语句。
|
||||||
|
4. 单函数 `main` 的最小流程。
|
||||||
|
|
||||||
|
|
||||||
|
说明:当前阶段变量统一采用内存模型:先 `alloca` 分配栈槽,再通过 `store/load` 读写。即使变量由常量初始化(如 `int a = 1;`),也会先 `store` 到栈槽,而不是直接把变量替换成 SSA 值。后续实验中,同学可按需求再重构。
|
||||||
|
|
||||||
|
## 6. 构建与运行
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
|
||||||
|
cmake --build build -j "$(nproc)"
|
||||||
|
```
|
||||||
|
|
||||||
|
## 7. Lab2 验证方式
|
||||||
|
|
||||||
|
项目编译后按提供测试输入回归:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./build/bin/compiler --emit-ir test/test_case/simple_add.sy
|
||||||
|
```
|
||||||
|
`
|
||||||
|
|
||||||
|
推荐使用统一脚本验证 “IR -> LLVM 后端 -> 可执行程序” 整体链路,用于验证ir的正确性:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./scripts/verify_ir_with_llvm.sh test/test_case/simple_add.sy out/ir --run
|
||||||
|
```
|
||||||
|
|
||||||
@@ -1,75 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
#./scripts/gen_ir.sh test/test_case/simple_add.sy --run
|
|
||||||
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
if [[ $# -lt 1 || $# -gt 3 ]]; then
|
|
||||||
echo "用法: $0 <input.sy> [output_dir] [--run]" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
input=$1
|
|
||||||
out_dir="out/ir"
|
|
||||||
run_exec=false
|
|
||||||
|
|
||||||
shift
|
|
||||||
while [[ $# -gt 0 ]]; do
|
|
||||||
case "$1" in
|
|
||||||
--run)
|
|
||||||
run_exec=true
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
out_dir="$1"
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
shift
|
|
||||||
done
|
|
||||||
|
|
||||||
if [[ ! -f "$input" ]]; then
|
|
||||||
echo "输入文件不存在: $input" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
compiler="./build/bin/compiler"
|
|
||||||
if [[ ! -x "$compiler" ]]; then
|
|
||||||
echo "未找到编译器: $compiler ,请先构建(如: mkdir -p build && cd build && cmake .. && make -j)" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
mkdir -p "$out_dir"
|
|
||||||
base=$(basename "$input")
|
|
||||||
stem=${base%.sy}
|
|
||||||
out_file="$out_dir/$stem.ll"
|
|
||||||
"$compiler" "$input" > "$out_file"
|
|
||||||
echo "IR 已生成: $out_file"
|
|
||||||
|
|
||||||
# 为 LLVM 使用准备纯净 IR(去掉可能的 AST 调试输出),写入同目录。
|
|
||||||
pure_file="$out_dir/$stem.ir.ll"
|
|
||||||
awk '/^define /{p=1} p' "$out_file" > "$pure_file"
|
|
||||||
|
|
||||||
if [[ ! -s "$pure_file" ]]; then
|
|
||||||
echo "警告: 未找到 IR 定义(文件可能只包含 AST 输出),未生成 $pure_file" >&2
|
|
||||||
else
|
|
||||||
echo "纯净 IR 已生成: $pure_file"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ "$run_exec" == true ]]; then
|
|
||||||
if ! command -v llc >/dev/null 2>&1; then
|
|
||||||
echo "未找到 llc,无法运行 IR。请安装 LLVM。" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
if ! command -v clang >/dev/null 2>&1; then
|
|
||||||
echo "未找到 clang,无法链接可执行文件。请安装 LLVM/Clang。" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
obj="$out_dir/$stem.o"
|
|
||||||
exe="$out_dir/$stem.exe"
|
|
||||||
llc -filetype=obj "$pure_file" -o "$obj"
|
|
||||||
clang "$obj" -o "$exe"
|
|
||||||
echo "运行 $exe ..."
|
|
||||||
set +e
|
|
||||||
"$exe"
|
|
||||||
status=$?
|
|
||||||
set -e
|
|
||||||
echo "退出码: $status"
|
|
||||||
fi
|
|
||||||
Reference in New Issue
Block a user