diff --git a/doc/lab2剩余任务分工.md b/doc/lab2剩余任务分工.md
new file mode 100644
index 0000000..70e63de
--- /dev/null
+++ b/doc/lab2剩余任务分工.md
@@ -0,0 +1,70 @@
+### 人员 1:基础表达式与赋值支持(lc,已完成)
+
+- 任务 1.1:支持更多二元运算符(Sub, Mul, Div, Mod)
+- 任务 1.2:支持一元运算符(正负号)
+- 任务 1.3:支持赋值表达式
+- 任务 1.4:支持逗号分隔的多个变量声明
+
+### 人员 2:控制流支持
+
+- 任务 2.1:支持 if-else 条件语句
+- 任务 2.2:支持 while 循环语句
+- 任务 2.3:支持 break/continue 语句
+- 任务 2.4:支持比较和逻辑表达式
+
+### 人员 3:函数与全局变量支持
+
+- 任务 3.1:支持全局变量声明与初始化
+- 任务 3.2:支持函数参数处理
+- 任务 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/include/ir/IR.h b/include/ir/IR.h
index b961192..6af2d96 100644
--- a/include/ir/IR.h
+++ b/include/ir/IR.h
@@ -152,7 +152,8 @@ class ConstantInt : public ConstantValue {
};
// 后续还需要扩展更多指令类型。
-enum class Opcode { Add, Sub, Mul, Alloca, Load, Store, Ret };
+// enum class Opcode { Add, Sub, Mul, Alloca, Load, Store, Ret };
+enum class Opcode { Add, Sub, Mul, Div, Mod, Neg, Alloca, Load, Store, Ret };
// User 是所有“会使用其他 Value 作为输入”的 IR 对象的抽象基类。
// 当前实现中只有 Instruction 继承自 User。
@@ -196,7 +197,14 @@ class BinaryInst : public Instruction {
BinaryInst(Opcode op, std::shared_ptr ty, Value* lhs, Value* rhs,
std::string name);
Value* GetLhs() const;
- Value* GetRhs() const;
+ Value* GetRhs() const;
+};
+
+class UnaryInst : public Instruction {
+ public:
+ UnaryInst(Opcode op, std::shared_ptr ty, Value* operand,
+ std::string name);
+ Value* GetUnaryOperand() const;
};
class ReturnInst : public Instruction {
@@ -300,6 +308,9 @@ class IRBuilder {
BinaryInst* CreateBinary(Opcode op, Value* lhs, Value* rhs,
const std::string& name);
BinaryInst* CreateAdd(Value* lhs, Value* rhs, const std::string& name);
+ BinaryInst* CreateSub(Value* lhs, Value* rhs, const std::string& name);
+ BinaryInst* CreateMul(Value* lhs, Value* rhs, const std::string& name);
+ UnaryInst* CreateNeg(Value* operand, const std::string& name);
AllocaInst* CreateAllocaI32(const std::string& name);
LoadInst* CreateLoad(Value* ptr, const std::string& name);
StoreInst* CreateStore(Value* val, Value* ptr);
diff --git a/include/irgen/IRGen.h b/include/irgen/IRGen.h
index 231ba90..2ed1c85 100644
--- a/include/irgen/IRGen.h
+++ b/include/irgen/IRGen.h
@@ -26,16 +26,17 @@ class IRGenImpl final : public SysYBaseVisitor {
std::any visitCompUnit(SysYParser::CompUnitContext* ctx) override;
std::any visitFuncDef(SysYParser::FuncDefContext* ctx) override;
- std::any visitBlockStmt(SysYParser::BlockStmtContext* ctx) override;
+ std::any visitBlock(SysYParser::BlockContext* ctx) override;
std::any visitBlockItem(SysYParser::BlockItemContext* ctx) override;
std::any visitDecl(SysYParser::DeclContext* ctx) override;
std::any visitStmt(SysYParser::StmtContext* ctx) override;
std::any visitVarDef(SysYParser::VarDefContext* ctx) override;
- std::any visitReturnStmt(SysYParser::ReturnStmtContext* ctx) override;
- std::any visitParenExp(SysYParser::ParenExpContext* ctx) override;
- std::any visitNumberExp(SysYParser::NumberExpContext* ctx) override;
- std::any visitVarExp(SysYParser::VarExpContext* ctx) override;
- std::any visitAdditiveExp(SysYParser::AdditiveExpContext* ctx) override;
+ std::any visitPrimaryExp(SysYParser::PrimaryExpContext* ctx) override;
+ std::any visitNumber(SysYParser::NumberContext* ctx) override;
+ std::any visitLVal(SysYParser::LValContext* ctx) override;
+ std::any visitAddExp(SysYParser::AddExpContext* ctx) override;
+ std::any visitMulExp(SysYParser::MulExpContext* ctx) override;
+ std::any visitUnaryExp(SysYParser::UnaryExpContext* ctx) override;
private:
enum class BlockFlow {
@@ -50,8 +51,8 @@ class IRGenImpl final : public SysYBaseVisitor {
const SemanticContext& sema_;
ir::Function* func_;
ir::IRBuilder builder_;
- // 名称绑定由 Sema 负责;IRGen 只维护“声明 -> 存储槽位”的代码生成状态。
- std::unordered_map storage_map_;
+ // 名称绑定由 Sema 负责;IRGen 只维护"变量名 -> 存储槽位"的代码生成状态。
+ std::unordered_map storage_map_;
};
std::unique_ptr GenerateIR(SysYParser::CompUnitContext& tree,
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/src/ir/IRBuilder.cpp b/src/ir/IRBuilder.cpp
index 90f03c4..54cc5d2 100644
--- a/src/ir/IRBuilder.cpp
+++ b/src/ir/IRBuilder.cpp
@@ -86,4 +86,22 @@ ReturnInst* IRBuilder::CreateRet(Value* v) {
return insert_block_->Append(Type::GetVoidType(), v);
}
+BinaryInst* IRBuilder::CreateSub(Value* lhs, Value* rhs, const std::string& name) {
+ return CreateBinary(Opcode::Sub, lhs, rhs, name);
+}
+
+BinaryInst* IRBuilder::CreateMul(Value* lhs, Value* rhs, const std::string& name) {
+ return CreateBinary(Opcode::Mul, lhs, rhs, name);
+}
+
+UnaryInst* IRBuilder::CreateNeg(Value* operand, const std::string& name) {
+ if (!insert_block_) {
+ throw std::runtime_error(FormatError("ir", "IRBuilder 未设置插入点"));
+ }
+ if (!operand) {
+ throw std::runtime_error(FormatError("ir", "IRBuilder::CreateNeg 缺少操作数"));
+ }
+ return insert_block_->Append(Opcode::Neg, Type::GetInt32Type(), operand, name);
+}
+
} // namespace ir
diff --git a/src/ir/IRPrinter.cpp b/src/ir/IRPrinter.cpp
index 30efbb6..3716751 100644
--- a/src/ir/IRPrinter.cpp
+++ b/src/ir/IRPrinter.cpp
@@ -32,6 +32,12 @@ static const char* OpcodeToString(Opcode op) {
return "sub";
case Opcode::Mul:
return "mul";
+ case Opcode::Div:
+ return "sdiv";
+ case Opcode::Mod:
+ return "srem";
+ case Opcode::Neg:
+ return "neg";
case Opcode::Alloca:
return "alloca";
case Opcode::Load:
@@ -65,7 +71,9 @@ void IRPrinter::Print(const Module& module, std::ostream& os) {
switch (inst->GetOpcode()) {
case Opcode::Add:
case Opcode::Sub:
- case Opcode::Mul: {
+ case Opcode::Mul:
+ case Opcode::Div:
+ case Opcode::Mod: {
auto* bin = static_cast(inst);
os << " " << bin->GetName() << " = "
<< OpcodeToString(bin->GetOpcode()) << " "
@@ -74,6 +82,14 @@ void IRPrinter::Print(const Module& module, std::ostream& os) {
<< ValueToString(bin->GetRhs()) << "\n";
break;
}
+ case Opcode::Neg: {
+ auto* unary = static_cast(inst);
+ os << " " << unary->GetName() << " = "
+ << OpcodeToString(unary->GetOpcode()) << " "
+ << TypeToString(*unary->GetUnaryOperand()->GetType()) << " "
+ << ValueToString(unary->GetUnaryOperand()) << "\n";
+ break;
+ }
case Opcode::Alloca: {
auto* alloca = static_cast(inst);
os << " " << alloca->GetName() << " = alloca i32\n";
diff --git a/src/ir/Instruction.cpp b/src/ir/Instruction.cpp
index 7928716..199b123 100644
--- a/src/ir/Instruction.cpp
+++ b/src/ir/Instruction.cpp
@@ -61,8 +61,9 @@ void Instruction::SetParent(BasicBlock* parent) { parent_ = parent; }
BinaryInst::BinaryInst(Opcode op, std::shared_ptr ty, Value* lhs,
Value* rhs, std::string name)
: Instruction(op, std::move(ty), std::move(name)) {
- if (op != Opcode::Add) {
- throw std::runtime_error(FormatError("ir", "BinaryInst 当前只支持 Add"));
+ if (op != Opcode::Add && op != Opcode::Sub && op != Opcode::Mul &&
+ op != Opcode::Div && op != Opcode::Mod) {
+ throw std::runtime_error(FormatError("ir", "BinaryInst 不支持的操作码"));
}
if (!lhs || !rhs) {
throw std::runtime_error(FormatError("ir", "BinaryInst 缺少操作数"));
@@ -85,6 +86,29 @@ Value* BinaryInst::GetLhs() const { return GetOperand(0); }
Value* BinaryInst::GetRhs() const { return GetOperand(1); }
+UnaryInst::UnaryInst(Opcode op, std::shared_ptr ty, Value* operand,
+ std::string name)
+ : Instruction(op, std::move(ty), std::move(name)) {
+ if (op != Opcode::Neg) {
+ throw std::runtime_error(FormatError("ir", "UnaryInst 不支持的操作码"));
+ }
+ if (!operand) {
+ throw std::runtime_error(FormatError("ir", "UnaryInst 缺少操作数"));
+ }
+ if (!type_ || !operand->GetType()) {
+ throw std::runtime_error(FormatError("ir", "UnaryInst 缺少类型信息"));
+ }
+ if (type_->GetKind() != operand->GetType()->GetKind()) {
+ throw std::runtime_error(FormatError("ir", "UnaryInst 类型不匹配"));
+ }
+ if (!type_->IsInt32()) {
+ throw std::runtime_error(FormatError("ir", "UnaryInst 当前只支持 i32"));
+ }
+ AddOperand(operand);
+}
+
+Value* UnaryInst::GetUnaryOperand() const { return GetOperand(0); }
+
ReturnInst::ReturnInst(std::shared_ptr void_ty, Value* val)
: Instruction(Opcode::Ret, std::move(void_ty), "") {
if (!val) {
diff --git a/src/irgen/IRGenDecl.cpp b/src/irgen/IRGenDecl.cpp
index 0eb62ae..df7ccf9 100644
--- a/src/irgen/IRGenDecl.cpp
+++ b/src/irgen/IRGenDecl.cpp
@@ -6,18 +6,7 @@
#include "ir/IR.h"
#include "utils/Log.h"
-namespace {
-
-std::string GetLValueName(SysYParser::LValueContext& lvalue) {
- if (!lvalue.ID()) {
- throw std::runtime_error(FormatError("irgen", "非法左值"));
- }
- return lvalue.ID()->getText();
-}
-
-} // namespace
-
-std::any IRGenImpl::visitBlockStmt(SysYParser::BlockStmtContext* ctx) {
+std::any IRGenImpl::visitBlock(SysYParser::BlockContext* ctx) {
if (!ctx) {
throw std::runtime_error(FormatError("irgen", "缺少语句块"));
}
@@ -63,14 +52,20 @@ std::any IRGenImpl::visitDecl(SysYParser::DeclContext* ctx) {
if (!ctx) {
throw std::runtime_error(FormatError("irgen", "缺少变量声明"));
}
- if (!ctx->btype() || !ctx->btype()->INT()) {
+ // 当前语法中 decl 包含 constDecl 或 varDecl,这里只支持 varDecl
+ auto* var_decl = ctx->varDecl();
+ if (!var_decl) {
+ throw std::runtime_error(FormatError("irgen", "当前仅支持变量声明"));
+ }
+ if (!var_decl->bType() || !var_decl->bType()->INT()) {
throw std::runtime_error(FormatError("irgen", "当前仅支持局部 int 变量声明"));
}
- auto* var_def = ctx->varDef();
- if (!var_def) {
- throw std::runtime_error(FormatError("irgen", "非法变量声明"));
+ // 遍历所有 varDef
+ for (auto* var_def : var_decl->varDef()) {
+ if (var_def) {
+ var_def->accept(this);
+ }
}
- var_def->accept(this);
return {};
}
@@ -83,22 +78,26 @@ std::any IRGenImpl::visitVarDef(SysYParser::VarDefContext* ctx) {
if (!ctx) {
throw std::runtime_error(FormatError("irgen", "缺少变量定义"));
}
- if (!ctx->lValue()) {
+ if (!ctx->ID()) {
throw std::runtime_error(FormatError("irgen", "变量声明缺少名称"));
}
- GetLValueName(*ctx->lValue());
- if (storage_map_.find(ctx) != storage_map_.end()) {
+ // 暂不支持数组声明(constIndex)
+ if (!ctx->constIndex().empty()) {
+ throw std::runtime_error(FormatError("irgen", "暂不支持数组声明"));
+ }
+ std::string var_name = ctx->ID()->getText();
+ if (storage_map_.find(var_name) != storage_map_.end()) {
throw std::runtime_error(FormatError("irgen", "声明重复生成存储槽位"));
}
auto* slot = builder_.CreateAllocaI32(module_.GetContext().NextTemp());
- storage_map_[ctx] = slot;
+ storage_map_[var_name] = slot;
ir::Value* init = nullptr;
- if (auto* init_value = ctx->initValue()) {
- if (!init_value->exp()) {
+ if (auto* init_val = ctx->initVal()) {
+ if (!init_val->exp()) {
throw std::runtime_error(FormatError("irgen", "当前不支持聚合初始化"));
}
- init = EvalExpr(*init_value->exp());
+ init = EvalExpr(*init_val->exp());
} else {
init = builder_.CreateConstInt(0);
}
diff --git a/src/irgen/IRGenExp.cpp b/src/irgen/IRGenExp.cpp
index cf4797c..55c3cc2 100644
--- a/src/irgen/IRGenExp.cpp
+++ b/src/irgen/IRGenExp.cpp
@@ -25,20 +25,51 @@ ir::Value* IRGenImpl::EvalExpr(SysYParser::ExpContext& expr) {
}
-std::any IRGenImpl::visitParenExp(SysYParser::ParenExpContext* ctx) {
- if (!ctx || !ctx->exp()) {
- throw std::runtime_error(FormatError("irgen", "非法括号表达式"));
+std::any IRGenImpl::visitPrimaryExp(SysYParser::PrimaryExpContext* ctx) {
+ if (!ctx) {
+ throw std::runtime_error(FormatError("irgen", "非法基本表达式"));
}
- return EvalExpr(*ctx->exp());
+ // 处理括号表达式:LPAREN exp RPAREN
+ if (ctx->exp()) {
+ return EvalExpr(*ctx->exp());
+ }
+ // 处理 lVal(变量使用)- 交给 visitLVal 处理
+ if (ctx->lVal()) {
+ // 直接在这里处理变量读取,避免 accept 调用可能导致的问题
+ auto* lval_ctx = ctx->lVal();
+ if (!lval_ctx || !lval_ctx->ID()) {
+ throw std::runtime_error(FormatError("irgen", "当前仅支持普通整型变量"));
+ }
+ const auto* decl = sema_.ResolveObjectUse(lval_ctx);
+ if (!decl) {
+ throw std::runtime_error(
+ FormatError("irgen",
+ "变量使用缺少语义绑定:" + lval_ctx->ID()->getText()));
+ }
+ std::string var_name = lval_ctx->ID()->getText();
+ auto it = storage_map_.find(var_name);
+ if (it == storage_map_.end()) {
+ throw std::runtime_error(
+ FormatError("irgen",
+ "变量声明缺少存储槽位:" + var_name));
+ }
+ return static_cast(
+ builder_.CreateLoad(it->second, module_.GetContext().NextTemp()));
+ }
+ // 处理 number
+ if (ctx->number()) {
+ return ctx->number()->accept(this);
+ }
+ throw std::runtime_error(FormatError("irgen", "不支持的基本表达式类型"));
}
-std::any IRGenImpl::visitNumberExp(SysYParser::NumberExpContext* ctx) {
- if (!ctx || !ctx->number() || !ctx->number()->ILITERAL()) {
+std::any IRGenImpl::visitNumber(SysYParser::NumberContext* ctx) {
+ if (!ctx || !ctx->intConst()) {
throw std::runtime_error(FormatError("irgen", "当前仅支持整数字面量"));
}
return static_cast(
- builder_.CreateConstInt(std::stoi(ctx->number()->getText())));
+ builder_.CreateConstInt(std::stoi(ctx->intConst()->getText())));
}
// 变量使用的处理流程:
@@ -47,34 +78,127 @@ std::any IRGenImpl::visitNumberExp(SysYParser::NumberExpContext* ctx) {
// 3. 最后生成 load,把内存中的值读出来。
//
// 因此当前 IRGen 自己不再做名字查找,而是直接消费 Sema 的绑定结果。
-std::any IRGenImpl::visitVarExp(SysYParser::VarExpContext* ctx) {
- if (!ctx || !ctx->var() || !ctx->var()->ID()) {
+std::any IRGenImpl::visitLVal(SysYParser::LValContext* ctx) {
+ if (!ctx || !ctx->ID()) {
throw std::runtime_error(FormatError("irgen", "当前仅支持普通整型变量"));
}
- auto* decl = sema_.ResolveVarUse(ctx->var());
+ const auto* decl = sema_.ResolveObjectUse(ctx);
if (!decl) {
throw std::runtime_error(
FormatError("irgen",
- "变量使用缺少语义绑定: " + ctx->var()->ID()->getText()));
+ "变量使用缺少语义绑定:" + ctx->ID()->getText()));
}
- auto it = storage_map_.find(decl);
+ // 使用变量名查找存储槽位
+ std::string var_name = ctx->ID()->getText();
+ auto it = storage_map_.find(var_name);
if (it == storage_map_.end()) {
throw std::runtime_error(
FormatError("irgen",
- "变量声明缺少存储槽位: " + ctx->var()->ID()->getText()));
+ "变量声明缺少存储槽位:" + var_name));
}
return static_cast(
builder_.CreateLoad(it->second, module_.GetContext().NextTemp()));
}
-std::any IRGenImpl::visitAdditiveExp(SysYParser::AdditiveExpContext* ctx) {
- if (!ctx || !ctx->exp(0) || !ctx->exp(1)) {
- throw std::runtime_error(FormatError("irgen", "非法加法表达式"));
+std::any IRGenImpl::visitAddExp(SysYParser::AddExpContext* ctx) {
+ if (!ctx) {
+ throw std::runtime_error(FormatError("irgen", "非法加减法表达式"));
+ }
+
+ // 如果是 mulExp 直接返回(addExp : mulExp)
+ if (ctx->mulExp() && ctx->addExp() == nullptr) {
+ return ctx->mulExp()->accept(this);
+ }
+
+ // 处理 addExp op mulExp 的递归形式
+ if (!ctx->addExp() || !ctx->mulExp()) {
+ throw std::runtime_error(FormatError("irgen", "非法加减法表达式结构"));
}
- ir::Value* lhs = EvalExpr(*ctx->exp(0));
- ir::Value* rhs = EvalExpr(*ctx->exp(1));
+
+ ir::Value* lhs = std::any_cast(ctx->addExp()->accept(this));
+ ir::Value* rhs = std::any_cast(ctx->mulExp()->accept(this));
+
+ ir::Opcode op = ir::Opcode::Add;
+ if (ctx->ADD()) {
+ op = ir::Opcode::Add;
+ } else if (ctx->SUB()) {
+ op = ir::Opcode::Sub;
+ } else {
+ throw std::runtime_error(FormatError("irgen", "未知的加减运算符"));
+ }
+
return static_cast(
- builder_.CreateBinary(ir::Opcode::Add, lhs, rhs,
- module_.GetContext().NextTemp()));
+ builder_.CreateBinary(op, lhs, rhs, module_.GetContext().NextTemp()));
}
+
+
+std::any IRGenImpl::visitUnaryExp(SysYParser::UnaryExpContext* ctx) {
+ if (!ctx) {
+ throw std::runtime_error(FormatError("irgen", "非法一元表达式"));
+ }
+
+ // 如果是 primaryExp 直接返回(unaryExp : primaryExp)
+ if (ctx->primaryExp()) {
+ return ctx->primaryExp()->accept(this);
+ }
+
+ // 处理函数调用(unaryExp : ID LPAREN funcRParams? RPAREN)
+ // 当前暂不支持,留给后续扩展
+ if (ctx->ID()) {
+ throw std::runtime_error(FormatError("irgen", "暂不支持函数调用"));
+ }
+
+ // 处理一元运算符(unaryExp : addUnaryOp unaryExp)
+ if (ctx->addUnaryOp() && ctx->unaryExp()) {
+ ir::Value* operand = std::any_cast(ctx->unaryExp()->accept(this));
+
+ // 判断是正号还是负号
+ if (ctx->addUnaryOp()->SUB()) {
+ // 负号:生成 sub 0, operand(LLVM IR 中没有 neg 指令)
+ ir::Value* zero = builder_.CreateConstInt(0);
+ return static_cast(
+ builder_.CreateSub(zero, operand, module_.GetContext().NextTemp()));
+ } else if (ctx->addUnaryOp()->ADD()) {
+ // 正号:直接返回操作数(+x 等价于 x)
+ return operand;
+ } else {
+ throw std::runtime_error(FormatError("irgen", "未知的一元运算符"));
+ }
+ }
+
+ throw std::runtime_error(FormatError("irgen", "不支持的一元表达式类型"));
+}
+
+std::any IRGenImpl::visitMulExp(SysYParser::MulExpContext* ctx) {
+ if (!ctx) {
+ throw std::runtime_error(FormatError("irgen", "非法乘除法表达式"));
+ }
+
+ // 如果是 unaryExp 直接返回(mulExp : unaryExp)
+ if (ctx->unaryExp() && ctx->mulExp() == nullptr) {
+ return ctx->unaryExp()->accept(this);
+ }
+
+ // 处理 mulExp op unaryExp 的递归形式
+ if (!ctx->mulExp() || !ctx->unaryExp()) {
+ throw std::runtime_error(FormatError("irgen", "非法乘除法表达式结构"));
+ }
+
+ ir::Value* lhs = std::any_cast(ctx->mulExp()->accept(this));
+ ir::Value* rhs = std::any_cast(ctx->unaryExp()->accept(this));
+
+ ir::Opcode op = ir::Opcode::Mul;
+ if (ctx->MUL()) {
+ op = ir::Opcode::Mul;
+ } else if (ctx->DIV()) {
+ op = ir::Opcode::Div;
+ } else if (ctx->MOD()) {
+ op = ir::Opcode::Mod;
+ } else {
+ throw std::runtime_error(FormatError("irgen", "未知的乘除运算符"));
+ }
+
+ return static_cast(
+ builder_.CreateBinary(op, lhs, rhs, module_.GetContext().NextTemp()));
+}
\ No newline at end of file
diff --git a/src/irgen/IRGenFunc.cpp b/src/irgen/IRGenFunc.cpp
index 4912d03..4ee5b3e 100644
--- a/src/irgen/IRGenFunc.cpp
+++ b/src/irgen/IRGenFunc.cpp
@@ -29,7 +29,7 @@ IRGenImpl::IRGenImpl(ir::Module& module, const SemanticContext& sema)
// 编译单元的 IR 生成当前只实现了最小功能:
// - Module 已在 GenerateIR 中创建,这里只负责继续生成其中的内容;
-// - 当前会读取编译单元中的函数定义,并交给 visitFuncDef 生成函数 IR;
+// - 当前会读取编译单元中的 topLevelItem,找到 funcDef 后生成函数 IR;
//
// 当前还没有实现:
// - 多个函数定义的遍历与生成;
@@ -38,12 +38,15 @@ std::any IRGenImpl::visitCompUnit(SysYParser::CompUnitContext* ctx) {
if (!ctx) {
throw std::runtime_error(FormatError("irgen", "缺少编译单元"));
}
- auto* func = ctx->funcDef();
- if (!func) {
- throw std::runtime_error(FormatError("irgen", "缺少函数定义"));
+ // 遍历所有 topLevelItem,找到 funcDef
+ for (auto* item : ctx->topLevelItem()) {
+ if (item && item->funcDef()) {
+ item->funcDef()->accept(this);
+ // 当前只支持单个函数,找到第一个后就返回
+ return {};
+ }
}
- func->accept(this);
- return {};
+ throw std::runtime_error(FormatError("irgen", "缺少函数定义"));
}
// 函数 IR 生成当前实现了:
@@ -61,12 +64,11 @@ std::any IRGenImpl::visitCompUnit(SysYParser::CompUnitContext* ctx) {
// - 入口块中的参数初始化逻辑。
// ...
-// 因此这里目前只支持最小的“无参 int 函数”生成。
std::any IRGenImpl::visitFuncDef(SysYParser::FuncDefContext* ctx) {
if (!ctx) {
throw std::runtime_error(FormatError("irgen", "缺少函数定义"));
}
- if (!ctx->blockStmt()) {
+ if (!ctx->block()) {
throw std::runtime_error(FormatError("irgen", "函数体为空"));
}
if (!ctx->ID()) {
@@ -80,7 +82,7 @@ std::any IRGenImpl::visitFuncDef(SysYParser::FuncDefContext* ctx) {
builder_.SetInsertPoint(func_->GetEntry());
storage_map_.clear();
- ctx->blockStmt()->accept(this);
+ ctx->block()->accept(this);
// 语义正确性主要由 sema 保证,这里只兜底检查 IR 结构是否合法。
VerifyFunctionStructure(*func_);
return {};
diff --git a/src/irgen/IRGenStmt.cpp b/src/irgen/IRGenStmt.cpp
index 751550c..de6a857 100644
--- a/src/irgen/IRGenStmt.cpp
+++ b/src/irgen/IRGenStmt.cpp
@@ -9,9 +9,9 @@
// 语句生成当前只实现了最小子集。
// 目前支持:
// - return ;
+// - 赋值语句:lVal = exp;
//
// 还未支持:
-// - 赋值语句
// - if / while 等控制流
// - 空语句、块语句嵌套分发之外的更多语句形态
@@ -19,21 +19,51 @@ std::any IRGenImpl::visitStmt(SysYParser::StmtContext* ctx) {
if (!ctx) {
throw std::runtime_error(FormatError("irgen", "缺少语句"));
}
- if (ctx->returnStmt()) {
- return ctx->returnStmt()->accept(this);
+
+ // 检查是否是赋值语句:lVal ASSIGN exp SEMICOLON
+ if (ctx->lVal() && ctx->ASSIGN()) {
+ if (!ctx->exp()) {
+ throw std::runtime_error(FormatError("irgen", "赋值语句缺少表达式"));
+ }
+
+ // 1. 计算右值表达式的值
+ ir::Value* rhs = EvalExpr(*ctx->exp());
+
+ // 2. 找到左值变量对应的存储槽位
+ auto* lval_ctx = ctx->lVal();
+ if (!lval_ctx || !lval_ctx->ID()) {
+ throw std::runtime_error(FormatError("irgen", "当前仅支持普通整型变量赋值"));
+ }
+
+ const auto* decl = sema_.ResolveObjectUse(lval_ctx);
+ if (!decl) {
+ throw std::runtime_error(
+ FormatError("irgen",
+ "变量使用缺少语义绑定:" + lval_ctx->ID()->getText()));
+ }
+
+ std::string var_name = lval_ctx->ID()->getText();
+ auto it = storage_map_.find(var_name);
+ if (it == storage_map_.end()) {
+ throw std::runtime_error(
+ FormatError("irgen",
+ "变量声明缺少存储槽位:" + var_name));
+ }
+
+ // 3. 生成 store 指令
+ builder_.CreateStore(rhs, it->second);
+ return BlockFlow::Continue;
}
- throw std::runtime_error(FormatError("irgen", "暂不支持的语句类型"));
-}
-
-
-std::any IRGenImpl::visitReturnStmt(SysYParser::ReturnStmtContext* ctx) {
- if (!ctx) {
- throw std::runtime_error(FormatError("irgen", "缺少 return 语句"));
- }
- if (!ctx->exp()) {
- throw std::runtime_error(FormatError("irgen", "return 缺少表达式"));
+
+ // 检查是否是 return 语句:RETURN exp? SEMICOLON
+ if (ctx->RETURN()) {
+ if (!ctx->exp()) {
+ throw std::runtime_error(FormatError("irgen", "return 缺少表达式"));
+ }
+ ir::Value* v = EvalExpr(*ctx->exp());
+ builder_.CreateRet(v);
+ return BlockFlow::Terminated;
}
- ir::Value* v = EvalExpr(*ctx->exp());
- builder_.CreateRet(v);
- return BlockFlow::Terminated;
+
+ throw std::runtime_error(FormatError("irgen", "暂不支持的语句类型"));
}
diff --git a/src/sem/Sema.cpp b/src/sem/Sema.cpp
index f0b49e5..fc73f9d 100644
--- a/src/sem/Sema.cpp
+++ b/src/sem/Sema.cpp
@@ -434,9 +434,11 @@ class SemaVisitor final : public SysYBaseVisitor {
if (!ctx) {
ThrowSemaError(ctx, "非法乘法表达式");
}
- if (ctx->unaryExp()) {
+ // 如果是 mulExp : unaryExp 形式(没有 MUL/DIV/MOD token),直接处理 unaryExp
+ if (!ctx->MUL() && !ctx->DIV() && !ctx->MOD()) {
return EvalExpr(*ctx->unaryExp());
}
+ // 否则是 mulExp MUL/DIV/MOD unaryExp 形式
ExprInfo lhs = EvalExpr(*ctx->mulExp());
ExprInfo rhs = EvalExpr(*ctx->unaryExp());
return EvalArithmetic(*ctx, lhs, rhs, ctx->MUL() ? '*' : (ctx->DIV() ? '/' : '%'));
@@ -446,9 +448,11 @@ class SemaVisitor final : public SysYBaseVisitor {
if (!ctx) {
ThrowSemaError(ctx, "非法加法表达式");
}
- if (ctx->mulExp()) {
+ // 如果是 addExp : mulExp 形式(没有 ADD/SUB token),直接处理 mulExp
+ if (!ctx->ADD() && !ctx->SUB()) {
return EvalExpr(*ctx->mulExp());
}
+ // 否则是 addExp ADD/SUB mulExp 形式
ExprInfo lhs = EvalExpr(*ctx->addExp());
ExprInfo rhs = EvalExpr(*ctx->mulExp());
return EvalArithmetic(*ctx, lhs, rhs, ctx->ADD() ? '+' : '-');
@@ -544,7 +548,7 @@ class SemaVisitor final : public SysYBaseVisitor {
const std::string name = ctx.ID()->getText();
const ObjectBinding* symbol = symbols_.Lookup(name);
if (!symbol) {
- ThrowSemaError(&ctx, "使用了未声明的标识符: " + name);
+ ThrowSemaError(&ctx, "使用了未声明的标识符:" + name);
}
sema_.BindObjectUse(&ctx, *symbol);
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;
+}