You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

215 lines
7.1 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#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;
}