编译原理--04 符号表、运行时存储组织和代码优化复习

前言

目录
01 文法和语言、词法分析复习
02 自顶向下、自底向上的LR分析复习
03 语法制导翻译和中间代码生成复习
04 符号表、运行时存储组织和代码优化复习

第8章 静态语义分析和中间代码生成(续)

符号表

符号表需要在编译期间用到,记录符号的具体信息。本部分只讨论PL/0符号表的建立。

PL/0符号表结构

PL/0的符号表包含5个信息:

  1. NAME符号名
  2. KIND符号类型
  3. LEVEL/VAL层次/值。如果类型为CONSTANT,存放的是常量的值;如果类型为VARIABLEPROCEDURE,存放所属分程序的层次,主程序的层次为0;在主程序中定义的内容层次为1;主程序内第一层分程序中定义的内容层次为2,以此类推。
  4. ADR地址。如果为简单变量或常量,则记录的是该量在数据区所占单元的相对地址,用DX表示给本层局部变量分配的相对存储位置,每说明一个变量后DX加1;如果为过程,则存放该过程的分程序入口地址(需要返填
  5. 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. 删除多余运算
  2. 循环不变代码外提
  3. 强度削弱
  4. 变换循环控制条件
  5. 合并已知量
  6. 复写传播与删除无用赋值

删除多余运算

\((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)\)

猜你喜欢

转载自www.cnblogs.com/X-Jun/p/11042544.html