fix(frontend): 规范一下前端实现

This commit is contained in:
jing
2026-03-10 23:03:14 +08:00
parent d2b54a9849
commit c72ffa6e39
8 changed files with 100 additions and 17 deletions

View File

@@ -10,16 +10,24 @@ compUnit
; ;
funcDef funcDef
: Int Main L_PAREN R_PAREN block : Int Ident L_PAREN R_PAREN block
; ;
block block
: L_BRACE stmt* R_BRACE : L_BRACE blockItem* R_BRACE
;
blockItem
: decl
| stmt
;
decl
: varDecl
; ;
stmt stmt
: varDecl : returnStmt
| returnStmt
; ;
varDecl varDecl
@@ -46,7 +54,6 @@ primary
Int : 'int'; Int : 'int';
Return : 'return'; Return : 'return';
Main : 'main';
AddOp : '+'; AddOp : '+';
Assign : '='; Assign : '=';

View File

@@ -12,6 +12,10 @@
namespace { namespace {
bool HasParsePrefix(const std::string& msg) {
return msg.rfind("[parse]", 0) == 0;
}
class ParseErrorListener : public antlr4::BaseErrorListener { class ParseErrorListener : public antlr4::BaseErrorListener {
public: public:
void syntaxError(antlr4::Recognizer* /*recognizer*/, antlr4::Token* /*offendingSymbol*/, void syntaxError(antlr4::Recognizer* /*recognizer*/, antlr4::Token* /*offendingSymbol*/,
@@ -49,6 +53,9 @@ AntlrResult ParseFileWithAntlr(const std::string& path) {
} catch (const std::exception& ex) { } catch (const std::exception& ex) {
const std::string msg = ex.what(); const std::string msg = ex.what();
if (!msg.empty()) { if (!msg.empty()) {
if (HasParsePrefix(msg)) {
throw;
}
throw std::runtime_error("[parse] 暂不支持的语法/词法 - " + msg); throw std::runtime_error("[parse] 暂不支持的语法/词法 - " + msg);
} }
if (auto* tok = parser->getCurrentToken()) { if (auto* tok = parser->getCurrentToken()) {

View File

@@ -23,7 +23,7 @@ class Context {
const std::shared_ptr<Type>& PtrInt32(); const std::shared_ptr<Type>& PtrInt32();
// 去重创建 i32 常量。 // 去重创建 i32 常量。
ConstantInt* GetConstInt(int v); ConstantInt* GetConstInt(int v);
// 生成临时名称,如 %t0、%t1 ...
std::string NextTemp(); std::string NextTemp();
private: private:

View File

@@ -6,6 +6,13 @@
#include <stdexcept> #include <stdexcept>
namespace ir { namespace ir {
namespace {
bool IsArithmeticType(const std::shared_ptr<Type>& ty) {
return ty && ty->kind() == Type::Kind::Int32;
}
} // namespace
ConstantInt* IRBuilder::CreateConstInt(int v) { ConstantInt* IRBuilder::CreateConstInt(int v) {
// 常量不需要挂在基本块里,由 Context 负责去重与生命周期。 // 常量不需要挂在基本块里,由 Context 负责去重与生命周期。
@@ -17,7 +24,23 @@ BinaryInst* IRBuilder::CreateBinary(Opcode op, Value* lhs, Value* rhs,
if (!insertBlock_) { if (!insertBlock_) {
throw std::runtime_error("IRBuilder 未设置插入点"); throw std::runtime_error("IRBuilder 未设置插入点");
} }
return insertBlock_->Append<BinaryInst>(op, Type::Int32(), lhs, rhs, name); if (!lhs) {
throw std::runtime_error("IRBuilder::CreateBinary 缺少 lhs");
}
if (!rhs) {
throw std::runtime_error("IRBuilder::CreateBinary 缺少 rhs");
}
if (op != Opcode::Add) {
throw std::runtime_error("IRBuilder::CreateBinary 当前只支持 Add");
}
if (!lhs->type() || !rhs->type() ||
lhs->type()->kind() != rhs->type()->kind()) {
throw std::runtime_error("IRBuilder::CreateBinary 操作数类型不匹配");
}
if (!IsArithmeticType(lhs->type())) {
throw std::runtime_error("IRBuilder::CreateBinary 当前只支持 i32 二元运算");
}
return insertBlock_->Append<BinaryInst>(op, lhs->type(), lhs, rhs, name);
} }
AllocaInst* IRBuilder::CreateAllocaI32(const std::string& name) { AllocaInst* IRBuilder::CreateAllocaI32(const std::string& name) {

View File

@@ -32,6 +32,8 @@ class IRGenImpl {
private: private:
void GenFuncDef(SysYParser::FuncDefContext& func); void GenFuncDef(SysYParser::FuncDefContext& func);
void GenBlock(SysYParser::BlockContext& block); void GenBlock(SysYParser::BlockContext& block);
bool GenBlockItem(SysYParser::BlockItemContext& item);
void GenDecl(SysYParser::DeclContext& decl);
bool GenStmt(SysYParser::StmtContext& stmt); bool GenStmt(SysYParser::StmtContext& stmt);
void GenVarDecl(SysYParser::VarDeclContext& decl); void GenVarDecl(SysYParser::VarDeclContext& decl);
void GenReturnStmt(SysYParser::ReturnStmtContext& ret); void GenReturnStmt(SysYParser::ReturnStmtContext& ret);

View File

@@ -6,15 +6,34 @@
#include "ir/IR.h" #include "ir/IR.h"
void IRGenImpl::GenBlock(SysYParser::BlockContext& block) { void IRGenImpl::GenBlock(SysYParser::BlockContext& block) {
for (auto* stmt : block.stmt()) { for (auto* item : block.blockItem()) {
if (stmt) { if (item) {
if (GenStmt(*stmt)) { if (GenBlockItem(*item)) {
break; break;
} }
} }
} }
} }
bool IRGenImpl::GenBlockItem(SysYParser::BlockItemContext& item) {
if (item.decl()) {
GenDecl(*item.decl());
return false;
}
if (item.stmt()) {
return GenStmt(*item.stmt());
}
throw std::runtime_error("[irgen] 暂不支持的 blockItem 类型");
}
void IRGenImpl::GenDecl(SysYParser::DeclContext& decl) {
if (decl.varDecl()) {
GenVarDecl(*decl.varDecl());
return;
}
throw std::runtime_error("[irgen] 暂不支持的声明类型");
}
void IRGenImpl::GenVarDecl(SysYParser::VarDeclContext& decl) { void IRGenImpl::GenVarDecl(SysYParser::VarDeclContext& decl) {
const std::string name = decl.Ident()->getText(); const std::string name = decl.Ident()->getText();
if (locals_.find(name) != locals_.end()) { if (locals_.find(name) != locals_.end()) {

View File

@@ -19,8 +19,11 @@ void IRGenImpl::GenFuncDef(SysYParser::FuncDefContext& func) {
if (!func.block()) { if (!func.block()) {
throw std::runtime_error("[irgen] 函数体为空"); throw std::runtime_error("[irgen] 函数体为空");
} }
if (!func.Ident()) {
throw std::runtime_error("[irgen] 缺少函数名");
}
func_ = module_.CreateFunction("main", ir::Type::Int32()); func_ = module_.CreateFunction(func.Ident()->getText(), ir::Type::Int32());
builder_.SetInsertPoint(func_->entry()); builder_.SetInsertPoint(func_->entry());
locals_.clear(); locals_.clear();

View File

@@ -48,14 +48,27 @@ void RunSema(SysYParser::CompUnitContext& comp_unit) {
if (!func || !func->block()) { if (!func || !func->block()) {
throw std::runtime_error("[sema] 缺少 main 函数定义"); throw std::runtime_error("[sema] 缺少 main 函数定义");
} }
if (!func->Ident() || func->Ident()->getText() != "main") {
throw std::runtime_error("[sema] 入口函数必须命名为 main");
}
SymbolTable table; SymbolTable table;
bool seen_return = false;
for (auto* stmt : func->block()->stmt()) { const auto& items = func->block()->blockItem();
if (!stmt) { if (items.empty()) {
throw std::runtime_error("[sema] main 函数不能为空,且必须以 return 结束");
}
for (size_t i = 0; i < items.size(); ++i) {
auto* item = items[i];
if (!item) {
continue; continue;
} }
if (auto* decl = stmt->varDecl()) { if (seen_return) {
throw std::runtime_error("[sema] return 必须是 main 函数中的最后一条语句");
}
if (auto* decl = item->decl() ? item->decl()->varDecl() : nullptr) {
const std::string name = decl->Ident()->getText(); const std::string name = decl->Ident()->getText();
if (table.Contains(name)) { if (table.Contains(name)) {
throw std::runtime_error("[sema] 重复定义变量: " + name); throw std::runtime_error("[sema] 重复定义变量: " + name);
@@ -66,10 +79,19 @@ void RunSema(SysYParser::CompUnitContext& comp_unit) {
table.Add(name); table.Add(name);
continue; continue;
} }
if (auto* ret = stmt->returnStmt()) { if (auto* stmt = item->stmt(); stmt && stmt->returnStmt()) {
auto* ret = stmt->returnStmt();
CheckExpr(*ret->exp(), table); CheckExpr(*ret->exp(), table);
break; seen_return = true;
if (i + 1 != items.size()) {
throw std::runtime_error("[sema] return 必须是 main 函数中的最后一条语句");
}
continue;
} }
throw std::runtime_error("[sema] 暂不支持的语句类型"); throw std::runtime_error("[sema] 暂不支持的 blockItem 类型");
}
if (!seen_return) {
throw std::runtime_error("[sema] main 函数必须包含 return 语句");
} }
} }