前言
目录 |
---|
01 文法和语言、词法分析复习 |
02 自顶向下、自底向上的LR分析复习 |
03 语法制导翻译和中间代码生成复习 |
04 符号表、运行时存储组织和代码优化复习 |
第8章 静态语义分析和中间代码生成(续)
符号表
符号表需要在编译期间用到,记录符号的具体信息。本部分只讨论PL/0符号表的建立。
PL/0符号表结构
PL/0的符号表包含5个信息:
- NAME,符号名
- KIND,符号类型
- LEVEL/VAL,层次/值。如果类型为CONSTANT,存放的是常量的值;如果类型为VARIABLE或PROCEDURE,存放所属分程序的层次,主程序的层次为0;在主程序中定义的内容层次为1;主程序内第一层分程序中定义的内容层次为2,以此类推。
- ADR,地址。如果为简单变量或常量,则记录的是该量在数据区所占单元的相对地址,用DX表示给本层局部变量分配的相对存储位置,每说明一个变量后DX加1;如果为过程,则存放该过程的分程序入口地址(需要返填)
- SIZE,大小。该过程局部变量的个数(需要返填)
例如下面的程序:
const a = 35, b = 49;
var c, d, e;
procedure p;
var g;
对应的符号表为:
NAME | KIND | VAL/LEVEL | ADD | SIZE |
---|---|---|---|---|
a | CONSTANT | 35 | ||
b | CONSTANT | 49 | ||
c | VARIABLE | LEV | DX | |
d | VARIABLE | LEV | DX+1 | |
e | VARIABLE | LEV | DX+2 | |
p | PROCEDURE | LEV | 4 | |
g | VARIABLE | LEV+1 | DX |
又例如下面的程序:
const a = 25;
var x, y;
procedure p;
var z;
begin
...
end;
procedure r;
var x, s;
procedure t;
var v;
begin
...
end;
begin
...
end;
begin
...
end.
对应的符号表为:
NAME | KIND | VAL/LEVEL | ADD | SIZE |
---|---|---|---|---|
a | CONSTANT | 25 | ||
x | VARIABLE | LEV | DX | |
y | VARIABLE | LEV | DX+1 | |
p | PROCEDURE | LEV | 3 | |
z | VARIABLE | LEV+1 | DX | |
r | PROCEDURE | LEV | 4 | |
x | VARIABLE | LEV+1 | DX | |
s | VARIABLE | LEV+1 | DX+1 | |
t | PROCEDURE | LEV+1 | 3 | |
v | VARIABLE | LEV+2 | DX |
第9章 运行时存储组织(暂跳)
第10章 代码优化
优化技术简介
常用优化技术有:
- 删除多余运算
- 循环不变代码外提
- 强度削弱
- 变换循环控制条件
- 合并已知量
- 复写传播与删除无用赋值
删除多余运算
\((1)T_1:=4*I\)
\((2)T_2:=addr(A)-4\)
\((3)T_3:=T_2[T_1]\)
\((4)T_4:=4*I\)
\((5)T_5:=addr(B)-4\)
\((6)T_6:=T_5[T_4]\)
可以看到\((4)\)式做了和\((1)\)式重复的工作,可以改写成\(T_4:=T_1\)
循环不变代码外提
原代码:
块1
\((1)P:=0\)
\((2)I:=1\)
块2
\((3)T_1:=4*I\)
\((4)T_2:=addr(A)-4\)
\((5)T_3:=T_2[T_1]\)
\((6)P:=P+T_3\)
\((7)I:=I+1\)
\((8)if \;I<=20\;goto\;(3)\)
可以看到\((4)\)式在每次循环都做重复的工作,可以把它提到循环外来,记得修改跳转:
块1
\((1)P:=0\)
\((2)I:=1\)
\((3)T_2:=addr(A)-4\)
块2
\((4)T_1:=4*I\)
\((5)T_3:=T_2[T_1]\)
\((6)P:=P+T_3\)
\((7)I:=I+1\)
\((8)if \;I<=20\;goto\;(4)\)
强度削弱
把强度大的运算换成强度小的运算,比如用加法换乘法:
块1
\((1)P:=0\)
\((2)I:=1\)
\((3)T_2:=addr(A)-4\)
块2
\((4)T_1:=4*I\)
\((5)T_3:=T_2[T_1]\)
\((6)P:=P+T_3\)
\((7)I:=I+1\)
\((8)if \;I<=20\;goto\;(4)\)
把\((4)\)式经过处理,并修改跳转:
块1
\((1)P:=0\)
\((2)I:=1\)
\((3)T_1:=0\)
\((4)T_2:=addr(A)-4\)
块2
\((5)T_1:=T_1+4\)
\((6)T_3:=T_2[T_1]\)
\((7)P:=P+T_3\)
\((8)I:=I+1\)
\((9)if \;I<=20\;goto\;(5)\)
变换循环控制条件
下面的代码中,\(I\)和\(T_1\)保持4倍的线性关系:
块1
\((1)I:=1\)
\((2)T_1:=4*I\)
块2
\((3)P:=T_2[T_1]\)
\((4)I:=I+1\)
\((5)T_1=T_1+4\)
\((6)if\;I<=20\;goto\;(3)\)
可以把循环条件\(I<=20\)改为\(T_1<=80\),然后修改\(T_1\)的初始赋值,这样\(I\)在整个循环都没有被用上,可以剔除:
块1
\((1)T_1:=4\)
块2
\((2)P:=T_2[T_1]\)
\((3)T_1=T_1+4\)
\((4)if\;T_1<=80\;goto\;(2)\)
合并已知量
下面的代码中,在计算\(4*I\)时,\(I\)必定为1:
\((1)I:=1\)
\((2)T_1:=4*I\)
因此可以直接在编译期间算出它的值是4:
\((1)I:=1\)
\((2)T_1:=4\)
复写传播和删除无用赋值
看下面的代码:
块1
\((1)T_1:=4\)
\((2)I:=1\)
块2
\((3)T_2:=T_1\)
\(...\)
\((7)T_3:=T_4[T_2]\)
\((8)T_1:=T_1+T_3\)
\((9)I:=I+1\)
\((10)if\;T_1<=80\;goto\;(3)\)
四元式\((3)\)把\(T_1\)的值写入\(T_2\)中,但\(T_2\)和\(T_1\)的值在\((3)\)到\((7)\)之间没有发生改变,故将\((7)\)改为\(T_3:=T_4[T_1]\)
此时\((3)\)式没有被引用,属于无用赋值,可以删掉。
然后,\((2)\),\((9)\)对\(I\)赋值,但也只是自我引用,其余地方没有需要用到\(I\),属于无用赋值,故可以删掉。
最终变为:
块1
\((1)T_1:=4\)
块2
\(...\)
\((5)T_3:=T_4[T_1]\)
\((6)T_1:=T_1+T_3\)
\((7)if\;T_1<=80\;goto\;(2)\)