【2025-11-16】现有代码上传

This commit is contained in:
hym816
2025-11-16 21:04:02 +08:00
parent 6e114d8735
commit d71eb4576e
28 changed files with 11524 additions and 0 deletions

368
semantic.cpp Normal file
View File

@@ -0,0 +1,368 @@
// semantic.cpp
#include "semantic.h"
#include "type.h" // 稍后实现
#include <iostream>
#include "ast.h"
SemanticAnalyzer::SemanticAnalyzer() {
// 1) 创建全局作用域
currentScope_ = std::make_shared<Scope>(nullptr);
rootScope_ = currentScope_;
// 2) 预先注册标准库函数原型extern。以 printf 为例:
{
// 返回类型 int
TypePtr ret = std::make_shared<BasicType>(TS_INT);
// 第一个参数 const char*
TypePtr p0 = std::make_shared<PointerType>(
std::make_shared<BasicType>(TS_CHAR));
// 可变参数标记:最后一个 bool 为 true
std::vector<TypePtr> params = { p0 };
TypePtr printfTy = std::make_shared<FunctionType>(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<TypeSpecifier>(spec->ival);
break;
}
}
}
TypePtr ty = std::make_shared<BasicType>(ts);
// —— 2. 递归处理 declarator各种修饰 ——
std::function<TypePtr(ASTNode*, TypePtr)> 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<PointerType>(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<int>(sizeNode->ival) : -1;
// 先把 direct_declkids[0])处理上去
TypePtr elem = applyDeclarator(decl->kids.empty() ? nullptr : decl->kids[0], base);
return std::make_shared<ArrayType>(elem, size);
}
case ASTTag::FUNC_DECL: {
// kids: [ direct_decl, (param_list?) ]
std::vector<TypePtr> 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<FunctionType>(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<FunctionType>(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<BasicType>(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 + "");
}
}