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} 负责对所有模块的函数体进行两遍扫描式的语义检查。
+ *
+ * 检查流程为:
+ *
+ * - 第一遍:为每个模块构建全局符号表,注册所有模块级变量与常量声明(并检查重复/未知类型)。
+ * - 第二遍:在所有全局符号表准备好后,依次分析各模块下所有函数的参数和函数体语句。
+ *
+ * 检查要点:
+ *
+ * - 类型未知或变量/常量重复声明时,均收集为语义错误。
+ * - 所有函数参数注册为局部变量。
+ * - 所有函数体语句分派到对应 StatementAnalyzer 实例做分析。
+ * - 非 void 返回类型的函数,必须有至少一条 return。
+ *
*/
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);