!32 feat: 补充基本数值类型转换指令

Merge pull request !32 from zhangxun/feature/full-type-conversion-support
This commit is contained in:
Luke 2025-07-11 02:37:18 +00:00 committed by Gitee
commit 30573a4e45
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
48 changed files with 1838 additions and 554 deletions

View File

@ -3,7 +3,7 @@
<option name="ALTERNATIVE_JRE_PATH" value="graalvm-ce-23" />
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" />
<module name="Snow" />
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo11 -o target/Demo11" />
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo11 -o target/Demo11" />
<extension name="coverage">
<pattern>
<option name="PATTERN" value="org.jcnc.snow.compiler.parser.preprocessor.lexer.impl.api.*" />

10
.run/Demo13.run.xml Normal file
View File

@ -0,0 +1,10 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Demo13" type="Application" factoryName="Application" folderName="Demo">
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" />
<module name="Snow" />
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo13 -o target/Demo13" />
<method v="2">
<option name="Make" enabled="true" />
</method>
</configuration>
</component>

View File

@ -3,6 +3,9 @@
<toRun name="Demo1" type="Application" />
<toRun name="Demo10" type="Application" />
<toRun name="Demo11" type="Application" />
<toRun name="Demo11" type="Application" />
<toRun name="Demo12" type="Application" />
<toRun name="Demo13" type="Application" />
<toRun name="Demo2" type="Application" />
<toRun name="Demo3" type="Application" />
<toRun name="Demo4" type="Application" />

View File

@ -0,0 +1,69 @@
module: Main
function: main
return_type: int
body:
5 == 7
5 == 7s
5 == 7b
5 == 7l
5 == 7f
5 == 7d
5b == 5b
5b == 5s
5b == 5l
5b == 5f
5b == 5d
5s == 5s
5s == 5l
5s == 5f
5s == 5d
5l == 5l
5l == 5f
5l == 5d
5f == 5f
5f == 5d
5d == 5d
declare b: byte = 8b
declare s: short = 8s
declare i: int = 8
declare l: long = 8l
declare f: float = 8f
declare d: double = 8d
b == b
b == s
b == i
b == l
b == f
b == d
s == s
s == i
s == l
s == f
s == d
i == i
i == l
i == f
i == d
l == l
l == f
l == d
f == f
f == d
d == d
return 65537
end body
end function
end module

View File

@ -4,6 +4,7 @@ import org.jcnc.snow.compiler.backend.builder.VMProgramBuilder;
import org.jcnc.snow.compiler.backend.core.InstructionGenerator;
import org.jcnc.snow.compiler.backend.utils.IROpCodeMapper;
import org.jcnc.snow.compiler.backend.utils.OpHelper;
import org.jcnc.snow.compiler.backend.utils.TypePromoteUtils;
import org.jcnc.snow.compiler.ir.core.IRValue;
import org.jcnc.snow.compiler.ir.instruction.BinaryOperationInstruction;
import org.jcnc.snow.compiler.ir.value.IRConstant;
@ -41,38 +42,12 @@ public class BinaryOpGenerator implements InstructionGenerator<BinaryOperationIn
return fn + "$" + tag + "$" + COUNTER.getAndIncrement();
}
/**
* 类型优先级D &gt; F &gt; L &gt; I &gt; S &gt; B
*/
private static int rank(char p) {
return switch (p) {
case 'D' -> 6;
case 'F' -> 5;
case 'L' -> 4;
case 'I' -> 3;
case 'S' -> 2;
case 'B' -> 1;
default -> 0;
};
}
/**
* 返回优先级更高的类型字符
*/
private static char promote(char a, char b) {
return rank(a) >= rank(b) ? a : b;
}
/**
* 单字符转字符串
*/
private static String str(char p) {
return String.valueOf(p);
}
/**
* 判断常量值是否等于 0
* 仅支持 Java 原生数值类型
*
* @param v 常量值
* @return 等于 0 返回 true否则 false
*/
private static boolean isZero(Object v) {
if (v == null) return false;
@ -87,31 +62,6 @@ public class BinaryOpGenerator implements InstructionGenerator<BinaryOperationIn
};
}
/**
* 获取从类型 {@code from} {@code to} 的转换指令名
* 相同类型或无显式转换需求返回 {@code null}
*/
private static String convert(char from, char to) {
if (from == to) return null;
return switch ("" + from + to) {
case "IL" -> "I2L";
case "ID" -> "I2D";
case "IF" -> "I2F";
case "LI" -> "L2I";
case "LD" -> "L2D";
case "LF" -> "L2F";
case "FI" -> "F2I";
case "FL" -> "F2L";
case "FD" -> "F2D";
case "DI" -> "D2I";
case "DL" -> "D2L";
case "DF" -> "D2F";
case "SI" -> "S2I";
case "BI" -> "B2I";
default -> null;
};
}
/* -------------------- 接口实现 -------------------- */
@Override
@ -161,16 +111,16 @@ public class BinaryOpGenerator implements InstructionGenerator<BinaryOperationIn
char lType = out.getSlotType(lSlot); // 未登记默认 'I'
char rType = out.getSlotType(rSlot);
char tType = promote(lType, rType); // 类型提升结果
String tPre = str(tType);
char tType = TypePromoteUtils.promote(lType, rType); // 类型提升结果
String tPre = TypePromoteUtils.str(tType);
/* ---------- 2. 加载并做类型转换 ---------- */
out.emit(OpHelper.opcode(str(lType) + "_LOAD") + " " + lSlot);
String cvt = convert(lType, tType);
out.emit(OpHelper.opcode(TypePromoteUtils.str(lType) + "_LOAD") + " " + lSlot);
String cvt = TypePromoteUtils.convert(lType, tType);
if (cvt != null) out.emit(OpHelper.opcode(cvt));
out.emit(OpHelper.opcode(str(rType) + "_LOAD") + " " + rSlot);
cvt = convert(rType, tType);
out.emit(OpHelper.opcode(TypePromoteUtils.str(rType) + "_LOAD") + " " + rSlot);
cvt = TypePromoteUtils.convert(rType, tType);
if (cvt != null) out.emit(OpHelper.opcode(cvt));
/* ---------- 3. 区分算术 / 比较 ---------- */
@ -186,7 +136,7 @@ public class BinaryOpGenerator implements InstructionGenerator<BinaryOperationIn
}
/* === 3-B. CMP_* —— 生成布尔结果 === */
String branchOp = OpHelper.opcode(IROpCodeMapper.toVMOp(ins.op())); // IC_E / IC_NE
String branchOp = OpHelper.opcode(IROpCodeMapper.toVMOp(ins.op())); // I_CE / I_CNE
String lblTrue = fresh(currentFn, "true");
String lblEnd = fresh(currentFn, "end");

View File

