[英]How does backpatching work with markers?
一次性代码生成在为条件生成代码时存在一个小问题。 典型的if
语句:
if CONDITION then ALTERNATIVE_1 else ALTERNATIVE_2
需要编译成这样的东西:
compute CONDITION
JUMP_IF_TRUE label1
JUMP_IF_FALSE label2
label1:
code for ALTERNATIVE_1
JUMP label3
label2:
code for ALTERNATIVE_2
JUMP label3
label3:
next statement
但是当生成CONDITION
的代码时,不知道label1
和label2
在哪里,并且当生成ALTERNATIVE_1
和ALTERNATIVE_2
的代码时,不知道label3
在哪里。
一种方法是使用符号名称作为标签,如上面的伪代码,并在知道它们时填写实际值。 这需要在跳转语句中存储符号名称,这会使数据结构复杂化(特别是,您不能只使用二进制汇编程序代码)。 它还需要第二次传球,只是为了填补跳跃目标。
一种(可能)更简单的方法是只记住跳转语句的地址,并在知道目标地址时进行补丁。 这称为“回调”,因为您返回并修补生成的代码。
事实证明,在许多情况下,您最终会有多个分支到同一个标签。 典型案例是“短路”布尔值,如C系列的&&
和||
运营商。 例如,扩展原始示例:
if (CONDITION_1 and CONDITION_2) or CONDITION_3 then ALTERNATIVE_1 else ALTERNATIVE_2
compute CONDITION_1
JUMP_IF_TRUE label1
JUMP_IF_FALSE label2
label1:
compute CONDITION_2
JUMP_IF_TRUE label3
JUMP_IF_FALSE label2
label2:
compute CONDITION_3
JUMP_IF_TRUE label3
JUMP_IF_FALSE label4
label3:
code for ALTERNATIVE_1
JUMP label5
label4:
code for ALTERNATIVE_2
JUMP label5
label5:
next statement
事实证明,对于简单语言,只需要记住两个不完整的跳转语句(通常称为“true”和“false”)。 因为可能有多次跳转到同一目标,所以这些跳转实际上是不完整跳转语句的链接列表,其中目标地址用于指向列表中的下一个跳转。 因此,backpatching遍历列表,修补正确的目标并使用原始目标查找需要修补的上一个语句。
你所谓的标记 (它是yacc / bison所称的“中规则制作”的实例)并不与回调真正相关。 它们可用于多种用途。 在一次性代码生成中,通常需要在规则中间执行某些操作,而回调只是一个示例。
例如,在假设的if
语句中,有必要在解析CONDITION
之前初始化backpatch列表,然后在THEN
和ELSE
子句的开头进行backpatch。 (另一个backpatch将在整个if
语句的解析结束时触发,但那个将在规则的finnal操作中。)
在规则中间执行操作的最简单方法是插入中间规则操作,这相当于使用操作插入空的“标记”生成,如您指向的示例bison文件中所示。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.