refactor(irgen): 完善irgen代码和文档,提升扩展兼容性
This commit is contained in:
@@ -2,49 +2,83 @@
|
|||||||
|
|
||||||
## 1. 本实验定位
|
## 1. 本实验定位
|
||||||
|
|
||||||
Lab2 的目标是在该示例基础上扩展语义覆盖范围,逐步把更多 SysY 语法正确翻译为 IR。
|
Lab2 的目标是在该示例基础上扩展语义覆盖范围,并逐步把更多 SysY 语法正确翻译为 IR。
|
||||||
|
|
||||||
## 2. Lab2 要求
|
## 2. Lab2 要求
|
||||||
|
|
||||||
需要同学完成:
|
需要同学完成:
|
||||||
|
|
||||||
1. 熟悉 IR 相关数据结构与构建接口。
|
1. 熟悉 IR 相关数据结构与构建接口。
|
||||||
2. 理解当前语法树 -> IR 的最小实现流程。
|
2. 理解当前语法树 -> 语义检查 -> IR 的最小实现流程。
|
||||||
3. 在现有框架上扩展 IR 生成能力,使其覆盖课程要求的Sysy语法。
|
3. 在现有框架上补充语义检查与 IR 生成功能,使其覆盖课程要求的 SysY 语法。
|
||||||
|
|
||||||
## 3. 相关文件
|
## 3. 相关文件
|
||||||
|
|
||||||
以下文件与本实验内容相关,建议优先阅读。
|
以下文件与本实验内容相关,建议优先阅读。
|
||||||
|
|
||||||
|
- `include/sem/Sema.h`
|
||||||
|
- `include/sem/SymbolTable.h`
|
||||||
|
- `src/sem/Sema.cpp`
|
||||||
|
- `src/sem/SymbolTable.cpp`
|
||||||
- `include/ir/IR.h`
|
- `include/ir/IR.h`
|
||||||
|
- `src/ir/Context.cpp`
|
||||||
|
- `src/ir/Value.cpp`
|
||||||
|
- `src/ir/Instruction.cpp`
|
||||||
|
- `src/ir/BasicBlock.cpp`
|
||||||
|
- `src/ir/Function.cpp`
|
||||||
|
- `src/ir/Module.cpp`
|
||||||
|
- `src/ir/IRBuilder.cpp`
|
||||||
|
- `src/ir/IRPrinter.cpp`
|
||||||
|
|
||||||
|
|
||||||
- `include/irgen/IRGen.h`
|
- `include/irgen/IRGen.h`
|
||||||
- `src/irgen/IRGenDecl.cpp`
|
- `src/irgen/IRGenDecl.cpp`
|
||||||
- `src/irgen/IRGenStmt.cpp`
|
- `src/irgen/IRGenStmt.cpp`
|
||||||
- `src/irgen/IRGenExp.cpp`
|
- `src/irgen/IRGenExp.cpp`
|
||||||
|
- `src/irgen/IRGenFunc.cpp`
|
||||||
|
- `src/irgen/IRGenDriver.cpp`
|
||||||
|
|
||||||
## 4. 当前最小示例实现说明
|
## 4. 当前最小示例实现说明
|
||||||
|
|
||||||
当前语法树 -> IR 仅覆盖最小子集:
|
当前语法树 -> 语义检查 -> IR 仅覆盖最小子集:
|
||||||
|
|
||||||
1. 常量整数、变量引用、二元加法表达式。
|
1. 常量整数、变量引用、二元加法表达式。
|
||||||
2. 局部变量声明(当前采用 LLVM 前端常见的 `alloca/load/store` 内存模型)。
|
2. 局部变量声明(当前采用 LLVM 前端常见的 `alloca/load/store` 内存模型)。
|
||||||
3. `return` 语句。
|
3. `return` 语句。
|
||||||
4. 单函数 `main` 的最小流程。
|
4. 单函数 `main` 的最小流程。
|
||||||
|
|
||||||
|
其中,`sema` 负责最基本的名称绑定与合法性检查,`irgen` 在此基础上继续生成 IR。
|
||||||
|
如果语义检查阶段没有补全,后续 IR 生成阶段通常也无法正确处理变量引用、声明绑定等逻辑。
|
||||||
|
|
||||||
|
|
||||||
说明:当前阶段变量统一采用内存模型:先 `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` 会记录哪些 `Instruction` 使用了它。
|
||||||
这对后续做数据流分析、死代码删除、常量传播等优化会很有帮助;但目前相关实现,接口仍不完整,后续实验中还需要同学继续补充和完善。
|
这对后续做数据流分析、死代码删除、常量传播等优化会很有帮助;但目前相关实现,接口仍不完整,后续实验中还需要同学继续补充和完善。
|
||||||
|
|
||||||
## 5. 构建与运行
|
## 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 生成代码该如何遍历和取信息。
|
||||||
|
|
||||||
|
如果 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` 的名字与成员函数,后者可辅助查看规则展开后的具体实现。
|
||||||
|
|
||||||
|
## 6. 构建与运行
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
|
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
|
||||||
cmake --build build -j "$(nproc)"
|
cmake --build build -j "$(nproc)"
|
||||||
```
|
```
|
||||||
|
|
||||||
## 6. Lab2 验证方式
|
## 7. Lab2 验证方式
|
||||||
|
|
||||||
可先用单个样例检查 IR 输出是否基本正确:
|
可先用单个样例检查 IR 输出是否基本正确:
|
||||||
|
|
||||||
@@ -52,11 +86,7 @@ cmake --build build -j "$(nproc)"
|
|||||||
./build/bin/compiler --emit-ir test/test_case/functional/simple_add.sy
|
./build/bin/compiler --emit-ir test/test_case/functional/simple_add.sy
|
||||||
```
|
```
|
||||||
|
|
||||||
如需打印语法树:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
./build/bin/compiler --emit-parse-tree test/test_case/functional/simple_add.sy
|
|
||||||
```
|
|
||||||
|
|
||||||
推荐使用统一脚本验证 “IR -> LLVM 后端 -> 可执行程序” 整体链路。`--run` 模式下会自动读取同名 `.in`,并将程序输出与退出码和同名 `.out` 比对,用于验证 IR 的正确性:
|
推荐使用统一脚本验证 “IR -> LLVM 后端 -> 可执行程序” 整体链路。`--run` 模式下会自动读取同名 `.in`,并将程序输出与退出码和同名 `.out` 比对,用于验证 IR 的正确性:
|
||||||
|
|
||||||
|
|||||||
@@ -26,23 +26,21 @@ class IRGenImpl {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
void GenFuncDef(SysYParser::FuncDefContext& func);
|
void GenFuncDef(SysYParser::FuncDefContext& func);
|
||||||
void GenBlock(SysYParser::BlockContext& block);
|
void GenBlock(SysYParser::BlockStmtContext& block);
|
||||||
bool GenBlockItem(SysYParser::BlockItemContext& item);
|
bool GenBlockItem(SysYParser::BlockItemContext& item);
|
||||||
void GenDecl(SysYParser::DeclContext& decl);
|
void GenDecl(SysYParser::DeclContext& decl);
|
||||||
bool GenStmt(SysYParser::StmtContext& stmt);
|
bool GenStmt(SysYParser::StmtContext& stmt);
|
||||||
void GenVarDecl(SysYParser::VarDeclContext& decl);
|
void GenVarDef(SysYParser::VarDefContext& decl);
|
||||||
void GenReturnStmt(SysYParser::ReturnStmtContext& ret);
|
void GenReturnStmt(SysYParser::ReturnStmtContext& ret);
|
||||||
|
|
||||||
ir::Value* GenExpr(SysYParser::ExpContext& expr);
|
ir::Value* GenExpr(SysYParser::ExpContext& expr);
|
||||||
ir::Value* GenAddExpr(SysYParser::AddExpContext& add);
|
|
||||||
ir::Value* GenPrimary(SysYParser::PrimaryContext& primary);
|
|
||||||
|
|
||||||
ir::Module& module_;
|
ir::Module& module_;
|
||||||
const SemanticContext& sema_;
|
const SemanticContext& sema_;
|
||||||
ir::Function* func_;
|
ir::Function* func_;
|
||||||
ir::IRBuilder builder_;
|
ir::IRBuilder builder_;
|
||||||
// 名称绑定由 Sema 负责;IRGen 只维护“声明 -> 存储槽位”的代码生成状态。
|
// 名称绑定由 Sema 负责;IRGen 只维护“声明 -> 存储槽位”的代码生成状态。
|
||||||
std::unordered_map<SysYParser::VarDeclContext*, ir::Value*> storage_map_;
|
std::unordered_map<SysYParser::VarDefContext*, ir::Value*> storage_map_;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unique_ptr<ir::Module> GenerateIR(SysYParser::CompUnitContext& tree,
|
std::unique_ptr<ir::Module> GenerateIR(SysYParser::CompUnitContext& tree,
|
||||||
|
|||||||
@@ -7,20 +7,20 @@
|
|||||||
|
|
||||||
class SemanticContext {
|
class SemanticContext {
|
||||||
public:
|
public:
|
||||||
void BindVarUse(SysYParser::PrimaryContext* use,
|
void BindVarUse(SysYParser::VarContext* use,
|
||||||
SysYParser::VarDeclContext* decl) {
|
SysYParser::VarDefContext* decl) {
|
||||||
var_uses_[use] = decl;
|
var_uses_[use] = decl;
|
||||||
}
|
}
|
||||||
|
|
||||||
SysYParser::VarDeclContext* ResolveVarUse(
|
SysYParser::VarDefContext* ResolveVarUse(
|
||||||
const SysYParser::PrimaryContext* use) const {
|
const SysYParser::VarContext* use) const {
|
||||||
auto it = var_uses_.find(use);
|
auto it = var_uses_.find(use);
|
||||||
return it == var_uses_.end() ? nullptr : it->second;
|
return it == var_uses_.end() ? nullptr : it->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unordered_map<const SysYParser::PrimaryContext*,
|
std::unordered_map<const SysYParser::VarContext*,
|
||||||
SysYParser::VarDeclContext*>
|
SysYParser::VarDefContext*>
|
||||||
var_uses_;
|
var_uses_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -8,10 +8,10 @@
|
|||||||
|
|
||||||
class SymbolTable {
|
class SymbolTable {
|
||||||
public:
|
public:
|
||||||
void Add(const std::string& name, SysYParser::VarDeclContext* decl);
|
void Add(const std::string& name, SysYParser::VarDefContext* decl);
|
||||||
bool Contains(const std::string& name) const;
|
bool Contains(const std::string& name) const;
|
||||||
SysYParser::VarDeclContext* Lookup(const std::string& name) const;
|
SysYParser::VarDefContext* Lookup(const std::string& name) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unordered_map<std::string, SysYParser::VarDeclContext*> table_;
|
std::unordered_map<std::string, SysYParser::VarDefContext*> table_;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -6,7 +6,18 @@
|
|||||||
#include "ir/IR.h"
|
#include "ir/IR.h"
|
||||||
#include "utils/Log.h"
|
#include "utils/Log.h"
|
||||||
|
|
||||||
void IRGenImpl::GenBlock(SysYParser::BlockContext& block) {
|
namespace {
|
||||||
|
|
||||||
|
std::string GetLValueName(SysYParser::LValueContext& lvalue) {
|
||||||
|
if (!lvalue.ID()) {
|
||||||
|
throw std::runtime_error(FormatError("irgen", "非法左值"));
|
||||||
|
}
|
||||||
|
return lvalue.ID()->getText();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
void IRGenImpl::GenBlock(SysYParser::BlockStmtContext& block) {
|
||||||
for (auto* item : block.blockItem()) {
|
for (auto* item : block.blockItem()) {
|
||||||
if (item) {
|
if (item) {
|
||||||
if (GenBlockItem(*item)) {
|
if (GenBlockItem(*item)) {
|
||||||
@@ -29,14 +40,21 @@ bool IRGenImpl::GenBlockItem(SysYParser::BlockItemContext& item) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void IRGenImpl::GenDecl(SysYParser::DeclContext& decl) {
|
void IRGenImpl::GenDecl(SysYParser::DeclContext& decl) {
|
||||||
if (decl.varDecl()) {
|
if (!decl.btype() || !decl.btype()->INT()) {
|
||||||
GenVarDecl(*decl.varDecl());
|
throw std::runtime_error(FormatError("irgen", "当前仅支持局部 int 变量声明"));
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
throw std::runtime_error(FormatError("irgen", "暂不支持的声明类型"));
|
auto* var_def = decl.varDef();
|
||||||
|
if (!var_def) {
|
||||||
|
throw std::runtime_error(FormatError("irgen", "非法变量声明"));
|
||||||
|
}
|
||||||
|
GenVarDef(*var_def);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IRGenImpl::GenVarDecl(SysYParser::VarDeclContext& decl) {
|
void IRGenImpl::GenVarDef(SysYParser::VarDefContext& decl) {
|
||||||
|
if (!decl.lValue()) {
|
||||||
|
throw std::runtime_error(FormatError("irgen", "变量声明缺少名称"));
|
||||||
|
}
|
||||||
|
GetLValueName(*decl.lValue());
|
||||||
if (storage_map_.find(&decl) != storage_map_.end()) {
|
if (storage_map_.find(&decl) != storage_map_.end()) {
|
||||||
throw std::runtime_error(FormatError("irgen", "声明重复生成存储槽位"));
|
throw std::runtime_error(FormatError("irgen", "声明重复生成存储槽位"));
|
||||||
}
|
}
|
||||||
@@ -44,8 +62,11 @@ void IRGenImpl::GenVarDecl(SysYParser::VarDeclContext& decl) {
|
|||||||
storage_map_[&decl] = slot;
|
storage_map_[&decl] = slot;
|
||||||
|
|
||||||
ir::Value* init = nullptr;
|
ir::Value* init = nullptr;
|
||||||
if (decl.exp()) {
|
if (auto* init_value = decl.initValue()) {
|
||||||
init = GenExpr(*decl.exp());
|
if (!init_value->exp()) {
|
||||||
|
throw std::runtime_error(FormatError("irgen", "当前不支持聚合初始化"));
|
||||||
|
}
|
||||||
|
init = GenExpr(*init_value->exp());
|
||||||
} else {
|
} else {
|
||||||
init = builder_.CreateConstInt(0);
|
init = builder_.CreateConstInt(0);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,49 +7,38 @@
|
|||||||
#include "utils/Log.h"
|
#include "utils/Log.h"
|
||||||
|
|
||||||
ir::Value* IRGenImpl::GenExpr(SysYParser::ExpContext& expr) {
|
ir::Value* IRGenImpl::GenExpr(SysYParser::ExpContext& expr) {
|
||||||
if (!expr.addExp()) {
|
if (auto* paren = dynamic_cast<SysYParser::ParenExpContext*>(&expr)) {
|
||||||
throw std::runtime_error(FormatError("irgen", "非法表达式"));
|
return GenExpr(*paren->exp());
|
||||||
}
|
}
|
||||||
return GenAddExpr(*expr.addExp());
|
if (auto* number = dynamic_cast<SysYParser::NumberExpContext*>(&expr)) {
|
||||||
|
if (!number->number() || !number->number()->ILITERAL()) {
|
||||||
|
throw std::runtime_error(FormatError("irgen", "当前仅支持整数字面量"));
|
||||||
}
|
}
|
||||||
|
return builder_.CreateConstInt(std::stoi(number->number()->getText()));
|
||||||
ir::Value* IRGenImpl::GenAddExpr(SysYParser::AddExpContext& add) {
|
|
||||||
// 当前表达式层次仍是最小实现,直接贴合 addExp -> primary 的语法形状。
|
|
||||||
const auto& terms = add.primary();
|
|
||||||
if (terms.empty()) {
|
|
||||||
throw std::runtime_error(FormatError("irgen", "空加法表达式"));
|
|
||||||
}
|
}
|
||||||
|
if (auto* var = dynamic_cast<SysYParser::VarExpContext*>(&expr)) {
|
||||||
ir::Value* acc = GenPrimary(*terms[0]);
|
if (!var->var() || !var->var()->ID()) {
|
||||||
for (size_t i = 1; i < terms.size(); ++i) {
|
throw std::runtime_error(FormatError("irgen", "当前仅支持普通整型变量"));
|
||||||
ir::Value* rhs = GenPrimary(*terms[i]);
|
|
||||||
std::string name = module_.GetContext().NextTemp();
|
|
||||||
acc = builder_.CreateBinary(ir::Opcode::Add, acc, rhs, name);
|
|
||||||
}
|
}
|
||||||
return acc;
|
auto* decl = sema_.ResolveVarUse(var->var());
|
||||||
}
|
|
||||||
|
|
||||||
ir::Value* IRGenImpl::GenPrimary(SysYParser::PrimaryContext& primary) {
|
|
||||||
if (primary.Number()) {
|
|
||||||
return builder_.CreateConstInt(std::stoi(primary.Number()->getText()));
|
|
||||||
}
|
|
||||||
if (primary.Ident()) {
|
|
||||||
auto* decl = sema_.ResolveVarUse(&primary);
|
|
||||||
if (!decl) {
|
if (!decl) {
|
||||||
throw std::runtime_error(
|
throw std::runtime_error(
|
||||||
FormatError("irgen",
|
FormatError("irgen",
|
||||||
"变量使用缺少语义绑定: " + primary.Ident()->getText()));
|
"变量使用缺少语义绑定: " + var->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",
|
||||||
"变量声明缺少存储槽位: " + primary.Ident()->getText()));
|
"变量声明缺少存储槽位: " + var->var()->ID()->getText()));
|
||||||
}
|
}
|
||||||
return builder_.CreateLoad(it->second, module_.GetContext().NextTemp());
|
return builder_.CreateLoad(it->second, module_.GetContext().NextTemp());
|
||||||
}
|
}
|
||||||
if (primary.exp()) {
|
if (auto* binary = dynamic_cast<SysYParser::AdditiveExpContext*>(&expr)) {
|
||||||
return GenExpr(*primary.exp());
|
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());
|
||||||
}
|
}
|
||||||
throw std::runtime_error(FormatError("irgen", "暂不支持的表达式形式"));
|
throw std::runtime_error(FormatError("irgen", "暂不支持的表达式形式"));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,26 +28,31 @@ IRGenImpl::IRGenImpl(ir::Module& module, const SemanticContext& sema)
|
|||||||
builder_(module.GetContext(), nullptr) {}
|
builder_(module.GetContext(), nullptr) {}
|
||||||
|
|
||||||
void IRGenImpl::Gen(SysYParser::CompUnitContext& cu) {
|
void IRGenImpl::Gen(SysYParser::CompUnitContext& cu) {
|
||||||
if (!cu.funcDef()) {
|
auto* func = cu.funcDef();
|
||||||
throw std::runtime_error(FormatError("irgen", "缺少 main 定义"));
|
if (func && func->ID() && func->ID()->getText() == "main") {
|
||||||
|
GenFuncDef(*func);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
GenFuncDef(*cu.funcDef());
|
throw std::runtime_error(FormatError("irgen", "缺少 main 定义"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void IRGenImpl::GenFuncDef(SysYParser::FuncDefContext& func) {
|
void IRGenImpl::GenFuncDef(SysYParser::FuncDefContext& func) {
|
||||||
if (!func.block()) {
|
if (!func.blockStmt()) {
|
||||||
throw std::runtime_error(FormatError("irgen", "函数体为空"));
|
throw std::runtime_error(FormatError("irgen", "函数体为空"));
|
||||||
}
|
}
|
||||||
if (!func.Ident()) {
|
if (!func.ID()) {
|
||||||
throw std::runtime_error(FormatError("irgen", "缺少函数名"));
|
throw std::runtime_error(FormatError("irgen", "缺少函数名"));
|
||||||
}
|
}
|
||||||
|
if (!func.funcType() || !func.funcType()->INT()) {
|
||||||
|
throw std::runtime_error(FormatError("irgen", "当前仅支持 int main"));
|
||||||
|
}
|
||||||
|
|
||||||
func_ = module_.CreateFunction(
|
func_ = module_.CreateFunction(
|
||||||
func.Ident()->getText(), module_.GetContext().Int32());
|
func.ID()->getText(), module_.GetContext().Int32());
|
||||||
builder_.SetInsertPoint(func_->GetEntry());
|
builder_.SetInsertPoint(func_->GetEntry());
|
||||||
storage_map_.clear();
|
storage_map_.clear();
|
||||||
|
|
||||||
GenBlock(*func.block());
|
GenBlock(*func.blockStmt());
|
||||||
// 语义正确性主要由 sema 保证,这里只兜底检查 IR 结构是否合法。
|
// 语义正确性主要由 sema 保证,这里只兜底检查 IR 结构是否合法。
|
||||||
VerifyFunctionStructure(*func_);
|
VerifyFunctionStructure(*func_);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
#include "sem/SymbolTable.h"
|
#include "sem/SymbolTable.h"
|
||||||
|
|
||||||
void SymbolTable::Add(const std::string& name,
|
void SymbolTable::Add(const std::string& name,
|
||||||
SysYParser::VarDeclContext* decl) {
|
SysYParser::VarDefContext* decl) {
|
||||||
table_[name] = decl;
|
table_[name] = decl;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -11,7 +11,7 @@ bool SymbolTable::Contains(const std::string& name) const {
|
|||||||
return table_.find(name) != table_.end();
|
return table_.find(name) != table_.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
SysYParser::VarDeclContext* SymbolTable::Lookup(const std::string& name) const {
|
SysYParser::VarDefContext* SymbolTable::Lookup(const std::string& name) const {
|
||||||
auto it = table_.find(name);
|
auto it = table_.find(name);
|
||||||
return it == table_.end() ? nullptr : it->second;
|
return it == table_.end() ? nullptr : it->second;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user