diff --git a/src/main/java/org/jcnc/snow/compiler/semantic/SemanticAnalyzer.java b/src/main/java/org/jcnc/snow/compiler/semantic/SemanticAnalyzer.java index 3640051..2a736c3 100644 --- a/src/main/java/org/jcnc/snow/compiler/semantic/SemanticAnalyzer.java +++ b/src/main/java/org/jcnc/snow/compiler/semantic/SemanticAnalyzer.java @@ -6,34 +6,56 @@ import org.jcnc.snow.compiler.parser.ast.base.StatementNode; import java.util.*; +/** + * 语义分析器。 + *

+ * 负责对整个模块列表进行静态语义检查, + * 包括模块导入、函数定义、变量使用、表达式类型推导等。 + * 分析过程中收集所有发现的语义错误,并最终返回错误列表。 + */ public class SemanticAnalyzer { + /** 所有模块信息(包括内置模块和用户模块) */ private final Map modules = new HashMap<>(); + /** 语义错误列表 */ private final List errors = new ArrayList<>(); + /** 是否启用详细日志打印 */ private final boolean verbose; + /** 内置类型映射表 */ private static final Map BUILTIN_TYPES = Map.of( - "int", BuiltinType.INT, - "string", BuiltinType.STRING, - "void", BuiltinType.VOID + "int", BuiltinType.INT, + "string", BuiltinType.STRING, + "void", BuiltinType.VOID ); - // 默认关闭详细日志 + /** + * 默认构造,关闭详细日志。 + */ public SemanticAnalyzer() { this(false); } /** - * @param verbose 是否开启详细日志打印 + * 构造函数。 + * + * @param verbose 是否启用详细日志 */ public SemanticAnalyzer(boolean verbose) { this.verbose = verbose; } + /** 打印日志,仅在 verbose 模式下输出。 */ private void log(String msg) { if (verbose) { System.out.println("[SemanticAnalyzer] " + msg); } } + /** + * 主分析入口。 + * + * @param moduleNodes 所有待分析的模块节点 + * @return 检查过程中发现的所有语义错误 + */ public List analyze(List moduleNodes) { log("开始语义分析"); initBuiltinModule(); @@ -47,6 +69,7 @@ public class SemanticAnalyzer { return errors; } + /** 初始化内置模块及其内置函数。 */ private void initBuiltinModule() { ModuleInfo builtin = new ModuleInfo("BuiltinUtils"); builtin.getFunctions().put("to_int", new FunctionType(List.of(BuiltinType.STRING), BuiltinType.INT)); @@ -56,6 +79,7 @@ public class SemanticAnalyzer { log("内置函数 to_int, to_string, print 注册到模块 " + builtin.getName()); } + /** 注册所有用户模块到模块表。 */ private void registerUserModules(List mods) { for (var mod : mods) { modules.put(mod.name(), new ModuleInfo(mod.name())); @@ -63,9 +87,12 @@ public class SemanticAnalyzer { } } + /** 注册模块的导入信息和函数签名。 */ private void registerSignaturesAndImports(List mods) { for (var mod : mods) { ModuleInfo mi = modules.get(mod.name()); + + // 处理导入 for (var imp : mod.imports()) { if (!modules.containsKey(imp.moduleName())) { errors.add(new SemanticError(imp, "未知模块: " + imp.moduleName())); @@ -75,6 +102,8 @@ public class SemanticAnalyzer { log("模块 " + mod.name() + " 导入模块: " + imp.moduleName()); } } + + // 处理函数定义 for (var fn : mod.functions()) { List params = new ArrayList<>(); for (var p : fn.parameters()) { @@ -82,38 +111,42 @@ public class SemanticAnalyzer { if (t == null) { errors.add(new SemanticError(p, "未知类型: " + p.type())); log("错误: 参数未知类型 " + p.type() + " 在函数 " + fn.name()); - t = BuiltinType.INT; + t = BuiltinType.INT; // 默认降级为 int } params.add(t); } - Type ret = parseType(fn.returnType()); - if (ret == null) { - errors.add(new SemanticError(fn, "未知返回类型: " + fn.returnType())); - log("错误: 函数返回类型未知 " + fn.returnType() + " 在函数 " + fn.name()); - ret = BuiltinType.VOID; - } + Type ret = Optional.ofNullable(parseType(fn.returnType())) + .orElseGet(() -> { + errors.add(new SemanticError(fn, "未知返回类型: " + fn.returnType())); + log("错误: 函数返回类型未知 " + fn.returnType() + " 在函数 " + fn.name()); + return BuiltinType.VOID; // 默认降级为 void + }); mi.getFunctions().put(fn.name(), new FunctionType(params, ret)); log("注册函数: " + mod.name() + "." + fn.name() + " 参数类型: " + params + " 返回类型: " + ret); } } } + /** 检查所有函数内部的语义正确性。 */ private void checkAllFunctions(List mods) { for (var mod : mods) { ModuleInfo mi = modules.get(mod.name()); for (var fn : mod.functions()) { log("开始检查函数: " + mod.name() + "." + fn.name()); SymbolTable locals = new SymbolTable(null); + // 注册参数 for (var p : fn.parameters()) { locals.define(new Symbol(p.name(), parseType(p.type()), SymbolKind.VARIABLE)); log("定义参数: " + p.name() + " 类型: " + p.type()); } + // 检查函数体 fn.body().forEach(stmt -> checkStatement(mi, fn, locals, stmt)); log("完成函数检查: " + mod.name() + "." + fn.name()); } } } + /** 检查单个语句。 */ private void checkStatement(ModuleInfo mi, FunctionNode fn, SymbolTable locals, StatementNode stmt) { log("检查语句: " + stmt); switch (stmt) { @@ -130,24 +163,26 @@ public class SemanticAnalyzer { } } + /** 检查变量声明。 */ private void checkDeclaration(ModuleInfo mi, DeclarationNode decl, SymbolTable locals) { Type varType = Optional.ofNullable(parseType(decl.getType())).orElse(BuiltinType.INT); log("声明变量: " + decl.getName() + " 类型: " + decl.getType()); + if (!locals.define(new Symbol(decl.getName(), varType, SymbolKind.VARIABLE))) { errors.add(new SemanticError(decl, "变量重复声明: " + decl.getName())); log("错误: 变量重复声明 " + decl.getName()); } + decl.getInitializer().ifPresent(init -> { Type initType = checkExpression(mi, null, locals, init); if (!varType.isCompatible(initType)) { errors.add(new SemanticError(decl, "初始化类型不匹配: 期望 " + varType + ", 实际 " + initType)); - log("错误: 初始化类型不匹配 for " + decl.getName() + ": 期望 " + varType + ", 实际 " + initType); - } else { - log("初始化成功: " + decl.getName() + " 类型: " + initType); + log("错误: 初始化类型不匹配 " + decl.getName()); } }); } + /** 检查赋值语句。 */ private void checkAssignment(ModuleInfo mi, AssignmentNode asg, SymbolTable locals) { log("赋值检查: " + asg.variable()); Symbol sym = locals.resolve(asg.variable()); @@ -159,39 +194,36 @@ public class SemanticAnalyzer { Type valType = checkExpression(mi, null, locals, asg.value()); if (!sym.type().isCompatible(valType)) { errors.add(new SemanticError(asg, "赋值类型不匹配: 期望 " + sym.type() + ", 实际 " + valType)); - log("错误: 赋值类型不匹配 for " + asg.variable() + ": 期望 " + sym.type() + ", 实际 " + valType); - } else { - log("赋值成功: " + asg.variable() + " = " + valType); + log("错误: 赋值类型不匹配 " + asg.variable()); } } + /** 检查 if 语句。 */ private void checkIf(ModuleInfo mi, FunctionNode fn, SymbolTable locals, IfNode ifn) { log("检查 if 条件"); Type cond = checkExpression(mi, fn, locals, ifn.condition()); if (cond != BuiltinType.INT) { errors.add(new SemanticError(ifn, "if 条件必须为 int 类型(表示真假)")); - log("错误: if 条件类型不为 int: " + cond); - } else { - log("if 条件类型合法: " + cond); + log("错误: if 条件类型不为 int"); } - ifn.thenBranch().forEach(s -> checkStatement(mi, fn, locals, s)); - ifn.elseBranch().forEach(s -> checkStatement(mi, fn, locals, s)); + ifn.thenBranch().forEach(stmt -> checkStatement(mi, fn, locals, stmt)); + ifn.elseBranch().forEach(stmt -> checkStatement(mi, fn, locals, stmt)); } + /** 检查循环。 */ private void checkLoop(ModuleInfo mi, FunctionNode fn, SymbolTable locals, LoopNode ln) { log("检查 loop 循环"); checkStatement(mi, fn, locals, ln.initializer()); Type cond = checkExpression(mi, fn, locals, ln.condition()); if (cond != BuiltinType.INT) { errors.add(new SemanticError(ln, "loop 条件必须为 int 类型(表示真假)")); - log("错误: loop 条件类型不为 int: " + cond); - } else { - log("loop 条件类型合法: " + cond); + log("错误: loop 条件类型不为 int"); } checkStatement(mi, fn, locals, ln.update()); - ln.body().forEach(s -> checkStatement(mi, fn, locals, s)); + ln.body().forEach(stmt -> checkStatement(mi, fn, locals, stmt)); } + /** 检查 return 语句。 */ private void checkReturn(ModuleInfo mi, FunctionNode fn, SymbolTable locals, ReturnNode ret) { log("检查 return"); FunctionType expected = modules.get(mi.getName()).getFunctions().get(fn.name()); @@ -200,18 +232,15 @@ public class SemanticAnalyzer { Type actual = checkExpression(mi, fn, locals, exp.get()); if (!expected.returnType().isCompatible(actual)) { errors.add(new SemanticError(ret, "return 类型不匹配: 期望 " + expected.returnType() + ", 实际 " + actual)); - log("错误: return 类型不匹配: 期望 " + expected.returnType() + ", 实际 " + actual); - } else { - log("return 类型合法: " + actual); + log("错误: return 类型不匹配"); } } else if (expected.returnType() != BuiltinType.VOID) { - errors.add(new SemanticError(ret, "非 void 函数必须返回值: " + expected.returnType())); - log("错误: 非 void 函数缺少返回值: 期望 " + expected.returnType()); - } else { - log("void 函数 return 合法"); + errors.add(new SemanticError(ret, "非 void 函数必须返回值")); + log("错误: 非 void 函数缺少返回值"); } } + /** 检查表达式,并返回其推断类型。 */ private Type checkExpression(ModuleInfo mi, FunctionNode fn, SymbolTable locals, ExpressionNode expr) { log("检查表达式: " + expr); Type result; @@ -227,45 +256,47 @@ public class SemanticAnalyzer { result = BuiltinType.INT; } } - log("表达式类型: " + result); return result; } + /** 检查变量引用。 */ private Type checkIdentifier(IdentifierNode id, SymbolTable locals) { - log("检查标识符: " + id.name()); Symbol sym = locals.resolve(id.name()); if (sym == null) { errors.add(new SemanticError(id, "未声明的标识符: " + id.name())); log("错误: 未声明的标识符 " + id.name()); return BuiltinType.INT; } - log("标识符类型: " + sym.type()); return sym.type(); } + /** 检查函数调用表达式,并推断返回类型。 */ private Type checkCall(ModuleInfo mi, FunctionNode fn, SymbolTable locals, CallExpressionNode call) { log("检查函数调用: " + call.callee()); + ModuleInfo target = mi; - String name; + String functionName; ExpressionNode callee = call.callee(); + // 解析调用目标 if (callee instanceof MemberExpressionNode(var object, var member)) { - if (object instanceof IdentifierNode(var modName)) { - if (!modules.containsKey(modName) || (!mi.getImports().contains(modName) && !mi.getName().equals(modName))) { - errors.add(new SemanticError(callee, "未知或未导入模块: " + modName)); - log("错误: 未导入模块 " + modName); + if (object instanceof IdentifierNode(var moduleName)) { + if (!modules.containsKey(moduleName) || + (!mi.getImports().contains(moduleName) && !mi.getName().equals(moduleName))) { + errors.add(new SemanticError(callee, "未知或未导入模块: " + moduleName)); + log("错误: 未导入模块 " + moduleName); return BuiltinType.INT; } - target = modules.get(modName); - name = member; - log("调用模块函数: " + modName + "." + member); + target = modules.get(moduleName); + functionName = member; + log("调用模块函数: " + moduleName + "." + member); } else { errors.add(new SemanticError(callee, "不支持的调用方式: " + callee)); log("错误: 不支持的调用方式 " + callee); return BuiltinType.INT; } } else if (callee instanceof IdentifierNode(var idName)) { - name = idName; + functionName = idName; log("调用当前模块函数: " + idName); } else { errors.add(new SemanticError(callee, "不支持的调用方式: " + callee)); @@ -273,75 +304,97 @@ public class SemanticAnalyzer { return BuiltinType.INT; } - FunctionType ft = target.getFunctions().get(name); + // 查找函数签名 + FunctionType ft = target.getFunctions().get(functionName); if (ft == null) { - errors.add(new SemanticError(callee, "函数未定义: " + name)); - log("错误: 函数未定义 " + name); + errors.add(new SemanticError(callee, "函数未定义: " + functionName)); + log("错误: 函数未定义 " + functionName); return BuiltinType.INT; } - var args = new ArrayList(); + // 检查参数 + List args = new ArrayList<>(); for (var a : call.arguments()) { - Type at = checkExpression(mi, fn, locals, a); - args.add(at); + args.add(checkExpression(mi, fn, locals, a)); } if (args.size() != ft.paramTypes().size()) { - errors.add(new SemanticError(call, "参数数量不匹配: 期望 " + ft.paramTypes().size() + " 个, 实际 " + args.size())); - log("错误: 参数数量不匹配: 期望 " + ft.paramTypes().size() + " 个, 实际 " + args.size()); + errors.add(new SemanticError(call, "参数数量不匹配: 期望 " + + ft.paramTypes().size() + " 个, 实际 " + args.size() + " 个")); + log("错误: 参数数量不匹配: 期望 " + ft.paramTypes().size() + ", 实际 " + args.size()); } else { for (int i = 0; i < args.size(); i++) { if (!ft.paramTypes().get(i).isCompatible(args.get(i))) { errors.add(new SemanticError(call, String.format( - "参数类型不匹配 (位置 %d): 期望 %s, 实际 %s", i, ft.paramTypes().get(i), args.get(i) + "参数类型不匹配 (位置 %d): 期望 %s, 实际 %s", i, ft.paramTypes().get(i), args.get(i) ))); log("错误: 参数类型不匹配 (位置 " + i + "): 期望 " + ft.paramTypes().get(i) + ", 实际 " + args.get(i)); } } - if (verbose) log("参数检查完成,所有参数类型符合期望"); } log("函数调用类型: 返回 " + ft.returnType()); return ft.returnType(); } + /** 检查二元表达式,并推断结果类型。 */ private Type checkBinary(BinaryExpressionNode bin, ModuleInfo mi, FunctionNode fn, SymbolTable locals) { log("检查二元表达式: " + bin.operator()); - Type l = checkExpression(mi, fn, locals, bin.left()); - Type r = checkExpression(mi, fn, locals, bin.right()); + Type left = checkExpression(mi, fn, locals, bin.left()); + Type right = checkExpression(mi, fn, locals, bin.right()); String op = bin.operator(); + Type result; switch (op) { case "+" -> { - if (l == BuiltinType.STRING || r == BuiltinType.STRING) result = BuiltinType.STRING; - else if (l == BuiltinType.INT && r == BuiltinType.INT) result = BuiltinType.INT; - else result = null; + // 字符串拼接 或 整数相加 + if (left == BuiltinType.STRING || right == BuiltinType.STRING) { + result = BuiltinType.STRING; + } else if (left == BuiltinType.INT && right == BuiltinType.INT) { + result = BuiltinType.INT; + } else { + result = null; + } } case "-", "*", "/", "%" -> { - if (l == BuiltinType.INT && r == BuiltinType.INT) result = BuiltinType.INT; - else result = null; + // 数学运算:要求两边都是 int + if (left == BuiltinType.INT && right == BuiltinType.INT) { + result = BuiltinType.INT; + } else { + result = null; + } } case "<", "<=", ">", ">=", "==", "!=" -> { - if (l == BuiltinType.INT && r == BuiltinType.INT) result = BuiltinType.INT; - else result = null; + // 比较运算:要求 int 返回 int (表示真假) + if (left == BuiltinType.INT && right == BuiltinType.INT) { + result = BuiltinType.INT; + } else { + result = null; + } } default -> { + // 未知运算符 errors.add(new SemanticError(bin, "未知运算符: " + op)); log("错误: 未知运算符 " + op); return BuiltinType.INT; } } + if (result == null) { - errors.add(new SemanticError(bin, String.format("运算符 '%s' 不支持类型: %s, %s", op, l, r))); - log("错误: 运算符 '" + op + "' 不支持类型: " + l + ", " + r); - result = BuiltinType.INT; + errors.add(new SemanticError(bin, String.format( + "运算符 '%s' 不支持类型: %s 和 %s", op, left, right + ))); + log("错误: 运算符 '" + op + "' 不支持类型: " + left + ", " + right); + result = BuiltinType.INT; // 默认降级为 int 避免后续出错 } else { - log("二元表达式计算类型: " + result); + log("二元表达式推导类型: " + result); } return result; } + /** 解析类型名称,返回对应的内置类型,如果不存在返回 null。 */ private Type parseType(String name) { return BUILTIN_TYPES.get(name); } -} \ No newline at end of file +} +