私はPascalScriptスクリプトエンジンのIssue14に取り組んでいます。この場合、Gotoコマンドを使用してCaseブロックからジャンプすると、完全に有効な(醜い場合)Object Pascalコードであっても、コンパイラエラーが発生します。
コンパイラのProcessCaseルーチンがHasInvalidJumpsを呼び出していることがわかります。これは、Caseブロックの外側につながるすべてのGotoをスキャンし、見つかった場合はコンパイラエラーを返します。そのチェックアウトについてコメントすると、コンパイルは問題なく実行されますが、実行時にクラッシュすることになります。バイトコードを逆アセンブルすると、その理由がわかります。元のスクリプトコードで注釈を付けました。
[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
「gotoL1;」103のステートメントは、113と114のクリーンアップポップをスキップし、スタックを無効な状態のままにします。
Delphiは計算スタックを使用しないため、これに問題はありません。ただし、PascalScriptはそれほど幸運ではありません。このパターンは、PascalScriptに変換した制御構造がほとんどなく、サポートできる必要がある、はるかに単純なシステムの一部のレガシースクリプトで非常に一般的であるため、これを機能させる方法が必要です。
スタックを適切にクリーンアップするためにcodegenにパッチを適用する方法を知っている人はいますか?