diff --git a/doc/lab2剩余任务分工.md b/doc/lab2剩余任务分工.md
index 70e63de..8969726 100644
--- a/doc/lab2剩余任务分工.md
+++ b/doc/lab2剩余任务分工.md
@@ -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 常量声明
-
-
-
-
## 人员 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
+ ```
\ No newline at end of file
diff --git a/include/ir/IR.h b/include/ir/IR.h
index 6af2d96..06f837f 100644
--- a/include/ir/IR.h
+++ b/include/ir/IR.h
@@ -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& GetVoidType();
+ static const std::shared_ptr& GetInt1Type();
static const std::shared_ptr& GetInt32Type();
static const std::shared_ptr& 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 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_;
diff --git a/include/irgen/IRGen.h b/include/irgen/IRGen.h
index 2ed1c85..fec791a 100644
--- a/include/irgen/IRGen.h
+++ b/include/irgen/IRGen.h
@@ -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 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 GenerateIR(SysYParser::CompUnitContext& tree,
diff --git a/patch_IR_h.patch b/patch_IR_h.patch
new file mode 100644
index 0000000..c1a32ce
--- /dev/null
+++ b/patch_IR_h.patch
@@ -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& GetVoidType();
++ static const std::shared_ptr& GetInt1Type();
+ static const std::shared_ptr& GetInt32Type();
+ static const std::shared_ptr& 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 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:
diff --git a/src/ir/Context.cpp b/src/ir/Context.cpp
index 16c982c..5f32c65 100644
--- a/src/ir/Context.cpp
+++ b/src/ir/Context.cpp
@@ -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();
}
diff --git a/src/ir/IRBuilder.cpp b/src/ir/IRBuilder.cpp
index 54cc5d2..3569ab6 100644
--- a/src/ir/IRBuilder.cpp
+++ b/src/ir/IRBuilder.cpp
@@ -104,4 +104,44 @@ UnaryInst* IRBuilder::CreateNeg(Value* operand, const std::string& name) {
return insert_block_->Append(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(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(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(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(cond, true_bb, false_bb);
+}
+
} // namespace ir
diff --git a/src/ir/IRPrinter.cpp b/src/ir/IRPrinter.cpp
index 3716751..40cfc77 100644
--- a/src/ir/IRPrinter.cpp
+++ b/src/ir/IRPrinter.cpp
@@ -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() : "";
}
+static std::string PrintLabel(const Value* bb) {
+ if (!bb) return "";
+ std::string name = bb->GetName();
+ if (name.empty()) return "";
+ if (name[0] == '%') return name;
+ return "%" + name;
+}
+
+static std::string PrintLabelDef(const Value* bb) {
+ if (!bb) return "";
+ 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(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(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(inst);
+ os << " br label " << PrintLabel(br->GetDest()) << "\n";
+ break;
+ }
+ case Opcode::CondBr: {
+ auto* cbr = static_cast(inst);
+ os << " br i1 " << ValueToString(cbr->GetCond())
+ << ", label " << PrintLabel(cbr->GetTrueBlock())
+ << ", label " << PrintLabel(cbr->GetFalseBlock()) << "\n";
+ break;
+ }
}
}
}
diff --git a/src/ir/Instruction.cpp b/src/ir/Instruction.cpp
index 199b123..9ae696c 100644
--- a/src/ir/Instruction.cpp
+++ b/src/ir/Instruction.cpp
@@ -52,7 +52,7 @@ Instruction::Instruction(Opcode op, std::shared_ptr 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 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(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(GetOperand(1)); }
+BasicBlock* CondBranchInst::GetFalseBlock() const { return static_cast(GetOperand(2)); }
+
} // namespace ir
diff --git a/src/ir/Type.cpp b/src/ir/Type.cpp
index 3e1684d..c32d640 100644
--- a/src/ir/Type.cpp
+++ b/src/ir/Type.cpp
@@ -10,6 +10,11 @@ const std::shared_ptr& Type::GetVoidType() {
return type;
}
+const std::shared_ptr& Type::GetInt1Type() {
+ static const std::shared_ptr type = std::make_shared(Kind::Int1);
+ return type;
+}
+
const std::shared_ptr& Type::GetInt32Type() {
static const std::shared_ptr type = std::make_shared(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; }
diff --git a/src/ir/Value.cpp b/src/ir/Value.cpp
index 2e9f4c1..12a06b4 100644
--- a/src/ir/Value.cpp
+++ b/src/ir/Value.cpp
@@ -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(); }
diff --git a/src/irgen/IRGenDecl.cpp b/src/irgen/IRGenDecl.cpp
index df7ccf9..1cd0db8 100644
--- a/src/irgen/IRGenDecl.cpp
+++ b/src/irgen/IRGenDecl.cpp
@@ -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;
}
diff --git a/src/irgen/IRGenExp.cpp b/src/irgen/IRGenExp.cpp
index 55c3cc2..4565c6e 100644
--- a/src/irgen/IRGenExp.cpp
+++ b/src/irgen/IRGenExp.cpp
@@ -201,4 +201,129 @@ std::any IRGenImpl::visitMulExp(SysYParser::MulExpContext* ctx) {
return static_cast(
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(ctx->relExp()->accept(this));
+ ir::Value* rhs = std::any_cast(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(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(ctx->eqExp()->accept(this));
+ ir::Value* rhs = std::any_cast(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(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(ctx->condUnaryExp()->accept(this));
+ if (operand->GetType()->IsInt1()) {
+ operand = builder_.CreateZext(operand, module_.GetContext().NextTemp());
+ }
+ ir::Value* zero = builder_.CreateConstInt(0);
+ return static_cast(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(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(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(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(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(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(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);
}
\ No newline at end of file
diff --git a/src/irgen/IRGenStmt.cpp b/src/irgen/IRGenStmt.cpp
index de6a857..e44bd0a 100644
--- a/src/irgen/IRGenStmt.cpp
+++ b/src/irgen/IRGenStmt.cpp
@@ -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(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(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(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(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(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", "暂不支持的语句类型"));
}
diff --git a/src/sem/Sema.cpp b/src/sem/Sema.cpp
index fc73f9d..95f0629 100644
--- a/src/sem/Sema.cpp
+++ b/src/sem/Sema.cpp
@@ -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());