diff --git a/src/main/java/org/jcnc/snow/compiler/semantic/core/FunctionChecker.java b/src/main/java/org/jcnc/snow/compiler/semantic/core/FunctionChecker.java index 0a585b9..6107fed 100644 --- a/src/main/java/org/jcnc/snow/compiler/semantic/core/FunctionChecker.java +++ b/src/main/java/org/jcnc/snow/compiler/semantic/core/FunctionChecker.java @@ -17,35 +17,55 @@ import java.util.ArrayList; import java.util.List; /** - * 对所有模块的函数体进行两遍扫描的语义检查: - * 1) 先为每个模块建立全局符号表(globals),注册模块级变量/常量; - * 2) 再在全局表就绪后,依次分析各函数体。 + * {@code FunctionChecker} 负责对所有模块的函数体进行两遍扫描式的语义检查。 + *

+ * 检查流程为: + *

    + *
  1. 第一遍:为每个模块构建全局符号表,注册所有模块级变量与常量声明(并检查重复/未知类型)。
  2. + *
  3. 第二遍:在所有全局符号表准备好后,依次分析各模块下所有函数的参数和函数体语句。
  4. + *
+ * 检查要点: + * */ public record FunctionChecker(Context ctx) { + /** + * 对传入的所有模块做函数体的两遍扫描式语义检查。 + * + * @param mods 所有待分析的模块 AST 节点集合 + */ public void check(Iterable mods) { List moduleList = new ArrayList<>(); // ---------- 第一遍:构建并注册各模块全局符号表 ---------- for (ModuleNode mod : mods) { - ctx.setCurrentModule(mod.name()); + ctx.setCurrentModule(mod.name()); // 标记当前模块 moduleList.add(mod); ModuleInfo mi = ctx.modules().get(mod.name()); - SymbolTable globalScope = new SymbolTable(null); + SymbolTable globalScope = new SymbolTable(null); // 模块级全局作用域 + // 处理所有全局变量/常量声明 for (DeclarationNode g : mod.globals()) { - Type t = ctx.parseType(g.getType()); + Type t = ctx.parseType(g.getType()); // 解析声明类型 if (t == null) { + // 类型未知,记录错误,兜底为 int 类型,避免后续 NullPointer ctx.errors().add(new SemanticError(g, "未知类型: " + g.getType())); - t = BuiltinType.INT; // 兜底,避免后续 NPE + t = BuiltinType.INT; } SymbolKind kind = g.isConst() ? SymbolKind.CONSTANT : SymbolKind.VARIABLE; String dupType = g.isConst() ? "常量" : "变量"; + // 注册符号表(防止重名) if (!globalScope.define(new Symbol(g.getName(), t, kind))) { ctx.errors().add(new SemanticError(g, dupType + "重复声明: " + g.getName())); } } + // 将全局符号表挂载到模块信息对象 mi.setGlobals(globalScope); } @@ -53,13 +73,13 @@ public record FunctionChecker(Context ctx) { for (ModuleNode mod : moduleList) { ctx.setCurrentModule(mod.name()); ModuleInfo mi = ctx.modules().get(mod.name()); - SymbolTable globalScope = mi.getGlobals(); + SymbolTable globalScope = mi.getGlobals(); // 全局作用域 for (FunctionNode fn : mod.functions()) { - // 构建函数局部作用域:父作用域为全局 + // 构建函数的局部作用域(父作用域为模块全局) SymbolTable locals = new SymbolTable(globalScope); - // 注册函数参数为局部变量 + // 注册所有函数参数到局部作用域,类型未知时兜底为 int fn.parameters().forEach(p -> { Type t = ctx.parseType(p.type()); if (t == null) { @@ -69,19 +89,20 @@ public record FunctionChecker(Context ctx) { locals.define(new Symbol(p.name(), t, SymbolKind.VARIABLE)); }); - // 分析函数体语句 —— 关键修复:传“实例”而不是 Class + // 分析函数体所有语句 for (StatementNode stmt : fn.body()) { - @SuppressWarnings("unchecked") StatementAnalyzer analyzer = - (StatementAnalyzer) ctx.getRegistry().getStatementAnalyzer(stmt); + ctx.getRegistry().getStatementAnalyzer(stmt); if (analyzer != null) { + // 传递语义分析器“实例”,避免类型擦除/反射调用 analyzer.analyze(ctx, mi, fn, locals, stmt); } else { + // 语句类型未支持,收集错误 ctx.errors().add(new SemanticError(stmt, "不支持的语句类型: " + stmt)); } } - // 非 void 的函数必须至少包含一条 return + // 非 void 函数,要求必须含至少一条 return 语句 Type ret = ctx.parseType(fn.returnType()); if (ret != null && ret != BuiltinType.VOID) { boolean hasReturn = fn.body().stream().anyMatch(s -> s instanceof ReturnNode);