([Ljava/lang/String;)V)无法从空堆栈中弹出操作数



为了上学,我必须编写自己的编程语言。该语言的一部分是用户能够创建和使用数组。我使用antlr 4.1来生成语法,由于编译器和代码生成器是使用java制作的,所以字节码是用Jasmin编写的。编译器能够编译我的代码,但是每当我使用单元测试来测试程序时,我都会得到以下错误:

. lang。VerifyError:类:HelloWorld,方法:主签名:([Ljava/lang/String;)V)无法从空堆栈中弹出操作数

这是我试图编译的代码(它能够像我说的那样编译)。

NMBR ARRAY nummers[20]
nummers.ADD(15)
PRINT(nummers.GET[0])

这些是数组使用的所有方法

@Override
public ArrayList<String> visitArrayStatement(CAPSParser.ArrayStatementContext ctx) {
Symbol s = symbols.get(ctx);
if (s.getName().equals(ctx.IDENTIFIER().getText())) {
jasminCode.add("ldc " + ctx.NMBR_VALUE().getText());
if (s.getType().equals(DataType.NMBR)) {
jasminCode.add("newarray int");
} else if (s.getType().equals(DataType.STR)) {
jasminCode.add("newarray java/lang/String");
}
jasminCode.add("astore " + s.getLocalslot());
}
return null;
}
@Override
public ArrayList<String> visitArrayAssignment(CAPSParser.ArrayAssignmentContext ctx) {
Symbol s = symbols.get(ctx);
arrayCounter++;
if (s.getName().equals(ctx.IDENTIFIER().getText())) {
jasminCode.add("aload " + s.getLocalslot());
jasminCode.add("ldc " + arrayCounter);
visit(ctx.expression());
if (s.getType().equals(DataType.NMBR)) {
jasminCode.add("iastore");
jasminCode.add("astore " + s.getLocalslot());
} else if (s.getType().equals(DataType.STR)) {
jasminCode.add("aastore");
jasminCode.add("astore " + s.getLocalslot());
}
}
return null;
}
@Override
public ArrayList<String> visitArrayGetValue(CAPSParser.ArrayGetValueContext ctx) {
Symbol s = symbols.get(ctx);
array = s;
if (s.getName().equals(ctx.IDENTIFIER().getText())) {
jasminCode.add("aload " + s.getLocalslot());
jasminCode.add("ldc " + ctx.NMBR_VALUE().getText());
if (s.getType().equals(DataType.NMBR)) {
jasminCode.add("iaload");
} else if (s.getType().equals(DataType.STR)) {
jasminCode.add("aaload");
}
}
return null;
}

最后这是我要运行的测试:

@Test
void checkOutputFile() throws Exception {
// Compile and assemble testFiles/hello.exlang
Compiler c = new Compiler();
JasminBytecode code = c.compileFile("testFiles/hello.exlang", "HelloWorld");
assertNotNull(code);
// Check that output matches what we expect
List<String> output = runCode(code);
assertArrayEquals(new String[] {
"15"
}, output.toArray());
}

这是生成的jasmin代码:

.bytecode 49.0
.class public hello
.super java/lang/Object
.method public static main([Ljava/lang/String;)V
.limit stack 99
.limit locals 99
ldc 20
newarray int
astore 1
aload 1
ldc 1
ldc 15
iastore
astore 1
aload 1
ldc 2
ldc 5
iastore
astore 1
aload 1
ldc 3
ldc 10
iastore
astore 1
aload 1
ldc 4
ldc 60
iastore
astore 1
getstatic java/lang/System/out Ljava/io/PrintStream;
aload 1
ldc 3
iaload
invokevirtual java/io/PrintStream/println(I)V
astore 1
return
.end method

有人知道为什么这会给我以下错误吗?如有任何帮助,我将不胜感激。

iastore的堆栈转换为:

..., arrayref, index, value →
...

iastore之后,数组,索引和值都将从堆栈中弹出,因此在它之后有另一个astore 1指令是没有意义的,因为它将存储arrayref以下的任何内容。如果此时操作数堆栈恰好为空,则astore将尝试弹出一个空堆栈,这就是错误消息所指向的。

您是否试图将修改后的数组存储回变量中?你不需要这么做。iastore修改变量引用的数组,但不创建副本。您可以删除visitArrayAssignment中出现的这一行的两次:

jasminCode.add("astore " + s.getLocalslot());

我还注意到你在调用System.out.println后正在做astore。但是println返回void,所以堆栈上没有任何返回值可以存储。你也应该删除astore

最新更新