From e0c8898dae3bddeda04f125150011a3ef37e23db Mon Sep 17 00:00:00 2001 From: ftt <> Date: Thu, 26 Mar 2026 08:23:21 +0800 Subject: [PATCH] =?UTF-8?q?=E7=BB=A7=E7=BB=AD=E4=BF=AE=E6=94=B9=E6=95=B0?= =?UTF-8?q?=E7=BB=84=E4=B8=8B=E6=A0=87=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/sem/SymbolTable.h | 4 + src/sem/Sema.cpp | 222 +++++++++++++++++++------------------- 2 files changed, 113 insertions(+), 113 deletions(-) diff --git a/include/sem/SymbolTable.h b/include/sem/SymbolTable.h index c546960..a541739 100644 --- a/include/sem/SymbolTable.h +++ b/include/sem/SymbolTable.h @@ -27,6 +27,10 @@ struct Symbol { bool is_initialized = false; // 是否已初始化 bool is_builtin = false; // 是否为库函数 + // 对于数组参数,存储维度信息 + std::vector array_dims; // 数组各维长度(参数数组的第一维可能为0表示省略) + bool is_array_param = false; // 是否是数组参数 + // 对于函数,额外存储参数列表(类型已包含在函数类型中,这里仅用于快速访问) std::vector> param_types; diff --git a/src/sem/Sema.cpp b/src/sem/Sema.cpp index 861caf3..feb9e1d 100644 --- a/src/sem/Sema.cpp +++ b/src/sem/Sema.cpp @@ -398,104 +398,7 @@ public: // 左值表达式(变量引用) std::any visitLVal(SysYParser::LValContext* ctx) override { - 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)); - } - // 检查数组访问 - 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; - } - } - } + ExprInfo result = CheckLValue(ctx); sema_.SetExprType(ctx, result); return {}; } @@ -1056,21 +959,30 @@ private: 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())) { - dim_count = arr_type->GetDimensions().size(); + dims = arr_type->GetDimensions(); + dim_count = dims.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(); @@ -1081,23 +993,53 @@ private: size_t subscript_count = ctx->exp().size(); - if (is_array_or_ptr) { + if (dim_count > 0 || sym->is_array_param || sym->type->IsArray() || + sym->type->IsPtrInt32() || sym->type->IsPtrFloat()) { if (subscript_count > 0) { // 有下标访问 - if (subscript_count != dim_count) { - throw std::runtime_error(FormatError("sema", "数组下标个数不匹配")); + if (subscript_count > dim_count && dim_count > 0) { + 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 类型")); } } - return {elem_type, true, false}; + + if (subscript_count == dim_count) { + // 完全索引,返回元素类型 + return {elem_type, true, false}; + } else { + // 部分索引,返回子数组的指针类型 + // 计算剩余维度的元素类型 + std::shared_ptr remaining_type = sym->type; + if (sym->is_array_param) { + // 对于数组参数,我们需要返回指向剩余维度的指针 + if (elem_type->IsInt32()) { + return {ir::Type::GetPtrInt32Type(), false, false}; + } else if (elem_type->IsFloat()) { + return {ir::Type::GetPtrFloatType(), false, false}; + } + } else { + for (size_t i = 0; i < subscript_count && remaining_type->IsArray(); i++) { + if (auto* arr_type = dynamic_cast(remaining_type.get())) { + remaining_type = arr_type->GetElementType(); + } + } + if (remaining_type->IsInt32()) { + return {ir::Type::GetPtrInt32Type(), false, false}; + } else if (remaining_type->IsFloat()) { + return {ir::Type::GetPtrFloatType(), false, false}; + } + } + return {ir::Type::GetPtrInt32Type(), false, false}; + } } else { // 没有下标访问 - if (sym->type->IsArray()) { - // 数组名作为地址(右值) + if (sym->type && sym->type->IsArray()) { + // 数组名作为地址 if (auto* arr_type = dynamic_cast(sym->type.get())) { if (arr_type->GetElementType()->IsInt32()) { return {ir::Type::GetPtrInt32Type(), false, true}; @@ -1106,8 +1048,15 @@ private: } } return {ir::Type::GetPtrInt32Type(), false, true}; + } else if (sym->is_array_param) { + // 数组参数名作为地址 + if (sym->type->IsPtrInt32()) { + return {ir::Type::GetPtrInt32Type(), false, true}; + } else { + return {ir::Type::GetPtrFloatType(), false, true}; + } } else { - // 指针类型(如函数参数)可以不带下标使用 + // 普通变量或指针 return {sym->type, true, is_const}; } } @@ -1280,6 +1229,20 @@ private: table_.addSymbol(sym); } + // 在 SemaVisitor 类中添加 + int EvaluateConstantAddExp(SysYParser::AddExpContext* ctx) { + if (!ctx) return 0; + // 使用常量求值器 + // 这里需要访问 ConstEvaluator,但 SemaVisitor 可能没有直接访问 + // 我们可以直接使用 CheckAddExp 并检查常量 + ExprInfo info = CheckAddExp(ctx); + if (info.is_const && info.is_const_int) { + return info.const_int_value; + } + throw std::runtime_error(FormatError("sema", "常量表达式求值失败")); + return 0; + } + void CollectFunctionParams(SysYParser::FuncFParamsContext* ctx) { if (!ctx) return; for (auto* param : ctx->funcFParam()) { @@ -1297,15 +1260,42 @@ private: } } if (!param_type) param_type = ir::Type::GetInt32Type(); + bool is_array = !param->L_BRACK().empty(); + std::vector dims; + if (is_array) { + // 第一维是 [],没有表达式,所以维度为0(表示省略) + dims.push_back(0); + + // 后续维度有表达式 + // 注意:exp() 返回的是 ExpContext 列表,对应后面的维度表达式 + for (auto* exp_ctx : param->exp()) { + // 使用常量求值器直接求值 + // 创建一个临时的 ConstExpContext + // 由于 ConstExpContext 只是 addExp 的包装,我们可以直接使用 addExp + auto* addExp = exp_ctx->addExp(); + if (!addExp) { + throw std::runtime_error(FormatError("sema", "无效的数组维度表达式")); + } + + // 求值常量表达式 + // 我们需要一个函数来求值常量表达式 + int dim = EvaluateConstantAddExp(addExp); + if (dim <= 0) { + throw std::runtime_error(FormatError("sema", "数组维度必须为正整数")); + } + dims.push_back(dim); + } + + // 数组参数退化为指针 if (param_type->IsInt32()) { param_type = ir::Type::GetPtrInt32Type(); } else if (param_type->IsFloat()) { param_type = ir::Type::GetPtrFloatType(); } - std::cout << "[DEBUG] 数组参数: " << name << " 类型转换为指针" << std::endl; } + Symbol sym; sym.name = name; sym.kind = SymbolKind::Parameter; @@ -1313,8 +1303,14 @@ private: sym.scope_level = table_.currentScopeLevel(); sym.is_initialized = true; sym.var_def_ctx = nullptr; + sym.is_array_param = is_array; + sym.array_dims = dims; table_.addSymbol(sym); - std::cout << "[DEBUG] 添加参数: " << name << " type_kind: " << (int)param_type->GetKind() << std::endl; + + std::cout << "[DEBUG] 添加参数: " << name << " type_kind: " << (int)param_type->GetKind() + << " is_array: " << is_array << " dims: "; + for (int d : dims) std::cout << d << " "; + std::cout << std::endl; } }