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

master
jing 1 week ago
parent d2b54a9849
commit c72ffa6e39

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

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

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

@ -6,6 +6,13 @@
#include <stdexcept>
namespace ir {
namespace {
bool IsArithmeticType(const std::shared_ptr<Type>& ty) {
return ty && ty->kind() == Type::Kind::Int32;
}
} // namespace
ConstantInt* IRBuilder::CreateConstInt(int v) {
// 常量不需要挂在基本块里,由 Context 负责去重与生命周期。
@ -17,7 +24,23 @@ BinaryInst* IRBuilder::CreateBinary(Opcode op, Value* lhs, Value* rhs,
if (!insertBlock_) {
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) {

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

@ -6,15 +6,34 @@
#include "ir/IR.h"
void IRGenImpl::GenBlock(SysYParser::BlockContext& block) {
for (auto* stmt : block.stmt()) {
if (stmt) {
if (GenStmt(*stmt)) {
for (auto* item : block.blockItem()) {
if (item) {
if (GenBlockItem(*item)) {
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) {
const std::string name = decl.Ident()->getText();
if (locals_.find(name) != locals_.end()) {

@ -19,8 +19,11 @@ void IRGenImpl::GenFuncDef(SysYParser::FuncDefContext& func) {
if (!func.block()) {
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());
locals_.clear();

@ -48,14 +48,27 @@ void RunSema(SysYParser::CompUnitContext& comp_unit) {
if (!func || !func->block()) {
throw std::runtime_error("[sema] 缺少 main 函数定义");
}
if (!func->Ident() || func->Ident()->getText() != "main") {
throw std::runtime_error("[sema] 入口函数必须命名为 main");
}
SymbolTable table;
bool seen_return = false;
const auto& items = func->block()->blockItem();
if (items.empty()) {
throw std::runtime_error("[sema] main 函数不能为空,且必须以 return 结束");
}
for (auto* stmt : func->block()->stmt()) {
if (!stmt) {
for (size_t i = 0; i < items.size(); ++i) {
auto* item = items[i];
if (!item) {
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();
if (table.Contains(name)) {
throw std::runtime_error("[sema] 重复定义变量: " + name);
@ -66,10 +79,19 @@ void RunSema(SysYParser::CompUnitContext& comp_unit) {
table.Add(name);
continue;
}
if (auto* ret = stmt->returnStmt()) {
if (auto* stmt = item->stmt(); stmt && stmt->returnStmt()) {
auto* ret = stmt->returnStmt();
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 语句");
}
}

Loading…
Cancel
Save