From 0ff3d918d9831f7d927a471e8636a75b468eede8 Mon Sep 17 00:00:00 2001 From: jing <3030349106@qq.com> Date: Tue, 3 Mar 2026 17:49:21 +0800 Subject: [PATCH] =?UTF-8?q?docs(doc):=20=E5=AE=8C=E5=96=84Lab2=E5=AE=9E?= =?UTF-8?q?=E9=AA=8C=E8=AF=B4=E6=98=8E=E4=B8=8ELLVM=E9=AA=8C=E8=AF=81?= =?UTF-8?q?=E8=84=9A=E6=9C=AC=E8=AF=B4=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 6 ++- doc/Lab2-AST到IR实验说明.md | 84 ++++++++++++++++++++++++++++++++ scripts/gen_ir.sh | 75 ---------------------------- 3 files changed, 88 insertions(+), 77 deletions(-) create mode 100644 doc/Lab2-AST到IR实验说明.md delete mode 100755 scripts/gen_ir.sh diff --git a/README.md b/README.md index 5929024..900bbea 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/gen_ir.sh` 在 `--run` 模式下会调用 LLVM 工具链(`llc` 与 `clang`)将生成的 IR 编译并运行。 +`scripts/verify_ir_with_llvm.sh` 在 `--run` 模式下会调用 LLVM 工具链(`llc` 与 `clang`)将生成的 IR 编译并运行。 ```bash sudo apt update @@ -91,5 +91,7 @@ cmake --build build -j "$(nproc)" (可选)生成 IR 并验证 LLVM 工具链是否可用: ```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`。 diff --git a/doc/Lab2-AST到IR实验说明.md b/doc/Lab2-AST到IR实验说明.md new file mode 100644 index 0000000..aa3f14c --- /dev/null +++ b/doc/Lab2-AST到IR实验说明.md @@ -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 +``` + diff --git a/scripts/gen_ir.sh b/scripts/gen_ir.sh deleted file mode 100755 index f1e7666..0000000 --- a/scripts/gen_ir.sh +++ /dev/null @@ -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 [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