初步模块化语义分析
This commit is contained in:
parent
bfd14c4de7
commit
15c85c5a48
@ -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<Class<?>, StatementAnalyzer<?>> stmtAnalyzers = new HashMap<>();
|
||||||
|
private final Map<Class<?>, ExpressionAnalyzer<?>> exprAnalyzers = new HashMap<>();
|
||||||
|
|
||||||
|
// --- 注册方法 -----------------------------------------------------------
|
||||||
|
public <S extends StatementNode> void registerStatementAnalyzer(Class<S> cls, StatementAnalyzer<S> analyzer) {
|
||||||
|
stmtAnalyzers.put(cls, analyzer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public <E extends ExpressionNode> void registerExpressionAnalyzer(Class<E> cls, ExpressionAnalyzer<E> analyzer) {
|
||||||
|
exprAnalyzers.put(cls, analyzer);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- 获取方法 -----------------------------------------------------------
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public <S extends StatementNode> StatementAnalyzer<S> getStatementAnalyzer(S stmt) {
|
||||||
|
return (StatementAnalyzer<S>) stmtAnalyzers.get(stmt.getClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public <E extends ExpressionNode> ExpressionAnalyzer<E> getExpressionAnalyzer(E expr) {
|
||||||
|
return (ExpressionAnalyzer<E>) exprAnalyzers.get(expr.getClass());
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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<AssignmentNode> {
|
||||||
|
@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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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<BinaryExpressionNode> {
|
||||||
|
@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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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<CallExpressionNode> {
|
||||||
|
@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<Type> 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
46
src/main/java/org/jcnc/snow/compiler/semantic/Context.java
Normal file
46
src/main/java/org/jcnc/snow/compiler/semantic/Context.java
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
package org.jcnc.snow.compiler.semantic;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 公共上下文对象,贯穿整个语义分析过程。
|
||||||
|
*/
|
||||||
|
public class Context {
|
||||||
|
private final Map<String, ModuleInfo> modules;
|
||||||
|
private final List<SemanticError> errors;
|
||||||
|
private final boolean verbose;
|
||||||
|
private final AnalyzerRegistry registry;
|
||||||
|
|
||||||
|
public Context(Map<String, ModuleInfo> modules,
|
||||||
|
List<SemanticError> errors,
|
||||||
|
boolean verbose,
|
||||||
|
AnalyzerRegistry registry) {
|
||||||
|
this.modules = modules;
|
||||||
|
this.errors = errors;
|
||||||
|
this.verbose = verbose;
|
||||||
|
this.registry = registry;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, ModuleInfo> getModules() {
|
||||||
|
return modules;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<SemanticError> 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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<DeclarationNode> {
|
||||||
|
@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());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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<E extends ExpressionNode> {
|
||||||
|
Type analyze(Context ctx, ModuleInfo mi, FunctionNode fn, SymbolTable locals, E expr);
|
||||||
|
}
|
||||||
@ -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<IdentifierNode> {
|
||||||
|
@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();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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<IfNode> {
|
||||||
|
@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);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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<LoopNode> {
|
||||||
|
@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);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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<NumberLiteralNode> {
|
||||||
|
@Override
|
||||||
|
public Type analyze(Context ctx, ModuleInfo mi, FunctionNode fn, SymbolTable locals, NumberLiteralNode expr) {
|
||||||
|
return BuiltinType.INT;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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<ReturnNode> {
|
||||||
|
@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 函数缺少返回值");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,400 +1,140 @@
|
|||||||
package org.jcnc.snow.compiler.semantic;
|
package org.jcnc.snow.compiler.semantic;
|
||||||
|
|
||||||
import org.jcnc.snow.compiler.parser.ast.*;
|
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.*;
|
import java.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 语义分析器。
|
* 重构后的语义分析器,采用注册表 + 分析器组合的分而治之设计。
|
||||||
* <p>
|
|
||||||
* 负责对整个模块列表进行静态语义检查,
|
|
||||||
* 包括模块导入、函数定义、变量使用、表达式类型推导等。
|
|
||||||
* 分析过程中收集所有发现的语义错误,并最终返回错误列表。
|
|
||||||
*/
|
*/
|
||||||
public class SemanticAnalyzer {
|
public class SemanticAnalyzer {
|
||||||
/** 所有模块信息(包括内置模块和用户模块) */
|
|
||||||
private final Map<String, ModuleInfo> modules = new HashMap<>();
|
|
||||||
/** 语义错误列表 */
|
|
||||||
private final List<SemanticError> errors = new ArrayList<>();
|
|
||||||
/** 是否启用详细日志打印 */
|
|
||||||
private final boolean verbose;
|
|
||||||
/** 内置类型映射表 */
|
/** 内置类型映射表 */
|
||||||
private static final Map<String, Type> BUILTIN_TYPES = Map.of(
|
public static final Map<String, Type> BUILTIN_TYPES = Map.of(
|
||||||
"int", BuiltinType.INT,
|
"int", BuiltinType.INT,
|
||||||
"string", BuiltinType.STRING,
|
"string", BuiltinType.STRING,
|
||||||
"void", BuiltinType.VOID
|
"void", BuiltinType.VOID
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
// ---------------------------------------------------------------------
|
||||||
* 默认构造,关闭详细日志。
|
private final Map<String, ModuleInfo> modules = new HashMap<>();
|
||||||
*/
|
private final List<SemanticError> errors = new ArrayList<>();
|
||||||
|
private final boolean verbose;
|
||||||
|
|
||||||
|
private final AnalyzerRegistry registry = new AnalyzerRegistry();
|
||||||
|
private final Context ctx;
|
||||||
|
|
||||||
public SemanticAnalyzer() {
|
public SemanticAnalyzer() {
|
||||||
this(false);
|
this(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 构造函数。
|
|
||||||
*
|
|
||||||
* @param verbose 是否启用详细日志
|
|
||||||
*/
|
|
||||||
public SemanticAnalyzer(boolean verbose) {
|
public SemanticAnalyzer(boolean verbose) {
|
||||||
this.verbose = verbose;
|
this.verbose = verbose;
|
||||||
|
this.ctx = new Context(modules, errors, verbose, registry);
|
||||||
|
registerAnalyzers();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 打印日志,仅在 verbose 模式下输出。 */
|
// ---------------------------------------------------------------------
|
||||||
private void log(String msg) {
|
private void registerAnalyzers() {
|
||||||
if (verbose) {
|
// 语句
|
||||||
System.out.println("[SemanticAnalyzer] " + msg);
|
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<SemanticError> analyze(List<ModuleNode> moduleNodes) {
|
public List<SemanticError> analyze(List<ModuleNode> moduleNodes) {
|
||||||
log("开始语义分析");
|
ctx.log("开始语义分析");
|
||||||
initBuiltinModule();
|
initBuiltinModule();
|
||||||
log("内置模块初始化完成");
|
ctx.log("内置模块初始化完成");
|
||||||
registerUserModules(moduleNodes);
|
registerUserModules(moduleNodes);
|
||||||
log("用户模块注册完成: " + modules.keySet());
|
ctx.log("用户模块注册完成: " + modules.keySet());
|
||||||
registerSignaturesAndImports(moduleNodes);
|
registerSignaturesAndImports(moduleNodes);
|
||||||
log("函数签名与导入检查完成");
|
ctx.log("函数签名与导入检查完成");
|
||||||
checkAllFunctions(moduleNodes);
|
checkAllFunctions(moduleNodes);
|
||||||
log("所有函数检查完成,错误总数: " + errors.size());
|
ctx.log("所有函数检查完成,错误总数: " + errors.size());
|
||||||
return errors;
|
return errors;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 初始化内置模块及其内置函数。 */
|
// ---------------------------------------------------------------------
|
||||||
private void initBuiltinModule() {
|
private void initBuiltinModule() {
|
||||||
ModuleInfo builtin = new ModuleInfo("BuiltinUtils");
|
ModuleInfo builtin = new ModuleInfo("BuiltinUtils");
|
||||||
builtin.getFunctions().put("to_int", new FunctionType(List.of(BuiltinType.STRING), BuiltinType.INT));
|
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("to_string", new FunctionType(List.of(BuiltinType.INT), BuiltinType.STRING));
|
||||||
builtin.getFunctions().put("print", new FunctionType(List.of(BuiltinType.STRING), BuiltinType.VOID));
|
builtin.getFunctions().put("print", new FunctionType(List.of(BuiltinType.STRING), BuiltinType.VOID));
|
||||||
modules.put(builtin.getName(), builtin);
|
modules.put(builtin.getName(), builtin);
|
||||||
log("内置函数 to_int, to_string, print 注册到模块 " + builtin.getName());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 注册所有用户模块到模块表。 */
|
|
||||||
private void registerUserModules(List<ModuleNode> mods) {
|
private void registerUserModules(List<ModuleNode> mods) {
|
||||||
for (var mod : mods) {
|
for (var mod : mods) {
|
||||||
modules.put(mod.name(), new ModuleInfo(mod.name()));
|
modules.put(mod.name(), new ModuleInfo(mod.name()));
|
||||||
log("注册用户模块: " + mod.name());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 注册模块的导入信息和函数签名。 */
|
|
||||||
private void registerSignaturesAndImports(List<ModuleNode> mods) {
|
private void registerSignaturesAndImports(List<ModuleNode> mods) {
|
||||||
for (var mod : mods) {
|
for (var mod : mods) {
|
||||||
ModuleInfo mi = modules.get(mod.name());
|
ModuleInfo mi = modules.get(mod.name());
|
||||||
|
// 导入
|
||||||
// 处理导入
|
|
||||||
for (var imp : mod.imports()) {
|
for (var imp : mod.imports()) {
|
||||||
if (!modules.containsKey(imp.moduleName())) {
|
if (!modules.containsKey(imp.moduleName())) {
|
||||||
errors.add(new SemanticError(imp, "未知模块: " + imp.moduleName()));
|
errors.add(new SemanticError(imp, "未知模块: " + imp.moduleName()));
|
||||||
log("错误: 未知模块导入 " + imp.moduleName());
|
continue;
|
||||||
} else {
|
}
|
||||||
mi.getImports().add(imp.moduleName());
|
mi.getImports().add(imp.moduleName());
|
||||||
log("模块 " + mod.name() + " 导入模块: " + imp.moduleName());
|
|
||||||
}
|
}
|
||||||
}
|
// 函数签名
|
||||||
|
|
||||||
// 处理函数定义
|
|
||||||
for (var fn : mod.functions()) {
|
for (var fn : mod.functions()) {
|
||||||
List<Type> params = new ArrayList<>();
|
List<Type> params = new ArrayList<>();
|
||||||
for (var p : fn.parameters()) {
|
for (var p : fn.parameters()) {
|
||||||
Type t = parseType(p.type());
|
Type t = ctx.parseType(p.type());
|
||||||
if (t == null) {
|
if (t == null) {
|
||||||
errors.add(new SemanticError(p, "未知类型: " + p.type()));
|
errors.add(new SemanticError(p, "未知类型: " + p.type()));
|
||||||
log("错误: 参数未知类型 " + p.type() + " 在函数 " + fn.name());
|
t = BuiltinType.INT;
|
||||||
t = BuiltinType.INT; // 默认降级为 int
|
|
||||||
}
|
}
|
||||||
params.add(t);
|
params.add(t);
|
||||||
}
|
}
|
||||||
Type ret = Optional.ofNullable(parseType(fn.returnType()))
|
Type ret = Optional.ofNullable(ctx.parseType(fn.returnType())).orElse(BuiltinType.VOID);
|
||||||
.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));
|
mi.getFunctions().put(fn.name(), new FunctionType(params, ret));
|
||||||
log("注册函数: " + mod.name() + "." + fn.name() + " 参数类型: " + params + " 返回类型: " + ret);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 检查所有函数内部的语义正确性。 */
|
|
||||||
private void checkAllFunctions(List<ModuleNode> mods) {
|
private void checkAllFunctions(List<ModuleNode> mods) {
|
||||||
for (var mod : mods) {
|
for (var mod : mods) {
|
||||||
ModuleInfo mi = modules.get(mod.name());
|
ModuleInfo mi = modules.get(mod.name());
|
||||||
for (var fn : mod.functions()) {
|
for (var fn : mod.functions()) {
|
||||||
log("开始检查函数: " + mod.name() + "." + fn.name());
|
|
||||||
SymbolTable locals = new SymbolTable(null);
|
SymbolTable locals = new SymbolTable(null);
|
||||||
// 注册参数
|
// 参数注册
|
||||||
for (var p : fn.parameters()) {
|
for (var p : fn.parameters()) {
|
||||||
locals.define(new Symbol(p.name(), parseType(p.type()), SymbolKind.VARIABLE));
|
locals.define(new Symbol(p.name(), ctx.parseType(p.type()), SymbolKind.VARIABLE));
|
||||||
log("定义参数: " + p.name() + " 类型: " + p.type());
|
|
||||||
}
|
}
|
||||||
// 检查函数体
|
// 函数体
|
||||||
fn.body().forEach(stmt -> checkStatement(mi, fn, locals, stmt));
|
for (var stmt : fn.body()) {
|
||||||
log("完成函数检查: " + mod.name() + "." + fn.name());
|
var analyzer = registry.getStatementAnalyzer(stmt);
|
||||||
}
|
if (analyzer != null) {
|
||||||
}
|
analyzer.analyze(ctx, mi, fn, locals, stmt);
|
||||||
}
|
} else {
|
||||||
|
|
||||||
/** 检查单个语句。 */
|
|
||||||
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));
|
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<ExpressionNode> 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<Type> 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));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|||||||
@ -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<S extends StatementNode> {
|
||||||
|
void analyze(Context ctx, ModuleInfo mi, FunctionNode fn, SymbolTable locals, S stmt);
|
||||||
|
}
|
||||||
@ -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<StringLiteralNode> {
|
||||||
|
@Override
|
||||||
|
public Type analyze(Context ctx, ModuleInfo mi, FunctionNode fn, SymbolTable locals, StringLiteralNode expr) {
|
||||||
|
return BuiltinType.STRING;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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<ExpressionNode>
|
||||||
|
public class UnsupportedExpressionAnalyzer<E extends ExpressionNode>
|
||||||
|
implements ExpressionAnalyzer<E> {
|
||||||
|
|
||||||
|
@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;
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user