回补如何与标记一起使用?

时间:2014-01-22 07:28:17

标签: language-agnostic bison intermediate-language compiler-construction

我在互联网上搜索过,无法找到关于回调如何运作的正确解释?

你能解释一下回调是如何运作的吗?如何使用标记

我知道它有两种主要类型的标记:

  1. 其中包含next-quad
  2. 包含下一个列表
  3. 我找到了this code,他们在其中输入了一个输入文件并使用RISKI语言创建了一个文件。

    在他们的第一次掷骰中,他们有:

    PROGRAM : N FUNCTION M MAIN_FUNCTION
    

    你可以看到N和M是标记(它们是空卷)。

1 个答案:

答案 0 :(得分:8)

一次性代码生成在为条件生成代码时遇到一个小问题。典型的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的代码时,不知道label1label2的位置,以及ALTERNATIVE_1和{{1}的代码正在生成,不知道ALTERNATIVE_2在哪里。

执行此操作的一种方法是为标签使用符号名称,如上面的伪代码,并在知道它们时填写实际值。这需要在跳转语句中存储符号名称,这会使数据结构复杂化(特别是,您不能只使用二进制汇编程序代码)。它还需要第二次传球,只是为了填补跳跃目标。

一种(可能)更简单的方法是只记住跳转语句的地址,并在知道目标地址时进行补丁。这称为“回调”,因为您返回并修补生成的代码。

事实证明,在许多情况下,您最终会有多个分支到同一个标签。典型的情况是“短路”布尔值,如C系列的label3&&运算符。例如,扩展原始示例:

||

事实证明,对于简单语言,只需要记住两个不完整的跳转语句(通常称为“true”和“false”)。因为可能有多次跳转到同一目标,所以这些跳转实际上是不完整跳转语句的链接列表,其中目标地址用于指向列表中的下一个跳转。所以backpatching遍历列表,修补正确的目标并使用原始目标找到需要修补的上一个语句。

你称之为标记(这是yacc / bison所称的“中规则制作”的实例)与回调并不真正相关。它们可用于多种用途。在一次性代码生成中,通常需要在规则中间执行某些操作,而回调只是一个示例。

例如,在假设的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 语句中,有必要在解析if之前初始化backpatch列表,然后在CONDITION和{{的开头处进行backpatch 1}}条款。 (另一个backpatch将在整个THEN语句的解析结束时触发,但那个将在规则的finnal操作中。)

在规则中间执行操作的最简单方法是插入中间规则操作,这相当于在操作中插入空的“标记”生成,如您指向的示例bison文件中所示。 / p>