|
|
#include "irgen/IRGen.h"
|
|
|
|
|
|
#include <stdexcept>
|
|
|
|
|
|
#include "SysYParser.h"
|
|
|
#include "ir/IR.h"
|
|
|
#include "utils/Log.h"
|
|
|
|
|
|
std::any IRGenImpl::visitBlock(SysYParser::BlockContext* ctx) {
|
|
|
if (!ctx) {
|
|
|
throw std::runtime_error(FormatError("irgen", "缺少语句块"));
|
|
|
}
|
|
|
bool terminated = false;
|
|
|
for (auto* item : ctx->blockItem()) {
|
|
|
if (item) {
|
|
|
if (VisitBlockItemResult(*item) == BlockFlow::Terminated) {
|
|
|
terminated = true;
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
return terminated ? BlockFlow::Terminated : BlockFlow::Continue;
|
|
|
}
|
|
|
|
|
|
IRGenImpl::BlockFlow IRGenImpl::VisitBlockItemResult(
|
|
|
SysYParser::BlockItemContext& item) {
|
|
|
return std::any_cast<BlockFlow>(item.accept(this));
|
|
|
}
|
|
|
|
|
|
std::any IRGenImpl::visitBlockItem(SysYParser::BlockItemContext* ctx) {
|
|
|
if (!ctx) {
|
|
|
throw std::runtime_error(FormatError("irgen", "缺少块内项"));
|
|
|
}
|
|
|
if (ctx->decl()) {
|
|
|
ctx->decl()->accept(this);
|
|
|
return BlockFlow::Continue;
|
|
|
}
|
|
|
if (ctx->stmt()) {
|
|
|
return ctx->stmt()->accept(this);
|
|
|
}
|
|
|
throw std::runtime_error(FormatError("irgen", "暂不支持的语句或声明"));
|
|
|
}
|
|
|
|
|
|
std::any IRGenImpl::visitConstDecl(SysYParser::ConstDeclContext* ctx) {
|
|
|
if (!ctx) return BlockFlow::Continue;
|
|
|
|
|
|
if (!ctx->bType() || (!ctx->bType()->INT() && !ctx->bType()->FLOAT())) {
|
|
|
throw std::runtime_error(FormatError("irgen", "当前仅支持 int/float 常量声明"));
|
|
|
}
|
|
|
|
|
|
for (auto* def : ctx->constDef()) {
|
|
|
if (def) def->accept(this);
|
|
|
}
|
|
|
return BlockFlow::Continue;
|
|
|
}
|
|
|
|
|
|
std::any IRGenImpl::visitConstDef(SysYParser::ConstDefContext* ctx) {
|
|
|
if (!ctx || !ctx->ID()) {
|
|
|
throw std::runtime_error(FormatError("irgen", "常量定义缺少名称"));
|
|
|
}
|
|
|
|
|
|
if (!ctx->constIndex().empty()) {
|
|
|
throw std::runtime_error(FormatError("irgen", "暂不支持数组常量声明"));
|
|
|
}
|
|
|
|
|
|
std::string var_name = ctx->ID()->getText();
|
|
|
|
|
|
bool is_float = false;
|
|
|
auto* parent_decl = dynamic_cast<SysYParser::ConstDeclContext*>(ctx->parent);
|
|
|
if (parent_decl && parent_decl->bType() && parent_decl->bType()->FLOAT()) {
|
|
|
is_float = true;
|
|
|
}
|
|
|
auto base_ty = is_float ? ir::Type::GetFloatType() : ir::Type::GetInt32Type();
|
|
|
|
|
|
ir::ConstantValue* init_const = nullptr;
|
|
|
if (auto* init_val = ctx->constInitVal()) {
|
|
|
if (init_val->constExp()) {
|
|
|
auto val_any = init_val->constExp()->accept(this);
|
|
|
ir::Value* val = std::any_cast<ir::Value*>(val_any);
|
|
|
init_const = dynamic_cast<ir::ConstantValue*>(val);
|
|
|
if (!init_const) {
|
|
|
throw std::runtime_error(FormatError("irgen", "常量初始化必须是编译期常量: " + var_name));
|
|
|
}
|
|
|
} else {
|
|
|
throw std::runtime_error(FormatError("irgen", "当前不支持聚合初始化"));
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 记录常量值供后续直接使用
|
|
|
const_values_[var_name] = init_const;
|
|
|
|
|
|
if (func_ == nullptr) {
|
|
|
auto* gv = module_.CreateGlobalVariable(var_name, base_ty, init_const);
|
|
|
storage_map_[var_name] = gv;
|
|
|
} else {
|
|
|
ir::Value* slot = is_float ? builder_.CreateAllocaFloat(module_.GetContext().NextTemp())
|
|
|
: builder_.CreateAllocaI32(module_.GetContext().NextTemp());
|
|
|
storage_map_[var_name] = slot;
|
|
|
builder_.CreateStore(init_const, slot);
|
|
|
}
|
|
|
|
|
|
return BlockFlow::Continue;
|
|
|
}
|
|
|
|
|
|
// 变量声明的 IR 生成目前也是最小实现:
|
|
|
// - 先检查声明的基础类型,支持 int 和 float;
|
|
|
// - 再把 Decl 中的变量定义交给 visitVarDef 继续处理。
|
|
|
std::any IRGenImpl::visitDecl(SysYParser::DeclContext* ctx) {
|
|
|
if (!ctx) {
|
|
|
throw std::runtime_error(FormatError("irgen", "缺少变量声明"));
|
|
|
}
|
|
|
// 当前语法中 decl 包含 constDecl 或 varDecl
|
|
|
if (auto* var_decl = ctx->varDecl()) {
|
|
|
if (!var_decl->bType() || (!var_decl->bType()->INT() && !var_decl->bType()->FLOAT())) {
|
|
|
throw std::runtime_error(FormatError("irgen", "当前仅支持 int/float 变量声明"));
|
|
|
}
|
|
|
for (auto* var_def : var_decl->varDef()) {
|
|
|
if (var_def) {
|
|
|
var_def->accept(this);
|
|
|
}
|
|
|
}
|
|
|
} else if (auto* const_decl = ctx->constDecl()) {
|
|
|
return const_decl->accept(this);
|
|
|
} else {
|
|
|
throw std::runtime_error(FormatError("irgen", "当前仅支持变量声明"));
|
|
|
}
|
|
|
return BlockFlow::Continue;
|
|
|
}
|
|
|
|
|
|
|
|
|
// 当前仍是教学用的最小版本,因此这里只支持:
|
|
|
// - 局部 int 变量;
|
|
|
// - 标量初始化;
|
|
|
// - 一个 VarDef 对应一个槽位。
|
|
|
std::any IRGenImpl::visitVarDef(SysYParser::VarDefContext* ctx) {
|
|
|
if (!ctx) {
|
|
|
throw std::runtime_error(FormatError("irgen", "缺少变量定义"));
|
|
|
}
|
|
|
if (!ctx->ID()) {
|
|
|
throw std::runtime_error(FormatError("irgen", "变量声明缺少名称"));
|
|
|
}
|
|
|
// 暂不支持数组声明(constIndex)
|
|
|
if (!ctx->constIndex().empty()) {
|
|
|
throw std::runtime_error(FormatError("irgen", "暂不支持数组声明"));
|
|
|
}
|
|
|
std::string var_name = ctx->ID()->getText();
|
|
|
if (storage_map_.find(var_name) != storage_map_.end()) {
|
|
|
throw std::runtime_error(FormatError("irgen", "声明重复生成存储槽位"));
|
|
|
}
|
|
|
|
|
|
// Determine base type from parent varDecl or constDecl
|
|
|
bool is_float = false;
|
|
|
auto* parent_decl = dynamic_cast<SysYParser::VarDeclContext*>(ctx->parent);
|
|
|
if (parent_decl && parent_decl->bType() && parent_decl->bType()->FLOAT()) {
|
|
|
is_float = true;
|
|
|
}
|
|
|
auto base_ty = is_float ? ir::Type::GetFloatType() : ir::Type::GetInt32Type();
|
|
|
|
|
|
if (func_ == nullptr) {
|
|
|
// 全局作用域
|
|
|
ir::ConstantValue* init_const = nullptr;
|
|
|
if (auto* init_val = ctx->initVal()) {
|
|
|
if (!init_val->exp()) {
|
|
|
throw std::runtime_error(FormatError("irgen", "当前不支持聚合初始化"));
|
|
|
}
|
|
|
auto* val = EvalExpr(*init_val->exp());
|
|
|
init_const = dynamic_cast<ir::ConstantValue*>(val);
|
|
|
if (!init_const) {
|
|
|
throw std::runtime_error(FormatError("irgen", "全局变量初始化必须是常量"));
|
|
|
}
|
|
|
} else {
|
|
|
if (is_float) {
|
|
|
init_const = module_.GetContext().GetConstFloat(0.0f);
|
|
|
} else {
|
|
|
init_const = module_.GetContext().GetConstInt(0);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
auto* gv = module_.CreateGlobalVariable(var_name, base_ty, init_const);
|
|
|
storage_map_[var_name] = gv;
|
|
|
|
|
|
} else {
|
|
|
// 局部作用域
|
|
|
auto* ptr_ty = is_float ? ir::Type::GetPtrFloatType() : ir::Type::GetPtrInt32Type();
|
|
|
// 简化处理,暂用 builder 创建 alloca
|
|
|
// 需要在 builder 中扩展 CreateAllocaFloat,此处简化直接按 I32 Alloca 的名称调用,或添加新接口
|
|
|
// 为了不大幅改动 Builder,我们复用 AllocaInst,或者添加 CreateAlloca
|
|
|
ir::Value* slot = nullptr;
|
|
|
if (is_float) {
|
|
|
slot = builder_.CreateAllocaFloat(module_.GetContext().NextTemp());
|
|
|
} else {
|
|
|
slot = builder_.CreateAllocaI32(module_.GetContext().NextTemp());
|
|
|
}
|
|
|
|
|
|
storage_map_[var_name] = slot;
|
|
|
|
|
|
ir::Value* init = nullptr;
|
|
|
if (auto* init_val = ctx->initVal()) {
|
|
|
if (!init_val->exp()) {
|
|
|
throw std::runtime_error(FormatError("irgen", "当前不支持聚合初始化"));
|
|
|
}
|
|
|
init = EvalExpr(*init_val->exp());
|
|
|
} else {
|
|
|
if (is_float) {
|
|
|
init = module_.GetContext().GetConstFloat(0.0f);
|
|
|
} else {
|
|
|
init = module_.GetContext().GetConstInt(0);
|
|
|
}
|
|
|
}
|
|
|
builder_.CreateStore(init, slot);
|
|
|
}
|
|
|
|
|
|
return BlockFlow::Continue;
|
|
|
}
|