我一直在使用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