Language agnostic 如何使用标记进行背面修补?

Language agnostic 如何使用标记进行背面修补?,language-agnostic,bison,intermediate-language,compiler-construction,Language Agnostic,Bison,Intermediate Language,Compiler Construction,我在互联网上到处搜索,找不到关于回补工作原理的正确解释 你能给我解释一下背面补丁是如何工作的吗?它如何与标记一起工作 我知道它有两种主要的标记类型: 还有下一个四元组 还有下一张名单 我发现,他们正在获取一个输入文件,并用RISKI语言创建一个文件 在第一卷中,他们有: PROGRAM : N FUNCTION M MAIN_FUNCTION 您可以看到N和M是标记(它们是空卷)。一次代码生成在为条件生成代码时有一个小问题。典型的if语句: if CONDITION then ALTERNAT

我在互联网上到处搜索,找不到关于回补工作原理的正确解释

你能给我解释一下背面补丁是如何工作的吗?它如何与标记一起工作

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

  • 还有下一个四元组
  • 还有下一张名单
  • 我发现,他们正在获取一个输入文件,并用RISKI语言创建一个文件

    在第一卷中,他们有:

    PROGRAM : N FUNCTION M MAIN_FUNCTION
    

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

    一次代码生成在为条件生成代码时有一个小问题。典型的
    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
    
    但是,当生成
    条件
    的代码时,不知道
    label1
    label2
    在哪里,并且当生成
    备选方案1
    备选方案2
    的代码时,不知道
    label3
    在哪里

    实现这一点的一种方法是为标签使用符号名,如上面的伪代码所示,并在实际值已知时填充它们。这需要在jump语句中存储一个符号名,这会使数据结构复杂化(特别是,不能只使用二进制汇编代码)。它还需要第二次通过,只是为了填充跳跃目标

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

    事实证明,在许多情况下,最终会有多个分支指向同一个标签。一个典型的例子是“短路”布尔运算,比如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
    语句中,有必要在解析
    条件
    之前初始化回补列表,然后在
    然后
    ELSE
    子句的开头回补。(另一个backpatch将在整个
    if
    语句的解析结束时触发,但该backpatch将出现在规则的finnal操作中。)


    在规则的中间执行操作的最简单的方法是插入中间规则动作,这相当于插入一个空的“标记”产生的动作,如您所指向的示例BISEN文件。

    您是指“回溯”吗?