fix(frontend): 规范一下前端实现
This commit is contained in:
@@ -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 : '=';
|
||||||
|
|||||||
@@ -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()) {
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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()) {
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|
||||||
|
|||||||
@@ -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 语句");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user