lab2: rebuild semantic analysis for current SysY grammar

dyz
olivame 2 weeks ago
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…
Cancel
Save