Complete Lab2 IR generation and document process

This commit is contained in:
2026-04-16 00:21:35 +08:00
parent 6fc0c89072
commit 979d271ebe
23 changed files with 2583 additions and 471 deletions

View File

@@ -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