Compiler construction 字节码编译器中计算跳转地址的智能解决方案?

Compiler construction 字节码编译器中计算跳转地址的智能解决方案?,compiler-construction,bytecode,Compiler Construction,Bytecode,假设我正在实现一个字节码编译器,类似于Lua的/Python的。。。等等 我正在遍历AST,生成字节码指令,在if-else的循环中遇到中断: while (cond1) if (cond2) ... else break (我试着写出等价的字节码,但看起来没什么帮助。) 关键是,在这个例子中至少有4条“跳转”指令,而我 想找到一个优雅的解决方案来填写跳转地址,因为我编译的AST。。。 我不知道while循环或break的跳转地址,直到我完全完成

假设我正在实现一个字节码编译器,类似于Lua的/Python的。。。等等

我正在遍历AST,生成字节码指令,在
if-else
循环中遇到
中断

while (cond1)
    if (cond2)
        ...
    else
        break
(我试着写出等价的字节码,但看起来没什么帮助。)

关键是,在这个例子中至少有4条“跳转”指令,而我 想找到一个优雅的解决方案来填写跳转地址,因为我编译的AST。。。 我不知道
while
循环或
break
的跳转地址,直到我完全完成 “编译”内部语句

  • 伪代码解决方案将是理想的
  • 解决方案不应取决于我是在实现基于寄存器还是基于堆栈的字节码编译器(我两者都在使用)
  • 我还没在看《龙之书》


    如果我递归编译AST,当我在一些任意数量的循环和
    If-else
    块中到达
    break
    语句时,编译器应该如何知道跳转到哪个空标签?我猜是递归AST遍历函数外部的某种类型的标签名堆栈。

    您需要的原理称为“backpatching”:为前向跳转填充一个伪值,为语句体生成代码,然后返回并在最后用真实值替换伪值

    e、 g


    关于您的编辑:

    如果我递归编译AST,当我在一些任意数量的循环和
    If-else
    块中到达
    break
    语句时,编译器应该如何知道跳转到哪个空标签?我猜是递归AST遍历函数外部的某种类型的标签名堆栈

    实现
    break
    语句的跳转的目标是最内部的封闭循环的结束;是的,您可以使用显式外部堆栈跟踪它

    但是,如果您有一个递归函数,那么您已经有了一个隐式堆栈——递归函数调用的调用框架——因此您可能也不需要显式堆栈

    e、 g.在

    ...
    while (outer)
        ...
        if (outer_done)
            break
        ...
    
        while (inner)
            ...
            if (inner_done)
                break
            ...
        [break from inner 'while' ends up here]
    
        ...
        if (outer_done_2)
            break
        ...
    [break from outer 'while' ends up here]
    ...
    
    内部
    while
    循环的整个代码生成过程发生在外部
    while
    循环主体的AST递归遍历中。在这个递归调用中,您只需要关心内部循环,而不需要关心外部循环

    因此,您需要做的就是:

    • 在开始处理
      时保存任何当前回接状态,而
    • 启动一个新的空列表,用于跟踪此
      正文中出现的任何
      中断
    • 处理正文(可能导致递归调用)
    • 贴上贴片
    • 然后在退出之前恢复以前的状态
    e、 g.有点像这样:

    codegen for while:
        save previous break backpatch list
        initialise break backpatch list as empty
        perform codegen for evaluating condition
        perform codegen for body statements
        apply backpatches
        restore previous break backpatch list
    

    当前的
    break
    backpatch列表必须是传递给所有codegen函数的某个状态的一部分(需要将
    break
    的codegen附加到该状态)。但是保存的列表可以作为
    的局部变量进行跟踪,而
    codegen函数。

    else块中的中断应该是
    jl2
    。当递归遍历AST节点时,需要将中断转换为正确的标签。这非常有用,但我已经做了很多。我在一篇文章中偶然发现了“backpatching”这个术语,但不幸的是,它没有深入到太多细节。我在我的问题中又加了一点,以澄清我在寻找什么。太好了,这很有意义。任何
    break
    continue
    语句当然只适用于当前的封闭循环构造。我只需要递归地传递一些状态结构。谢谢你的帮助。
    codegen for while:
        save previous break backpatch list
        initialise break backpatch list as empty
        perform codegen for evaluating condition
        perform codegen for body statements
        apply backpatches
        restore previous break backpatch list