From 7eed5fe6f6efaaa488402f58cb10c48b6d2803db Mon Sep 17 00:00:00 2001 From: ftt <> Date: Wed, 25 Mar 2026 21:07:32 +0800 Subject: [PATCH] =?UTF-8?q?[sema]=20=E6=95=B0=E7=BB=84=E4=B8=8B=E6=A0=87?= =?UTF-8?q?=E4=B8=AA=E6=95=B0=E4=B8=8D=E5=8C=B9=E9=85=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/sem/Sema.cpp | 262 +++++++++++++++++++++++++++++++--------- src/sem/SymbolTable.cpp | 25 ++++ 2 files changed, 229 insertions(+), 58 deletions(-) diff --git a/src/sem/Sema.cpp b/src/sem/Sema.cpp index 68f9b0d..a76437b 100644 --- a/src/sem/Sema.cpp +++ b/src/sem/Sema.cpp @@ -400,6 +400,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", "非法变量引用")); } @@ -410,54 +411,77 @@ public: } // 检查数组访问 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; } - // 调试输出 - std::cout << "[DEBUG] visitLVal: " << name - << " kind: " << (int)sym->kind - << " type_kind: " << (sym->type ? (int)sym->type->GetKind() : -1) - << " is_array_or_ptr: " << is_array_or_ptr - << " subscript_count: " << ctx->exp().size() - << std::endl; + if (is_array_or_ptr) { - if (!is_array_access) { - throw std::runtime_error(FormatError("sema", "数组变量必须使用下标访问: " + name)); - } // 获取维度信息 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 (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 类型")); + + 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); } } - result.type = elem_type; - result.is_lvalue = true; - result.is_const = false; } else { if (is_array_access) { throw std::runtime_error(FormatError("sema", "非数组变量不能使用下标: " + name)); @@ -482,10 +506,8 @@ public: std::any visitIfStmtInternal(SysYParser::StmtContext* ctx) { // 检查条件表达式 if (ctx->cond()) { - ExprInfo cond = CheckCond(ctx->cond()); - if (!cond.type || !cond.type->IsInt32()) { - throw std::runtime_error(FormatError("sema", "if 条件必须是 int 类型")); - } + ExprInfo cond = CheckCond(ctx->cond()); // CheckCond 已经处理了类型转换 + // 不需要额外检查,因为 CheckCond 已经确保类型正确 } // 处理 then 分支 if (ctx->stmt().size() > 0) { @@ -500,17 +522,15 @@ public: // while 语句内部实现 std::any visitWhileStmtInternal(SysYParser::StmtContext* ctx) { - if (ctx->cond()) { // 检查条件表达式 - ExprInfo cond = CheckCond(ctx->cond()); - if (!cond.type || !cond.type->IsInt32()) { - throw std::runtime_error(FormatError("sema", "while 条件必须是 int 类型")); - } + if (ctx->cond()) { + ExprInfo cond = CheckCond(ctx->cond()); // CheckCond 已经处理了类型转换 + // 不需要额外检查 } - loop_stack_.push_back({true, ctx}); // 进入循环上下文 - if (ctx->stmt().size() > 0) { // 处理循环体 + loop_stack_.push_back({true, ctx}); + if (ctx->stmt().size() > 0) { ctx->stmt()[0]->accept(this); } - loop_stack_.pop_back(); // 退出循环上下文 + loop_stack_.pop_back(); return {}; } @@ -564,6 +584,7 @@ public: // 主表达式 std::any visitPrimaryExp(SysYParser::PrimaryExpContext* ctx) override { + std::cout << "[DEBUG] visitPrimaryExp: " << ctx->getText() << std::endl; ExprInfo result; if (ctx->lVal()) { // 左值表达式 result = CheckLValue(ctx->lVal()); @@ -595,12 +616,14 @@ public: // 一元表达式 std::any visitUnaryExp(SysYParser::UnaryExpContext* ctx) override { + std::cout << "[DEBUG] visitUnaryExp: " << ctx->getText() << std::endl; ExprInfo result; if (ctx->primaryExp()) { ctx->primaryExp()->accept(this); auto* info = sema_.GetExprType(ctx->primaryExp()); if (info) result = *info; } else if (ctx->Ident() && ctx->L_PAREN()) { // 函数调用 + std::cout << "[DEBUG] 函数调用: " << ctx->Ident()->getText() << std::endl; result = CheckFuncCall(ctx); } else if (ctx->unaryOp()) { // 一元运算 ctx->unaryExp()->accept(this); @@ -611,20 +634,37 @@ public: } else { std::string op = ctx->unaryOp()->getText(); if (op == "!") { - if (!operand->type->IsInt32()) { - throw std::runtime_error(FormatError("sema", "逻辑非操作数必须是 int 类型")); + // 逻辑非:要求操作数是 int 类型,或者可以转换为 int 的 float + if (operand->type->IsInt32()) { + // 已经是 int,没问题 + } else if (operand->type->IsFloat()) { + // float 可以隐式转换为 int + sema_.AddConversion(ctx->unaryExp(), operand->type, ir::Type::GetInt32Type()); + // 更新操作数类型为 int + operand->type = ir::Type::GetInt32Type(); + operand->is_const_int = true; + if (operand->is_const && !operand->is_const_int) { + // 如果原来是 float 常量,转换为 int 常量 + operand->const_int_value = (int)operand->const_float_value; + operand->is_const_int = true; + } + } else { + throw std::runtime_error(FormatError("sema", "逻辑非操作数必须是 int 类型或可以转换为 int 的 float 类型")); } result.type = ir::Type::GetInt32Type(); + result.is_lvalue = false; result.is_const = operand->is_const; if (operand->is_const && operand->is_const_int) { result.is_const_int = true; result.const_int_value = (operand->const_int_value == 0) ? 1 : 0; } } else { + // 正负号 if (!operand->type->IsInt32() && !operand->type->IsFloat()) { throw std::runtime_error(FormatError("sema", "正负号操作数必须是算术类型")); } result.type = operand->type; + result.is_lvalue = false; result.is_const = operand->is_const; if (op == "-" && operand->is_const) { if (operand->type->IsInt32() && operand->is_const_int) { @@ -635,7 +675,6 @@ public: } } } - result.is_lvalue = false; } } sema_.SetExprType(ctx, result); @@ -808,12 +847,36 @@ public: if (!left_info || !right_info) { throw std::runtime_error(FormatError("sema", "逻辑与操作数类型推导失败")); } else { - if (!left_info->type->IsInt32()) { - throw std::runtime_error(FormatError("sema", "逻辑与左操作数必须是 int 类型")); + // 处理左操作数 + if (left_info->type->IsInt32()) { + // 已经是 int,没问题 + } else if (left_info->type->IsFloat()) { + // float 可以隐式转换为 int + sema_.AddConversion(ctx->lAndExp(), left_info->type, ir::Type::GetInt32Type()); + left_info->type = ir::Type::GetInt32Type(); + if (left_info->is_const && !left_info->is_const_int) { + left_info->const_int_value = (int)left_info->const_float_value; + left_info->is_const_int = true; + } + } else { + throw std::runtime_error(FormatError("sema", "逻辑与左操作数必须是 int 类型或可以转换为 int 的 float 类型")); } - if (!right_info->type->IsInt32()) { - throw std::runtime_error(FormatError("sema", "逻辑与右操作数必须是 int 类型")); + + // 处理右操作数 + if (right_info->type->IsInt32()) { + // 已经是 int,没问题 + } else if (right_info->type->IsFloat()) { + // float 可以隐式转换为 int + sema_.AddConversion(ctx->eqExp(), right_info->type, ir::Type::GetInt32Type()); + right_info->type = ir::Type::GetInt32Type(); + if (right_info->is_const && !right_info->is_const_int) { + right_info->const_int_value = (int)right_info->const_float_value; + right_info->is_const_int = true; + } + } else { + throw std::runtime_error(FormatError("sema", "逻辑与右操作数必须是 int 类型或可以转换为 int 的 float 类型")); } + result.type = ir::Type::GetInt32Type(); result.is_lvalue = false; if (left_info->is_const && right_info->is_const && @@ -828,6 +891,17 @@ public: ctx->eqExp()->accept(this); auto* info = sema_.GetExprType(ctx->eqExp()); if (info) { + // 对于单个操作数,也需要确保类型是 int(用于条件表达式) + if (info->type->IsFloat()) { + sema_.AddConversion(ctx->eqExp(), info->type, ir::Type::GetInt32Type()); + info->type = ir::Type::GetInt32Type(); + if (info->is_const && !info->is_const_int) { + info->const_int_value = (int)info->const_float_value; + info->is_const_int = true; + } + } else if (!info->type->IsInt32()) { + throw std::runtime_error(FormatError("sema", "逻辑与操作数必须是 int 类型或可以转换为 int 的 float 类型")); + } sema_.SetExprType(ctx, *info); } return {}; @@ -847,12 +921,36 @@ public: if (!left_info || !right_info) { throw std::runtime_error(FormatError("sema", "逻辑或操作数类型推导失败")); } else { - if (!left_info->type->IsInt32()) { - throw std::runtime_error(FormatError("sema", "逻辑或左操作数必须是 int 类型")); + // 处理左操作数 + if (left_info->type->IsInt32()) { + // 已经是 int,没问题 + } else if (left_info->type->IsFloat()) { + // float 可以隐式转换为 int + sema_.AddConversion(ctx->lOrExp(), left_info->type, ir::Type::GetInt32Type()); + left_info->type = ir::Type::GetInt32Type(); + if (left_info->is_const && !left_info->is_const_int) { + left_info->const_int_value = (int)left_info->const_float_value; + left_info->is_const_int = true; + } + } else { + throw std::runtime_error(FormatError("sema", "逻辑或左操作数必须是 int 类型或可以转换为 int 的 float 类型")); } - if (!right_info->type->IsInt32()) { - throw std::runtime_error(FormatError("sema", "逻辑或右操作数必须是 int 类型")); + + // 处理右操作数 + if (right_info->type->IsInt32()) { + // 已经是 int,没问题 + } else if (right_info->type->IsFloat()) { + // float 可以隐式转换为 int + sema_.AddConversion(ctx->lAndExp(), right_info->type, ir::Type::GetInt32Type()); + right_info->type = ir::Type::GetInt32Type(); + if (right_info->is_const && !right_info->is_const_int) { + right_info->const_int_value = (int)right_info->const_float_value; + right_info->is_const_int = true; + } + } else { + throw std::runtime_error(FormatError("sema", "逻辑或右操作数必须是 int 类型或可以转换为 int 的 float 类型")); } + result.type = ir::Type::GetInt32Type(); result.is_lvalue = false; if (left_info->is_const && right_info->is_const && @@ -867,6 +965,17 @@ public: ctx->lAndExp()->accept(this); auto* info = sema_.GetExprType(ctx->lAndExp()); if (info) { + // 对于单个操作数,也需要确保类型是 int(用于条件表达式) + if (info->type->IsFloat()) { + sema_.AddConversion(ctx->lAndExp(), info->type, ir::Type::GetInt32Type()); + info->type = ir::Type::GetInt32Type(); + if (info->is_const && !info->is_const_int) { + info->const_int_value = (int)info->const_float_value; + info->is_const_int = true; + } + } else if (!info->type->IsInt32()) { + throw std::runtime_error(FormatError("sema", "逻辑或操作数必须是 int 类型或可以转换为 int 的 float 类型")); + } sema_.SetExprType(ctx, *info); } return {}; @@ -895,6 +1004,7 @@ private: if (!ctx || !ctx->addExp()) { throw std::runtime_error(FormatError("sema", "无效表达式")); } + std::cout << "[DEBUG] CheckExp: " << ctx->getText() << std::endl; ctx->addExp()->accept(this); auto* info = sema_.GetExprType(ctx->addExp()); if (!info) { @@ -927,7 +1037,13 @@ private: if (!info) { throw std::runtime_error(FormatError("sema", "条件表达式类型推导失败")); } - return *info; + ExprInfo result = *info; + // 条件表达式的结果必须是 int,如果是 float 则需要转换 + // 注意:lOrExp 已经处理了类型转换,这里只是再检查一次 + if (!result.type->IsInt32()) { + throw std::runtime_error(FormatError("sema", "条件表达式必须是 int 类型")); + } + return result; } ExprInfo CheckLValue(SysYParser::LValContext* ctx) { @@ -939,15 +1055,18 @@ private: if (!sym) { throw std::runtime_error(FormatError("sema", "未定义的变量: " + name)); } + + 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(); + 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; + if (sym->type && sym->type->IsArray()) { if (auto* arr_type = dynamic_cast(sym->type.get())) { dim_count = arr_type->GetDimensions().size(); @@ -961,18 +1080,39 @@ private: elem_type = ir::Type::GetFloatType(); } } + size_t subscript_count = ctx->exp().size(); + if (is_array_or_ptr) { - if (subscript_count != 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 类型")); + if (subscript_count > 0) { + // 有下标访问 + if (subscript_count != 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 类型")); + } + } + return {elem_type, true, false}; + } else { + // 没有下标访问 + if (sym->type->IsArray()) { + // 数组名作为地址(右值) + if (auto* arr_type = dynamic_cast(sym->type.get())) { + if (arr_type->GetElementType()->IsInt32()) { + return {ir::Type::GetPtrInt32Type(), false, true}; + } else if (arr_type->GetElementType()->IsFloat()) { + return {ir::Type::GetPtrFloatType(), false, true}; + } + } + return {ir::Type::GetPtrInt32Type(), false, true}; + } else { + // 指针类型(如函数参数)可以不带下标使用 + return {sym->type, true, is_const}; } } - return {elem_type, true, false}; } else { if (subscript_count > 0) { throw std::runtime_error(FormatError("sema", "非数组变量不能使用下标: " + name)); @@ -986,12 +1126,14 @@ private: throw std::runtime_error(FormatError("sema", "非法函数调用")); } std::string func_name = ctx->Ident()->getText(); + std::cout << "[DEBUG] CheckFuncCall: " << func_name << std::endl; auto* func_sym = table_.lookup(func_name); if (!func_sym || func_sym->kind != SymbolKind::Function) { throw std::runtime_error(FormatError("sema", "未定义的函数: " + func_name)); } std::vector args; if (ctx->funcRParams()) { + std::cout << "[DEBUG] 处理函数调用参数:" << std::endl; for (auto* exp : ctx->funcRParams()->exp()) { if (exp) { args.push_back(CheckExp(exp)); @@ -1002,6 +1144,8 @@ private: throw std::runtime_error(FormatError("sema", "参数个数不匹配")); } for (size_t i = 0; i < std::min(args.size(), func_sym->param_types.size()); ++i) { + std::cout << "[DEBUG] 检查参数 " << i << ": 实参类型 " << (int)args[i].type->GetKind() + << " 形参类型 " << (int)func_sym->param_types[i]->GetKind() << std::endl; if (!IsTypeCompatible(args[i].type, func_sym->param_types[i])) { throw std::runtime_error(FormatError("sema", "参数类型不匹配")); } @@ -1162,6 +1306,7 @@ private: } else if (param_type->IsFloat()) { param_type = ir::Type::GetPtrFloatType(); } + std::cout << "[DEBUG] 数组参数: " << name << " 类型转换为指针" << std::endl; } Symbol sym; sym.name = name; @@ -1171,6 +1316,7 @@ private: sym.is_initialized = true; sym.var_def_ctx = nullptr; table_.addSymbol(sym); + std::cout << "[DEBUG] 添加参数: " << name << " type_kind: " << (int)param_type->GetKind() << std::endl; } } diff --git a/src/sem/SymbolTable.cpp b/src/sem/SymbolTable.cpp index 280fc8c..0f37e73 100644 --- a/src/sem/SymbolTable.cpp +++ b/src/sem/SymbolTable.cpp @@ -310,4 +310,29 @@ void SymbolTable::registerBuiltinFunctions() { stoptime.scope_level = 0; stoptime.is_builtin = true; addSymbol(stoptime); + + // getfarray: int getfarray(float arr[]) + std::vector> getfarray_params = { ir::Type::GetPtrFloatType() }; + Symbol getfarray; + getfarray.name = "getfarray"; + getfarray.kind = SymbolKind::Function; + getfarray.type = ir::Type::GetFunctionType(ir::Type::GetInt32Type(), getfarray_params); + getfarray.param_types = getfarray_params; + getfarray.scope_level = 0; + getfarray.is_builtin = true; + addSymbol(getfarray); + + // putfarray: void putfarray(int len, float arr[]) + std::vector> putfarray_params = { + ir::Type::GetInt32Type(), + ir::Type::GetPtrFloatType() + }; + Symbol putfarray; + putfarray.name = "putfarray"; + putfarray.kind = SymbolKind::Function; + putfarray.type = ir::Type::GetFunctionType(ir::Type::GetVoidType(), putfarray_params); + putfarray.param_types = putfarray_params; + putfarray.scope_level = 0; + putfarray.is_builtin = true; + addSymbol(putfarray); } \ No newline at end of file