Merge branch 'dev' into feat/refactor-opcode

# Conflicts:
#	src/main/java/org/jcnc/snow/vm/engine/VMOpCode.java
This commit is contained in:
Luke 2025-06-27 13:58:23 +08:00
commit 6a940011a1
51 changed files with 376 additions and 75 deletions

View File

@ -2,8 +2,8 @@ package org.jcnc.snow.compiler.backend.generator;
import org.jcnc.snow.compiler.backend.builder.VMProgramBuilder; import org.jcnc.snow.compiler.backend.builder.VMProgramBuilder;
import org.jcnc.snow.compiler.backend.core.InstructionGenerator; import org.jcnc.snow.compiler.backend.core.InstructionGenerator;
import org.jcnc.snow.compiler.backend.util.IROpCodeMapper; import org.jcnc.snow.compiler.backend.utils.IROpCodeMapper;
import org.jcnc.snow.compiler.backend.util.OpHelper; import org.jcnc.snow.compiler.backend.utils.OpHelper;
import org.jcnc.snow.compiler.ir.core.IRValue; import org.jcnc.snow.compiler.ir.core.IRValue;
import org.jcnc.snow.compiler.ir.instruction.BinaryOperationInstruction; import org.jcnc.snow.compiler.ir.instruction.BinaryOperationInstruction;
import org.jcnc.snow.compiler.ir.value.IRConstant; import org.jcnc.snow.compiler.ir.value.IRConstant;

View File

@ -2,7 +2,7 @@ package org.jcnc.snow.compiler.backend.generator;
import org.jcnc.snow.compiler.backend.builder.VMProgramBuilder; import org.jcnc.snow.compiler.backend.builder.VMProgramBuilder;
import org.jcnc.snow.compiler.backend.core.InstructionGenerator; import org.jcnc.snow.compiler.backend.core.InstructionGenerator;
import org.jcnc.snow.compiler.backend.util.OpHelper; import org.jcnc.snow.compiler.backend.utils.OpHelper;
import org.jcnc.snow.compiler.ir.instruction.CallInstruction; import org.jcnc.snow.compiler.ir.instruction.CallInstruction;
import org.jcnc.snow.compiler.ir.value.IRVirtualRegister; import org.jcnc.snow.compiler.ir.value.IRVirtualRegister;

View File

@ -1,7 +1,7 @@
package org.jcnc.snow.compiler.backend.generator; package org.jcnc.snow.compiler.backend.generator;
import org.jcnc.snow.compiler.backend.util.IROpCodeMapper; import org.jcnc.snow.compiler.backend.utils.IROpCodeMapper;
import org.jcnc.snow.compiler.backend.util.OpHelper; import org.jcnc.snow.compiler.backend.utils.OpHelper;
import org.jcnc.snow.compiler.backend.builder.VMProgramBuilder; import org.jcnc.snow.compiler.backend.builder.VMProgramBuilder;
import org.jcnc.snow.compiler.backend.core.InstructionGenerator; import org.jcnc.snow.compiler.backend.core.InstructionGenerator;
import org.jcnc.snow.compiler.ir.instruction.IRCompareJumpInstruction; import org.jcnc.snow.compiler.ir.instruction.IRCompareJumpInstruction;

View File

@ -1,6 +1,6 @@
package org.jcnc.snow.compiler.backend.generator; package org.jcnc.snow.compiler.backend.generator;
import org.jcnc.snow.compiler.backend.util.OpHelper; import org.jcnc.snow.compiler.backend.utils.OpHelper;
import org.jcnc.snow.compiler.backend.builder.VMProgramBuilder; import org.jcnc.snow.compiler.backend.builder.VMProgramBuilder;
import org.jcnc.snow.compiler.backend.core.InstructionGenerator; import org.jcnc.snow.compiler.backend.core.InstructionGenerator;
import org.jcnc.snow.compiler.ir.instruction.IRJumpInstruction; import org.jcnc.snow.compiler.ir.instruction.IRJumpInstruction;

View File

@ -2,7 +2,7 @@ package org.jcnc.snow.compiler.backend.generator;
import org.jcnc.snow.compiler.backend.builder.VMProgramBuilder; import org.jcnc.snow.compiler.backend.builder.VMProgramBuilder;
import org.jcnc.snow.compiler.backend.core.InstructionGenerator; import org.jcnc.snow.compiler.backend.core.InstructionGenerator;
import org.jcnc.snow.compiler.backend.util.OpHelper; import org.jcnc.snow.compiler.backend.utils.OpHelper;
import org.jcnc.snow.compiler.ir.instruction.LoadConstInstruction; import org.jcnc.snow.compiler.ir.instruction.LoadConstInstruction;
import org.jcnc.snow.compiler.ir.value.IRConstant; import org.jcnc.snow.compiler.ir.value.IRConstant;
import org.jcnc.snow.compiler.ir.value.IRVirtualRegister; import org.jcnc.snow.compiler.ir.value.IRVirtualRegister;

View File

@ -2,7 +2,7 @@ package org.jcnc.snow.compiler.backend.generator;
import org.jcnc.snow.compiler.backend.builder.VMProgramBuilder; import org.jcnc.snow.compiler.backend.builder.VMProgramBuilder;
import org.jcnc.snow.compiler.backend.core.InstructionGenerator; import org.jcnc.snow.compiler.backend.core.InstructionGenerator;
import org.jcnc.snow.compiler.backend.util.OpHelper; import org.jcnc.snow.compiler.backend.utils.OpHelper;
import org.jcnc.snow.compiler.ir.instruction.ReturnInstruction; import org.jcnc.snow.compiler.ir.instruction.ReturnInstruction;
import org.jcnc.snow.compiler.ir.value.IRVirtualRegister; import org.jcnc.snow.compiler.ir.value.IRVirtualRegister;

View File

@ -1,7 +1,7 @@
package org.jcnc.snow.compiler.backend.generator; package org.jcnc.snow.compiler.backend.generator;
import org.jcnc.snow.compiler.backend.util.IROpCodeMapper; import org.jcnc.snow.compiler.backend.utils.IROpCodeMapper;
import org.jcnc.snow.compiler.backend.util.OpHelper; import org.jcnc.snow.compiler.backend.utils.OpHelper;
import org.jcnc.snow.compiler.backend.builder.VMProgramBuilder; import org.jcnc.snow.compiler.backend.builder.VMProgramBuilder;
import org.jcnc.snow.compiler.backend.core.InstructionGenerator; import org.jcnc.snow.compiler.backend.core.InstructionGenerator;
import org.jcnc.snow.compiler.ir.instruction.UnaryOperationInstruction; import org.jcnc.snow.compiler.ir.instruction.UnaryOperationInstruction;

