feat: 支持 const 常量声明与初始化

hp 3 days ago
parent d8486b7313
commit fc08c12f40

@ -29,6 +29,8 @@ class IRGenImpl final : public SysYBaseVisitor {
std::any visitBlock(SysYParser::BlockContext* ctx) override;
std::any visitBlockItem(SysYParser::BlockItemContext* ctx) override;
std::any visitDecl(SysYParser::DeclContext* ctx) override;
std::any visitConstDecl(SysYParser::ConstDeclContext* ctx) override;
std::any visitConstDef(SysYParser::ConstDefContext* ctx) override;
std::any visitStmt(SysYParser::StmtContext* ctx) override;
std::any visitVarDef(SysYParser::VarDefContext* ctx) override;
std::any visitPrimaryExp(SysYParser::PrimaryExpContext* ctx) override;
@ -60,6 +62,9 @@ class IRGenImpl final : public SysYBaseVisitor {
ir::IRBuilder builder_;
// 名称绑定由 Sema 负责IRGen 只维护"变量名 -> 存储槽位"的代码生成状态。
std::unordered_map<std::string, ir::Value*> storage_map_;
// 记录常量名到常量值的映射,用于后续生成指令时直接替换
std::unordered_map<std::string, ir::ConstantValue*> const_values_;
// 用于 break 和 continue 跳转的目标位置
ir::BasicBlock* current_loop_cond_bb_ = nullptr;

@ -41,6 +41,67 @@ std::any IRGenImpl::visitBlockItem(SysYParser::BlockItemContext* ctx) {
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 继续处理。
@ -59,15 +120,7 @@ std::any IRGenImpl::visitDecl(SysYParser::DeclContext* ctx) {
}
}
} else if (auto* const_decl = ctx->constDecl()) {
// 稍后实现 constDecl
if (!const_decl->bType() || (!const_decl->bType()->INT() && !const_decl->bType()->FLOAT())) {
throw std::runtime_error(FormatError("irgen", "当前仅支持 int/float 常量声明"));
}
for (auto* const_def : const_decl->constDef()) {
if (const_def) {
const_def->accept(this);
}
}
return const_decl->accept(this);
} else {
throw std::runtime_error(FormatError("irgen", "当前仅支持变量声明"));
}

@ -82,6 +82,15 @@ std::any IRGenImpl::visitLVal(SysYParser::LValContext* ctx) {
if (!ctx || !ctx->ID()) {
throw std::runtime_error(FormatError("irgen", "当前仅支持普通整型变量"));
}
std::string var_name = ctx->ID()->getText();
// 优先检查是否为已记录的常量,如果是则直接返回常量值,不再生成 Load 指令
auto it_const = const_values_.find(var_name);
if (it_const != const_values_.end()) {
return static_cast<ir::Value*>(it_const->second);
}
const auto* decl = sema_.ResolveObjectUse(ctx);
if (!decl) {
throw std::runtime_error(
@ -89,7 +98,6 @@ std::any IRGenImpl::visitLVal(SysYParser::LValContext* ctx) {
"变量使用缺少语义绑定:" + ctx->ID()->getText()));
}
// 使用变量名查找存储槽位
std::string var_name = ctx->ID()->getText();
auto it = storage_map_.find(var_name);
if (it == storage_map_.end()) {
throw std::runtime_error(

Loading…
Cancel
Save