Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/delphi/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/visual-studio-2012/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Delphi 当跳出块时,有没有安全的方法来清理基于堆栈的代码?_Delphi_Goto_Pascalscript - Fatal编程技术网

Delphi 当跳出块时,有没有安全的方法来清理基于堆栈的代码?

Delphi 当跳出块时,有没有安全的方法来清理基于堆栈的代码?,delphi,goto,pascalscript,Delphi,Goto,Pascalscript,我一直在研究PascalScript脚本引擎,在该引擎中,使用Goto命令跳出Case块会产生编译器错误,即使这是完全有效的(尽管很难看)对象Pascal代码 结果是编译器中的ProcessCase例程调用HasInvalidJumps,它扫描导致Case块之外的任何GoTo,如果发现一个,则给出编译器错误。如果我对该签出进行注释,它会编译得很好,但最终会在运行时崩溃。字节码的反汇编说明了原因。我已经用原始脚本代码对其进行了注释: [TYPES] <SNIPPED> [VARS] V

我一直在研究PascalScript脚本引擎,在该引擎中,使用Goto命令跳出Case块会产生编译器错误,即使这是完全有效的(尽管很难看)对象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
[类型]
[变量]
变量[0]:27类TFORM
变量[1]:28类
Var[2]:11s32//i:integer
[程序]
过程[0]导出:!MAIN-1
{begin}
[0]分配GlobalVar[2],[1]
{i:=1;}
[15] 推式11(S32)//1
[20] 分配基数[1],全局变量[2]
{案例一}
[31]推式25(U8)//2
{   0:}
[36]比较到基[2]:[0]=基[1]
[57]COND_NOT_GOTO currpos+5 Base[2][72]
{end;}
[67]转到当前位置+41[113]
{   1:}
[72]比较基数[2]:[1]=基数[1]
[93]COND_NOT_GOTO currpos+10 Base[2][113]
{转到L1;}
[103]转到当前位置+8[116]
{end;}
[108]转到当前位置+0[113]

{end;//简单的解决方案是:


生成GOTO for GOTO语句时,在GOTO前面加上与RET之前相同的清理代码。

简单的解决方案是:


生成GOTO for GOTO语句时,在GOTO前面加上RET之前的相同清除代码。

IIRC经典PASCAL中的GOTO规则是:

  • 只允许跳出块(在树的“同一”分支上从较高嵌套级别跳出到较低嵌套级别)
  • 从当地的程序到他们的父母
后者是afaik,从未得到Borland衍生Pascal的支持,但前者仍然成立

因此,您需要像Martin所说的那样生成退出代码,但它可能适用于多个块级别,因此您不能为每个goto生成一个can代码,但必须生成代码(以退出所需块的精确数量)

典型的测试模式是使用goto退出多个嵌套的ifs(可能在一个循环中),因为这是一个经典的微优化,至少在D7之前更快

请记住,if求值及其分支的begin..end块可能生成了需要清理的temp

----------后来添加

我认为codegenerator需要一种方法来遍历goto和它的端点之间的范围,为沿途的块生成相关的退出代码。这种方法修复程序适用于一般情况,而不仅仅是这个示例。 因为您只能跳出范围,而不能跳入范围,所以这可能没那么难

IOW生成等价于(对于假设的双格块)

Lgoto1gluecode: //出口代码第一块 流行音乐 波比 //出口代码第一块 弹出一个 流行音乐B 转到真实目的地


可以进行其他分析。例如,如果只有一个作用域,并且它已经有一个清理出口标签,则可以直接跳转。如果您确定上述pop只是丢弃的值(而不是保存的寄存器),则可以使用add$16,%esp(4*4字节值)立即执行等等。

IIRC经典帕斯卡中的goto规则是:

  • 只允许跳出块(在树的“同一”分支上从较高嵌套级别跳出到较低嵌套级别)
  • 从当地的程序到他们的父母
后者是afaik,从未得到Borland衍生Pascal的支持,但前者仍然成立

因此,您需要像Martin所说的那样生成退出代码,但它可能适用于多个块级别,因此您不能为每个goto生成一个can代码,但必须生成代码(以退出所需块的精确数量)

典型的测试模式是使用goto退出多个嵌套的ifs(可能在一个循环中),因为这是一个经典的微优化,至少在D7之前更快

请记住,if求值及其分支的begin..end块可能生成了需要清理的temp

----------后来添加

我认为codegenerator需要一种方法来遍历goto和它的端点之间的范围,为沿途的块生成相关的退出代码。这种方法修复程序适用于一般情况,而不仅仅是这个示例。 因为您只能跳出范围,而不能跳入范围,所以这可能没那么难

IOW生成等价于(对于假设的双格块)

Lgoto1gluecode: //出口代码第一块 流行音乐 波比 //出口代码第一块 弹出一个 流行音乐B 转到真实目的地


可以进行其他分析。例如,如果只有一个作用域,并且它已经有一个清理出口标签,则可以直接跳转。如果您确定上述pop只是丢弃的值(而不是保存的寄存器),则可以使用add$16,%esp(4*4字节值)立即执行等等。

在我看来,向前跳多远的计算似乎是个问题。我必须花一些时间研究解析器的实现,以进一步提供帮助,但我的猜测是,在使用goto时必须执行额外的处理,堆栈上有值,goto将放在这些值之后将从堆栈中删除。当然,要确定这一点,您需要将正在分析的当前位置(goto)和前向分析保存到目标位置,以观察堆栈更改,如果是,则保存到ad