View File

@ -1,4 +1,4 @@
package org.jcnc.snow.compiler.backend.util; package org.jcnc.snow.compiler.backend.utils;
import org.jcnc.snow.compiler.ir.core.IROpCode; import org.jcnc.snow.compiler.ir.core.IROpCode;

View File

@ -1,4 +1,4 @@
package org.jcnc.snow.compiler.backend.util; package org.jcnc.snow.compiler.backend.utils;
import org.jcnc.snow.vm.engine.VMOpCode; import org.jcnc.snow.vm.engine.VMOpCode;
@ -22,6 +22,11 @@ public final class OpHelper {
*/ */
private static final Map<String, String> OPCODE_MAP; private static final Map<String, String> OPCODE_MAP;
/**
* opcode 字符串 指令名 的静态映射表
*/
private static final Map<Integer, String> OPCODE_NAME_MAP;
static { static {
Map<String, String> map = new HashMap<>(); Map<String, String> map = new HashMap<>();
map.put("I_ADD", Integer.toString(VMOpCode.I_ADD)); map.put("I_ADD", Integer.toString(VMOpCode.I_ADD));
@ -127,6 +132,11 @@ public final class OpHelper {
map.put("RET", Integer.toString(VMOpCode.RET)); map.put("RET", Integer.toString(VMOpCode.RET));
map.put("HALT", Integer.toString(VMOpCode.HALT)); map.put("HALT", Integer.toString(VMOpCode.HALT));
OPCODE_MAP = Collections.unmodifiableMap(map); OPCODE_MAP = Collections.unmodifiableMap(map);
Map<Integer, String> revmap = new HashMap<>(); // reverse map
OPCODE_MAP.forEach((key, value) -> revmap.put(Integer.parseInt(value), key));
OPCODE_NAME_MAP = Collections.unmodifiableMap(revmap);
} }
/** /**
@ -170,5 +180,27 @@ public final class OpHelper {
throw new IllegalStateException("Unknown const type: " + v.getClass()); throw new IllegalStateException("Unknown const type: " + v.getClass());
} }
/**
* 根据 opcode 数值的字符串形式获取指令名
* @param code 字符串形式的 opcode 数值
* @return opcode 对应的指令名
*/
public static String opcodeName(String code) {
return opcodeName(Integer.parseInt(code));
}
/**
* 根据 opcode 获取指令名
* @param code opcode
* @return opcode 对应的指令名
*/
public static String opcodeName(int code) {
String name = OPCODE_NAME_MAP.get(code);
if (name == null) {
throw new IllegalStateException("Unknown opcode: " + name);
}
return name;
}
// endregion // endregion
} }

View File

@ -76,6 +76,14 @@ public final class IRProgramBuilder {
* @return 生成的 FunctionNode用于后续 IRFunction 构建 * @return 生成的 FunctionNode用于后续 IRFunction 构建
*/ */
private FunctionNode wrapTopLevel(StatementNode stmt) { private FunctionNode wrapTopLevel(StatementNode stmt) {
return new FunctionNode("_start", null, String.valueOf(List.of()), List.of(stmt)); return new FunctionNode(
"_start",
null,
String.valueOf(List.of()),
List.of(stmt),
-1,
-1,
""
);
} }
} }

View File

