回填

指令的标号和索引

  1. 先生成基于标号的三地址代码

  2. 再遍历三地址码将标号替换为对应索引

基于标号的翻译

继承属性,自顶向下。生成新标号时并向下(右)传递,生成跳转语句时填入。经过(生成)跳转目标时插入生成代码中

如上图,在B.true时就生成即将跳转的新标号,并填入到goto语句中;当经过预期跳转的目标时将标号插入。

新思路:

综合属性,自底向上。经过(生成)跳转目标时,记录其索引。将跳转目标索引填入到相应跳转语句中。

回填

为布尔表达式和控制流语句生成目标代码,关键问题:某些跳转指令应该跳转到哪里?

基本思想:

  • 翻译过程中,若遇到跳转目标未知的情况,则先生成跳转指令坯,备用goto __/if ... goto __

  • 将指令坯并向父节点传递(综合属性)

  • 翻译过程中,若遇到某条指令是跳转目标,则记录其索引,备用

  • 当父节点收集齐跳转指令坯及其跳转目标时,将索引填入指令坯

同一列表中跳转指令的目标都相同。

辅助函数:backpatch(p,i) :将i作为跳转目标插入p的所有指令中。扫描到B.truelist中的跳转目标的索引,则调用该函数将这个索引插入B.truelist的所有指令中。

所以,在文法中需要引入非终结符号(SDT)

  • M:在适当的时候获取将要生成指令的索引,用M.instr记录跳转目标指令的索引

  • N:在适当的位置生成跳转指令坯,生成goto指令坯,N.nextlist包含该指令索引

回填和非回填的比较

生成指令坯,然后加入相应的list。原来跳转到B.true的指令,现在加入到B.truelist中;原来跳转到B.false的指令,现在加入到B.falselist中。true/false属性的赋值,在回填方案中对应为相应的truelist/falselist的赋值或者merge。

辅助函数:

  • makelist(i) :创建一个包含跳转指令(其索引为i)的列表

  • merge(p1,p2) :将p1和p2指向的索引列表合并然后返回

布尔表达式的回填例子

break、continue的处理

虽然break、continue在语法上是一个独立的句子,但是它的代码和外围语句相关

方法:(break语句)

  • 跟踪外围循环语句S

  • 生成一个跳转指令坯

  • 将这个指令坯的索引加入到S的nextlist中

Last updated