forked from NUDT-compiler/nudt-compiler-cpp
parent
7dd139671b
commit
3342955abb
@ -1,30 +1,69 @@
|
||||
// 基于语法树的语义检查与名称绑定。
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "SysYParser.h"
|
||||
|
||||
enum class SemanticType {
|
||||
Void,
|
||||
Int,
|
||||
Float,
|
||||
};
|
||||
|
||||
struct ScalarConstant {
|
||||
SemanticType type = SemanticType::Int;
|
||||
double number = 0.0;
|
||||
};
|
||||
|
||||
struct ObjectBinding {
|
||||
enum class DeclKind {
|
||||
Var,
|
||||
Const,
|
||||
Param,
|
||||
};
|
||||
|
||||
std::string name;
|
||||
SemanticType type = SemanticType::Int;
|
||||
DeclKind decl_kind = DeclKind::Var;
|
||||
bool is_array_param = false;
|
||||
std::vector<int> dimensions;
|
||||
const SysYParser::VarDefContext* var_def = nullptr;
|
||||
const SysYParser::ConstDefContext* const_def = nullptr;
|
||||
const SysYParser::FuncFParamContext* func_param = nullptr;
|
||||
bool has_const_value = false;
|
||||
ScalarConstant const_value;
|
||||
};
|
||||
|
||||
struct FunctionBinding {
|
||||
std::string name;
|
||||
SemanticType return_type = SemanticType::Int;
|
||||
std::vector<ObjectBinding> params;
|
||||
const SysYParser::FuncDefContext* func_def = nullptr;
|
||||
bool is_builtin = false;
|
||||
};
|
||||
|
||||
class SemanticContext {
|
||||
public:
|
||||
void BindVarUse(SysYParser::VarContext* use,
|
||||
SysYParser::VarDefContext* decl) {
|
||||
var_uses_[use] = decl;
|
||||
}
|
||||
void BindObjectUse(const SysYParser::LValContext* use, ObjectBinding binding);
|
||||
const ObjectBinding* ResolveObjectUse(
|
||||
const SysYParser::LValContext* use) const;
|
||||
|
||||
void BindFunctionCall(const SysYParser::UnaryExpContext* call,
|
||||
FunctionBinding binding);
|
||||
const FunctionBinding* ResolveFunctionCall(
|
||||
const SysYParser::UnaryExpContext* call) const;
|
||||
|
||||
SysYParser::VarDefContext* ResolveVarUse(
|
||||
const SysYParser::VarContext* use) const {
|
||||
auto it = var_uses_.find(use);
|
||||
return it == var_uses_.end() ? nullptr : it->second;
|
||||
}
|
||||
void RegisterFunction(FunctionBinding binding);
|
||||
const FunctionBinding* ResolveFunction(const std::string& name) const;
|
||||
|
||||
private:
|
||||
std::unordered_map<const SysYParser::VarContext*,
|
||||
SysYParser::VarDefContext*>
|
||||
var_uses_;
|
||||
std::unordered_map<const SysYParser::LValContext*, ObjectBinding> object_uses_;
|
||||
std::unordered_map<const SysYParser::UnaryExpContext*, FunctionBinding>
|
||||
function_calls_;
|
||||
std::unordered_map<std::string, FunctionBinding> functions_;
|
||||
};
|
||||
|
||||
// 目前仅检查:
|
||||
// - 变量先声明后使用
|
||||
// - 局部变量不允许重复定义
|
||||
SemanticContext RunSema(SysYParser::CompUnitContext& comp_unit);
|
||||
|
||||
@ -1,17 +1,25 @@
|
||||
// 极简符号表:记录局部变量定义点。
|
||||
// 维护对象符号的多层作用域。
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "SysYParser.h"
|
||||
#include "sem/Sema.h"
|
||||
|
||||
class SymbolTable {
|
||||
public:
|
||||
void Add(const std::string& name, SysYParser::VarDefContext* decl);
|
||||
bool Contains(const std::string& name) const;
|
||||
SysYParser::VarDefContext* Lookup(const std::string& name) const;
|
||||
SymbolTable();
|
||||
|
||||
void EnterScope();
|
||||
void ExitScope();
|
||||
|
||||
bool Add(const ObjectBinding& symbol);
|
||||
bool ContainsInCurrentScope(std::string_view name) const;
|
||||
const ObjectBinding* Lookup(std::string_view name) const;
|
||||
size_t Depth() const;
|
||||
|
||||
private:
|
||||
std::unordered_map<std::string, SysYParser::VarDefContext*> table_;
|
||||
std::vector<std::unordered_map<std::string, ObjectBinding>> scopes_;
|
||||
};
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,17 +1,39 @@
|
||||
// 维护局部变量声明的注册与查找。
|
||||
// 维护对象符号的注册与按作用域查找。
|
||||
|
||||
#include "sem/SymbolTable.h"
|
||||
|
||||
void SymbolTable::Add(const std::string& name,
|
||||
SysYParser::VarDefContext* decl) {
|
||||
table_[name] = decl;
|
||||
#include <stdexcept>
|
||||
|
||||
SymbolTable::SymbolTable() : scopes_(1) {}
|
||||
|
||||
void SymbolTable::EnterScope() { scopes_.emplace_back(); }
|
||||
|
||||
void SymbolTable::ExitScope() {
|
||||
if (scopes_.size() <= 1) {
|
||||
throw std::runtime_error("symbol table scope underflow");
|
||||
}
|
||||
scopes_.pop_back();
|
||||
}
|
||||
|
||||
bool SymbolTable::Contains(const std::string& name) const {
|
||||
return table_.find(name) != table_.end();
|
||||
bool SymbolTable::Add(const ObjectBinding& symbol) {
|
||||
auto& scope = scopes_.back();
|
||||
return scope.emplace(symbol.name, symbol).second;
|
||||
}
|
||||
|
||||
SysYParser::VarDefContext* SymbolTable::Lookup(const std::string& name) const {
|
||||
auto it = table_.find(name);
|
||||
return it == table_.end() ? nullptr : it->second;
|
||||
bool SymbolTable::ContainsInCurrentScope(std::string_view name) const {
|
||||
const auto& scope = scopes_.back();
|
||||
return scope.find(std::string(name)) != scope.end();
|
||||
}
|
||||
|
||||
const ObjectBinding* SymbolTable::Lookup(std::string_view name) const {
|
||||
const std::string key(name);
|
||||
for (auto it = scopes_.rbegin(); it != scopes_.rend(); ++it) {
|
||||
auto found = it->find(key);
|
||||
if (found != it->end()) {
|
||||
return &found->second;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
size_t SymbolTable::Depth() const { return scopes_.size(); }
|
||||
|
||||
Loading…
Reference in new issue