feat:语义分析支持布尔值比较

This commit is contained in:
Luke 2025-06-25 14:39:18 +08:00
parent dff64e7dbb
commit a64209c211

View File

@ -11,79 +11,75 @@ import org.jcnc.snow.compiler.semantic.type.BuiltinType;
import org.jcnc.snow.compiler.semantic.type.Type;
/**
* {@code BinaryExpressionAnalyzer} 是一个用于分析二元表达式的语义分析器
* {@code BinaryExpressionAnalyzer} 负责对二元表达式做语义分析并返回其类型
* <p>
* 支持的特性包括
* <ul>
* <li>字符串拼接当运算符为加号 "+" 且任一操作数为字符串类型时</li>
* <li>数值类型的自动宽化转换 int float 运算将转换为 float</li>
* <li>基本的数值运算符 +, -, *, /, %</li>
* <li>关系运算符和比较运算符 <, <=, >, >=, ==, !=</li>
* </ul>
* 对于不支持的运算符或不兼容的类型组合将记录语义错误并默认返回 {@code BuiltinType.INT} 以保持分析过程的连续性
* 支持特性
* 1. 字符串拼接+
* 2. 数值运算与自动宽化
* 3. 比较 / 关系运算
* 4. 布尔值比较== / !=
* <p>
* 实现类遵循 {@code ExpressionAnalyzer<BinaryExpressionNode>} 接口规范
* 如遇不支持的运算符或不兼容的类型组合将记录语义错误
* 并以 {@code int} 作为回退类型保持后续分析不中断
*/
public class BinaryExpressionAnalyzer implements ExpressionAnalyzer<BinaryExpressionNode> {
/**
* 分析给定的二元表达式节点返回其表达式类型
*
* @param ctx 当前语义分析上下文用于访问日志记录错误收集注册表等服务
* @param mi 当前模块信息包含模块级别的符号与类型定义
* @param fn 当前正在分析的函数节点
* @param locals 当前函数作用域内的符号表用于变量查找
* @param bin 要分析的二元表达式节点
* @return 分析后推断出的表达式类型
*/
@Override
public Type analyze(Context ctx,
ModuleInfo mi,
FunctionNode fn,
SymbolTable locals,
BinaryExpressionNode bin) {
ctx.log("检查二元表达式: " + bin.operator());
// 获取左侧表达式类型
Type left = ctx.getRegistry().getExpressionAnalyzer(bin.left())
/* ----------- 先递归分析左右子表达式类型 ----------- */
Type left = ctx.getRegistry()
.getExpressionAnalyzer(bin.left())
.analyze(ctx, mi, fn, locals, bin.left());
// 获取右侧表达式类型
Type right = ctx.getRegistry().getExpressionAnalyzer(bin.right())
Type right = ctx.getRegistry()
.getExpressionAnalyzer(bin.right())
.analyze(ctx, mi, fn, locals, bin.right());
String op = bin.operator();
// 情况 1字符串拼接+ 操作符且任一操作数为字符串类型
/* ----------- 情况 1字符串拼接 ----------- */
if (op.equals("+") &&
(left == BuiltinType.STRING || right == BuiltinType.STRING)) {
return BuiltinType.STRING;
}
// 情况 2数值类型运算或比较
if ("+-*/%".contains(op) || ("<<=>>===!=").contains(op)) {
if (left.isNumeric() && right.isNumeric()) {
// 自动宽化到更宽的数值类型 int + float => float
Type wide = Type.widen(left, right);
if (wide == null) wide = BuiltinType.INT; // 容错降级为 int
// 若为比较运算符统一返回 boolean 类型作为布尔值表示
if ("< <= > >= == !=".contains(op)) {
/* ----------- 情况 1.5:布尔值比较 ----------- */
if (("==".equals(op) || "!=".equals(op)) &&
left == BuiltinType.BOOLEAN &&
right == BuiltinType.BOOLEAN) {
return BuiltinType.BOOLEAN;
}
/* ----------- 情况 2数值运算 / 比较 ----------- */
if ("+-*/%".contains(op) || ("<<=>>===!=").contains(op)) {
if (left.isNumeric() && right.isNumeric()) {
// 自动数值宽化 int + float float
Type wide = Type.widen(left, right);
if (wide == null) wide = BuiltinType.INT; // 容错降级
// 比较运算统一返回 boolean
if ("< <= > >= == !=".contains(op)) {
return BuiltinType.BOOLEAN;
}
return wide;
}
}
// 情况 3不支持的类型组合记录语义错误
/* ----------- 情况 3不支持的类型组合 ----------- */
ctx.getErrors().add(new SemanticError(
bin,
String.format("运算符 '%s' 不支持类型: %s 和 %s", op, left, right)
));
ctx.log("错误: 运算符 '" + op + "' 不支持类型: " + left + ", " + right);
// 错误情况下默认返回 int 类型以保证语义分析不中断
// 回退类型
return BuiltinType.INT;
}
}