fix(frontend): 规范一下前端实现
This commit is contained in:
@@ -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
|
||||
;
|
||||
|
||||
blockItem
|
||||
: decl
|
||||
| stmt
|
||||
;
|
||||
|
||||
decl
|
||||
: varDecl
|
||||
;
|
||||
|
||||
stmt
|
||||
: varDecl
|
||||
| returnStmt
|
||||
: 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;
|
||||
|
||||
for (auto* stmt : func->block()->stmt()) {
|
||||
if (!stmt) {
|
||||
const auto& items = func->block()->blockItem();
|
||||
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;
|
||||
}
|
||||
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 语句");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user