Merge branch 'dev' into feature/user-cli
This commit is contained in:
commit
0f4659c8b4
17
.run/Demo8.run.xml
Normal file
17
.run/Demo8.run.xml
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="Demo8" type="Application" factoryName="Application" folderName="Demo" activateToolWindowBeforeRun="false">
|
||||||
|
<option name="ALTERNATIVE_JRE_PATH" value="graalvm-ce-23" />
|
||||||
|
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.compiler.cli.SnowCompiler" />
|
||||||
|
<module name="Snow" />
|
||||||
|
<option name="PROGRAM_PARAMETERS" value="-d playground/Demo8" />
|
||||||
|
<extension name="coverage">
|
||||||
|
<pattern>
|
||||||
|
<option name="PATTERN" value="org.jcnc.snow.compiler.parser.preprocessor.lexer.impl.api.*" />
|
||||||
|
<option name="ENABLED" value="true" />
|
||||||
|
</pattern>
|
||||||
|
</extension>
|
||||||
|
<method v="2">
|
||||||
|
<option name="Make" enabled="true" />
|
||||||
|
</method>
|
||||||
|
</configuration>
|
||||||
|
</component>
|
||||||
12
playground/Demo8/Main.snow
Normal file
12
playground/Demo8/Main.snow
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
module: Main
|
||||||
|
function: main
|
||||||
|
parameter:
|
||||||
|
return_type: long
|
||||||
|
body:
|
||||||
|
declare n: long
|
||||||
|
n = 2147483647
|
||||||
|
n = n + 1
|
||||||
|
return n
|
||||||
|
end body
|
||||||
|
end function
|
||||||
|
end module
|
||||||
@ -28,6 +28,60 @@ public class CmpJumpGenerator implements InstructionGenerator<IRCompareJumpInstr
|
|||||||
return IRCompareJumpInstruction.class;
|
return IRCompareJumpInstruction.class;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 类型优先级:D > F > L > I > S > 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取从类型 {@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;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 生成条件比较跳转相关的虚拟机指令。
|
* 生成条件比较跳转相关的虚拟机指令。
|
||||||
*
|
*
|
||||||
@ -45,10 +99,22 @@ public class CmpJumpGenerator implements InstructionGenerator<IRCompareJumpInstr
|
|||||||
int leftSlot = slotMap.get(ins.left());
|
int leftSlot = slotMap.get(ins.left());
|
||||||
// 获取右操作数所在的寄存器槽编号
|
// 获取右操作数所在的寄存器槽编号
|
||||||
int rightSlot = slotMap.get(ins.right());
|
int rightSlot = slotMap.get(ins.right());
|
||||||
|
|
||||||
|
char lType = out.getSlotType(leftSlot); // 未登记默认 'I'
|
||||||
|
char rType = out.getSlotType(rightSlot);
|
||||||
|
|
||||||
|
char tType = promote(lType, rType); // 类型提升结果
|
||||||
|
|
||||||
// 加载左操作数到虚拟机栈
|
// 加载左操作数到虚拟机栈
|
||||||
out.emit(OpHelper.opcode("I_LOAD") + " " + leftSlot);
|
out.emit(OpHelper.opcode(str(lType) + "_LOAD") + " " + leftSlot);
|
||||||
|
String cvt = convert(lType, tType);
|
||||||
|
if (cvt != null) out.emit(OpHelper.opcode(cvt));
|
||||||
|
|
||||||
// 加载右操作数到虚拟机栈
|
// 加载右操作数到虚拟机栈
|
||||||
out.emit(OpHelper.opcode("I_LOAD") + " " + rightSlot);
|
out.emit(OpHelper.opcode(str(rType) + "_LOAD") + " " + rightSlot);
|
||||||
|
cvt = convert(rType, tType);
|
||||||
|
if (cvt != null) out.emit(OpHelper.opcode(cvt));
|
||||||
|
|
||||||
// 获取与当前比较操作对应的虚拟机操作码
|
// 获取与当前比较操作对应的虚拟机操作码
|
||||||
String cmpOp = IROpCodeMapper.toVMOp(ins.op());
|
String cmpOp = IROpCodeMapper.toVMOp(ins.op());
|
||||||
// 生成分支跳转指令,如果比较成立则跳转到目标标签
|
// 生成分支跳转指令,如果比较成立则跳转到目标标签
|
||||||
|
|||||||
@ -82,6 +82,7 @@ public final class IROpCodeMapper {
|
|||||||
opcodeMap.put(IROpCode.NEG_D64, "D_NEG");
|
opcodeMap.put(IROpCode.NEG_D64, "D_NEG");
|
||||||
|
|
||||||
// 比较运算映射
|
// 比较运算映射
|
||||||
|
// 整形32位比较运算映射
|
||||||
opcodeMap.put(IROpCode.CMP_EQ, "IC_E"); // 相等
|
opcodeMap.put(IROpCode.CMP_EQ, "IC_E"); // 相等
|
||||||
opcodeMap.put(IROpCode.CMP_NE, "IC_NE"); // 不等
|
opcodeMap.put(IROpCode.CMP_NE, "IC_NE"); // 不等
|
||||||
opcodeMap.put(IROpCode.CMP_LT, "IC_L"); // 小于
|
opcodeMap.put(IROpCode.CMP_LT, "IC_L"); // 小于
|
||||||
@ -89,6 +90,14 @@ public final class IROpCodeMapper {
|
|||||||
opcodeMap.put(IROpCode.CMP_LE, "IC_LE"); // 小于等于
|
opcodeMap.put(IROpCode.CMP_LE, "IC_LE"); // 小于等于
|
||||||
opcodeMap.put(IROpCode.CMP_GE, "IC_GE"); // 大于等于
|
opcodeMap.put(IROpCode.CMP_GE, "IC_GE"); // 大于等于
|
||||||
|
|
||||||
|
// 整形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"); // 大于等于
|
||||||
|
|
||||||
// 加载与存储
|
// 加载与存储
|
||||||
opcodeMap.put(IROpCode.LOAD, "I_LOAD"); // 加载
|
opcodeMap.put(IROpCode.LOAD, "I_LOAD"); // 加载
|
||||||
opcodeMap.put(IROpCode.STORE, "I_STORE"); // 存储
|
opcodeMap.put(IROpCode.STORE, "I_STORE"); // 存储
|
||||||
|
|||||||
@ -95,6 +95,12 @@ public final class OpHelper {
|
|||||||
map.put("IC_GE", Integer.toString(VMOpCode.IC_GE));
|
map.put("IC_GE", Integer.toString(VMOpCode.IC_GE));
|
||||||
map.put("IC_L", Integer.toString(VMOpCode.IC_L));
|
map.put("IC_L", Integer.toString(VMOpCode.IC_L));
|
||||||
map.put("IC_LE", Integer.toString(VMOpCode.IC_LE));
|
map.put("IC_LE", Integer.toString(VMOpCode.IC_LE));
|
||||||
|
map.put("LC_E", Integer.toString(VMOpCode.LC_E));
|
||||||
|
map.put("LC_NE", Integer.toString(VMOpCode.LC_NE));
|
||||||
|
map.put("LC_G", Integer.toString(VMOpCode.LC_G));
|
||||||
|
map.put("LC_GE", Integer.toString(VMOpCode.LC_GE));
|
||||||
|
map.put("LC_L", Integer.toString(VMOpCode.LC_L));
|
||||||
|
map.put("LC_LE", Integer.toString(VMOpCode.LC_LE));
|
||||||
map.put("I_PUSH", Integer.toString(VMOpCode.I_PUSH));
|
map.put("I_PUSH", Integer.toString(VMOpCode.I_PUSH));
|
||||||
map.put("L_PUSH", Integer.toString(VMOpCode.L_PUSH));
|
map.put("L_PUSH", Integer.toString(VMOpCode.L_PUSH));
|
||||||
map.put("S_PUSH", Integer.toString(VMOpCode.S_PUSH));
|
map.put("S_PUSH", Integer.toString(VMOpCode.S_PUSH));
|
||||||
|
|||||||
@ -109,7 +109,7 @@ public record ExpressionBuilder(IRContext ctx) {
|
|||||||
switch (node) {
|
switch (node) {
|
||||||
// 数字字面量,直接加载到目标寄存器
|
// 数字字面量,直接加载到目标寄存器
|
||||||
case NumberLiteralNode n ->
|
case NumberLiteralNode n ->
|
||||||
InstructionFactory.loadConstInto(ctx, dest, ExpressionUtils.parseIntSafely(n.value()));
|
InstructionFactory.loadConstInto(ctx, dest, ExpressionUtils.buildNumberConstant(ctx, n.value()));
|
||||||
// 标识符,查找并move到目标寄存器
|
// 标识符,查找并move到目标寄存器
|
||||||
case IdentifierNode id -> {
|
case IdentifierNode id -> {
|
||||||
IRVirtualRegister src = ctx.getScope().lookup(id.name());
|
IRVirtualRegister src = ctx.getScope().lookup(id.name());
|
||||||
@ -207,7 +207,7 @@ public record ExpressionBuilder(IRContext ctx) {
|
|||||||
* @return 存放该常量的寄存器
|
* @return 存放该常量的寄存器
|
||||||
*/
|
*/
|
||||||
private IRVirtualRegister buildNumberLiteral(String value) {
|
private IRVirtualRegister buildNumberLiteral(String value) {
|
||||||
IRConstant constant = ExpressionUtils.buildNumberConstant(value);
|
IRConstant constant = ExpressionUtils.buildNumberConstant(ctx, value);
|
||||||
IRVirtualRegister reg = ctx.newRegister();
|
IRVirtualRegister reg = ctx.newRegister();
|
||||||
ctx.addInstruction(new LoadConstInstruction(reg, constant));
|
ctx.addInstruction(new LoadConstInstruction(reg, constant));
|
||||||
return reg;
|
return reg;
|
||||||
|
|||||||
@ -51,7 +51,7 @@ public class FunctionBuilder {
|
|||||||
// 2) 声明形参:为每个参数分配虚拟寄存器并声明到作用域
|
// 2) 声明形参:为每个参数分配虚拟寄存器并声明到作用域
|
||||||
for (ParameterNode p : functionNode.parameters()) {
|
for (ParameterNode p : functionNode.parameters()) {
|
||||||
IRVirtualRegister reg = irFunction.newRegister(); // 新寄存器
|
IRVirtualRegister reg = irFunction.newRegister(); // 新寄存器
|
||||||
irContext.getScope().declare(p.name(), reg); // 变量名→寄存器绑定
|
irContext.getScope().declare(p.name(), p.type(), reg); // 变量名→寄存器绑定
|
||||||
irFunction.addParameter(reg); // 添加到函数参数列表
|
irFunction.addParameter(reg); // 添加到函数参数列表
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -24,6 +24,13 @@ final class IRBuilderScope {
|
|||||||
*/
|
*/
|
||||||
private final Map<String, IRVirtualRegister> vars = new HashMap<>();
|
private final Map<String, IRVirtualRegister> vars = new HashMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 存储变量名到对应类型的映射。
|
||||||
|
* <br>
|
||||||
|
* 变量名为键,变量类型为值,用于变量类型提升。
|
||||||
|
*/
|
||||||
|
private final Map<String, String> varTypes = new HashMap<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 当前作用域所绑定的 IRFunction 对象,用于申请新的虚拟寄存器。
|
* 当前作用域所绑定的 IRFunction 对象,用于申请新的虚拟寄存器。
|
||||||
*/
|
*/
|
||||||
@ -44,10 +51,12 @@ final class IRBuilderScope {
|
|||||||
* 调用绑定的 IRFunction.newRegister() 生成寄存器后保存到映射表中。
|
* 调用绑定的 IRFunction.newRegister() 生成寄存器后保存到映射表中。
|
||||||
*
|
*
|
||||||
* @param name 变量名称,作为映射键使用
|
* @param name 变量名称,作为映射键使用
|
||||||
|
* @param type 变量类型
|
||||||
*/
|
*/
|
||||||
void declare(String name) {
|
void declare(String name, String type) {
|
||||||
IRVirtualRegister reg = fn.newRegister();
|
IRVirtualRegister reg = fn.newRegister();
|
||||||
vars.put(name, reg);
|
vars.put(name, reg);
|
||||||
|
varTypes.put(name, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -55,10 +64,12 @@ final class IRBuilderScope {
|
|||||||
* 该方法可用于将外部或前一作用域的寄存器导入到本作用域。
|
* 该方法可用于将外部或前一作用域的寄存器导入到本作用域。
|
||||||
*
|
*
|
||||||
* @param name 变量名称,作为映射键使用
|
* @param name 变量名称,作为映射键使用
|
||||||
|
* @param type 变量类型
|
||||||
* @param reg 要绑定到该名称的 IRVirtualRegister 实例
|
* @param reg 要绑定到该名称的 IRVirtualRegister 实例
|
||||||
*/
|
*/
|
||||||
void declare(String name, IRVirtualRegister reg) {
|
void declare(String name, String type, IRVirtualRegister reg) {
|
||||||
vars.put(name, reg);
|
vars.put(name, reg);
|
||||||
|
varTypes.put(name, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -82,4 +93,15 @@ final class IRBuilderScope {
|
|||||||
IRVirtualRegister lookup(String name) {
|
IRVirtualRegister lookup(String name) {
|
||||||
return vars.get(name);
|
return vars.get(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据变量名称在当前作用域中查找对应的类型。
|
||||||
|
*
|
||||||
|
* @param name 需要查询的变量名称
|
||||||
|
* @return 如果该名称已声明,则返回对应的类型
|
||||||
|
* 如果未声明,则返回 null
|
||||||
|
*/
|
||||||
|
String lookupType(String name) {
|
||||||
|
return varTypes.get(name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import org.jcnc.snow.compiler.ir.core.IRFunction;
|
|||||||
import org.jcnc.snow.compiler.ir.core.IRInstruction;
|
import org.jcnc.snow.compiler.ir.core.IRInstruction;
|
||||||
import org.jcnc.snow.compiler.ir.value.IRVirtualRegister;
|
import org.jcnc.snow.compiler.ir.value.IRVirtualRegister;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* IRContext 类负责封装当前正在构建的 IRFunction 实例
|
* IRContext 类负责封装当前正在构建的 IRFunction 实例
|
||||||
* 以及与之配套的作用域管理(IRBuilderScope),
|
* 以及与之配套的作用域管理(IRBuilderScope),
|
||||||
@ -31,6 +32,11 @@ public class IRContext {
|
|||||||
*/
|
*/
|
||||||
private final IRBuilderScope scope;
|
private final IRBuilderScope scope;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当前声明变量的类型,不在声明变量时为空
|
||||||
|
*/
|
||||||
|
private String varType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 构造一个新的 IRContext,并将指定的 IRFunction 与作用域关联。
|
* 构造一个新的 IRContext,并将指定的 IRFunction 与作用域关联。
|
||||||
*
|
*
|
||||||
@ -41,6 +47,7 @@ public class IRContext {
|
|||||||
this.scope = new IRBuilderScope();
|
this.scope = new IRBuilderScope();
|
||||||
// 关联作用域与 IRFunction,以便在声明变量时申请寄存器
|
// 关联作用域与 IRFunction,以便在声明变量时申请寄存器
|
||||||
this.scope.attachFunction(function);
|
this.scope.attachFunction(function);
|
||||||
|
this.varType = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -85,4 +92,29 @@ public class IRContext {
|
|||||||
public String newLabel() {
|
public String newLabel() {
|
||||||
return "L" + (labelCounter++);
|
return "L" + (labelCounter++);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前 declare 编译阶段变量类型
|
||||||
|
*
|
||||||
|
* @return 当前 declare 的变量类型
|
||||||
|
*/
|
||||||
|
public String getVarType() {
|
||||||
|
return varType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置当前 declare 编译阶段变量类型
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public void setVarType(String type) {
|
||||||
|
this.varType = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清除当前 declare 编译阶段变量类型
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public void clearVarType() {
|
||||||
|
this.varType = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -58,8 +58,8 @@ public class InstructionFactory {
|
|||||||
* @param dest 目标寄存器
|
* @param dest 目标寄存器
|
||||||
* @param value 要加载的整数常量
|
* @param value 要加载的整数常量
|
||||||
*/
|
*/
|
||||||
public static void loadConstInto(IRContext ctx, IRVirtualRegister dest, int value) {
|
public static void loadConstInto(IRContext ctx, IRVirtualRegister dest, IRConstant value) {
|
||||||
ctx.addInstruction(new LoadConstInstruction(dest, new IRConstant(value)));
|
ctx.addInstruction(new LoadConstInstruction(dest, value));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -55,19 +55,37 @@ public class StatementBuilder {
|
|||||||
}
|
}
|
||||||
if (stmt instanceof AssignmentNode(String var, ExpressionNode rhs)) {
|
if (stmt instanceof AssignmentNode(String var, ExpressionNode rhs)) {
|
||||||
// 赋值语句,如 a = b + 1;
|
// 赋值语句,如 a = b + 1;
|
||||||
IRVirtualRegister target = getOrDeclareRegister(var);
|
|
||||||
|
final String type = ctx.getScope().lookupType(var);
|
||||||
|
|
||||||
|
// 1. 设置声明变量的类型
|
||||||
|
ctx.setVarType(type);
|
||||||
|
|
||||||
|
IRVirtualRegister target = getOrDeclareRegister(var, type);
|
||||||
expr.buildInto(rhs, target);
|
expr.buildInto(rhs, target);
|
||||||
|
|
||||||
|
// 2. 清除变量声明
|
||||||
|
ctx.clearVarType();
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (stmt instanceof DeclarationNode decl) {
|
if (stmt instanceof DeclarationNode decl) {
|
||||||
// 变量声明,如 int a = 1;
|
// 变量声明,如 int a = 1;
|
||||||
if (decl.getInitializer().isPresent()) {
|
if (decl.getInitializer().isPresent()) {
|
||||||
// 声明同时有初值
|
// 声明同时有初值
|
||||||
|
|
||||||
|
// 1. 设置声明变量的类型
|
||||||
|
ctx.setVarType(decl.getType());
|
||||||
|
|
||||||
IRVirtualRegister r = expr.build(decl.getInitializer().get());
|
IRVirtualRegister r = expr.build(decl.getInitializer().get());
|
||||||
ctx.getScope().declare(decl.getName(), r);
|
|
||||||
|
// 2. 清除变量声明
|
||||||
|
ctx.clearVarType();
|
||||||
|
|
||||||
|
ctx.getScope().declare(decl.getName(), decl.getType(), r);
|
||||||
} else {
|
} else {
|
||||||
// 仅声明,无初值
|
// 仅声明,无初值
|
||||||
ctx.getScope().declare(decl.getName());
|
ctx.getScope().declare(decl.getName(), decl.getType());
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -92,11 +110,11 @@ public class StatementBuilder {
|
|||||||
* @param name 变量名
|
* @param name 变量名
|
||||||
* @return 变量对应的虚拟寄存器
|
* @return 变量对应的虚拟寄存器
|
||||||
*/
|
*/
|
||||||
private IRVirtualRegister getOrDeclareRegister(String name) {
|
private IRVirtualRegister getOrDeclareRegister(String name, String type) {
|
||||||
IRVirtualRegister reg = ctx.getScope().lookup(name);
|
IRVirtualRegister reg = ctx.getScope().lookup(name);
|
||||||
if (reg == null) {
|
if (reg == null) {
|
||||||
reg = ctx.newRegister();
|
reg = ctx.newRegister();
|
||||||
ctx.getScope().declare(name, reg);
|
ctx.getScope().declare(name, type, reg);
|
||||||
}
|
}
|
||||||
return reg;
|
return reg;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -66,13 +66,21 @@ public enum IROpCode {
|
|||||||
DIV_D64, // 64位浮点除法
|
DIV_D64, // 64位浮点除法
|
||||||
NEG_D64, // 64位浮点取负
|
NEG_D64, // 64位浮点取负
|
||||||
|
|
||||||
/* ───── 逻辑与比较运算指令 ───── */
|
/* ───── 逻辑与比较运算指令(32位整数:int) ───── */
|
||||||
CMP_EQ, // 相等比较:a == b
|
CMP_EQ, // 32位相等比较:a == b
|
||||||
CMP_NE, // 不等比较:a != b
|
CMP_NE, // 32位不等比较:a != b
|
||||||
CMP_LT, // 小于比较:a < b
|
CMP_LT, // 32位小于比较:a < b
|
||||||
CMP_GT, // 大于比较:a > b
|
CMP_GT, // 32位大于比较:a > b
|
||||||
CMP_LE, // 小于等于:a <= b
|
CMP_LE, // 32位小于等于:a <= b
|
||||||
CMP_GE, // 大于等于:a >= b
|
CMP_GE, // 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
|
||||||
|
|
||||||
/* ───── 数据访问与常量操作 ───── */
|
/* ───── 数据访问与常量操作 ───── */
|
||||||
LOAD, // 从内存加载数据至寄存器
|
LOAD, // 从内存加载数据至寄存器
|
||||||
|
|||||||
@ -40,11 +40,11 @@ public final class IROpCodeMappings {
|
|||||||
);
|
);
|
||||||
// 比较操作符映射
|
// 比较操作符映射
|
||||||
public static final Map<String, IROpCode> CMP = Map.of(
|
public static final Map<String, IROpCode> CMP = Map.of(
|
||||||
"==", IROpCode.CMP_EQ,
|
"==", IROpCode.CMP_LEQ,
|
||||||
"!=", IROpCode.CMP_NE,
|
"!=", IROpCode.CMP_LNE,
|
||||||
"<", IROpCode.CMP_LT,
|
"<", IROpCode.CMP_LLT,
|
||||||
">", IROpCode.CMP_GT,
|
">", IROpCode.CMP_LGT,
|
||||||
"<=", IROpCode.CMP_LE,
|
"<=", IROpCode.CMP_LLE,
|
||||||
">=", IROpCode.CMP_GE
|
">=", IROpCode.CMP_LGE
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
package org.jcnc.snow.compiler.ir.utils;
|
package org.jcnc.snow.compiler.ir.utils;
|
||||||
|
|
||||||
|
import org.jcnc.snow.compiler.ir.builder.IRContext;
|
||||||
import org.jcnc.snow.compiler.ir.core.IROpCode;
|
import org.jcnc.snow.compiler.ir.core.IROpCode;
|
||||||
import org.jcnc.snow.compiler.ir.core.IROpCodeMappings;
|
import org.jcnc.snow.compiler.ir.core.IROpCodeMappings;
|
||||||
import org.jcnc.snow.compiler.ir.value.IRConstant;
|
import org.jcnc.snow.compiler.ir.value.IRConstant;
|
||||||
@ -56,14 +57,29 @@ public class ExpressionUtils {
|
|||||||
* 根据数字字面量字符串自动判断类型,生成对应类型的 IRConstant。
|
* 根据数字字面量字符串自动判断类型,生成对应类型的 IRConstant。
|
||||||
* 支持 b/s/l/f/d 类型后缀与浮点格式,自动分配合适类型。
|
* 支持 b/s/l/f/d 类型后缀与浮点格式,自动分配合适类型。
|
||||||
*
|
*
|
||||||
|
* @param ctx IR 编译上下文环境
|
||||||
* @param value 字面量字符串(如 "1", "2l", "3.14f", "5D")
|
* @param value 字面量字符串(如 "1", "2l", "3.14f", "5D")
|
||||||
* @return 生成的 IRConstant 对象,包含正确类型
|
* @return 生成的 IRConstant 对象,包含正确类型
|
||||||
*/
|
*/
|
||||||
public static IRConstant buildNumberConstant(String value) {
|
public static IRConstant buildNumberConstant(IRContext ctx, String value) {
|
||||||
char suffix = value.isEmpty() ? '\0' : Character.toLowerCase(value.charAt(value.length() - 1));
|
char suffix = value.isEmpty() ? '\0' : Character.toLowerCase(value.charAt(value.length() - 1));
|
||||||
String digits = switch (suffix) {
|
String digits = switch (suffix) {
|
||||||
case 'b','s','l','f','d' -> value.substring(0, value.length() - 1);
|
case 'b','s','l','f','d' -> value.substring(0, value.length() - 1);
|
||||||
default -> value;
|
default -> {
|
||||||
|
if (ctx.getVarType() != null) {
|
||||||
|
final var receiverType = ctx.getVarType();
|
||||||
|
switch (receiverType) {
|
||||||
|
case "byte" -> suffix = 'b';
|
||||||
|
case "short" -> suffix = 's';
|
||||||
|
case "int" -> suffix = 'i';
|
||||||
|
case "long" -> suffix = 'l';
|
||||||
|
case "float" -> suffix = 'f';
|
||||||
|
case "double" -> suffix = 'd';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
yield value;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
// 根据类型后缀或数值格式创建常量
|
// 根据类型后缀或数值格式创建常量
|
||||||
return switch (suffix) {
|
return switch (suffix) {
|
||||||
|
|||||||
@ -9,12 +9,12 @@ import java.util.Map;
|
|||||||
*/
|
*/
|
||||||
public class IROpCodeUtils {
|
public class IROpCodeUtils {
|
||||||
private static final Map<IROpCode, IROpCode> INVERT = Map.of(
|
private static final Map<IROpCode, IROpCode> INVERT = Map.of(
|
||||||
IROpCode.CMP_EQ, IROpCode.CMP_NE,
|
IROpCode.CMP_LEQ, IROpCode.CMP_LNE,
|
||||||
IROpCode.CMP_NE, IROpCode.CMP_EQ,
|
IROpCode.CMP_LNE, IROpCode.CMP_LEQ,
|
||||||
IROpCode.CMP_LT, IROpCode.CMP_GE,
|
IROpCode.CMP_LLT, IROpCode.CMP_LGE,
|
||||||
IROpCode.CMP_GE, IROpCode.CMP_LT,
|
IROpCode.CMP_LGE, IROpCode.CMP_LLT,
|
||||||
IROpCode.CMP_GT, IROpCode.CMP_LE,
|
IROpCode.CMP_LGT, IROpCode.CMP_LLE,
|
||||||
IROpCode.CMP_LE, IROpCode.CMP_GT
|
IROpCode.CMP_LLE, IROpCode.CMP_LGT
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -0,0 +1,76 @@
|
|||||||
|
package org.jcnc.snow.vm.commands.control.long64;
|
||||||
|
|
||||||
|
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;
|
||||||
|
import org.jcnc.snow.vm.utils.LoggingUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The LCECommand class implements the {@link Command} interface and represents a conditional jump command in the virtual machine.
|
||||||
|
* This class compares two values from the stack, and if they are equal, it jumps to the specified target command.
|
||||||
|
*
|
||||||
|
* <p>Specific behavior:</p>
|
||||||
|
* <ul>
|
||||||
|
* <li>Pops two integers from the virtual machine stack.</li>
|
||||||
|
* <li>If the two integers are equal, jumps to the target command.</li>
|
||||||
|
* <li>Otherwise, the program continues with the next command.</li>
|
||||||
|
* </ul>
|
||||||
|
*/
|
||||||
|
public class LCECommand implements Command {
|
||||||
|
/**
|
||||||
|
* Default constructor for creating an instance of LCECommand.
|
||||||
|
* This constructor is empty as no specific initialization is required.
|
||||||
|
*/
|
||||||
|
public LCECommand() {
|
||||||
|
// Empty constructor
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executes the virtual machine instruction's operation.
|
||||||
|
*
|
||||||
|
* <p>This method retrieves the necessary data from the virtual machine stack and local variable store based on the instruction's
|
||||||
|
* specific implementation, performs the operation, and updates the program counter (PC) to reflect the next instruction
|
||||||
|
* to be executed.</p>
|
||||||
|
*
|
||||||
|
* <p>The parameters provided allow the command to manipulate the operand stack, modify the local variables, and control the flow
|
||||||
|
* of execution by updating the program counter.</p>
|
||||||
|
*
|
||||||
|
* <p>The exact behavior of this method will depend on the specific instruction being executed (e.g., arithmetic, branching,
|
||||||
|
* function calls, etc.). For example, a `CALL` instruction will modify the call stack by pushing a new frame,
|
||||||
|
* while a `POP` instruction will remove an item from the operand stack.</p>
|
||||||
|
*
|
||||||
|
* @param parts The array of instruction parameters, which usually includes the operator and related arguments
|
||||||
|
* (such as target addresses, values, or function names). These parameters may vary based on
|
||||||
|
* the instruction being executed.
|
||||||
|
* @param currentPC The current program counter-value, indicating the address of the instruction being executed.
|
||||||
|
* This value is typically incremented after the execution of each instruction to point to the next one.
|
||||||
|
* @param operandStack The virtual machine's operand stack manager, responsible for performing operations on the operand stack,
|
||||||
|
* such as pushing, popping, and peeking values.
|
||||||
|
* @param localVariableStore The local variable store, typically used to manage method-local variables during instruction execution.
|
||||||
|
* The store may not be used in every command but can be leveraged by instructions that require access
|
||||||
|
* to local variables.
|
||||||
|
* @param callStack The virtual machine's call stack, which keeps track of the method invocation hierarchy. It is used by
|
||||||
|
* instructions that involve method calls or returns (such as `CALL` and `RETURN` instructions).
|
||||||
|
* @return The updated program counter-value, typically the current program counter-value incremented by 1, unless the
|
||||||
|
* instruction modifies control flow (such as a `JUMP` or `CALL`), in which case it may return a new address
|
||||||
|
* corresponding to the target of the jump or the subroutine to call.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public int execute(String[] parts, int currentPC, OperandStack operandStack, LocalVariableStore localVariableStore, CallStack callStack) {
|
||||||
|
// Parse the target command address
|
||||||
|
int target = Integer.parseInt(parts[1]);
|
||||||
|
|
||||||
|
// Pop the two operands from the stack
|
||||||
|
long b = (long) operandStack.pop();
|
||||||
|
long a = (long) operandStack.pop();
|
||||||
|
|
||||||
|
// If the operands are equal, jump to the target command
|
||||||
|
if (a == b) {
|
||||||
|
LoggingUtils.logInfo("Jumping to command", String.valueOf(target));
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
|
return currentPC + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,76 @@
|
|||||||
|
package org.jcnc.snow.vm.commands.control.long64;
|
||||||
|
|
||||||
|
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;
|
||||||
|
import org.jcnc.snow.vm.utils.LoggingUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The LCGCommand class implements the {@link Command} interface and represents a conditional jump command in the virtual machine.
|
||||||
|
* This class compares two values from the stack, and if the first value is greater than the second, it jumps to the specified target command.
|
||||||
|
*
|
||||||
|
* <p>Specific behavior:</p>
|
||||||
|
* <ul>
|
||||||
|
* <li>Pops two integers from the virtual machine stack.</li>
|
||||||
|
* <li>If the first integer is greater than the second, jumps to the target command.</li>
|
||||||
|
* <li>Otherwise, the program continues with the next command.</li>
|
||||||
|
* </ul>
|
||||||
|
*/
|
||||||
|
public class LCGCommand implements Command {
|
||||||
|
/**
|
||||||
|
* Default constructor for creating an instance of LCGCommand.
|
||||||
|
* This constructor is empty as no specific initialization is required.
|
||||||
|
*/
|
||||||
|
public LCGCommand() {
|
||||||
|
// Empty constructor
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executes the virtual machine instruction's operation.
|
||||||
|
*
|
||||||
|
* <p>This method retrieves the necessary data from the virtual machine stack and local variable store based on the instruction's
|
||||||
|
* specific implementation, performs the operation, and updates the program counter (PC) to reflect the next instruction
|
||||||
|
* to be executed.</p>
|
||||||
|
*
|
||||||
|
* <p>The parameters provided allow the command to manipulate the operand stack, modify the local variables, and control the flow
|
||||||
|
* of execution by updating the program counter.</p>
|
||||||
|
*
|
||||||
|
* <p>The exact behavior of this method will depend on the specific instruction being executed (e.g., arithmetic, branching,
|
||||||
|
* function calls, etc.). For example, a `CALL` instruction will modify the call stack by pushing a new frame,
|
||||||
|
* while a `POP` instruction will remove an item from the operand stack.</p>
|
||||||
|
*
|
||||||
|
* @param parts The array of instruction parameters, which usually includes the operator and related arguments
|
||||||
|
* (such as target addresses, values, or function names). These parameters may vary based on
|
||||||
|
* the instruction being executed.
|
||||||
|
* @param currentPC The current program counter-value, indicating the address of the instruction being executed.
|
||||||
|
* This value is typically incremented after the execution of each instruction to point to the next one.
|
||||||
|
* @param operandStack The virtual machine's operand stack manager, responsible for performing operations on the operand stack,
|
||||||
|
* such as pushing, popping, and peeking values.
|
||||||
|
* @param localVariableStore The local variable store, typically used to manage method-local variables during instruction execution.
|
||||||
|
* The store may not be used in every command but can be leveraged by instructions that require access
|
||||||
|
* to local variables.
|
||||||
|
* @param callStack The virtual machine's call stack, which keeps track of the method invocation hierarchy. It is used by
|
||||||
|
* instructions that involve method calls or returns (such as `CALL` and `RETURN` instructions).
|
||||||
|
* @return The updated program counter-value, typically the current program counter-value incremented by 1, unless the
|
||||||
|
* instruction modifies control flow (such as a `JUMP` or `CALL`), in which case it may return a new address
|
||||||
|
* corresponding to the target of the jump or the subroutine to call.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public int execute(String[] parts, int currentPC, OperandStack operandStack, LocalVariableStore localVariableStore, CallStack callStack) {
|
||||||
|
// Parse the target command address
|
||||||
|
int target = Integer.parseInt(parts[1]);
|
||||||
|
|
||||||
|
// Pop the two operands from the stack
|
||||||
|
long b = (long) operandStack.pop();
|
||||||
|
long a = (long) operandStack.pop();
|
||||||
|
|
||||||
|
// If the first operand is greater than the second, jump to the target command
|
||||||
|
if (a > b) {
|
||||||
|
LoggingUtils.logInfo("Jumping to command", String.valueOf(target));
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
|
return currentPC + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,76 @@
|
|||||||
|
package org.jcnc.snow.vm.commands.control.long64;
|
||||||
|
|
||||||
|
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;
|
||||||
|
import org.jcnc.snow.vm.utils.LoggingUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The LCGECommand class implements the {@link Command} interface and represents a conditional jump command in the virtual machine.
|
||||||
|
* This class compares two values from the stack, and if the first value is greater than or equal to the second, it jumps to the specified target command.
|
||||||
|
*
|
||||||
|
* <p>Specific behavior:</p>
|
||||||
|
* <ul>
|
||||||
|
* <li>Pops two integers from the virtual machine stack.</li>
|
||||||
|
* <li>If the first integer is greater than or equal to the second, jumps to the target command.</li>
|
||||||
|
* <li>Otherwise, the program continues with the next command.</li>
|
||||||
|
* </ul>
|
||||||
|
*/
|
||||||
|
public class LCGECommand implements Command {
|
||||||
|
/**
|
||||||
|
* Default constructor for creating an instance of LCGECommand.
|
||||||
|
* This constructor is empty as no specific initialization is required.
|
||||||
|
*/
|
||||||
|
public LCGECommand() {
|
||||||
|
// Empty constructor
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executes the virtual machine instruction's operation.
|
||||||
|
*
|
||||||
|
* <p>This method retrieves the necessary data from the virtual machine stack and local variable store based on the instruction's
|
||||||
|
* specific implementation, performs the operation, and updates the program counter (PC) to reflect the next instruction
|
||||||
|
* to be executed.</p>
|
||||||
|
*
|
||||||
|
* <p>The parameters provided allow the command to manipulate the operand stack, modify the local variables, and control the flow
|
||||||
|
* of execution by updating the program counter.</p>
|
||||||
|
*
|
||||||
|
* <p>The exact behavior of this method will depend on the specific instruction being executed (e.g., arithmetic, branching,
|
||||||
|
* function calls, etc.). For example, a `CALL` instruction will modify the call stack by pushing a new frame,
|
||||||
|
* while a `POP` instruction will remove an item from the operand stack.</p>
|
||||||
|
*
|
||||||
|
* @param parts The array of instruction parameters, which usually includes the operator and related arguments
|
||||||
|
* (such as target addresses, values, or function names). These parameters may vary based on
|
||||||
|
* the instruction being executed.
|
||||||
|
* @param currentPC The current program counter-value, indicating the address of the instruction being executed.
|
||||||
|
* This value is typically incremented after the execution of each instruction to point to the next one.
|
||||||
|
* @param operandStack The virtual machine's operand stack manager, responsible for performing operations on the operand stack,
|
||||||
|
* such as pushing, popping, and peeking values.
|
||||||
|
* @param localVariableStore The local variable store, typically used to manage method-local variables during instruction execution.
|
||||||
|
* The store may not be used in every command but can be leveraged by instructions that require access
|
||||||
|
* to local variables.
|
||||||
|
* @param callStack The virtual machine's call stack, which keeps track of the method invocation hierarchy. It is used by
|
||||||
|
* instructions that involve method calls or returns (such as `CALL` and `RETURN` instructions).
|
||||||
|
* @return The updated program counter-value, typically the current program counter-value incremented by 1, unless the
|
||||||
|
* instruction modifies control flow (such as a `JUMP` or `CALL`), in which case it may return a new address
|
||||||
|
* corresponding to the target of the jump or the subroutine to call.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public int execute(String[] parts, int currentPC, OperandStack operandStack, LocalVariableStore localVariableStore, CallStack callStack) {
|
||||||
|
// Parse the target command address
|
||||||
|
int target = Integer.parseInt(parts[1]);
|
||||||
|
|
||||||
|
// Pop the two operands from the stack
|
||||||
|
long b = (long) operandStack.pop();
|
||||||
|
long a = (long) operandStack.pop();
|
||||||
|
|
||||||
|
// If the first operand is greater than or equal to the second, jump to the target command
|
||||||
|
if (a >= b) {
|
||||||
|
LoggingUtils.logInfo("Jumping to command", String.valueOf(target));
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
|
return currentPC + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,76 @@
|
|||||||
|
package org.jcnc.snow.vm.commands.control.long64;
|
||||||
|
|
||||||
|
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;
|
||||||
|
import org.jcnc.snow.vm.utils.LoggingUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The LCLCommand class implements the {@link Command} interface and represents a conditional jump command in the virtual machine.
|
||||||
|
* This class compares two values from the stack, and if the first value is less than the second, it jumps to the specified target command.
|
||||||
|
*
|
||||||
|
* <p>Specific behavior:</p>
|
||||||
|
* <ul>
|
||||||
|
* <li>Pops two integers from the virtual machine stack.</li>
|
||||||
|
* <li>If the first integer is less than the second, jumps to the target command.</li>
|
||||||
|
* <li>Otherwise, the program continues with the next command.</li>
|
||||||
|
* </ul>
|
||||||
|
*/
|
||||||
|
public class LCLCommand implements Command {
|
||||||
|
/**
|
||||||
|
* Default constructor for creating an instance of LCLCommand.
|
||||||
|
* This constructor is empty as no specific initialization is required.
|
||||||
|
*/
|
||||||
|
public LCLCommand() {
|
||||||
|
// Empty constructor
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executes the virtual machine instruction's operation.
|
||||||
|
*
|
||||||
|
* <p>This method retrieves the necessary data from the virtual machine stack and local variable store based on the instruction's
|
||||||
|
* specific implementation, performs the operation, and updates the program counter (PC) to reflect the next instruction
|
||||||
|
* to be executed.</p>
|
||||||
|
*
|
||||||
|
* <p>The parameters provided allow the command to manipulate the operand stack, modify the local variables, and control the flow
|
||||||
|
* of execution by updating the program counter.</p>
|
||||||
|
*
|
||||||
|
* <p>The exact behavior of this method will depend on the specific instruction being executed (e.g., arithmetic, branching,
|
||||||
|
* function calls, etc.). For example, a `CALL` instruction will modify the call stack by pushing a new frame,
|
||||||
|
* while a `POP` instruction will remove an item from the operand stack.</p>
|
||||||
|
*
|
||||||
|
* @param parts The array of instruction parameters, which usually includes the operator and related arguments
|
||||||
|
* (such as target addresses, values, or function names). These parameters may vary based on
|
||||||
|
* the instruction being executed.
|
||||||
|
* @param currentPC The current program counter-value, indicating the address of the instruction being executed.
|
||||||
|
* This value is typically incremented after the execution of each instruction to point to the next one.
|
||||||
|
* @param operandStack The virtual machine's operand stack manager, responsible for performing operations on the operand stack,
|
||||||
|
* such as pushing, popping, and peeking values.
|
||||||
|
* @param localVariableStore The local variable store, typically used to manage method-local variables during instruction execution.
|
||||||
|
* The store may not be used in every command but can be leveraged by instructions that require access
|
||||||
|
* to local variables.
|
||||||
|
* @param callStack The virtual machine's call stack, which keeps track of the method invocation hierarchy. It is used by
|
||||||
|
* instructions that involve method calls or returns (such as `CALL` and `RETURN` instructions).
|
||||||
|
* @return The updated program counter-value, typically the current program counter-value incremented by 1, unless the
|
||||||
|
* instruction modifies control flow (such as a `JUMP` or `CALL`), in which case it may return a new address
|
||||||
|
* corresponding to the target of the jump or the subroutine to call.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public int execute(String[] parts, int currentPC, OperandStack operandStack, LocalVariableStore localVariableStore, CallStack callStack) {
|
||||||
|
// Parse the target command address
|
||||||
|
int target = Integer.parseInt(parts[1]);
|
||||||
|
|
||||||
|
// Pop the two operands from the stack
|
||||||
|
long b = (long) operandStack.pop();
|
||||||
|
long a = (long) operandStack.pop();
|
||||||
|
|
||||||
|
// If the first operand is less than the second, jump to the target command
|
||||||
|
if (a < b) {
|
||||||
|
LoggingUtils.logInfo("Jumping to command", String.valueOf(target));
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
|
return currentPC + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,76 @@
|
|||||||
|
package org.jcnc.snow.vm.commands.control.long64;
|
||||||
|
|
||||||
|
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;
|
||||||
|
import org.jcnc.snow.vm.utils.LoggingUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The LCLECommand class implements the {@link Command} interface and represents a conditional jump command in the virtual machine.
|
||||||
|
* This class compares two values from the stack, and if the first value is less than or equal to the second, it jumps to the specified target command.
|
||||||
|
*
|
||||||
|
* <p>Specific behavior:</p>
|
||||||
|
* <ul>
|
||||||
|
* <li>Pops two integers from the virtual machine stack.</li>
|
||||||
|
* <li>If the first integer is less than or equal to the second, jumps to the target command.</li>
|
||||||
|
* <li>Otherwise, the program continues with the next command.</li>
|
||||||
|
* </ul>
|
||||||
|
*/
|
||||||
|
public class LCLECommand implements Command {
|
||||||
|
/**
|
||||||
|
* Default constructor for creating an instance of LCLECommand.
|
||||||
|
* This constructor is empty as no specific initialization is required.
|
||||||
|
*/
|
||||||
|
public LCLECommand() {
|
||||||
|
// Empty constructor
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executes the virtual machine instruction's operation.
|
||||||
|
*
|
||||||
|
* <p>This method retrieves the necessary data from the virtual machine stack and local variable store based on the instruction's
|
||||||
|
* specific implementation, performs the operation, and updates the program counter (PC) to reflect the next instruction
|
||||||
|
* to be executed.</p>
|
||||||
|
*
|
||||||
|
* <p>The parameters provided allow the command to manipulate the operand stack, modify the local variables, and control the flow
|
||||||
|
* of execution by updating the program counter.</p>
|
||||||
|
*
|
||||||
|
* <p>The exact behavior of this method will depend on the specific instruction being executed (e.g., arithmetic, branching,
|
||||||
|
* function calls, etc.). For example, a `CALL` instruction will modify the call stack by pushing a new frame,
|
||||||
|
* while a `POP` instruction will remove an item from the operand stack.</p>
|
||||||
|
*
|
||||||
|
* @param parts The array of instruction parameters, which usually includes the operator and related arguments
|
||||||
|
* (such as target addresses, values, or function names). These parameters may vary based on
|
||||||
|
* the instruction being executed.
|
||||||
|
* @param currentPC The current program counter-value, indicating the address of the instruction being executed.
|
||||||
|
* This value is typically incremented after the execution of each instruction to point to the next one.
|
||||||
|
* @param operandStack The virtual machine's operand stack manager, responsible for performing operations on the operand stack,
|
||||||
|
* such as pushing, popping, and peeking values.
|
||||||
|
* @param localVariableStore The local variable store, typically used to manage method-local variables during instruction execution.
|
||||||
|
* The store may not be used in every command but can be leveraged by instructions that require access
|
||||||
|
* to local variables.
|
||||||
|
* @param callStack The virtual machine's call stack, which keeps track of the method invocation hierarchy. It is used by
|
||||||
|
* instructions that involve method calls or returns (such as `CALL` and `RETURN` instructions).
|
||||||
|
* @return The updated program counter-value, typically the current program counter-value incremented by 1, unless the
|
||||||
|
* instruction modifies control flow (such as a `JUMP` or `CALL`), in which case it may return a new address
|
||||||
|
* corresponding to the target of the jump or the subroutine to call.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public int execute(String[] parts, int currentPC, OperandStack operandStack, LocalVariableStore localVariableStore, CallStack callStack) {
|
||||||
|
// Parse the target command address
|
||||||
|
int target = Integer.parseInt(parts[1]);
|
||||||
|
|
||||||
|
// Pop the two operands from the stack
|
||||||
|
long b = (long) operandStack.pop();
|
||||||
|
long a = (long) operandStack.pop();
|
||||||
|
|
||||||
|
// If the first operand is less than or equal to the second, jump to the target command
|
||||||
|
if (a <= b) {
|
||||||
|
LoggingUtils.logInfo("Jumping to command", String.valueOf(target));
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
|
return currentPC + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,76 @@
|
|||||||
|
package org.jcnc.snow.vm.commands.control.long64;
|
||||||
|
|
||||||
|
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;
|
||||||
|
import org.jcnc.snow.vm.utils.LoggingUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The LCNECommand class implements the {@link Command} interface and represents a conditional jump command
|
||||||
|
* in the virtual machine that triggers if two values are not equal.
|
||||||
|
*
|
||||||
|
* <p>Specific behavior:</p>
|
||||||
|
* <ul>
|
||||||
|
* <li>Pops two integers from the virtual machine stack.</li>
|
||||||
|
* <li>If the two integers are not equal, jumps to the target command.</li>
|
||||||
|
* <li>Otherwise, the program continues with the next command.</li>
|
||||||
|
* </ul>
|
||||||
|
*/
|
||||||
|
public class LCNECommand implements Command {
|
||||||
|
/**
|
||||||
|
* Default constructor for creating an instance of LCNECommand.
|
||||||
|
* This constructor is empty as no specific initialization is required.
|
||||||
|
*/
|
||||||
|
public LCNECommand() {
|
||||||
|
// Empty constructor
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executes the virtual machine instruction's operation.
|
||||||
|
*
|
||||||
|
* <p>This method retrieves the necessary data from the virtual machine stack and local variable store based on the instruction's
|
||||||
|
* specific implementation, performs the operation, and updates the program counter (PC) to reflect the next instruction
|
||||||
|
* to be executed.</p>
|
||||||
|
*
|
||||||
|
* <p>The parameters provided allow the command to manipulate the operand stack, modify the local variables, and control the flow
|
||||||
|
* of execution by updating the program counter.</p>
|
||||||
|
*
|
||||||
|
* <p>The exact behavior of this method will depend on the specific instruction being executed (e.g., arithmetic, branching,
|
||||||
|
* function calls, etc.). For example, a `CALL` instruction will modify the call stack by pushing a new frame,
|
||||||
|
* while a `POP` instruction will remove an item from the operand stack.</p>
|
||||||
|
*
|
||||||
|
* @param parts The array of instruction parameters, which usually includes the operator and related arguments
|
||||||
|
* (such as target addresses, values, or function names). These parameters may vary based on
|
||||||
|
* the instruction being executed.
|
||||||
|
* @param currentPC The current program counter-value, indicating the address of the instruction being executed.
|
||||||
|
* This value is typically incremented after the execution of each instruction to point to the next one.
|
||||||
|
* @param operandStack The virtual machine's operand stack manager, responsible for performing operations on the operand stack,
|
||||||
|
* such as pushing, popping, and peeking values.
|
||||||
|
* @param localVariableStore The local variable store, typically used to manage method-local variables during instruction execution.
|
||||||
|
* The store may not be used in every command but can be leveraged by instructions that require access
|
||||||
|
* to local variables.
|
||||||
|
* @param callStack The virtual machine's call stack, which keeps track of the method invocation hierarchy. It is used by
|
||||||
|
* instructions that involve method calls or returns (such as `CALL` and `RETURN` instructions).
|
||||||
|
* @return The updated program counter-value, typically the current program counter-value incremented by 1, unless the
|
||||||
|
* instruction modifies control flow (such as a `JUMP` or `CALL`), in which case it may return a new address
|
||||||
|
* corresponding to the target of the jump or the subroutine to call.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public int execute(String[] parts, int currentPC, OperandStack operandStack, LocalVariableStore localVariableStore, CallStack callStack) {
|
||||||
|
// Parse the target command address
|
||||||
|
int target = Integer.parseInt(parts[1]);
|
||||||
|
|
||||||
|
// Pop the two operands from the stack
|
||||||
|
long b = (long) operandStack.pop();
|
||||||
|
long a = (long) operandStack.pop();
|
||||||
|
|
||||||
|
// If the operands are not equal, jump to the target command
|
||||||
|
if (a != b) {
|
||||||
|
LoggingUtils.logInfo("Jumping to command", String.valueOf(target));
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
|
return currentPC + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1101,6 +1101,7 @@ public class VMOpCode {
|
|||||||
|
|
||||||
|
|
||||||
// 3. Control Flow Operations (91–110)
|
// 3. Control Flow Operations (91–110)
|
||||||
|
// 3.1 JUMP (91-91)
|
||||||
/**
|
/**
|
||||||
* JUMP Opcode: Represents an unconditional jump to a target instruction address.
|
* JUMP Opcode: Represents an unconditional jump to a target instruction address.
|
||||||
* <p>This opcode is implemented by the {@link JumpCommand} class, which defines its specific execution logic.</p>
|
* <p>This opcode is implemented by the {@link JumpCommand} class, which defines its specific execution logic.</p>
|
||||||
@ -1120,6 +1121,7 @@ public class VMOpCode {
|
|||||||
* </ul>
|
* </ul>
|
||||||
*/
|
*/
|
||||||
public static final int JUMP = 91;
|
public static final int JUMP = 91;
|
||||||
|
// 3.2 int32 (92-97)
|
||||||
/**
|
/**
|
||||||
* IC_E Opcode: Represents a conditional jump based on int32 equality.
|
* IC_E Opcode: Represents a conditional jump based on int32 equality.
|
||||||
* <p>This opcode is implemented by the {@link ICECommand} class, which defines its specific execution logic.</p>
|
* <p>This opcode is implemented by the {@link ICECommand} class, which defines its specific execution logic.</p>
|
||||||
@ -1246,6 +1248,133 @@ public class VMOpCode {
|
|||||||
* </ul>
|
* </ul>
|
||||||
*/
|
*/
|
||||||
public static final int IC_LE = 97;
|
public static final int IC_LE = 97;
|
||||||
|
// 3.3 long64 (98-103)
|
||||||
|
/**
|
||||||
|
* LC_E Opcode: Represents a conditional jump based on long64 equality.
|
||||||
|
* <p>This opcode is implemented by the {@link ICECommand} class, which defines its specific execution logic.</p>
|
||||||
|
*
|
||||||
|
* <p>Execution Steps:</p>
|
||||||
|
* <ol>
|
||||||
|
* <li>Parses the target instruction address from the instruction parameters.</li>
|
||||||
|
* <li>Pops two long64 values from the operand stack.</li>
|
||||||
|
* <li>Compares the two long64s for equality.</li>
|
||||||
|
* <li>If the long64s are equal, updates the program counter (PC) to the specified target address,
|
||||||
|
* effectively jumping to the target instruction.</li>
|
||||||
|
* <li>If the long64s are not equal, increments the program counter to proceed with the next sequential instruction.</li>
|
||||||
|
* </ol>
|
||||||
|
*
|
||||||
|
* <p>This opcode is commonly used for:</p>
|
||||||
|
* <ul>
|
||||||
|
* <li>Conditional branching in virtual machine execution based on long64 comparison.</li>
|
||||||
|
* <li>Implementing control flow structures such as if-statements and loops.</li>
|
||||||
|
* </ul>
|
||||||
|
*/
|
||||||
|
public static final int LC_E = 98;
|
||||||
|
/**
|
||||||
|
* LC_NE Opcode: Represents a conditional jump based on long64 inequality.
|
||||||
|
* <p>This opcode is implemented by the {@link ICNECommand} class, which defines its specific execution logic.</p>
|
||||||
|
*
|
||||||
|
* <p>Execution Steps:</p>
|
||||||
|
* <ol>
|
||||||
|
* <li>Parses the target instruction address from the instruction parameters.</li>
|
||||||
|
* <li>Pops two long64 values from the operand stack.</li>
|
||||||
|
* <li>Compares the two long64s for inequality.</li>
|
||||||
|
* <li>If the long64s are not equal, updates the program counter (PC) to the specified target address,
|
||||||
|
* effectively jumping to the target instruction.</li>
|
||||||
|
* <li>If the long64s are equal, increments the program counter to proceed with the next sequential instruction.</li>
|
||||||
|
* </ol>
|
||||||
|
*
|
||||||
|
* <p>This opcode is commonly used for:</p>
|
||||||
|
* <ul>
|
||||||
|
* <li>Conditional branching in virtual machine execution based on long64 comparison.</li>
|
||||||
|
* <li>Implementing control flow structures such as conditional loops and if-else statements.</li>
|
||||||
|
* </ul>
|
||||||
|
*/
|
||||||
|
public static final int LC_NE = 99;
|
||||||
|
/**
|
||||||
|
* LC_G Opcode: Represents a conditional jump based on long64 comparison (greater than).
|
||||||
|
* <p>This opcode is implemented by the {@link ICGCommand} class, which defines its specific execution logic.</p>
|
||||||
|
*
|
||||||
|
* <p>Execution Steps:</p>
|
||||||
|
* <ol>
|
||||||
|
* <li>Parses the target instruction address from the instruction parameters.</li>
|
||||||
|
* <li>Pops two long64 values from the operand stack.</li>
|
||||||
|
* <li>Compares the first long64 with the second to determine if it is greater.</li>
|
||||||
|
* <li>If the first long64 is greater than the second, updates the program counter (PC) to the specified target address,
|
||||||
|
* effectively jumping to the target instruction.</li>
|
||||||
|
* <li>If the first long64 is not greater than the second, increments the program counter to proceed with the next sequential instruction.</li>
|
||||||
|
* </ol>
|
||||||
|
*
|
||||||
|
* <p>This opcode is commonly used for:</p>
|
||||||
|
* <ul>
|
||||||
|
* <li>Conditional branching in virtual machine execution based on long64 comparison.</li>
|
||||||
|
* <li>Implementing control flow structures such as greater-than conditions in loops and conditional statements.</li>
|
||||||
|
* </ul>
|
||||||
|
*/
|
||||||
|
public static final int LC_G = 100;
|
||||||
|
/**
|
||||||
|
* LC_GE Opcode: Represents a conditional jump based on long64 comparison (greater than or equal to).
|
||||||
|
* <p>This opcode is implemented by the {@link ICGECommand} class, which defines its specific execution logic.</p>
|
||||||
|
*
|
||||||
|
* <p>Execution Steps:</p>
|
||||||
|
* <ol>
|
||||||
|
* <li>Parses the target instruction address from the instruction parameters.</li>
|
||||||
|
* <li>Pops two long64 values from the operand stack.</li>
|
||||||
|
* <li>Compares the first long64 with the second to determine if it is greater than or equal to the second long64.</li>
|
||||||
|
* <li>If the first long64 is greater than or equal to the second, updates the program counter (PC) to the specified target address,
|
||||||
|
* effectively jumping to the target instruction.</li>
|
||||||
|
* <li>If the first long64 is less than the second, increments the program counter to proceed with the next sequential instruction.</li>
|
||||||
|
* </ol>
|
||||||
|
*
|
||||||
|
* <p>This opcode is commonly used for:</p>
|
||||||
|
* <ul>
|
||||||
|
* <li>Conditional branching in virtual machine execution based on long64 comparison.</li>
|
||||||
|
* <li>Implementing control flow structures such as loops, conditional statements, and range checks.</li>
|
||||||
|
* </ul>
|
||||||
|
*/
|
||||||
|
public static final int LC_GE = 101;
|
||||||
|
/**
|
||||||
|
* LC_L Opcode: Represents a conditional jump based on long64 comparison (less than).
|
||||||
|
* <p>This opcode is implemented by the {@link ICLCommand} class, which defines its specific execution logic.</p>
|
||||||
|
*
|
||||||
|
* <p>Execution Steps:</p>
|
||||||
|
* <ol>
|
||||||
|
* <li>Parses the target instruction address from the instruction parameters.</li>
|
||||||
|
* <li>Pops two long64 values from the operand stack.</li>
|
||||||
|
* <li>Compares the first long64 with the second to determine if it is less than the second long64.</li>
|
||||||
|
* <li>If the first long64 is less than the second, updates the program counter (PC) to the specified target address,
|
||||||
|
* effectively jumping to the target instruction.</li>
|
||||||
|
* <li>If the first long64 is greater than or equal to the second, increments the program counter to proceed with the next sequential instruction.</li>
|
||||||
|
* </ol>
|
||||||
|
*
|
||||||
|
* <p>This opcode is commonly used for:</p>
|
||||||
|
* <ul>
|
||||||
|
* <li>Conditional branching in virtual machine execution based on long64 comparison.</li>
|
||||||
|
* <li>Implementing control flow structures such as loops, conditional statements, and range validations.</li>
|
||||||
|
* </ul>
|
||||||
|
*/
|
||||||
|
public static final int LC_L = 102;
|
||||||
|
/**
|
||||||
|
* LC_LE Opcode: Represents a conditional jump based on long64 comparison (less than or equal).
|
||||||
|
* <p>This opcode is implemented by the {@link ICLECommand} class, which defines its specific execution logic.</p>
|
||||||
|
*
|
||||||
|
* <p>Execution Steps:</p>
|
||||||
|
* <ol>
|
||||||
|
* <li>Parses the target instruction address from the instruction parameters.</li>
|
||||||
|
* <li>Pops two long64 values from the operand stack.</li>
|
||||||
|
* <li>Compares the first long64 with the second to determine if it is less than or equal to the second long64.</li>
|
||||||
|
* <li>If the first long64 is less than or equal to the second, updates the program counter (PC) to the specified target address,
|
||||||
|
* effectively jumping to the target instruction.</li>
|
||||||
|
* <li>If the first long64 is greater than the second, increments the program counter to proceed with the next sequential instruction.</li>
|
||||||
|
* </ol>
|
||||||
|
*
|
||||||
|
* <p>This opcode is commonly used for:</p>
|
||||||
|
* <ul>
|
||||||
|
* <li>Conditional branching in virtual machine execution based on long64 comparison.</li>
|
||||||
|
* <li>Implementing control flow structures such as loops, conditional statements, and boundary checks.</li>
|
||||||
|
* </ul>
|
||||||
|
*/
|
||||||
|
public static final int LC_LE = 103;
|
||||||
|
|
||||||
// 4. Stack Operations (111–150)
|
// 4. Stack Operations (111–150)
|
||||||
// 4.1 PUSH (111-120)
|
// 4.1 PUSH (111-120)
|
||||||
|
|||||||
@ -16,6 +16,7 @@ import org.jcnc.snow.vm.commands.bitwise.long64.LOrCommand;
|
|||||||
import org.jcnc.snow.vm.commands.bitwise.long64.LXorCommand;
|
import org.jcnc.snow.vm.commands.bitwise.long64.LXorCommand;
|
||||||
import org.jcnc.snow.vm.commands.control.all.JumpCommand;
|
import org.jcnc.snow.vm.commands.control.all.JumpCommand;
|
||||||
import org.jcnc.snow.vm.commands.control.int32.*;
|
import org.jcnc.snow.vm.commands.control.int32.*;
|
||||||
|
import org.jcnc.snow.vm.commands.control.long64.*;
|
||||||
import org.jcnc.snow.vm.commands.function.CallCommand;
|
import org.jcnc.snow.vm.commands.function.CallCommand;
|
||||||
import org.jcnc.snow.vm.commands.function.RetCommand;
|
import org.jcnc.snow.vm.commands.function.RetCommand;
|
||||||
import org.jcnc.snow.vm.commands.memory.all.MovCommand;
|
import org.jcnc.snow.vm.commands.memory.all.MovCommand;
|
||||||
@ -142,13 +143,22 @@ public class CommandFactory {
|
|||||||
COMMANDS[VMOpCode.L_XOR] = new LXorCommand(); // 88
|
COMMANDS[VMOpCode.L_XOR] = new LXorCommand(); // 88
|
||||||
|
|
||||||
// 3. Control Flow Operations (91–110)
|
// 3. Control Flow Operations (91–110)
|
||||||
|
// 3.1 JUMP (91-91)
|
||||||
COMMANDS[VMOpCode.JUMP] = new JumpCommand(); // 91
|
COMMANDS[VMOpCode.JUMP] = new JumpCommand(); // 91
|
||||||
|
// 3.2 int32 (92-97)
|
||||||
COMMANDS[VMOpCode.IC_E] = new ICECommand(); // 92
|
COMMANDS[VMOpCode.IC_E] = new ICECommand(); // 92
|
||||||
COMMANDS[VMOpCode.IC_NE] = new ICNECommand(); // 93
|
COMMANDS[VMOpCode.IC_NE] = new ICNECommand(); // 93
|
||||||
COMMANDS[VMOpCode.IC_G] = new ICGCommand(); // 94
|
COMMANDS[VMOpCode.IC_G] = new ICGCommand(); // 94
|
||||||
COMMANDS[VMOpCode.IC_GE] = new ICGECommand(); // 95
|
COMMANDS[VMOpCode.IC_GE] = new ICGECommand(); // 95
|
||||||
COMMANDS[VMOpCode.IC_L] = new ICLCommand(); // 96
|
COMMANDS[VMOpCode.IC_L] = new ICLCommand(); // 96
|
||||||
COMMANDS[VMOpCode.IC_LE] = new ICLECommand(); // 97
|
COMMANDS[VMOpCode.IC_LE] = new ICLECommand(); // 97
|
||||||
|
// 3.3 long64 (98-103)
|
||||||
|
COMMANDS[VMOpCode.LC_E] = new LCECommand(); // 98
|
||||||
|
COMMANDS[VMOpCode.LC_NE] = new LCNECommand(); // 99
|
||||||
|
COMMANDS[VMOpCode.LC_G] = new LCGCommand(); // 100
|
||||||
|
COMMANDS[VMOpCode.LC_GE] = new LCGECommand(); // 101
|
||||||
|
COMMANDS[VMOpCode.LC_L] = new LCLCommand(); // 102
|
||||||
|
COMMANDS[VMOpCode.LC_LE] = new LCLECommand(); // 103
|
||||||
|
|
||||||
// 4. Stack Operations (111–150)
|
// 4. Stack Operations (111–150)
|
||||||
// 4.1 PUSH (111-120)
|
// 4.1 PUSH (111-120)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user