style(ir): 纠正代码位置
This commit is contained in:
@@ -3,3 +3,22 @@
|
||||
// - 维护或可计算前驱/后继关系,用于 CFG 分析与优化
|
||||
|
||||
#include "ir/IR.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace ir {
|
||||
|
||||
BasicBlock::BasicBlock(std::string name) : name_(std::move(name)) {}
|
||||
|
||||
const std::string& BasicBlock::name() const { return name_; }
|
||||
|
||||
bool BasicBlock::HasTerminator() const {
|
||||
return !instructions_.empty() && instructions_.back()->IsTerminator();
|
||||
}
|
||||
|
||||
const std::vector<std::unique_ptr<Instruction>>& BasicBlock::instructions()
|
||||
const {
|
||||
return instructions_;
|
||||
}
|
||||
|
||||
} // namespace ir
|
||||
|
||||
@@ -20,4 +20,12 @@ BasicBlock* Function::CreateBlock(const std::string& name) {
|
||||
return ptr;
|
||||
}
|
||||
|
||||
BasicBlock* Function::entry() { return entry_; }
|
||||
|
||||
const BasicBlock* Function::entry() const { return entry_; }
|
||||
|
||||
const std::vector<std::unique_ptr<BasicBlock>>& Function::blocks() const {
|
||||
return blocks_;
|
||||
}
|
||||
|
||||
} // namespace ir
|
||||
|
||||
75
src/ir/IR.h
75
src/ir/IR.h
@@ -41,8 +41,8 @@ Context& DefaultContext();
|
||||
class Type {
|
||||
public:
|
||||
enum class Kind { Void, Int32, PtrInt32 };
|
||||
explicit Type(Kind k) : kind_(k) {}
|
||||
Kind kind() const { return kind_; }
|
||||
explicit Type(Kind k);
|
||||
Kind kind() const;
|
||||
static std::shared_ptr<Type> Void();
|
||||
static std::shared_ptr<Type> Int32();
|
||||
static std::shared_ptr<Type> PtrInt32();
|
||||
@@ -53,14 +53,13 @@ class Type {
|
||||
|
||||
class Value {
|
||||
public:
|
||||
Value(std::shared_ptr<Type> ty, std::string name)
|
||||
: type_(std::move(ty)), name_(std::move(name)) {}
|
||||
Value(std::shared_ptr<Type> ty, std::string name);
|
||||
virtual ~Value() = default;
|
||||
const std::shared_ptr<Type>& type() const { return type_; }
|
||||
const std::string& name() const { return name_; }
|
||||
void set_name(std::string n) { name_ = std::move(n); }
|
||||
void AddUser(Instruction* user) { users_.push_back(user); }
|
||||
const std::vector<Instruction*>& users() const { return users_; }
|
||||
const std::shared_ptr<Type>& type() const;
|
||||
const std::string& name() const;
|
||||
void set_name(std::string n);
|
||||
void AddUser(Instruction* user);
|
||||
const std::vector<Instruction*>& users() const;
|
||||
|
||||
protected:
|
||||
std::shared_ptr<Type> type_;
|
||||
@@ -77,16 +76,16 @@ class ConstantInt : public Value {
|
||||
int value_{};
|
||||
};
|
||||
|
||||
// 后续还需要扩展更多指令类型。
|
||||
enum class Opcode { Add, Sub, Mul, Alloca, Load, Store, Ret };
|
||||
|
||||
class Instruction : public Value {
|
||||
public:
|
||||
Instruction(Opcode op, std::shared_ptr<Type> 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; }
|
||||
Instruction(Opcode op, std::shared_ptr<Type> ty, std::string name = "");
|
||||
Opcode opcode() const;
|
||||
bool IsTerminator() const;
|
||||
BasicBlock* parent() const;
|
||||
void set_parent(BasicBlock* parent);
|
||||
|
||||
private:
|
||||
Opcode opcode_;
|
||||
@@ -97,8 +96,8 @@ class BinaryInst : public Instruction {
|
||||
public:
|
||||
BinaryInst(Opcode op, std::shared_ptr<Type> ty, Value* lhs, Value* rhs,
|
||||
std::string name);
|
||||
Value* lhs() const { return lhs_; }
|
||||
Value* rhs() const { return rhs_; }
|
||||
Value* lhs() const;
|
||||
Value* rhs() const;
|
||||
|
||||
private:
|
||||
Value* lhs_;
|
||||
@@ -108,7 +107,7 @@ class BinaryInst : public Instruction {
|
||||
class ReturnInst : public Instruction {
|
||||
public:
|
||||
explicit ReturnInst(Value* val);
|
||||
Value* value() const { return value_; }
|
||||
Value* value() const;
|
||||
|
||||
private:
|
||||
Value* value_;
|
||||
@@ -122,7 +121,7 @@ class AllocaInst : public Instruction {
|
||||
class LoadInst : public Instruction {
|
||||
public:
|
||||
LoadInst(Value* ptr, std::string name);
|
||||
Value* ptr() const { return ptr_; }
|
||||
Value* ptr() const;
|
||||
|
||||
private:
|
||||
Value* ptr_;
|
||||
@@ -131,8 +130,8 @@ class LoadInst : public Instruction {
|
||||
class StoreInst : public Instruction {
|
||||
public:
|
||||
StoreInst(Value* val, Value* ptr);
|
||||
Value* value() const { return value_; }
|
||||
Value* ptr() const { return ptr_; }
|
||||
Value* value() const;
|
||||
Value* ptr() const;
|
||||
|
||||
private:
|
||||
Value* value_;
|
||||
@@ -141,14 +140,10 @@ class StoreInst : public Instruction {
|
||||
|
||||
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<std::unique_ptr<Instruction>>& instructions() const {
|
||||
return instructions_;
|
||||
}
|
||||
explicit BasicBlock(std::string name);
|
||||
const std::string& name() const;
|
||||
bool HasTerminator() const;
|
||||
const std::vector<std::unique_ptr<Instruction>>& instructions() const;
|
||||
template <typename T, typename... Args>
|
||||
T* Append(Args&&... args) {
|
||||
if (HasTerminator()) {
|
||||
@@ -172,11 +167,9 @@ class Function : public Value {
|
||||
// 允许显式指定返回类型,便于后续扩展多种函数签名。
|
||||
Function(std::string name, std::shared_ptr<Type> ret_type);
|
||||
BasicBlock* CreateBlock(const std::string& name);
|
||||
BasicBlock* entry() { return entry_; }
|
||||
const BasicBlock* entry() const { return entry_; }
|
||||
const std::vector<std::unique_ptr<BasicBlock>>& blocks() const {
|
||||
return blocks_;
|
||||
}
|
||||
BasicBlock* entry();
|
||||
const BasicBlock* entry() const;
|
||||
const std::vector<std::unique_ptr<BasicBlock>>& blocks() const;
|
||||
|
||||
private:
|
||||
BasicBlock* entry_ = nullptr;
|
||||
@@ -188,9 +181,7 @@ class Module {
|
||||
// 创建函数时显式传入返回类型,便于在 IRGen 中根据语法树信息选择类型。
|
||||
Function* CreateFunction(const std::string& name,
|
||||
std::shared_ptr<Type> ret_type);
|
||||
const std::vector<std::unique_ptr<Function>>& functions() const {
|
||||
return functions_;
|
||||
}
|
||||
const std::vector<std::unique_ptr<Function>>& functions() const;
|
||||
|
||||
private:
|
||||
std::vector<std::unique_ptr<Function>> functions_;
|
||||
@@ -198,17 +189,15 @@ class Module {
|
||||
|
||||
class IRBuilder {
|
||||
public:
|
||||
explicit IRBuilder(BasicBlock* bb) : insertBlock_(bb) {}
|
||||
void SetInsertPoint(BasicBlock* bb) { insertBlock_ = bb; }
|
||||
BasicBlock* GetInsertBlock() const { return insertBlock_; }
|
||||
explicit IRBuilder(BasicBlock* bb);
|
||||
void SetInsertPoint(BasicBlock* bb);
|
||||
BasicBlock* GetInsertBlock() const;
|
||||
|
||||
// 构造常量、二元运算、返回指令的最小集合。
|
||||
ConstantInt* CreateConstInt(int v);
|
||||
BinaryInst* CreateBinary(Opcode op, Value* lhs, Value* rhs,
|
||||
const std::string& name);
|
||||
BinaryInst* CreateAdd(Value* lhs, Value* rhs, const std::string& name) {
|
||||
return CreateBinary(Opcode::Add, lhs, rhs, name);
|
||||
}
|
||||
BinaryInst* CreateAdd(Value* lhs, Value* rhs, const std::string& name);
|
||||
AllocaInst* CreateAllocaI32(const std::string& name);
|
||||
LoadInst* CreateLoad(Value* ptr, const std::string& name);
|
||||
StoreInst* CreateStore(Value* val, Value* ptr);
|
||||
|
||||
@@ -18,6 +18,12 @@ bool IsPtrInt32Type(const std::shared_ptr<Type>& ty) {
|
||||
|
||||
} // namespace
|
||||
|
||||
IRBuilder::IRBuilder(BasicBlock* bb) : insertBlock_(bb) {}
|
||||
|
||||
void IRBuilder::SetInsertPoint(BasicBlock* bb) { insertBlock_ = bb; }
|
||||
|
||||
BasicBlock* IRBuilder::GetInsertBlock() const { return insertBlock_; }
|
||||
|
||||
ConstantInt* IRBuilder::CreateConstInt(int v) {
|
||||
// 常量不需要挂在基本块里,由 Context 负责去重与生命周期。
|
||||
return DefaultContext().GetConstInt(v);
|
||||
@@ -47,6 +53,11 @@ BinaryInst* IRBuilder::CreateBinary(Opcode op, Value* lhs, Value* rhs,
|
||||
return insertBlock_->Append<BinaryInst>(op, lhs->type(), lhs, rhs, name);
|
||||
}
|
||||
|
||||
BinaryInst* IRBuilder::CreateAdd(Value* lhs, Value* rhs,
|
||||
const std::string& name) {
|
||||
return CreateBinary(Opcode::Add, lhs, rhs, name);
|
||||
}
|
||||
|
||||
AllocaInst* IRBuilder::CreateAllocaI32(const std::string& name) {
|
||||
if (!insertBlock_) {
|
||||
throw std::runtime_error("IRBuilder 未设置插入点");
|
||||
|
||||
@@ -18,6 +18,17 @@ bool IsPtrInt32Type(const std::shared_ptr<Type>& ty) {
|
||||
|
||||
} // namespace
|
||||
|
||||
Instruction::Instruction(Opcode op, std::shared_ptr<Type> ty, std::string name)
|
||||
: Value(std::move(ty), std::move(name)), opcode_(op) {}
|
||||
|
||||
Opcode Instruction::opcode() const { return opcode_; }
|
||||
|
||||
bool Instruction::IsTerminator() const { return opcode_ == Opcode::Ret; }
|
||||
|
||||
BasicBlock* Instruction::parent() const { return parent_; }
|
||||
|
||||
void Instruction::set_parent(BasicBlock* parent) { parent_ = parent; }
|
||||
|
||||
BinaryInst::BinaryInst(Opcode op, std::shared_ptr<Type> ty, Value* lhs,
|
||||
Value* rhs, std::string name)
|
||||
: Instruction(op, std::move(ty), std::move(name)), lhs_(lhs), rhs_(rhs) {
|
||||
@@ -45,6 +56,10 @@ BinaryInst::BinaryInst(Opcode op, std::shared_ptr<Type> ty, Value* lhs,
|
||||
}
|
||||
}
|
||||
|
||||
Value* BinaryInst::lhs() const { return lhs_; }
|
||||
|
||||
Value* BinaryInst::rhs() const { return rhs_; }
|
||||
|
||||
ReturnInst::ReturnInst(Value* val)
|
||||
: Instruction(Opcode::Ret, Type::Void(), ""), value_(val) {
|
||||
if (!value_) {
|
||||
@@ -53,6 +68,8 @@ ReturnInst::ReturnInst(Value* val)
|
||||
value_->AddUser(this);
|
||||
}
|
||||
|
||||
Value* ReturnInst::value() const { return value_; }
|
||||
|
||||
AllocaInst::AllocaInst(std::string name)
|
||||
: Instruction(Opcode::Alloca, Type::PtrInt32(), std::move(name)) {}
|
||||
|
||||
@@ -67,6 +84,8 @@ LoadInst::LoadInst(Value* ptr, std::string name)
|
||||
ptr_->AddUser(this);
|
||||
}
|
||||
|
||||
Value* LoadInst::ptr() const { return ptr_; }
|
||||
|
||||
StoreInst::StoreInst(Value* val, Value* ptr)
|
||||
: Instruction(Opcode::Store, Type::Void(), ""), value_(val), ptr_(ptr) {
|
||||
if (!value_) {
|
||||
@@ -85,4 +104,8 @@ StoreInst::StoreInst(Value* val, Value* ptr)
|
||||
ptr_->AddUser(this);
|
||||
}
|
||||
|
||||
Value* StoreInst::value() const { return value_; }
|
||||
|
||||
Value* StoreInst::ptr() const { return ptr_; }
|
||||
|
||||
} // namespace ir
|
||||
|
||||
@@ -12,4 +12,8 @@ Function* Module::CreateFunction(const std::string& name,
|
||||
return functions_.back().get();
|
||||
}
|
||||
|
||||
const std::vector<std::unique_ptr<Function>>& Module::functions() const {
|
||||
return functions_;
|
||||
}
|
||||
|
||||
} // namespace ir
|
||||
|
||||
@@ -6,6 +6,10 @@
|
||||
|
||||
namespace ir {
|
||||
|
||||
Type::Type(Kind k) : kind_(k) {}
|
||||
|
||||
Type::Kind Type::kind() const { return kind_; }
|
||||
|
||||
std::shared_ptr<Type> Type::Void() { return DefaultContext().Void(); }
|
||||
|
||||
std::shared_ptr<Type> Type::Int32() { return DefaultContext().Int32(); }
|
||||
|
||||
@@ -5,6 +5,19 @@
|
||||
|
||||
namespace ir {
|
||||
|
||||
Value::Value(std::shared_ptr<Type> ty, std::string name)
|
||||
: type_(std::move(ty)), name_(std::move(name)) {}
|
||||
|
||||
const std::shared_ptr<Type>& Value::type() const { return type_; }
|
||||
|
||||
const std::string& Value::name() const { return name_; }
|
||||
|
||||
void Value::set_name(std::string n) { name_ = std::move(n); }
|
||||
|
||||
void Value::AddUser(Instruction* user) { users_.push_back(user); }
|
||||
|
||||
const std::vector<Instruction*>& Value::users() const { return users_; }
|
||||
|
||||
ConstantInt::ConstantInt(int v) : Value(Type::Int32(), ""), value_(v) {}
|
||||
|
||||
} // namespace ir
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
#include "SysYParser.h"
|
||||
#include "ir/IR.h"
|
||||
#include "sem/Sema.h"
|
||||
|
||||
namespace antlr4 {
|
||||
namespace tree {
|
||||
@@ -25,7 +26,7 @@ class Value;
|
||||
|
||||
class IRGenImpl {
|
||||
public:
|
||||
explicit IRGenImpl(ir::Module& module);
|
||||
IRGenImpl(ir::Module& module, const SemanticContext& sema);
|
||||
|
||||
void Gen(SysYParser::CompUnitContext& cu);
|
||||
|
||||
@@ -43,10 +44,12 @@ class IRGenImpl {
|
||||
ir::Value* GenPrimary(SysYParser::PrimaryContext& primary);
|
||||
|
||||
ir::Module& module_;
|
||||
const SemanticContext& sema_;
|
||||
ir::Function* func_;
|
||||
ir::IRBuilder builder_;
|
||||
// 当前只维护函数级局部变量表;若后续引入嵌套块作用域,需要改成作用域栈。
|
||||
std::unordered_map<std::string, ir::Value*> locals_;
|
||||
// 名称绑定由 Sema 负责;IRGen 只维护“声明 -> 存储槽位”的代码生成状态。
|
||||
std::unordered_map<SysYParser::VarDeclContext*, ir::Value*> storage_map_;
|
||||
};
|
||||
|
||||
std::unique_ptr<ir::Module> GenerateIR(antlr4::tree::ParseTree* tree);
|
||||
std::unique_ptr<ir::Module> GenerateIR(SysYParser::CompUnitContext& tree,
|
||||
const SemanticContext& sema);
|
||||
|
||||
@@ -36,12 +36,11 @@ void IRGenImpl::GenDecl(SysYParser::DeclContext& decl) {
|
||||
}
|
||||
|
||||
void IRGenImpl::GenVarDecl(SysYParser::VarDeclContext& decl) {
|
||||
const std::string name = decl.Ident()->getText();
|
||||
if (locals_.find(name) != locals_.end()) {
|
||||
throw std::runtime_error("[irgen] 重复定义变量: " + name);
|
||||
if (storage_map_.find(&decl) != storage_map_.end()) {
|
||||
throw std::runtime_error("[irgen] 声明重复生成存储槽位");
|
||||
}
|
||||
auto* slot = builder_.CreateAllocaI32(ir::DefaultContext().NextTemp());
|
||||
locals_[name] = slot;
|
||||
storage_map_[&decl] = slot;
|
||||
|
||||
ir::Value* init = nullptr;
|
||||
if (decl.exp()) {
|
||||
|
||||
@@ -4,21 +4,12 @@
|
||||
#include <stdexcept>
|
||||
|
||||
#include "SysYParser.h"
|
||||
#include "antlr4-runtime.h"
|
||||
#include "ir/IR.h"
|
||||
|
||||
std::unique_ptr<ir::Module> GenerateIR(antlr4::tree::ParseTree* tree) {
|
||||
if (!tree) {
|
||||
throw std::runtime_error("[irgen] 语法树为空");
|
||||
}
|
||||
|
||||
auto* cu = dynamic_cast<SysYParser::CompUnitContext*>(tree);
|
||||
if (!cu) {
|
||||
throw std::runtime_error("[irgen] 语法树根节点不是 compUnit");
|
||||
}
|
||||
|
||||
std::unique_ptr<ir::Module> GenerateIR(SysYParser::CompUnitContext& tree,
|
||||
const SemanticContext& sema) {
|
||||
auto module = std::make_unique<ir::Module>();
|
||||
IRGenImpl gen(*module);
|
||||
gen.Gen(*cu);
|
||||
IRGenImpl gen(*module, sema);
|
||||
gen.Gen(tree);
|
||||
return module;
|
||||
}
|
||||
|
||||
@@ -33,10 +33,15 @@ ir::Value* IRGenImpl::GenPrimary(SysYParser::PrimaryContext& primary) {
|
||||
return ir::DefaultContext().GetConstInt(std::stoi(primary.Number()->getText()));
|
||||
}
|
||||
if (primary.Ident()) {
|
||||
const std::string name = primary.Ident()->getText();
|
||||
auto it = locals_.find(name);
|
||||
if (it == locals_.end()) {
|
||||
throw std::runtime_error("[irgen] 变量未找到: " + name);
|
||||
auto* decl = sema_.ResolveVarUse(&primary);
|
||||
if (!decl) {
|
||||
throw std::runtime_error("[irgen] 变量使用缺少语义绑定: " +
|
||||
primary.Ident()->getText());
|
||||
}
|
||||
auto it = storage_map_.find(decl);
|
||||
if (it == storage_map_.end()) {
|
||||
throw std::runtime_error("[irgen] 变量声明缺少存储槽位: " +
|
||||
primary.Ident()->getText());
|
||||
}
|
||||
return builder_.CreateLoad(it->second, ir::DefaultContext().NextTemp());
|
||||
}
|
||||
|
||||
@@ -19,8 +19,8 @@ void VerifyFunctionStructure(const ir::Function& func) {
|
||||
|
||||
} // namespace
|
||||
|
||||
IRGenImpl::IRGenImpl(ir::Module& module)
|
||||
: module_(module), func_(nullptr), builder_(nullptr) {}
|
||||
IRGenImpl::IRGenImpl(ir::Module& module, const SemanticContext& sema)
|
||||
: module_(module), sema_(sema), func_(nullptr), builder_(nullptr) {}
|
||||
|
||||
void IRGenImpl::Gen(SysYParser::CompUnitContext& cu) {
|
||||
if (!cu.funcDef()) {
|
||||
@@ -39,7 +39,7 @@ void IRGenImpl::GenFuncDef(SysYParser::FuncDefContext& func) {
|
||||
|
||||
func_ = module_.CreateFunction(func.Ident()->getText(), ir::Type::Int32());
|
||||
builder_.SetInsertPoint(func_->entry());
|
||||
locals_.clear();
|
||||
storage_map_.clear();
|
||||
|
||||
GenBlock(*func.block());
|
||||
// 语义正确性主要由 sema 保证,这里只兜底检查 IR 结构是否合法。
|
||||
|
||||
@@ -30,9 +30,9 @@ int main(int argc, char** argv) {
|
||||
if (!comp_unit) {
|
||||
throw std::runtime_error("[main] 语法树根节点不是 compUnit");
|
||||
}
|
||||
RunSema(*comp_unit);
|
||||
auto sema = RunSema(*comp_unit);
|
||||
|
||||
auto module = GenerateIR(antlr.tree);
|
||||
auto module = GenerateIR(*comp_unit, sema);
|
||||
if (opts.emit_ir) {
|
||||
ir::IRPrinter printer;
|
||||
if (need_blank_line) {
|
||||
|
||||
@@ -7,43 +7,47 @@
|
||||
|
||||
namespace {
|
||||
|
||||
void CheckExpr(SysYParser::ExpContext& exp, const SymbolTable& table);
|
||||
void CheckExpr(SysYParser::ExpContext& exp, const SymbolTable& table,
|
||||
SemanticContext& sema);
|
||||
|
||||
void CheckPrimary(SysYParser::PrimaryContext& primary,
|
||||
const SymbolTable& table) {
|
||||
const SymbolTable& table, SemanticContext& sema) {
|
||||
if (primary.Number()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (primary.Ident()) {
|
||||
const std::string name = primary.Ident()->getText();
|
||||
if (!table.Contains(name)) {
|
||||
auto* decl = table.Lookup(name);
|
||||
if (!decl) {
|
||||
throw std::runtime_error("[sema] 使用了未定义的变量: " + name);
|
||||
}
|
||||
sema.BindVarUse(&primary, decl);
|
||||
return;
|
||||
}
|
||||
|
||||
if (primary.exp()) {
|
||||
CheckExpr(*primary.exp(), table);
|
||||
CheckExpr(*primary.exp(), table, sema);
|
||||
return;
|
||||
}
|
||||
|
||||
throw std::runtime_error("[sema] 暂不支持的 primary 形式");
|
||||
}
|
||||
|
||||
void CheckExpr(SysYParser::ExpContext& exp, const SymbolTable& table) {
|
||||
void CheckExpr(SysYParser::ExpContext& exp, const SymbolTable& table,
|
||||
SemanticContext& sema) {
|
||||
if (!exp.addExp()) {
|
||||
throw std::runtime_error("[sema] 非法表达式");
|
||||
}
|
||||
const auto& terms = exp.addExp()->primary();
|
||||
for (auto* term : terms) {
|
||||
CheckPrimary(*term, table);
|
||||
CheckPrimary(*term, table, sema);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void RunSema(SysYParser::CompUnitContext& comp_unit) {
|
||||
SemanticContext RunSema(SysYParser::CompUnitContext& comp_unit) {
|
||||
auto* func = comp_unit.funcDef();
|
||||
if (!func || !func->block()) {
|
||||
throw std::runtime_error("[sema] 缺少 main 函数定义");
|
||||
@@ -53,6 +57,7 @@ void RunSema(SysYParser::CompUnitContext& comp_unit) {
|
||||
}
|
||||
|
||||
SymbolTable table;
|
||||
SemanticContext sema;
|
||||
bool seen_return = false;
|
||||
|
||||
const auto& items = func->block()->blockItem();
|
||||
@@ -74,14 +79,14 @@ void RunSema(SysYParser::CompUnitContext& comp_unit) {
|
||||
throw std::runtime_error("[sema] 重复定义变量: " + name);
|
||||
}
|
||||
if (decl->exp()) {
|
||||
CheckExpr(*decl->exp(), table);
|
||||
CheckExpr(*decl->exp(), table, sema);
|
||||
}
|
||||
table.Add(name);
|
||||
table.Add(name, decl);
|
||||
continue;
|
||||
}
|
||||
if (auto* stmt = item->stmt(); stmt && stmt->returnStmt()) {
|
||||
auto* ret = stmt->returnStmt();
|
||||
CheckExpr(*ret->exp(), table);
|
||||
CheckExpr(*ret->exp(), table, sema);
|
||||
seen_return = true;
|
||||
if (i + 1 != items.size()) {
|
||||
throw std::runtime_error("[sema] return 必须是 main 函数中的最后一条语句");
|
||||
@@ -94,4 +99,6 @@ void RunSema(SysYParser::CompUnitContext& comp_unit) {
|
||||
if (!seen_return) {
|
||||
throw std::runtime_error("[sema] main 函数必须包含 return 语句");
|
||||
}
|
||||
|
||||
return sema;
|
||||
}
|
||||
|
||||
@@ -1,9 +1,30 @@
|
||||
// 基于语法树的极简语义检查。
|
||||
// 基于语法树的极简语义检查与名称绑定。
|
||||
#pragma once
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
#include "SysYParser.h"
|
||||
|
||||
class SemanticContext {
|
||||
public:
|
||||
void BindVarUse(SysYParser::PrimaryContext* use,
|
||||
SysYParser::VarDeclContext* decl) {
|
||||
var_uses_[use] = decl;
|
||||
}
|
||||
|
||||
SysYParser::VarDeclContext* ResolveVarUse(
|
||||
const SysYParser::PrimaryContext* use) const {
|
||||
auto it = var_uses_.find(use);
|
||||
return it == var_uses_.end() ? nullptr : it->second;
|
||||
}
|
||||
|
||||
private:
|
||||
std::unordered_map<const SysYParser::PrimaryContext*,
|
||||
SysYParser::VarDeclContext*>
|
||||
var_uses_;
|
||||
};
|
||||
|
||||
// 目前仅检查:
|
||||
// - 变量先声明后使用
|
||||
// - 局部变量不允许重复定义
|
||||
void RunSema(SysYParser::CompUnitContext& comp_unit);
|
||||
SemanticContext RunSema(SysYParser::CompUnitContext& comp_unit);
|
||||
|
||||
@@ -1,16 +1,24 @@
|
||||
// 极简符号表:记录局部变量是否定义。
|
||||
// 极简符号表:记录局部变量定义点。
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "SysYParser.h"
|
||||
|
||||
class SymbolTable {
|
||||
public:
|
||||
void Add(const std::string& name) { table_[name] = true; }
|
||||
void Add(const std::string& name, SysYParser::VarDeclContext* decl) {
|
||||
table_[name] = decl;
|
||||
}
|
||||
bool Contains(const std::string& name) const {
|
||||
return table_.find(name) != table_.end();
|
||||
}
|
||||
SysYParser::VarDeclContext* Lookup(const std::string& name) const {
|
||||
auto it = table_.find(name);
|
||||
return it == table_.end() ? nullptr : it->second;
|
||||
}
|
||||
|
||||
private:
|
||||
std::unordered_map<std::string, bool> table_;
|
||||
std::unordered_map<std::string, SysYParser::VarDeclContext*> table_;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user