refactor(irgen): 规范采用visitor生成

This commit is contained in:
jing
2026-03-18 02:07:34 +08:00
parent 7d4d60c546
commit dfa71bc0d7
8 changed files with 297 additions and 130 deletions

View File

@@ -50,26 +50,37 @@ Lab2 的目标是在该示例基础上扩展语义覆盖范围,并逐步把更
其中,`sema` 负责最基本的名称绑定与合法性检查,`irgen` 在此基础上继续生成 IR。 其中,`sema` 负责最基本的名称绑定与合法性检查,`irgen` 在此基础上继续生成 IR。
如果语义检查阶段没有补全,后续 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 值。后续实验中,同学可按需求再重构。 说明:当前阶段变量统一采用内存模型:先 `alloca` 分配栈槽,再通过 `store/load` 读写。即使变量由常量初始化(如 `int a = 1;`),也会先 `store` 到栈槽,而不是直接把变量替换成 SSA 值。后续实验中,同学可按需求再重构。
此外,当前 IR 还维护了最基本的 use-def 关系:每个 `Value` 会记录哪些 `Instruction` 使用了它 此外,当前 IR 还维护了最基本的 use-def 关系:每个 `Value` 会记录自己的 `Use`/`User` 信息,`Instruction` 通过 operand 列表与这些关系自动关联
这对后续做数据流分析、死代码删除、常量传播等优化会很有帮助;但目前相关实现,接口仍不完整,后续实验中还需要同学继续补充和完善。 这对后续做数据流分析、死代码删除、常量传播等优化会很有帮助;但目前相关实现,接口仍不完整,后续实验中还需要同学继续补充和完善。
## 5. 语法树与 Sema / IRGen 的关系 ## 5. 语法树与 Sema / IRGen 的关系
当前项目中的 `sema``irgen` 都不是面向独立 AST 设计的,而是直接遍历 ANTLR 生成的语法树节点完成语义检查与 IR 生成。 当前项目中的 `sema``irgen` 都不是面向独立 AST 设计的,而是直接基于 ANTLR 生成的语法树节点,并通过 Visitor 方式完成语义检查与 IR 生成。
因此,`src/antlr4/SysY.g4` 中 rule 的命名、层级结构以及 labeled alternative 的写法,会直接影响 `SysYParser::*Context` 的类型名和访问接口;一旦 grammar 发生变化,`sem` / `irgen` 中对应的遍历逻辑通常也需要同步修改。 因此,`SysY.g4` 中 rule 的命名、层级结构以及 labeled alternative 的写法,会直接影响 `SysYParser::*Context` 的类型名和访问接口;一旦 grammar 发生变化,`sem` / `irgen` 中对应的 `visit*` 逻辑通常也需要同步修改。
这也是为什么在 Lab1 扩展 grammar 后Lab2 常常还需要继续修改 `sem` / `irgen`
不是因为 IR 本身一定变了,而是因为“语法树长什么样”,直接决定了语义检查和 IR 生成代码该如何遍历和取信息。
如果 grammar 扩展后 `sem` / `irgen` 没有同步修改,常见现象包括: 如果 grammar 扩展后 `sem` / `irgen` 没有同步修改,常见现象包括:
1. 编译阶段报错,例如某个 `SysYParser::*Context` 类型不存在,或某个成员函数不存在。 1. 编译阶段报错,例如某个 `SysYParser::*Context` 类型不存在,或某个成员函数不存在。
2. 运行阶段报错,例如进入 `暂不支持的表达式形式``暂不支持的语句类型`,或名称绑定失败等分支。 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. 构建与运行 ## 6. 构建与运行

View File

