feat:支持 64位整型比较
This commit is contained in:
parent
8894fa3300
commit
dbf510f4ed
@ -4,6 +4,7 @@ import org.jcnc.snow.compiler.ir.core.IROpCode;
|
|||||||
import org.jcnc.snow.compiler.ir.instruction.CallInstruction;
|
import org.jcnc.snow.compiler.ir.instruction.CallInstruction;
|
||||||
import org.jcnc.snow.compiler.ir.instruction.LoadConstInstruction;
|
import org.jcnc.snow.compiler.ir.instruction.LoadConstInstruction;
|
||||||
import org.jcnc.snow.compiler.ir.instruction.UnaryOperationInstruction;
|
import org.jcnc.snow.compiler.ir.instruction.UnaryOperationInstruction;
|
||||||
|
import org.jcnc.snow.compiler.ir.utils.ComparisonUtils;
|
||||||
import org.jcnc.snow.compiler.ir.value.IRConstant;
|
import org.jcnc.snow.compiler.ir.value.IRConstant;
|
||||||
import org.jcnc.snow.compiler.ir.value.IRVirtualRegister;
|
import org.jcnc.snow.compiler.ir.value.IRVirtualRegister;
|
||||||
import org.jcnc.snow.compiler.ir.utils.ExpressionUtils;
|
import org.jcnc.snow.compiler.ir.utils.ExpressionUtils;
|
||||||
@ -137,13 +138,18 @@ public record ExpressionBuilder(IRContext ctx) {
|
|||||||
*/
|
*/
|
||||||
private IRVirtualRegister buildBinary(BinaryExpressionNode bin) {
|
private IRVirtualRegister buildBinary(BinaryExpressionNode bin) {
|
||||||
String op = bin.operator();
|
String op = bin.operator();
|
||||||
IRVirtualRegister left = build(bin.left());
|
IRVirtualRegister left = build(bin.left());
|
||||||
IRVirtualRegister right = build(bin.right());
|
IRVirtualRegister right = build(bin.right());
|
||||||
// 处理比较操作符
|
|
||||||
if (ExpressionUtils.isComparisonOperator(op)) {
|
// 1. 比较运算
|
||||||
return InstructionFactory.binOp(ctx, ExpressionUtils.cmpOp(op), left, right);
|
if (ComparisonUtils.isComparisonOperator(op)) {
|
||||||
|
return InstructionFactory.binOp(
|
||||||
|
ctx,
|
||||||
|
ComparisonUtils.cmpOp(op, bin.left(), bin.right()),
|
||||||
|
left, right);
|
||||||
}
|
}
|
||||||
// 处理算术运算符
|
|
||||||
|
// 2. 其他算术 / 逻辑运算
|
||||||
IROpCode code = ExpressionUtils.resolveOpCode(op, bin.left(), bin.right());
|
IROpCode code = ExpressionUtils.resolveOpCode(op, bin.left(), bin.right());
|
||||||
if (code == null) throw new IllegalStateException("不支持的运算符: " + op);
|
if (code == null) throw new IllegalStateException("不支持的运算符: " + op);
|
||||||
return InstructionFactory.binOp(ctx, code, left, right);
|
return InstructionFactory.binOp(ctx, code, left, right);
|
||||||
@ -161,8 +167,12 @@ public record ExpressionBuilder(IRContext ctx) {
|
|||||||
IRVirtualRegister a = build(bin.left());
|
IRVirtualRegister a = build(bin.left());
|
||||||
IRVirtualRegister b = build(bin.right());
|
IRVirtualRegister b = build(bin.right());
|
||||||
String op = bin.operator();
|
String op = bin.operator();
|
||||||
if (ExpressionUtils.isComparisonOperator(op)) {
|
|
||||||
InstructionFactory.binOpInto(ctx, ExpressionUtils.cmpOp(op), a, b, dest);
|
if (ComparisonUtils.isComparisonOperator(op)) {
|
||||||
|
InstructionFactory.binOpInto(
|
||||||
|
ctx,
|
||||||
|
ComparisonUtils.cmpOp(op, bin.left(), bin.right()),
|
||||||
|
a, b, dest);
|
||||||
} else {
|
} else {
|
||||||
IROpCode code = ExpressionUtils.resolveOpCode(op, bin.left(), bin.right());
|
IROpCode code = ExpressionUtils.resolveOpCode(op, bin.left(), bin.right());
|
||||||
if (code == null) throw new IllegalStateException("不支持的运算符: " + op);
|
if (code == null) throw new IllegalStateException("不支持的运算符: " + op);
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
package org.jcnc.snow.compiler.ir.builder;
|
package org.jcnc.snow.compiler.ir.builder;
|
||||||
|
|
||||||
import org.jcnc.snow.compiler.ir.core.IROpCode;
|
import org.jcnc.snow.compiler.ir.core.IROpCode;
|
||||||
import org.jcnc.snow.compiler.ir.utils.ExpressionUtils;
|
import org.jcnc.snow.compiler.ir.utils.ComparisonUtils;
|
||||||
import org.jcnc.snow.compiler.ir.utils.IROpCodeUtils;
|
import org.jcnc.snow.compiler.ir.utils.IROpCodeUtils;
|
||||||
import org.jcnc.snow.compiler.ir.value.IRVirtualRegister;
|
import org.jcnc.snow.compiler.ir.value.IRVirtualRegister;
|
||||||
import org.jcnc.snow.compiler.parser.ast.*;
|
import org.jcnc.snow.compiler.parser.ast.*;
|
||||||
@ -18,23 +18,41 @@ import java.util.Locale;
|
|||||||
*/
|
*/
|
||||||
public class StatementBuilder {
|
public class StatementBuilder {
|
||||||
|
|
||||||
/** 当前 IR 上下文,包含作用域、指令序列等信息。 */
|
/**
|
||||||
|
* 当前 IR 上下文,包含作用域、指令序列等信息。
|
||||||
|
*/
|
||||||
private final IRContext ctx;
|
private final IRContext ctx;
|
||||||
/** 表达式 IR 构建器,用于将表达式节点转为 IR 指令。 */
|
/**
|
||||||
|
* 表达式 IR 构建器,用于将表达式节点转为 IR 指令。
|
||||||
|
*/
|
||||||
private final ExpressionBuilder expr;
|
private final ExpressionBuilder expr;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 构造方法。
|
* 构造方法。
|
||||||
|
*
|
||||||
* @param ctx IR 编译上下文环境
|
* @param ctx IR 编译上下文环境
|
||||||
*/
|
*/
|
||||||
public StatementBuilder(IRContext ctx) {
|
public StatementBuilder(IRContext ctx) {
|
||||||
this.ctx = ctx;
|
this.ctx = ctx;
|
||||||
this.expr = new ExpressionBuilder(ctx);
|
this.expr = new ExpressionBuilder(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static char typeSuffixFromType(String type) {
|
||||||
|
if (type == null) return '\0';
|
||||||
|
return switch (type.toLowerCase(Locale.ROOT)) {
|
||||||
|
case "byte" -> 'b';
|
||||||
|
case "short" -> 's';
|
||||||
|
case "long" -> 'l';
|
||||||
|
case "float" -> 'f';
|
||||||
|
case "double" -> 'd';
|
||||||
|
default -> '\0'; // 其余默认按 32-bit 整型处理
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 将一个 AST 语句节点转为 IR 指令序列。
|
* 将一个 AST 语句节点转为 IR 指令序列。
|
||||||
* 根据节点类型分发到对应的处理方法。
|
* 根据节点类型分发到对应的处理方法。
|
||||||
|
*
|
||||||
* @param stmt 待转换的语句节点
|
* @param stmt 待转换的语句节点
|
||||||
*/
|
*/
|
||||||
public void build(StatementNode stmt) {
|
public void build(StatementNode stmt) {
|
||||||
@ -107,6 +125,7 @@ public class StatementBuilder {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取变量名对应的寄存器,不存在则声明一个新的。
|
* 获取变量名对应的寄存器,不存在则声明一个新的。
|
||||||
|
*
|
||||||
* @param name 变量名
|
* @param name 变量名
|
||||||
* @return 变量对应的虚拟寄存器
|
* @return 变量对应的虚拟寄存器
|
||||||
*/
|
*/
|
||||||
@ -121,6 +140,7 @@ public class StatementBuilder {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 批量构建一组语句节点,顺序处理每个语句。
|
* 批量构建一组语句节点,顺序处理每个语句。
|
||||||
|
*
|
||||||
* @param stmts 语句节点集合
|
* @param stmts 语句节点集合
|
||||||
*/
|
*/
|
||||||
private void buildStatements(Iterable<StatementNode> stmts) {
|
private void buildStatements(Iterable<StatementNode> stmts) {
|
||||||
@ -130,12 +150,13 @@ public class StatementBuilder {
|
|||||||
/**
|
/**
|
||||||
* 构建循环语句(for/while)。
|
* 构建循环语句(for/while)。
|
||||||
* 处理流程:初始语句 → 条件判断 → 循环体 → 更新语句 → 跳回条件。
|
* 处理流程:初始语句 → 条件判断 → 循环体 → 更新语句 → 跳回条件。
|
||||||
|
*
|
||||||
* @param loop 循环节点
|
* @param loop 循环节点
|
||||||
*/
|
*/
|
||||||
private void buildLoop(LoopNode loop) {
|
private void buildLoop(LoopNode loop) {
|
||||||
if (loop.initializer() != null) build(loop.initializer());
|
if (loop.initializer() != null) build(loop.initializer());
|
||||||
String lblStart = ctx.newLabel();
|
String lblStart = ctx.newLabel();
|
||||||
String lblEnd = ctx.newLabel();
|
String lblEnd = ctx.newLabel();
|
||||||
// 循环开始标签
|
// 循环开始标签
|
||||||
InstructionFactory.label(ctx, lblStart);
|
InstructionFactory.label(ctx, lblStart);
|
||||||
|
|
||||||
@ -155,11 +176,12 @@ public class StatementBuilder {
|
|||||||
/**
|
/**
|
||||||
* 构建分支语句(if/else)。
|
* 构建分支语句(if/else)。
|
||||||
* 处理流程:条件判断 → then 分支 → else 分支(可选)。
|
* 处理流程:条件判断 → then 分支 → else 分支(可选)。
|
||||||
|
*
|
||||||
* @param ifNode if 语句节点
|
* @param ifNode if 语句节点
|
||||||
*/
|
*/
|
||||||
private void buildIf(IfNode ifNode) {
|
private void buildIf(IfNode ifNode) {
|
||||||
String lblElse = ctx.newLabel();
|
String lblElse = ctx.newLabel();
|
||||||
String lblEnd = ctx.newLabel();
|
String lblEnd = ctx.newLabel();
|
||||||
// 条件不成立则跳转到 else
|
// 条件不成立则跳转到 else
|
||||||
emitConditionalJump(ifNode.condition(), lblElse);
|
emitConditionalJump(ifNode.condition(), lblElse);
|
||||||
|
|
||||||
@ -178,35 +200,30 @@ public class StatementBuilder {
|
|||||||
/**
|
/**
|
||||||
* 条件跳转指令的生成。
|
* 条件跳转指令的生成。
|
||||||
* 如果是二元比较表达式,直接使用对应比较操作码;否则等价于与 0 比较。
|
* 如果是二元比较表达式,直接使用对应比较操作码;否则等价于与 0 比较。
|
||||||
* @param cond 条件表达式
|
*
|
||||||
|
* @param cond 条件表达式
|
||||||
* @param falseLabel 条件不成立时跳转到的标签
|
* @param falseLabel 条件不成立时跳转到的标签
|
||||||
*/
|
*/
|
||||||
private void emitConditionalJump(ExpressionNode cond, String falseLabel) {
|
private void emitConditionalJump(ExpressionNode cond, String falseLabel) {
|
||||||
if (cond instanceof BinaryExpressionNode(ExpressionNode left, String operator, ExpressionNode right)
|
if (cond instanceof BinaryExpressionNode(
|
||||||
&& ExpressionUtils.isComparisonOperator(operator)) {
|
ExpressionNode left,
|
||||||
// 如果是比较操作(如 ==, >, <),直接生成对应的条件跳转
|
String operator,
|
||||||
|
ExpressionNode right
|
||||||
|
)
|
||||||
|
&& ComparisonUtils.isComparisonOperator(operator)) {
|
||||||
|
|
||||||
IRVirtualRegister a = expr.build(left);
|
IRVirtualRegister a = expr.build(left);
|
||||||
IRVirtualRegister b = expr.build(right);
|
IRVirtualRegister b = expr.build(right);
|
||||||
// 获取反向比较操作码
|
|
||||||
IROpCode falseOp = IROpCodeUtils.invert(ExpressionUtils.cmpOp(operator));
|
// 使用适配后位宽正确的比较指令
|
||||||
|
IROpCode cmp = ComparisonUtils.cmpOp(operator, left, right);
|
||||||
|
IROpCode falseOp = IROpCodeUtils.invert(cmp);
|
||||||
|
|
||||||
InstructionFactory.cmpJump(ctx, falseOp, a, b, falseLabel);
|
InstructionFactory.cmpJump(ctx, falseOp, a, b, falseLabel);
|
||||||
} else {
|
} else {
|
||||||
// 否则将 cond 与 0 比较,相等则跳转
|
|
||||||
IRVirtualRegister condReg = expr.build(cond);
|
IRVirtualRegister condReg = expr.build(cond);
|
||||||
IRVirtualRegister zero = InstructionFactory.loadConst(ctx, 0);
|
IRVirtualRegister zero = InstructionFactory.loadConst(ctx, 0);
|
||||||
InstructionFactory.cmpJump(ctx, IROpCode.CMP_EQ, condReg, zero, falseLabel);
|
InstructionFactory.cmpJump(ctx, IROpCode.CMP_EQ, condReg, zero, falseLabel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static char typeSuffixFromType(String type) {
|
|
||||||
if (type == null) return '\0';
|
|
||||||
return switch (type.toLowerCase(Locale.ROOT)) {
|
|
||||||
case "byte" -> 'b';
|
|
||||||
case "short" -> 's';
|
|
||||||
case "long" -> 'l';
|
|
||||||
case "float" -> 'f';
|
|
||||||
case "double" -> 'd';
|
|
||||||
default -> '\0'; // 其余默认按 32-bit 整型处理
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,12 +9,12 @@ public final class IROpCodeMappings {
|
|||||||
private IROpCodeMappings() {} // 禁止实例化
|
private IROpCodeMappings() {} // 禁止实例化
|
||||||
|
|
||||||
// 8位整型运算符映射
|
// 8位整型运算符映射
|
||||||
public static final Map<String, IROpCode> OP_I8 = Map.of(
|
public static final Map<String, IROpCode> OP_B8 = Map.of(
|
||||||
"+", IROpCode.ADD_B8, "-", IROpCode.SUB_B8,
|
"+", IROpCode.ADD_B8, "-", IROpCode.SUB_B8,
|
||||||
"*", IROpCode.MUL_B8, "/", IROpCode.DIV_B8
|
"*", IROpCode.MUL_B8, "/", IROpCode.DIV_B8
|
||||||
);
|
);
|
||||||
// 16位整型
|
// 16位整型
|
||||||
public static final Map<String, IROpCode> OP_I16 = Map.of(
|
public static final Map<String, IROpCode> OP_S16 = Map.of(
|
||||||
"+", IROpCode.ADD_S16, "-", IROpCode.SUB_S16,
|
"+", IROpCode.ADD_S16, "-", IROpCode.SUB_S16,
|
||||||
"*", IROpCode.MUL_S16, "/", IROpCode.DIV_S16
|
"*", IROpCode.MUL_S16, "/", IROpCode.DIV_S16
|
||||||
);
|
);
|
||||||
@ -38,8 +38,20 @@ public final class IROpCodeMappings {
|
|||||||
"+", IROpCode.ADD_D64, "-", IROpCode.SUB_D64,
|
"+", IROpCode.ADD_D64, "-", IROpCode.SUB_D64,
|
||||||
"*", IROpCode.MUL_D64, "/", IROpCode.DIV_D64
|
"*", IROpCode.MUL_D64, "/", IROpCode.DIV_D64
|
||||||
);
|
);
|
||||||
// 比较操作符映射
|
|
||||||
public static final Map<String, IROpCode> CMP = Map.of(
|
/* ────── 比较运算符映射 ────── */
|
||||||
|
/** 32-bit(int)比较 */
|
||||||
|
public static final Map<String, IROpCode> CMP_I32 = Map.of(
|
||||||
|
"==", IROpCode.CMP_EQ,
|
||||||
|
"!=", IROpCode.CMP_NE,
|
||||||
|
"<", IROpCode.CMP_LT,
|
||||||
|
">", IROpCode.CMP_GT,
|
||||||
|
"<=", IROpCode.CMP_LE,
|
||||||
|
">=", IROpCode.CMP_GE
|
||||||
|
);
|
||||||
|
|
||||||
|
/** 64-bit(long)比较 */
|
||||||
|
public static final Map<String, IROpCode> CMP_L64 = Map.of(
|
||||||
"==", IROpCode.CMP_LEQ,
|
"==", IROpCode.CMP_LEQ,
|
||||||
"!=", IROpCode.CMP_LNE,
|
"!=", IROpCode.CMP_LNE,
|
||||||
"<", IROpCode.CMP_LLT,
|
"<", IROpCode.CMP_LLT,
|
||||||
@ -47,4 +59,6 @@ public final class IROpCodeMappings {
|
|||||||
"<=", IROpCode.CMP_LLE,
|
"<=", IROpCode.CMP_LLE,
|
||||||
">=", IROpCode.CMP_LGE
|
">=", IROpCode.CMP_LGE
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,47 @@
|
|||||||
|
package org.jcnc.snow.compiler.ir.utils;
|
||||||
|
|
||||||
|
import org.jcnc.snow.compiler.ir.core.IROpCode;
|
||||||
|
import org.jcnc.snow.compiler.ir.core.IROpCodeMappings;
|
||||||
|
import org.jcnc.snow.compiler.parser.ast.NumberLiteralNode;
|
||||||
|
import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 比较运算辅助工具:
|
||||||
|
* 根据左右操作数类型(目前通过字面量后缀 <code>L/l</code> 判定)选择
|
||||||
|
* 正确的 IR 比较指令,保证 int/long 均能正常运行。
|
||||||
|
*/
|
||||||
|
public final class ComparisonUtils {
|
||||||
|
private ComparisonUtils() {}
|
||||||
|
|
||||||
|
/** 判断给定操作符是否为比较运算符 */
|
||||||
|
public static boolean isComparisonOperator(String op) {
|
||||||
|
// 两张表 key 完全一致,只需检查一张
|
||||||
|
return IROpCodeMappings.CMP_I32.containsKey(op);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回符合操作数位宽的比较 IROpCode。
|
||||||
|
*
|
||||||
|
* @param op 比较符号(==, !=, <, >, <=, >=)
|
||||||
|
* @param left 左操作数 AST
|
||||||
|
* @param right 右操作数 AST
|
||||||
|
*/
|
||||||
|
public static IROpCode cmpOp(String op, ExpressionNode left, ExpressionNode right) {
|
||||||
|
boolean useLong = isLongLiteral(left) || isLongLiteral(right);
|
||||||
|
Map<String, IROpCode> table = useLong ? IROpCodeMappings.CMP_L64
|
||||||
|
: IROpCodeMappings.CMP_I32;
|
||||||
|
return table.get(op);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------ 内部工具 ------------ */
|
||||||
|
|
||||||
|
private static boolean isLongLiteral(ExpressionNode node) {
|
||||||
|
if (node instanceof NumberLiteralNode n) {
|
||||||
|
String v = n.value();
|
||||||
|
return v.endsWith("L") || v.endsWith("l");
|
||||||
|
}
|
||||||
|
return false; // 变量暂不处理(后续可扩展符号表查询)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -12,99 +12,83 @@ import java.util.Map;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 表达式分析与运算符辅助工具类。
|
* 表达式分析与运算符辅助工具类。
|
||||||
* <p>
|
*
|
||||||
* 主要功能包括:
|
* <p>主要功能:</p>
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>字面量常量的解析与类型推断</li>
|
* <li>字面量常量的解析与类型推断</li>
|
||||||
* <li>自动匹配操作码</li>
|
* <li>自动匹配算术/比较操作码</li>
|
||||||
* <li>表达式类型合并与判定</li>
|
* <li>表达式类型合并与提升</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
*/
|
*/
|
||||||
public class ExpressionUtils {
|
public final class ExpressionUtils {
|
||||||
|
|
||||||
/** 用于存储默认的类型后缀(如函数返回类型),线程隔离。 */
|
private ExpressionUtils() {}
|
||||||
|
|
||||||
|
/* ────────────────── 线程级默认类型后缀 ────────────────── */
|
||||||
|
|
||||||
|
/** 默认类型后缀(如当前函数返回类型),线程隔离。 */
|
||||||
private static final ThreadLocal<Character> DEFAULT_SUFFIX =
|
private static final ThreadLocal<Character> DEFAULT_SUFFIX =
|
||||||
ThreadLocal.withInitial(() -> '\0');
|
ThreadLocal.withInitial(() -> '\0');
|
||||||
|
|
||||||
/**
|
public static void setDefaultSuffix(char suffix) { DEFAULT_SUFFIX.set(suffix); }
|
||||||
* 在进入函数 IR 构建前设置默认的类型后缀(比如函数返回类型)。
|
|
||||||
* @param suffix 默认后缀字符,如 'i', 'l', 'f', 'd' 等
|
|
||||||
*/
|
|
||||||
public static void setDefaultSuffix(char suffix) {
|
|
||||||
DEFAULT_SUFFIX.set(suffix);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
public static void clearDefaultSuffix() { DEFAULT_SUFFIX.set('\0'); }
|
||||||
* 在函数 IR 构建结束后清除默认后缀,避免影响后续分析。
|
|
||||||
*/
|
/* ───────────────────── 字面量 & 常量 ───────────────────── */
|
||||||
public static void clearDefaultSuffix() {
|
|
||||||
DEFAULT_SUFFIX.set('\0');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 解析整数字面量字符串,自动去除类型后缀(b/s/l/f/d/B/S/L/F/D),并转换为 int。
|
* 解析整数字面量字符串,自动去除类型后缀(b/s/l/f/d/B/S/L/F/D),并转换为 int。
|
||||||
*
|
|
||||||
* @param literal 字面量字符串,如 "123", "123l", "42B"
|
|
||||||
* @return 解析得到的 int 整数
|
|
||||||
*/
|
*/
|
||||||
public static int parseIntSafely(String literal) {
|
public static int parseIntSafely(String literal) {
|
||||||
// 去掉类型后缀,只保留数字部分
|
|
||||||
String digits = literal.replaceAll("[bslfdBSDLF]$", "");
|
String digits = literal.replaceAll("[bslfdBSDLF]$", "");
|
||||||
return Integer.parseInt(digits);
|
return Integer.parseInt(digits);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据数字字面量字符串自动判断类型,生成对应类型的 IRConstant。
|
* 根据数字字面量字符串自动判断类型,生成对应类型的 {@link IRConstant}。
|
||||||
* 支持 b/s/l/f/d 类型后缀与浮点格式,自动分配合适类型。
|
* 支持 b/s/l/f/d 后缀与浮点格式。
|
||||||
*
|
|
||||||
* @param ctx IR 编译上下文环境
|
|
||||||
* @param value 字面量字符串(如 "1", "2l", "3.14f", "5D")
|
|
||||||
* @return 生成的 IRConstant 对象,包含正确类型
|
|
||||||
*/
|
*/
|
||||||
public static IRConstant buildNumberConstant(IRContext ctx, String value) {
|
public static IRConstant buildNumberConstant(IRContext ctx, String value) {
|
||||||
char suffix = value.isEmpty() ? '\0' : Character.toLowerCase(value.charAt(value.length() - 1));
|
char suffix = value.isEmpty() ? '\0'
|
||||||
|
: Character.toLowerCase(value.charAt(value.length() - 1));
|
||||||
|
|
||||||
String digits = switch (suffix) {
|
String digits = switch (suffix) {
|
||||||
case 'b','s','l','f','d' -> value.substring(0, value.length() - 1);
|
case 'b','s','l','f','d' -> value.substring(0, value.length() - 1);
|
||||||
default -> {
|
default -> {
|
||||||
|
/* 如果字面量本身没有后缀,则回退到变量目标类型(如声明语句左值) */
|
||||||
if (ctx.getVarType() != null) {
|
if (ctx.getVarType() != null) {
|
||||||
final var receiverType = ctx.getVarType();
|
String t = ctx.getVarType();
|
||||||
switch (receiverType) {
|
suffix = switch (t) {
|
||||||
case "byte" -> suffix = 'b';
|
case "byte" -> 'b';
|
||||||
case "short" -> suffix = 's';
|
case "short" -> 's';
|
||||||
case "int" -> suffix = 'i';
|
case "int" -> 'i';
|
||||||
case "long" -> suffix = 'l';
|
case "long" -> 'l';
|
||||||
case "float" -> suffix = 'f';
|
case "float" -> 'f';
|
||||||
case "double" -> suffix = 'd';
|
case "double" -> 'd';
|
||||||
}
|
default -> '\0';
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
yield value;
|
yield value;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
// 根据类型后缀或数值格式创建常量
|
|
||||||
|
/* 创建常量 */
|
||||||
return switch (suffix) {
|
return switch (suffix) {
|
||||||
case 'b' -> new IRConstant(Byte.parseByte(digits));
|
case 'b' -> new IRConstant(Byte.parseByte(digits));
|
||||||
case 's' -> new IRConstant(Short.parseShort(digits));
|
case 's' -> new IRConstant(Short.parseShort(digits));
|
||||||
case 'l' -> new IRConstant(Long.parseLong(digits));
|
case 'l' -> new IRConstant(Long.parseLong(digits));
|
||||||
case 'f' -> new IRConstant(Float.parseFloat(digits));
|
case 'f' -> new IRConstant(Float.parseFloat(digits));
|
||||||
case 'd' -> new IRConstant(Double.parseDouble(digits));
|
case 'd' -> new IRConstant(Double.parseDouble(digits));
|
||||||
default -> looksLikeFloat(digits)
|
default -> looksLikeFloat(digits)
|
||||||
? new IRConstant(Double.parseDouble(digits))
|
? new IRConstant(Double.parseDouble(digits))
|
||||||
: new IRConstant(Integer.parseInt(digits));
|
: new IRConstant(Integer.parseInt(digits));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ────────────────────── 一元运算 ────────────────────── */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据表达式节点推断一元取负(-)运算应使用的操作码。
|
* 推断一元取负(-)运算应使用的 {@link IROpCode}。
|
||||||
*
|
|
||||||
* <p>优先级与 {@link #resolveOpCode} 使用的类型提升规则保持一致:</p>
|
|
||||||
* <ul>
|
|
||||||
* <li>字面量或标识符带显式后缀时,直接以后缀决定位宽;</li>
|
|
||||||
* <li>未显式指定时,默认使用 32 位整型 {@link IROpCode#NEG_I32}。</li>
|
|
||||||
* </ul>
|
|
||||||
*
|
|
||||||
* @param operand 一元取负运算的操作数
|
|
||||||
* @return 匹配的 {@link IROpCode}
|
|
||||||
*/
|
*/
|
||||||
public static IROpCode negOp(ExpressionNode operand) {
|
public static IROpCode negOp(ExpressionNode operand) {
|
||||||
char t = typeChar(operand);
|
char t = typeChar(operand);
|
||||||
@ -114,113 +98,82 @@ public class ExpressionUtils {
|
|||||||
case 'l' -> IROpCode.NEG_L64;
|
case 'l' -> IROpCode.NEG_L64;
|
||||||
case 'f' -> IROpCode.NEG_F32;
|
case 'f' -> IROpCode.NEG_F32;
|
||||||
case 'd' -> IROpCode.NEG_D64;
|
case 'd' -> IROpCode.NEG_D64;
|
||||||
default -> IROpCode.NEG_I32;
|
default -> IROpCode.NEG_I32; // '\0' 或 'i'
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* =================== 类型推断与操作符匹配 =================== */
|
/* ────────────────── 比较运算(已适配 long) ────────────────── */
|
||||||
|
|
||||||
/**
|
/** 判断给定字符串是否是比较运算符(==, !=, <, >, <=, >=)。 */
|
||||||
* 递归推断单个表达式节点的类型后缀(b/s/l/f/d)。
|
public static boolean isComparisonOperator(String op) {
|
||||||
* 对于二元表达式,将左右两侧的类型自动提升合并,遵循优先级顺序:d > f > l > s > b > '\0'。
|
return ComparisonUtils.isComparisonOperator(op);
|
||||||
*
|
|
||||||
* @param node 表达式节点
|
|
||||||
* @return 类型后缀字符,b/s/l/f/d 或 '\0'
|
|
||||||
*/
|
|
||||||
private static char typeChar(ExpressionNode node) {
|
|
||||||
// 字面量节点,直接判断最后一位
|
|
||||||
if (node instanceof NumberLiteralNode(String value)) {
|
|
||||||
char last = Character.toLowerCase(value.charAt(value.length() - 1));
|
|
||||||
return switch (last) {
|
|
||||||
case 'b', 's', 'l', 'f', 'd' -> last;
|
|
||||||
default -> looksLikeFloat(value) ? 'd' : '\0';
|
|
||||||
};
|
|
||||||
}
|
|
||||||
// 二元表达式,递归判断左右子节点
|
|
||||||
if (node instanceof BinaryExpressionNode bin) {
|
|
||||||
char l = typeChar(bin.left());
|
|
||||||
char r = typeChar(bin.right());
|
|
||||||
return maxTypeChar(l, r);
|
|
||||||
}
|
|
||||||
// 其他情况(如变量节点),暂不处理,默认返回 '\0'
|
|
||||||
return '\0';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 推断两个表达式节点合并后的类型后缀。
|
* 兼容旧调用:仅凭操作符返回 <em>int32</em> 比较指令。
|
||||||
* 返回优先级更高的类型后缀字符。
|
|
||||||
*
|
|
||||||
* @param left 左表达式节点
|
|
||||||
* @param right 右表达式节点
|
|
||||||
* @return 合并后类型的后缀字符
|
|
||||||
*/
|
*/
|
||||||
|
public static IROpCode cmpOp(String op) {
|
||||||
|
return IROpCodeMappings.CMP_I32.get(op); // 旧逻辑:一律 i32
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 推荐调用:根据左右表达式类型自动选择 int / long 比较指令。
|
||||||
|
*/
|
||||||
|
public static IROpCode cmpOp(String op, ExpressionNode left, ExpressionNode right) {
|
||||||
|
return ComparisonUtils.cmpOp(op, left, right);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ──────────────── 类型推断 & 算术操作码匹配 ──────────────── */
|
||||||
|
|
||||||
|
/** 递归推断单个表达式节点的类型后缀(b/s/i/l/f/d)。 */
|
||||||
|
private static char typeChar(ExpressionNode node) {
|
||||||
|
if (node instanceof NumberLiteralNode(String value)) {
|
||||||
|
char last = Character.toLowerCase(value.charAt(value.length() - 1));
|
||||||
|
return switch (last) {
|
||||||
|
case 'b','s','i','l','f','d' -> last;
|
||||||
|
default -> looksLikeFloat(value) ? 'd' : '\0';
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (node instanceof BinaryExpressionNode bin) {
|
||||||
|
return maxTypeChar(typeChar(bin.left()), typeChar(bin.right()));
|
||||||
|
}
|
||||||
|
return '\0'; // 变量等暂不处理
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 合并两侧表达式的类型后缀。 */
|
||||||
public static char resolveSuffix(ExpressionNode left, ExpressionNode right) {
|
public static char resolveSuffix(ExpressionNode left, ExpressionNode right) {
|
||||||
return maxTypeChar(typeChar(left), typeChar(right));
|
return maxTypeChar(typeChar(left), typeChar(right));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** 类型优先级:d > f > l > i > s > b > '\0' */
|
||||||
* 在两个类型后缀中选取精度更高的一个。
|
|
||||||
* 优先级依次为:d > f > l > s > b > '\0'
|
|
||||||
*
|
|
||||||
* @param l 左类型后缀
|
|
||||||
* @param r 右类型后缀
|
|
||||||
* @return 更高优先级的类型后缀字符
|
|
||||||
*/
|
|
||||||
private static char maxTypeChar(char l, char r) {
|
private static char maxTypeChar(char l, char r) {
|
||||||
if (l == 'd' || r == 'd') return 'd';
|
if (l == 'd' || r == 'd') return 'd';
|
||||||
if (l == 'f' || r == 'f') return 'f';
|
if (l == 'f' || r == 'f') return 'f';
|
||||||
if (l == 'l' || r == 'l') return 'l';
|
if (l == 'l' || r == 'l') return 'l';
|
||||||
|
if (l == 'i' || r == 'i') return 'i';
|
||||||
if (l == 's' || r == 's') return 's';
|
if (l == 's' || r == 's') return 's';
|
||||||
if (l == 'b' || r == 'b') return 'b';
|
if (l == 'b' || r == 'b') return 'b';
|
||||||
return '\0';
|
return '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 判断给定字符串是否为比较运算符(如 >, <, == 等)。
|
* 根据操作符和两侧表达式选择正确的算术 {@link IROpCode}。
|
||||||
*
|
|
||||||
* @param op 操作符字符串
|
|
||||||
* @return 如果是比较操作符返回 true,否则返回 false
|
|
||||||
*/
|
|
||||||
public static boolean isComparisonOperator(String op) {
|
|
||||||
return IROpCodeMappings.CMP.containsKey(op);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取比较操作符对应的中间表示操作码(IROpCode)。
|
|
||||||
*
|
|
||||||
* @param op 比较操作符字符串
|
|
||||||
* @return 对应的 IROpCode,如果不存在则返回 null
|
|
||||||
*/
|
|
||||||
public static IROpCode cmpOp(String op) {
|
|
||||||
return IROpCodeMappings.CMP.get(op);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据操作符和两侧表达式自动选择正确的 IROpCode。
|
|
||||||
* 首先根据参与表达式类型推断后缀,若无法推断则回退到函数默认类型,
|
|
||||||
* 还无法推断则默认使用 i32(32位整型)。
|
|
||||||
*
|
|
||||||
* @param op 操作符字符串,如 "+"
|
|
||||||
* @param left 左侧表达式节点
|
|
||||||
* @param right 右侧表达式节点
|
|
||||||
* @return 匹配的 IROpCode,如果不存在则返回 null
|
|
||||||
*/
|
*/
|
||||||
public static IROpCode resolveOpCode(String op,
|
public static IROpCode resolveOpCode(String op,
|
||||||
ExpressionNode left,
|
ExpressionNode left,
|
||||||
ExpressionNode right) {
|
ExpressionNode right) {
|
||||||
|
|
||||||
/* 1) 尝试从参与者常量字面量推断 */
|
/* 1. 尝试根据字面量推断 */
|
||||||
char suffix = resolveSuffix(left, right);
|
char suffix = resolveSuffix(left, right);
|
||||||
|
|
||||||
/* 2) 若无法推断,退回到函数返回类型(DEFAULT_SUFFIX) */
|
/* 2. 若失败则使用函数级默认类型 */
|
||||||
if (suffix == '\0') {
|
if (suffix == '\0') suffix = DEFAULT_SUFFIX.get();
|
||||||
suffix = DEFAULT_SUFFIX.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 3) 再次失败则默认为 i32 */
|
/* 3. 仍失败则默认为 int32 */
|
||||||
Map<String, IROpCode> table = switch (suffix) {
|
Map<String, IROpCode> table = switch (suffix) {
|
||||||
case 'b' -> IROpCodeMappings.OP_I8;
|
case 'b' -> IROpCodeMappings.OP_B8;
|
||||||
case 's' -> IROpCodeMappings.OP_I16;
|
case 's' -> IROpCodeMappings.OP_S16;
|
||||||
|
case 'i' -> IROpCodeMappings.OP_I32;
|
||||||
case 'l' -> IROpCodeMappings.OP_L64;
|
case 'l' -> IROpCodeMappings.OP_L64;
|
||||||
case 'f' -> IROpCodeMappings.OP_F32;
|
case 'f' -> IROpCodeMappings.OP_F32;
|
||||||
case 'd' -> IROpCodeMappings.OP_D64;
|
case 'd' -> IROpCodeMappings.OP_D64;
|
||||||
@ -230,13 +183,12 @@ public class ExpressionUtils {
|
|||||||
return table.get(op);
|
return table.get(op);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/* ────────────────────────── 工具 ───────────────────────── */
|
||||||
* 判断字符串是否为浮点数形式(即包含小数点或科学计数法 e/E)。
|
|
||||||
*
|
/** 是否像浮点字面量(包含 '.' 或 e/E)。 */
|
||||||
* @param digits 数字字符串
|
|
||||||
* @return 如果看起来像浮点数则返回 true,否则返回 false
|
|
||||||
*/
|
|
||||||
private static boolean looksLikeFloat(String digits) {
|
private static boolean looksLikeFloat(String digits) {
|
||||||
return digits.indexOf('.') >= 0 || digits.indexOf('e') >= 0 || digits.indexOf('E') >= 0;
|
return digits.indexOf('.') >= 0
|
||||||
|
|| digits.indexOf('e') >= 0
|
||||||
|
|| digits.indexOf('E') >= 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,13 +8,21 @@ import java.util.Map;
|
|||||||
* IR 操作码辅助工具。
|
* IR 操作码辅助工具。
|
||||||
*/
|
*/
|
||||||
public class IROpCodeUtils {
|
public class IROpCodeUtils {
|
||||||
private static final Map<IROpCode, IROpCode> INVERT = Map.of(
|
private static final Map<IROpCode, IROpCode> INVERT = Map.ofEntries(
|
||||||
IROpCode.CMP_LEQ, IROpCode.CMP_LNE,
|
// 32-bit
|
||||||
IROpCode.CMP_LNE, IROpCode.CMP_LEQ,
|
Map.entry(IROpCode.CMP_EQ, IROpCode.CMP_NE),
|
||||||
IROpCode.CMP_LLT, IROpCode.CMP_LGE,
|
Map.entry(IROpCode.CMP_NE, IROpCode.CMP_EQ),
|
||||||
IROpCode.CMP_LGE, IROpCode.CMP_LLT,
|
Map.entry(IROpCode.CMP_LT, IROpCode.CMP_GE),
|
||||||
IROpCode.CMP_LGT, IROpCode.CMP_LLE,
|
Map.entry(IROpCode.CMP_GE, IROpCode.CMP_LT),
|
||||||
IROpCode.CMP_LLE, IROpCode.CMP_LGT
|
Map.entry(IROpCode.CMP_GT, IROpCode.CMP_LE),
|
||||||
|
Map.entry(IROpCode.CMP_LE, IROpCode.CMP_GT),
|
||||||
|
// 64-bit
|
||||||
|
Map.entry(IROpCode.CMP_LEQ, IROpCode.CMP_LNE),
|
||||||
|
Map.entry(IROpCode.CMP_LNE, IROpCode.CMP_LEQ),
|
||||||
|
Map.entry(IROpCode.CMP_LLT, IROpCode.CMP_LGE),
|
||||||
|
Map.entry(IROpCode.CMP_LGE, IROpCode.CMP_LLT),
|
||||||
|
Map.entry(IROpCode.CMP_LGT, IROpCode.CMP_LLE),
|
||||||
|
Map.entry(IROpCode.CMP_LLE, IROpCode.CMP_LGT)
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user