lc #2

Merged
p5tlr2yxg merged 6 commits from lc into master 1 week ago

@ -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 常量声明
<br />
<br />
## 人员 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`
后续人员可以在此基础上扩展更复杂的功能(控制流、函数调用等)。

@ -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<Type> 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<Type> 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);

@ -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<SysYParser::VarDefContext*, ir::Value*> storage_map_;
// 名称绑定由 Sema 负责IRGen 只维护"变量名 -> 存储槽位"的代码生成状态。
std::unordered_map<std::string, ir::Value*> storage_map_;
};
std::unique_ptr<ir::Module> GenerateIR(SysYParser::CompUnitContext& tree,

@ -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

@ -86,4 +86,22 @@ ReturnInst* IRBuilder::CreateRet(Value* v) {
return insert_block_->Append<ReturnInst>(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<UnaryInst>(Opcode::Neg, Type::GetInt32Type(), operand, name);
}
} // namespace ir

@ -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<const BinaryInst*>(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<const UnaryInst*>(inst);
os << " " << unary->GetName() << " = "
<< OpcodeToString(unary->GetOpcode()) << " "
<< TypeToString(*unary->GetUnaryOperand()->GetType()) << " "
<< ValueToString(unary->GetUnaryOperand()) << "\n";
break;
}
case Opcode::Alloca: {
auto* alloca = static_cast<const AllocaInst*>(inst);
os << " " << alloca->GetName() << " = alloca i32\n";

@ -61,8 +61,9 @@ void Instruction::SetParent(BasicBlock* parent) { parent_ = parent; }
BinaryInst::BinaryInst(Opcode op, std::shared_ptr<Type> 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<Type> 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<Type> void_ty, Value* val)
: Instruction(Opcode::Ret, std::move(void_ty), "") {
if (!val) {

@ -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);
}

@ -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<ir::Value*>(
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<ir::Value*>(
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<ir::Value*>(
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<ir::Value*>(ctx->addExp()->accept(this));
ir::Value* rhs = std::any_cast<ir::Value*>(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<ir::Value*>(
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<ir::Value*>(ctx->unaryExp()->accept(this));
// 判断是正号还是负号
if (ctx->addUnaryOp()->SUB()) {
// 负号:生成 sub 0, operandLLVM IR 中没有 neg 指令)
ir::Value* zero = builder_.CreateConstInt(0);
return static_cast<ir::Value*>(
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<ir::Value*>(ctx->mulExp()->accept(this));
ir::Value* rhs = std::any_cast<ir::Value*>(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<ir::Value*>(
builder_.CreateBinary(op, lhs, rhs, module_.GetContext().NextTemp()));
}

@ -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 {};

@ -9,9 +9,9 @@
// 语句生成当前只实现了最小子集。
// 目前支持:
// - return <exp>;
// - 赋值语句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", "暂不支持的语句类型"));
}

@ -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);

@ -0,0 +1,6 @@
// 测试:简单加法
int main() {
int a = 1;
int b = 2;
return a + b;
}

@ -0,0 +1,8 @@
// 测试:减法和乘法
int main() {
int a = 10;
int b = 3;
int c = a - b;
int d = a * b;
return c + d;
}

@ -0,0 +1,8 @@
// 测试:除法和取模
int main() {
int a = 20;
int b = 6;
int c = a / b;
int d = a % b;
return c + d;
}

@ -0,0 +1,7 @@
// 测试:一元运算符(正负号)
int main() {
int a = 5;
int b = -a;
int c = +10;
return b + c;
}

@ -0,0 +1,7 @@
// 测试:赋值表达式
int main() {
int a = 10;
int b = 20;
a = b;
return a;
}

@ -0,0 +1,5 @@
// 测试:逗号分隔的多变量声明
int main() {
int a = 1, b = 2, c = 3;
return a + b + c;
}

@ -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;
}
Loading…
Cancel
Save