diff --git a/doc/Lab1-语法树构建.md b/doc/Lab1-语法树构建.md index 688eafd..67b79f6 100644 --- a/doc/Lab1-语法树构建.md +++ b/doc/Lab1-语法树构建.md @@ -69,3 +69,8 @@ java -jar third_party/antlr-4.13.2-complete.jar \ # 仅输出语法树 ./build/bin/compiler --emit-parse-tree test/test_case/simple_add.sy ``` + +## 7. 关于 AST 的建议 + +同学们也可以自行设计一层抽象语法树(AST),将 ANTLR 语法树先转换为 AST,再进入后续阶段。 +这样可以减少对具体文法细节的依赖,使语义分析、IR 生成和后续扩展更清晰。这里不做具体要求。 diff --git a/doc/Lab2-中间表示生成.md b/doc/Lab2-中间表示生成.md index 864181a..9da0950 100644 --- a/doc/Lab2-中间表示生成.md +++ b/doc/Lab2-中间表示生成.md @@ -57,6 +57,9 @@ Lab2 的目标是在该示例基础上扩展语义覆盖范围,逐步把更多 说明:当前阶段变量统一采用内存模型:先 `alloca` 分配栈槽,再通过 `store/load` 读写。即使变量由常量初始化(如 `int a = 1;`),也会先 `store` 到栈槽,而不是直接把变量替换成 SSA 值。后续实验中,同学可按需求再重构。 +此外,当前 IR 还维护了最基本的 use-def 关系:每个 `Value` 会记录哪些 `Instruction` 使用了它。 +这对后续做数据流分析、死代码删除、常量传播等优化会很有帮助;但目前相关实现,接口仍不完整,后续实验中还需要同学继续补充和完善。 + ## 6. 构建与运行 ```bash diff --git a/src/ir/Function.cpp b/src/ir/Function.cpp index 34c7b71..3772494 100644 --- a/src/ir/Function.cpp +++ b/src/ir/Function.cpp @@ -6,7 +6,18 @@ namespace ir { Function::Function(std::string name, std::shared_ptr ret_type) - : Value(std::move(ret_type), std::move(name)), - entry_(std::make_unique("entry")) {} + : Value(std::move(ret_type), std::move(name)) { + entry_ = CreateBlock("entry"); +} + +BasicBlock* Function::CreateBlock(const std::string& name) { + auto block = std::make_unique(name); + auto* ptr = block.get(); + blocks_.push_back(std::move(block)); + if (!entry_) { + entry_ = ptr; + } + return ptr; +} } // namespace ir diff --git a/src/ir/IR.h b/src/ir/IR.h index 0e60eb8..1f03ee1 100644 --- a/src/ir/IR.h +++ b/src/ir/IR.h @@ -3,6 +3,7 @@ #pragma once #include +#include #include #include #include @@ -13,6 +14,7 @@ namespace ir { class Type; class ConstantInt; class Instruction; +class BasicBlock; // IR 上下文:集中管理类型、常量等共享资源,便于复用与扩展。 class Context { @@ -82,9 +84,13 @@ class Instruction : public Value { Instruction(Opcode op, std::shared_ptr ty, std::string name = "") : Value(std::move(ty), std::move(name)), opcode_(op) {} Opcode opcode() const { return opcode_; } + bool IsTerminator() const { return opcode_ == Opcode::Ret; } + BasicBlock* parent() const { return parent_; } + void set_parent(BasicBlock* parent) { parent_ = parent; } private: Opcode opcode_; + BasicBlock* parent_ = nullptr; }; class BinaryInst : public Instruction { @@ -137,13 +143,21 @@ class BasicBlock { public: explicit BasicBlock(std::string name) : name_(std::move(name)) {} const std::string& name() const { return name_; } + bool HasTerminator() const { + return !instructions_.empty() && instructions_.back()->IsTerminator(); + } const std::vector>& instructions() const { return instructions_; } template T* Append(Args&&... args) { + if (HasTerminator()) { + throw std::runtime_error("BasicBlock 已有 terminator,不能继续追加指令: " + + name_); + } auto inst = std::make_unique(std::forward(args)...); auto* ptr = inst.get(); + ptr->set_parent(this); instructions_.push_back(std::move(inst)); return ptr; } @@ -157,11 +171,16 @@ class Function : public Value { public: // 允许显式指定返回类型,便于后续扩展多种函数签名。 Function(std::string name, std::shared_ptr ret_type); - BasicBlock* entry() { return entry_.get(); } - const BasicBlock* entry() const { return entry_.get(); } + BasicBlock* CreateBlock(const std::string& name); + BasicBlock* entry() { return entry_; } + const BasicBlock* entry() const { return entry_; } + const std::vector>& blocks() const { + return blocks_; + } private: - std::unique_ptr entry_; + BasicBlock* entry_ = nullptr; + std::vector> blocks_; }; class Module { diff --git a/src/ir/IRBuilder.cpp b/src/ir/IRBuilder.cpp index a38652f..1812f14 100644 --- a/src/ir/IRBuilder.cpp +++ b/src/ir/IRBuilder.cpp @@ -12,6 +12,10 @@ bool IsArithmeticType(const std::shared_ptr& ty) { return ty && ty->kind() == Type::Kind::Int32; } +bool IsPtrInt32Type(const std::shared_ptr& ty) { + return ty && ty->kind() == Type::Kind::PtrInt32; +} + } // namespace ConstantInt* IRBuilder::CreateConstInt(int v) { @@ -54,6 +58,12 @@ LoadInst* IRBuilder::CreateLoad(Value* ptr, const std::string& name) { if (!insertBlock_) { throw std::runtime_error("IRBuilder 未设置插入点"); } + if (!ptr) { + throw std::runtime_error("IRBuilder::CreateLoad 缺少 ptr"); + } + if (!IsPtrInt32Type(ptr->type())) { + throw std::runtime_error("IRBuilder::CreateLoad 当前只支持从 i32* 加载"); + } return insertBlock_->Append(ptr, name); } @@ -61,6 +71,18 @@ StoreInst* IRBuilder::CreateStore(Value* val, Value* ptr) { if (!insertBlock_) { throw std::runtime_error("IRBuilder 未设置插入点"); } + if (!val) { + throw std::runtime_error("IRBuilder::CreateStore 缺少 val"); + } + if (!ptr) { + throw std::runtime_error("IRBuilder::CreateStore 缺少 ptr"); + } + if (!IsArithmeticType(val->type())) { + throw std::runtime_error("IRBuilder::CreateStore 当前只支持存储 i32"); + } + if (!IsPtrInt32Type(ptr->type())) { + throw std::runtime_error("IRBuilder::CreateStore 当前只支持写入 i32*"); + } return insertBlock_->Append(val, ptr); } @@ -68,6 +90,9 @@ ReturnInst* IRBuilder::CreateRet(Value* v) { if (!insertBlock_) { throw std::runtime_error("IRBuilder 未设置插入点"); } + if (!v) { + throw std::runtime_error("IRBuilder::CreateRet 缺少返回值"); + } return insertBlock_->Append(v); } diff --git a/src/ir/IRPrinter.cpp b/src/ir/IRPrinter.cpp index 726fe70..4e7642d 100644 --- a/src/ir/IRPrinter.cpp +++ b/src/ir/IRPrinter.cpp @@ -5,6 +5,7 @@ #include "ir/IR.h" #include +#include #include namespace ir { @@ -41,6 +42,13 @@ static const char* OpcodeToString(Opcode op) { return "?"; } +static std::string ValueToString(const Value* v) { + if (auto* ci = dynamic_cast(v)) { + return std::to_string(ci->value()); + } + return v ? v->name() : ""; +} + void IRPrinter::Print(const Module& module) { for (const auto& func : module.functions()) { std::cout << "define " << TypeToString(*func->type()) << " @" @@ -60,7 +68,8 @@ void IRPrinter::Print(const Module& module) { auto* bin = static_cast(inst); std::cout << " " << bin->name() << " = " << OpcodeToString(bin->opcode()) << " " << TypeToString(*bin->lhs()->type()) << " " - << bin->lhs()->name() << ", " << bin->rhs()->name() << "\n"; + << ValueToString(bin->lhs()) << ", " + << ValueToString(bin->rhs()) << "\n"; break; } case Opcode::Alloca: { @@ -71,19 +80,19 @@ void IRPrinter::Print(const Module& module) { case Opcode::Load: { auto* load = static_cast(inst); std::cout << " " << load->name() << " = load i32, i32* " - << load->ptr()->name() << "\n"; + << ValueToString(load->ptr()) << "\n"; break; } case Opcode::Store: { auto* store = static_cast(inst); - std::cout << " store i32 " << store->value()->name() << ", i32* " - << store->ptr()->name() << "\n"; + std::cout << " store i32 " << ValueToString(store->value()) << ", i32* " + << ValueToString(store->ptr()) << "\n"; break; } case Opcode::Ret: { auto* ret = static_cast(inst); std::cout << " ret " << TypeToString(*ret->value()->type()) << " " - << ret->value()->name() << "\n"; + << ValueToString(ret->value()) << "\n"; break; } } diff --git a/src/ir/Instruction.cpp b/src/ir/Instruction.cpp index d7091be..596724a 100644 --- a/src/ir/Instruction.cpp +++ b/src/ir/Instruction.cpp @@ -3,11 +3,40 @@ // - 指令操作数与结果类型管理,支持打印与优化 #include "ir/IR.h" +#include + namespace ir { +namespace { + +bool IsArithmeticType(const std::shared_ptr& ty) { + return ty && ty->kind() == Type::Kind::Int32; +} + +bool IsPtrInt32Type(const std::shared_ptr& ty) { + return ty && ty->kind() == Type::Kind::PtrInt32; +} + +} // namespace 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) { + if (op != Opcode::Add) { + throw std::runtime_error("BinaryInst 当前只支持 Add"); + } + if (!lhs_ || !rhs_) { + throw std::runtime_error("BinaryInst 缺少操作数"); + } + if (!type_ || !lhs_->type() || !rhs_->type()) { + throw std::runtime_error("BinaryInst 缺少类型信息"); + } + if (lhs_->type()->kind() != rhs_->type()->kind() || + type_->kind() != lhs_->type()->kind()) { + throw std::runtime_error("BinaryInst 类型不匹配"); + } + if (!IsArithmeticType(type_)) { + throw std::runtime_error("BinaryInst 当前只支持 i32"); + } if (lhs_) { lhs_->AddUser(this); } @@ -18,9 +47,10 @@ BinaryInst::BinaryInst(Opcode op, std::shared_ptr ty, Value* lhs, ReturnInst::ReturnInst(Value* val) : Instruction(Opcode::Ret, Type::Void(), ""), value_(val) { - if (value_) { - value_->AddUser(this); + if (!value_) { + throw std::runtime_error("ReturnInst 缺少返回值"); } + value_->AddUser(this); } AllocaInst::AllocaInst(std::string name) @@ -28,19 +58,31 @@ AllocaInst::AllocaInst(std::string name) LoadInst::LoadInst(Value* ptr, std::string name) : Instruction(Opcode::Load, Type::Int32(), std::move(name)), ptr_(ptr) { - if (ptr_) { - ptr_->AddUser(this); + if (!ptr_) { + throw std::runtime_error("LoadInst 缺少 ptr"); } + if (!IsPtrInt32Type(ptr_->type())) { + throw std::runtime_error("LoadInst 当前只支持从 i32* 加载"); + } + ptr_->AddUser(this); } StoreInst::StoreInst(Value* val, Value* ptr) : Instruction(Opcode::Store, Type::Void(), ""), value_(val), ptr_(ptr) { - if (value_) { - value_->AddUser(this); + if (!value_) { + throw std::runtime_error("StoreInst 缺少 value"); + } + if (!ptr_) { + throw std::runtime_error("StoreInst 缺少 ptr"); + } + if (!IsArithmeticType(value_->type())) { + throw std::runtime_error("StoreInst 当前只支持存储 i32"); } - if (ptr_) { - ptr_->AddUser(this); + if (!IsPtrInt32Type(ptr_->type())) { + throw std::runtime_error("StoreInst 当前只支持写入 i32*"); } + value_->AddUser(this); + ptr_->AddUser(this); } } // namespace ir diff --git a/src/irgen/IRGenStmt.cpp b/src/irgen/IRGenStmt.cpp index 8914705..9b63daa 100644 --- a/src/irgen/IRGenStmt.cpp +++ b/src/irgen/IRGenStmt.cpp @@ -6,10 +6,6 @@ #include "ir/IR.h" bool IRGenImpl::GenStmt(SysYParser::StmtContext& stmt) { - if (stmt.varDecl()) { - GenVarDecl(*stmt.varDecl()); - return false; - } if (stmt.returnStmt()) { GenReturnStmt(*stmt.returnStmt()); return true;