Complete Lab2 IR generation and document process
This commit is contained in:
398
src/sem/Sema.cpp
398
src/sem/Sema.cpp
@@ -10,185 +10,321 @@
|
||||
|
||||
namespace {
|
||||
|
||||
std::string GetLValueName(SysYParser::LValueContext& lvalue) {
|
||||
if (!lvalue.ID()) {
|
||||
throw std::runtime_error(FormatError("sema", "非法左值"));
|
||||
}
|
||||
return lvalue.ID()->getText();
|
||||
}
|
||||
|
||||
class SemaVisitor final : public SysYBaseVisitor {
|
||||
public:
|
||||
explicit SemaVisitor() {
|
||||
// 预填标准库函数
|
||||
AddBuiltin("getint", Symbol::Kind::Function);
|
||||
AddBuiltin("getch", Symbol::Kind::Function);
|
||||
AddBuiltin("getfloat", Symbol::Kind::Function);
|
||||
AddBuiltin("getarray", Symbol::Kind::Function);
|
||||
AddBuiltin("getfarray", Symbol::Kind::Function);
|
||||
AddBuiltin("putint", Symbol::Kind::Function);
|
||||
AddBuiltin("putch", Symbol::Kind::Function);
|
||||
AddBuiltin("putfloat", Symbol::Kind::Function);
|
||||
AddBuiltin("putarray", Symbol::Kind::Function);
|
||||
AddBuiltin("putfarray", Symbol::Kind::Function);
|
||||
AddBuiltin("starttime", Symbol::Kind::Function);
|
||||
AddBuiltin("stoptime", Symbol::Kind::Function);
|
||||
AddBuiltin("putf", Symbol::Kind::Function);
|
||||
}
|
||||
|
||||
private:
|
||||
void AddBuiltin(const std::string& name, Symbol::Kind kind) {
|
||||
Symbol sym;
|
||||
sym.kind = kind;
|
||||
sym.def_ctx = nullptr; // 内建函数没有语法树节点
|
||||
table_.Add(name, sym);
|
||||
}
|
||||
|
||||
std::any visitCompUnit(SysYParser::CompUnitContext* ctx) override {
|
||||
if (!ctx) {
|
||||
throw std::runtime_error(FormatError("sema", "缺少编译单元"));
|
||||
if (!ctx) return {};
|
||||
for (auto* child : ctx->children) {
|
||||
if (auto* decl = dynamic_cast<SysYParser::DeclContext*>(child)) {
|
||||
decl->accept(this);
|
||||
} else if (auto* funcDef = dynamic_cast<SysYParser::FuncDefContext*>(child)) {
|
||||
funcDef->accept(this);
|
||||
}
|
||||
}
|
||||
auto* func = ctx->funcDef();
|
||||
if (!func || !func->blockStmt()) {
|
||||
throw std::runtime_error(FormatError("sema", "缺少 main 函数定义"));
|
||||
return {};
|
||||
}
|
||||
|
||||
std::any visitDecl(SysYParser::DeclContext* ctx) override {
|
||||
if (ctx->constDecl()) return ctx->constDecl()->accept(this);
|
||||
if (ctx->varDecl()) return ctx->varDecl()->accept(this);
|
||||
return {};
|
||||
}
|
||||
|
||||
std::any visitConstDecl(SysYParser::ConstDeclContext* ctx) override {
|
||||
for (auto* def : ctx->constDef()) {
|
||||
const std::string name = def->ID()->getText();
|
||||
if (table_.IsInCurrentScope(name)) {
|
||||
throw std::runtime_error(FormatError("sema", "重复定义常量: " + name));
|
||||
}
|
||||
Symbol sym;
|
||||
sym.kind = Symbol::Kind::Constant;
|
||||
sym.def_ctx = def;
|
||||
sym.is_const = true;
|
||||
sym.is_array = !def->exp().empty();
|
||||
table_.Add(name, sym);
|
||||
|
||||
for (auto* exp : def->exp()) exp->accept(this);
|
||||
def->initValue()->accept(this);
|
||||
}
|
||||
if (!func->ID() || func->ID()->getText() != "main") {
|
||||
throw std::runtime_error(FormatError("sema", "缺少 main 函数定义"));
|
||||
}
|
||||
func->accept(this);
|
||||
if (!seen_return_) {
|
||||
throw std::runtime_error(
|
||||
FormatError("sema", "main 函数必须包含 return 语句"));
|
||||
return {};
|
||||
}
|
||||
|
||||
std::any visitVarDecl(SysYParser::VarDeclContext* ctx) override {
|
||||
for (auto* def : ctx->varDef()) {
|
||||
const std::string name = def->ID()->getText();
|
||||
if (table_.IsInCurrentScope(name)) {
|
||||
throw std::runtime_error(FormatError("sema", "重复定义变量: " + name));
|
||||
}
|
||||
Symbol sym;
|
||||
sym.kind = Symbol::Kind::Variable;
|
||||
sym.def_ctx = def;
|
||||
sym.is_const = false;
|
||||
sym.is_array = !def->exp().empty();
|
||||
table_.Add(name, sym);
|
||||
|
||||
for (auto* exp : def->exp()) exp->accept(this);
|
||||
if (def->initValue()) def->initValue()->accept(this);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
std::any visitFuncDef(SysYParser::FuncDefContext* ctx) override {
|
||||
if (!ctx || !ctx->blockStmt()) {
|
||||
throw std::runtime_error(FormatError("sema", "缺少 main 函数定义"));
|
||||
const std::string name = ctx->ID()->getText();
|
||||
if (table_.IsInCurrentScope(name)) {
|
||||
throw std::runtime_error(FormatError("sema", "重复定义函数: " + name));
|
||||
}
|
||||
if (!ctx->funcType() || !ctx->funcType()->INT()) {
|
||||
throw std::runtime_error(FormatError("sema", "当前仅支持 int main"));
|
||||
Symbol sym;
|
||||
sym.kind = Symbol::Kind::Function;
|
||||
sym.def_ctx = ctx;
|
||||
table_.Add(name, sym);
|
||||
|
||||
table_.PushScope();
|
||||
if (ctx->funcFParams()) {
|
||||
ctx->funcFParams()->accept(this);
|
||||
}
|
||||
const auto& items = ctx->blockStmt()->blockItem();
|
||||
if (items.empty()) {
|
||||
throw std::runtime_error(
|
||||
FormatError("sema", "main 函数不能为空,且必须以 return 结束"));
|
||||
if (ctx->blockStmt()) {
|
||||
// Visit block items without pushing another scope to keep params in same scope
|
||||
for (auto* item : ctx->blockStmt()->blockItem()) {
|
||||
item->accept(this);
|
||||
}
|
||||
}
|
||||
ctx->blockStmt()->accept(this);
|
||||
table_.PopScope();
|
||||
return {};
|
||||
}
|
||||
|
||||
std::any visitFuncFParam(SysYParser::FuncFParamContext* ctx) override {
|
||||
const std::string name = ctx->ID()->getText();
|
||||
if (table_.IsInCurrentScope(name)) {
|
||||
throw std::runtime_error(FormatError("sema", "函数参数名冲突: " + name));
|
||||
}
|
||||
Symbol sym;
|
||||
sym.kind = Symbol::Kind::Parameter;
|
||||
sym.def_ctx = ctx;
|
||||
sym.is_array = !ctx->LBRACK().empty();
|
||||
table_.Add(name, sym);
|
||||
|
||||
for (auto* exp : ctx->exp()) exp->accept(this);
|
||||
return {};
|
||||
}
|
||||
|
||||
std::any visitBlockStmt(SysYParser::BlockStmtContext* ctx) override {
|
||||
if (!ctx) {
|
||||
throw std::runtime_error(FormatError("sema", "缺少语句块"));
|
||||
}
|
||||
const auto& items = ctx->blockItem();
|
||||
for (size_t i = 0; i < items.size(); ++i) {
|
||||
auto* item = items[i];
|
||||
if (!item) {
|
||||
continue;
|
||||
}
|
||||
if (seen_return_) {
|
||||
throw std::runtime_error(
|
||||
FormatError("sema", "return 必须是 main 函数中的最后一条语句"));
|
||||
}
|
||||
current_item_index_ = i;
|
||||
total_items_ = items.size();
|
||||
table_.PushScope();
|
||||
for (auto* item : ctx->blockItem()) {
|
||||
item->accept(this);
|
||||
}
|
||||
table_.PopScope();
|
||||
return {};
|
||||
}
|
||||
|
||||
std::any visitBlockItem(SysYParser::BlockItemContext* ctx) override {
|
||||
if (!ctx) {
|
||||
throw std::runtime_error(FormatError("sema", "暂不支持的语句或声明"));
|
||||
}
|
||||
if (ctx->decl()) {
|
||||
ctx->decl()->accept(this);
|
||||
return {};
|
||||
}
|
||||
if (ctx->stmt()) {
|
||||
ctx->stmt()->accept(this);
|
||||
return {};
|
||||
}
|
||||
throw std::runtime_error(FormatError("sema", "暂不支持的语句或声明"));
|
||||
}
|
||||
|
||||
std::any visitDecl(SysYParser::DeclContext* ctx) override {
|
||||
if (!ctx) {
|
||||
throw std::runtime_error(FormatError("sema", "非法变量声明"));
|
||||
}
|
||||
if (!ctx->btype() || !ctx->btype()->INT()) {
|
||||
throw std::runtime_error(FormatError("sema", "当前仅支持局部 int 变量声明"));
|
||||
}
|
||||
auto* var_def = ctx->varDef();
|
||||
if (!var_def || !var_def->lValue()) {
|
||||
throw std::runtime_error(FormatError("sema", "非法变量声明"));
|
||||
}
|
||||
const std::string name = GetLValueName(*var_def->lValue());
|
||||
if (table_.Contains(name)) {
|
||||
throw std::runtime_error(FormatError("sema", "重复定义变量: " + name));
|
||||
}
|
||||
if (auto* init = var_def->initValue()) {
|
||||
if (!init->exp()) {
|
||||
throw std::runtime_error(FormatError("sema", "当前不支持聚合初始化"));
|
||||
}
|
||||
init->exp()->accept(this);
|
||||
}
|
||||
table_.Add(name, var_def);
|
||||
return {};
|
||||
}
|
||||
|
||||
std::any visitStmt(SysYParser::StmtContext* ctx) override {
|
||||
if (!ctx || !ctx->returnStmt()) {
|
||||
throw std::runtime_error(FormatError("sema", "暂不支持的语句或声明"));
|
||||
}
|
||||
ctx->returnStmt()->accept(this);
|
||||
return {};
|
||||
}
|
||||
|
||||
std::any visitReturnStmt(SysYParser::ReturnStmtContext* ctx) override {
|
||||
if (!ctx || !ctx->exp()) {
|
||||
throw std::runtime_error(FormatError("sema", "return 缺少表达式"));
|
||||
std::any visitAssignStmt(SysYParser::AssignStmtContext* ctx) override {
|
||||
ctx->lValue()->accept(this);
|
||||
const std::string name = ctx->lValue()->ID()->getText();
|
||||
Symbol* sym = table_.Lookup(name);
|
||||
if (sym && sym->is_const) {
|
||||
throw std::runtime_error(FormatError("sema", "试图给常量赋值: " + name));
|
||||
}
|
||||
ctx->exp()->accept(this);
|
||||
seen_return_ = true;
|
||||
if (current_item_index_ + 1 != total_items_) {
|
||||
throw std::runtime_error(
|
||||
FormatError("sema", "return 必须是 main 函数中的最后一条语句"));
|
||||
return {};
|
||||
}
|
||||
|
||||
std::any visitLValue(SysYParser::LValueContext* ctx) override {
|
||||
const std::string name = ctx->ID()->getText();
|
||||
Symbol* sym = table_.Lookup(name);
|
||||
if (!sym) {
|
||||
throw std::runtime_error(FormatError("sema", "使用了未定义的标识符: " + name));
|
||||
}
|
||||
if (sym->kind == Symbol::Kind::Function) {
|
||||
throw std::runtime_error(FormatError("sema", "函数名不能作为左值: " + name));
|
||||
}
|
||||
sema_.BindLValue(ctx, sym->def_ctx);
|
||||
for (auto* exp : ctx->exp()) exp->accept(this);
|
||||
return {};
|
||||
}
|
||||
|
||||
std::any visitFuncCallExp(SysYParser::FuncCallExpContext* ctx) override {
|
||||
const std::string name = ctx->ID()->getText();
|
||||
Symbol* sym = table_.Lookup(name);
|
||||
if (!sym) {
|
||||
throw std::runtime_error(FormatError("sema", "调用未定义的函数: " + name));
|
||||
}
|
||||
if (sym->kind != Symbol::Kind::Function) {
|
||||
throw std::runtime_error(FormatError("sema", "标识符不是函数: " + name));
|
||||
}
|
||||
sema_.BindFuncCall(ctx, dynamic_cast<SysYParser::FuncDefContext*>(sym->def_ctx));
|
||||
if (ctx->funcRParams()) {
|
||||
ctx->funcRParams()->accept(this);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
// Visit expressions to ensure all sub-expressions are checked (e.g. for variable uses)
|
||||
std::any visitParenExp(SysYParser::ParenExpContext* ctx) override {
|
||||
if (!ctx || !ctx->exp()) {
|
||||
throw std::runtime_error(FormatError("sema", "非法括号表达式"));
|
||||
}
|
||||
ctx->exp()->accept(this);
|
||||
return {};
|
||||
return ctx->exp()->accept(this);
|
||||
}
|
||||
|
||||
std::any visitVarExp(SysYParser::VarExpContext* ctx) override {
|
||||
if (!ctx || !ctx->var()) {
|
||||
throw std::runtime_error(FormatError("sema", "非法变量表达式"));
|
||||
}
|
||||
ctx->var()->accept(this);
|
||||
return {};
|
||||
std::any visitLValueExp(SysYParser::LValueExpContext* ctx) override {
|
||||
return ctx->lValue()->accept(this);
|
||||
}
|
||||
|
||||
std::any visitNumberExp(SysYParser::NumberExpContext* ctx) override {
|
||||
if (!ctx || !ctx->number() || !ctx->number()->ILITERAL()) {
|
||||
throw std::runtime_error(FormatError("sema", "当前仅支持整数字面量"));
|
||||
}
|
||||
return ctx->number()->accept(this);
|
||||
}
|
||||
|
||||
std::any visitNumber(SysYParser::NumberContext* ctx) override {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::any visitAdditiveExp(SysYParser::AdditiveExpContext* ctx) override {
|
||||
if (!ctx || !ctx->exp(0) || !ctx->exp(1)) {
|
||||
throw std::runtime_error(FormatError("sema", "暂不支持的表达式形式"));
|
||||
}
|
||||
std::any visitNotExp(SysYParser::NotExpContext* ctx) override {
|
||||
return ctx->exp()->accept(this);
|
||||
}
|
||||
|
||||
std::any visitUnaryAddExp(SysYParser::UnaryAddExpContext* ctx) override {
|
||||
return ctx->exp()->accept(this);
|
||||
}
|
||||
|
||||
std::any visitUnarySubExp(SysYParser::UnarySubExpContext* ctx) override {
|
||||
return ctx->exp()->accept(this);
|
||||
}
|
||||
|
||||
std::any visitMulExp(SysYParser::MulExpContext* ctx) override {
|
||||
ctx->exp(0)->accept(this);
|
||||
ctx->exp(1)->accept(this);
|
||||
return {};
|
||||
}
|
||||
|
||||
std::any visitVar(SysYParser::VarContext* ctx) override {
|
||||
if (!ctx || !ctx->ID()) {
|
||||
throw std::runtime_error(FormatError("sema", "非法变量引用"));
|
||||
}
|
||||
const std::string name = ctx->ID()->getText();
|
||||
auto* decl = table_.Lookup(name);
|
||||
if (!decl) {
|
||||
throw std::runtime_error(FormatError("sema", "使用了未定义的变量: " + name));
|
||||
}
|
||||
sema_.BindVarUse(ctx, decl);
|
||||
std::any visitDivExp(SysYParser::DivExpContext* ctx) override {
|
||||
ctx->exp(0)->accept(this);
|
||||
ctx->exp(1)->accept(this);
|
||||
return {};
|
||||
}
|
||||
|
||||
SemanticContext TakeSemanticContext() { return std::move(sema_); }
|
||||
std::any visitModExp(SysYParser::ModExpContext* ctx) override {
|
||||
ctx->exp(0)->accept(this);
|
||||
ctx->exp(1)->accept(this);
|
||||
return {};
|
||||
}
|
||||
|
||||
private:
|
||||
std::any visitAddExp(SysYParser::AddExpContext* ctx) override {
|
||||
ctx->exp(0)->accept(this);
|
||||
ctx->exp(1)->accept(this);
|
||||
return {};
|
||||
}
|
||||
|
||||
std::any visitSubExp(SysYParser::SubExpContext* ctx) override {
|
||||
ctx->exp(0)->accept(this);
|
||||
ctx->exp(1)->accept(this);
|
||||
return {};
|
||||
}
|
||||
|
||||
std::any visitLtExp(SysYParser::LtExpContext* ctx) override {
|
||||
ctx->exp(0)->accept(this);
|
||||
ctx->exp(1)->accept(this);
|
||||
return {};
|
||||
}
|
||||
|
||||
std::any visitLeExp(SysYParser::LeExpContext* ctx) override {
|
||||
ctx->exp(0)->accept(this);
|
||||
ctx->exp(1)->accept(this);
|
||||
return {};
|
||||
}
|
||||
|
||||
std::any visitGtExp(SysYParser::GtExpContext* ctx) override {
|
||||
ctx->exp(0)->accept(this);
|
||||
ctx->exp(1)->accept(this);
|
||||
return {};
|
||||
}
|
||||
|
||||
std::any visitGeExp(SysYParser::GeExpContext* ctx) override {
|
||||
ctx->exp(0)->accept(this);
|
||||
ctx->exp(1)->accept(this);
|
||||
return {};
|
||||
}
|
||||
|
||||
std::any visitEqExp(SysYParser::EqExpContext* ctx) override {
|
||||
ctx->exp(0)->accept(this);
|
||||
ctx->exp(1)->accept(this);
|
||||
return {};
|
||||
}
|
||||
|
||||
std::any visitNeExp(SysYParser::NeExpContext* ctx) override {
|
||||
ctx->exp(0)->accept(this);
|
||||
ctx->exp(1)->accept(this);
|
||||
return {};
|
||||
}
|
||||
|
||||
std::any visitAndExp(SysYParser::AndExpContext* ctx) override {
|
||||
ctx->exp(0)->accept(this);
|
||||
ctx->exp(1)->accept(this);
|
||||
return {};
|
||||
}
|
||||
|
||||
std::any visitOrExp(SysYParser::OrExpContext* ctx) override {
|
||||
ctx->exp(0)->accept(this);
|
||||
ctx->exp(1)->accept(this);
|
||||
return {};
|
||||
}
|
||||
|
||||
std::any visitReturnStmt(SysYParser::ReturnStmtContext* ctx) override {
|
||||
if (ctx->exp()) ctx->exp()->accept(this);
|
||||
return {};
|
||||
}
|
||||
|
||||
std::any visitIfStmt(SysYParser::IfStmtContext* ctx) override {
|
||||
ctx->exp()->accept(this);
|
||||
ctx->stmt(0)->accept(this);
|
||||
if (ctx->stmt(1)) ctx->stmt(1)->accept(this);
|
||||
return {};
|
||||
}
|
||||
|
||||
std::any visitWhileStmt(SysYParser::WhileStmtContext* ctx) override {
|
||||
ctx->exp()->accept(this);
|
||||
ctx->stmt()->accept(this);
|
||||
return {};
|
||||
}
|
||||
|
||||
std::any visitBreakStmt(SysYParser::BreakStmtContext* ctx) override {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::any visitContinueStmt(SysYParser::ContinueStmtContext* ctx) override {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::any visitExpStmt(SysYParser::ExpStmtContext* ctx) override {
|
||||
if (ctx->exp()) ctx->exp()->accept(this);
|
||||
return {};
|
||||
}
|
||||
public:
|
||||
SemanticContext TakeSemanticContext() { return std::move(sema_); }
|
||||
|
||||
private:
|
||||
SymbolTable table_;
|
||||
SemanticContext sema_;
|
||||
bool seen_return_ = false;
|
||||
size_t current_item_index_ = 0;
|
||||
size_t total_items_ = 0;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
Reference in New Issue
Block a user