Merge pull request 'lyy' (#3) from lyy into master

Reviewed-on: #3
Reviewed-by: p5tlr2yxg <dyz516@nudt.edu.cn>
master
p5tlr2yxg 1 week ago
commit 79756970ef

1
.gitignore vendored

@ -68,3 +68,4 @@ Thumbs.db
# Project outputs
# =========================
test/test_result/
sema_check

@ -5,7 +5,7 @@
- 任务 1.3:支持赋值表达式
- 任务 1.4:支持逗号分隔的多个变量声明
### 人员 2控制流支持
### 人员 2控制流支持lyy,已完成)
- 任务 2.1:支持 if-else 条件语句
- 任务 2.2:支持 while 循环语句
@ -19,10 +19,6 @@
- 任务 3.3:支持函数调用生成
- 任务 3.4:支持 const 常量声明
<br />
<br />
## 人员 1 完成情况详细说明(更新于 2026-03-30
### ✅ 已完成任务
@ -68,3 +64,39 @@
- **IR 构建**`IRBuilder::CreateBinary`, `IRBuilder::CreateNeg`, `IRBuilder::CreateStore`
后续人员可以在此基础上扩展更复杂的功能(控制流、函数调用等)。
## 人员 2 完成情况详细说明(更新于 2026-03-31
### ✅ 已完成任务
人员 2 已完整实现 Lab2 IR 生成中涉及的控制流支持,包括:
1. **IR 结构与底层辅助拓展**
- 补充 `Int1` 基础类型以及 `Value::IsInt1()`
- 新增 `CmpInst`, `ZextInst`, `BranchInst` 以及 `CondBranchInst` 以支持关系计算和跳转逻辑。
- 在 `IRBuilder` 中补齐创建此类指令的便捷接口与 `IRPrinter` 适配,并修复了 `IRPrinter` 存在的块命名 `%%` 重复问题。
- 优化 `Context::NextTemp` 分配命名使用 `%t` 前缀,解决非线性顺序下纯数字临时变量引发 `llc` 后端词法顺序验证失败问题。
2. **比较和逻辑表达式**(任务 2.4
- 新增实现 `visitRelExp`、`visitEqExp`。
- 实现条件二元表达式全链路短路求值 (`visitLAndExp`、`visitLOrExp`)。短路时通过控制流跳转+利用局部栈变量分配并多次赋值记录实现栈传递,规避了 `phi` 的麻烦。
- 利用 `visitCondUnaryExp` 增加逻辑非 `!` 判定。
3. **控制流框架支持**(任务 2.1 - 2.3
- 在 `visitStmt` 中完美实现了 `if-else` 条件语句(自动插入无条件跳合块)、`while` 循环语句。
- 在 `IRGen` 实例中通过 `current_loop_cond_bb_` 等维护循环栈,实现了 `break``continue`
- 修复了此前框架在 `IRGenDecl.cpp``visitBlock` 中缺少终结向上传递导致的 `break` 生成不匹配死块 BUG 及重复 `Branch` 问题。
4. **关键前序 Bug 修复**
- 发现了在原框架里 `src/sem/Sema.cpp` 进行 AST 解析时 `RelExp``EqExp` 对于非原生底层变量追踪由于左偏漏调规则导致 `null_ptr` (`变量使用缺少语义绑定a`) 报错的问题,并做出了精修复。
### 🧪 测试验证
- **Lab2 语义分析**:修复后所有已有的语义正例验证正常。
- **IR 生成与后端执行**:✅ 自建嵌套含复合逻辑循环脚本测试通过。
- **验证命令**(运行含 break 和 while 的范例文件):
```bash
cd build && make -j$(nproc) && cd .. && ./scripts/verify_ir.sh test/test_case/functional/29_break.sy --run
```
**完整测试脚本**
```bash
for f in test/test_case/functional/*.sy; do echo "Testing $f..."; ./scripts/verify_ir.sh "$f" --run > /dev/null || echo "FAILED $f"; done
```

@ -93,16 +93,18 @@ class Context {
class Type {
public:
enum class Kind { Void, Int32, PtrInt32 };
enum class Kind { Void, Int1, Int32, PtrInt32 };
explicit Type(Kind k);
// 使用静态共享对象获取类型。
// 同一类型可直接比较返回值是否相等,例如:
// Type::GetInt32Type() == Type::GetInt32Type()
static const std::shared_ptr<Type>& GetVoidType();
static const std::shared_ptr<Type>& GetInt1Type();
static const std::shared_ptr<Type>& GetInt32Type();
static const std::shared_ptr<Type>& GetPtrInt32Type();
Kind GetKind() const;
bool IsVoid() const;
bool IsInt1() const;
bool IsInt32() const;
bool IsPtrInt32() const;
@ -118,6 +120,7 @@ class Value {
const std::string& GetName() const;
void SetName(std::string n);
bool IsVoid() const;
bool IsInt1() const;
bool IsInt32() const;
bool IsPtrInt32() const;
bool IsConstant() const;
@ -153,7 +156,9 @@ class ConstantInt : public ConstantValue {
// 后续还需要扩展更多指令类型。
// enum class Opcode { Add, Sub, Mul, Alloca, Load, Store, Ret };
enum class Opcode { Add, Sub, Mul, Div, Mod, Neg, Alloca, Load, Store, Ret };
enum class Opcode { Add, Sub, Mul, Div, Mod, Neg, Alloca, Load, Store, Ret, Cmp, Zext, Br, CondBr };
enum class CmpOp { Eq, Ne, Lt, Gt, Le, Ge };
// User 是所有“会使用其他 Value 作为输入”的 IR 对象的抽象基类。
// 当前实现中只有 Instruction 继承自 User。
@ -231,6 +236,37 @@ class StoreInst : public Instruction {
Value* GetPtr() const;
};
class CmpInst : public Instruction {
public:
CmpInst(CmpOp cmp_op, Value* lhs, Value* rhs, std::string name);
CmpOp GetCmpOp() const;
Value* GetLhs() const;
Value* GetRhs() const;
private:
CmpOp cmp_op_;
};
class ZextInst : public Instruction {
public:
ZextInst(std::shared_ptr<Type> dest_ty, Value* val, std::string name);
Value* GetValue() const;
};
class BranchInst : public Instruction {
public:
BranchInst(BasicBlock* dest);
BasicBlock* GetDest() const;
};
class CondBranchInst : public Instruction {
public:
CondBranchInst(Value* cond, BasicBlock* true_bb, BasicBlock* false_bb);
Value* GetCond() const;
BasicBlock* GetTrueBlock() const;
BasicBlock* GetFalseBlock() const;
};
// BasicBlock 已纳入 Value 体系,便于后续向更完整 IR 类图靠拢。
// 当前其类型仍使用 void 作为占位,后续可替换为专门的 label type。
class BasicBlock : public Value {
@ -315,6 +351,10 @@ class IRBuilder {
LoadInst* CreateLoad(Value* ptr, const std::string& name);
StoreInst* CreateStore(Value* val, Value* ptr);
ReturnInst* CreateRet(Value* v);
CmpInst* CreateCmp(CmpOp op, Value* lhs, Value* rhs, const std::string& name);
ZextInst* CreateZext(Value* val, const std::string& name);
BranchInst* CreateBr(BasicBlock* dest);
CondBranchInst* CreateCondBr(Value* cond, BasicBlock* true_bb, BasicBlock* false_bb);
private:
Context& ctx_;

@ -37,6 +37,12 @@ class IRGenImpl final : public SysYBaseVisitor {
std::any visitAddExp(SysYParser::AddExpContext* ctx) override;
std::any visitMulExp(SysYParser::MulExpContext* ctx) override;
std::any visitUnaryExp(SysYParser::UnaryExpContext* ctx) override;
std::any visitRelExp(SysYParser::RelExpContext* ctx) override;
std::any visitEqExp(SysYParser::EqExpContext* ctx) override;
std::any visitLAndExp(SysYParser::LAndExpContext* ctx) override;
std::any visitLOrExp(SysYParser::LOrExpContext* ctx) override;
std::any visitCondUnaryExp(SysYParser::CondUnaryExpContext* ctx) override;
std::any visitCond(SysYParser::CondContext* ctx) override;
private:
enum class BlockFlow {
@ -53,6 +59,15 @@ class IRGenImpl final : public SysYBaseVisitor {
ir::IRBuilder builder_;
// 名称绑定由 Sema 负责IRGen 只维护"变量名 -> 存储槽位"的代码生成状态。
std::unordered_map<std::string, ir::Value*> storage_map_;
// 用于 break 和 continue 跳转的目标位置
ir::BasicBlock* current_loop_cond_bb_ = nullptr;
ir::BasicBlock* current_loop_exit_bb_ = nullptr;
int bb_cnt_ = 0;
std::string NextBlockName(const std::string& prefix = "bb") {
return prefix + "_" + std::to_string(++bb_cnt_);
}
};
std::unique_ptr<ir::Module> GenerateIR(SysYParser::CompUnitContext& tree,

@ -0,0 +1,83 @@
--- include/ir/IR.h
+++ include/ir/IR.h
@@ -93,6 +93,7 @@
class Type {
public:
- enum class Kind { Void, Int32, PtrInt32 };
+ enum class Kind { Void, Int1, Int32, PtrInt32 };
explicit Type(Kind k);
// 使用静态共享对象获取类型。
// 同一类型可直接比较返回值是否相等,例如:
// Type::GetInt32Type() == Type::GetInt32Type()
static const std::shared_ptr<Type>& GetVoidType();
+ static const std::shared_ptr<Type>& GetInt1Type();
static const std::shared_ptr<Type>& GetInt32Type();
static const std::shared_ptr<Type>& GetPtrInt32Type();
Kind GetKind() const;
bool IsVoid() const;
+ bool IsInt1() const;
bool IsInt32() const;
bool IsPtrInt32() const;
@@ -118,6 +119,7 @@
const std::string& GetName() const;
void SetName(std::string n);
bool IsVoid() const;
+ bool IsInt1() const;
bool IsInt32() const;
bool IsPtrInt32() const;
bool IsConstant() const;
@@ -153,7 +155,9 @@
// 后续还需要扩展更多指令类型。
-// enum class Opcode { Add, Sub, Mul, Alloca, Load, Store, Ret };
-enum class Opcode { Add, Sub, Mul, Div, Mod, Neg, Alloca, Load, Store, Ret };
+enum class Opcode { Add, Sub, Mul, Div, Mod, Neg, Alloca, Load, Store, Ret, Cmp, Zext, Br, CondBr };
+
+enum class CmpOp { Eq, Ne, Lt, Gt, Le, Ge };
// User 是所有“会使用其他 Value 作为输入”的 IR 对象的抽象基类。
@@ -231,6 +235,33 @@
Value* GetPtr() const;
};
+class CmpInst : public Instruction {
+ public:
+ CmpInst(CmpOp cmp_op, Value* lhs, Value* rhs, std::string name);
+ CmpOp GetCmpOp() const;
+ Value* GetLhs() const;
+ Value* GetRhs() const;
+ private:
+ CmpOp cmp_op_;
+};
+
+class ZextInst : public Instruction {
+ public:
+ ZextInst(std::shared_ptr<Type> dest_ty, Value* val, std::string name);
+ Value* GetValue() const;
+};
+
+class BranchInst : public Instruction {
+ public:
+ BranchInst(BasicBlock* dest);
+ BasicBlock* GetDest() const;
+};
+
+class CondBranchInst : public Instruction {
+ public:
+ CondBranchInst(Value* cond, BasicBlock* true_bb, BasicBlock* false_bb);
+ Value* GetCond() const;
+ BasicBlock* GetTrueBlock() const;
+ BasicBlock* GetFalseBlock() const;
+};
+
// BasicBlock 已纳入 Value 体系,便于后续向更完整 IR 类图靠拢。
@@ -315,6 +346,10 @@
LoadInst* CreateLoad(Value* ptr, const std::string& name);
StoreInst* CreateStore(Value* val, Value* ptr);
ReturnInst* CreateRet(Value* v);
+ CmpInst* CreateCmp(CmpOp op, Value* lhs, Value* rhs, const std::string& name);
+ ZextInst* CreateZext(Value* val, const std::string& name);
+ BranchInst* CreateBr(BasicBlock* dest);
+ CondBranchInst* CreateCondBr(Value* cond, BasicBlock* true_bb, BasicBlock* false_bb);
private:

@ -17,7 +17,7 @@ ConstantInt* Context::GetConstInt(int v) {
std::string Context::NextTemp() {
std::ostringstream oss;
oss << "%" << ++temp_index_;
oss << "%t" << ++temp_index_;
return oss.str();
}

@ -104,4 +104,44 @@ UnaryInst* IRBuilder::CreateNeg(Value* operand, const std::string& name) {
return insert_block_->Append<UnaryInst>(Opcode::Neg, Type::GetInt32Type(), operand, name);
}
CmpInst* IRBuilder::CreateCmp(CmpOp op, Value* lhs, Value* rhs, const std::string& name) {
if (!insert_block_) {
throw std::runtime_error(FormatError("ir", "IRBuilder 未设置插入点"));
}
if (!lhs || !rhs) {
throw std::runtime_error(FormatError("ir", "IRBuilder::CreateCmp 缺少操作数"));
}
return insert_block_->Append<CmpInst>(op, lhs, rhs, name);
}
ZextInst* IRBuilder::CreateZext(Value* val, const std::string& name) {
if (!insert_block_) {
throw std::runtime_error(FormatError("ir", "IRBuilder 未设置插入点"));
}
if (!val) {
throw std::runtime_error(FormatError("ir", "IRBuilder::CreateZext 缺少操作数"));
}
return insert_block_->Append<ZextInst>(Type::GetInt32Type(), val, name);
}
BranchInst* IRBuilder::CreateBr(BasicBlock* dest) {
if (!insert_block_) {
throw std::runtime_error(FormatError("ir", "IRBuilder 未设置插入点"));
}
if (!dest) {
throw std::runtime_error(FormatError("ir", "IRBuilder::CreateBr 缺少操作数"));
}
return insert_block_->Append<BranchInst>(dest);
}
CondBranchInst* IRBuilder::CreateCondBr(Value* cond, BasicBlock* true_bb, BasicBlock* false_bb) {
if (!insert_block_) {
throw std::runtime_error(FormatError("ir", "IRBuilder 未设置插入点"));
}
if (!cond || !true_bb || !false_bb) {
throw std::runtime_error(FormatError("ir", "IRBuilder::CreateCondBr 缺少操作数"));
}
return insert_block_->Append<CondBranchInst>(cond, true_bb, false_bb);
}
} // namespace ir

@ -16,6 +16,8 @@ static const char* TypeToString(const Type& ty) {
switch (ty.GetKind()) {
case Type::Kind::Void:
return "void";
case Type::Kind::Int1:
return "i1";
case Type::Kind::Int32:
return "i32";
case Type::Kind::PtrInt32:
@ -46,6 +48,31 @@ static const char* OpcodeToString(Opcode op) {
return "store";
case Opcode::Ret:
return "ret";
case Opcode::Cmp:
return "icmp";
case Opcode::Zext:
return "zext";
case Opcode::Br:
case Opcode::CondBr:
return "br";
}
return "?";
}
static const char* CmpOpToString(CmpOp op) {
switch (op) {
case CmpOp::Eq:
return "eq";
case CmpOp::Ne:
return "ne";
case CmpOp::Lt:
return "slt";
case CmpOp::Gt:
return "sgt";
case CmpOp::Le:
return "sle";
case CmpOp::Ge:
return "sge";
}
return "?";
}
@ -57,6 +84,21 @@ static std::string ValueToString(const Value* v) {
return v ? v->GetName() : "<null>";
}
static std::string PrintLabel(const Value* bb) {
if (!bb) return "<null>";
std::string name = bb->GetName();
if (name.empty()) return "<empty>";
if (name[0] == '%') return name;
return "%" + name;
}
static std::string PrintLabelDef(const Value* bb) {
if (!bb) return "<null>";
std::string name = bb->GetName();
if (!name.empty() && name[0] == '%') return name.substr(1);
return name;
}
void IRPrinter::Print(const Module& module, std::ostream& os) {
for (const auto& func : module.GetFunctions()) {
os << "define " << TypeToString(*func->GetType()) << " @" << func->GetName()
@ -65,7 +107,7 @@ void IRPrinter::Print(const Module& module, std::ostream& os) {
if (!bb) {
continue;
}
os << bb->GetName() << ":\n";
os << PrintLabelDef(bb.get()) << ":\n";
for (const auto& instPtr : bb->GetInstructions()) {
const auto* inst = instPtr.get();
switch (inst->GetOpcode()) {
@ -113,6 +155,35 @@ void IRPrinter::Print(const Module& module, std::ostream& os) {
<< ValueToString(ret->GetValue()) << "\n";
break;
}
case Opcode::Cmp: {
auto* cmp = static_cast<const CmpInst*>(inst);
os << " " << cmp->GetName() << " = icmp "
<< CmpOpToString(cmp->GetCmpOp()) << " "
<< TypeToString(*cmp->GetLhs()->GetType()) << " "
<< ValueToString(cmp->GetLhs()) << ", "
<< ValueToString(cmp->GetRhs()) << "\n";
break;
}
case Opcode::Zext: {
auto* zext = static_cast<const ZextInst*>(inst);
os << " " << zext->GetName() << " = zext "
<< TypeToString(*zext->GetOperand(0)->GetType()) << " "
<< ValueToString(zext->GetOperand(0)) << " to "
<< TypeToString(*zext->GetType()) << "\n";
break;
}
case Opcode::Br: {
auto* br = static_cast<const BranchInst*>(inst);
os << " br label " << PrintLabel(br->GetDest()) << "\n";
break;
}
case Opcode::CondBr: {
auto* cbr = static_cast<const CondBranchInst*>(inst);
os << " br i1 " << ValueToString(cbr->GetCond())
<< ", label " << PrintLabel(cbr->GetTrueBlock())
<< ", label " << PrintLabel(cbr->GetFalseBlock()) << "\n";
break;
}
}
}
}

@ -52,7 +52,7 @@ Instruction::Instruction(Opcode op, std::shared_ptr<Type> ty, std::string name)
Opcode Instruction::GetOpcode() const { return opcode_; }
bool Instruction::IsTerminator() const { return opcode_ == Opcode::Ret; }
bool Instruction::IsTerminator() const { return opcode_ == Opcode::Ret || opcode_ == Opcode::Br || opcode_ == Opcode::CondBr; }
BasicBlock* Instruction::GetParent() const { return parent_; }
@ -172,4 +172,63 @@ Value* StoreInst::GetValue() const { return GetOperand(0); }
Value* StoreInst::GetPtr() const { return GetOperand(1); }
CmpInst::CmpInst(CmpOp cmp_op, Value* lhs, Value* rhs, std::string name)
: Instruction(Opcode::Cmp, Type::GetInt1Type(), std::move(name)), cmp_op_(cmp_op) {
if (!lhs || !rhs) {
throw std::runtime_error(FormatError("ir", "CmpInst 缺少操作数"));
}
if (!lhs->GetType() || !rhs->GetType()) {
throw std::runtime_error(FormatError("ir", "CmpInst 缺少操作数类型信息"));
}
if (lhs->GetType()->GetKind() != rhs->GetType()->GetKind()) {
throw std::runtime_error(FormatError("ir", "CmpInst 操作数类型不匹配"));
}
AddOperand(lhs);
AddOperand(rhs);
}
CmpOp CmpInst::GetCmpOp() const { return cmp_op_; }
Value* CmpInst::GetLhs() const { return GetOperand(0); }
Value* CmpInst::GetRhs() const { return GetOperand(1); }
ZextInst::ZextInst(std::shared_ptr<Type> dest_ty, Value* val, std::string name)
: Instruction(Opcode::Zext, std::move(dest_ty), std::move(name)) {
if (!val) {
throw std::runtime_error(FormatError("ir", "ZextInst 缺少操作数"));
}
if (!type_->IsInt32() || !val->GetType()->IsInt1()) {
throw std::runtime_error(FormatError("ir", "ZextInst 当前只支持 i1 到 i32"));
}
AddOperand(val);
}
Value* ZextInst::GetValue() const { return GetOperand(0); }
BranchInst::BranchInst(BasicBlock* dest)
: Instruction(Opcode::Br, Type::GetVoidType(), "") {
if (!dest) {
throw std::runtime_error(FormatError("ir", "BranchInst 缺少目的块"));
}
AddOperand(dest);
}
BasicBlock* BranchInst::GetDest() const { return static_cast<BasicBlock*>(GetOperand(0)); }
CondBranchInst::CondBranchInst(Value* cond, BasicBlock* true_bb, BasicBlock* false_bb)
: Instruction(Opcode::CondBr, Type::GetVoidType(), "") {
if (!cond || !true_bb || !false_bb) {
throw std::runtime_error(FormatError("ir", "CondBranchInst 缺少连边操作数"));
}
if (!cond->GetType()->IsInt1()) {
throw std::runtime_error(FormatError("ir", "CondBranchInst 必须使用 i1 作为条件"));
}
AddOperand(cond);
AddOperand(true_bb);
AddOperand(false_bb);
}
Value* CondBranchInst::GetCond() const { return GetOperand(0); }
BasicBlock* CondBranchInst::GetTrueBlock() const { return static_cast<BasicBlock*>(GetOperand(1)); }
BasicBlock* CondBranchInst::GetFalseBlock() const { return static_cast<BasicBlock*>(GetOperand(2)); }
} // namespace ir

@ -10,6 +10,11 @@ const std::shared_ptr<Type>& Type::GetVoidType() {
return type;
}
const std::shared_ptr<Type>& Type::GetInt1Type() {
static const std::shared_ptr<Type> type = std::make_shared<Type>(Kind::Int1);
return type;
}
const std::shared_ptr<Type>& Type::GetInt32Type() {
static const std::shared_ptr<Type> type = std::make_shared<Type>(Kind::Int32);
return type;
@ -24,6 +29,8 @@ Type::Kind Type::GetKind() const { return kind_; }
bool Type::IsVoid() const { return kind_ == Kind::Void; }
bool Type::IsInt1() const { return kind_ == Kind::Int1; }
bool Type::IsInt32() const { return kind_ == Kind::Int32; }
bool Type::IsPtrInt32() const { return kind_ == Kind::PtrInt32; }

@ -18,6 +18,8 @@ void Value::SetName(std::string n) { name_ = std::move(n); }
bool Value::IsVoid() const { return type_ && type_->IsVoid(); }
bool Value::IsInt1() const { return type_ && type_->IsInt1(); }
bool Value::IsInt32() const { return type_ && type_->IsInt32(); }
bool Value::IsPtrInt32() const { return type_ && type_->IsPtrInt32(); }

@ -10,15 +10,16 @@ std::any IRGenImpl::visitBlock(SysYParser::BlockContext* ctx) {
if (!ctx) {
throw std::runtime_error(FormatError("irgen", "缺少语句块"));
}
bool terminated = false;
for (auto* item : ctx->blockItem()) {
if (item) {
if (VisitBlockItemResult(*item) == BlockFlow::Terminated) {
// 当前语法要求 return 为块内最后一条语句;命中后可停止生成。
terminated = true;
break;
}
}
}
return {};
return terminated ? BlockFlow::Terminated : BlockFlow::Continue;
}
IRGenImpl::BlockFlow IRGenImpl::VisitBlockItemResult(
@ -66,7 +67,7 @@ std::any IRGenImpl::visitDecl(SysYParser::DeclContext* ctx) {
var_def->accept(this);
}
}
return {};
return BlockFlow::Continue;
}
@ -102,5 +103,5 @@ std::any IRGenImpl::visitVarDef(SysYParser::VarDefContext* ctx) {
init = builder_.CreateConstInt(0);
}
builder_.CreateStore(init, slot);
return {};
return BlockFlow::Continue;
}

@ -201,4 +201,129 @@ std::any IRGenImpl::visitMulExp(SysYParser::MulExpContext* ctx) {
return static_cast<ir::Value*>(
builder_.CreateBinary(op, lhs, rhs, module_.GetContext().NextTemp()));
}
std::any IRGenImpl::visitRelExp(SysYParser::RelExpContext* ctx) {
if (ctx->addExp() && ctx->relExp() == nullptr) {
return ctx->addExp()->accept(this);
}
ir::Value* lhs = std::any_cast<ir::Value*>(ctx->relExp()->accept(this));
ir::Value* rhs = std::any_cast<ir::Value*>(ctx->addExp()->accept(this));
if (lhs->GetType()->IsInt1()) lhs = builder_.CreateZext(lhs, module_.GetContext().NextTemp());
if (rhs->GetType()->IsInt1()) rhs = builder_.CreateZext(rhs, module_.GetContext().NextTemp());
ir::CmpOp op;
if (ctx->LT()) op = ir::CmpOp::Lt;
else if (ctx->GT()) op = ir::CmpOp::Gt;
else if (ctx->LE()) op = ir::CmpOp::Le;
else if (ctx->GE()) op = ir::CmpOp::Ge;
else throw std::runtime_error(FormatError("irgen", "未知的关系运算符"));
return static_cast<ir::Value*>(builder_.CreateCmp(op, lhs, rhs, module_.GetContext().NextTemp()));
}
std::any IRGenImpl::visitEqExp(SysYParser::EqExpContext* ctx) {
if (ctx->relExp() && ctx->eqExp() == nullptr) {
return ctx->relExp()->accept(this);
}
ir::Value* lhs = std::any_cast<ir::Value*>(ctx->eqExp()->accept(this));
ir::Value* rhs = std::any_cast<ir::Value*>(ctx->relExp()->accept(this));
if (lhs->GetType()->IsInt1()) lhs = builder_.CreateZext(lhs, module_.GetContext().NextTemp());
if (rhs->GetType()->IsInt1()) rhs = builder_.CreateZext(rhs, module_.GetContext().NextTemp());
ir::CmpOp op;
if (ctx->EQ()) op = ir::CmpOp::Eq;
else if (ctx->NE()) op = ir::CmpOp::Ne;
else throw std::runtime_error(FormatError("irgen", "未知的相等运算符"));
return static_cast<ir::Value*>(builder_.CreateCmp(op, lhs, rhs, module_.GetContext().NextTemp()));
}
std::any IRGenImpl::visitCondUnaryExp(SysYParser::CondUnaryExpContext* ctx) {
if (ctx->eqExp()) {
return ctx->eqExp()->accept(this);
}
if (ctx->NOT()) {
ir::Value* operand = std::any_cast<ir::Value*>(ctx->condUnaryExp()->accept(this));
if (operand->GetType()->IsInt1()) {
operand = builder_.CreateZext(operand, module_.GetContext().NextTemp());
}
ir::Value* zero = builder_.CreateConstInt(0);
return static_cast<ir::Value*>(builder_.CreateCmp(ir::CmpOp::Eq, operand, zero, module_.GetContext().NextTemp()));
}
throw std::runtime_error(FormatError("irgen", "非法条件一元表达式"));
}
std::any IRGenImpl::visitLAndExp(SysYParser::LAndExpContext* ctx) {
if (ctx->condUnaryExp() && ctx->lAndExp() == nullptr) {
return ctx->condUnaryExp()->accept(this);
}
ir::AllocaInst* res_ptr = builder_.CreateAllocaI32(module_.GetContext().NextTemp());
ir::Value* zero = builder_.CreateConstInt(0);
builder_.CreateStore(zero, res_ptr);
ir::BasicBlock* rhs_bb = func_->CreateBlock(NextBlockName("land_rhs"));
ir::BasicBlock* end_bb = func_->CreateBlock(NextBlockName("land_end"));
ir::Value* lhs = std::any_cast<ir::Value*>(ctx->lAndExp()->accept(this));
if (lhs->GetType()->IsInt1()) {
lhs = builder_.CreateZext(lhs, module_.GetContext().NextTemp());
}
ir::Value* lhs_cond = builder_.CreateCmp(ir::CmpOp::Ne, lhs, zero, module_.GetContext().NextTemp());
builder_.CreateCondBr(lhs_cond, rhs_bb, end_bb);
builder_.SetInsertPoint(rhs_bb);
ir::Value* rhs = std::any_cast<ir::Value*>(ctx->condUnaryExp()->accept(this));
if (rhs->GetType()->IsInt1()) {
rhs = builder_.CreateZext(rhs, module_.GetContext().NextTemp());
}
ir::Value* rhs_cond = builder_.CreateCmp(ir::CmpOp::Ne, rhs, zero, module_.GetContext().NextTemp());
ir::Value* rhs_res = builder_.CreateZext(rhs_cond, module_.GetContext().NextTemp());
builder_.CreateStore(rhs_res, res_ptr);
builder_.CreateBr(end_bb);
builder_.SetInsertPoint(end_bb);
return static_cast<ir::Value*>(builder_.CreateLoad(res_ptr, module_.GetContext().NextTemp()));
}
std::any IRGenImpl::visitLOrExp(SysYParser::LOrExpContext* ctx) {
if (ctx->lAndExp() && ctx->lOrExp() == nullptr) {
return ctx->lAndExp()->accept(this);
}
ir::AllocaInst* res_ptr = builder_.CreateAllocaI32(module_.GetContext().NextTemp());
ir::Value* one = builder_.CreateConstInt(1);
builder_.CreateStore(one, res_ptr);
ir::BasicBlock* rhs_bb = func_->CreateBlock(NextBlockName("lor_rhs"));
ir::BasicBlock* end_bb = func_->CreateBlock(NextBlockName("lor_end"));
ir::Value* lhs = std::any_cast<ir::Value*>(ctx->lOrExp()->accept(this));
ir::Value* zero = builder_.CreateConstInt(0);
if (lhs->GetType()->IsInt1()) {
lhs = builder_.CreateZext(lhs, module_.GetContext().NextTemp());
}
ir::Value* lhs_cond = builder_.CreateCmp(ir::CmpOp::Eq, lhs, zero, module_.GetContext().NextTemp());
builder_.CreateCondBr(lhs_cond, rhs_bb, end_bb);
builder_.SetInsertPoint(rhs_bb);
ir::Value* rhs = std::any_cast<ir::Value*>(ctx->lAndExp()->accept(this));
if (rhs->GetType()->IsInt1()) {
rhs = builder_.CreateZext(rhs, module_.GetContext().NextTemp());
}
ir::Value* rhs_cond = builder_.CreateCmp(ir::CmpOp::Ne, rhs, zero, module_.GetContext().NextTemp());
ir::Value* rhs_res = builder_.CreateZext(rhs_cond, module_.GetContext().NextTemp());
builder_.CreateStore(rhs_res, res_ptr);
builder_.CreateBr(end_bb);
builder_.SetInsertPoint(end_bb);
return static_cast<ir::Value*>(builder_.CreateLoad(res_ptr, module_.GetContext().NextTemp()));
}
std::any IRGenImpl::visitCond(SysYParser::CondContext* ctx) {
if (!ctx || !ctx->lOrExp()) {
throw std::runtime_error(FormatError("irgen", "非法条件表达式"));
}
return ctx->lOrExp()->accept(this);
}

@ -20,50 +20,133 @@ std::any IRGenImpl::visitStmt(SysYParser::StmtContext* ctx) {
throw std::runtime_error(FormatError("irgen", "缺少语句"));
}
// 检查是否是赋值语句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()));
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));
FormatError("irgen", "变量声明缺少存储槽位:" + var_name));
}
// 3. 生成 store 指令
builder_.CreateStore(rhs, it->second);
return BlockFlow::Continue;
}
// 检查是否是 return 语句RETURN exp? SEMICOLON
if (ctx->IF()) {
ir::Value* cond_val = std::any_cast<ir::Value*>(ctx->cond()->accept(this));
// cond_val must be i1, if it's not we need to check if it's != 0
if (cond_val->GetType()->IsInt32()) {
ir::Value* zero = builder_.CreateConstInt(0);
cond_val = builder_.CreateCmp(ir::CmpOp::Ne, cond_val, zero, module_.GetContext().NextTemp());
}
ir::BasicBlock* then_bb = func_->CreateBlock(NextBlockName("if_then"));
ir::BasicBlock* else_bb = ctx->ELSE() ? func_->CreateBlock(NextBlockName("if_else")) : nullptr;
ir::BasicBlock* merge_bb = func_->CreateBlock(NextBlockName("if_merge"));
builder_.CreateCondBr(cond_val, then_bb, else_bb ? else_bb : merge_bb);
builder_.SetInsertPoint(then_bb);
auto then_flow = std::any_cast<BlockFlow>(ctx->stmt(0)->accept(this));
if (then_flow == BlockFlow::Continue) {
builder_.CreateBr(merge_bb);
}
if (ctx->ELSE()) {
builder_.SetInsertPoint(else_bb);
auto else_flow = std::any_cast<BlockFlow>(ctx->stmt(1)->accept(this));
if (else_flow == BlockFlow::Continue) {
builder_.CreateBr(merge_bb);
}
}
builder_.SetInsertPoint(merge_bb);
return BlockFlow::Continue;
}
if (ctx->WHILE()) {
ir::BasicBlock* cond_bb = func_->CreateBlock(NextBlockName("while_cond"));
ir::BasicBlock* body_bb = func_->CreateBlock(NextBlockName("while_body"));
ir::BasicBlock* exit_bb = func_->CreateBlock(NextBlockName("while_exit"));
builder_.CreateBr(cond_bb);
builder_.SetInsertPoint(cond_bb);
ir::Value* cond_val = std::any_cast<ir::Value*>(ctx->cond()->accept(this));
if (cond_val->GetType()->IsInt32()) {
ir::Value* zero = builder_.CreateConstInt(0);
cond_val = builder_.CreateCmp(ir::CmpOp::Ne, cond_val, zero, module_.GetContext().NextTemp());
}
builder_.CreateCondBr(cond_val, body_bb, exit_bb);
builder_.SetInsertPoint(body_bb);
ir::BasicBlock* old_cond = current_loop_cond_bb_;
ir::BasicBlock* old_exit = current_loop_exit_bb_;
current_loop_cond_bb_ = cond_bb;
current_loop_exit_bb_ = exit_bb;
auto body_flow = std::any_cast<BlockFlow>(ctx->stmt(0)->accept(this));
if (body_flow == BlockFlow::Continue) {
builder_.CreateBr(cond_bb);
}
current_loop_cond_bb_ = old_cond;
current_loop_exit_bb_ = old_exit;
builder_.SetInsertPoint(exit_bb);
return BlockFlow::Continue;
}
if (ctx->BREAK()) {
if (!current_loop_exit_bb_) {
throw std::runtime_error(FormatError("irgen", "break 必须在循环内"));
}
builder_.CreateBr(current_loop_exit_bb_);
return BlockFlow::Terminated;
}
if (ctx->CONTINUE()) {
if (!current_loop_cond_bb_) {
throw std::runtime_error(FormatError("irgen", "continue 必须在循环内"));
}
builder_.CreateBr(current_loop_cond_bb_);
return BlockFlow::Terminated;
}
if (ctx->RETURN()) {
if (!ctx->exp()) {
throw std::runtime_error(FormatError("irgen", "return 缺少表达式"));
if (ctx->exp()) {
ir::Value* v = EvalExpr(*ctx->exp());
builder_.CreateRet(v);
} else {
throw std::runtime_error(FormatError("irgen", "暂不支持 void return"));
}
ir::Value* v = EvalExpr(*ctx->exp());
builder_.CreateRet(v);
return BlockFlow::Terminated;
}
if (ctx->block()) {
return ctx->block()->accept(this);
}
if (ctx->exp()) {
EvalExpr(*ctx->exp());
return BlockFlow::Continue;
}
if (ctx->SEMICOLON()) {
return BlockFlow::Continue;
}
throw std::runtime_error(FormatError("irgen", "暂不支持的语句类型"));
}

@ -462,7 +462,7 @@ class SemaVisitor final : public SysYBaseVisitor {
if (!ctx) {
ThrowSemaError(ctx, "非法关系表达式");
}
if (ctx->addExp()) {
if (ctx->relExp() == nullptr) {
return EvalExpr(*ctx->addExp());
}
ExprInfo lhs = EvalExpr(*ctx->relExp());
@ -474,7 +474,7 @@ class SemaVisitor final : public SysYBaseVisitor {
if (!ctx) {
ThrowSemaError(ctx, "非法相等表达式");
}
if (ctx->relExp()) {
if (ctx->eqExp() == nullptr) {
return EvalExpr(*ctx->relExp());
}
ExprInfo lhs = EvalExpr(*ctx->eqExp());
@ -504,7 +504,7 @@ class SemaVisitor final : public SysYBaseVisitor {
if (!ctx) {
ThrowSemaError(ctx, "非法逻辑与表达式");
}
if (ctx->condUnaryExp()) {
if (ctx->lAndExp() == nullptr) {
return EvalExpr(*ctx->condUnaryExp());
}
ExprInfo lhs = EvalExpr(*ctx->lAndExp());
@ -516,7 +516,7 @@ class SemaVisitor final : public SysYBaseVisitor {
if (!ctx) {
ThrowSemaError(ctx, "非法逻辑或表达式");
}
if (ctx->lAndExp()) {
if (ctx->lOrExp() == nullptr) {
return EvalExpr(*ctx->lAndExp());
}
ExprInfo lhs = EvalExpr(*ctx->lOrExp());

Loading…
Cancel
Save