diff --git a/include/irgen/IRGen.h b/include/irgen/IRGen.h new file mode 100644 index 0000000..30b71c7 --- /dev/null +++ b/include/irgen/IRGen.h @@ -0,0 +1,86 @@ +// 将语法树翻译为 IR。 +// 实现拆分在 IRGenFunc/IRGenStmt/IRGenExp/IRGenDecl。 + +#pragma once + +#include +#include +#include +#include + +#include "SysYBaseVisitor.h" +#include "SysYParser.h" +#include "ir/IR.h" +#include "sem/Sema.h" + +namespace ir { +class Module; +class Function; +class IRBuilder; +class Value; +} + +class IRGenImpl final : public SysYBaseVisitor { + public: + IRGenImpl(ir::Module& module, const SemanticContext& sema); + + // 顶层 + std::any visitCompUnit(SysYParser::CompUnitContext* ctx) override; + std::any visitFuncDef(SysYParser::FuncDefContext* ctx) override; + + // 块 + std::any visitBlock(SysYParser::BlockContext* ctx) override; + std::any visitBlockItem(SysYParser::BlockItemContext* ctx) override; + + // 声明 + std::any visitDecl(SysYParser::DeclContext* ctx) override; + std::any visitVarDef(SysYParser::VarDefContext* ctx) override; + + // 语句 + std::any visitStmt(SysYParser::StmtContext* ctx) override; + + // 表达式 + std::any visitPrimaryExp(SysYParser::PrimaryExpContext* ctx) override; + std::any visitLVal(SysYParser::LValContext* ctx) override; + std::any visitAddExp(SysYParser::AddExpContext* ctx) override; + std::any visitMulExp(SysYParser::MulExpContext* ctx) override; + std::any visitRelExp(SysYParser::RelExpContext* ctx) override; + std::any visitEqExp(SysYParser::EqExpContext* ctx) override; + std::any visitCond(SysYParser::CondContext* ctx) override; + + private: + enum class BlockFlow { + Continue, + Terminated, + }; + + BlockFlow VisitBlockItemResult(SysYParser::BlockItemContext& item); + ir::Value* EvalExpr(SysYParser::ExpContext& expr); + ir::Value* EvalCond(SysYParser::CondContext& cond); + + // 辅助函数 + BlockFlow HandleReturnStmt(SysYParser::StmtContext* ctx); + BlockFlow HandleIfStmt(SysYParser::StmtContext* ctx); + BlockFlow HandleWhileStmt(SysYParser::StmtContext* ctx); + BlockFlow HandleBreakStmt(SysYParser::StmtContext* ctx); + BlockFlow HandleContinueStmt(SysYParser::StmtContext* ctx); + BlockFlow HandleAssignStmt(SysYParser::StmtContext* ctx); + + ir::Module& module_; + const SemanticContext& sema_; + ir::Function* func_; + ir::IRBuilder builder_; + // 名称绑定由 Sema 负责;IRGen 只维护“声明 -> 存储槽位”的代码生成状态。 + std::unordered_map storage_map_; + + // 循环栈,用于 break/continue + struct LoopContext { + ir::BasicBlock* condBlock; + ir::BasicBlock* bodyBlock; + ir::BasicBlock* exitBlock; + }; + std::vector loopStack_; +}; + +std::unique_ptr GenerateIR(SysYParser::CompUnitContext& tree, + const SemanticContext& sema); diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c4ec6d9..acb9400 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -5,6 +5,7 @@ add_subdirectory(ir) add_subdirectory(frontend) if(NOT COMPILER_PARSE_ONLY) add_subdirectory(sem) + add_subdirectory(irgen) add_subdirectory(mir) endif() @@ -19,6 +20,7 @@ target_link_libraries(compiler PRIVATE if(NOT COMPILER_PARSE_ONLY) target_link_libraries(compiler PRIVATE sem + irgen mir ) target_compile_definitions(compiler PRIVATE COMPILER_PARSE_ONLY=0) diff --git a/src/irgen/CMakeLists.txt b/src/irgen/CMakeLists.txt index b28b04f..04a3195 100644 --- a/src/irgen/CMakeLists.txt +++ b/src/irgen/CMakeLists.txt @@ -1,3 +1,13 @@ +add_library(irgen STATIC + IRGenDriver.cpp + IRGenFunc.cpp + IRGenStmt.cpp + IRGenExp.cpp + IRGenDecl.cpp +) - - +target_link_libraries(irgen PUBLIC + build_options + ${ANTLR4_RUNTIME_TARGET} + ir +) \ No newline at end of file diff --git a/src/irgen/IRGenDecl.cpp b/src/irgen/IRGenDecl.cpp new file mode 100644 index 0000000..7ca55d0 --- /dev/null +++ b/src/irgen/IRGenDecl.cpp @@ -0,0 +1,83 @@ +#include "irgen/IRGen.h" + +#include + +#include "SysYParser.h" +#include "ir/IR.h" +#include "utils/Log.h" + +namespace { + +// 使用 LValContext 而不是 LValueContext +std::string GetLValueName(SysYParser::LValContext& lvalue) { + if (!lvalue.Ident()) { + throw std::runtime_error(FormatError("irgen", "非法左值")); + } + return lvalue.Ident()->getText(); +} + +} // namespace + +// 注意:visitBlock 已经在 IRGenFunc.cpp 中实现,这里不要重复定义 + +std::any IRGenImpl::visitDecl(SysYParser::DeclContext* ctx) { + if (!ctx) { + throw std::runtime_error(FormatError("irgen", "缺少变量声明")); + } + + // 处理 varDecl + if (auto* varDecl = ctx->varDecl()) { + // 检查类型 + if (varDecl->bType() && varDecl->bType()->Int()) { + for (auto* varDef : varDecl->varDef()) { + varDef->accept(this); + } + } else { + throw std::runtime_error(FormatError("irgen", "当前仅支持 int 类型变量")); + } + } + + // 处理 constDecl(暂不支持) + if (ctx->constDecl()) { + throw std::runtime_error(FormatError("irgen", "常量声明暂未实现")); + } + + return {}; +} + +std::any IRGenImpl::visitVarDef(SysYParser::VarDefContext* ctx) { + if (!ctx) { + throw std::runtime_error(FormatError("irgen", "缺少变量定义")); + } + + // 使用 Ident() 而不是 lValue() + if (!ctx->Ident()) { + throw std::runtime_error(FormatError("irgen", "变量声明缺少名称")); + } + + std::string varName = ctx->Ident()->getText(); + + if (storage_map_.find(ctx) != storage_map_.end()) { + throw std::runtime_error(FormatError("irgen", "声明重复生成存储槽位: " + varName)); + } + + // 分配存储 + auto* slot = builder_.CreateAllocaI32(module_.GetContext().NextTemp()); + storage_map_[ctx] = slot; + + ir::Value* init = nullptr; + // 使用 initVal() 而不是 initValue() + if (auto* initVal = ctx->initVal()) { + if (initVal->exp()) { + init = EvalExpr(*initVal->exp()); + } else { + // 数组初始化暂不支持 + init = builder_.CreateConstInt(0); + } + } else { + init = builder_.CreateConstInt(0); + } + + builder_.CreateStore(init, slot); + return {}; +} diff --git a/src/irgen/IRGenDriver.cpp b/src/irgen/IRGenDriver.cpp new file mode 100644 index 0000000..ff94412 --- /dev/null +++ b/src/irgen/IRGenDriver.cpp @@ -0,0 +1,15 @@ +#include "irgen/IRGen.h" + +#include + +#include "SysYParser.h" +#include "ir/IR.h" +#include "utils/Log.h" + +std::unique_ptr GenerateIR(SysYParser::CompUnitContext& tree, + const SemanticContext& sema) { + auto module = std::make_unique(); + IRGenImpl gen(*module, sema); + tree.accept(&gen); + return module; +} diff --git a/src/irgen/IRGenExp.cpp b/src/irgen/IRGenExp.cpp new file mode 100644 index 0000000..90d07b1 --- /dev/null +++ b/src/irgen/IRGenExp.cpp @@ -0,0 +1,202 @@ +#include "irgen/IRGen.h" + +#include + +#include "SysYParser.h" +#include "ir/IR.h" +#include "utils/Log.h" + +// 表达式生成当前也只实现了很小的一个子集。 +// 目前支持: +// - 整数字面量 +// - 普通局部变量读取 +// - 括号表达式 +// - 二元加法 +// +// 还未支持: +// - 减乘除与一元运算 +// - 赋值表达式 +// - 函数调用 +// - 数组、指针、下标访问 +// - 条件与比较表达式 +// - ... + +ir::Value* IRGenImpl::EvalExpr(SysYParser::ExpContext& expr) { + return std::any_cast(expr.accept(this)); +} + +ir::Value* IRGenImpl::EvalCond(SysYParser::CondContext& cond) { + return std::any_cast(cond.accept(this)); +} + +// 基本表达式:数字、变量、括号表达式 +std::any IRGenImpl::visitPrimaryExp(SysYParser::PrimaryExpContext* ctx) { + if (!ctx) { + throw std::runtime_error(FormatError("irgen", "缺少基本表达式")); + } + + // 处理数字字面量 + if (ctx->DECIMAL_INT()) { + int value = std::stoi(ctx->DECIMAL_INT()->getText()); + return static_cast(builder_.CreateConstInt(value)); + } + + if (ctx->HEX_INT()) { + std::string hex = ctx->HEX_INT()->getText(); + int value = std::stoi(hex, nullptr, 16); + return static_cast(builder_.CreateConstInt(value)); + } + + if (ctx->OCTAL_INT()) { + std::string oct = ctx->OCTAL_INT()->getText(); + int value = std::stoi(oct, nullptr, 8); + return static_cast(builder_.CreateConstInt(value)); + } + + if (ctx->ZERO()) { + return static_cast(builder_.CreateConstInt(0)); + } + + // 处理变量 + if (ctx->lVal()) { + return ctx->lVal()->accept(this); + } + + // 处理括号表达式 + if (ctx->L_PAREN() && ctx->exp()) { + return EvalExpr(*ctx->exp()); + } + + throw std::runtime_error(FormatError("irgen", "不支持的基本表达式类型")); +} + +// 左值(变量)处理 +// 1. 先通过语义分析结果把变量使用绑定回声明; +// 2. 再通过 storage_map_ 找到该声明对应的栈槽位; +// 3. 最后生成 load,把内存中的值读出来。 +std::any IRGenImpl::visitLVal(SysYParser::LValContext* ctx) { + if (!ctx || !ctx->Ident()) { + throw std::runtime_error(FormatError("irgen", "非法左值")); + } + + std::string varName = ctx->Ident()->getText(); + + // 从语义分析获取变量定义 + auto* decl = sema_.ResolveVarUse(ctx); + if (!decl) { + throw std::runtime_error( + FormatError("irgen", + "变量使用缺少语义绑定: " + varName)); + } + + auto it = storage_map_.find(decl); + if (it == storage_map_.end()) { + throw std::runtime_error( + FormatError("irgen", + "变量声明缺少存储槽位: " + varName)); + } + + return static_cast( + builder_.CreateLoad(it->second, module_.GetContext().NextTemp())); +} + + +// 加法表达式 +std::any IRGenImpl::visitAddExp(SysYParser::AddExpContext* ctx) { + if (!ctx) { + throw std::runtime_error(FormatError("irgen", "非法加法表达式")); + } + + // 注意:mulExp() 返回的是 MulExpContext*,不是 vector + // 需要递归处理 AddExp 的左结合性 + // AddExp : MulExp | AddExp ('+' | '-') MulExp + + // 先处理左操作数 + ir::Value* result = nullptr; + + // 如果有左子节点(AddExp),递归处理 + if (ctx->addExp()) { + result = std::any_cast(ctx->addExp()->accept(this)); + } else { + // 否则是 MulExp + result = std::any_cast(ctx->mulExp()->accept(this)); + } + + // 如果有运算符和右操作数 + if (ctx->AddOp() || ctx->SubOp()) { + ir::Value* rhs = std::any_cast(ctx->mulExp()->accept(this)); + + if (ctx->AddOp()) { + result = builder_.CreateAdd(result, rhs, module_.GetContext().NextTemp()); + } else if (ctx->SubOp()) { + // 减法:a - b = a + (-b) + // 暂时用加法,后续需要实现真正的减法 + result = builder_.CreateAdd(result, rhs, module_.GetContext().NextTemp()); + } + } + + return static_cast(result); +} + +// 在 IRGenExp.cpp 中添加 + +// 简化版 visitMulExp +std::any IRGenImpl::visitMulExp(SysYParser::MulExpContext* ctx) { + if (!ctx) { + throw std::runtime_error(FormatError("irgen", "非法乘法表达式")); + } + + // 暂时只返回 unaryExp 的值 + if (ctx->unaryExp()) { + return ctx->unaryExp()->accept(this); + } + + // 如果有 mulExp 子节点,递归处理 + if (ctx->mulExp()) { + return ctx->mulExp()->accept(this); + } + + throw std::runtime_error(FormatError("irgen", "乘法表达式暂未实现")); +} + +// 关系表达式(暂未完整实现) +std::any IRGenImpl::visitRelExp(SysYParser::RelExpContext* ctx) { + if (!ctx) { + throw std::runtime_error(FormatError("irgen", "非法关系表达式")); + } + + // 简化:返回 addExp 的值 + if (ctx->addExp()) { + return ctx->addExp()->accept(this); + } + + throw std::runtime_error(FormatError("irgen", "关系表达式暂未实现")); +} + +// 相等表达式(暂未完整实现) +std::any IRGenImpl::visitEqExp(SysYParser::EqExpContext* ctx) { + if (!ctx) { + throw std::runtime_error(FormatError("irgen", "非法相等表达式")); + } + + // 简化:返回 relExp 的值 + if (ctx->relExp()) { + return ctx->relExp()->accept(this); + } + + throw std::runtime_error(FormatError("irgen", "相等表达式暂未实现")); +} + +// 条件表达式 +std::any IRGenImpl::visitCond(SysYParser::CondContext* ctx) { + if (!ctx) { + throw std::runtime_error(FormatError("irgen", "非法条件表达式")); + } + + // 简化:返回 lOrExp 的值 + if (ctx->lOrExp()) { + return ctx->lOrExp()->accept(this); + } + + throw std::runtime_error(FormatError("irgen", "条件表达式暂未实现")); +} diff --git a/src/irgen/IRGenFunc.cpp b/src/irgen/IRGenFunc.cpp new file mode 100644 index 0000000..87f3ac8 --- /dev/null +++ b/src/irgen/IRGenFunc.cpp @@ -0,0 +1,132 @@ +#include "irgen/IRGen.h" + +#include +#include +#include + +#include "SysYParser.h" +#include "ir/IR.h" +#include "utils/Log.h" + +namespace { + +void VerifyFunctionStructure(const ir::Function& func) { + for (const auto& bb : func.GetBlocks()) { + if (!bb || !bb->HasTerminator()) { + throw std::runtime_error( + FormatError("irgen", "基本块未正确终结: " + + (bb ? bb->GetName() : std::string("")))); + } + } +} + +} // namespace + +IRGenImpl::IRGenImpl(ir::Module& module, const SemanticContext& sema) + : module_(module), + sema_(sema), + func_(nullptr), + builder_(module.GetContext(), nullptr) {} + +// 修正:没有 mainFuncDef,通过函数名找到 main +std::any IRGenImpl::visitCompUnit(SysYParser::CompUnitContext* ctx) { + if (!ctx) { + throw std::runtime_error(FormatError("irgen", "缺少编译单元")); + } + + // 获取所有函数定义 + auto funcDefs = ctx->funcDef(); + + // 找到 main 函数 + SysYParser::FuncDefContext* mainFunc = nullptr; + for (auto* funcDef : funcDefs) { + if (funcDef->Ident() && funcDef->Ident()->getText() == "main") { + mainFunc = funcDef; + break; + } + } + + if (!mainFunc) { + throw std::runtime_error(FormatError("irgen", "缺少main函数")); + } + + // 生成 main 函数 + mainFunc->accept(this); + + return {}; +} + +std::any IRGenImpl::visitFuncDef(SysYParser::FuncDefContext* ctx) { + if (!ctx) { + throw std::runtime_error(FormatError("irgen", "缺少函数定义")); + } + + // 使用 Ident() 而不是 ID() + if (!ctx->Ident()) { + throw std::runtime_error(FormatError("irgen", "缺少函数名")); + } + + std::string funcName = ctx->Ident()->getText(); + + // 检查函数体 - 使用 block() 而不是 blockStmt() + if (!ctx->block()) { + throw std::runtime_error(FormatError("irgen", "函数体为空")); + } + + // 检查返回类型 - 使用 Int() 而不是 INT() + if (!ctx->funcType() || !ctx->funcType()->Int()) { + throw std::runtime_error(FormatError("irgen", "当前仅支持int函数")); + } + + // 创建函数 + func_ = module_.CreateFunction(funcName, ir::Type::GetInt32Type()); + builder_.SetInsertPoint(func_->GetEntry()); + storage_map_.clear(); + + // 生成函数体 - 使用 block() 而不是 blockStmt() + ctx->block()->accept(this); + + // 确保函数有返回值 + if (!func_->GetEntry()->HasTerminator()) { + auto retVal = builder_.CreateConstInt(0); + builder_.CreateRet(retVal); + } + + VerifyFunctionStructure(*func_); + return {}; +} + +std::any IRGenImpl::visitBlock(SysYParser::BlockContext* ctx) { + if (!ctx) { + throw std::runtime_error(FormatError("irgen", "缺少语句块")); + } + + for (auto* item : ctx->blockItem()) { + if (item) { + if (VisitBlockItemResult(*item) == BlockFlow::Terminated) { + break; + } + } + } + + return {}; +} + +IRGenImpl::BlockFlow IRGenImpl::VisitBlockItemResult( + SysYParser::BlockItemContext& item) { + return std::any_cast(item.accept(this)); +} + +std::any IRGenImpl::visitBlockItem(SysYParser::BlockItemContext* ctx) { + if (!ctx) { + throw std::runtime_error(FormatError("irgen", "缺少块内项")); + } + if (ctx->stmt()) { + return ctx->stmt()->accept(this); + } + if (ctx->decl()) { + ctx->decl()->accept(this); + return BlockFlow::Continue; + } + throw std::runtime_error(FormatError("irgen", "暂不支持的块内项")); +} diff --git a/src/irgen/IRGenStmt.cpp b/src/irgen/IRGenStmt.cpp new file mode 100644 index 0000000..fef78ea --- /dev/null +++ b/src/irgen/IRGenStmt.cpp @@ -0,0 +1,88 @@ +#include "irgen/IRGen.h" + +#include + +#include "SysYParser.h" +#include "ir/IR.h" +#include "utils/Log.h" + +// 语句生成当前只实现了最小子集。 +// 目前支持: +// - return ; +// +// 还未支持: +// - 赋值语句 +// - if / while 等控制流 +// - 空语句、块语句嵌套分发之外的更多语句形态 + +std::any IRGenImpl::visitStmt(SysYParser::StmtContext* ctx) { + if (!ctx) { + throw std::runtime_error(FormatError("irgen", "缺少语句")); + } + + // return 语句 - 通过 Return() 关键字判断 + if (ctx->Return()) { + return HandleReturnStmt(ctx); + } + + // 块语句 + if (ctx->block()) { + return ctx->block()->accept(this); + } + + // 空语句或表达式语句(先计算表达式) + if (ctx->exp()) { + EvalExpr(*ctx->exp()); + return BlockFlow::Continue; + } + + throw std::runtime_error(FormatError("irgen", "暂不支持的语句类型")); +} + +IRGenImpl::BlockFlow IRGenImpl::HandleReturnStmt(SysYParser::StmtContext* ctx) { + if (!ctx) { + throw std::runtime_error(FormatError("irgen", "缺少 return 语句")); + } + + ir::Value* retValue = nullptr; + if (ctx->exp()) { + retValue = EvalExpr(*ctx->exp()); + } + // 如果没有表达式,返回0(对于int main) + if (!retValue) { + retValue = builder_.CreateConstInt(0); + } + + builder_.CreateRet(retValue); + return BlockFlow::Terminated; +} + +// if语句(待实现) +IRGenImpl::BlockFlow IRGenImpl::HandleIfStmt(SysYParser::StmtContext* ctx) { + // TODO: 实现if语句 + throw std::runtime_error(FormatError("irgen", "if语句暂未实现")); +} + +// while语句(待实现) +IRGenImpl::BlockFlow IRGenImpl::HandleWhileStmt(SysYParser::StmtContext* ctx) { + // TODO: 实现while语句 + throw std::runtime_error(FormatError("irgen", "while语句暂未实现")); +} + +// break语句(待实现) +IRGenImpl::BlockFlow IRGenImpl::HandleBreakStmt(SysYParser::StmtContext* ctx) { + // TODO: 实现break + throw std::runtime_error(FormatError("irgen", "break语句暂未实现")); +} + +// continue语句(待实现) +IRGenImpl::BlockFlow IRGenImpl::HandleContinueStmt(SysYParser::StmtContext* ctx) { + // TODO: 实现continue + throw std::runtime_error(FormatError("irgen", "continue语句暂未实现")); +} + +// 赋值语句(待实现) +IRGenImpl::BlockFlow IRGenImpl::HandleAssignStmt(SysYParser::StmtContext* ctx) { + // TODO: 实现赋值 + throw std::runtime_error(FormatError("irgen", "赋值语句暂未实现")); +} diff --git a/src/main.cpp b/src/main.cpp index fc40f04..88ed747 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -6,7 +6,7 @@ #include "frontend/SyntaxTreePrinter.h" #if !COMPILER_PARSE_ONLY #include "ir/IR.h" -//#include "irgen/IRGen.h" +#include "irgen/IRGen.h" #include "mir/MIR.h" #include "sem/Sema.h" #endif @@ -35,7 +35,7 @@ int main(int argc, char** argv) { } auto sema = RunSema(*comp_unit); - /*auto module = GenerateIR(*comp_unit, sema); + auto module = GenerateIR(*comp_unit, sema); if (opts.emit_ir) { ir::IRPrinter printer; if (need_blank_line) { @@ -53,7 +53,7 @@ int main(int argc, char** argv) { std::cout << "\n"; } mir::PrintAsm(*machine_func, std::cout); - }*/ + } #else if (opts.emit_ir || opts.emit_asm) { throw std::runtime_error( diff --git a/src/sem/Sema.cpp b/src/sem/Sema.cpp index feb9e1d..1668616 100644 --- a/src/sem/Sema.cpp +++ b/src/sem/Sema.cpp @@ -398,7 +398,122 @@ public: // 左值表达式(变量引用) std::any visitLVal(SysYParser::LValContext* ctx) override { - ExprInfo result = CheckLValue(ctx); + std::cout << "[DEBUG] visitLVal: " << ctx->getText() << std::endl; + if (!ctx || !ctx->Ident()) { + throw std::runtime_error(FormatError("sema", "非法变量引用")); + } + std::string name = ctx->Ident()->getText(); + auto* sym = table_.lookup(name); + if (!sym) { + throw std::runtime_error(FormatError("sema", "使用了未定义的变量: " + name)); + } + // ========== 关键修复:绑定变量使用到定义 ========== + if (sym) { + std::cerr << "[DEBUG] 找到符号: " << sym->name + << ", kind: " << (int)sym->kind + << ", var_def_ctx: " << sym->var_def_ctx << std::endl; + if (sym->var_def_ctx) { + std::cout << "[DEBUG] 绑定变量使用" << std::endl; + sema_.BindVarUse(ctx, sym->var_def_ctx); + } + } + else if (sym->kind == SymbolKind::Parameter) { + // 对于函数参数,需要特殊处理 + // 参数可能没有对应的 VarDefContext,需要创建一个 + // 或者通过其他方式标识 + std::cout << "[DEBUG] 参数变量: " << name << " (无法绑定到 VarDefContext)" << std::endl; + // 可以创建一个临时标识,但这里先不处理 + } + // ============================================ + // 检查数组访问 + bool is_array_access = !ctx->exp().empty(); + std::cout << "[DEBUG] name: " << name + << ", is_array_access: " << is_array_access + << ", subscript_count: " << ctx->exp().size() << std::endl; + ExprInfo result; + // 判断是否为数组类型或指针类型(数组参数) + bool is_array_or_ptr = false; + if (sym->type) { + is_array_or_ptr = sym->type->IsArray() || sym->type->IsPtrInt32() || sym->type->IsPtrFloat(); + std::cout << "[DEBUG] type_kind: " << (int)sym->type->GetKind() + << ", is_array: " << sym->type->IsArray() + << ", is_ptr: " << (sym->type->IsPtrInt32() || sym->type->IsPtrFloat()) << std::endl; + } + + if (is_array_or_ptr) { + // 获取维度信息 + size_t dim_count = 0; + std::shared_ptr elem_type = sym->type; + if (sym->type->IsArray()) { + if (auto* arr_type = dynamic_cast(sym->type.get())) { + dim_count = arr_type->GetDimensions().size(); + elem_type = arr_type->GetElementType(); + std::cout << "[DEBUG] 数组维度: " << dim_count << std::endl; + } + } else if (sym->type->IsPtrInt32() || sym->type->IsPtrFloat()) { + dim_count = 1; + if (sym->type->IsPtrInt32()) { + elem_type = ir::Type::GetInt32Type(); + } else if (sym->type->IsPtrFloat()) { + elem_type = ir::Type::GetFloatType(); + } + std::cout << "[DEBUG] 指针类型, dim_count: 1" << std::endl; + } + + if (is_array_access) { + std::cout << "[DEBUG] 有下标访问,期望维度: " << dim_count + << ", 实际下标数: " << ctx->exp().size() << std::endl; + if (ctx->exp().size() != dim_count) { + throw std::runtime_error(FormatError("sema", "数组下标个数不匹配")); + } + for (auto* idx_exp : ctx->exp()) { + ExprInfo idx = CheckExp(idx_exp); + if (!idx.type->IsInt32()) { + throw std::runtime_error(FormatError("sema", "数组下标必须是 int 类型")); + } + } + result.type = elem_type; + result.is_lvalue = true; + result.is_const = false; + } else { + std::cout << "[DEBUG] 无下标访问" << std::endl; + if (sym->type->IsArray()) { + std::cout << "[DEBUG] 数组名作为地址,转换为指针" << std::endl; + if (auto* arr_type = dynamic_cast(sym->type.get())) { + if (arr_type->GetElementType()->IsInt32()) { + result.type = ir::Type::GetPtrInt32Type(); + } else if (arr_type->GetElementType()->IsFloat()) { + result.type = ir::Type::GetPtrFloatType(); + } else { + result.type = ir::Type::GetPtrInt32Type(); + } + } else { + result.type = ir::Type::GetPtrInt32Type(); + } + result.is_lvalue = false; + result.is_const = true; + } else { + result.type = sym->type; + result.is_lvalue = true; + result.is_const = (sym->kind == SymbolKind::Constant); + } + } + } else { + if (is_array_access) { + throw std::runtime_error(FormatError("sema", "非数组变量不能使用下标: " + name)); + } + result.type = sym->type; + result.is_lvalue = true; + result.is_const = (sym->kind == SymbolKind::Constant); + if (result.is_const && sym->type && !sym->type->IsArray()) { + if (sym->is_int_const) { + result.is_const_int = true; + result.const_int_value = sym->const_value.i32; + } else { + result.const_float_value = sym->const_value.f32; + } + } + } sema_.SetExprType(ctx, result); return {}; } @@ -956,33 +1071,30 @@ private: if (!sym) { throw std::runtime_error(FormatError("sema", "未定义的变量: " + name)); } + // ========== 添加绑定 ========== + if (sym->var_def_ctx) { + std::cout << "[DEBUG] CheckLValue 绑定变量: " << name << std::endl; + sema_.BindVarUse(ctx, sym->var_def_ctx); + } + // ============================ bool is_array_access = !ctx->exp().empty(); bool is_const = (sym->kind == SymbolKind::Constant); + bool is_array_or_ptr = false; + + if (sym->type) { + is_array_or_ptr = sym->type->IsArray() || sym->type->IsPtrInt32() || sym->type->IsPtrFloat(); + } size_t dim_count = 0; std::shared_ptr elem_type = sym->type; - std::vector dims; - // 获取维度信息 if (sym->type && sym->type->IsArray()) { if (auto* arr_type = dynamic_cast(sym->type.get())) { - dims = arr_type->GetDimensions(); - dim_count = dims.size(); + dim_count = arr_type->GetDimensions().size(); elem_type = arr_type->GetElementType(); } - } else if (sym->is_array_param) { - // 数组参数,使用保存的维度信息 - dims = sym->array_dims; - dim_count = dims.size(); - // 元素类型是基本类型 - if (sym->type->IsPtrInt32()) { - elem_type = ir::Type::GetInt32Type(); - } else if (sym->type->IsPtrFloat()) { - elem_type = ir::Type::GetFloatType(); - } } else if (sym->type && (sym->type->IsPtrInt32() || sym->type->IsPtrFloat())) { - // 普通指针,只能有一个下标 dim_count = 1; if (sym->type->IsPtrInt32()) { elem_type = ir::Type::GetInt32Type(); @@ -1408,4 +1520,4 @@ SemanticContext RunSema(SysYParser::CompUnitContext& comp_unit) { SemaVisitor visitor; comp_unit.accept(&visitor); return visitor.TakeSemanticContext(); -} \ No newline at end of file +}