59 lines
1.5 KiB
C++
59 lines
1.5 KiB
C++
// 极简语义分析:只检查变量是否先声明再使用。
|
||
// 如需扩展,可在此基础上加入:
|
||
// - 常量折叠/类型检查
|
||
// - 函数签名/参数数量校验
|
||
// - 控制流相关检查(return 覆盖、break/continue 合法性等)
|
||
#include "sem/Sema.h"
|
||
|
||
#include <stdexcept>
|
||
#include <string>
|
||
#include <unordered_set>
|
||
|
||
#include "ast/AstNodes.h"
|
||
#include "sem/SymbolTable.h"
|
||
|
||
namespace {
|
||
|
||
class SemaVisitor {
|
||
public:
|
||
explicit SemaVisitor(SymbolTable& table) : table_(table) {}
|
||
|
||
void CheckBlock(const ast::Block& block) {
|
||
for (const auto& item : block.items) {
|
||
if (auto decl = dynamic_cast<ast::VarDecl*>(item.get())) {
|
||
table_.Add(decl->name);
|
||
if (decl->init) CheckExpr(*decl->init);
|
||
continue;
|
||
}
|
||
if (auto ret = dynamic_cast<ast::ReturnStmt*>(item.get())) {
|
||
CheckExpr(*ret->value);
|
||
}
|
||
}
|
||
}
|
||
|
||
void CheckExpr(const ast::Expr& expr) {
|
||
if (auto var = dynamic_cast<const ast::VarExpr*>(&expr)) {
|
||
if (!table_.Contains(var->name)) {
|
||
throw std::runtime_error("[sema] 使用了未定义的变量: " + var->name);
|
||
}
|
||
} else if (auto bin = dynamic_cast<const ast::BinaryExpr*>(&expr)) {
|
||
CheckExpr(*bin->lhs);
|
||
CheckExpr(*bin->rhs);
|
||
|
||
}
|
||
}
|
||
|
||
private:
|
||
SymbolTable& table_;
|
||
};
|
||
|
||
} // namespace
|
||
|
||
std::shared_ptr<ast::CompUnit> RunSema(std::shared_ptr<ast::CompUnit> ast) {
|
||
if (!ast || !ast->func || !ast->func->body) return ast;
|
||
SymbolTable table;
|
||
SemaVisitor visitor(table);
|
||
visitor.CheckBlock(*ast->func->body);
|
||
return ast;
|
||
}
|