diff --git a/src/main/java/org/jcnc/snow/compiler/semantic/AnalyzerRegistry.java b/src/main/java/org/jcnc/snow/compiler/semantic/AnalyzerRegistry.java new file mode 100644 index 0000000..59f146d --- /dev/null +++ b/src/main/java/org/jcnc/snow/compiler/semantic/AnalyzerRegistry.java @@ -0,0 +1,35 @@ +package org.jcnc.snow.compiler.semantic; + +import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode; +import org.jcnc.snow.compiler.parser.ast.base.StatementNode; + +import java.util.HashMap; +import java.util.Map; + +/** + * Analyzer 注册表,负责按节点类型分发对应的 Analyzer。 + */ +public class AnalyzerRegistry { + private final Map, StatementAnalyzer> stmtAnalyzers = new HashMap<>(); + private final Map, ExpressionAnalyzer> exprAnalyzers = new HashMap<>(); + + // --- 注册方法 ----------------------------------------------------------- + public void registerStatementAnalyzer(Class cls, StatementAnalyzer analyzer) { + stmtAnalyzers.put(cls, analyzer); + } + + public void registerExpressionAnalyzer(Class cls, ExpressionAnalyzer analyzer) { + exprAnalyzers.put(cls, analyzer); + } + + // --- 获取方法 ----------------------------------------------------------- + @SuppressWarnings("unchecked") + public StatementAnalyzer getStatementAnalyzer(S stmt) { + return (StatementAnalyzer) stmtAnalyzers.get(stmt.getClass()); + } + + @SuppressWarnings("unchecked") + public ExpressionAnalyzer getExpressionAnalyzer(E expr) { + return (ExpressionAnalyzer) exprAnalyzers.get(expr.getClass()); + } +} diff --git a/src/main/java/org/jcnc/snow/compiler/semantic/AssignmentAnalyzer.java b/src/main/java/org/jcnc/snow/compiler/semantic/AssignmentAnalyzer.java new file mode 100644 index 0000000..a5698b7 --- /dev/null +++ b/src/main/java/org/jcnc/snow/compiler/semantic/AssignmentAnalyzer.java @@ -0,0 +1,23 @@ +package org.jcnc.snow.compiler.semantic; + +import org.jcnc.snow.compiler.parser.ast.AssignmentNode; +import org.jcnc.snow.compiler.parser.ast.FunctionNode; + +public class AssignmentAnalyzer implements StatementAnalyzer { + @Override + public void analyze(Context ctx, ModuleInfo mi, FunctionNode fn, SymbolTable locals, AssignmentNode asg) { + ctx.log("赋值检查: " + asg.variable()); + Symbol sym = locals.resolve(asg.variable()); + if (sym == null || sym.kind() != SymbolKind.VARIABLE) { + ctx.getErrors().add(new SemanticError(asg, "未声明的变量: " + asg.variable())); + ctx.log("错误: 未声明的变量 " + asg.variable()); + return; + } + var exprAnalyzer = ctx.getRegistry().getExpressionAnalyzer(asg.value()); + Type valType = exprAnalyzer.analyze(ctx, mi, fn, locals, asg.value()); + if (!sym.type().isCompatible(valType)) { + ctx.getErrors().add(new SemanticError(asg, "赋值类型不匹配: 期望 " + sym.type() + ", 实际 " + valType)); + ctx.log("错误: 赋值类型不匹配 " + asg.variable()); + } + } +} diff --git a/src/main/java/org/jcnc/snow/compiler/semantic/BinaryExpressionAnalyzer.java b/src/main/java/org/jcnc/snow/compiler/semantic/BinaryExpressionAnalyzer.java new file mode 100644 index 0000000..df020b6 --- /dev/null +++ b/src/main/java/org/jcnc/snow/compiler/semantic/BinaryExpressionAnalyzer.java @@ -0,0 +1,57 @@ +package org.jcnc.snow.compiler.semantic; + +import org.jcnc.snow.compiler.parser.ast.BinaryExpressionNode; +import org.jcnc.snow.compiler.parser.ast.FunctionNode; + +public class BinaryExpressionAnalyzer implements ExpressionAnalyzer { + @Override + public Type analyze(Context ctx, ModuleInfo mi, FunctionNode fn, SymbolTable locals, BinaryExpressionNode bin) { + ctx.log("检查二元表达式: " + bin.operator()); + var leftA = ctx.getRegistry().getExpressionAnalyzer(bin.left()); + Type left = leftA.analyze(ctx, mi, fn, locals, bin.left()); + var rightA = ctx.getRegistry().getExpressionAnalyzer(bin.right()); + Type right = rightA.analyze(ctx, mi, fn, locals, bin.right()); + + String op = bin.operator(); + Type result; + switch (op) { + case "+" -> { + 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 (left == BuiltinType.INT && right == BuiltinType.INT) { + result = BuiltinType.INT; + } else { + result = null; + } + } + case "<", "<=", ">", ">=", "==", "!=" -> { + if (left == BuiltinType.INT && right == BuiltinType.INT) { + result = BuiltinType.INT; + } else { + result = null; + } + } + default -> { + ctx.getErrors().add(new SemanticError(bin, "未知运算符: " + op)); + ctx.log("错误: 未知运算符 " + op); + return BuiltinType.INT; + } + } + + if (result == null) { + ctx.getErrors().add(new SemanticError(bin, String.format("运算符 '%s' 不支持类型: %s 和 %s", op, left, right))); + ctx.log("错误: 运算符 '" + op + "' 不支持类型: " + left + ", " + right); + result = BuiltinType.INT; + } else { + ctx.log("二元表达式推导类型: " + result); + } + return result; + } +} diff --git a/src/main/java/org/jcnc/snow/compiler/semantic/CallExpressionAnalyzer.java b/src/main/java/org/jcnc/snow/compiler/semantic/CallExpressionAnalyzer.java new file mode 100644 index 0000000..efcdb59 --- /dev/null +++ b/src/main/java/org/jcnc/snow/compiler/semantic/CallExpressionAnalyzer.java @@ -0,0 +1,75 @@ +package org.jcnc.snow.compiler.semantic; + +import org.jcnc.snow.compiler.parser.ast.CallExpressionNode; +import org.jcnc.snow.compiler.parser.ast.FunctionNode; +import org.jcnc.snow.compiler.parser.ast.IdentifierNode; +import org.jcnc.snow.compiler.parser.ast.MemberExpressionNode; +import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode; + +import java.util.ArrayList; +import java.util.List; + +public class CallExpressionAnalyzer implements ExpressionAnalyzer { + @Override + public Type analyze(Context ctx, ModuleInfo mi, FunctionNode fn, SymbolTable locals, CallExpressionNode call) { + ctx.log("检查函数调用: " + call.callee()); + + ModuleInfo target = mi; + String functionName; + ExpressionNode callee = call.callee(); + + if (callee instanceof MemberExpressionNode(var object, String member)) { + if (object instanceof IdentifierNode id) { + String moduleName = id.name(); + if (!ctx.getModules().containsKey(moduleName) || + (!mi.getImports().contains(moduleName) && !mi.getName().equals(moduleName))) { + ctx.getErrors().add(new SemanticError(callee, "未知或未导入模块: " + moduleName)); + ctx.log("错误: 未导入模块 " + moduleName); + return BuiltinType.INT; + } + target = ctx.getModules().get(moduleName); + functionName = member; + ctx.log("调用模块函数: " + moduleName + "." + member); + } else { + ctx.getErrors().add(new SemanticError(callee, "不支持的调用方式: " + callee)); + ctx.log("错误: 不支持的调用方式 " + callee); + return BuiltinType.INT; + } + } else if (callee instanceof IdentifierNode id) { + functionName = id.name(); + ctx.log("调用当前模块函数: " + functionName); + } else { + ctx.getErrors().add(new SemanticError(callee, "不支持的调用方式: " + callee)); + ctx.log("错误: 不支持的调用方式 " + callee); + return BuiltinType.INT; + } + + FunctionType ft = target.getFunctions().get(functionName); + if (ft == null) { + ctx.getErrors().add(new SemanticError(callee, "函数未定义: " + functionName)); + ctx.log("错误: 函数未定义 " + functionName); + return BuiltinType.INT; + } + + List args = new ArrayList<>(); + for (var argExpr : call.arguments()) { + var argAnalyzer = ctx.getRegistry().getExpressionAnalyzer(argExpr); + args.add(argAnalyzer.analyze(ctx, mi, fn, locals, argExpr)); + } + + if (args.size() != ft.paramTypes().size()) { + ctx.getErrors().add(new SemanticError(call, "参数数量不匹配: 期望 " + ft.paramTypes().size() + " 个, 实际 " + args.size() + " 个")); + ctx.log("错误: 参数数量不匹配: 期望 " + ft.paramTypes().size() + ", 实际 " + args.size()); + } else { + for (int i = 0; i < args.size(); i++) { + if (!ft.paramTypes().get(i).isCompatible(args.get(i))) { + ctx.getErrors().add(new SemanticError(call, String.format("参数类型不匹配 (位置 %d): 期望 %s, 实际 %s", i, ft.paramTypes().get(i), args.get(i)))); + ctx.log("错误: 参数类型不匹配 (位置 " + i + "): 期望 " + ft.paramTypes().get(i) + ", 实际 " + args.get(i)); + } + } + } + + ctx.log("函数调用类型: 返回 " + ft.returnType()); + return ft.returnType(); + } +} diff --git a/src/main/java/org/jcnc/snow/compiler/semantic/Context.java b/src/main/java/org/jcnc/snow/compiler/semantic/Context.java new file mode 100644 index 0000000..af5fb4e --- /dev/null +++ b/src/main/java/org/jcnc/snow/compiler/semantic/Context.java @@ -0,0 +1,46 @@ +package org.jcnc.snow.compiler.semantic; + +import java.util.*; + +/** + * 公共上下文对象,贯穿整个语义分析过程。 + */ +public class Context { + private final Map modules; + private final List errors; + private final boolean verbose; + private final AnalyzerRegistry registry; + + public Context(Map modules, + List errors, + boolean verbose, + AnalyzerRegistry registry) { + this.modules = modules; + this.errors = errors; + this.verbose = verbose; + this.registry = registry; + } + + public Map getModules() { + return modules; + } + + public List getErrors() { + return errors; + } + + public AnalyzerRegistry getRegistry() { + return registry; + } + + public void log(String msg) { + if (verbose) { + System.out.println("[SemanticAnalyzer] " + msg); + } + } + + /** 根据名称解析为内置类型,未知则返回 null */ + public Type parseType(String name) { + return SemanticAnalyzer.BUILTIN_TYPES.get(name); + } +} diff --git a/src/main/java/org/jcnc/snow/compiler/semantic/DeclarationAnalyzer.java b/src/main/java/org/jcnc/snow/compiler/semantic/DeclarationAnalyzer.java new file mode 100644 index 0000000..4d04516 --- /dev/null +++ b/src/main/java/org/jcnc/snow/compiler/semantic/DeclarationAnalyzer.java @@ -0,0 +1,32 @@ +package org.jcnc.snow.compiler.semantic; + +import org.jcnc.snow.compiler.parser.ast.DeclarationNode; +import org.jcnc.snow.compiler.parser.ast.FunctionNode; + +public class DeclarationAnalyzer implements StatementAnalyzer { + @Override + public void analyze(Context ctx, ModuleInfo mi, FunctionNode fn, SymbolTable locals, DeclarationNode decl) { + Type varType = ctx.parseType(decl.getType()); + if (varType == null) { + ctx.getErrors().add(new SemanticError(decl, "未知类型: " + decl.getType())); + ctx.log("错误: 参数未知类型 " + decl.getType() + " 在声明 " + decl.getName()); + varType = BuiltinType.INT; + } + ctx.log("声明变量: " + decl.getName() + " 类型: " + varType); + + if (!locals.define(new Symbol(decl.getName(), varType, SymbolKind.VARIABLE))) { + ctx.getErrors().add(new SemanticError(decl, "变量重复声明: " + decl.getName())); + ctx.log("错误: 变量重复声明 " + decl.getName()); + } + + Type finalVarType = varType; + decl.getInitializer().ifPresent(init -> { + var exprAnalyzer = ctx.getRegistry().getExpressionAnalyzer(init); + Type initType = exprAnalyzer.analyze(ctx, mi, fn, locals, init); + if (!finalVarType.isCompatible(initType)) { + ctx.getErrors().add(new SemanticError(decl, "初始化类型不匹配: 期望 " + finalVarType + ", 实际 " + initType)); + ctx.log("错误: 初始化类型不匹配 " + decl.getName()); + } + }); + } +} diff --git a/src/main/java/org/jcnc/snow/compiler/semantic/ExpressionAnalyzer.java b/src/main/java/org/jcnc/snow/compiler/semantic/ExpressionAnalyzer.java new file mode 100644 index 0000000..e365562 --- /dev/null +++ b/src/main/java/org/jcnc/snow/compiler/semantic/ExpressionAnalyzer.java @@ -0,0 +1,11 @@ +package org.jcnc.snow.compiler.semantic; + +import org.jcnc.snow.compiler.parser.ast.FunctionNode; +import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode; + +/** + * 表达式分析器接口。 + */ +public interface ExpressionAnalyzer { + Type analyze(Context ctx, ModuleInfo mi, FunctionNode fn, SymbolTable locals, E expr); +} diff --git a/src/main/java/org/jcnc/snow/compiler/semantic/IdentifierAnalyzer.java b/src/main/java/org/jcnc/snow/compiler/semantic/IdentifierAnalyzer.java new file mode 100644 index 0000000..bd172da --- /dev/null +++ b/src/main/java/org/jcnc/snow/compiler/semantic/IdentifierAnalyzer.java @@ -0,0 +1,17 @@ +package org.jcnc.snow.compiler.semantic; + +import org.jcnc.snow.compiler.parser.ast.FunctionNode; +import org.jcnc.snow.compiler.parser.ast.IdentifierNode; + +public class IdentifierAnalyzer implements ExpressionAnalyzer { + @Override + public Type analyze(Context ctx, ModuleInfo mi, FunctionNode fn, SymbolTable locals, IdentifierNode id) { + Symbol sym = locals.resolve(id.name()); + if (sym == null) { + ctx.getErrors().add(new SemanticError(id, "未声明的标识符: " + id.name())); + ctx.log("错误: 未声明的标识符 " + id.name()); + return BuiltinType.INT; + } + return sym.type(); + } +} diff --git a/src/main/java/org/jcnc/snow/compiler/semantic/IfAnalyzer.java b/src/main/java/org/jcnc/snow/compiler/semantic/IfAnalyzer.java new file mode 100644 index 0000000..0d92d88 --- /dev/null +++ b/src/main/java/org/jcnc/snow/compiler/semantic/IfAnalyzer.java @@ -0,0 +1,25 @@ +package org.jcnc.snow.compiler.semantic; + +import org.jcnc.snow.compiler.parser.ast.FunctionNode; +import org.jcnc.snow.compiler.parser.ast.IfNode; + +public class IfAnalyzer implements StatementAnalyzer { + @Override + public void analyze(Context ctx, ModuleInfo mi, FunctionNode fn, SymbolTable locals, IfNode ifn) { + ctx.log("检查 if 条件"); + var exprAnalyzer = ctx.getRegistry().getExpressionAnalyzer(ifn.condition()); + Type cond = exprAnalyzer.analyze(ctx, mi, fn, locals, ifn.condition()); + if (cond != BuiltinType.INT) { + ctx.getErrors().add(new SemanticError(ifn, "if 条件必须为 int 类型(表示真假)")); + ctx.log("错误: if 条件类型不为 int"); + } + ifn.thenBranch().forEach(stmt -> { + var stAnalyzer = ctx.getRegistry().getStatementAnalyzer(stmt); + if (stAnalyzer != null) stAnalyzer.analyze(ctx, mi, fn, locals, stmt); + }); + ifn.elseBranch().forEach(stmt -> { + var stAnalyzer = ctx.getRegistry().getStatementAnalyzer(stmt); + if (stAnalyzer != null) stAnalyzer.analyze(ctx, mi, fn, locals, stmt); + }); + } +} diff --git a/src/main/java/org/jcnc/snow/compiler/semantic/LoopAnalyzer.java b/src/main/java/org/jcnc/snow/compiler/semantic/LoopAnalyzer.java new file mode 100644 index 0000000..2fdd280 --- /dev/null +++ b/src/main/java/org/jcnc/snow/compiler/semantic/LoopAnalyzer.java @@ -0,0 +1,27 @@ +package org.jcnc.snow.compiler.semantic; + +import org.jcnc.snow.compiler.parser.ast.FunctionNode; +import org.jcnc.snow.compiler.parser.ast.LoopNode; + +public class LoopAnalyzer implements StatementAnalyzer { + @Override + public void analyze(Context ctx, ModuleInfo mi, FunctionNode fn, SymbolTable locals, LoopNode ln) { + ctx.log("检查 loop 循环"); + var initAnalyzer = ctx.getRegistry().getStatementAnalyzer(ln.initializer()); + if (initAnalyzer != null) initAnalyzer.analyze(ctx, mi, fn, locals, ln.initializer()); + + var condAnalyzer = ctx.getRegistry().getExpressionAnalyzer(ln.condition()); + Type cond = condAnalyzer.analyze(ctx, mi, fn, locals, ln.condition()); + if (cond != BuiltinType.INT) { + ctx.getErrors().add(new SemanticError(ln, "loop 条件必须为 int 类型(表示真假)")); + ctx.log("错误: loop 条件类型不为 int"); + } + var updateAnalyzer = ctx.getRegistry().getStatementAnalyzer(ln.update()); + if (updateAnalyzer != null) updateAnalyzer.analyze(ctx, mi, fn, locals, ln.update()); + + ln.body().forEach(stmt -> { + var stAnalyzer = ctx.getRegistry().getStatementAnalyzer(stmt); + if (stAnalyzer != null) stAnalyzer.analyze(ctx, mi, fn, locals, stmt); + }); + } +} diff --git a/src/main/java/org/jcnc/snow/compiler/semantic/NumberLiteralAnalyzer.java b/src/main/java/org/jcnc/snow/compiler/semantic/NumberLiteralAnalyzer.java new file mode 100644 index 0000000..1fb9d92 --- /dev/null +++ b/src/main/java/org/jcnc/snow/compiler/semantic/NumberLiteralAnalyzer.java @@ -0,0 +1,11 @@ +package org.jcnc.snow.compiler.semantic; + +import org.jcnc.snow.compiler.parser.ast.FunctionNode; +import org.jcnc.snow.compiler.parser.ast.NumberLiteralNode; + +public class NumberLiteralAnalyzer implements ExpressionAnalyzer { + @Override + public Type analyze(Context ctx, ModuleInfo mi, FunctionNode fn, SymbolTable locals, NumberLiteralNode expr) { + return BuiltinType.INT; + } +} diff --git a/src/main/java/org/jcnc/snow/compiler/semantic/ReturnAnalyzer.java b/src/main/java/org/jcnc/snow/compiler/semantic/ReturnAnalyzer.java new file mode 100644 index 0000000..4b5e106 --- /dev/null +++ b/src/main/java/org/jcnc/snow/compiler/semantic/ReturnAnalyzer.java @@ -0,0 +1,25 @@ +package org.jcnc.snow.compiler.semantic; + +import org.jcnc.snow.compiler.parser.ast.FunctionNode; +import org.jcnc.snow.compiler.parser.ast.ReturnNode; + +public class ReturnAnalyzer implements StatementAnalyzer { + @Override + public void analyze(Context ctx, ModuleInfo mi, FunctionNode fn, SymbolTable locals, ReturnNode ret) { + ctx.log("检查 return"); + FunctionType expected = ctx.getModules().get(mi.getName()).getFunctions().get(fn.name()); + ret.getExpression().ifPresentOrElse(exp -> { + var exprAnalyzer = ctx.getRegistry().getExpressionAnalyzer(exp); + Type actual = exprAnalyzer.analyze(ctx, mi, fn, locals, exp); + if (!expected.returnType().isCompatible(actual)) { + ctx.getErrors().add(new SemanticError(ret, "return 类型不匹配: 期望 " + expected.returnType() + ", 实际 " + actual)); + ctx.log("错误: return 类型不匹配"); + } + }, () -> { + if (expected.returnType() != BuiltinType.VOID) { + ctx.getErrors().add(new SemanticError(ret, "非 void 函数必须返回值")); + ctx.log("错误: 非 void 函数缺少返回值"); + } + }); + } +} 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 2a736c3..0883156 100644 --- a/src/main/java/org/jcnc/snow/compiler/semantic/SemanticAnalyzer.java +++ b/src/main/java/org/jcnc/snow/compiler/semantic/SemanticAnalyzer.java @@ -1,400 +1,140 @@ package org.jcnc.snow.compiler.semantic; import org.jcnc.snow.compiler.parser.ast.*; -import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode; -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( + public static final Map BUILTIN_TYPES = Map.of( "int", BuiltinType.INT, "string", BuiltinType.STRING, "void", BuiltinType.VOID ); - /** - * 默认构造,关闭详细日志。 - */ + // --------------------------------------------------------------------- + private final Map modules = new HashMap<>(); + private final List errors = new ArrayList<>(); + private final boolean verbose; + + private final AnalyzerRegistry registry = new AnalyzerRegistry(); + private final Context ctx; + public SemanticAnalyzer() { this(false); } - /** - * 构造函数。 - * - * @param verbose 是否启用详细日志 - */ public SemanticAnalyzer(boolean verbose) { this.verbose = verbose; + this.ctx = new Context(modules, errors, verbose, registry); + registerAnalyzers(); } - /** 打印日志,仅在 verbose 模式下输出。 */ - private void log(String msg) { - if (verbose) { - System.out.println("[SemanticAnalyzer] " + msg); - } + // --------------------------------------------------------------------- + private void registerAnalyzers() { + // 语句 + registry.registerStatementAnalyzer(DeclarationNode.class, new DeclarationAnalyzer()); + registry.registerStatementAnalyzer(AssignmentNode.class, new AssignmentAnalyzer()); + registry.registerStatementAnalyzer(IfNode.class, new IfAnalyzer()); + registry.registerStatementAnalyzer(LoopNode.class, new LoopAnalyzer()); + registry.registerStatementAnalyzer(ReturnNode.class, new ReturnAnalyzer()); + registry.registerStatementAnalyzer(ExpressionStatementNode.class, + (c, mi, fn, locals, stmt) -> { + var a = c.getRegistry().getExpressionAnalyzer(stmt.expression()); + a.analyze(c, mi, fn, locals, stmt.expression()); + }); + + // 表达式 + registry.registerExpressionAnalyzer(NumberLiteralNode.class, new NumberLiteralAnalyzer()); + registry.registerExpressionAnalyzer(StringLiteralNode.class, new StringLiteralAnalyzer()); + registry.registerExpressionAnalyzer(IdentifierNode.class, new IdentifierAnalyzer()); + registry.registerExpressionAnalyzer(CallExpressionNode.class, new CallExpressionAnalyzer()); + registry.registerExpressionAnalyzer(BinaryExpressionNode.class, new BinaryExpressionAnalyzer()); + // 兜底处理 + // 兜底:所有暂未实现的表达式都用 UnsupportedExpressionAnalyzer 处理 + registry.registerExpressionAnalyzer(MemberExpressionNode.class, + new UnsupportedExpressionAnalyzer<>()); } - /** - * 主分析入口。 - * - * @param moduleNodes 所有待分析的模块节点 - * @return 检查过程中发现的所有语义错误 - */ + // --------------------------------------------------------------------- public List analyze(List moduleNodes) { - log("开始语义分析"); + ctx.log("开始语义分析"); initBuiltinModule(); - log("内置模块初始化完成"); + ctx.log("内置模块初始化完成"); registerUserModules(moduleNodes); - log("用户模块注册完成: " + modules.keySet()); + ctx.log("用户模块注册完成: " + modules.keySet()); registerSignaturesAndImports(moduleNodes); - log("函数签名与导入检查完成"); + ctx.log("函数签名与导入检查完成"); checkAllFunctions(moduleNodes); - log("所有函数检查完成,错误总数: " + errors.size()); + ctx.log("所有函数检查完成,错误总数: " + errors.size()); return errors; } - /** 初始化内置模块及其内置函数。 */ + // --------------------------------------------------------------------- private void initBuiltinModule() { ModuleInfo builtin = new ModuleInfo("BuiltinUtils"); builtin.getFunctions().put("to_int", new FunctionType(List.of(BuiltinType.STRING), BuiltinType.INT)); builtin.getFunctions().put("to_string", new FunctionType(List.of(BuiltinType.INT), BuiltinType.STRING)); builtin.getFunctions().put("print", new FunctionType(List.of(BuiltinType.STRING), BuiltinType.VOID)); modules.put(builtin.getName(), builtin); - 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())); - log("注册用户模块: " + mod.name()); } } - /** 注册模块的导入信息和函数签名。 */ 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())); - log("错误: 未知模块导入 " + imp.moduleName()); - } else { - mi.getImports().add(imp.moduleName()); - log("模块 " + mod.name() + " 导入模块: " + imp.moduleName()); + continue; } + mi.getImports().add(imp.moduleName()); } - - // 处理函数定义 + // 函数签名 for (var fn : mod.functions()) { List params = new ArrayList<>(); for (var p : fn.parameters()) { - Type t = parseType(p.type()); + Type t = ctx.parseType(p.type()); if (t == null) { errors.add(new SemanticError(p, "未知类型: " + p.type())); - log("错误: 参数未知类型 " + p.type() + " 在函数 " + fn.name()); - t = BuiltinType.INT; // 默认降级为 int + t = BuiltinType.INT; } params.add(t); } - Type ret = Optional.ofNullable(parseType(fn.returnType())) - .orElseGet(() -> { - errors.add(new SemanticError(fn, "未知返回类型: " + fn.returnType())); - log("错误: 函数返回类型未知 " + fn.returnType() + " 在函数 " + fn.name()); - return BuiltinType.VOID; // 默认降级为 void - }); + Type ret = Optional.ofNullable(ctx.parseType(fn.returnType())).orElse(BuiltinType.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()); + locals.define(new Symbol(p.name(), ctx.parseType(p.type()), SymbolKind.VARIABLE)); } - // 检查函数体 - 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) { - case DeclarationNode decl -> checkDeclaration(mi, decl, locals); - case AssignmentNode asg -> checkAssignment(mi, asg, locals); - case ExpressionStatementNode es -> checkExpression(mi, fn, locals, es.expression()); - case IfNode ifn -> checkIf(mi, fn, locals, ifn); - case LoopNode ln -> checkLoop(mi, fn, locals, ln); - case ReturnNode ret -> checkReturn(mi, fn, locals, ret); - default -> { - errors.add(new SemanticError(stmt, "不支持的语句类型: " + stmt)); - log("错误: 不支持的语句类型 " + stmt); - } - } - } - - /** 检查变量声明。 */ - 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("错误: 初始化类型不匹配 " + decl.getName()); - } - }); - } - - /** 检查赋值语句。 */ - private void checkAssignment(ModuleInfo mi, AssignmentNode asg, SymbolTable locals) { - log("赋值检查: " + asg.variable()); - Symbol sym = locals.resolve(asg.variable()); - if (sym == null || sym.kind() != SymbolKind.VARIABLE) { - errors.add(new SemanticError(asg, "未声明的变量: " + asg.variable())); - log("错误: 未声明的变量 " + asg.variable()); - return; - } - Type valType = checkExpression(mi, null, locals, asg.value()); - if (!sym.type().isCompatible(valType)) { - errors.add(new SemanticError(asg, "赋值类型不匹配: 期望 " + sym.type() + ", 实际 " + 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"); - } - 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"); - } - checkStatement(mi, fn, locals, ln.update()); - 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()); - Optional exp = ret.getExpression(); - if (exp.isPresent()) { - Type actual = checkExpression(mi, fn, locals, exp.get()); - if (!expected.returnType().isCompatible(actual)) { - errors.add(new SemanticError(ret, "return 类型不匹配: 期望 " + expected.returnType() + ", 实际 " + actual)); - log("错误: return 类型不匹配"); - } - } else if (expected.returnType() != BuiltinType.VOID) { - errors.add(new SemanticError(ret, "非 void 函数必须返回值")); - log("错误: 非 void 函数缺少返回值"); - } - } - - /** 检查表达式,并返回其推断类型。 */ - private Type checkExpression(ModuleInfo mi, FunctionNode fn, SymbolTable locals, ExpressionNode expr) { - log("检查表达式: " + expr); - Type result; - switch (expr) { - case NumberLiteralNode ignored -> result = BuiltinType.INT; - case StringLiteralNode ignored -> result = BuiltinType.STRING; - case IdentifierNode id -> result = checkIdentifier(id, locals); - case CallExpressionNode call -> result = checkCall(mi, fn, locals, call); - case BinaryExpressionNode bin -> result = checkBinary(bin, mi, fn, locals); - default -> { - errors.add(new SemanticError(expr, "不支持的表达式类型: " + expr)); - log("错误: 不支持的表达式类型 " + expr); - result = BuiltinType.INT; - } - } - return result; - } - - /** 检查变量引用。 */ - private Type checkIdentifier(IdentifierNode id, SymbolTable locals) { - Symbol sym = locals.resolve(id.name()); - if (sym == null) { - errors.add(new SemanticError(id, "未声明的标识符: " + id.name())); - log("错误: 未声明的标识符 " + id.name()); - return BuiltinType.INT; - } - return sym.type(); - } - - /** 检查函数调用表达式,并推断返回类型。 */ - private Type checkCall(ModuleInfo mi, FunctionNode fn, SymbolTable locals, CallExpressionNode call) { - log("检查函数调用: " + call.callee()); - - ModuleInfo target = mi; - String functionName; - ExpressionNode callee = call.callee(); - - // 解析调用目标 - if (callee instanceof MemberExpressionNode(var object, var member)) { - 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(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)) { - functionName = idName; - log("调用当前模块函数: " + idName); - } else { - errors.add(new SemanticError(callee, "不支持的调用方式: " + callee)); - log("错误: 不支持的调用方式 " + callee); - return BuiltinType.INT; - } - - // 查找函数签名 - FunctionType ft = target.getFunctions().get(functionName); - if (ft == null) { - errors.add(new SemanticError(callee, "函数未定义: " + functionName)); - log("错误: 函数未定义 " + functionName); - return BuiltinType.INT; - } - - // 检查参数 - List args = new ArrayList<>(); - for (var a : call.arguments()) { - 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()); - } 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) - ))); - log("错误: 参数类型不匹配 (位置 " + i + "): 期望 " + ft.paramTypes().get(i) + ", 实际 " + args.get(i)); + // 函数体 + for (var stmt : fn.body()) { + var analyzer = registry.getStatementAnalyzer(stmt); + if (analyzer != null) { + analyzer.analyze(ctx, mi, fn, locals, stmt); + } else { + errors.add(new SemanticError(stmt, "不支持的语句类型: " + stmt)); + } } } } - - log("函数调用类型: 返回 " + ft.returnType()); - return ft.returnType(); - } - - /** 检查二元表达式,并推断结果类型。 */ - private Type checkBinary(BinaryExpressionNode bin, ModuleInfo mi, FunctionNode fn, SymbolTable locals) { - log("检查二元表达式: " + bin.operator()); - 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 (left == BuiltinType.STRING || right == BuiltinType.STRING) { - result = BuiltinType.STRING; - } else if (left == BuiltinType.INT && right == BuiltinType.INT) { - result = BuiltinType.INT; - } else { - result = null; - } - } - case "-", "*", "/", "%" -> { - // 数学运算:要求两边都是 int - if (left == BuiltinType.INT && right == BuiltinType.INT) { - result = BuiltinType.INT; - } else { - result = null; - } - } - case "<", "<=", ">", ">=", "==", "!=" -> { - // 比较运算:要求 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, left, right - ))); - log("错误: 运算符 '" + op + "' 不支持类型: " + left + ", " + right); - result = BuiltinType.INT; // 默认降级为 int 避免后续出错 - } else { - log("二元表达式推导类型: " + result); - } - return result; - } - - /** 解析类型名称,返回对应的内置类型,如果不存在返回 null。 */ - private Type parseType(String name) { - return BUILTIN_TYPES.get(name); } } - diff --git a/src/main/java/org/jcnc/snow/compiler/semantic/StatementAnalyzer.java b/src/main/java/org/jcnc/snow/compiler/semantic/StatementAnalyzer.java new file mode 100644 index 0000000..08d61a9 --- /dev/null +++ b/src/main/java/org/jcnc/snow/compiler/semantic/StatementAnalyzer.java @@ -0,0 +1,11 @@ +package org.jcnc.snow.compiler.semantic; + +import org.jcnc.snow.compiler.parser.ast.FunctionNode; +import org.jcnc.snow.compiler.parser.ast.base.StatementNode; + +/** + * 语句分析器接口。 + */ +public interface StatementAnalyzer { + void analyze(Context ctx, ModuleInfo mi, FunctionNode fn, SymbolTable locals, S stmt); +} diff --git a/src/main/java/org/jcnc/snow/compiler/semantic/StringLiteralAnalyzer.java b/src/main/java/org/jcnc/snow/compiler/semantic/StringLiteralAnalyzer.java new file mode 100644 index 0000000..cde626f --- /dev/null +++ b/src/main/java/org/jcnc/snow/compiler/semantic/StringLiteralAnalyzer.java @@ -0,0 +1,11 @@ +package org.jcnc.snow.compiler.semantic; + +import org.jcnc.snow.compiler.parser.ast.FunctionNode; +import org.jcnc.snow.compiler.parser.ast.StringLiteralNode; + +public class StringLiteralAnalyzer implements ExpressionAnalyzer { + @Override + public Type analyze(Context ctx, ModuleInfo mi, FunctionNode fn, SymbolTable locals, StringLiteralNode expr) { + return BuiltinType.STRING; + } +} diff --git a/src/main/java/org/jcnc/snow/compiler/semantic/UnsupportedExpressionAnalyzer.java b/src/main/java/org/jcnc/snow/compiler/semantic/UnsupportedExpressionAnalyzer.java new file mode 100644 index 0000000..f3139d3 --- /dev/null +++ b/src/main/java/org/jcnc/snow/compiler/semantic/UnsupportedExpressionAnalyzer.java @@ -0,0 +1,21 @@ +package org.jcnc.snow.compiler.semantic; + +import org.jcnc.snow.compiler.parser.ast.FunctionNode; +import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode; + +// 之前:implements ExpressionAnalyzer +public class UnsupportedExpressionAnalyzer + implements ExpressionAnalyzer { + + @Override + public Type analyze(Context ctx, + ModuleInfo mi, + FunctionNode fn, + SymbolTable locals, + E expr) { + ctx.getErrors().add(new SemanticError(expr, + "不支持的表达式类型: " + expr)); + ctx.log("错误: 不支持的表达式类型 " + expr); + return BuiltinType.INT; + } +}