@@ -3,10 +3,12 @@
#pragma once #pragma once
#include <any>
#include <memory> #include <memory>
#include <string> #include <string>
#include <unordered_map> #include <unordered_map>
#include "SysYBaseVisitor.h"
#include "SysYParser.h" #include "SysYParser.h"
#include "ir/IR.h" #include "ir/IR.h"
#include "sem/Sema.h" #include "sem/Sema.h"
@@ -18,22 +20,31 @@ class IRBuilder;
class Value; class Value;
} }
class IRGenImpl { class IRGenImpl final : public SysYBaseVisitor {
public: public:
IRGenImpl(ir::Module& module, const SemanticContext& sema); 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: private:
void GenFuncDef(SysYParser::FuncDefContext& func); enum class BlockFlow {
void GenBlock(SysYParser::BlockStmtContext& block); Continue,
bool GenBlockItem(SysYParser::BlockItemContext& item); Terminated,
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); BlockFlow VisitBlockItemResult(SysYParser::BlockItemContext& item);
ir::Value* EvalExpr(SysYParser::ExpContext& expr);
ir::Module& module_; ir::Module& module_;
const SemanticContext& sema_; const SemanticContext& sema_;

View File

@@ -8,8 +8,47 @@
#include "utils/Log.h" #include "utils/Log.h"
namespace ir { namespace ir {
User::User(std::shared_ptr<Type> 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<Type> ty, std::string name) Instruction::Instruction(Opcode op, std::shared_ptr<Type> 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_; } Opcode Instruction::GetOpcode() const { return opcode_; }
@@ -21,48 +60,43 @@ void Instruction::SetParent(BasicBlock* parent) { parent_ = parent; }
BinaryInst::BinaryInst(Opcode op, std::shared_ptr<Type> ty, Value* lhs, BinaryInst::BinaryInst(Opcode op, std::shared_ptr<Type> ty, Value* lhs,
Value* rhs, std::string name) 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) { if (op != Opcode::Add) {
throw std::runtime_error(FormatError("ir", "BinaryInst 当前只支持 Add")); throw std::runtime_error(FormatError("ir", "BinaryInst 当前只支持 Add"));
} }
if (!lhs_ || !rhs_) { if (!lhs || !rhs) {
throw std::runtime_error(FormatError("ir", "BinaryInst 缺少操作数")); 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 缺少类型信息")); throw std::runtime_error(FormatError("ir", "BinaryInst 缺少类型信息"));
} }
if (lhs_->GetType()->GetKind() != rhs_->GetType()->GetKind() || if (lhs->GetType()->GetKind() != rhs->GetType()->GetKind() ||
type_->GetKind() != lhs_->GetType()->GetKind()) { type_->GetKind() != lhs->GetType()->GetKind()) {
throw std::runtime_error(FormatError("ir", "BinaryInst 类型不匹配")); throw std::runtime_error(FormatError("ir", "BinaryInst 类型不匹配"));
} }
if (!type_->IsInt32()) { if (!type_->IsInt32()) {
throw std::runtime_error(FormatError("ir", "BinaryInst 当前只支持 i32")); throw std::runtime_error(FormatError("ir", "BinaryInst 当前只支持 i32"));
} }
if (lhs_) { AddOperand(lhs);
lhs_->AddUser(this); AddOperand(rhs);
}
if (rhs_) {
rhs_->AddUser(this);
}
} }
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<Type> void_ty, Value* val) ReturnInst::ReturnInst(std::shared_ptr<Type> void_ty, Value* val)
: Instruction(Opcode::Ret, std::move(void_ty), ""), : Instruction(Opcode::Ret, std::move(void_ty), "") {
value_(val) { if (!val) {
if (!value_) {
throw std::runtime_error(FormatError("ir", "ReturnInst 缺少返回值")); throw std::runtime_error(FormatError("ir", "ReturnInst 缺少返回值"));
} }
if (!type_ || !type_->IsVoid()) { if (!type_ || !type_->IsVoid()) {
throw std::runtime_error(FormatError("ir", "ReturnInst 返回类型必须为 void")); 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<Type> ptr_ty, std::string name) AllocaInst::AllocaInst(std::shared_ptr<Type> ptr_ty, std::string name)
: Instruction(Opcode::Alloca, std::move(ptr_ty), std::move(name)) { : Instruction(Opcode::Alloca, std::move(ptr_ty), std::move(name)) {
@@ -72,49 +106,46 @@ AllocaInst::AllocaInst(std::shared_ptr<Type> ptr_ty, std::string name)
} }
LoadInst::LoadInst(std::shared_ptr<Type> val_ty, Value* ptr, std::string name) LoadInst::LoadInst(std::shared_ptr<Type> val_ty, Value* ptr, std::string name)
: Instruction(Opcode::Load, std::move(val_ty), std::move(name)), : Instruction(Opcode::Load, std::move(val_ty), std::move(name)) {
ptr_(ptr) { if (!ptr) {
if (!ptr_) {
throw std::runtime_error(FormatError("ir", "LoadInst 缺少 ptr")); throw std::runtime_error(FormatError("ir", "LoadInst 缺少 ptr"));
} }
if (!type_ || !type_->IsInt32()) { if (!type_ || !type_->IsInt32()) {
throw std::runtime_error(FormatError("ir", "LoadInst 当前只支持加载 i32")); throw std::runtime_error(FormatError("ir", "LoadInst 当前只支持加载 i32"));
} }
if (!ptr_->GetType() || !ptr_->GetType()->IsPtrInt32()) { if (!ptr->GetType() || !ptr->GetType()->IsPtrInt32()) {
throw std::runtime_error( throw std::runtime_error(
FormatError("ir", "LoadInst 当前只支持从 i32* 加载")); 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<Type> void_ty, Value* val, Value* ptr) StoreInst::StoreInst(std::shared_ptr<Type> void_ty, Value* val, Value* ptr)
: Instruction(Opcode::Store, std::move(void_ty), ""), : Instruction(Opcode::Store, std::move(void_ty), "") {
value_(val), if (!val) {
ptr_(ptr) {
if (!value_) {
throw std::runtime_error(FormatError("ir", "StoreInst 缺少 value")); throw std::runtime_error(FormatError("ir", "StoreInst 缺少 value"));
} }
if (!ptr_) { if (!ptr) {
throw std::runtime_error(FormatError("ir", "StoreInst 缺少 ptr")); throw std::runtime_error(FormatError("ir", "StoreInst 缺少 ptr"));
} }
if (!type_ || !type_->IsVoid()) { if (!type_ || !type_->IsVoid()) {
throw std::runtime_error(FormatError("ir", "StoreInst 返回类型必须为 void")); 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")); throw std::runtime_error(FormatError("ir", "StoreInst 当前只支持存储 i32"));
} }
if (!ptr_->GetType() || !ptr_->GetType()->IsPtrInt32()) { if (!ptr->GetType() || !ptr->GetType()->IsPtrInt32()) {
throw std::runtime_error( throw std::runtime_error(
FormatError("ir", "StoreInst 当前只支持写入 i32*")); FormatError("ir", "StoreInst 当前只支持写入 i32*"));
} }
value_->AddUser(this); AddOperand(val);
ptr_->AddUser(this); 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 } // namespace ir

View File

@@ -17,58 +17,91 @@ std::string GetLValueName(SysYParser::LValueContext& lvalue) {
} // namespace } // namespace
void IRGenImpl::GenBlock(SysYParser::BlockStmtContext& block) { std::any IRGenImpl::visitBlockStmt(SysYParser::BlockStmtContext* ctx) {
for (auto* item : block.blockItem()) { if (!ctx) {
throw std::runtime_error(FormatError("irgen", "缺少语句块"));
}
for (auto* item : ctx->blockItem()) {
if (item) { if (item) {
if (GenBlockItem(*item)) { if (VisitBlockItemResult(*item) == BlockFlow::Terminated) {
// 当前语法要求 return 为块内最后一条语句;命中后可停止生成。 // 当前语法要求 return 为块内最后一条语句;命中后可停止生成。
break; break;
} }
} }
} }
return {};
} }
bool IRGenImpl::GenBlockItem(SysYParser::BlockItemContext& item) { IRGenImpl::BlockFlow IRGenImpl::VisitBlockItemResult(
if (item.decl()) { SysYParser::BlockItemContext& item) {
GenDecl(*item.decl()); return std::any_cast<BlockFlow>(item.accept(this));
return false;
} }
if (item.stmt()) {
return GenStmt(*item.stmt()); 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 (ctx->stmt()) {
return ctx->stmt()->accept(this);
} }
throw std::runtime_error(FormatError("irgen", "暂不支持的语句或声明")); throw std::runtime_error(FormatError("irgen", "暂不支持的语句或声明"));
} }
void IRGenImpl::GenDecl(SysYParser::DeclContext& decl) { // 变量声明的 IR 生成目前也是最小实现:
if (!decl.btype() || !decl.btype()->INT()) { // - 先检查声明的基础类型,当前仅支持局部 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 变量声明")); throw std::runtime_error(FormatError("irgen", "当前仅支持局部 int 变量声明"));
} }
auto* var_def = decl.varDef(); auto* var_def = ctx->varDef();
if (!var_def) { if (!var_def) {
throw std::runtime_error(FormatError("irgen", "非法变量声明")); 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", "变量声明缺少名称")); throw std::runtime_error(FormatError("irgen", "变量声明缺少名称"));
} }
GetLValueName(*decl.lValue()); GetLValueName(*ctx->lValue());
if (storage_map_.find(&decl) != storage_map_.end()) { if (storage_map_.find(ctx) != storage_map_.end()) {
throw std::runtime_error(FormatError("irgen", "声明重复生成存储槽位")); throw std::runtime_error(FormatError("irgen", "声明重复生成存储槽位"));
} }
auto* slot = builder_.CreateAllocaI32(module_.GetContext().NextTemp()); auto* slot = builder_.CreateAllocaI32(module_.GetContext().NextTemp());
storage_map_[&decl] = slot; storage_map_[ctx] = slot;
ir::Value* init = nullptr; ir::Value* init = nullptr;
if (auto* init_value = decl.initValue()) { if (auto* init_value = ctx->initValue()) {
if (!init_value->exp()) { if (!init_value->exp()) {
throw std::runtime_error(FormatError("irgen", "当前不支持聚合初始化")); throw std::runtime_error(FormatError("irgen", "当前不支持聚合初始化"));
} }
init = GenExpr(*init_value->exp()); init = EvalExpr(*init_value->exp());
} else { } else {
init = builder_.CreateConstInt(0); init = builder_.CreateConstInt(0);
} }
builder_.CreateStore(init, slot); builder_.CreateStore(init, slot);
return {};
} }

View File

@@ -10,6 +10,6 @@ std::unique_ptr<ir::Module> GenerateIR(SysYParser::CompUnitContext& tree,
const SemanticContext& sema) { const SemanticContext& sema) {
auto module = std::make_unique<ir::Module>(); auto module = std::make_unique<ir::Module>();
IRGenImpl gen(*module, sema); IRGenImpl gen(*module, sema);
gen.Gen(tree); tree.accept(&gen);
return module; return module;
} }

View File

@@ -6,39 +6,75 @@
#include "ir/IR.h" #include "ir/IR.h"
#include "utils/Log.h" #include "utils/Log.h"
ir::Value* IRGenImpl::GenExpr(SysYParser::ExpContext& expr) { // 表达式生成当前也只实现了很小的一个子集。
if (auto* paren = dynamic_cast<SysYParser::ParenExpContext*>(&expr)) { // 目前支持:
return GenExpr(*paren->exp()); // - 整数字面量
// - 普通局部变量读取
// - 括号表达式
// - 二元加法
//
// 还未支持:
// - 减乘除与一元运算
// - 赋值表达式
// - 函数调用
// - 数组、指针、下标访问
// - 条件与比较表达式
// - ...
ir::Value* IRGenImpl::EvalExpr(SysYParser::ExpContext& expr) {
return std::any_cast<ir::Value*>(expr.accept(this));
} }
if (auto* number = dynamic_cast<SysYParser::NumberExpContext*>(&expr)) {
if (!number->number() || !number->number()->ILITERAL()) {
std::any IRGenImpl::visitParenExp(SysYParser::ParenExpContext* ctx) {
if (!ctx || !ctx->exp()) {
throw std::runtime_error(FormatError("irgen", "非法括号表达式"));
}
return EvalExpr(*ctx->exp());
}
std::any IRGenImpl::visitNumberExp(SysYParser::NumberExpContext* ctx) {
if (!ctx || !ctx->number() || !ctx->number()->ILITERAL()) {
throw std::runtime_error(FormatError("irgen", "当前仅支持整数字面量")); throw std::runtime_error(FormatError("irgen", "当前仅支持整数字面量"));
} }
return builder_.CreateConstInt(std::stoi(number->number()->getText())); return static_cast<ir::Value*>(
builder_.CreateConstInt(std::stoi(ctx->number()->getText())));
} }
if (auto* var = dynamic_cast<SysYParser::VarExpContext*>(&expr)) {
if (!var->var() || !var->var()->ID()) { // 变量使用的处理流程:
// 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", "当前仅支持普通整型变量")); throw std::runtime_error(FormatError("irgen", "当前仅支持普通整型变量"));
} }
auto* decl = sema_.ResolveVarUse(var->var()); auto* decl = sema_.ResolveVarUse(ctx->var());
if (!decl) { if (!decl) {
throw std::runtime_error( throw std::runtime_error(
FormatError("irgen", FormatError("irgen",
"变量使用缺少语义绑定: " + var->var()->ID()->getText())); "变量使用缺少语义绑定: " + ctx->var()->ID()->getText()));
} }
auto it = storage_map_.find(decl); auto it = storage_map_.find(decl);
if (it == storage_map_.end()) { if (it == storage_map_.end()) {
throw std::runtime_error( throw std::runtime_error(
FormatError("irgen", FormatError("irgen",
"变量声明缺少存储槽位: " + var->var()->ID()->getText())); "变量声明缺少存储槽位: " + ctx->var()->ID()->getText()));
} }
return builder_.CreateLoad(it->second, module_.GetContext().NextTemp()); return static_cast<ir::Value*>(
builder_.CreateLoad(it->second, module_.GetContext().NextTemp()));
} }
if (auto* binary = dynamic_cast<SysYParser::AdditiveExpContext*>(&expr)) {
ir::Value* lhs = GenExpr(*binary->exp(0));
ir::Value* rhs = GenExpr(*binary->exp(1)); std::any IRGenImpl::visitAdditiveExp(SysYParser::AdditiveExpContext* ctx) {
return builder_.CreateBinary(ir::Opcode::Add, lhs, rhs, if (!ctx || !ctx->exp(0) || !ctx->exp(1)) {
module_.GetContext().NextTemp()); 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<ir::Value*>(
builder_.CreateBinary(ir::Opcode::Add, lhs, rhs,
module_.GetContext().NextTemp()));
} }

View File

@@ -27,32 +27,61 @@ IRGenImpl::IRGenImpl(ir::Module& module, const SemanticContext& sema)
func_(nullptr), func_(nullptr),
builder_(module.GetContext(), nullptr) {} builder_(module.GetContext(), nullptr) {}
void IRGenImpl::Gen(SysYParser::CompUnitContext& cu) { // 编译单元的 IR 生成当前只实现了最小功能:
auto* func = cu.funcDef(); // - Module 已在 GenerateIR 中创建,这里只负责继续生成其中的内容;
if (func && func->ID() && func->ID()->getText() == "main") { // - 当前会读取编译单元中的函数定义,并交给 visitFuncDef 生成函数 IR
GenFuncDef(*func); //
return; // 当前还没有实现:
// - 多个函数定义的遍历与生成;
// - 全局变量、全局常量的 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) { // 函数 IR 生成当前实现了:
if (!func.blockStmt()) { // 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", "函数体为空")); throw std::runtime_error(FormatError("irgen", "函数体为空"));
} }
if (!func.ID()) { if (!ctx->ID()) {
throw std::runtime_error(FormatError("irgen", "缺少函数名")); throw std::runtime_error(FormatError("irgen", "缺少函数名"));
} }
if (!func.funcType() || !func.funcType()->INT()) { if (!ctx->funcType() || !ctx->funcType()->INT()) {
throw std::runtime_error(FormatError("irgen", "当前仅支持 int main")); throw std::runtime_error(FormatError("irgen", "当前仅支持无参 int 函数"));
} }
func_ = module_.CreateFunction( func_ = module_.CreateFunction(ctx->ID()->getText(), ir::Type::GetInt32Type());
func.ID()->getText(), module_.GetContext().Int32());
builder_.SetInsertPoint(func_->GetEntry()); builder_.SetInsertPoint(func_->GetEntry());
storage_map_.clear(); storage_map_.clear();
GenBlock(*func.blockStmt()); ctx->blockStmt()->accept(this);
// 语义正确性主要由 sema 保证,这里只兜底检查 IR 结构是否合法。 // 语义正确性主要由 sema 保证,这里只兜底检查 IR 结构是否合法。
VerifyFunctionStructure(*func_); VerifyFunctionStructure(*func_);
return {};
} }

View File

@@ -6,18 +6,34 @@
#include "ir/IR.h" #include "ir/IR.h"
#include "utils/Log.h" #include "utils/Log.h"
bool IRGenImpl::GenStmt(SysYParser::StmtContext& stmt) { // 语句生成当前只实现了最小子集。
if (stmt.returnStmt()) { // 目前支持:
GenReturnStmt(*stmt.returnStmt()); // - return <exp>;
return true; //
// 还未支持:
// - 赋值语句
// - 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", "暂不支持的语句类型")); 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 缺少表达式")); throw std::runtime_error(FormatError("irgen", "return 缺少表达式"));
} }
ir::Value* v = GenExpr(*ret.exp()); ir::Value* v = EvalExpr(*ctx->exp());
builder_.CreateRet(v); builder_.CreateRet(v);
return BlockFlow::Terminated;
} }