// semantic.cpp #include "semantic.h" #include "type.h" // 稍后实现 #include #include "ast.h" SemanticAnalyzer::SemanticAnalyzer() { // 1) 创建全局作用域 currentScope_ = std::make_shared(nullptr); rootScope_ = currentScope_; // 2) 预先注册标准库函数原型(extern)。以 printf 为例: { // 返回类型 int TypePtr ret = std::make_shared(TS_INT); // 第一个参数 const char* TypePtr p0 = std::make_shared( std::make_shared(TS_CHAR)); // 可变参数标记:最后一个 bool 为 true std::vector params = { p0 }; TypePtr printfTy = std::make_shared(ret, params, true); // 插入符号表:名字、类型、存储类别 extern、位置可随意填 (0,0) currentScope_->insert({ "printf", printfTy, SC_EXTERN, SourceLoc{0,0} }); } } void SemanticAnalyzer::analyze(ASTNode* root) { visit(root); } // 构造类型:给出 specifier 列表和 declarator 节点 // semantic.cpp static TypePtr buildType(ASTNode* spec_list, ASTNode* declarator) { // —— 1. 处理 spec_list —— // 缺省用 int TypeSpecifier ts = TS_INT; if (spec_list) { for (auto* spec : spec_list->kids) { if (spec && spec->tag == ASTTag::SPECIFIER) { ts = static_cast(spec->ival); break; } } } TypePtr ty = std::make_shared(ts); // —— 2. 递归处理 declarator,各种修饰 —— std::function applyDeclarator = [&](ASTNode* decl, TypePtr base) -> TypePtr { if (!decl) return base; switch (decl->tag) { case ASTTag::POINTER: { ASTNode* child = !decl->kids.empty() ? decl->kids[0] : nullptr; return std::make_shared(applyDeclarator(child, base)); } case ASTTag::ARRAY_DECL: { // kids: [ direct_decl, (tq_list?), (size_expr?) ] ASTNode* sizeNode = nullptr; if (decl->kids.size() >= 3 && decl->kids[2] && decl->kids[2]->tag == ASTTag::CONST) sizeNode = decl->kids[2]; int size = sizeNode ? static_cast(sizeNode->ival) : -1; // 先把 direct_decl(kids[0])处理上去 TypePtr elem = applyDeclarator(decl->kids.empty() ? nullptr : decl->kids[0], base); return std::make_shared(elem, size); } case ASTTag::FUNC_DECL: { // kids: [ direct_decl, (param_list?) ] std::vector params; if (decl->kids.size() == 2 && decl->kids[1]) { for (auto* p : decl->kids[1]->kids) { if (!p) continue; ASTNode* pspec = p->kids.empty() ? nullptr : p->kids[0]; ASTNode* pdtor = (p->kids.size()>1 ? p->kids[1] : nullptr); params.push_back(buildType(pspec, pdtor)); } } return std::make_shared(base, params, false); } case ASTTag::DECLARATOR: { // kids 可能是 0、1、2 三种 size_t k = decl->kids.size(); if (k == 0) { return base; } // 先处理最末级修饰 ASTNode* last = decl->kids.back(); TypePtr t = applyDeclarator(last, base); // 若有两个修饰(pointer + direct_decl),再处理 pointer if (k == 2 && decl->kids[0]) { t = applyDeclarator(decl->kids[0], t); } return t; } default: return base; } }; // —— 最终从 declarator(可能为空)开始递归 —— return applyDeclarator(declarator, ty); } void SemanticAnalyzer::visit(ASTNode* n) { if (!n) return; switch (n->tag) { case ASTTag::FUNCTION_DEF: visitFunctionDef(n); break; case ASTTag::COMPOUND_STMT: visitCompoundStmt(n); break; case ASTTag::DECLARATION: visitDeclaration(n); break; case ASTTag::INIT_DECL: visitInitDecl(n); break; case ASTTag::ID: visitIdentifier(n); break; case ASTTag::FOR_DECL_STMT: visitForDeclStmt(n); break; // <-- Add this case if missing default: // 递归遍历所有子节点 for (auto* c : n->kids) visit(c); } } void SemanticAnalyzer::visitForDeclStmt(ASTNode* n) { // n->kids = { decl, cond_expr_stmt, iter_expr?, body } // --- 1. 进入 for 循环的新作用域 --- currentScope_ = currentScope_->push(); bool scopePushed = true; // Assume push succeeds for now if (!currentScope_) { error(n->loc, "Semantic Error: Failed to push scope for FOR loop."); scopePushed = false; // Maybe try to visit children anyway to find other errors? Depends on desired robustness. } // --- 2. 访问初始化声明 (在新的作用域内) --- // decl is n->kids[0], which should be a DECLARATION node if (n->kids.size() > 0 && n->kids[0]) { visit(n->kids[0]); // This will eventually call visitDeclaration -> visitInitDecl for 'i' } // --- 3. 访问条件表达式 (在新的作用域内) --- // cond_expr_stmt is n->kids[1] if (n->kids.size() > 1 && n->kids[1]) { visit(n->kids[1]); // TODO: Add type checking, expect boolean result for condition } // --- 4. 访问迭代表达式 (在新的作用域内) --- // iter_expr is n->kids[2] (optional) if (n->kids.size() > 2 && n->kids[2]) { visit(n->kids[2]); } // --- 5. 访问循环体 (在新的作用域内) --- // body is n->kids[3] if (n->kids.size() > 3 && n->kids[3]) { visit(n->kids[3]); } // --- 6. 离开 for 循环作用域 --- if (scopePushed && currentScope_) { // Ensure scope was pushed and is still valid currentScope_ = currentScope_->pop(); } } // 在 semantic.cpp 中替换掉旧的 visitFunctionDef void SemanticAnalyzer::visitFunctionDef(ASTNode* n) { // kids: { spec_list, declarator, [decl_list], compound_stmt } ASTNode* spec_list = n->kids[0]; ASTNode* dtor = n->kids[1]; // 顶层 declarator 节点 ASTNode* body = (n->kids.size() > 3 && n->kids.back()->tag == ASTTag::COMPOUND_STMT) ? n->kids.back() // 通常是最后一个,但做个检查 : nullptr; if (!body && n->kids.size() > 2 && n->kids[2]->tag == ASTTag::COMPOUND_STMT) { body = n->kids[2]; // 兼容没有 decl_list 的情况 } // --- 1. 构建函数类型 --- // buildType 函数会递归处理 dtor 来构建包含参数和返回类型的完整 FunctionType TypePtr funcType = buildType(spec_list, dtor); // --- 2. 提取函数名 (使用与 IRGenerator 中相同的、基于 AST 的修正逻辑) --- std::string funcName = "unknown_function"; // 默认备用名 if (dtor && dtor->tag == ASTTag::DECLARATOR && !dtor->kids.empty()) { // 假设 FUNC_DECL 是顶层 DECLARATOR 的最后一个子节点 ASTNode* funcDeclNode = dtor->kids.back(); if (funcDeclNode && funcDeclNode->tag == ASTTag::FUNC_DECL && !funcDeclNode->kids.empty()) { // 假设包含名字的 DECLARATOR 是 FUNC_DECL 的第一个子节点 ASTNode* nameDeclaratorNode = funcDeclNode->kids[0]; // 检查这个节点是否是 DECLARATOR 并且 text 字段非空 if (nameDeclaratorNode && nameDeclaratorNode->tag == ASTTag::DECLARATOR && !nameDeclaratorNode->text.empty()) { funcName = nameDeclaratorNode->text; // 获取函数名 } } } if (funcName == "unknown_function") { error(dtor ? dtor->loc : n->loc, "Semantic Error: Could not extract function name from definition."); // 如果无法提取函数名,后续处理可能意义不大,可以考虑提前返回 // return; } // --- 3. 将函数符号插入到 *当前* 作用域 --- // 此时 currentScope_ 应该是全局作用域 SourceLoc nameLoc = dtor ? dtor->loc : n->loc; // 尽量使用 declarator 的位置 if (funcName != "unknown_function") { // 使用 SC_EXTERN 可能更符合全局函数的语义,但 SC_AUTO 也能工作 if (!currentScope_->insert({funcName, funcType, SC_EXTERN /* 或 SC_AUTO */, nameLoc})) { error(nameLoc, "Semantic Error: Function '" + funcName + "' redefined."); // 如果重定义,后续处理也意义不大 // return; } else { // 成功插入符号后,可选地将类型指针附加回 AST 节点(如果需要的话) // 例如:n->type = funcType.get(); // 附加到 FUNCTION_DEF 节点 // 或者 dtor->type = funcType.get(); // 附加到 declarator 节点 // 注意:这样做只是为了方便后续阶段访问,不管理内存 if(dtor) dtor->type = funcType.get(); // 尝试附加到 dtor } } // --- 4. 创建并切换到函数内部的新作用域,处理参数 --- currentScope_ = currentScope_->push(); // 进入函数作用域 // 从 FUNC_DECL 节点提取参数列表并添加到新作用域 if (funcName != "unknown_function" && funcType && // 确保函数名和类型有效 dtor && dtor->tag == ASTTag::DECLARATOR && !dtor->kids.empty()) { ASTNode* funcDeclNode = dtor->kids.back(); // FUNC_DECL // 检查是否有参数列表节点 (FUNC_DECL 的第二个子节点) if (funcDeclNode && funcDeclNode->tag == ASTTag::FUNC_DECL && funcDeclNode->kids.size() == 2) { ASTNode* paramListNode = funcDeclNode->kids[1]; // PARAM_LIST node if (paramListNode && paramListNode->tag == ASTTag::PARAM_LIST) { int paramIndex = 0; // 从 FunctionType 获取预期的参数类型,用于交叉验证或处理 K&R 情况 auto expectedParamTypes = std::dynamic_pointer_cast(funcType)->params(); for (auto* paramDeclNode : paramListNode->kids) { // 每个孩子是 PARAM_DECL if (paramDeclNode && paramDeclNode->tag == ASTTag::PARAM_DECL && paramDeclNode->kids.size() >= 1) { ASTNode* paramSpec = paramDeclNode->kids[0]; ASTNode* paramDtor = (paramDeclNode->kids.size() > 1) ? paramDeclNode->kids[1] : nullptr; // 使用 buildType 构建参数的实际类型 TypePtr paramType = buildType(paramSpec, paramDtor); // 提取参数名(如果存在) std::string paramName = ""; SourceLoc paramLoc = paramDeclNode->loc; if (paramDtor) { // 提取参数名,需要类似查找函数名的逻辑,但针对参数声明符 ASTNode* current = paramDtor; while (current && current->tag != ASTTag::ID && !current->text.empty() && current->tag != ASTTag::DECLARATOR) { // 适配参数名可能在 DECLARATOR text 或其子 ID 中 if (!current->kids.empty()) current = current->kids[0]; else break; } if (current && current->tag == ASTTag::ID) { paramName = current->text; paramLoc = current->loc; } else if (current && current->tag == ASTTag::DECLARATOR && !current->text.empty()){ paramName = current->text; paramLoc = current->loc; } } // 将参数插入到函数的当前作用域 if (!paramName.empty()) { if (!currentScope_->insert({paramName, paramType, SC_AUTO, paramLoc})) { error(paramLoc, "Semantic Error: Redeclaration of parameter '" + paramName + "'."); } else { // 可选:将类型附加到参数的 AST 节点 // if (paramDtor) paramDtor->type = paramType.get(); } } else { // TODO: 处理没有名字的参数 (如 void func(int);) } paramIndex++; } } // TODO: 处理可变参数 ... (PARAM_LIST_ELIPS) } } } // --- 5. 访问函数体 --- if (body) { visit(body); // 在函数作用域内处理函数体 } // --- 6. 离开函数作用域 --- currentScope_ = currentScope_->pop(); } void SemanticAnalyzer::visitCompoundStmt(ASTNode* n) { // 进入新的块 currentScope_ = currentScope_->push(); for (auto* item : n->kids) visit(item); currentScope_ = currentScope_->pop(); } void SemanticAnalyzer::visitDeclaration(ASTNode* n) { // 记下 spec_list,以便后面 visitInitDecl 拿到 lastSpecList_ = n->kids[0]; // n->kids = {spec_list, [init_decl_list]} if (n->kids.size() >= 2) { visit(n->kids[1]); // visit INIT_DECL_LIST } } void SemanticAnalyzer::visitInitDecl(ASTNode* n) { // n->kids = { declarator, [initializer] } ASTNode* dtor = n->kids[0]; SourceLoc nameLoc = dtor ? dtor->loc : n->loc; // 获取名字定义的大概位置 // 用上一次 visitDeclaration 缓存的 spec_list TypePtr varType = buildType(lastSpecList_, dtor); std::string name = extractNameFromDeclarator(dtor); if (!varType) { std::cerr << "[DEBUG Semantic] ERROR: buildType returned nullptr for variable '" << name << "' at line " << nameLoc.line << "!" << std::endl; // 你可以在这里决定如何处理: // 1. 报告一个内部错误 error(nameLoc, "Internal Compiler Error: Failed to build type for variable '" + name + "'."); // 2. 尝试赋一个默认类型(比如 int),但这可能隐藏问题 // varType = std::make_shared(TS_INT); // 3. 或者直接返回,阻止插入无类型的符号 if (n->kids.size() == 2) { visit(n->kids[1]); } // 也许仍然访问初始化器 return; } // 清空,避免下次乱用 lastSpecList_ = nullptr; // --- 使用与 IR 生成器相同的健壮方法提取名字 --- // <--- 修改点 // --- 添加检查,确保名字提取成功 --- if (name.empty()) { error(nameLoc, "Semantic Error: Could not extract variable name from declarator."); // 如果名字为空,后续插入无意义,可以提前返回或跳过插入 if (n->kids.size() == 2) { visit(n->kids[1]); } // 仍然处理初始化表达式,以发现其中的错误 return; } std::cerr << "[DEBUG Semantic] Inserted '" << name << "' into scope: " << currentScope_.get() << std::endl; // --- 使用提取到的名字插入符号表 --- if (!currentScope_->insert({name, varType, SC_AUTO, nameLoc})) { // 使用 nameLoc error(nameLoc, "Semantic Error: Variable '" + name + "' redefined."); } // --- 处理初始化器(如果有) --- if (n->kids.size() == 2) { visit(n->kids[1]); // 访问 initializer // TODO: 在这里可以添加类型检查,确保 initializer 的类型与 varType 兼容/可转换 } } void SemanticAnalyzer::visitIdentifier(ASTNode* n) { // 使用时查表 auto* sym = currentScope_->lookup(n->text); if (!sym) { error(n->loc, "未定义的标识符“" + n->text + "”"); } }