编译原理
  • 编译原理
  • 一些简答题
  • 绪论
    • 编译器简介
    • 程序设计语言
    • 静态与动态
    • 参数传递机制
  • 词法分析
    • 词法单元、模式、词素
    • 串和语言
    • 正则表达式
    • 状态转换图
    • 不确定有穷自动机NFA
    • 确定有穷自动机DFA
    • 算法:正则表达式转NFA
    • 自动机到词法分析器
  • 语法分析
    • 语法分析器
    • 上下文无关文法
    • 二义性和左递归
    • 递归下降语法分析
    • 算法:求解FIRST集和FOLLOW集
    • 算法:LL(1)
    • 自底向上语法分析
    • 移入-归约语法分析
    • 算法:LR(0)
    • 算法:SLR(1)
    • 算法:LR(1)
    • 算法:LALR
    • LR分析器和LALR分析器
  • 语法制导
    • 语法制导定义(SDD)
    • 综合属性和继承属性
    • 语法树上的SDD求值
    • 依赖图
    • L属性的SDD
    • 类型
    • SDD的应用
  • 中间代码生成
    • 三地址代码
    • SSA(静态单赋值)
    • 类型和声明
    • 表达式的翻译
    • 类型检查
    • 控制流
    • 回填
  • 运行时刻环境
    • 存储组织
    • 栈式分配
    • 栈中非局部数据的访问
    • 堆管理
    • 垃圾回收
  • 代码生成
    • 代码生成器的设计
    • 目标语言
    • 目标代码中的地址
    • 基本块和流图
    • 基本块的优化
Powered by GitBook
On this page
  • 指令的标号和索引
  • 基于标号的翻译
  • 回填
  • 回填和非回填的比较
  • break、continue的处理
  1. 中间代码生成

回填

Previous控制流Next存储组织

Last updated 4 months ago

指令的标号和索引

  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中

布尔表达式的回填例子