@ -66,12 +66,12 @@ public class StatementBuilder {
buildIf(ifNode); buildIf(ifNode);
return; return;
} }
if (stmt instanceof ExpressionStatementNode(ExpressionNode exp)) { if (stmt instanceof ExpressionStatementNode(ExpressionNode exp, _, _, _)) {
// 纯表达式语句 foo(); // 纯表达式语句 foo();
expr.build(exp); expr.build(exp);
return; return;
} }
if (stmt instanceof AssignmentNode(String var, ExpressionNode rhs)) { if (stmt instanceof AssignmentNode(String var, ExpressionNode rhs, _, _, _)) {
// 赋值语句 a = b + 1; // 赋值语句 a = b + 1;
final String type = ctx.getScope().lookupType(var); final String type = ctx.getScope().lookupType(var);
@ -208,7 +208,10 @@ public class StatementBuilder {
if (cond instanceof BinaryExpressionNode( if (cond instanceof BinaryExpressionNode(
ExpressionNode left, ExpressionNode left,
String operator, String operator,
ExpressionNode right ExpressionNode right,
_,
_,
_
) )
&& ComparisonUtils.isComparisonOperator(operator)) { && ComparisonUtils.isComparisonOperator(operator)) {

View File

@ -16,8 +16,17 @@ import org.jcnc.snow.compiler.parser.ast.base.StatementNode;
* *
* @param variable 左值变量名即赋值目标 * @param variable 左值变量名即赋值目标
* @param value 表达式右值即赋值来源 * @param value 表达式右值即赋值来源
* @param line 当前节点所在的行号
* @param column 当前节点所在的列号
* @param file 当前节点所在的文件
*/ */
public record AssignmentNode(String variable, ExpressionNode value) implements StatementNode { public record AssignmentNode(
String variable,
ExpressionNode value,
int line,
int column,
String file
) implements StatementNode {
/** /**
* 返回赋值语句的字符串形式便于调试与日志输出 * 返回赋值语句的字符串形式便于调试与日志输出

View File

@ -12,9 +12,18 @@ import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode;
* @param left 左操作数子表达式 * @param left 左操作数子表达式
* @param operator 运算符字符串 "+", "-", "*", "/" * @param operator 运算符字符串 "+", "-", "*", "/"
* @param right 右操作数子表达式 * @param right 右操作数子表达式
* @param line 当前节点所在的行号
* @param column 当前节点所在的列号
* @param file 当前节点所在的文件
*/ */
public record BinaryExpressionNode(ExpressionNode left, String operator, public record BinaryExpressionNode(
ExpressionNode right) implements ExpressionNode { ExpressionNode left,
String operator,
ExpressionNode right,
int line,
int column,
String file
) implements ExpressionNode {
/** /**
* 返回该二元运算表达式的字符串表示形式 * 返回该二元运算表达式的字符串表示形式

View File

@ -14,6 +14,7 @@ import java.util.List;
* @param arguments 参数表达式列表表示函数调用中传递给函数的实际参数参数的顺序与调用顺序一致 * @param arguments 参数表达式列表表示函数调用中传递给函数的实际参数参数的顺序与调用顺序一致
* @param line 当前表达式所在的行号方便调试和错误定位 * @param line 当前表达式所在的行号方便调试和错误定位
* @param column 当前表达式所在的列号用于精确定位错误位置 * @param column 当前表达式所在的列号用于精确定位错误位置
* @param file 当前表达式所在的文件用于错误定位
*/ */
public record CallExpressionNode( public record CallExpressionNode(
ExpressionNode callee, // 被调用的表达式节点表示函数或方法名 ExpressionNode callee, // 被调用的表达式节点表示函数或方法名

View File

@ -23,6 +23,15 @@ public class DeclarationNode implements StatementNode {
/** 可选的初始化表达式 */ /** 可选的初始化表达式 */
private final Optional<ExpressionNode> initializer; private final Optional<ExpressionNode> initializer;
/** 当前节点所在的行号 **/
private final int line;
/** 当前节点所在的列号 **/
private final int column;
/** 当前节点所在的文件 **/
private final String file;
/** /**
* 构造一个 {@code DeclarationNode} 实例 * 构造一个 {@code DeclarationNode} 实例
* *
@ -30,10 +39,13 @@ public class DeclarationNode implements StatementNode {
* @param type 变量类型字符串 "int""string" * @param type 变量类型字符串 "int""string"
* @param initializer 可选初始化表达式若为 {@code null} 表示未初始化 * @param initializer 可选初始化表达式若为 {@code null} 表示未初始化
*/ */
public DeclarationNode(String name, String type, ExpressionNode initializer) { public DeclarationNode(String name, String type, ExpressionNode initializer, int line, int column, String file) {
this.name = name; this.name = name;
this.type = type; this.type = type;
this.initializer = Optional.ofNullable(initializer); this.initializer = Optional.ofNullable(initializer);
this.line = line;
this.column = column;
this.file = file;
} }
/** /**
@ -62,4 +74,29 @@ public class DeclarationNode implements StatementNode {
public Optional<ExpressionNode> getInitializer() { public Optional<ExpressionNode> getInitializer() {
return initializer; return initializer;
} }
/**
* 获取当前表达式所在的行号
*
* @return 当前表达式的行号
*/
public int line() {
return line;
}
/**
* 获取当前表达式所在的列号
*
* @return 当前表达式的列号
*/
public int column() {
return column;
}
/**
* 获取当前表达式所在的文件名
*
* @return 当前表达式所在的文件名
*/
public String file() { return file; }
} }

View File

@ -11,6 +11,14 @@ import org.jcnc.snow.compiler.parser.ast.base.StatementNode;
* </p> * </p>
* *
* @param expression 表达式主体通常为函数调用赋值方法链式调用等可求值表达式 * @param expression 表达式主体通常为函数调用赋值方法链式调用等可求值表达式
* @param line 当前节点所在的行号
* @param column 当前节点所在的列号
* @param file 当前节点所在的文件
*/ */
public record ExpressionStatementNode(ExpressionNode expression) implements StatementNode { public record ExpressionStatementNode(
ExpressionNode expression,
int line,
int column,
String file
) implements StatementNode {
} }

View File

@ -17,7 +17,17 @@ import java.util.List;
* @param parameters 参数列表每项为 {@link ParameterNode} 表示一个形参定义 * @param parameters 参数列表每项为 {@link ParameterNode} 表示一个形参定义
* @param returnType 函数的返回类型 "int""void" * @param returnType 函数的返回类型 "int""void"
* @param body 函数体语句块由一组 {@link StatementNode} 构成 * @param body 函数体语句块由一组 {@link StatementNode} 构成
* @param line 当前节点所在的行号
* @param column 当前节点所在的列号
* @param file 当前节点所在的文件
*/ */
public record FunctionNode(String name, List<ParameterNode> parameters, String returnType, public record FunctionNode(
List<StatementNode> body) implements Node { String name,
List<ParameterNode> parameters,
String returnType,
List<StatementNode> body,
int line,
int column,
String file
) implements Node {
} }

View File

@ -10,8 +10,16 @@ import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode;
* </p> * </p>
* *
* @param name 标识符的文本名称如变量名 "x"函数名 "foo" * @param name 标识符的文本名称如变量名 "x"函数名 "foo"
* @param line 当前节点所在的行号
* @param column 当前节点所在的列号
* @param file 当前节点所在的文件
*/ */
public record IdentifierNode(String name) implements ExpressionNode { public record IdentifierNode(
String name,
int line,
int column,
String file
) implements ExpressionNode {
/** /**
* 返回标识符节点的字符串形式通常为其名称本身 * 返回标识符节点的字符串形式通常为其名称本身

View File

@ -29,10 +29,16 @@ import java.util.List;
* @param condition 控制分支执行的条件表达式 * @param condition 控制分支执行的条件表达式
* @param thenBranch 条件为 true 时执行的语句块 * @param thenBranch 条件为 true 时执行的语句块
* @param elseBranch 条件为 false 时执行的语句块可为空 * @param elseBranch 条件为 false 时执行的语句块可为空
* @param line 当前节点所在的行号
* @param column 当前节点所在的列号
* @param file 当前节点所在的文件
*/ */
public record IfNode( public record IfNode(
ExpressionNode condition, ExpressionNode condition,
List<StatementNode> thenBranch, List<StatementNode> thenBranch,
List<StatementNode> elseBranch List<StatementNode> elseBranch,
int line,
int column,
String file
) implements StatementNode { ) implements StatementNode {
} }

View File

@ -14,6 +14,14 @@ import org.jcnc.snow.compiler.parser.ast.base.Node;
* </p> * </p>
* *
* @param moduleName 被导入的模块名称通常为点分层次结构 "core.utils" * @param moduleName 被导入的模块名称通常为点分层次结构 "core.utils"
* @param line 当前节点所在的行号
* @param column 当前节点所在的列号
* @param file 当前节点所在的文件
*/ */
public record ImportNode(String moduleName) implements Node { public record ImportNode(
String moduleName,
int line,
int column,
String file
) implements Node {
} }

View File

@ -17,7 +17,17 @@ import java.util.List;
* @param condition 每次迭代前评估的条件表达式控制循环是否继续 * @param condition 每次迭代前评估的条件表达式控制循环是否继续
* @param update 每轮迭代完成后执行的更新语句 * @param update 每轮迭代完成后执行的更新语句
* @param body 循环体语句列表表示循环主体执行逻辑 * @param body 循环体语句列表表示循环主体执行逻辑
* @param line 当前节点所在的行号
* @param column 当前节点所在的列号
* @param file 当前节点所在的文件
*/ */
public record LoopNode(StatementNode initializer, ExpressionNode condition, StatementNode update, public record LoopNode(
List<StatementNode> body) implements StatementNode { StatementNode initializer,
ExpressionNode condition,
StatementNode update,
List<StatementNode> body,
int line,
int column,
String file
) implements StatementNode {
} }

View File

@ -11,8 +11,17 @@ import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode;
* *
* @param object 左侧对象表达式表示成员所属的作用域或容器 * @param object 左侧对象表达式表示成员所属的作用域或容器
* @param member 要访问的成员名称字段名或方法名 * @param member 要访问的成员名称字段名或方法名
* @param line 当前节点所在的行号
* @param column 当前节点所在的列号
* @param file 当前节点所在的文件
*/ */
public record MemberExpressionNode(ExpressionNode object, String member) implements ExpressionNode { public record MemberExpressionNode(
ExpressionNode object,
String member,
int line,
int column,
String file
) implements ExpressionNode {
/** /**
* 返回成员访问表达式的字符串形式 * 返回成员访问表达式的字符串形式

View File

@ -13,8 +13,18 @@ import java.util.StringJoiner;
* @param name 模块名称 * @param name 模块名称
* @param imports 模块导入列表每个导入是一个 {@link ImportNode} * @param imports 模块导入列表每个导入是一个 {@link ImportNode}
* @param functions 模块中的函数列表每个函数是一个 {@link FunctionNode} * @param functions 模块中的函数列表每个函数是一个 {@link FunctionNode}
* @param line 当前节点所在的行号
* @param column 当前节点所在的列号
* @param file 当前节点所在的文件
*/ */
public record ModuleNode(String name, List<ImportNode> imports, List<FunctionNode> functions) implements Node { public record ModuleNode(
String name,
List<ImportNode> imports,
List<FunctionNode> functions,
int line,
int column,
String file
) implements Node {
/** /**
* 返回模块节点的字符串表示形式包含模块名导入模块列表和函数列表 * 返回模块节点的字符串表示形式包含模块名导入模块列表和函数列表

View File

@ -11,8 +11,17 @@ import org.jcnc.snow.compiler.parser.ast.base.Node;
* *
* @param name 参数名称标识符 * @param name 参数名称标识符
* @param type 参数类型字符串 "int""string" * @param type 参数类型字符串 "int""string"
* @param line 当前节点所在的行号
* @param column 当前节点所在的列号
* @param file 当前节点所在的文件
*/ */
public record ParameterNode(String name, String type) implements Node { public record ParameterNode(
String name,
String type,
int line,
int column,
String file
) implements Node {
/** /**
* 返回参数的字符串形式格式为 {@code name:type} * 返回参数的字符串形式格式为 {@code name:type}

View File

@ -23,13 +23,25 @@ public class ReturnNode implements StatementNode {
/** 可选的返回值表达式 */ /** 可选的返回值表达式 */
private final Optional<ExpressionNode> expression; private final Optional<ExpressionNode> expression;
/** 当前节点所在的行号 **/
private final int line;
/** 当前节点所在的列号 **/
private final int column;
/** 当前节点所在的文件 **/
private final String file;
/** /**
* 构造一个 {@code ReturnNode} 实例 * 构造一个 {@code ReturnNode} 实例
* *
* @param expression 返回值表达式如果无返回值则可为 {@code null} * @param expression 返回值表达式如果无返回值则可为 {@code null}
*/ */
public ReturnNode(ExpressionNode expression) { public ReturnNode(ExpressionNode expression, int line, int column, String file) {
this.expression = Optional.ofNullable(expression); this.expression = Optional.ofNullable(expression);
this.line = line;
this.column = column;
this.file = file;
} }
/** /**
@ -40,4 +52,29 @@ public class ReturnNode implements StatementNode {
public Optional<ExpressionNode> getExpression() { public Optional<ExpressionNode> getExpression() {
return expression; return expression;
} }
/**
* 获取当前表达式所在的行号
*
* @return 当前表达式的行号
*/
public int line() {
return line;
}
/**
* 获取当前表达式所在的列号
*
* @return 当前表达式的列号
*/
public int column() {
return column;
}
/**
* 获取当前表达式所在的文件名
*
* @return 当前表达式所在的文件名
*/
public String file() { return file; }
} }

View File

@ -15,9 +15,17 @@ import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode;
* *
* @param operator 一元运算符 "-" "!" * @param operator 一元运算符 "-" "!"
* @param operand 运算对象 / 右操作数 * @param operand 运算对象 / 右操作数
* @param line 当前节点所在的行号
* @param column 当前节点所在的列号
* @param file 当前节点所在的文件
*/ */
public record UnaryExpressionNode(String operator, public record UnaryExpressionNode(
ExpressionNode operand) implements ExpressionNode { String operator,
ExpressionNode operand,
int line,
int column,
String file
) implements ExpressionNode {
/** /**
* 生成调试友好的字符串表示例如 {@code "-x"} {@code "!flag"} * 生成调试友好的字符串表示例如 {@code "-x"} {@code "!flag"}

View File

@ -37,6 +37,11 @@ public record BinaryOperatorParselet(Precedence precedence, boolean leftAssoc) i
*/ */
@Override @Override
public ExpressionNode parse(ParserContext ctx, ExpressionNode left) { public ExpressionNode parse(ParserContext ctx, ExpressionNode left) {
// 获取当前 token 的行号列号和文件名
int line = ctx.getTokens().peek().getLine();
int column = ctx.getTokens().peek().getCol();
String file = ctx.getSourceName();
Token op = ctx.getTokens().next(); Token op = ctx.getTokens().next();
int prec = precedence.ordinal(); int prec = precedence.ordinal();
@ -46,7 +51,7 @@ public record BinaryOperatorParselet(Precedence precedence, boolean leftAssoc) i
leftAssoc ? Precedence.values()[prec] : Precedence.values()[prec - 1] leftAssoc ? Precedence.values()[prec] : Precedence.values()[prec - 1]
); );
return new BinaryExpressionNode(left, op.getLexeme(), right); return new BinaryExpressionNode(left, op.getLexeme(), right, line, column, file);
} }
/** /**

View File

@ -26,14 +26,15 @@ public class CallParselet implements InfixParselet {
*/ */
@Override @Override
public ExpressionNode parse(ParserContext ctx, ExpressionNode left) { public ExpressionNode parse(ParserContext ctx, ExpressionNode left) {
// 获取函数名 token 的行号列号和文件名
int line = ctx.getTokens().peek(-1).getLine();
int column = ctx.getTokens().peek(-1).getCol();
String file = ctx.getSourceName();
ctx.getTokens().next(); // 消费 "(" ctx.getTokens().next(); // 消费 "("
List<ExpressionNode> args = new ArrayList<>(); List<ExpressionNode> args = new ArrayList<>();
// 获取当前 token 的行号和列号
int line = ctx.getTokens().peek().getLine();
int column = ctx.getTokens().peek().getCol();
// 解析函数调用参数 // 解析函数调用参数
if (!ctx.getTokens().peek().getLexeme().equals(")")) { if (!ctx.getTokens().peek().getLexeme().equals(")")) {
do { do {
@ -43,8 +44,7 @@ public class CallParselet implements InfixParselet {
ctx.getTokens().expect(")"); // 消费并验证 ")" ctx.getTokens().expect(")"); // 消费并验证 ")"
// 创建 CallExpressionNode 并传递位置信息,文件名称 // 创建 CallExpressionNode 并传递位置信息
String file = ctx.getSourceName();
return new CallExpressionNode(left, args, line, column, file); return new CallExpressionNode(left, args, line, column, file);
} }

View File

@ -24,6 +24,11 @@ public class IdentifierParselet implements PrefixParselet {
*/ */
@Override @Override
public ExpressionNode parse(ParserContext ctx, Token token) { public ExpressionNode parse(ParserContext ctx, Token token) {
return new IdentifierNode(token.getLexeme()); // 获取标识符 token 的行号列号和文件名
int line = ctx.getTokens().peek(-1).getLine();
int column = ctx.getTokens().peek(-1).getCol();
String file = ctx.getSourceName();
return new IdentifierNode(token.getLexeme(), line, column, file);
} }
} }

View File

@ -28,8 +28,13 @@ public class MemberParselet implements InfixParselet {
TokenStream ts = ctx.getTokens(); TokenStream ts = ctx.getTokens();
ts.expect("."); // 消费点号 ts.expect("."); // 消费点号
// 获取当前 token 的行号列号和文件名
int line = ctx.getTokens().peek().getLine();
int column = ctx.getTokens().peek().getCol();
String file = ctx.getSourceName();
String member = ts.expectType(TokenType.IDENTIFIER).getLexeme(); String member = ts.expectType(TokenType.IDENTIFIER).getLexeme();
return new MemberExpressionNode(left, member); return new MemberExpressionNode(left, member, line, column, file);
} }
/** /**

View File

@ -41,6 +41,11 @@ public class UnaryOperatorParselet implements PrefixParselet {
*/ */
@Override @Override
public ExpressionNode parse(ParserContext ctx, Token token) { public ExpressionNode parse(ParserContext ctx, Token token) {
// 获取当前 token 的行号列号和文件名
int line = ctx.getTokens().peek().getLine();
int column = ctx.getTokens().peek().getCol();
String file = ctx.getSourceName();
/* ------------------------------------------------------------ /* ------------------------------------------------------------
* 1. UNARY 优先级递归解析操作数避免错误结合顺序 * 1. UNARY 优先级递归解析操作数避免错误结合顺序
* ------------------------------------------------------------ */ * ------------------------------------------------------------ */
@ -50,6 +55,6 @@ public class UnaryOperatorParselet implements PrefixParselet {
/* ------------------------------------------------------------ /* ------------------------------------------------------------
* 2. 封装成 AST 节点并返回 * 2. 封装成 AST 节点并返回
* ------------------------------------------------------------ */ * ------------------------------------------------------------ */
return new UnaryExpressionNode(token.getLexeme(), operand); return new UnaryExpressionNode(token.getLexeme(), operand, line, column, file);
} }
} }

View File

@ -57,6 +57,11 @@ public class FunctionParser implements TopLevelParser {
public FunctionNode parse(ParserContext ctx) { public FunctionNode parse(ParserContext ctx) {
TokenStream ts = ctx.getTokens(); TokenStream ts = ctx.getTokens();
// 获取当前 token 的行号列号和文件名
int line = ctx.getTokens().peek().getLine();
int column = ctx.getTokens().peek().getCol();
String file = ctx.getSourceName();
parseFunctionHeader(ts); parseFunctionHeader(ts);
String functionName = parseFunctionName(ts); String functionName = parseFunctionName(ts);
@ -69,7 +74,7 @@ public class FunctionParser implements TopLevelParser {
parseFunctionFooter(ts); parseFunctionFooter(ts);
return new FunctionNode(functionName, parameters, returnType[0], body); return new FunctionNode(functionName, parameters, returnType[0], body, line, column, file);
} }
/** /**
@ -92,7 +97,7 @@ public class FunctionParser implements TopLevelParser {
map.put("parameter", new SectionDefinition( map.put("parameter", new SectionDefinition(
(TokenStream stream) -> stream.peek().getLexeme().equals("parameter"), (TokenStream stream) -> stream.peek().getLexeme().equals("parameter"),
(ParserContext context, TokenStream stream) -> params.addAll(parseParameters(stream)) (ParserContext context, TokenStream stream) -> params.addAll(parseParameters(context))
)); ));
map.put("return_type", new SectionDefinition( map.put("return_type", new SectionDefinition(
@ -154,10 +159,12 @@ public class FunctionParser implements TopLevelParser {
* </pre> * </pre>
* </p> * </p>
* *
* @param ts 当前使用的 {@link TokenStream} * @param ctx 当前解析上下文包含 {@link TokenStream} 和符号表等作用域信息
* @return 所有参数节点的列表 * @return 所有参数节点的列表
*/ */
private List<ParameterNode> parseParameters(TokenStream ts) { private List<ParameterNode> parseParameters(ParserContext ctx) {
TokenStream ts = ctx.getTokens();
ts.expect("parameter"); ts.expect("parameter");
ts.expect(":"); ts.expect(":");
skipComments(ts); skipComments(ts);
@ -175,13 +182,19 @@ public class FunctionParser implements TopLevelParser {
if (lex.equals("return_type") || lex.equals("body") || lex.equals("end")) { if (lex.equals("return_type") || lex.equals("body") || lex.equals("end")) {
break; break;
} }
// 获取当前 token 的行号列号和文件名
int line = ctx.getTokens().peek().getLine();
int column = ctx.getTokens().peek().getCol();
String file = ctx.getSourceName();
ts.expect("declare"); ts.expect("declare");
String pname = ts.expectType(TokenType.IDENTIFIER).getLexeme(); String pname = ts.expectType(TokenType.IDENTIFIER).getLexeme();
ts.expect(":"); ts.expect(":");
String ptype = ts.expectType(TokenType.TYPE).getLexeme(); String ptype = ts.expectType(TokenType.TYPE).getLexeme();
skipComments(ts); skipComments(ts);
ts.expectType(TokenType.NEWLINE); ts.expectType(TokenType.NEWLINE);
list.add(new ParameterNode(pname, ptype)); list.add(new ParameterNode(pname, ptype, line, column, file));
} }
return list; return list;
} }

View File

@ -46,13 +46,18 @@ public class ImportParser {
// 解析一个或多个模块名标识符允许使用逗号分隔多个模块 // 解析一个或多个模块名标识符允许使用逗号分隔多个模块
do { do {
// 获取当前 token 的行号列号和文件名
int line = ctx.getTokens().peek().getLine();
int column = ctx.getTokens().peek().getCol();
String file = ctx.getSourceName();
// 获取当前标识符类型的词法单元并提取其原始词素 // 获取当前标识符类型的词法单元并提取其原始词素
String mod = ctx.getTokens() String mod = ctx.getTokens()
.expectType(TokenType.IDENTIFIER) .expectType(TokenType.IDENTIFIER)
.getLexeme(); .getLexeme();
// 创建 ImportNode 节点并加入列表 // 创建 ImportNode 节点并加入列表
imports.add(new ImportNode(mod)); imports.add(new ImportNode(mod, line, column, file));
} while (ctx.getTokens().match(",")); // 如果匹配到逗号继续解析下一个模块名 } while (ctx.getTokens().match(",")); // 如果匹配到逗号继续解析下一个模块名
// 最后必须匹配换行符标志 import 语句的结束 // 最后必须匹配换行符标志 import 语句的结束

View File

@ -40,6 +40,11 @@ public class ModuleParser implements TopLevelParser {
// 获取当前上下文中提供的词法流 // 获取当前上下文中提供的词法流
TokenStream ts = ctx.getTokens(); TokenStream ts = ctx.getTokens();
// 获取当前 token 的行号列号和文件名
int line = ctx.getTokens().peek().getLine();
int column = ctx.getTokens().peek().getCol();
String file = ctx.getSourceName();
// 期望模块声明以关键字 "module:" 开始 // 期望模块声明以关键字 "module:" 开始
ts.expect("module"); ts.expect("module");
ts.expect(":"); ts.expect(":");
@ -90,6 +95,6 @@ public class ModuleParser implements TopLevelParser {
ts.expect("module"); ts.expect("module");
// 构建并返回完整的模块语法树节点 // 构建并返回完整的模块语法树节点
return new ModuleNode(name, imports, functions); return new ModuleNode(name, imports, functions, line, column, file);
} }
} }

View File

@ -43,6 +43,11 @@ public class DeclarationStatementParser implements StatementParser {
*/ */
@Override @Override
public DeclarationNode parse(ParserContext ctx) { public DeclarationNode parse(ParserContext ctx) {
// 获取当前 token 的行号列号和文件名
int line = ctx.getTokens().peek().getLine();
int column = ctx.getTokens().peek().getCol();
String file = ctx.getSourceName();
// 声明语句必须以 "declare" 开头 // 声明语句必须以 "declare" 开头
ctx.getTokens().expect("declare"); ctx.getTokens().expect("declare");
@ -69,6 +74,6 @@ public class DeclarationStatementParser implements StatementParser {
ctx.getTokens().expectType(TokenType.NEWLINE); ctx.getTokens().expectType(TokenType.NEWLINE);
// 返回构建好的声明语法树节点 // 返回构建好的声明语法树节点
return new DeclarationNode(name, type, init); return new DeclarationNode(name, type, init, line, column, file);
} }
} }

View File

@ -50,6 +50,11 @@ public class ExpressionStatementParser implements StatementParser {
throw new IllegalStateException("Cannot parse expression starting with keyword: " + ts.peek().getLexeme()); throw new IllegalStateException("Cannot parse expression starting with keyword: " + ts.peek().getLexeme());
} }
// 获取当前 token 的行号列号和文件名
int line = ctx.getTokens().peek().getLine();
int column = ctx.getTokens().peek().getCol();
String file = ctx.getSourceName();
// 处理赋值语句格式为 identifier = expression // 处理赋值语句格式为 identifier = expression
if (ts.peek().getType() == TokenType.IDENTIFIER if (ts.peek().getType() == TokenType.IDENTIFIER
&& ts.peek(1).getLexeme().equals("=")) { && ts.peek(1).getLexeme().equals("=")) {
@ -58,13 +63,13 @@ public class ExpressionStatementParser implements StatementParser {
ts.expect("="); // 消耗等号 ts.expect("="); // 消耗等号
ExpressionNode value = new PrattExpressionParser().parse(ctx); // 解析表达式 ExpressionNode value = new PrattExpressionParser().parse(ctx); // 解析表达式
ts.expectType(TokenType.NEWLINE); // 语句必须以换行符结束 ts.expectType(TokenType.NEWLINE); // 语句必须以换行符结束
return new AssignmentNode(varName, value); // 返回赋值节点 return new AssignmentNode(varName, value, line, column, file); // 返回赋值节点
} }
// 处理普通表达式语句如函数调用字面量运算表达式等 // 处理普通表达式语句如函数调用字面量运算表达式等
ExpressionNode expr = new PrattExpressionParser().parse(ctx); ExpressionNode expr = new PrattExpressionParser().parse(ctx);
ts.expectType(TokenType.NEWLINE); // 语句必须以换行符结束 ts.expectType(TokenType.NEWLINE); // 语句必须以换行符结束
return new ExpressionStatementNode(expr); // 返回表达式语句节点 return new ExpressionStatementNode(expr, line, column, file); // 返回表达式语句节点
} }
} }

View File

@ -47,6 +47,11 @@ public class IfStatementParser implements StatementParser {
public IfNode parse(ParserContext ctx) { public IfNode parse(ParserContext ctx) {
var ts = ctx.getTokens(); // 获取 token 流引用 var ts = ctx.getTokens(); // 获取 token 流引用
// 获取当前 token 的行号列号和文件名
int line = ctx.getTokens().peek().getLine();
int column = ctx.getTokens().peek().getCol();
String file = ctx.getSourceName();
// 消耗起始关键字 "if" // 消耗起始关键字 "if"
ts.expect("if"); ts.expect("if");
@ -120,6 +125,6 @@ public class IfStatementParser implements StatementParser {
ts.expectType(TokenType.NEWLINE); ts.expectType(TokenType.NEWLINE);
// 构建并返回 IfNode包含条件then 分支和 else 分支 // 构建并返回 IfNode包含条件then 分支和 else 分支
return new IfNode(condition, thenBranch, elseBranch); return new IfNode(condition, thenBranch, elseBranch, line, column, file);
} }
} }

View File

@ -64,6 +64,12 @@ public class LoopStatementParser implements StatementParser {
public LoopNode parse(ParserContext ctx) { public LoopNode parse(ParserContext ctx) {
TokenStream ts = ctx.getTokens(); TokenStream ts = ctx.getTokens();
// 获取当前 token 的行号列号
int loop_line = ctx.getTokens().peek().getLine();
int loop_column = ctx.getTokens().peek().getCol();
String file = ctx.getSourceName();
// 匹配 loop: 起始语法 // 匹配 loop: 起始语法
ParserUtils.matchHeader(ts, "loop"); ParserUtils.matchHeader(ts, "loop");
@ -101,12 +107,16 @@ public class LoopStatementParser implements StatementParser {
sections.put("update", new FlexibleSectionParser.SectionDefinition( sections.put("update", new FlexibleSectionParser.SectionDefinition(
ts1 -> ts1.peek().getLexeme().equals("update"), ts1 -> ts1.peek().getLexeme().equals("update"),
(ctx1, ts1) -> { (ctx1, ts1) -> {
// 获取当前 token 的行号列号
int line = ctx.getTokens().peek().getLine();
int column = ctx.getTokens().peek().getCol();
ParserUtils.matchHeader(ts1, "update"); ParserUtils.matchHeader(ts1, "update");
String varName = ts1.expectType(TokenType.IDENTIFIER).getLexeme(); String varName = ts1.expectType(TokenType.IDENTIFIER).getLexeme();
ts1.expect("="); ts1.expect("=");
ExpressionNode expr = new PrattExpressionParser().parse(ctx1); ExpressionNode expr = new PrattExpressionParser().parse(ctx1);
ts1.expectType(TokenType.NEWLINE); ts1.expectType(TokenType.NEWLINE);
update[0] = new AssignmentNode(varName, expr); update[0] = new AssignmentNode(varName, expr, line, column, file);
ParserUtils.skipNewlines(ts1); ParserUtils.skipNewlines(ts1);
} }
)); ));
@ -140,6 +150,6 @@ public class LoopStatementParser implements StatementParser {
ParserUtils.matchFooter(ts, "loop"); ParserUtils.matchFooter(ts, "loop");
// 返回构造完成的 LoopNode // 返回构造完成的 LoopNode
return new LoopNode(initializer[0], condition[0], update[0], body); return new LoopNode(initializer[0], condition[0], update[0], body, loop_line, loop_column, file);
} }
} }

View File

@ -35,6 +35,11 @@ public class ReturnStatementParser implements StatementParser {
*/ */
@Override @Override
public ReturnNode parse(ParserContext ctx) { public ReturnNode parse(ParserContext ctx) {
// 获取当前 token 的行号列号和文件名
int line = ctx.getTokens().peek().getLine();
int column = ctx.getTokens().peek().getCol();
String file = ctx.getSourceName();
// 消耗 "return" 关键字 // 消耗 "return" 关键字
ctx.getTokens().expect("return"); ctx.getTokens().expect("return");
@ -49,6 +54,6 @@ public class ReturnStatementParser implements StatementParser {
ctx.getTokens().expectType(TokenType.NEWLINE); ctx.getTokens().expectType(TokenType.NEWLINE);
// 构建并返回 ReturnNode可能为空表达式 // 构建并返回 ReturnNode可能为空表达式
return new ReturnNode(expr); return new ReturnNode(expr, line, column, file);
} }
} }

View File

@ -51,8 +51,8 @@ public class CallExpressionAnalyzer implements ExpressionAnalyzer<CallExpression
ExpressionNode callee = call.callee(); ExpressionNode callee = call.callee();
// 支持模块调用形式ModuleName.FunctionName(...) // 支持模块调用形式ModuleName.FunctionName(...)
if (callee instanceof MemberExpressionNode(var obj, String member) if (callee instanceof MemberExpressionNode(var obj, String member, _, _, _)
&& obj instanceof IdentifierNode(String mod)) { && obj instanceof IdentifierNode(String mod, _, _, _)) {
// 验证模块是否存在并已导入 // 验证模块是否存在并已导入
if (!ctx.getModules().containsKey(mod) if (!ctx.getModules().containsKey(mod)
|| (!mi.getImports().contains(mod) && !mi.getName().equals(mod))) { || (!mi.getImports().contains(mod) && !mi.getName().equals(mod))) {
@ -65,7 +65,7 @@ public class CallExpressionAnalyzer implements ExpressionAnalyzer<CallExpression
functionName = member; functionName = member;
// 简单函数名形式func(...) // 简单函数名形式func(...)
} else if (callee instanceof IdentifierNode(String name)) { } else if (callee instanceof IdentifierNode(String name, _, _, _)) {
functionName = name; functionName = name;
// 不支持的 callee 形式 // 不支持的 callee 形式

View File

@ -1,7 +1,7 @@
package org.jcnc.snow.pkg.tasks; package org.jcnc.snow.pkg.tasks;
import org.jcnc.snow.cli.commands.CompileCommand; import org.jcnc.snow.cli.commands.CompileCommand;
import org.jcnc.snow.pkg.model.Project; import org.jcnc.snow.compiler.backend.utils.OpHelper;
import org.jcnc.snow.compiler.backend.alloc.RegisterAllocator; import org.jcnc.snow.compiler.backend.alloc.RegisterAllocator;
import org.jcnc.snow.compiler.backend.builder.VMCodeGenerator; import org.jcnc.snow.compiler.backend.builder.VMCodeGenerator;
import org.jcnc.snow.compiler.backend.builder.VMProgramBuilder; import org.jcnc.snow.compiler.backend.builder.VMProgramBuilder;
@ -18,6 +18,7 @@ import org.jcnc.snow.compiler.parser.context.ParserContext;
import org.jcnc.snow.compiler.parser.core.ParserEngine; import org.jcnc.snow.compiler.parser.core.ParserEngine;
import org.jcnc.snow.compiler.parser.function.ASTPrinter; import org.jcnc.snow.compiler.parser.function.ASTPrinter;
import org.jcnc.snow.compiler.semantic.core.SemanticAnalyzerRunner; import org.jcnc.snow.compiler.semantic.core.SemanticAnalyzerRunner;
import org.jcnc.snow.pkg.model.Project;
import org.jcnc.snow.vm.VMLauncher; import org.jcnc.snow.vm.VMLauncher;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
@ -198,7 +199,12 @@ public final class CompileTask implements Task {
List<String> finalCode = builder.build(); List<String> finalCode = builder.build();
System.out.println("### VM code"); System.out.println("### VM code");
finalCode.forEach(System.out::println); for (int i = 0; i < finalCode.size(); i++) {
String[] parts = finalCode.get(i).split(" ");
String name = OpHelper.opcodeName(parts[0]);
parts = Arrays.copyOfRange(parts, 1, parts.length);
System.out.printf("%04d: %-10s %s\n", i, name, String.join(" ", parts));
}
// ---------------- 5. 写出 .water 文件 ---------------- // ---------------- 5. 写出 .water 文件 ----------------
Path outputFile = deriveOutputPath(sources, outputName, dir); Path outputFile = deriveOutputPath(sources, outputName, dir);

View File

@ -50,7 +50,7 @@ public class BAddCommand implements Command {
byte a = (byte) operandStack.pop(); byte a = (byte) operandStack.pop();
// Perform the addition and push the result back onto the stack // Perform the addition and push the result back onto the stack
operandStack.push(a + b); operandStack.push((byte)(a + b));
// Return the updated program counter (next instruction) // Return the updated program counter (next instruction)
return currentPC + 1; return currentPC + 1;

View File

@ -56,7 +56,7 @@ public class BDivCommand implements Command {
} }
// Perform the division and push the result back onto the stack // Perform the division and push the result back onto the stack
operandStack.push(a / b); operandStack.push((byte)(a / b));
// Return the updated program counter (next instruction) // Return the updated program counter (next instruction)
return currentPC + 1; return currentPC + 1;

View File

@ -50,7 +50,7 @@ public class BModCommand implements Command {
byte a = (byte) operandStack.pop(); byte a = (byte) operandStack.pop();
// Perform the modulus operation and push the result back onto the stack // Perform the modulus operation and push the result back onto the stack
operandStack.push(a % b); operandStack.push((byte)(a % b));
// Return the updated program counter (next instruction) // Return the updated program counter (next instruction)
return currentPC + 1; return currentPC + 1;

View File

@ -50,7 +50,7 @@ public class BMulCommand implements Command {
byte a = (byte) operandStack.pop(); byte a = (byte) operandStack.pop();
// Perform the multiplication and push the result back onto the stack // Perform the multiplication and push the result back onto the stack
operandStack.push(a * b); operandStack.push((byte)(a * b));
// Return the updated program counter (next instruction) // Return the updated program counter (next instruction)
return currentPC + 1; return currentPC + 1;

View File

@ -50,7 +50,7 @@ public class BSubCommand implements Command {
byte a = (byte) operandStack.pop(); byte a = (byte) operandStack.pop();
// Perform the subtraction and push the result back onto the stack // Perform the subtraction and push the result back onto the stack
operandStack.push(a - b); operandStack.push((byte)(a - b));
// Return the updated program counter (next instruction) // Return the updated program counter (next instruction)
return currentPC + 1; return currentPC + 1;

View File

@ -46,11 +46,11 @@ public class SAddCommand implements Command {
@Override @Override
public int execute(String[] parts, int currentPC, OperandStack operandStack, LocalVariableStore localVariableStore, CallStack callStack) { public int execute(String[] parts, int currentPC, OperandStack operandStack, LocalVariableStore localVariableStore, CallStack callStack) {
// Pop the top two operands from the stack // Pop the top two operands from the stack
Short b = (Short) operandStack.pop(); short b = (short) operandStack.pop();
Short a = (Short) operandStack.pop(); short a = (short) operandStack.pop();
// Perform the addition and push the result back onto the stack // Perform the addition and push the result back onto the stack
operandStack.push(a + b); operandStack.push((short)(a + b));
// Return the updated program counter (next instruction) // Return the updated program counter (next instruction)
return currentPC + 1; return currentPC + 1;

View File

@ -56,7 +56,7 @@ public class SDivCommand implements Command {
} }
// Perform the division and push the result back onto the stack // Perform the division and push the result back onto the stack
operandStack.push(a / b); operandStack.push((short)(a / b));
// Return the updated program counter (next instruction) // Return the updated program counter (next instruction)
return currentPC + 1; return currentPC + 1;

View File

@ -50,7 +50,7 @@ public class SModCommand implements Command {
short a = (short) operandStack.pop(); short a = (short) operandStack.pop();
// Perform the modulus operation and push the result back onto the stack // Perform the modulus operation and push the result back onto the stack
operandStack.push(a % b); operandStack.push((short)(a % b));
// Return the updated program counter (next instruction) // Return the updated program counter (next instruction)
return currentPC + 1; return currentPC + 1;

View File

@ -50,7 +50,7 @@ public class SMulCommand implements Command {
short a = (short) operandStack.pop(); short a = (short) operandStack.pop();
// Perform the multiplication and push the result back onto the stack // Perform the multiplication and push the result back onto the stack
operandStack.push(a * b); operandStack.push((short)(a * b));
// Return the updated program counter (next instruction) // Return the updated program counter (next instruction)
return currentPC + 1; return currentPC + 1;

View File

@ -50,7 +50,7 @@ public class SSubCommand implements Command {
short a = (short) operandStack.pop(); short a = (short) operandStack.pop();
// Perform the subtraction and push the result back onto the stack // Perform the subtraction and push the result back onto the stack
operandStack.push(a - b); operandStack.push((short)(a - b));
// Return the updated program counter (next instruction) // Return the updated program counter (next instruction)
return currentPC + 1; return currentPC + 1;