From fc08c12f40d69b41076f49a6838b4249b29bf49f Mon Sep 17 00:00:00 2001 From: hp <1278334840@qq.com> Date: Mon, 6 Apr 2026 21:50:57 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=94=AF=E6=8C=81=20const=20=E5=B8=B8?= =?UTF-8?q?=E9=87=8F=E5=A3=B0=E6=98=8E=E4=B8=8E=E5=88=9D=E5=A7=8B=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/irgen/IRGen.h | 5 +++ src/irgen/IRGenDecl.cpp | 71 +++++++++++++++++++++++++++++++++++------ src/irgen/IRGenExp.cpp | 10 +++++- 3 files changed, 76 insertions(+), 10 deletions(-) diff --git a/include/irgen/IRGen.h b/include/irgen/IRGen.h index b56d538..bca31b9 100644 --- a/include/irgen/IRGen.h +++ b/include/irgen/IRGen.h @@ -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 storage_map_; + + // 记录常量名到常量值的映射,用于后续生成指令时直接替换 + std::unordered_map const_values_; // 用于 break 和 continue 跳转的目标位置 ir::BasicBlock* current_loop_cond_bb_ = nullptr; diff --git a/src/irgen/IRGenDecl.cpp b/src/irgen/IRGenDecl.cpp index ebc29e0..40c2ef5 100644 --- a/src/irgen/IRGenDecl.cpp +++ b/src/irgen/IRGenDecl.cpp @@ -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(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(val_any); + init_const = dynamic_cast(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", "当前仅支持变量声明")); } diff --git a/src/irgen/IRGenExp.cpp b/src/irgen/IRGenExp.cpp index 5ddec76..0384e40 100644 --- a/src/irgen/IRGenExp.cpp +++ b/src/irgen/IRGenExp.cpp @@ -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(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(