【编译原理笔记12】中间代码生成:简单赋值语句的翻译,数组引用的翻译

本次笔记内容:
6-3 简单赋值语句的翻译
6-4 数组引用的翻译

本节课幻灯片,见于我的 GitHub 仓库:第12讲 中间代码生成_2.pdf

简单赋值语句的翻译

赋值语句翻译的任务

【编译原理笔记12】中间代码生成:简单赋值语句的翻译,数组引用的翻译
赋值语句翻译的主要任务:

  • 生成对表达式求值的三地址码

赋值语句的SDT

【编译原理笔记12】中间代码生成:简单赋值语句的翻译,数组引用的翻译
动作中有三个函数:

  • lookup(name):查询符号表,返回 name 对应的记录;
  • gen(code):生成三地址指令 code ;
  • newtemp():生成一个新的临时变量 t ,返回t的地址

可以看出,表达式的 code 属性要复制子表达式的 code 属性,以此递推…这样,code 属性就可能是一个比较长的字符串。这样在复制和移动的过程中就需要较长的时间。因此使用增量的方式进行翻译

增量翻译 Incremental Translation

在增量翻译中,不需要设置 code 属性,而是在已经生成的三地址码后面追加三地址指令。下图中,就可以把 code 属性对应的行删掉。
【编译原理笔记12】中间代码生成:简单赋值语句的翻译,数组引用的翻译
在增量方法中,gen( )不仅要构造出一个新的三地址指令,还要将它添加到至今为止已生成的指令序列之后

【编译原理笔记12】中间代码生成:简单赋值语句的翻译,数组引用的翻译
【编译原理笔记12】中间代码生成:简单赋值语句的翻译,数组引用的翻译
【编译原理笔记12】中间代码生成:简单赋值语句的翻译,数组引用的翻译
【编译原理笔记12】中间代码生成:简单赋值语句的翻译,数组引用的翻译
【编译原理笔记12】中间代码生成:简单赋值语句的翻译,数组引用的翻译
【编译原理笔记12】中间代码生成:简单赋值语句的翻译,数组引用的翻译
上图中,根据③的语义动作,生成一个临时变量用于记录表达式的地址,假设变量名为t2t_2;之后调用了栈函数,生成一条三地址指令:
t2=t1ct_2 = t_1 * c
【编译原理笔记12】中间代码生成:简单赋值语句的翻译,数组引用的翻译
注意这里我们用名字表示地址。
【编译原理笔记12】中间代码生成:简单赋值语句的翻译,数组引用的翻译

数组引用的翻译

赋值语句的基本文法:

  • Sid=E;L=E;S \to id=E;|L=E;
  • EE1+E2E1(E1)idLE \to E_1 + E_2 | -E_1 | (E_1)|\text{id}|L
  • Lid[E]L1[E]L\to \text{id}[E]|L_1 [E]

数组引用翻译成三地址码时要解决的主要问题是确定数组元素的存放地址,也就是数组元素的寻址。

数组元素寻址 Addressing Array Elements

一维数组

假设每个数组元素的宽度是ww,则数组元素a[i]a[i]的相对地址是:
base+i×wbase+i\times w
其中,basebase是数组的基地址,i×wi\times w是偏移地址。

二维数组

假设一行的宽度是w1w_1,同一行中每个数组元素的宽度是w2w_2,则数组元素a[i1][i2]a[i_1] [i_2]的相对地址是:
base+i1×w1+i2×w2base+i_1 \times w_1+i_2\times w_2

k维数组

数组元素a[i1][i2][ik]a[i_1] [i_2] …[i_k]的相对地址是:
base+i1×w1+i2×w2++ik×wkbase+i_1\times w_1+i_2\times w_2+…+i_k\times w_k
其中:

  • w1a[i1]w_1 \to a[i_1] 的宽度
  • w2a[i1][i2]w_2 \to a[i_1] [i_2] 的宽度
  • wka[i1][i2][ik]w_k \to a[i_1] [i_2] …[i_k] 的宽度

【编译原理笔记12】中间代码生成:简单赋值语句的翻译,数组引用的翻译

带有数组引用的赋值语句的翻译

例1
【编译原理笔记12】中间代码生成:简单赋值语句的翻译,数组引用的翻译
这里,用数组的名字 a 表示其基地址。

例2
【编译原理笔记12】中间代码生成:简单赋值语句的翻译,数组引用的翻译

数组引用的SDT

【编译原理笔记12】中间代码生成:简单赋值语句的翻译,数组引用的翻译
在数组引用的翻译方案的设计过程中,关键的问题在于如何将地址计算公式数组引用的文法关联起来。
【编译原理笔记12】中间代码生成:简单赋值语句的翻译,数组引用的翻译
还通过这个例子来理解 SDT 。