我一直在使用PascalScript脚本引擎上的Issue 14,其中使用Goto命令跳出Case区块会产生编译器错误,即使这是完全有效的(如果难看的话)Object Pascal代码。跳出某个块时,是否有安全的方式来清除基于堆栈的代码?
发现编译器中的ProcessCase例程调用HasInvalidJumps,它扫描在Case区块外面导致的任何Gotos,并在找到一个时发出编译器错误。如果我发表评论,它编译得很好,但最终会在运行时崩溃。反汇编字节码显示了原因。我已用原始脚本代码对其进行注释:
[TYPES]
<SNIPPED>
[VARS]
Var [0]: 27 Class TFORM
Var [1]: 28 Class TAPPLICATION
Var [2]: 11 S32 //i: integer
[PROCS]
Proc [0] Export: !MAIN -1
{begin}
[0] ASSIGN GlobalVar[2], [1]
{ i := 1;}
[15] PUSHTYPE 11(S32) // 1
[20] ASSIGN Base[1], GlobalVar[2]
{ case i of}
[31] PUSHTYPE 25(U8) // 2
{ 0:}
[36] COMPARE into Base[2]: [0] = Base[1]
[57] COND_NOT_GOTO currpos + 5 Base[2] [72]
{ end;}
[67] GOTO currpos + 41 [113]
{ 1:}
[72] COMPARE into Base[2]: [1] = Base[1]
[93] COND_NOT_GOTO currpos + 10 Base[2] [113]
{ goto L1;}
[103] GOTO currpos + 8 [116]
{ end;}
[108] GOTO currpos + 0 [113]
{ end; //<-- case}
[113] POP // 1
[114] POP // 0
{ Exit;}
[115] RET
{L1:
Writeln('Label L1');}
[116] PUSHTYPE 17(WideString) // 1
[121] ASSIGN Base[1], ['????????']
[144] CALL 1
{end.}
[149] POP // 0
[150] RET
Proc [1]: External Decl: \00\00 WRITELN
“goto L1;”在103处的语句跳过113和114处的清除弹出,这使得堆栈处于无效状态。
德尔福没有任何问题,因为它不使用计算堆栈。然而,PascalScript并不如此幸运。我需要一些方法来完成这项工作,因为这种模式在一些比较简单的系统的传统脚本中非常常见,而且很少有我已经转换为PascalScript并需要支持的控制结构。
任何人有任何想法如何打补丁Codegen所以它会正确地清理堆栈?
虽然展开堆栈可能在这里工作,但我不确定它适用于所有情况。 – skamradt 2009-06-22 16:55:44
明天你会得到一个跳出两个嵌套case语句的goto,但是在标签后面有一些代码,你可以从 – 2009-06-26 21:20:04