假设我正在实现一个字节码编译器,类似于Lua的/ Python ......等等。
我正在遍历AST,生成字节码指令,并且在break
循环内的if-else
内部遇到while
:
while (cond1)
if (cond2)
...
else
break
(我尝试写出等效的字节码,但它看起来并没有太大帮助。)
关键是,该示例中至少有4个“跳转”指令,而我
想要找到一个优雅的解决方案来填充跳转地址,因为我编译AST ...
在我完全完成之前,我不知道while
循环或break
的跳转地址
“汇编”了内部陈述。
我还没读这本龙书。
如果我以递归方式编译AST,当我在一些任意数量的循环和break
块内到达if-else
语句时,编译器应该如何知道要跳转到哪个空标签?我猜测递归AST行走函数外部的某种类型的标签名称堆栈。
答案 0 :(得分:6)
您需要的原则称为“反向修补”:为正向跳转填充虚拟值,为语句正文生成代码,然后返回并将虚拟值替换为末尾的虚拟值。
e.g。
# start of codegen for 'while'
L1:
[evaluate cond1]
jne L2 # forward reference: use a dummy value for now
# start of codegen for 'if ... else'
L3:
[evaluate cond2]
jne L4 # another forward reference: use a dummy value for now
[code in 'if' branch]
j L5 # another forward reference: use a dummy value for now
L4:
[code in 'else' branch before 'break']
j L2
[code in 'else' branch after 'break']
L5: # end of 'if ... else'
# now go back and fill in references to L4, L5 inside the 'if ... else' block
# end of codegen for 'if ... else'
# codegen for 'while' continues...
j L1 # loop
L2: # end of 'while' loop
# now go back and fill in references to L2 inside the 'while' block
# end of codegen for 'while'
关于你的编辑:
如果我以递归方式编译AST,当我在一些任意数量的循环和
break
块内到达if-else
语句时,编译器应该如何知道要跳转到哪个空标签?我猜测递归AST行走函数外部的某种类型的标签名称堆栈。
实现break
语句的跳转目标是最内层封闭循环的结束;是的,您可以使用显式外部堆栈跟踪它。
但是,如果你有一个递归的AST walk函数,你已经有了一个隐式堆栈 - 递归函数调用的调用框架 - 所以你可能也不需要一个明确的调用框架。
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的递归遍历中。在这个递归调用中,你只需要关心内部循环,而不是外部循环。
所以,你需要做的就是:
while
break
while
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需要附加到它)。但是保存的列表可以作为while
codegen函数的局部变量进行跟踪。