@ -4,20 +4,21 @@ import org.jcnc.snow.compiler.backend.utils.IROpCodeMapper;
import org.jcnc.snow.compiler.backend.utils.OpHelper;
import org.jcnc.snow.compiler.backend.builder.VMProgramBuilder;
import org.jcnc.snow.compiler.backend.core.InstructionGenerator;
import org.jcnc.snow.compiler.backend.utils.TypePromoteUtils;
import org.jcnc.snow.compiler.ir.instruction.IRCompareJumpInstruction;
import org.jcnc.snow.compiler.ir.value.IRVirtualRegister;
import java.util.Map;
/**
* <b>条件比较跳转指令生成器</b>
* 条件比较跳转指令生成器
* <p>
* 该类实现了 {@link InstructionGenerator} 接口
* 负责将 IR 中的 {@link IRCompareJumpInstruction}条件比较并跳转指令
* 转换为目标虚拟机VM可执行的指令序列
* </p>
*
* <b>主要功能</b>
* 主要功能
* <ul>
* <li>根据 IR 比较指令左右操作数的类型自动进行类型提升与转换</li>
* <li>生成相应的 VM 加载类型转换比较与跳转指令</li>
@ -36,85 +37,6 @@ public class CmpJumpGenerator implements InstructionGenerator<IRCompareJumpInstr
return IRCompareJumpInstruction.class;
}
/**
* <b>类型宽度优先级</b>D > F > L > I > S > B
* <ul>
* <li>Ddouble6</li>
* <li>Ffloat5</li>
* <li>Llong4</li>
* <li>Iint3</li>
* <li>Sshort2</li>
* <li>Bbyte1</li>
* <li>未识别类型0</li>
* </ul>
*
* @param p 类型标记字符
* @return 优先级数值越大类型越宽
*/
private static int rank(char p) {
return switch (p) {
case 'D' -> 6;
case 'F' -> 5;
case 'L' -> 4;
case 'I' -> 3;
case 'S' -> 2;
case 'B' -> 1;
default -> 0;
};
}
/**
* 返回更的公共类型即优先级高的类型
*
* @param a 类型标记字符 1
* @param b 类型标记字符 2
* @return 宽度更高的类型标记字符
*/
private static char promote(char a, char b) {
return rank(a) >= rank(b) ? a : b;
}
/**
* 单字符类型标记转字符串
*
* @param p 类型标记字符
* @return 类型字符串
*/
private static String str(char p) {
return String.valueOf(p);
}
/**
* 获取 {@code from to} 的类型转换指令名如不需转换则返回 {@code null}
* <p>
* 仅覆盖目前常见的整数与浮点类型提升与转换后续有新类型可补充
* </p>
*
* @param from 源类型标记字符
* @param to 目标类型标记字符
* @return 转换指令名L2I无转换返回 {@code null}
*/
private static String convert(char from, char to) {
if (from == to) return null;
return switch ("" + from + to) {
case "IL" -> "I2L";
case "ID" -> "I2D";
case "IF" -> "I2F";
case "LI" -> "L2I";
case "LD" -> "L2D";
case "LF" -> "L2F";
case "FI" -> "F2I";
case "FL" -> "F2L";
case "FD" -> "F2D";
case "DI" -> "D2I";
case "DL" -> "D2L";
case "DF" -> "D2F";
case "SI" -> "S2I";
case "BI" -> "B2I";
default -> null;
};
}
/**
* 生成 IR 条件比较跳转指令的 VM 指令序列
* <ol>
@ -138,21 +60,21 @@ public class CmpJumpGenerator implements InstructionGenerator<IRCompareJumpInstr
// 1. 获取左右操作数的槽位与静态类型
int leftSlot = slotMap.get(ins.left());
int rightSlot = slotMap.get(ins.right());
char lType = out.getSlotType(leftSlot); // 若未登记则默认 'I'
char lType = out.getSlotType(leftSlot);
char rType = out.getSlotType(rightSlot);
char tType = promote(lType, rType); // 公共类型提升
char tType = TypePromoteUtils.promote(lType, rType); // 公共类型提升
// 2. 加载左右操作数并按需类型转换
// 左操作数
out.emit(OpHelper.opcode(str(lType) + "_LOAD") + " " + leftSlot);
String cvt = convert(lType, tType);
out.emit(OpHelper.opcode(TypePromoteUtils.str(lType) + "_LOAD") + " " + leftSlot);
String cvt = TypePromoteUtils.convert(lType, tType);
if (cvt != null) {
out.emit(OpHelper.opcode(cvt));
}
// 右操作数
out.emit(OpHelper.opcode(str(rType) + "_LOAD") + " " + rightSlot);
cvt = convert(rType, tType);
out.emit(OpHelper.opcode(TypePromoteUtils.str(rType) + "_LOAD") + " " + rightSlot);
cvt = TypePromoteUtils.convert(rType, tType);
if (cvt != null) {
out.emit(OpHelper.opcode(cvt));
}
@ -160,12 +82,12 @@ public class CmpJumpGenerator implements InstructionGenerator<IRCompareJumpInstr
// 3. 选择正确的比较指令前缀
String cmpOp = IROpCodeMapper.toVMOp(ins.op());
/*
* 指令前缀 int 类型要用 IC_*, long 类型要用 LC_*
* 指令前缀 int 类型要用 I_C*, long 类型要用 L_C*
*/
if (tType == 'I' && cmpOp.startsWith("LC_")) {
cmpOp = "IC_" + cmpOp.substring(3);
} else if (tType == 'L' && cmpOp.startsWith("IC_")) {
cmpOp = "LC_" + cmpOp.substring(3);
if (tType == 'I' && cmpOp.startsWith("L_C")) {
cmpOp = "I_C" + cmpOp.substring(3);
} else if (tType == 'L' && cmpOp.startsWith("I_C")) {
cmpOp = "L_C" + cmpOp.substring(3);
}
// 4. 发出比较与跳转指令

View File

@ -82,34 +82,66 @@ public final class IROpCodeMapper {
opcodeMap.put(IROpCode.NEG_D64, "D_NEG");
// 比较运算映射
// 整形32位比较运算映射
opcodeMap.put(IROpCode.CMP_IEQ, "IC_E"); // 相等
opcodeMap.put(IROpCode.CMP_INE, "IC_NE"); // 不等
opcodeMap.put(IROpCode.CMP_ILT, "IC_L"); // 小于
opcodeMap.put(IROpCode.CMP_IGT, "IC_G"); // 大于
opcodeMap.put(IROpCode.CMP_ILE, "IC_LE"); // 小于等于
opcodeMap.put(IROpCode.CMP_IGE, "IC_GE"); // 大于等于
// 8位整数比较运算映射
opcodeMap.put(IROpCode.CMP_BEQ, "B_CE"); // 相等
opcodeMap.put(IROpCode.CMP_BNE, "B_CNE"); // 不等
opcodeMap.put(IROpCode.CMP_BLT, "B_CL"); // 小于
opcodeMap.put(IROpCode.CMP_BGT, "B_CG"); // 大于
opcodeMap.put(IROpCode.CMP_BLE, "B_CLE"); // 小于等于
opcodeMap.put(IROpCode.CMP_BGE, "B_CGE"); // 大于等于
// 整形64位比较运算映射
opcodeMap.put(IROpCode.CMP_LEQ, "LC_E"); // 相等
opcodeMap.put(IROpCode.CMP_LNE, "LC_NE"); // 不等
opcodeMap.put(IROpCode.CMP_LLT, "LC_L"); // 小于
opcodeMap.put(IROpCode.CMP_LGT, "LC_G"); // 大于
opcodeMap.put(IROpCode.CMP_LLE, "LC_LE"); // 小于等于
opcodeMap.put(IROpCode.CMP_LGE, "LC_GE"); // 大于等于
// 16位整数比较运算映射
opcodeMap.put(IROpCode.CMP_SEQ, "S_CE"); // 相等
opcodeMap.put(IROpCode.CMP_SNE, "S_CNE"); // 不等
opcodeMap.put(IROpCode.CMP_SLT, "S_CL"); // 小于
opcodeMap.put(IROpCode.CMP_SGT, "S_CG"); // 大于
opcodeMap.put(IROpCode.CMP_SLE, "S_CLE"); // 小于等于
opcodeMap.put(IROpCode.CMP_SGE, "S_CGE"); // 大于等于
// 32位整数比较运算映射
opcodeMap.put(IROpCode.CMP_IEQ, "I_CE"); // 相等
opcodeMap.put(IROpCode.CMP_INE, "I_CNE"); // 不等
opcodeMap.put(IROpCode.CMP_ILT, "I_CL"); // 小于
opcodeMap.put(IROpCode.CMP_IGT, "I_CG"); // 大于
opcodeMap.put(IROpCode.CMP_ILE, "I_CLE"); // 小于等于
opcodeMap.put(IROpCode.CMP_IGE, "I_CGE"); // 大于等于
// 64位整数比较运算映射
opcodeMap.put(IROpCode.CMP_LEQ, "L_CE"); // 相等
opcodeMap.put(IROpCode.CMP_LNE, "L_CNE"); // 不等
opcodeMap.put(IROpCode.CMP_LLT, "L_CL"); // 小于
opcodeMap.put(IROpCode.CMP_LGT, "L_CG"); // 大于
opcodeMap.put(IROpCode.CMP_LLE, "L_CLE"); // 小于等于
opcodeMap.put(IROpCode.CMP_LGE, "L_CGE"); // 大于等于
// 32位浮点比较运算映射
opcodeMap.put(IROpCode.CMP_FEQ, "F_CE"); // 相等
opcodeMap.put(IROpCode.CMP_FNE, "F_CNE"); // 不等
opcodeMap.put(IROpCode.CMP_FLT, "F_CL"); // 小于
opcodeMap.put(IROpCode.CMP_FGT, "F_CG"); // 大于
opcodeMap.put(IROpCode.CMP_FLE, "F_CLE"); // 小于等于
opcodeMap.put(IROpCode.CMP_FGE, "F_CGE"); // 大于等于
// 64位浮点比较运算映射
opcodeMap.put(IROpCode.CMP_DEQ, "D_CE"); // 相等
opcodeMap.put(IROpCode.CMP_DNE, "D_CNE"); // 不等
opcodeMap.put(IROpCode.CMP_DLT, "D_CL"); // 小于
opcodeMap.put(IROpCode.CMP_DGT, "D_CG"); // 大于
opcodeMap.put(IROpCode.CMP_DLE, "D_CLE"); // 小于等于
opcodeMap.put(IROpCode.CMP_DGE, "D_CGE"); // 大于等于
// 加载与存储
opcodeMap.put(IROpCode.LOAD, "I_LOAD"); // 加载
opcodeMap.put(IROpCode.STORE, "I_STORE"); // 存储
opcodeMap.put(IROpCode.CONST, "I_PUSH"); // 常量入栈
opcodeMap.put(IROpCode.LOAD, "I_LOAD"); // 加载
opcodeMap.put(IROpCode.STORE, "I_STORE"); // 存储
opcodeMap.put(IROpCode.CONST, "I_PUSH"); // 常量入栈
// 跳转与标签
opcodeMap.put(IROpCode.JUMP, "JMP"); // 无条件跳转
opcodeMap.put(IROpCode.LABEL, "LABEL"); // 标签
opcodeMap.put(IROpCode.JUMP, "JMP"); // 无条件跳转
opcodeMap.put(IROpCode.LABEL, "LABEL"); // 标签
// 函数相关
opcodeMap.put(IROpCode.CALL, "CALL"); // 调用
opcodeMap.put(IROpCode.RET, "RET"); // 返回
opcodeMap.put(IROpCode.CALL, "CALL"); // 调用
opcodeMap.put(IROpCode.RET, "RET"); // 返回
}
/**

View File

@ -29,108 +29,154 @@ public final class OpHelper {
static {
Map<String, String> map = new HashMap<>();
map.put("I_ADD", Integer.toString(VMOpCode.I_ADD));
map.put("I_SUB", Integer.toString(VMOpCode.I_SUB));
map.put("I_MUL", Integer.toString(VMOpCode.I_MUL));
map.put("I_DIV", Integer.toString(VMOpCode.I_DIV));
map.put("I_MOD", Integer.toString(VMOpCode.I_MOD));
map.put("I_INC", Integer.toString(VMOpCode.I_INC));
map.put("I_NEG", Integer.toString(VMOpCode.I_NEG));
map.put("L_ADD", Integer.toString(VMOpCode.L_ADD));
map.put("L_SUB", Integer.toString(VMOpCode.L_SUB));
map.put("L_MUL", Integer.toString(VMOpCode.L_MUL));
map.put("L_DIV", Integer.toString(VMOpCode.L_DIV));
map.put("L_MOD", Integer.toString(VMOpCode.L_MOD));
map.put("L_INC", Integer.toString(VMOpCode.L_INC));
map.put("L_NEG", Integer.toString(VMOpCode.L_NEG));
map.put("S_ADD", Integer.toString(VMOpCode.S_ADD));
map.put("S_SUB", Integer.toString(VMOpCode.S_SUB));
map.put("S_MUL", Integer.toString(VMOpCode.S_MUL));
map.put("S_DIV", Integer.toString(VMOpCode.S_DIV));
map.put("S_MOD", Integer.toString(VMOpCode.S_MOD));
map.put("S_INC", Integer.toString(VMOpCode.S_INC));
map.put("S_NEG", Integer.toString(VMOpCode.S_NEG));
map.put("B_ADD", Integer.toString(VMOpCode.B_ADD));
map.put("B_SUB", Integer.toString(VMOpCode.B_SUB));
map.put("B_MUL", Integer.toString(VMOpCode.B_MUL));
map.put("B_DIV", Integer.toString(VMOpCode.B_DIV));
map.put("B_MOD", Integer.toString(VMOpCode.B_MOD));
map.put("B_INC", Integer.toString(VMOpCode.B_INC));
map.put("B_NEG", Integer.toString(VMOpCode.B_NEG));
map.put("D_ADD", Integer.toString(VMOpCode.D_ADD));
map.put("D_SUB", Integer.toString(VMOpCode.D_SUB));
map.put("D_MUL", Integer.toString(VMOpCode.D_MUL));
map.put("D_DIV", Integer.toString(VMOpCode.D_DIV));
map.put("D_MOD", Integer.toString(VMOpCode.D_MOD));
map.put("D_NEG", Integer.toString(VMOpCode.D_NEG));
map.put("B_INC", Integer.toString(VMOpCode.B_INC));
map.put("B_AND", Integer.toString(VMOpCode.B_AND));
map.put("B_OR", Integer.toString(VMOpCode.B_OR));
map.put("B_XOR", Integer.toString(VMOpCode.B_XOR));
map.put("B_PUSH", Integer.toString(VMOpCode.B_PUSH));
map.put("B_LOAD", Integer.toString(VMOpCode.B_LOAD));
map.put("B_STORE", Integer.toString(VMOpCode.B_STORE));
map.put("B_CE", Integer.toString(VMOpCode.B_CE));
map.put("B_CNE", Integer.toString(VMOpCode.B_CNE));
map.put("B_CG", Integer.toString(VMOpCode.B_CG));
map.put("B_CGE", Integer.toString(VMOpCode.B_CGE));
map.put("B_CL", Integer.toString(VMOpCode.B_CL));
map.put("B_CLE", Integer.toString(VMOpCode.B_CLE));
map.put("S_ADD", Integer.toString(VMOpCode.S_ADD));
map.put("S_SUB", Integer.toString(VMOpCode.S_SUB));
map.put("S_MUL", Integer.toString(VMOpCode.S_MUL));
map.put("S_DIV", Integer.toString(VMOpCode.S_DIV));
map.put("S_MOD", Integer.toString(VMOpCode.S_MOD));
map.put("S_NEG", Integer.toString(VMOpCode.S_NEG));
map.put("S_INC", Integer.toString(VMOpCode.S_INC));
map.put("S_AND", Integer.toString(VMOpCode.S_AND));
map.put("S_OR", Integer.toString(VMOpCode.S_OR));
map.put("S_XOR", Integer.toString(VMOpCode.S_XOR));
map.put("S_PUSH", Integer.toString(VMOpCode.S_PUSH));
map.put("S_LOAD", Integer.toString(VMOpCode.S_LOAD));
map.put("S_STORE", Integer.toString(VMOpCode.S_STORE));
map.put("S_CE", Integer.toString(VMOpCode.S_CE));
map.put("S_CNE", Integer.toString(VMOpCode.S_CNE));
map.put("S_CG", Integer.toString(VMOpCode.S_CG));
map.put("S_CGE", Integer.toString(VMOpCode.S_CGE));
map.put("S_CL", Integer.toString(VMOpCode.S_CL));
map.put("S_CLE", Integer.toString(VMOpCode.S_CLE));
map.put("I_ADD", Integer.toString(VMOpCode.I_ADD));
map.put("I_SUB", Integer.toString(VMOpCode.I_SUB));
map.put("I_MUL", Integer.toString(VMOpCode.I_MUL));
map.put("I_DIV", Integer.toString(VMOpCode.I_DIV));
map.put("I_MOD", Integer.toString(VMOpCode.I_MOD));
map.put("I_NEG", Integer.toString(VMOpCode.I_NEG));
map.put("I_INC", Integer.toString(VMOpCode.I_INC));
map.put("I_AND", Integer.toString(VMOpCode.I_AND));
map.put("I_OR", Integer.toString(VMOpCode.I_OR));
map.put("I_XOR", Integer.toString(VMOpCode.I_XOR));
map.put("I_PUSH", Integer.toString(VMOpCode.I_PUSH));
map.put("I_LOAD", Integer.toString(VMOpCode.I_LOAD));
map.put("I_STORE", Integer.toString(VMOpCode.I_STORE));
map.put("I_CE", Integer.toString(VMOpCode.I_CE));
map.put("I_CNE", Integer.toString(VMOpCode.I_CNE));
map.put("I_CG", Integer.toString(VMOpCode.I_CG));
map.put("I_CGE", Integer.toString(VMOpCode.I_CGE));
map.put("I_CL", Integer.toString(VMOpCode.I_CL));
map.put("I_CLE", Integer.toString(VMOpCode.I_CLE));
map.put("L_ADD", Integer.toString(VMOpCode.L_ADD));
map.put("L_SUB", Integer.toString(VMOpCode.L_SUB));
map.put("L_MUL", Integer.toString(VMOpCode.L_MUL));
map.put("L_DIV", Integer.toString(VMOpCode.L_DIV));
map.put("L_MOD", Integer.toString(VMOpCode.L_MOD));
map.put("L_NEG", Integer.toString(VMOpCode.L_NEG));
map.put("L_INC", Integer.toString(VMOpCode.L_INC));
map.put("L_AND", Integer.toString(VMOpCode.L_AND));
map.put("L_OR", Integer.toString(VMOpCode.L_OR));
map.put("L_XOR", Integer.toString(VMOpCode.L_XOR));
map.put("L_PUSH", Integer.toString(VMOpCode.L_PUSH));
map.put("L_LOAD", Integer.toString(VMOpCode.L_LOAD));
map.put("L_STORE", Integer.toString(VMOpCode.L_STORE));
map.put("L_CE", Integer.toString(VMOpCode.L_CE));
map.put("L_CNE", Integer.toString(VMOpCode.L_CNE));
map.put("L_CG", Integer.toString(VMOpCode.L_CG));
map.put("L_CGE", Integer.toString(VMOpCode.L_CGE));
map.put("L_CL", Integer.toString(VMOpCode.L_CL));
map.put("L_CLE", Integer.toString(VMOpCode.L_CLE));
map.put("F_ADD", Integer.toString(VMOpCode.F_ADD));
map.put("F_SUB", Integer.toString(VMOpCode.F_SUB));
map.put("F_MUL", Integer.toString(VMOpCode.F_MUL));
map.put("F_DIV", Integer.toString(VMOpCode.F_DIV));
map.put("F_MOD", Integer.toString(VMOpCode.F_MOD));
map.put("F_NEG", Integer.toString(VMOpCode.F_NEG));
map.put("D_INC", Integer.toString(VMOpCode.D_INC));
map.put("F_INC", Integer.toString(VMOpCode.F_INC));
map.put("I2L", Integer.toString(VMOpCode.I2L));
map.put("I2S", Integer.toString(VMOpCode.I2S));
map.put("F_PUSH", Integer.toString(VMOpCode.F_PUSH));
map.put("F_LOAD", Integer.toString(VMOpCode.F_LOAD));
map.put("F_STORE", Integer.toString(VMOpCode.F_STORE));
map.put("F_CE", Integer.toString(VMOpCode.F_CE));
map.put("F_CNE", Integer.toString(VMOpCode.F_CNE));
map.put("F_CG", Integer.toString(VMOpCode.F_CG));
map.put("F_CGE", Integer.toString(VMOpCode.F_CGE));
map.put("F_CL", Integer.toString(VMOpCode.F_CL));
map.put("F_CLE", Integer.toString(VMOpCode.F_CLE));
map.put("D_ADD", Integer.toString(VMOpCode.D_ADD));
map.put("D_SUB", Integer.toString(VMOpCode.D_SUB));
map.put("D_MUL", Integer.toString(VMOpCode.D_MUL));
map.put("D_DIV", Integer.toString(VMOpCode.D_DIV));
map.put("D_MOD", Integer.toString(VMOpCode.D_MOD));
map.put("D_NEG", Integer.toString(VMOpCode.D_NEG));
map.put("D_INC", Integer.toString(VMOpCode.D_INC));
map.put("D_PUSH", Integer.toString(VMOpCode.D_PUSH));
map.put("D_LOAD", Integer.toString(VMOpCode.D_LOAD));
map.put("D_STORE", Integer.toString(VMOpCode.D_STORE));
map.put("D_CE", Integer.toString(VMOpCode.D_CE));
map.put("D_CNE", Integer.toString(VMOpCode.D_CNE));
map.put("D_CG", Integer.toString(VMOpCode.D_CG));
map.put("D_CGE", Integer.toString(VMOpCode.D_CGE));
map.put("D_CL", Integer.toString(VMOpCode.D_CL));
map.put("D_CLE", Integer.toString(VMOpCode.D_CLE));
map.put("B2S", Integer.toString(VMOpCode.B2S));
map.put("B2I", Integer.toString(VMOpCode.B2I));
map.put("B2L", Integer.toString(VMOpCode.B2L));
map.put("B2F", Integer.toString(VMOpCode.B2F));
map.put("B2D", Integer.toString(VMOpCode.B2D));
map.put("S2B", Integer.toString(VMOpCode.S2B));
map.put("S2I", Integer.toString(VMOpCode.S2I));
map.put("S2L", Integer.toString(VMOpCode.S2L));
map.put("S2F", Integer.toString(VMOpCode.S2F));
map.put("S2D", Integer.toString(VMOpCode.S2D));
map.put("I2B", Integer.toString(VMOpCode.I2B));
map.put("I2D", Integer.toString(VMOpCode.I2D));
map.put("I2S", Integer.toString(VMOpCode.I2S));
map.put("I2L", Integer.toString(VMOpCode.I2L));
map.put("I2F", Integer.toString(VMOpCode.I2F));
map.put("I2D", Integer.toString(VMOpCode.I2D));
map.put("L2B", Integer.toString(VMOpCode.L2B));
map.put("L2S", Integer.toString(VMOpCode.L2S));
map.put("L2I", Integer.toString(VMOpCode.L2I));
map.put("L2D", Integer.toString(VMOpCode.L2D));
map.put("L2F", Integer.toString(VMOpCode.L2F));
map.put("L2D", Integer.toString(VMOpCode.L2D));
map.put("F2B", Integer.toString(VMOpCode.F2B));
map.put("F2S", Integer.toString(VMOpCode.F2S));
map.put("F2I", Integer.toString(VMOpCode.F2I));
map.put("F2L", Integer.toString(VMOpCode.F2L));
map.put("F2D", Integer.toString(VMOpCode.F2D));
map.put("D2B", Integer.toString(VMOpCode.D2B));
map.put("D2S", Integer.toString(VMOpCode.D2S));
map.put("D2I", Integer.toString(VMOpCode.D2I));
map.put("D2L", Integer.toString(VMOpCode.D2L));
map.put("D2F", Integer.toString(VMOpCode.D2F));
map.put("S2I", Integer.toString(VMOpCode.S2I));
map.put("B2I", Integer.toString(VMOpCode.B2I));
map.put("I_AND", Integer.toString(VMOpCode.I_AND));
map.put("I_OR", Integer.toString(VMOpCode.I_OR));
map.put("I_XOR", Integer.toString(VMOpCode.I_XOR));
map.put("L_AND", Integer.toString(VMOpCode.L_AND));
map.put("L_OR", Integer.toString(VMOpCode.L_OR));
map.put("L_XOR", Integer.toString(VMOpCode.L_XOR));
map.put("JUMP", Integer.toString(VMOpCode.JUMP));
map.put("IC_E", Integer.toString(VMOpCode.I_CE));
map.put("IC_NE", Integer.toString(VMOpCode.I_CNE));
map.put("IC_G", Integer.toString(VMOpCode.I_CG));
map.put("IC_GE", Integer.toString(VMOpCode.I_CGE));
map.put("IC_L", Integer.toString(VMOpCode.I_CL));
map.put("IC_LE", Integer.toString(VMOpCode.I_CLE));
map.put("LC_E", Integer.toString(VMOpCode.L_CE));
map.put("LC_NE", Integer.toString(VMOpCode.L_CNE));
map.put("LC_G", Integer.toString(VMOpCode.L_CG));
map.put("LC_GE", Integer.toString(VMOpCode.L_CGE));
map.put("LC_L", Integer.toString(VMOpCode.L_CL));
map.put("LC_LE", Integer.toString(VMOpCode.L_CLE));
map.put("I_PUSH", Integer.toString(VMOpCode.I_PUSH));
map.put("L_PUSH", Integer.toString(VMOpCode.L_PUSH));
map.put("S_PUSH", Integer.toString(VMOpCode.S_PUSH));
map.put("B_PUSH", Integer.toString(VMOpCode.B_PUSH));
map.put("D_PUSH", Integer.toString(VMOpCode.D_PUSH));
map.put("F_PUSH", Integer.toString(VMOpCode.F_PUSH));
map.put("POP", Integer.toString(VMOpCode.POP));
map.put("DUP", Integer.toString(VMOpCode.DUP));
map.put("SWAP", Integer.toString(VMOpCode.SWAP));
map.put("I_STORE", Integer.toString(VMOpCode.I_STORE));
map.put("L_STORE", Integer.toString(VMOpCode.L_STORE));
map.put("S_STORE", Integer.toString(VMOpCode.S_STORE));
map.put("B_STORE", Integer.toString(VMOpCode.B_STORE));
map.put("D_STORE", Integer.toString(VMOpCode.D_STORE));
map.put("F_STORE", Integer.toString(VMOpCode.F_STORE));
map.put("I_LOAD", Integer.toString(VMOpCode.I_LOAD));
map.put("L_LOAD", Integer.toString(VMOpCode.L_LOAD));
map.put("S_LOAD", Integer.toString(VMOpCode.S_LOAD));
map.put("B_LOAD", Integer.toString(VMOpCode.B_LOAD));
map.put("D_LOAD", Integer.toString(VMOpCode.D_LOAD));
map.put("F_LOAD", Integer.toString(VMOpCode.F_LOAD));
map.put("MOV", Integer.toString(VMOpCode.MOV));
map.put("JUMP", Integer.toString(VMOpCode.JUMP));
map.put("CALL", Integer.toString(VMOpCode.CALL));
map.put("RET", Integer.toString(VMOpCode.RET));
map.put("MOV", Integer.toString(VMOpCode.MOV));
map.put("HALT", Integer.toString(VMOpCode.HALT));
map.put("SYSCALL", Integer.toString(VMOpCode.SYSCALL));
map.put("DEBUG_TRAP", Integer.toString(VMOpCode.DEBUG_TRAP));
OPCODE_MAP = Collections.unmodifiableMap(map);
Map<Integer, String> revmap = new HashMap<>(); // reverse map

View File

@ -0,0 +1,126 @@
package org.jcnc.snow.compiler.backend.utils;
/**
* 工具类提供基本数值类型的提升与类型转换辅助功能
* <p>
* 在进行数值类型运算比较等操作时低优先级的类型会被提升为高优先级类型参与运算
* 例如 int + long 运算int 会被提升为 long最终运算结果类型为 long
* <p>
* 类型优先级从高到低依次为
* Ddouble6
* Ffloat 5
* Llong 4
* Iint 3
* Sshort 2
* Bbyte 1
* 未识别类型 0
*/
public class TypePromoteUtils {
/**
* 返回数值类型的宽度优先级数值越大类型越宽
* 类型及优先级映射如下
* Ddouble: 6
* Ffloat : 5
* Llong : 4
* Iint : 3
* Sshort : 2
* Bbyte : 1
* 未知类型 : 0
*
* @param p 类型标记字符B/S/I/L/F/D
* @return 优先级数值0 表示未知类型
*/
private static int rank(char p) {
return switch (p) {
case 'D' -> 6;
case 'F' -> 5;
case 'L' -> 4;
case 'I' -> 3;
case 'S' -> 2;
case 'B' -> 1;
default -> 0;
};
}
/**
* 返回两个类型中较的公共类型即优先级较高的类型
* 若优先级相等返回第一个参数的类型
*
* @param a 类型标记字符1
* @param b 类型标记字符2
* @return 优先级较高的类型标记字符
*/
public static char promote(char a, char b) {
return rank(a) >= rank(b) ? a : b;
}
/**
* 将单个字符的类型标记转为字符串
*
* @param p 类型标记字符
* @return 类型标记的字符串形式
*/
public static String str(char p) {
return String.valueOf(p);
}
/**
* 获取类型转换指令名例如 "I2L", "F2D"表示从源类型到目标类型的转换操作
* 如果源类型和目标类型相同则返回 null表示无需转换
* <p>
* 支持的类型标记字符包括BbyteSshortIintLlongFfloatDdouble
* 所有可能的类型转换均已覆盖如下所示
* B S/I/L/F/D
* S B/I/L/F/D
* I B/S/L/F/D
* L B/S/I/F/D
* F B/S/I/L/D
* D B/S/I/L/F
*
* @param from 源类型标记字符
* @param to 目标类型标记字符
* @return 类型转换指令名 "L2I"如无须转换则返回 null
*/
public static String convert(char from, char to) {
if (from == to) return null;
return switch ("" + from + to) {
case "BS" -> "B2S";
case "BI" -> "B2I";
case "BL" -> "B2L";
case "BF" -> "B2F";
case "BD" -> "B2D";
case "SB" -> "S2B";
case "SI" -> "S2I";
case "SL" -> "S2L";
case "SF" -> "S2F";
case "SD" -> "S2D";
case "IB" -> "I2B";
case "IS" -> "I2S";
case "IL" -> "I2L";
case "IF" -> "I2F";
case "ID" -> "I2D";
case "LB" -> "L2B";
case "LS" -> "L2S";
case "LI" -> "L2I";
case "LF" -> "L2F";
case "LD" -> "L2D";
case "FB" -> "F2B";
case "FS" -> "F2S";
case "FI" -> "F2I";
case "FL" -> "F2L";
case "FD" -> "F2D";
case "DB" -> "D2B";
case "DS" -> "D2S";
case "DI" -> "D2I";
case "DL" -> "D2L";
case "DF" -> "D2F";
default -> null;
};
}
}

View File

@ -145,7 +145,7 @@ public record ExpressionBuilder(IRContext ctx) {
if (ComparisonUtils.isComparisonOperator(op)) {
return InstructionFactory.binOp(
ctx,
ComparisonUtils.cmpOp(op, bin.left(), bin.right()),
ComparisonUtils.cmpOp(ctx.getScope().getVarTypes(), op, bin.left(), bin.right()),
left, right);
}
@ -171,7 +171,7 @@ public record ExpressionBuilder(IRContext ctx) {
if (ComparisonUtils.isComparisonOperator(op)) {
InstructionFactory.binOpInto(
ctx,
ComparisonUtils.cmpOp(op, bin.left(), bin.right()),
ComparisonUtils.cmpOp(ctx.getScope().getVarTypes(), op, bin.left(), bin.right()),
a, b, dest);
} else {
IROpCode code = ExpressionUtils.resolveOpCode(op, bin.left(), bin.right());

View File

@ -13,7 +13,7 @@ import java.util.Map;
* <ul>
* <li>维护在当前作用域中已声明变量的寄存器分配信息</li>
* <li>支持将已有虚拟寄存器与变量名重新绑定</li>
* <li>根据变量名查找对应的虚拟寄存器实例</li>
* <li>根据变量名查找对应的虚拟寄存器实例或类型</li>
* </ul>
*/
final class IRBuilderScope {
@ -104,4 +104,12 @@ final class IRBuilderScope {
String lookupType(String name) {
return varTypes.get(name);
}
/**
* 获取 变量->类型的映射 的不可变副本
* @return 变量->类型的映射 的不可变副本
*/
Map<String, String> getVarTypes() {
return Map.copyOf(varTypes);
}
}

View File

@ -218,7 +218,7 @@ public class StatementBuilder {
IRVirtualRegister b = expr.build(right);
// 使用适配后位宽正确的比较指令
IROpCode cmp = ComparisonUtils.cmpOp(operator, left, right);
IROpCode cmp = ComparisonUtils.cmpOp(ctx.getScope().getVarTypes(), operator, left, right);
IROpCode falseOp = IROpCodeUtils.invert(cmp);
InstructionFactory.cmpJump(ctx, falseOp, a, b, falseLabel);

View File

@ -66,21 +66,53 @@ public enum IROpCode {
DIV_D64, // 64位浮点除法
NEG_D64, // 64位浮点取负
/* ───── 逻辑与比较运算指令8位整数byte ───── */
CMP_BEQ, // 8位整数相等比较a == b
CMP_BNE, // 8位整数不等比较a != b
CMP_BLT, // 8位整数小于比较a < b
CMP_BGT, // 8位整数大于比较a > b
CMP_BLE, // 8位整数小于等于a <= b
CMP_BGE, // 8位整数大于等于a >= b
/* ───── 逻辑与比较运算指令16位整数int ───── */
CMP_SEQ, // 16位整数相等比较a == b
CMP_SNE, // 16位整数不等比较a != b
CMP_SLT, // 16位整数小于比较a < b
CMP_SGT, // 16位整数大于比较a > b
CMP_SLE, // 16位整数小于等于a <= b
CMP_SGE, // 16位整数大于等于a >= b
/* ───── 逻辑与比较运算指令32位整数int ───── */
CMP_IEQ, // 32位相等比较a == b
CMP_INE, // 32位不等比较a != b
CMP_ILT, // 32位小于比较a < b
CMP_IGT, // 32位大于比较a > b
CMP_ILE, // 32位小于等于a <= b
CMP_IGE, // 32位大于等于a >= b
CMP_IEQ, // 32位整数相等比较a == b
CMP_INE, // 32位整数不等比较a != b
CMP_ILT, // 32位整数小于比较a < b
CMP_IGT, // 32位整数大于比较a > b
CMP_ILE, // 32位整数小于等于a <= b
CMP_IGE, // 32位整数大于等于a >= b
/* ───── 逻辑与比较运算指令64位整数long ───── */
CMP_LEQ, // 64位相等比较a == b
CMP_LNE, // 64位不等比较a != b
CMP_LLT, // 64位小于比较a < b
CMP_LGT, // 64位大于比较a > b
CMP_LLE, // 64位小于等于a <= b
CMP_LGE, // 64位大于等于a >= b
CMP_LEQ, // 64位整数相等比较a == b
CMP_LNE, // 64位整数不等比较a != b
CMP_LLT, // 64位整数小于比较a < b
CMP_LGT, // 64位整数大于比较a > b
CMP_LLE, // 64位整数小于等于a <= b
CMP_LGE, // 64位整数大于等于a >= b
/* ───── 逻辑与比较运算指令32位浮点数float ───── */
CMP_FEQ, // 32位浮点相等比较a == b
CMP_FNE, // 32位浮点不等比较a != b
CMP_FLT, // 32位浮点小于比较a < b
CMP_FGT, // 32位浮点大于比较a > b
CMP_FLE, // 32位浮点小于等于a <= b
CMP_FGE, // 32位浮点大于等于a >= b
/* ───── 逻辑与比较运算指令64位浮点数double ───── */
CMP_DEQ, // 64位浮点相等比较a == b
CMP_DNE, // 64位浮点不等比较a != b
CMP_DLT, // 64位浮点小于比较a < b
CMP_DGT, // 64位浮点大于比较a > b
CMP_DLE, // 64位浮点小于等于a <= b
CMP_DGE, // 64位浮点大于等于a >= b
/* ───── 数据访问与常量操作 ───── */
LOAD, // 从内存加载数据至寄存器

View File

@ -40,6 +40,26 @@ public final class IROpCodeMappings {
);
/* ────── 比较运算符映射 ────── */
/** 8-bitbyte比较 */
public static final Map<String, IROpCode> CMP_B8 = Map.of(
"==", IROpCode.CMP_BEQ,
"!=", IROpCode.CMP_BNE,
"<", IROpCode.CMP_BLT,
">", IROpCode.CMP_BGT,
"<=", IROpCode.CMP_BLE,
">=", IROpCode.CMP_BGE
);
/** 16-bitshort比较 */
public static final Map<String, IROpCode> CMP_S16 = Map.of(
"==", IROpCode.CMP_SEQ,
"!=", IROpCode.CMP_SNE,
"<", IROpCode.CMP_SLT,
">", IROpCode.CMP_SGT,
"<=", IROpCode.CMP_SLE,
">=", IROpCode.CMP_SGE
);
/** 32-bitint比较 */
public static final Map<String, IROpCode> CMP_I32 = Map.of(
"==", IROpCode.CMP_IEQ,
@ -60,5 +80,23 @@ public final class IROpCodeMappings {
">=", IROpCode.CMP_LGE
);
/** 32-bitfloat比较 */
public static final Map<String, IROpCode> CMP_F32 = Map.of(
"==", IROpCode.CMP_FEQ,
"!=", IROpCode.CMP_FNE,
"<", IROpCode.CMP_FLT,
">", IROpCode.CMP_FGT,
"<=", IROpCode.CMP_FLE,
">=", IROpCode.CMP_FGE
);
/** 64-bitdouble比较 */
public static final Map<String, IROpCode> CMP_D64 = Map.of(
"==", IROpCode.CMP_DEQ,
"!=", IROpCode.CMP_DNE,
"<", IROpCode.CMP_DLT,
">", IROpCode.CMP_DGT,
"<=", IROpCode.CMP_DLE,
">=", IROpCode.CMP_DGE
);
}

View File

@ -2,6 +2,7 @@ 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.IdentifierNode;
import org.jcnc.snow.compiler.parser.ast.NumberLiteralNode;
import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode;
import org.jcnc.snow.compiler.parser.ast.base.NodeContext;
@ -9,42 +10,134 @@ import org.jcnc.snow.compiler.parser.ast.base.NodeContext;
import java.util.Map;
/**
* 比较运算辅助工具
* 根据左右操作数类型目前通过字面量后缀 <code>L/l</code> 判定选择
* 正确的 IR 比较指令保证 int/long 均能正常运行
* 工具类用于比较运算相关的类型推断和指令选择
* <p>
* 该类主要用于根据左右操作数的静态类型自动选择正确的 IR 层比较操作码
* 支持自动类型提升保证 intlongfloatdouble 等类型的比较均能得到正确的 IR 指令
* </p>
*
* 类型判定支持
* <ul>
* <li>字面量后缀支持 B/S/I/L/F/D大小写均可</li>
* <li>浮点数支持如无后缀但有小数点视为 double</li>
* <li>变量类型根据传入变量表推断类型未识别则默认 int</li>
* </ul>
*/
public final class ComparisonUtils {
private ComparisonUtils() {
}
private ComparisonUtils() {}
/**
* 判断给定操作符是否为比较运算符
* 判断给定字符串是否为受支持的比较运算符==, !=, <, >, <=, >=
* 仅检查 int 类型指令表因所有类型的比较符号集合相同
*
* @param op 比较运算符字符串
* @return 若为比较运算符返回 true否则返回 false
*/
public static boolean isComparisonOperator(String op) {
// 两张表 key 完全一致只需检查一张
// 只需查 int 类型表即可
return IROpCodeMappings.CMP_I32.containsKey(op);
}
/**
* 返回符合操作数位宽的比较 IROpCode
* 返回类型宽度优先级越大代表类型越宽类型对应的优先级
* - D (double): 6
* - F (float): 5
* - L (long): 4
* - I (int): 3
* - S (short): 2
* - B (byte): 1
* - 未知类型: 0
*
* @param op 比较符号==, !=, <, >, <=, >=
* @param left 左操作数 AST
* @param right 右操作数 AST
* @param p 类型标记字符
* @return 类型优先级数值
*/
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;
private static int rank(char p) {
return switch (p) {
case 'D' -> 6;
case 'F' -> 5;
case 'L' -> 4;
case 'I' -> 3;
case 'S' -> 2;
case 'B' -> 1;
default -> 0;
};
}
/**
* 返回两个类型中较的类型即优先级较高的类型
* 若优先级相等返回第一个参数的类型
*
* @param a 类型标记字符1
* @param b 类型标记字符2
* @return 宽度更高的类型字符
*/
public static char promote(char a, char b) {
return rank(a) >= rank(b) ? a : b;
}
/**
* 根据变量类型映射和操作数表达式推断操作数类型
* 并自动类型提升后选择正确的比较操作码IROpCode
* 若未能推断类型或操作符不受支持会抛出异常
*
* @param variables 变量名到类型的映射 "a" -> "int"
* @param op 比较符号==, !=, <, >, <=, >=
* @param left 左操作数表达式
* @param right 右操作数表达式
* @return 适用的比较 IROpCode
* @throws IllegalStateException 如果无法推断合适的类型
*/
public static IROpCode cmpOp(Map<String, String> variables, String op, ExpressionNode left, ExpressionNode right) {
char typeLeft = analysisType(variables, left);
char typeRight = analysisType(variables, right);
char type = promote(typeLeft, typeRight);
Map<String, IROpCode> table = switch (type) {
case 'B' -> IROpCodeMappings.CMP_B8;
case 'S' -> IROpCodeMappings.CMP_S16;
case 'I' -> IROpCodeMappings.CMP_I32;
case 'L' -> IROpCodeMappings.CMP_L64;
case 'F' -> IROpCodeMappings.CMP_F32;
case 'D' -> IROpCodeMappings.CMP_D64;
default -> throw new IllegalStateException("Unexpected value: " + type);
};
return table.get(op);
}
/* ------------ 内部工具 ------------ */
private static boolean isLongLiteral(ExpressionNode node) {
/**
* 内部工具方法根据表达式节点和变量表推断类型标记字符
* 字面量支持 B/S/I/L/F/D大小写均可浮点数默认 double
* 标识符类型按变量表映射未知则默认 int
*
* @param variables 变量名到类型的映射
* @param node 表达式节点
* @return 类型标记字符B/S/I/L/F/D未知时返回 I
*/
private static char analysisType(Map<String, String> variables, ExpressionNode node) {
if (node instanceof NumberLiteralNode(String value, NodeContext _)) {
return value.endsWith("L") || value.endsWith("l");
char suffix = Character.toUpperCase(value.charAt(value.length() - 1));
if ("BSILFD".indexOf(suffix) != -1) {
return suffix;
}
if (value.indexOf('.') != -1) {
return 'D';
}
return 'I'; // 默认 int
}
return false; // 变量暂不处理后续可扩展符号表查询
if (node instanceof IdentifierNode(String name, NodeContext _)) {
final String type = variables.get(name);
if (type != null) {
switch (type) {
case "byte": return 'B';
case "short": return 'S';
case "int": return 'I';
case "long": return 'L';
case "float": return 'F';
case "double": return 'D';
}
}
}
return 'I'; // 默认 int
}
}

View File

@ -12,33 +12,46 @@ import org.jcnc.snow.compiler.parser.ast.base.NodeContext;
import java.util.Map;
/**
* 表达式分析与运算符辅助工具类
*
* <p>主要功能</p>
* <ul>
* <li>字面量常量的解析与类型推断</li>
* <li>自动匹配算术/比较操作码</li>
* <li>表达式类型合并与提升</li>
* </ul>
* 表达式分析与操作符选择工具类
* <p>
* 主要功能
* - 解析字面量常量自动推断类型
* - 自动匹配并选择适合的算术/比较操作码
* - 表达式类型的合并与类型提升
* - 支持线程隔离的函数级默认类型后缀
*/
public final class ExpressionUtils {
private ExpressionUtils() {}
/* ────────────────── 线程级默认类型后缀 ────────────────── */
// 线程级默认类型后缀
/** 默认类型后缀(如当前函数返回类型),线程隔离。 */
/**
* 当前线程的默认类型后缀如当前函数返回类型等用于类型推断兜底
*/
private static final ThreadLocal<Character> DEFAULT_SUFFIX =
ThreadLocal.withInitial(() -> '\0');
/**
* 设置当前线程的默认类型后缀
*
* @param suffix 类型后缀字符b/s/i/l/f/d'\0'表示无
*/
public static void setDefaultSuffix(char suffix) { DEFAULT_SUFFIX.set(suffix); }
/**
* 清除当前线程的默认类型后缀重置为无
*/
public static void clearDefaultSuffix() { DEFAULT_SUFFIX.set('\0'); }
/* ───────────────────── 字面量 & 常量 ───────────────────── */
// 字面量常量解析
/**
* 解析整数字面量字符串自动去除类型后缀b/s/l/f/d/B/S/L/F/D并转换为 int
* 安全解析整数字面量字符串自动去除单字符类型后缀b/s/l/f/d大小写均可并转换为 int
*
* @param literal 字面量字符串
* @return 字面量对应的 int 数值
* @throws NumberFormatException 如果字面量无法转换为整数
*/
public static int parseIntSafely(String literal) {
String digits = literal.replaceAll("[bslfdBSDLF]$", "");
@ -46,8 +59,14 @@ public final class ExpressionUtils {
}
/**
* 根据数字字面量字符串自动判断类型生成对应类型的 {@link IRConstant}
* 支持 b/s/l/f/d 后缀与浮点格式
* 根据数字字面量字符串推断类型并生成对应的 IRConstant 常量值
* <p>
* 支持的字面量后缀有 b/s/l/f/d大小写均可
* 无后缀时优先参考 IRContext 当前变量类型否则根据字面量格式'.''e'判断为 double否则为 int
*
* @param ctx IRContext允许参考变量声明类型
* @param value 数字字面量字符串
* @return 对应类型的 IRConstant 常量
*/
public static IRConstant buildNumberConstant(IRContext ctx, String value) {
char suffix = value.isEmpty() ? '\0'
@ -56,7 +75,7 @@ public final class ExpressionUtils {
String digits = switch (suffix) {
case 'b','s','l','f','d' -> value.substring(0, value.length() - 1);
default -> {
/* 如果字面量本身没有后缀,则回退到变量目标类型(如声明语句左值) */
// 无后缀优先参考变量类型
if (ctx.getVarType() != null) {
String t = ctx.getVarType();
suffix = switch (t) {
@ -73,7 +92,7 @@ public final class ExpressionUtils {
}
};
/* 创建常量 */
// 生成常量对象
return switch (suffix) {
case 'b' -> new IRConstant(Byte.parseByte(digits));
case 's' -> new IRConstant(Short.parseShort(digits));
@ -86,10 +105,13 @@ public final class ExpressionUtils {
};
}
/* ────────────────────── 一元运算 ────────────────────── */
// 一元运算指令匹配
/**
* 推断一元取负-运算应使用的 {@link IROpCode}
* 根据表达式节点的类型后缀选择对应的取负-运算操作码
*
* @param operand 操作数表达式
* @return 匹配类型的 IROpCode
*/
public static IROpCode negOp(ExpressionNode operand) {
char t = typeChar(operand);
@ -99,34 +121,54 @@ public final class ExpressionUtils {
case 'l' -> IROpCode.NEG_L64;
case 'f' -> IROpCode.NEG_F32;
case 'd' -> IROpCode.NEG_D64;
default -> IROpCode.NEG_I32; // '\0' 'i'
default -> IROpCode.NEG_I32; // 无法推断或为 int
};
}
/* ────────────────── 比较运算(已适配 long ────────────────── */
// 比较运算相关
/** 判断给定字符串是否是比较运算符(==, !=, <, >, <=, >=)。 */
/**
* 判断给定字符串是否为支持的比较运算符==, !=, <, >, <=, >=
*
* @param op 操作符字符串
* @return 若为比较运算符返回 true否则返回 false
*/
public static boolean isComparisonOperator(String op) {
return ComparisonUtils.isComparisonOperator(op);
}
/**
* 兼容旧调用仅凭操作符返回 <em>int32</em> 比较指令
* 兼容旧逻辑仅凭操作符直接返回 int32 比较指令
*
* @param op 比较操作符
* @return int32 类型的比较操作码
*/
public static IROpCode cmpOp(String op) {
return IROpCodeMappings.CMP_I32.get(op); // 旧逻辑一律 i32
return IROpCodeMappings.CMP_I32.get(op);
}
/**
* 推荐调用根据左右表达式类型自动选择 int / long 比较指令
* 推荐调用根据左右表达式类型自动选择 int/long/float/double 等合适的比较操作码
*
* @param variables 变量名到类型的映射
* @param op 比较符号
* @param left 左操作数表达式
* @param right 右操作数表达式
* @return 匹配类型的比较操作码
*/
public static IROpCode cmpOp(String op, ExpressionNode left, ExpressionNode right) {
return ComparisonUtils.cmpOp(op, left, right);
public static IROpCode cmpOp(Map<String, String> variables, String op, ExpressionNode left, ExpressionNode right) {
return ComparisonUtils.cmpOp(variables, op, left, right);
}
/* ──────────────── 类型推断 & 算术操作码匹配 ──────────────── */
// 类型推断与算术操作码匹配
/** 递归推断单个表达式节点的类型后缀b/s/i/l/f/d。 */
/**
* 递归推断表达式节点的类型后缀b/s/i/l/f/d
* 优先从字面量和二元表达式合并类型变量节点暂不处理返回 '\0'
*
* @param node 表达式节点
* @return 推断的类型后缀小写不确定时返回 '\0'
*/
private static char typeChar(ExpressionNode node) {
if (node instanceof NumberLiteralNode(String value, NodeContext _)) {
char last = Character.toLowerCase(value.charAt(value.length() - 1));
@ -141,12 +183,25 @@ public final class ExpressionUtils {
return '\0'; // 变量等暂不处理
}
/** 合并两侧表达式的类型后缀。 */
/**
* 合并两个表达式节点的类型后缀按照 d > f > l > i > s > b > '\0' 优先级返回最宽类型
*
* @param left 左表达式
* @param right 右表达式
* @return 合并后的类型后缀
*/
public static char resolveSuffix(ExpressionNode left, ExpressionNode right) {
return maxTypeChar(typeChar(left), typeChar(right));
}
/** 类型优先级d > f > l > i > s > b > '\0' */
/**
* 返回两个类型后缀中的最大类型宽度优先
* 优先级d > f > l > i > s > b > '\0'
*
* @param l 类型后缀1
* @param r 类型后缀2
* @return 最宽类型后缀
*/
private static char maxTypeChar(char l, char r) {
if (l == 'd' || r == 'd') return 'd';
if (l == 'f' || r == 'f') return 'f';
@ -158,35 +213,42 @@ public final class ExpressionUtils {
}
/**
* 根据操作符和两侧表达式选择正确的算术 {@link IROpCode}
* 根据操作符和两侧表达式选择匹配的算术操作码IROpCode
* <p>
* 类型推断优先使用左右表达式的类型后缀推断失败时回退为线程级默认类型后缀再失败则默认为 int32
*
* @param op 算术操作符
* @param left 左表达式
* @param right 右表达式
* @return 匹配类型的 IROpCode
*/
public static IROpCode resolveOpCode(String op,
ExpressionNode left,
ExpressionNode right) {
/* 1. 尝试根据字面量推断 */
// 1. 优先根据表达式类型推断
char suffix = resolveSuffix(left, right);
/* 2. 若失败则使用函数级默认类型 */
// 2. 推断失败则使用线程默认类型
if (suffix == '\0') suffix = DEFAULT_SUFFIX.get();
/* 3. 仍失败则默认为 int32 */
// 3. 仍失败则默认为 int32
Map<String, IROpCode> table = switch (suffix) {
case 'b' -> IROpCodeMappings.OP_B8;
case 's' -> IROpCodeMappings.OP_S16;
case 'i' -> IROpCodeMappings.OP_I32;
case 'l' -> IROpCodeMappings.OP_L64;
case 'f' -> IROpCodeMappings.OP_F32;
case 'd' -> IROpCodeMappings.OP_D64;
default -> IROpCodeMappings.OP_I32;
};
return table.get(op);
}
/* ────────────────────────── 工具 ───────────────────────── */
// 字符串辅助工具
/** 是否像浮点字面量(包含 '.' 或 e/E。 */
/**
* 判断字面量字符串是否看起来像浮点数包含小数点或 e/E 科学计数法
*
* @param digits 字面量字符串
* @return 是浮点格式则返回 true
*/
private static boolean looksLikeFloat(String digits) {
return digits.indexOf('.') >= 0
|| digits.indexOf('e') >= 0

View File

@ -0,0 +1,47 @@
package org.jcnc.snow.vm.commands.type.conversion;
import org.jcnc.snow.vm.interfaces.Command;
import org.jcnc.snow.vm.module.CallStack;
import org.jcnc.snow.vm.module.LocalVariableStore;
import org.jcnc.snow.vm.module.OperandStack;
/**
* B2DCommand Opcode: Represents the type conversion operation from byte8 to double64 in the virtual machine.
* <p>This opcode is implemented by the {@link B2DCommand} class, which defines its specific execution logic.</p>
*
* <p>Execution Steps:</p>
* <ol>
* <li>Pop the top byte8 value from the operand stack.</li>
* <li>Convert the byte8 value to a double64 value.</li>
* <li>Push the converted double64 value back onto the operand stack for subsequent operations.</li>
* </ol>
*
* <p>This opcode is used to widen a byte8 value to a double64 type.</p>
*/
public class B2DCommand implements Command {
/**
* Default constructor for creating an instance of B2DCommand.
*/
public B2DCommand() {
// Empty constructor
}
/**
* Executes the byte8 to double64 conversion operation.
*
* @param parts The array of instruction parameters, which is not used in this operation.
* @param currentPC The current program counter, representing the instruction address.
* @param operandStack The operand stack of the virtual machine.
* @param localVariableStore The local variable store for managing method-local variables.
* @param callStack The call stack of the virtual machine.
* @return The updated program counter after execution.
*/
@Override
public int execute(String[] parts, int currentPC, OperandStack operandStack,
LocalVariableStore localVariableStore, CallStack callStack) {
double convertedValue = (byte) operandStack.pop();
operandStack.push(convertedValue);
return currentPC + 1;
}
}

View File

@ -0,0 +1,47 @@
package org.jcnc.snow.vm.commands.type.conversion;
import org.jcnc.snow.vm.interfaces.Command;
import org.jcnc.snow.vm.module.CallStack;
import org.jcnc.snow.vm.module.LocalVariableStore;
import org.jcnc.snow.vm.module.OperandStack;
/**
* B2FCommand Opcode: Represents the type conversion operation from byte8 to float32 in the virtual machine.
* <p>This opcode is implemented by the {@link B2FCommand} class, which defines its specific execution logic.</p>
*
* <p>Execution Steps:</p>
* <ol>
* <li>Pop the top byte8 value from the operand stack.</li>
* <li>Convert the byte8 value to a float32 value.</li>
* <li>Push the converted float32 value back onto the operand stack for subsequent operations.</li>
* </ol>
*
* <p>This opcode is used to widen a byte8 value to a float32 type.</p>
*/
public class B2FCommand implements Command {
/**
* Default constructor for creating an instance of B2FCommand.
*/
public B2FCommand() {
// Empty constructor
}
/**
* Executes the byte8 to float32 conversion operation.
*
* @param parts The array of instruction parameters, which is not used in this operation.
* @param currentPC The current program counter, representing the instruction address.
* @param operandStack The operand stack of the virtual machine.
* @param localVariableStore The local variable store for managing method-local variables.
* @param callStack The call stack of the virtual machine.
* @return The updated program counter after execution.
*/
@Override
public int execute(String[] parts, int currentPC, OperandStack operandStack,
LocalVariableStore localVariableStore, CallStack callStack) {
float convertedValue = (byte) operandStack.pop();
operandStack.push(convertedValue);
return currentPC + 1;
}
}

View File

@ -16,7 +16,7 @@ import org.jcnc.snow.vm.module.OperandStack;
* <li>Push the converted int32 value back onto the operand stack for subsequent operations.</li>
* </ol>
*
* <p>This opcode is used to widen a byte8 value to an int32 type to ensure compatibility with integer-based operations.</p>
* <p>This opcode is used to widen a byte8 value to an int32 type.</p>
*/
public class B2ICommand implements Command {

View File

@ -0,0 +1,47 @@
package org.jcnc.snow.vm.commands.type.conversion;
import org.jcnc.snow.vm.interfaces.Command;
import org.jcnc.snow.vm.module.CallStack;
import org.jcnc.snow.vm.module.LocalVariableStore;
import org.jcnc.snow.vm.module.OperandStack;
/**
* B2LCommand Opcode: Represents the type conversion operation from byte8 to long64 in the virtual machine.
* <p>This opcode is implemented by the {@link B2LCommand} class, which defines its specific execution logic.</p>
*
* <p>Execution Steps:</p>
* <ol>
* <li>Pop the top byte8 value from the operand stack.</li>
* <li>Convert the byte8 value to a long64 value.</li>
* <li>Push the converted long64 value back onto the operand stack for subsequent operations.</li>
* </ol>
*
* <p>This opcode is used to widen a byte8 value to a long64 type.</p>
*/
public class B2LCommand implements Command {
/**
* Default constructor for creating an instance of B2LCommand.
*/
public B2LCommand() {
// Empty constructor
}
/**
* Executes the byte8 to long64 conversion operation.
*
* @param parts The array of instruction parameters, which is not used in this operation.
* @param currentPC The current program counter, representing the instruction address.
* @param operandStack The operand stack of the virtual machine.
* @param localVariableStore The local variable store for managing method-local variables.
* @param callStack The call stack of the virtual machine.
* @return The updated program counter after execution.
*/
@Override
public int execute(String[] parts, int currentPC, OperandStack operandStack,
LocalVariableStore localVariableStore, CallStack callStack) {
long convertedValue = (byte) operandStack.pop();
operandStack.push(convertedValue);
return currentPC + 1;
}
}

View File

@ -0,0 +1,47 @@
package org.jcnc.snow.vm.commands.type.conversion;
import org.jcnc.snow.vm.interfaces.Command;
import org.jcnc.snow.vm.module.CallStack;
import org.jcnc.snow.vm.module.LocalVariableStore;
import org.jcnc.snow.vm.module.OperandStack;
/**
* B2SCommand Opcode: Represents the type conversion operation from byte8 to short16 in the virtual machine.
* <p>This opcode is implemented by the {@link B2SCommand} class, which defines its specific execution logic.</p>
*
* <p>Execution Steps:</p>
* <ol>
* <li>Pop the top byte8 value from the operand stack.</li>
* <li>Convert the byte8 value to a short16 value.</li>
* <li>Push the converted short16 value back onto the operand stack for subsequent operations.</li>
* </ol>
*
* <p>This opcode is used to widen a byte8 value to a short16 type.</p>
*/
public class B2SCommand implements Command {
/**
* Default constructor for creating an instance of B2SCommand.
*/
public B2SCommand() {
// Empty constructor
}
/**
* Executes the byte8 to short16 conversion operation.
*
* @param parts The array of instruction parameters, which is not used in this operation.
* @param currentPC The current program counter, representing the instruction address.
* @param operandStack The operand stack of the virtual machine.
* @param localVariableStore The local variable store for managing method-local variables.
* @param callStack The call stack of the virtual machine.
* @return The updated program counter after execution.
*/
@Override
public int execute(String[] parts, int currentPC, OperandStack operandStack,
LocalVariableStore localVariableStore, CallStack callStack) {
short convertedValue = (byte) operandStack.pop();
operandStack.push(convertedValue);
return currentPC + 1;
}
}

View File

@ -0,0 +1,48 @@
package org.jcnc.snow.vm.commands.type.conversion;
import org.jcnc.snow.vm.interfaces.Command;
import org.jcnc.snow.vm.module.CallStack;
import org.jcnc.snow.vm.module.LocalVariableStore;
import org.jcnc.snow.vm.module.OperandStack;
/**
* D2BCommand Opcode: Represents the type conversion operation from double64 to byte8 in the virtual machine.
* <p>This opcode is implemented by the {@link D2BCommand} class, which defines its specific execution logic.</p>
*
* <p>Execution Steps:</p>
* <ol>
* <li>Pop the top double64 value from the operand stack.</li>
* <li>Convert the double64 value to a byte8 value (this may involve truncation).</li>
* <li>Push the converted byte8 value back onto the operand stack for subsequent operations.</li>
* </ol>
*
* <p>This opcode is used to narrow a double64 value to a byte8 type.</p>
*/
public class D2BCommand implements Command {
/**
* Default constructor for creating an instance of D2BCommand.
*/
public D2BCommand() {
// Empty constructor
}
/**
* Executes the double64 to byte8 conversion operation.
*
* @param parts The array of instruction parameters, which is not used in this operation.
* @param currentPC The current program counter, representing the instruction address.
* @param operandStack The operand stack of the virtual machine.
* @param localVariableStore The local variable store for managing method-local variables.
* @param callStack The call stack of the virtual machine.
* @return The updated program counter after execution.
*/
@Override
public int execute(String[] parts, int currentPC, OperandStack operandStack,
LocalVariableStore localVariableStore, CallStack callStack) {
double value = (double) operandStack.pop();
byte convertedValue = (byte) value;
operandStack.push(convertedValue);
return currentPC + 1;
}
}

View File

@ -16,7 +16,7 @@ import org.jcnc.snow.vm.module.OperandStack;
* <li>Push the converted float32 value back onto the operand stack for subsequent operations.</li>
* </ol>
*
* <p>This opcode is used to narrow a double64 value to a float32 type when lower precision floating-point arithmetic is acceptable.</p>
* <p>This opcode is used to narrow a double64 value to a float32 type.</p>
*/
public class D2FCommand implements Command {

View File

@ -16,7 +16,7 @@ import org.jcnc.snow.vm.module.OperandStack;
* <li>Push the converted int32 value back onto the operand stack for subsequent operations.</li>
* </ol>
*
* <p>This opcode is used to narrow a double64 value to an int32 type for further integer-based operations.</p>
* <p>This opcode is used to narrow a double64 value to an int32 type.</p>
*/
public class D2ICommand implements Command {

View File

@ -16,7 +16,7 @@ import org.jcnc.snow.vm.module.OperandStack;
* <li>Push the converted long64 value back onto the operand stack for subsequent operations.</li>
* </ol>
*
* <p>This opcode is used to narrow a double64 value to a long64 type, which can then be used for integer operations.</p>
* <p>This opcode is used to narrow a double64 value to a long64 type.</p>
*/
public class D2LCommand implements Command {

View File

@ -0,0 +1,48 @@
package org.jcnc.snow.vm.commands.type.conversion;
import org.jcnc.snow.vm.interfaces.Command;
import org.jcnc.snow.vm.module.CallStack;
import org.jcnc.snow.vm.module.LocalVariableStore;
import org.jcnc.snow.vm.module.OperandStack;
/**
* D2SCommand Opcode: Represents the type conversion operation from double64 to short16 in the virtual machine.
* <p>This opcode is implemented by the {@link D2SCommand} class, which defines its specific execution logic.</p>
*
* <p>Execution Steps:</p>
* <ol>
* <li>Pop the top double64 value from the operand stack.</li>
* <li>Convert the double64 value to a short16 value (this may involve truncation).</li>
* <li>Push the converted short16 value back onto the operand stack for subsequent operations.</li>
* </ol>
*
* <p>This opcode is used to narrow a double64 value to a short16 type.</p>
*/
public class D2SCommand implements Command {
/**
* Default constructor for creating an instance of D2SCommand.
*/
public D2SCommand() {
// Empty constructor
}
/**
* Executes the double64 to short16 conversion operation.
*
* @param parts The array of instruction parameters, which is not used in this operation.
* @param currentPC The current program counter, representing the instruction address.
* @param operandStack The operand stack of the virtual machine.
* @param localVariableStore The local variable store for managing method-local variables.
* @param callStack The call stack of the virtual machine.
* @return The updated program counter after execution.
*/
@Override
public int execute(String[] parts, int currentPC, OperandStack operandStack,
LocalVariableStore localVariableStore, CallStack callStack) {
double value = (double) operandStack.pop();
short convertedValue = (short) value;
operandStack.push(convertedValue);
return currentPC + 1;
}
}

View File

@ -0,0 +1,48 @@
package org.jcnc.snow.vm.commands.type.conversion;
import org.jcnc.snow.vm.interfaces.Command;
import org.jcnc.snow.vm.module.CallStack;
import org.jcnc.snow.vm.module.LocalVariableStore;
import org.jcnc.snow.vm.module.OperandStack;
/**
* F2BCommand Opcode: Represents the type conversion operation from float32 to byte8 in the virtual machine.
* <p>This opcode is implemented by the {@link F2BCommand} class, which defines its specific execution logic.</p>
*
* <p>Execution Steps:</p>
* <ol>
* <li>Pop the top float32 value from the operand stack.</li>
* <li>Convert the float32 value to a byte8 value (this may involve truncation).</li>
* <li>Push the converted byte8 value back onto the operand stack for subsequent operations.</li>
* </ol>
*
* <p>This opcode is used to convert a float32 value to a byte8 type.</p>
*/
public class F2BCommand implements Command {
/**
* Default constructor for creating an instance of F2BCommand.
*/
public F2BCommand() {
// Empty constructor
}
/**
* Executes the float32 to byte8 conversion operation.
*
* @param parts The array of instruction parameters, which is not used in this operation.
* @param currentPC The current program counter, representing the instruction address.
* @param operandStack The operand stack of the virtual machine.
* @param localVariableStore The local variable store for managing method-local variables.
* @param callStack The call stack of the virtual machine.
* @return The updated program counter after execution.
*/
@Override
public int execute(String[] parts, int currentPC, OperandStack operandStack,
LocalVariableStore localVariableStore, CallStack callStack) {
float value = (float) operandStack.pop();
byte convertedValue = (byte) value;
operandStack.push(convertedValue);
return currentPC + 1;
}
}

View File

@ -16,7 +16,7 @@ import org.jcnc.snow.vm.module.OperandStack;
* <li>Push the converted double64 value back onto the operand stack for subsequent operations.</li>
* </ol>
*
* <p>This opcode is used to promote a float32 value to a double64 type, thereby increasing precision for floating-point computations.</p>
* <p>This opcode is used to promote a float32 value to a double64 type.</p>
*/
public class F2DCommand implements Command {

View File

@ -16,7 +16,7 @@ import org.jcnc.snow.vm.module.OperandStack;
* <li>Push the converted int32 value back onto the operand stack for subsequent operations.</li>
* </ol>
*
* <p>This opcode is used to convert a float32 value to an int32 type for further integer operations or comparisons.</p>
* <p>This opcode is used to convert a float32 value to an int32 type.</p>
*/
public class F2ICommand implements Command {

View File

@ -16,7 +16,7 @@ import org.jcnc.snow.vm.module.OperandStack;
* <li>Push the converted long64 value back onto the operand stack for subsequent operations.</li>
* </ol>
*
* <p>This opcode is used to widen a float32 value to a long64 type for operations requiring a larger numeric range.</p>
* <p>This opcode is used to widen a float32 value to a long64 type.</p>
*/
public class F2LCommand implements Command {

View File

@ -0,0 +1,48 @@
package org.jcnc.snow.vm.commands.type.conversion;
import org.jcnc.snow.vm.interfaces.Command;
import org.jcnc.snow.vm.module.CallStack;
import org.jcnc.snow.vm.module.LocalVariableStore;
import org.jcnc.snow.vm.module.OperandStack;
/**
* F2SCommand Opcode: Represents the type conversion operation from float32 to short16 in the virtual machine.
* <p>This opcode is implemented by the {@link F2SCommand} class, which defines its specific execution logic.</p>
*
* <p>Execution Steps:</p>
* <ol>
* <li>Pop the top float32 value from the operand stack.</li>
* <li>Convert the float32 value to a short16 value (this may involve truncation).</li>
* <li>Push the converted short16 value back onto the operand stack for subsequent operations.</li>
* </ol>
*
* <p>This opcode is used to convert a float32 value to a short16 type.</p>
*/
public class F2SCommand implements Command {
/**
* Default constructor for creating an instance of F2SCommand.
*/
public F2SCommand() {
// Empty constructor
}
/**
* Executes the float32 to short16 conversion operation.
*
* @param parts The array of instruction parameters, which is not used in this operation.
* @param currentPC The current program counter, representing the instruction address.
* @param operandStack The operand stack of the virtual machine.
* @param localVariableStore The local variable store for managing method-local variables.
* @param callStack The call stack of the virtual machine.
* @return The updated program counter after execution.
*/
@Override
public int execute(String[] parts, int currentPC, OperandStack operandStack,
LocalVariableStore localVariableStore, CallStack callStack) {
float value = (float) operandStack.pop();
short convertedValue = (short) value;
operandStack.push(convertedValue);
return currentPC + 1;
}
}

View File

@ -16,7 +16,7 @@ import org.jcnc.snow.vm.module.OperandStack;
* <li>Push the converted byte8 value back onto the operand stack for subsequent operations.</li>
* </ol>
*
* <p>This opcode is used to narrow an int32 value to a byte8 type when a smaller numeric representation is required.</p>
* <p>This opcode is used to narrow an int32 value to a byte8 type.</p>
*/
public class I2BCommand implements Command {

View File

@ -16,7 +16,7 @@ import org.jcnc.snow.vm.module.OperandStack;
* <li>Push the converted double64 value back onto the operand stack for subsequent operations.</li>
* </ol>
*
* <p>This opcode is used to widen an int32 value to a double64 type, providing high-precision floating-point calculations.</p>
* <p>This opcode is used to widen an int32 value to a double64 type.</p>
*/
public class I2DCommand implements Command {

View File

@ -16,7 +16,7 @@ import org.jcnc.snow.vm.module.OperandStack;
* <li>Push the converted float32 value back onto the operand stack for subsequent operations.</li>
* </ol>
*
* <p>This opcode is used to convert an int32 value to a float32 type when floating-point arithmetic is required.</p>
* <p>This opcode is used to convert an int32 value to a float32 type.</p>
*/
public class I2FCommand implements Command {

View File

@ -16,7 +16,7 @@ import org.jcnc.snow.vm.module.OperandStack;
* <li>Push the converted long64 value back onto the operand stack for subsequent operations.</li>
* </ol>
*
* <p>This opcode is commonly used to widen an int32 value to a long64 type to accommodate larger numeric ranges.</p>
* <p>This opcode is commonly used to widen an int32 value to a long64 type.</p>
*/
public class I2LCommand implements Command {

View File

@ -16,7 +16,7 @@ import org.jcnc.snow.vm.module.OperandStack;
* <li>Push the converted short16 value back onto the operand stack for subsequent operations.</li>
* </ol>
*
* <p>This opcode is typically used to narrow an int32 value to a short16 type when a smaller data representation is required.</p>
* <p>This opcode is typically used to narrow an int32 value to a short16 type.</p>
*/
public class I2SCommand implements Command {

View File

@ -0,0 +1,48 @@
package org.jcnc.snow.vm.commands.type.conversion;
import org.jcnc.snow.vm.interfaces.Command;
import org.jcnc.snow.vm.module.CallStack;
import org.jcnc.snow.vm.module.LocalVariableStore;
import org.jcnc.snow.vm.module.OperandStack;
/**
* L2BCommand Opcode: Represents the type conversion operation from long64 to byte8 in the virtual machine.
* <p>This opcode is implemented by the {@link L2BCommand} class, which defines its specific execution logic.</p>
*
* <p>Execution Steps:</p>
* <ol>
* <li>Pop the top long64 value from the operand stack.</li>
* <li>Convert the long64 value to a byte8 value.</li>
* <li>Push the converted byte8 value back onto the operand stack for subsequent operations.</li>
* </ol>
*
* <p>This opcode is used to widen a long64 value to a byte8 type.</p>
*/
public class L2BCommand implements Command {
/**
* Default constructor for creating an instance of L2BCommand.
*/
public L2BCommand() {
// Empty constructor
}
/**
* Executes the long64 to byte8 conversion operation.
*
* @param parts The array of instruction parameters, which is not used in this operation.
* @param currentPC The current program counter, representing the instruction address.
* @param operandStack The operand stack of the virtual machine.
* @param localVariableStore The local variable store for managing method-local variables.
* @param callStack The call stack of the virtual machine.
* @return The updated program counter after execution.
*/
@Override
public int execute(String[] parts, int currentPC, OperandStack operandStack,
LocalVariableStore localVariableStore, CallStack callStack) {
long value = (long) operandStack.pop();
byte convertedValue = (byte) value;
operandStack.push(convertedValue);
return currentPC + 1;
}
}

View File

@ -16,7 +16,7 @@ import org.jcnc.snow.vm.module.OperandStack;
* <li>Push the converted double64 value back onto the operand stack for subsequent operations.</li>
* </ol>
*
* <p>This opcode is used to widen a long64 value to a double64 type for high-precision floating-point computations.</p>
* <p>This opcode is used to widen a long64 value to a double64 type.</p>
*/
public class L2DCommand implements Command {

View File

@ -16,7 +16,7 @@ import org.jcnc.snow.vm.module.OperandStack;
* <li>Push the converted float32 value back onto the operand stack for subsequent operations.</li>
* </ol>
*
* <p>This opcode is used to convert a long64 value to a float32 type, typically for floating-point arithmetic involving long values.</p>
* <p>This opcode is used to convert a long64 value to a float32 type.</p>
*/
public class L2FCommand implements Command {

View File

@ -16,7 +16,7 @@ import org.jcnc.snow.vm.module.OperandStack;
* <li>Push the converted int32 value back onto the operand stack for subsequent operations.</li>
* </ol>
*
* <p>This opcode is typically used to narrow a long64 value to an int32 type for further integer operations.</p>
* <p>This opcode is typically used to narrow a long64 value to an int32 typ.</p>
*/
public class L2ICommand implements Command {

View File

@ -0,0 +1,48 @@
package org.jcnc.snow.vm.commands.type.conversion;
import org.jcnc.snow.vm.interfaces.Command;
import org.jcnc.snow.vm.module.CallStack;
import org.jcnc.snow.vm.module.LocalVariableStore;
import org.jcnc.snow.vm.module.OperandStack;
/**
* L2SCommand Opcode: Represents the type conversion operation from long64 to short16 in the virtual machine.
* <p>This opcode is implemented by the {@link L2SCommand} class, which defines its specific execution logic.</p>
*
* <p>Execution Steps:</p>
* <ol>
* <li>Pop the top long64 value from the operand stack.</li>
* <li>Convert the long64 value to a short16 value.</li>
* <li>Push the converted short16 value back onto the operand stack for subsequent operations.</li>
* </ol>
*
* <p>This opcode is used to widen a long64 value to a short16 type.</p>
*/
public class L2SCommand implements Command {
/**
* Default constructor for creating an instance of L2SCommand.
*/
public L2SCommand() {
// Empty constructor
}
/**
* Executes the long64 to short16 conversion operation.
*
* @param parts The array of instruction parameters, which is not used in this operation.
* @param currentPC The current program counter, representing the instruction address.
* @param operandStack The operand stack of the virtual machine.
* @param localVariableStore The local variable store for managing method-local variables.
* @param callStack The call stack of the virtual machine.
* @return The updated program counter after execution.
*/
@Override
public int execute(String[] parts, int currentPC, OperandStack operandStack,
LocalVariableStore localVariableStore, CallStack callStack) {
long value = (long) operandStack.pop();
short convertedValue = (short) value;
operandStack.push(convertedValue);
return currentPC + 1;
}
}

View File

@ -0,0 +1,48 @@
package org.jcnc.snow.vm.commands.type.conversion;
import org.jcnc.snow.vm.interfaces.Command;
import org.jcnc.snow.vm.module.CallStack;
import org.jcnc.snow.vm.module.LocalVariableStore;
import org.jcnc.snow.vm.module.OperandStack;
/**
* S2BCommand Opcode: Represents the type conversion operation from short16 to byte8 in the virtual machine.
* <p>This opcode is implemented by the {@link S2BCommand} class, which defines its specific execution logic.</p>
*
* <p>Execution Steps:</p>
* <ol>
* <li>Pop the top short16 value from the operand stack.</li>
* <li>Convert the short16 value to a byte8 value.</li>
* <li>Push the converted byte8 value back onto the operand stack for subsequent operations.</li>
* </ol>
*
* <p>This opcode is used to widen a short16 value to a byte8 type.</p>
*/
public class S2BCommand implements Command {
/**
* Default constructor for creating an instance of S2BCommand.
*/
public S2BCommand() {
// Empty constructor
}
/**
* Executes the short16 to byte8 conversion operation.
*
* @param parts The array of instruction parameters, which is not used in this operation.
* @param currentPC The current program counter, representing the instruction address.
* @param operandStack The operand stack of the virtual machine.
* @param localVariableStore The local variable store for managing method-local variables.
* @param callStack The call stack of the virtual machine.
* @return The updated program counter after execution.
*/
@Override
public int execute(String[] parts, int currentPC, OperandStack operandStack,
LocalVariableStore localVariableStore, CallStack callStack) {
short value = (short) operandStack.pop();
byte convertedValue = (byte) value;
operandStack.push(convertedValue);
return currentPC + 1;
}
}

View File

@ -0,0 +1,47 @@
package org.jcnc.snow.vm.commands.type.conversion;
import org.jcnc.snow.vm.interfaces.Command;
import org.jcnc.snow.vm.module.CallStack;
import org.jcnc.snow.vm.module.LocalVariableStore;
import org.jcnc.snow.vm.module.OperandStack;
/**
* S2DCommand Opcode: Represents the type conversion operation from short16 to double64 in the virtual machine.
* <p>This opcode is implemented by the {@link S2DCommand} class, which defines its specific execution logic.</p>
*
* <p>Execution Steps:</p>
* <ol>
* <li>Pop the top short16 value from the operand stack.</li>
* <li>Convert the short16 value to a double64 value.</li>
* <li>Push the converted double64 value back onto the operand stack for subsequent operations.</li>
* </ol>
*
* <p>This opcode is used to widen a short16 value to a double64 type.</p>
*/
public class S2DCommand implements Command {
/**
* Default constructor for creating an instance of S2DCommand.
*/
public S2DCommand() {
// Empty constructor
}
/**
* Executes the short16 to double64 conversion operation.
*
* @param parts The array of instruction parameters, which is not used in this operation.
* @param currentPC The current program counter, representing the instruction address.
* @param operandStack The operand stack of the virtual machine.
* @param localVariableStore The local variable store for managing method-local variables.
* @param callStack The call stack of the virtual machine.
* @return The updated program counter after execution.
*/
@Override
public int execute(String[] parts, int currentPC, OperandStack operandStack,
LocalVariableStore localVariableStore, CallStack callStack) {
double convertedValue = (short) operandStack.pop();
operandStack.push(convertedValue);
return currentPC + 1;
}
}

View File

@ -0,0 +1,47 @@
package org.jcnc.snow.vm.commands.type.conversion;
import org.jcnc.snow.vm.interfaces.Command;
import org.jcnc.snow.vm.module.CallStack;
import org.jcnc.snow.vm.module.LocalVariableStore;
import org.jcnc.snow.vm.module.OperandStack;
/**
* S2FCommand Opcode: Represents the type conversion operation from short16 to float32 in the virtual machine.
* <p>This opcode is implemented by the {@link S2FCommand} class, which defines its specific execution logic.</p>
*
* <p>Execution Steps:</p>
* <ol>
* <li>Pop the top short16 value from the operand stack.</li>
* <li>Convert the short16 value to a float32 value.</li>
* <li>Push the converted float32 value back onto the operand stack for subsequent operations.</li>
* </ol>
*
* <p>This opcode is used to widen a short16 value to a float32 type.</p>
*/
public class S2FCommand implements Command {
/**
* Default constructor for creating an instance of S2FCommand.
*/
public S2FCommand() {
// Empty constructor
}
/**
* Executes the short16 to float32 conversion operation.
*
* @param parts The array of instruction parameters, which is not used in this operation.
* @param currentPC The current program counter, representing the instruction address.
* @param operandStack The operand stack of the virtual machine.
* @param localVariableStore The local variable store for managing method-local variables.
* @param callStack The call stack of the virtual machine.
* @return The updated program counter after execution.
*/
@Override
public int execute(String[] parts, int currentPC, OperandStack operandStack,
LocalVariableStore localVariableStore, CallStack callStack) {
float convertedValue = (short) operandStack.pop();
operandStack.push(convertedValue);
return currentPC + 1;
}
}

View File

@ -16,7 +16,7 @@ import org.jcnc.snow.vm.module.OperandStack;
* <li>Push the converted int32 value back onto the operand stack for subsequent operations.</li>
* </ol>
*
* <p>This opcode is used to widen a short16 value to an int32 type, facilitating subsequent integer arithmetic or comparison operations.</p>
* <p>This opcode is used to widen a short16 value to an int32 type.</p>
*/
public class S2ICommand implements Command {

View File

@ -0,0 +1,47 @@
package org.jcnc.snow.vm.commands.type.conversion;
import org.jcnc.snow.vm.interfaces.Command;
import org.jcnc.snow.vm.module.CallStack;
import org.jcnc.snow.vm.module.LocalVariableStore;
import org.jcnc.snow.vm.module.OperandStack;
/**
* S2LCommand Opcode: Represents the type conversion operation from short16 to long64 in the virtual machine.
* <p>This opcode is implemented by the {@link S2LCommand} class, which defines its specific execution logic.</p>
*
* <p>Execution Steps:</p>
* <ol>
* <li>Pop the top short16 value from the operand stack.</li>
* <li>Convert the short16 value to a long64 value.</li>
* <li>Push the converted long64 value back onto the operand stack for subsequent operations.</li>
* </ol>
*
* <p>This opcode is used to widen a short16 value to a long64 type.</p>
*/
public class S2LCommand implements Command {
/**
* Default constructor for creating an instance of S2LCommand.
*/
public S2LCommand() {
// Empty constructor
}
/**
* Executes the short16 to long64 conversion operation.
*
* @param parts The array of instruction parameters, which is not used in this operation.
* @param currentPC The current program counter, representing the instruction address.
* @param operandStack The operand stack of the virtual machine.
* @param localVariableStore The local variable store for managing method-local variables.
* @param callStack The call stack of the virtual machine.
* @return The updated program counter after execution.
*/
@Override
public int execute(String[] parts, int currentPC, OperandStack operandStack,
LocalVariableStore localVariableStore, CallStack callStack) {
long convertedValue = (short) operandStack.pop();
operandStack.push(convertedValue);
return currentPC + 1;
}
}

View File

@ -2043,216 +2043,21 @@ public class VMOpCode {
// endregion
// region Type Conversion (0x00C0-0x00DF)
// region Byte8 (0x00C0-0xC4)
/**
* I2L Opcode: Represents the type conversion operation from int32 to long64 in the virtual machine.
* <p>This opcode is implemented by the {@link I2LCommand} class, which defines its specific execution logic.</p>
* B2S Opcode: Represents the type conversion operation from byte8 to short16 in the virtual machine.
* <p>This opcode is implemented by the {@link B2SCommand} class, which defines its specific execution logic.</p>
*
* <p>Execution Steps:</p>
* <ol>
* <li>Pop the top int32 value from the operand stack.</li>
* <li>Convert the int32 value to a long64 value.</li>
* <li>Push the converted long64 value back onto the operand stack for subsequent operations.</li>
* </ol>
*
* <p>This opcode is commonly used to widen an int32 value to a long64 type to accommodate larger numeric ranges.</p>
*/
public static final int I2L = 0x00C0;
/**
* I2S Opcode: Represents the type conversion operation from int32 to short16 in the virtual machine.
* <p>This opcode is implemented by the {@link I2SCommand} class, which defines its specific execution logic.</p>
*
* <p>Execution Steps:</p>
* <ol>
* <li>Pop the top int32 value from the operand stack.</li>
* <li>Convert the int32 value to a short16 value (this may involve truncation).</li>
* <li>Pop the top byte8 value from the operand stack.</li>
* <li>Convert the byte8 value to a short16 value.</li>
* <li>Push the converted short16 value back onto the operand stack for subsequent operations.</li>
* </ol>
*
* <p>This opcode is typically used to narrow an int32 value to a short16 type when a smaller data representation is needed.</p>
* <p>This opcode is commonly used to widen a byte8 value to a short16 type.</p>
*/
public static final int I2S = 0x00C1;
/**
* I2B Opcode: Represents the type conversion operation from int32 to byte8 in the virtual machine.
* <p>This opcode is implemented by the {@link I2BCommand} class, which defines its specific execution logic.</p>
*
* <p>Execution Steps:</p>
* <ol>
* <li>Pop the top int32 value from the operand stack.</li>
* <li>Convert the int32 value to a byte8 value (this may involve truncation).</li>
* <li>Push the converted byte8 value back onto the operand stack for subsequent operations.</li>
* </ol>
*
* <p>This opcode is used to narrow an int32 value to a byte8 type, suitable when a smaller numeric type is required.</p>
*/
public static final int I2B = 0x00C2;
/**
* I2D Opcode: Represents the type conversion operation from int32 to double64 in the virtual machine.
* <p>This opcode is implemented by the {@link I2DCommand} class, which defines its specific execution logic.</p>
*
* <p>Execution Steps:</p>
* <ol>
* <li>Pop the top int32 value from the operand stack.</li>
* <li>Convert the int32 value to a double64 value.</li>
* <li>Push the converted double64 value back onto the operand stack for subsequent operations.</li>
* </ol>
*
* <p>This opcode is used to widen an int32 value to a double64 type, providing high-precision floating-point calculations.</p>
*/
public static final int I2D = 0x00C3;
/**
* I2F Opcode: Represents the type conversion operation from int32 to float32 in the virtual machine.
* <p>This opcode is implemented by the {@link I2FCommand} class, which defines its specific execution logic.</p>
*
* <p>Execution Steps:</p>
* <ol>
* <li>Pop the top int32 value from the operand stack.</li>
* <li>Convert the int32 value to a float32 value.</li>
* <li>Push the converted float32 value back onto the operand stack for subsequent operations.</li>
* </ol>
*
* <p>This opcode is used to convert an int32 value to a float32 type when floating-point arithmetic is required.</p>
*/
public static final int I2F = 0x00C4;
/**
* L2I Opcode: Represents the type conversion operation from long64 to int32 in the virtual machine.
* <p>This opcode is implemented by the {@link L2ICommand} class, which defines its specific execution logic.</p>
*
* <p>Execution Steps:</p>
* <ol>
* <li>Pop the top long64 value from the operand stack.</li>
* <li>Convert the long64 value to an int32 value (this may involve truncation).</li>
* <li>Push the converted int32 value back onto the operand stack for subsequent operations.</li>
* </ol>
*
* <p>This opcode is typically used to narrow a long64 value to an int32 type for further integer operations.</p>
*/
public static final int L2I = 0x00C5;
/**
* L2D Opcode: Represents the type conversion operation from long64 to double64 in the virtual machine.
* <p>This opcode is implemented by the {@link L2DCommand} class, which defines its specific execution logic.</p>
*
* <p>Execution Steps:</p>
* <ol>
* <li>Pop the top long64 value from the operand stack.</li>
* <li>Convert the long64 value to a double64 value.</li>
* <li>Push the converted double64 value back onto the operand stack for subsequent operations.</li>
* </ol>
*
* <p>This opcode is used to widen a long64 value to a double64 type for high-precision floating-point computations.</p>
*/
public static final int L2D = 0x00C6;
/**
* L2F Opcode: Represents the type conversion operation from long64 to float32 in the virtual machine.
* <p>This opcode is implemented by the {@link L2FCommand} class, which defines its specific execution logic.</p>
*
* <p>Execution Steps:</p>
* <ol>
* <li>Pop the top long64 value from the operand stack.</li>
* <li>Convert the long64 value to a float32 value.</li>
* <li>Push the converted float32 value back onto the operand stack for subsequent operations.</li>
* </ol>
*
* <p>This opcode is used to convert a long64 value to a float32 type, typically for floating-point arithmetic involving long values.</p>
*/
public static final int L2F = 0x00C7;
/**
* F2I Opcode: Represents the type conversion operation from float32 to int32 in the virtual machine.
* <p>This opcode is implemented by the {@link F2ICommand} class, which defines its specific execution logic.</p>
*
* <p>Execution Steps:</p>
* <ol>
* <li>Pop the top float32 value from the operand stack.</li>
* <li>Convert the float32 value to an int32 value (this may involve truncation).</li>
* <li>Push the converted int32 value back onto the operand stack for subsequent operations.</li>
* </ol>
*
* <p>This opcode is used to convert a float32 value to an int32 type for further integer-based operations or comparisons.</p>
*/
public static final int F2I = 0x00C8;
/**
* F2L Opcode: Represents the type conversion operation from float32 to long64 in the virtual machine.
* <p>This opcode is implemented by the {@link F2LCommand} class, which defines its specific execution logic.</p>
*
* <p>Execution Steps:</p>
* <ol>
* <li>Pop the top float32 value from the operand stack.</li>
* <li>Convert the float32 value to a long64 value.</li>
* <li>Push the converted long64 value back onto the operand stack for subsequent operations.</li>
* </ol>
*
* <p>This opcode is used to widen a float32 value to a long64 type, which is useful when operations require a larger numeric range.</p>
*/
public static final int F2L = 0x00C9;
/**
* F2D Opcode: Represents the type conversion operation from float32 to double64 in the virtual machine.
* <p>This opcode is implemented by the {@link F2DCommand} class, which defines its specific execution logic.</p>
*
* <p>Execution Steps:</p>
* <ol>
* <li>Pop the top float32 value from the operand stack.</li>
* <li>Convert the float32 value to a double64 value.</li>
* <li>Push the converted double64 value back onto the operand stack for subsequent operations.</li>
* </ol>
*
* <p>This opcode is used to promote a float32 value to a double64 type, thereby increasing precision for floating-point computations.</p>
*/
public static final int F2D = 0x00CA;
/**
* D2I Opcode: Represents the type conversion operation from double64 to int32 in the virtual machine.
* <p>This opcode is implemented by the {@link D2ICommand} class, which defines its specific execution logic.</p>
*
* <p>Execution Steps:</p>
* <ol>
* <li>Pop the top double64 value from the operand stack.</li>
* <li>Convert the double64 value to an int32 value (this may involve truncation).</li>
* <li>Push the converted int32 value back onto the operand stack for subsequent operations.</li>
* </ol>
*
* <p>This opcode is used to narrow a double64 value to an int32 type for further integer-based processing.</p>
*/
public static final int D2I = 0x00CB;
/**
* D2L Opcode: Represents the type conversion operation from double64 to long64 in the virtual machine.
* <p>This opcode is implemented by the {@link D2LCommand} class, which defines its specific execution logic.</p>
*
* <p>Execution Steps:</p>
* <ol>
* <li>Pop the top double64 value from the operand stack.</li>
* <li>Convert the double64 value to a long64 value (this may involve truncation).</li>
* <li>Push the converted long64 value back onto the operand stack for subsequent operations.</li>
* </ol>
*
* <p>This opcode is used to narrow a double64 value to a long64 type, which can then be used for integer operations.</p>
*/
public static final int D2L = 0x00CC;
/**
* D2F Opcode: Represents the type conversion operation from double64 to float32 in the virtual machine.
* <p>This opcode is implemented by the {@link D2FCommand} class, which defines its specific execution logic.</p>
*
* <p>Execution Steps:</p>
* <ol>
* <li>Pop the top double64 value from the operand stack.</li>
* <li>Convert the double64 value to a float32 value.</li>
* <li>Push the converted float32 value back onto the operand stack for subsequent operations.</li>
* </ol>
*
* <p>This opcode is used to narrow a double64 value to a float32 type when lower precision floating-point arithmetic is acceptable.</p>
*/
public static final int D2F = 0x00CD;
/**
* S2I Opcode: Represents the type conversion operation from short16 to int32 in the virtual machine.
* <p>This opcode is implemented by the {@link S2ICommand} class, which defines its specific execution logic.</p>
*
* <p>Execution Steps:</p>
* <ol>
* <li>Pop the top short16 value from the operand stack.</li>
* <li>Convert the short16 value to an int32 value.</li>
* <li>Push the converted int32 value back onto the operand stack for subsequent operations.</li>
* </ol>
*
* <p>This opcode is used to widen a short16 value to an int32 type, facilitating subsequent integer arithmetic or comparison operations.</p>
*/
public static final int S2I = 0x00CE;
public static final int B2S = 0x00C0;
/**
* B2I Opcode: Represents the type conversion operation from byte8 to int32 in the virtual machine.
* <p>This opcode is implemented by the {@link B2ICommand} class, which defines its specific execution logic.</p>
@ -2264,10 +2069,418 @@ public class VMOpCode {
* <li>Push the converted int32 value back onto the operand stack for subsequent operations.</li>
* </ol>
*
* <p>This opcode is used to widen a byte8 value to an int32 type to ensure compatibility with integer-based operations.</p>
* <p>This opcode is commonly used to widen a byte8 value to an int32 type.</p>
*/
public static final int B2I = 0x00CF;
// endregion
public static final int B2I = 0x00C1;
/**
* B2L Opcode: Represents the type conversion operation from byte8 to long64 in the virtual machine.
* <p>This opcode is implemented by the {@link B2LCommand} class, which defines its specific execution logic.</p>
*
* <p>Execution Steps:</p>
* <ol>
* <li>Pop the top byte8 value from the operand stack.</li>
* <li>Convert the byte8 value to a long64 value.</li>
* <li>Push the converted long64 value back onto the operand stack for subsequent operations.</li>
* </ol>
*
* <p>This opcode is commonly used to widen a byte8 value to a long64 type.</p>
*/
public static final int B2L = 0x00C2;
/**
* B2F Opcode: Represents the type conversion operation from byte8 to float32 in the virtual machine.
* <p>This opcode is implemented by the {@link B2FCommand} class, which defines its specific execution logic.</p>
*
* <p>Execution Steps:</p>
* <ol>
* <li>Pop the top byte8 value from the operand stack.</li>
* <li>Convert the byte8 value to a float32 value.</li>
* <li>Push the converted float32 value back onto the operand stack for subsequent operations.</li>
* </ol>
*
* <p>This opcode is used to convert a byte8 value to a float32 type.</p>
*/
public static final int B2F = 0x00C3;
/**
* B2D Opcode: Represents the type conversion operation from byte8 to double64 in the virtual machine.
* <p>This opcode is implemented by the {@link B2DCommand} class, which defines its specific execution logic.</p>
*
* <p>Execution Steps:</p>
* <ol>
* <li>Pop the top byte8 value from the operand stack.</li>
* <li>Convert the byte8 value to a double64 value.</li>
* <li>Push the converted double64 value back onto the operand stack for subsequent operations.</li>
* </ol>
*
* <p>This opcode is used to widen a byte8 value to a double64 type.</p>
*/
public static final int B2D = 0x00C4;
// endregion Byte8
// region Short16 (0x00C5-0xC9)
/**
* S2B Opcode: Represents the type conversion operation from short16 to byte8 in the virtual machine.
* <p>This opcode is implemented by the {@link S2BCommand} class, which defines its specific execution logic.</p>
*
* <p>Execution Steps:</p>
* <ol>
* <li>Pop the top short16 value from the operand stack.</li>
* <li>Convert the short16 value to a byte8 value (this may involve truncation).</li>
* <li>Push the converted byte8 value back onto the operand stack for subsequent operations.</li>
* </ol>
*
* <p>This opcode is used to narrow a short16 value to a byte8 type.</p>
*/
public static final int S2B = 0x00C5;
/**
* S2I Opcode: Represents the type conversion operation from short16 to int32 in the virtual machine.
* <p>This opcode is implemented by the {@link S2ICommand} class, which defines its specific execution logic.</p>
*
* <p>Execution Steps:</p>
* <ol>
* <li>Pop the top short16 value from the operand stack.</li>
* <li>Convert the short16 value to an int32 value.</li>
* <li>Push the converted int32 value back onto the operand stack for subsequent operations.</li>
* </ol>
*
* <p>This opcode is commonly used to widen a short16 value to an int32 type.</p>
*/
public static final int S2I = 0x00C6;
/**
* S2L Opcode: Represents the type conversion operation from short16 to long64 in the virtual machine.
* <p>This opcode is implemented by the {@link S2LCommand} class, which defines its specific execution logic.</p>
*
* <p>Execution Steps:</p>
* <ol>
* <li>Pop the top short16 value from the operand stack.</li>
* <li>Convert the short16 value to a long64 value.</li>
* <li>Push the converted long64 value back onto the operand stack for subsequent operations.</li>
* </ol>
*
* <p>This opcode is commonly used to widen a short16 value to a long64 type.</p>
*/
public static final int S2L = 0x00C7;
/**
* S2F Opcode: Represents the type conversion operation from short16 to float32 in the virtual machine.
* <p>This opcode is implemented by the {@link S2FCommand} class, which defines its specific execution logic.</p>
*
* <p>Execution Steps:</p>
* <ol>
* <li>Pop the top short16 value from the operand stack.</li>
* <li>Convert the short16 value to a float32 value.</li>
* <li>Push the converted float32 value back onto the operand stack for subsequent operations.</li>
* </ol>
*
* <p>This opcode is used to convert a short16 value to a float32 type.</p>
*/
public static final int S2F = 0x00C8;
/**
* S2D Opcode: Represents the type conversion operation from short16 to double64 in the virtual machine.
* <p>This opcode is implemented by the {@link S2DCommand} class, which defines its specific execution logic.</p>
*
* <p>Execution Steps:</p>
* <ol>
* <li>Pop the top short16 value from the operand stack.</li>
* <li>Convert the short16 value to a double64 value.</li>
* <li>Push the converted double64 value back onto the operand stack for subsequent operations.</li>
* </ol>
*
* <p>This opcode is used to widen a short16 value to a double64 type.</p>
*/
public static final int S2D = 0x00C9;
// endregion Short16
// region Int32 (0x00CA-0xCE)
/**
* I2B Opcode: Represents the type conversion operation from int32 to byte8 in the virtual machine.
* <p>This opcode is implemented by the {@link I2BCommand} class, which defines its specific execution logic.</p>
*
* <p>Execution Steps:</p>
* <ol>
* <li>Pop the top int32 value from the operand stack.</li>
* <li>Convert the int32 value to a byte8 value (this may involve truncation).</li>
* <li>Push the converted byte8 value back onto the operand stack for subsequent operations.</li>
* </ol>
*
* <p>This opcode is used to narrow an int32 value to a byte8 type.</p>
*/
public static final int I2B = 0x00CA;
/**
* I2S Opcode: Represents the type conversion operation from int32 to short16 in the virtual machine.
* <p>This opcode is implemented by the {@link I2SCommand} class, which defines its specific execution logic.</p>
*
* <p>Execution Steps:</p>
* <ol>
* <li>Pop the top int32 value from the operand stack.</li>
* <li>Convert the int32 value to a short16 value (this may involve truncation).</li>
* <li>Push the converted short16 value back onto the operand stack for subsequent operations.</li>
* </ol>
*
* <p>This opcode is typically used to narrow an int32 value to a short16 type.</p>
*/
public static final int I2S = 0x00CB;
/**
* I2L Opcode: Represents the type conversion operation from int32 to long64 in the virtual machine.
* <p>This opcode is implemented by the {@link I2LCommand} class, which defines its specific execution logic.</p>
*
* <p>Execution Steps:</p>
* <ol>
* <li>Pop the top int32 value from the operand stack.</li>
* <li>Convert the int32 value to a long64 value.</li>
* <li>Push the converted long64 value back onto the operand stack for subsequent operations.</li>
* </ol>
*
* <p>This opcode is commonly used to widen an int32 value to a long64 type.</p>
*/
public static final int I2L = 0x00CC;
/**
* I2F Opcode: Represents the type conversion operation from int32 to float32 in the virtual machine.
* <p>This opcode is implemented by the {@link I2FCommand} class, which defines its specific execution logic.</p>
*
* <p>Execution Steps:</p>
* <ol>
* <li>Pop the top int32 value from the operand stack.</li>
* <li>Convert the int32 value to a float32 value.</li>
* <li>Push the converted float32 value back onto the operand stack for subsequent operations.</li>
* </ol>
*
* <p>This opcode is used to convert an int32 value to a float32 type.</p>
*/
public static final int I2F = 0x00CD;
/**
* I2D Opcode: Represents the type conversion operation from int32 to double64 in the virtual machine.
* <p>This opcode is implemented by the {@link I2DCommand} class, which defines its specific execution logic.</p>
*
* <p>Execution Steps:</p>
* <ol>
* <li>Pop the top int32 value from the operand stack.</li>
* <li>Convert the int32 value to a double64 value.</li>
* <li>Push the converted double64 value back onto the operand stack for subsequent operations.</li>
* </ol>
*
* <p>This opcode is used to widen an int32 value to a double64 type.</p>
*/
public static final int I2D = 0x00CE;
// endregion Int32
// region Long64 (0x00CF-0xD3)
/**
* L2B Opcode: Represents the type conversion operation from long64 to byte8 in the virtual machine.
* <p>This opcode is implemented by the {@link L2BCommand} class, which defines its specific execution logic.</p>
*
* <p>Execution Steps:</p>
* <ol>
* <li>Pop the top long64 value from the operand stack.</li>
* <li>Convert the long64 value to a byte8 value (this may involve truncation).</li>
* <li>Push the converted byte8 value back onto the operand stack for subsequent operations.</li>
* </ol>
*
* <p>This opcode is used to narrow a long64 value to a byte8 type.</p>
*/
public static final int L2B = 0x00CF;
/**
* L2S Opcode: Represents the type conversion operation from long64 to short16 in the virtual machine.
* <p>This opcode is implemented by the {@link L2SCommand} class, which defines its specific execution logic.</p>
*
* <p>Execution Steps:</p>
* <ol>
* <li>Pop the top long64 value from the operand stack.</li>
* <li>Convert the long64 value to a short16 value (this may involve truncation).</li>
* <li>Push the converted short16 value back onto the operand stack for subsequent operations.</li>
* </ol>
*
* <p>This opcode is used to narrow a long64 value to a short16 type.</p>
*/
public static final int L2S = 0x00D0;
/**
* L2I Opcode: Represents the type conversion operation from long64 to int32 in the virtual machine.
* <p>This opcode is implemented by the {@link L2ICommand} class, which defines its specific execution logic.</p>
*
* <p>Execution Steps:</p>
* <ol>
* <li>Pop the top long64 value from the operand stack.</li>
* <li>Convert the long64 value to an int32 value (this may involve truncation).</li>
* <li>Push the converted int32 value back onto the operand stack for subsequent operations.</li>
* </ol>
*
* <p>This opcode is typically used to narrow a long64 value to an int32 type .</p>
*/
public static final int L2I = 0x00D1;
/**
* L2F Opcode: Represents the type conversion operation from long64 to float32 in the virtual machine.
* <p>This opcode is implemented by the {@link L2FCommand} class, which defines its specific execution logic.</p>
*
* <p>Execution Steps:</p>
* <ol>
* <li>Pop the top long64 value from the operand stack.</li>
* <li>Convert the long64 value to a float32 value.</li>
* <li>Push the converted float32 value back onto the operand stack for subsequent operations.</li>
* </ol>
*
* <p>This opcode is used to convert a long64 value to a float32 type.</p>
*/
public static final int L2F = 0x00D2;
/**
* L2D Opcode: Represents the type conversion operation from long64 to double64 in the virtual machine.
* <p>This opcode is implemented by the {@link L2DCommand} class, which defines its specific execution logic.</p>
*
* <p>Execution Steps:</p>
* <ol>
* <li>Pop the top long64 value from the operand stack.</li>
* <li>Convert the long64 value to a double64 value.</li>
* <li>Push the converted double64 value back onto the operand stack for subsequent operations.</li>
* </ol>
*
* <p>This opcode is used to widen a long64 value to a double64 type.</p>
*/
public static final int L2D = 0x00D3;
// endregion Long64
// region Float32 (0x00D4-0xD8)
/**
* F2B Opcode: Represents the type conversion operation from float32 to byte8 in the virtual machine.
* <p>This opcode is implemented by the {@link F2BCommand} class, which defines its specific execution logic.</p>
*
* <p>Execution Steps:</p>
* <ol>
* <li>Pop the top float32 value from the operand stack.</li>
* <li>Convert the float32 value to a byte8 value (this may involve truncation).</li>
* <li>Push the converted byte8 value back onto the operand stack for subsequent operations.</li>
* </ol>
*
* <p>This opcode is used to convert a float32 value to a byte8 type.</p>
*/
public static final int F2B = 0x00D4;
/**
* F2S Opcode: Represents the type conversion operation from float32 to short16 in the virtual machine.
* <p>This opcode is implemented by the {@link F2SCommand} class, which defines its specific execution logic.</p>
*
* <p>Execution Steps:</p>
* <ol>
* <li>Pop the top float32 value from the operand stack.</li>
* <li>Convert the float32 value to a short16 value (this may involve truncation).</li>
* <li>Push the converted short16 value back onto the operand stack for subsequent operations.</li>
* </ol>
*
* <p>This opcode is used to convert a float32 value to a short16 type.</p>
*/
public static final int F2S = 0x00D5;
/**
* F2I Opcode: Represents the type conversion operation from float32 to int32 in the virtual machine.
* <p>This opcode is implemented by the {@link F2ICommand} class, which defines its specific execution logic.</p>
*
* <p>Execution Steps:</p>
* <ol>
* <li>Pop the top float32 value from the operand stack.</li>
* <li>Convert the float32 value to an int32 value (this may involve truncation).</li>
* <li>Push the converted int32 value back onto the operand stack for subsequent operations.</li>
* </ol>
*
* <p>This opcode is used to convert a float32 value to an int32 type.</p>
*/
public static final int F2I = 0x00D6;
/**
* F2L Opcode: Represents the type conversion operation from float32 to long64 in the virtual machine.
* <p>This opcode is implemented by the {@link F2LCommand} class, which defines its specific execution logic.</p>
*
* <p>Execution Steps:</p>
* <ol>
* <li>Pop the top float32 value from the operand stack.</li>
* <li>Convert the float32 value to a long64 value.</li>
* <li>Push the converted long64 value back onto the operand stack for subsequent operations.</li>
* </ol>
*
* <p>This opcode is used to widen a float32 value to a long64 type.</p>
*/
public static final int F2L = 0x00D7;
/**
* F2D Opcode: Represents the type conversion operation from float32 to double64 in the virtual machine.
* <p>This opcode is implemented by the {@link F2DCommand} class, which defines its specific execution logic.</p>
*
* <p>Execution Steps:</p>
* <ol>
* <li>Pop the top float32 value from the operand stack.</li>
* <li>Convert the float32 value to a double64 value.</li>
* <li>Push the converted double64 value back onto the operand stack for subsequent operations.</li>
* </ol>
*
* <p>This opcode is used to promote a float32 value to a double64 type.</p>
*/
public static final int F2D = 0x00D8;
// endregion Float32
// region Double64 (0x00D9-0xDD)
/**
* D2B Opcode: Represents the type conversion operation from double64 to byte8 in the virtual machine.
* <p>This opcode is implemented by the {@link D2BCommand} class, which defines its specific execution logic.</p>
*
* <p>Execution Steps:</p>
* <ol>
* <li>Pop the top double64 value from the operand stack.</li>
* <li>Convert the double64 value to a byte8 value (this may involve truncation).</li>
* <li>Push the converted byte8 value back onto the operand stack for subsequent operations.</li>
* </ol>
*
* <p>This opcode is used to narrow a double64 value to a byte8 type.</p>
*/
public static final int D2B = 0x00D9;
/**
* D2S Opcode: Represents the type conversion operation from double64 to short16 in the virtual machine.
* <p>This opcode is implemented by the {@link D2SCommand} class, which defines its specific execution logic.</p>
*
* <p>Execution Steps:</p>
* <ol>
* <li>Pop the top double64 value from the operand stack.</li>
* <li>Convert the double64 value to a short16 value (this may involve truncation).</li>
* <li>Push the converted short16 value back onto the operand stack for subsequent operations.</li>
* </ol>
*
* <p>This opcode is used to narrow a double64 value to a short16 type.</p>
*/
public static final int D2S = 0x00DA;
/**
* D2I Opcode: Represents the type conversion operation from double64 to int32 in the virtual machine.
* <p>This opcode is implemented by the {@link D2ICommand} class, which defines its specific execution logic.</p>
*
* <p>Execution Steps:</p>
* <ol>
* <li>Pop the top double64 value from the operand stack.</li>
* <li>Convert the double64 value to an int32 value (this may involve truncation).</li>
* <li>Push the converted int32 value back onto the operand stack for subsequent operations.</li>
* </ol>
*
* <p>This opcode is used to narrow a double64 value to an int32 type.</p>
*/
public static final int D2I = 0x00DB;
/**
* D2L Opcode: Represents the type conversion operation from double64 to long64 in the virtual machine.
* <p>This opcode is implemented by the {@link D2LCommand} class, which defines its specific execution logic.</p>
*
* <p>Execution Steps:</p>
* <ol>
* <li>Pop the top double64 value from the operand stack.</li>
* <li>Convert the double64 value to a long64 value (this may involve truncation).</li>
* <li>Push the converted long64 value back onto the operand stack for subsequent operations.</li>
* </ol>
*
* <p>This opcode is used to narrow a double64 value to a long64 type.</p>
*/
public static final int D2L = 0x00DC;
/**
* D2F Opcode: Represents the type conversion operation from double64 to float32 in the virtual machine.
* <p>This opcode is implemented by the {@link D2FCommand} class, which defines its specific execution logic.</p>
*
* <p>Execution Steps:</p>
* <ol>
* <li>Pop the top double64 value from the operand stack.</li>
* <li>Convert the double64 value to a float32 value.</li>
* <li>Push the converted float32 value back onto the operand stack for subsequent operations.</li>
* </ol>
*
* <p>This opcode is used to narrow a double64 value to a float32 type.</p>
*/
public static final int D2F = 0x00DD;
// endregion Double64
// endregion Conversion
// region Stack Control (0x0100-0x01FF)
/**

View File

@ -207,26 +207,41 @@ public class CommandFactory {
// endregion
// region Type Conversion (0x00C0-0x00DF)
COMMANDS[VMOpCode.I2L] = new I2LCommand();
COMMANDS[VMOpCode.I2S] = new I2SCommand();
COMMANDS[VMOpCode.B2S] = new B2SCommand();
COMMANDS[VMOpCode.B2I] = new B2ICommand();
COMMANDS[VMOpCode.B2L] = new B2LCommand();
COMMANDS[VMOpCode.B2F] = new B2FCommand();
COMMANDS[VMOpCode.B2D] = new B2DCommand();
COMMANDS[VMOpCode.S2B] = new S2BCommand();
COMMANDS[VMOpCode.S2I] = new S2ICommand();
COMMANDS[VMOpCode.S2L] = new S2LCommand();
COMMANDS[VMOpCode.S2F] = new S2FCommand();
COMMANDS[VMOpCode.S2D] = new S2DCommand();
COMMANDS[VMOpCode.I2B] = new I2BCommand();
COMMANDS[VMOpCode.I2D] = new I2DCommand();
COMMANDS[VMOpCode.I2S] = new I2SCommand();
COMMANDS[VMOpCode.I2L] = new I2LCommand();
COMMANDS[VMOpCode.I2F] = new I2FCommand();
COMMANDS[VMOpCode.I2D] = new I2DCommand();
COMMANDS[VMOpCode.L2B] = new L2BCommand();
COMMANDS[VMOpCode.L2S] = new L2SCommand();
COMMANDS[VMOpCode.L2I] = new L2ICommand();
COMMANDS[VMOpCode.L2D] = new L2DCommand();
COMMANDS[VMOpCode.L2F] = new L2FCommand();
COMMANDS[VMOpCode.L2D] = new L2DCommand();
COMMANDS[VMOpCode.F2B] = new F2BCommand();
COMMANDS[VMOpCode.F2S] = new F2SCommand();
COMMANDS[VMOpCode.F2I] = new F2ICommand();
COMMANDS[VMOpCode.F2L] = new F2LCommand();
COMMANDS[VMOpCode.F2D] = new F2DCommand();
COMMANDS[VMOpCode.D2B] = new D2BCommand();
COMMANDS[VMOpCode.D2S] = new D2SCommand();
COMMANDS[VMOpCode.D2I] = new D2ICommand();
COMMANDS[VMOpCode.D2L] = new D2LCommand();
COMMANDS[VMOpCode.D2F] = new D2FCommand();
COMMANDS[VMOpCode.S2I] = new S2ICommand();
COMMANDS[VMOpCode.B2I] = new B2ICommand();
// endregion
// region Stack Control (0x0100-0x01FF)