From dfa71bc0d71864fce3b72809d65b69d22b372b31 Mon Sep 17 00:00:00 2001 From: jing <3030349106@qq.com> Date: Wed, 18 Mar 2026 02:07:34 +0800 Subject: [PATCH] =?UTF-8?q?refactor(irgen):=20=E8=A7=84=E8=8C=83=E9=87=87?= =?UTF-8?q?=E7=94=A8visitor=E7=94=9F=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/Lab2-中间表示生成.md | 25 +++++--- include/irgen/IRGen.h | 33 +++++++---- src/ir/Instruction.cpp | 103 +++++++++++++++++++++------------ src/irgen/IRGenDecl.cpp | 73 ++++++++++++++++------- src/irgen/IRGenDriver.cpp | 2 +- src/irgen/IRGenExp.cpp | 98 +++++++++++++++++++++---------- src/irgen/IRGenFunc.cpp | 57 +++++++++++++----- src/irgen/IRGenStmt.cpp | 30 +++++++--- 8 files changed, 294 insertions(+), 127 deletions(-) diff --git a/doc/Lab2-中间表示生成.md b/doc/Lab2-中间表示生成.md index 3be8846..fd25e02 100644 --- a/doc/Lab2-中间表示生成.md +++ b/doc/Lab2-中间表示生成.md @@ -50,26 +50,37 @@ Lab2 的目标是在该示例基础上扩展语义覆盖范围,并逐步把更 其中,`sema` 负责最基本的名称绑定与合法性检查,`irgen` 在此基础上继续生成 IR。 如果语义检查阶段没有补全,后续 IR 生成阶段通常也无法正确处理变量引用、声明绑定等逻辑。 +当前 `irgen` 的组织方式基于 ANTLR Visitor 的实现。 + +`IRGenImpl` 继承自 `SysYBaseVisitor`,按照语法树节点类型分发到不同的 `visit*` 函数中完成 IR 生成。整体流程大致是: + +1. `GenerateIR(tree, sema)` 先创建 `Module`,再构造 `IRGenImpl`。 +2. 从语法树根节点开始访问,进入 `visitCompUnit`。 +3. `visitFuncDef` 在 `Module` 中创建 `Function`,并把 `IRBuilder` 的插入点设置到入口基本块。 +4. `visitBlockStmt` / `visitBlockItem` 顺序遍历块内声明与语句。 +5. `visitDecl` / `visitVarDef` 为局部变量生成 `alloca` 和初始化 `store`。 +6. `visitExp` 相关函数递归生成常量、`load`、`add` 等表达式值。 +7. `visitReturnStmt` 生成 `ret`,终结当前基本块。 + +需要强调的是:当前 `IRGen` 还只是一个教学用的最小实现。它只支持 `int main()`、局部 `int` 变量、整数字面量、变量读取、二元加法与 `return`;函数形参、全局变量、控制流、调用、数组等都还需要同学后续补充。 + 说明:当前阶段变量统一采用内存模型:先 `alloca` 分配栈槽,再通过 `store/load` 读写。即使变量由常量初始化(如 `int a = 1;`),也会先 `store` 到栈槽,而不是直接把变量替换成 SSA 值。后续实验中,同学可按需求再重构。 -此外,当前 IR 还维护了最基本的 use-def 关系:每个 `Value` 会记录哪些 `Instruction` 使用了它。 +此外,当前 IR 还维护了最基本的 use-def 关系:每个 `Value` 会记录自己的 `Use`/`User` 信息,`Instruction` 通过 operand 列表与这些关系自动关联。 这对后续做数据流分析、死代码删除、常量传播等优化会很有帮助;但目前相关实现,接口仍不完整,后续实验中还需要同学继续补充和完善。 ## 5. 语法树与 Sema / IRGen 的关系 -当前项目中的 `sema` 与 `irgen` 都不是面向独立 AST 设计的,而是直接遍历 ANTLR 生成的语法树节点来完成语义检查与 IR 生成。 -因此,`src/antlr4/SysY.g4` 中 rule 的命名、层级结构以及 labeled alternative 的写法,会直接影响 `SysYParser::*Context` 的类型名和访问接口;一旦 grammar 发生变化,`sem` / `irgen` 中对应的遍历逻辑通常也需要同步修改。 - -这也是为什么在 Lab1 扩展 grammar 后,Lab2 常常还需要继续修改 `sem` / `irgen`: -不是因为 IR 本身一定变了,而是因为“语法树长什么样”,直接决定了语义检查和 IR 生成代码该如何遍历和取信息。 +当前项目中的 `sema` 与 `irgen` 都不是面向独立 AST 设计的,而是直接基于 ANTLR 生成的语法树节点,并通过 Visitor 方式完成语义检查与 IR 生成。 +因此,`SysY.g4` 中 rule 的命名、层级结构以及 labeled alternative 的写法,会直接影响 `SysYParser::*Context` 的类型名和访问接口;一旦 grammar 发生变化,`sem` / `irgen` 中对应的 `visit*` 逻辑通常也需要同步修改。 如果 grammar 扩展后 `sem` / `irgen` 没有同步修改,常见现象包括: 1. 编译阶段报错,例如某个 `SysYParser::*Context` 类型不存在,或某个成员函数不存在。 2. 运行阶段报错,例如进入 `暂不支持的表达式形式`、`暂不支持的语句类型`,或名称绑定失败等分支。 -遇到这类问题时,需要同学自行对照 `SysY.g4`、ANTLR 生成的 `SysYParser.h`,以及 `src/sem` / `src/irgen` 中的遍历逻辑,完成对应的接口调整与功能补全。ANTLR 生成的结构可参考 `build/generated/antlr4/SysYParser.h` 与 `build/generated/antlr4/SysYParser.cpp`;其中前者更适合查看各类 `SysYParser::*Context` 的名字与成员函数,后者可辅助查看规则展开后的具体实现。 +遇到这类问题时,需要同学对照 `SysY.g4`、ANTLR 生成的 `SysYParser.h`,以及 `src/sem` / `src/irgen` 中的 Visitor 遍历逻辑,完成对应的接口调整与功能补全。 ## 6. 构建与运行 diff --git a/include/irgen/IRGen.h b/include/irgen/IRGen.h index ae9789e..231ba90 100644 --- a/include/irgen/IRGen.h +++ b/include/irgen/IRGen.h @@ -3,10 +3,12 @@ #pragma once +#include #include #include #include +#include "SysYBaseVisitor.h" #include "SysYParser.h" #include "ir/IR.h" #include "sem/Sema.h" @@ -18,22 +20,31 @@ class IRBuilder; class Value; } -class IRGenImpl { +class IRGenImpl final : public SysYBaseVisitor { public: IRGenImpl(ir::Module& module, const SemanticContext& sema); - void Gen(SysYParser::CompUnitContext& cu); + std::any visitCompUnit(SysYParser::CompUnitContext* ctx) override; + std::any visitFuncDef(SysYParser::FuncDefContext* ctx) override; + std::any visitBlockStmt(SysYParser::BlockStmtContext* 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; private: - void GenFuncDef(SysYParser::FuncDefContext& func); - void GenBlock(SysYParser::BlockStmtContext& block); - bool GenBlockItem(SysYParser::BlockItemContext& item); - void GenDecl(SysYParser::DeclContext& decl); - bool GenStmt(SysYParser::StmtContext& stmt); - void GenVarDef(SysYParser::VarDefContext& decl); - void GenReturnStmt(SysYParser::ReturnStmtContext& ret); - - ir::Value* GenExpr(SysYParser::ExpContext& expr); + enum class BlockFlow { + Continue, + Terminated, + }; + + BlockFlow VisitBlockItemResult(SysYParser::BlockItemContext& item); + ir::Value* EvalExpr(SysYParser::ExpContext& expr); ir::Module& module_; const SemanticContext& sema_; diff --git a/src/ir/Instruction.cpp b/src/ir/Instruction.cpp index e368b6b..7928716 100644 --- a/src/ir/Instruction.cpp +++ b/src/ir/Instruction.cpp @@ -8,8 +8,47 @@ #include "utils/Log.h" namespace ir { +User::User(std::shared_ptr ty, std::string name) + : Value(std::move(ty), std::move(name)) {} + +size_t User::GetNumOperands() const { return operands_.size(); } + +Value* User::GetOperand(size_t index) const { + if (index >= operands_.size()) { + throw std::out_of_range("User operand index out of range"); + } + return operands_[index]; +} + +void User::SetOperand(size_t index, Value* value) { + if (index >= operands_.size()) { + throw std::out_of_range("User operand index out of range"); + } + if (!value) { + throw std::runtime_error(FormatError("ir", "User operand 不能为空")); + } + auto* old = operands_[index]; + if (old == value) { + return; + } + if (old) { + old->RemoveUse(this, index); + } + operands_[index] = value; + value->AddUse(this, index); +} + +void User::AddOperand(Value* value) { + if (!value) { + throw std::runtime_error(FormatError("ir", "User operand 不能为空")); + } + size_t operand_index = operands_.size(); + operands_.push_back(value); + value->AddUse(this, operand_index); +} + Instruction::Instruction(Opcode op, std::shared_ptr ty, std::string name) - : Value(std::move(ty), std::move(name)), opcode_(op) {} + : User(std::move(ty), std::move(name)), opcode_(op) {} Opcode Instruction::GetOpcode() const { return opcode_; } @@ -21,48 +60,43 @@ 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)), lhs_(lhs), rhs_(rhs) { + : Instruction(op, std::move(ty), std::move(name)) { if (op != Opcode::Add) { throw std::runtime_error(FormatError("ir", "BinaryInst 当前只支持 Add")); } - if (!lhs_ || !rhs_) { + if (!lhs || !rhs) { throw std::runtime_error(FormatError("ir", "BinaryInst 缺少操作数")); } - if (!type_ || !lhs_->GetType() || !rhs_->GetType()) { + if (!type_ || !lhs->GetType() || !rhs->GetType()) { throw std::runtime_error(FormatError("ir", "BinaryInst 缺少类型信息")); } - if (lhs_->GetType()->GetKind() != rhs_->GetType()->GetKind() || - type_->GetKind() != lhs_->GetType()->GetKind()) { + if (lhs->GetType()->GetKind() != rhs->GetType()->GetKind() || + type_->GetKind() != lhs->GetType()->GetKind()) { throw std::runtime_error(FormatError("ir", "BinaryInst 类型不匹配")); } if (!type_->IsInt32()) { throw std::runtime_error(FormatError("ir", "BinaryInst 当前只支持 i32")); } - if (lhs_) { - lhs_->AddUser(this); - } - if (rhs_) { - rhs_->AddUser(this); - } + AddOperand(lhs); + AddOperand(rhs); } -Value* BinaryInst::GetLhs() const { return lhs_; } +Value* BinaryInst::GetLhs() const { return GetOperand(0); } -Value* BinaryInst::GetRhs() const { return rhs_; } +Value* BinaryInst::GetRhs() const { return GetOperand(1); } ReturnInst::ReturnInst(std::shared_ptr void_ty, Value* val) - : Instruction(Opcode::Ret, std::move(void_ty), ""), - value_(val) { - if (!value_) { + : Instruction(Opcode::Ret, std::move(void_ty), "") { + if (!val) { throw std::runtime_error(FormatError("ir", "ReturnInst 缺少返回值")); } if (!type_ || !type_->IsVoid()) { throw std::runtime_error(FormatError("ir", "ReturnInst 返回类型必须为 void")); } - value_->AddUser(this); + AddOperand(val); } -Value* ReturnInst::GetValue() const { return value_; } +Value* ReturnInst::GetValue() const { return GetOperand(0); } AllocaInst::AllocaInst(std::shared_ptr ptr_ty, std::string name) : Instruction(Opcode::Alloca, std::move(ptr_ty), std::move(name)) { @@ -72,49 +106,46 @@ AllocaInst::AllocaInst(std::shared_ptr ptr_ty, std::string name) } LoadInst::LoadInst(std::shared_ptr val_ty, Value* ptr, std::string name) - : Instruction(Opcode::Load, std::move(val_ty), std::move(name)), - ptr_(ptr) { - if (!ptr_) { + : Instruction(Opcode::Load, std::move(val_ty), std::move(name)) { + if (!ptr) { throw std::runtime_error(FormatError("ir", "LoadInst 缺少 ptr")); } if (!type_ || !type_->IsInt32()) { throw std::runtime_error(FormatError("ir", "LoadInst 当前只支持加载 i32")); } - if (!ptr_->GetType() || !ptr_->GetType()->IsPtrInt32()) { + if (!ptr->GetType() || !ptr->GetType()->IsPtrInt32()) { throw std::runtime_error( FormatError("ir", "LoadInst 当前只支持从 i32* 加载")); } - ptr_->AddUser(this); + AddOperand(ptr); } -Value* LoadInst::GetPtr() const { return ptr_; } +Value* LoadInst::GetPtr() const { return GetOperand(0); } StoreInst::StoreInst(std::shared_ptr void_ty, Value* val, Value* ptr) - : Instruction(Opcode::Store, std::move(void_ty), ""), - value_(val), - ptr_(ptr) { - if (!value_) { + : Instruction(Opcode::Store, std::move(void_ty), "") { + if (!val) { throw std::runtime_error(FormatError("ir", "StoreInst 缺少 value")); } - if (!ptr_) { + if (!ptr) { throw std::runtime_error(FormatError("ir", "StoreInst 缺少 ptr")); } if (!type_ || !type_->IsVoid()) { throw std::runtime_error(FormatError("ir", "StoreInst 返回类型必须为 void")); } - if (!value_->GetType() || !value_->GetType()->IsInt32()) { + if (!val->GetType() || !val->GetType()->IsInt32()) { throw std::runtime_error(FormatError("ir", "StoreInst 当前只支持存储 i32")); } - if (!ptr_->GetType() || !ptr_->GetType()->IsPtrInt32()) { + if (!ptr->GetType() || !ptr->GetType()->IsPtrInt32()) { throw std::runtime_error( FormatError("ir", "StoreInst 当前只支持写入 i32*")); } - value_->AddUser(this); - ptr_->AddUser(this); + AddOperand(val); + AddOperand(ptr); } -Value* StoreInst::GetValue() const { return value_; } +Value* StoreInst::GetValue() const { return GetOperand(0); } -Value* StoreInst::GetPtr() const { return ptr_; } +Value* StoreInst::GetPtr() const { return GetOperand(1); } } // namespace ir diff --git a/src/irgen/IRGenDecl.cpp b/src/irgen/IRGenDecl.cpp index 4e83134..0eb62ae 100644 --- a/src/irgen/IRGenDecl.cpp +++ b/src/irgen/IRGenDecl.cpp @@ -17,58 +17,91 @@ std::string GetLValueName(SysYParser::LValueContext& lvalue) { } // namespace -void IRGenImpl::GenBlock(SysYParser::BlockStmtContext& block) { - for (auto* item : block.blockItem()) { +std::any IRGenImpl::visitBlockStmt(SysYParser::BlockStmtContext* ctx) { + if (!ctx) { + throw std::runtime_error(FormatError("irgen", "缺少语句块")); + } + for (auto* item : ctx->blockItem()) { if (item) { - if (GenBlockItem(*item)) { + if (VisitBlockItemResult(*item) == BlockFlow::Terminated) { // 当前语法要求 return 为块内最后一条语句;命中后可停止生成。 break; } } } + return {}; +} + +IRGenImpl::BlockFlow IRGenImpl::VisitBlockItemResult( + SysYParser::BlockItemContext& item) { + return std::any_cast(item.accept(this)); } -bool IRGenImpl::GenBlockItem(SysYParser::BlockItemContext& item) { - if (item.decl()) { - GenDecl(*item.decl()); - return false; +std::any IRGenImpl::visitBlockItem(SysYParser::BlockItemContext* ctx) { + if (!ctx) { + throw std::runtime_error(FormatError("irgen", "缺少块内项")); + } + if (ctx->decl()) { + ctx->decl()->accept(this); + return BlockFlow::Continue; } - if (item.stmt()) { - return GenStmt(*item.stmt()); + if (ctx->stmt()) { + return ctx->stmt()->accept(this); } throw std::runtime_error(FormatError("irgen", "暂不支持的语句或声明")); } -void IRGenImpl::GenDecl(SysYParser::DeclContext& decl) { - if (!decl.btype() || !decl.btype()->INT()) { +// 变量声明的 IR 生成目前也是最小实现: +// - 先检查声明的基础类型,当前仅支持局部 int; +// - 再把 Decl 中的变量定义交给 visitVarDef 继续处理。 +// +// 和更完整的版本相比,这里还没有: +// - 一个 Decl 中多个变量定义的顺序处理; +// - const、数组、全局变量等不同声明形态; +// - 更丰富的类型系统。 +std::any IRGenImpl::visitDecl(SysYParser::DeclContext* ctx) { + if (!ctx) { + throw std::runtime_error(FormatError("irgen", "缺少变量声明")); + } + if (!ctx->btype() || !ctx->btype()->INT()) { throw std::runtime_error(FormatError("irgen", "当前仅支持局部 int 变量声明")); } - auto* var_def = decl.varDef(); + auto* var_def = ctx->varDef(); if (!var_def) { throw std::runtime_error(FormatError("irgen", "非法变量声明")); } - GenVarDef(*var_def); + var_def->accept(this); + return {}; } -void IRGenImpl::GenVarDef(SysYParser::VarDefContext& decl) { - if (!decl.lValue()) { + +// 当前仍是教学用的最小版本,因此这里只支持: +// - 局部 int 变量; +// - 标量初始化; +// - 一个 VarDef 对应一个槽位。 +std::any IRGenImpl::visitVarDef(SysYParser::VarDefContext* ctx) { + if (!ctx) { + throw std::runtime_error(FormatError("irgen", "缺少变量定义")); + } + if (!ctx->lValue()) { throw std::runtime_error(FormatError("irgen", "变量声明缺少名称")); } - GetLValueName(*decl.lValue()); - if (storage_map_.find(&decl) != storage_map_.end()) { + GetLValueName(*ctx->lValue()); + if (storage_map_.find(ctx) != storage_map_.end()) { throw std::runtime_error(FormatError("irgen", "声明重复生成存储槽位")); } auto* slot = builder_.CreateAllocaI32(module_.GetContext().NextTemp()); - storage_map_[&decl] = slot; + storage_map_[ctx] = slot; ir::Value* init = nullptr; - if (auto* init_value = decl.initValue()) { + if (auto* init_value = ctx->initValue()) { if (!init_value->exp()) { throw std::runtime_error(FormatError("irgen", "当前不支持聚合初始化")); } - init = GenExpr(*init_value->exp()); + init = EvalExpr(*init_value->exp()); } else { init = builder_.CreateConstInt(0); } builder_.CreateStore(init, slot); + return {}; } diff --git a/src/irgen/IRGenDriver.cpp b/src/irgen/IRGenDriver.cpp index 6f2a775..ff94412 100644 --- a/src/irgen/IRGenDriver.cpp +++ b/src/irgen/IRGenDriver.cpp @@ -10,6 +10,6 @@ std::unique_ptr GenerateIR(SysYParser::CompUnitContext& tree, const SemanticContext& sema) { auto module = std::make_unique(); IRGenImpl gen(*module, sema); - gen.Gen(tree); + tree.accept(&gen); return module; } diff --git a/src/irgen/IRGenExp.cpp b/src/irgen/IRGenExp.cpp index efe8723..cf4797c 100644 --- a/src/irgen/IRGenExp.cpp +++ b/src/irgen/IRGenExp.cpp @@ -6,39 +6,75 @@ #include "ir/IR.h" #include "utils/Log.h" -ir::Value* IRGenImpl::GenExpr(SysYParser::ExpContext& expr) { - if (auto* paren = dynamic_cast(&expr)) { - return GenExpr(*paren->exp()); +// 表达式生成当前也只实现了很小的一个子集。 +// 目前支持: +// - 整数字面量 +// - 普通局部变量读取 +// - 括号表达式 +// - 二元加法 +// +// 还未支持: +// - 减乘除与一元运算 +// - 赋值表达式 +// - 函数调用 +// - 数组、指针、下标访问 +// - 条件与比较表达式 +// - ... +ir::Value* IRGenImpl::EvalExpr(SysYParser::ExpContext& expr) { + return std::any_cast(expr.accept(this)); +} + + +std::any IRGenImpl::visitParenExp(SysYParser::ParenExpContext* ctx) { + if (!ctx || !ctx->exp()) { + throw std::runtime_error(FormatError("irgen", "非法括号表达式")); } - if (auto* number = dynamic_cast(&expr)) { - if (!number->number() || !number->number()->ILITERAL()) { - throw std::runtime_error(FormatError("irgen", "当前仅支持整数字面量")); - } - return builder_.CreateConstInt(std::stoi(number->number()->getText())); + return EvalExpr(*ctx->exp()); +} + + +std::any IRGenImpl::visitNumberExp(SysYParser::NumberExpContext* ctx) { + if (!ctx || !ctx->number() || !ctx->number()->ILITERAL()) { + throw std::runtime_error(FormatError("irgen", "当前仅支持整数字面量")); } - if (auto* var = dynamic_cast(&expr)) { - if (!var->var() || !var->var()->ID()) { - throw std::runtime_error(FormatError("irgen", "当前仅支持普通整型变量")); - } - auto* decl = sema_.ResolveVarUse(var->var()); - if (!decl) { - throw std::runtime_error( - FormatError("irgen", - "变量使用缺少语义绑定: " + var->var()->ID()->getText())); - } - auto it = storage_map_.find(decl); - if (it == storage_map_.end()) { - throw std::runtime_error( - FormatError("irgen", - "变量声明缺少存储槽位: " + var->var()->ID()->getText())); - } - return builder_.CreateLoad(it->second, module_.GetContext().NextTemp()); + return static_cast( + builder_.CreateConstInt(std::stoi(ctx->number()->getText()))); +} + +// 变量使用的处理流程: +// 1. 先通过语义分析结果把变量使用绑定回声明; +// 2. 再通过 storage_map_ 找到该声明对应的栈槽位; +// 3. 最后生成 load,把内存中的值读出来。 +// +// 因此当前 IRGen 自己不再做名字查找,而是直接消费 Sema 的绑定结果。 +std::any IRGenImpl::visitVarExp(SysYParser::VarExpContext* ctx) { + if (!ctx || !ctx->var() || !ctx->var()->ID()) { + throw std::runtime_error(FormatError("irgen", "当前仅支持普通整型变量")); + } + auto* decl = sema_.ResolveVarUse(ctx->var()); + if (!decl) { + throw std::runtime_error( + FormatError("irgen", + "变量使用缺少语义绑定: " + ctx->var()->ID()->getText())); + } + auto it = storage_map_.find(decl); + if (it == storage_map_.end()) { + throw std::runtime_error( + FormatError("irgen", + "变量声明缺少存储槽位: " + ctx->var()->ID()->getText())); } - if (auto* binary = dynamic_cast(&expr)) { - ir::Value* lhs = GenExpr(*binary->exp(0)); - ir::Value* rhs = GenExpr(*binary->exp(1)); - return builder_.CreateBinary(ir::Opcode::Add, lhs, rhs, - module_.GetContext().NextTemp()); + 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", "非法加法表达式")); } - throw std::runtime_error(FormatError("irgen", "暂不支持的表达式形式")); + ir::Value* lhs = EvalExpr(*ctx->exp(0)); + ir::Value* rhs = EvalExpr(*ctx->exp(1)); + return static_cast( + builder_.CreateBinary(ir::Opcode::Add, lhs, rhs, + module_.GetContext().NextTemp())); } diff --git a/src/irgen/IRGenFunc.cpp b/src/irgen/IRGenFunc.cpp index 6683183..4912d03 100644 --- a/src/irgen/IRGenFunc.cpp +++ b/src/irgen/IRGenFunc.cpp @@ -27,32 +27,61 @@ IRGenImpl::IRGenImpl(ir::Module& module, const SemanticContext& sema) func_(nullptr), builder_(module.GetContext(), nullptr) {} -void IRGenImpl::Gen(SysYParser::CompUnitContext& cu) { - auto* func = cu.funcDef(); - if (func && func->ID() && func->ID()->getText() == "main") { - GenFuncDef(*func); - return; +// 编译单元的 IR 生成当前只实现了最小功能: +// - Module 已在 GenerateIR 中创建,这里只负责继续生成其中的内容; +// - 当前会读取编译单元中的函数定义,并交给 visitFuncDef 生成函数 IR; +// +// 当前还没有实现: +// - 多个函数定义的遍历与生成; +// - 全局变量、全局常量的 IR 生成。 +std::any IRGenImpl::visitCompUnit(SysYParser::CompUnitContext* ctx) { + if (!ctx) { + throw std::runtime_error(FormatError("irgen", "缺少编译单元")); } - throw std::runtime_error(FormatError("irgen", "缺少 main 定义")); + auto* func = ctx->funcDef(); + if (!func) { + throw std::runtime_error(FormatError("irgen", "缺少函数定义")); + } + func->accept(this); + return {}; } -void IRGenImpl::GenFuncDef(SysYParser::FuncDefContext& func) { - if (!func.blockStmt()) { +// 函数 IR 生成当前实现了: +// 1. 获取函数名; +// 2. 检查函数返回类型; +// 3. 在 Module 中创建 Function; +// 4. 将 builder 插入点设置到入口基本块; +// 5. 继续生成函数体。 +// +// 当前还没有实现: +// - 通用函数返回类型处理; +// - 形参列表遍历与参数类型收集; +// - FunctionType 这样的函数类型对象; +// - Argument/形式参数 IR 对象; +// - 入口块中的参数初始化逻辑。 +// ... + +// 因此这里目前只支持最小的“无参 int 函数”生成。 +std::any IRGenImpl::visitFuncDef(SysYParser::FuncDefContext* ctx) { + if (!ctx) { + throw std::runtime_error(FormatError("irgen", "缺少函数定义")); + } + if (!ctx->blockStmt()) { throw std::runtime_error(FormatError("irgen", "函数体为空")); } - if (!func.ID()) { + if (!ctx->ID()) { throw std::runtime_error(FormatError("irgen", "缺少函数名")); } - if (!func.funcType() || !func.funcType()->INT()) { - throw std::runtime_error(FormatError("irgen", "当前仅支持 int main")); + if (!ctx->funcType() || !ctx->funcType()->INT()) { + throw std::runtime_error(FormatError("irgen", "当前仅支持无参 int 函数")); } - func_ = module_.CreateFunction( - func.ID()->getText(), module_.GetContext().Int32()); + func_ = module_.CreateFunction(ctx->ID()->getText(), ir::Type::GetInt32Type()); builder_.SetInsertPoint(func_->GetEntry()); storage_map_.clear(); - GenBlock(*func.blockStmt()); + ctx->blockStmt()->accept(this); // 语义正确性主要由 sema 保证,这里只兜底检查 IR 结构是否合法。 VerifyFunctionStructure(*func_); + return {}; } diff --git a/src/irgen/IRGenStmt.cpp b/src/irgen/IRGenStmt.cpp index 67ce213..751550c 100644 --- a/src/irgen/IRGenStmt.cpp +++ b/src/irgen/IRGenStmt.cpp @@ -6,18 +6,34 @@ #include "ir/IR.h" #include "utils/Log.h" -bool IRGenImpl::GenStmt(SysYParser::StmtContext& stmt) { - if (stmt.returnStmt()) { - GenReturnStmt(*stmt.returnStmt()); - return true; +// 语句生成当前只实现了最小子集。 +// 目前支持: +// - return ; +// +// 还未支持: +// - 赋值语句 +// - if / while 等控制流 +// - 空语句、块语句嵌套分发之外的更多语句形态 + +std::any IRGenImpl::visitStmt(SysYParser::StmtContext* ctx) { + if (!ctx) { + throw std::runtime_error(FormatError("irgen", "缺少语句")); + } + if (ctx->returnStmt()) { + return ctx->returnStmt()->accept(this); } throw std::runtime_error(FormatError("irgen", "暂不支持的语句类型")); } -void IRGenImpl::GenReturnStmt(SysYParser::ReturnStmtContext& ret) { - if (!ret.exp()) { + +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 缺少表达式")); } - ir::Value* v = GenExpr(*ret.exp()); + ir::Value* v = EvalExpr(*ctx->exp()); builder_.CreateRet(v); + return BlockFlow::Terminated; }