程序设计语言——编译原理 第六、七章总结

程序设计语言——编译原理 第六、七章总结

知识点

CHP6

语义分析是在上下文无关文法的基础上,进行扩充,为每个文法符号赋值,形成属性文法。      

1.属性文法

①为文法符号E引进属性符号val,用E.val表示E的值

②属性计算规则以赋值语句的形式给出,附在每个产生式后,用花括号括出

③为表明同一符号不同的出现位置,用上角标区分

④终结符的值由词法分析程序提供

2.属性&分类

属性代表与文法符号相关信息(例如其类型,值,代码序列……)

属性分为综合属性与继承属性

综合属性

①用于“自下而上”传递信息

②在语法树中,一个结点的综合属性的值,由其子结点的属性值确定

继承属性

①用于“自上而下”传递信息。

②在语法树中,一个结点的继承属性由此结点的父结点和/或兄弟结点的某些属性确定

3.语义规则

属性计算的过程即是语义处理的过程

对于文法的每一个产生式配备一组属性的计算规则,则称为语义规则

在一个属性文法中,对应于每个产生式A都有一套与之相关联的语义规则,每条语义规则的形式为:

b:=f(c1,c2,…,ck)  

这里f是一个函数,而且或者

(1)b是A的一个综合属性并且c1,c2,…ck是产生式右边文法符号的属性;或者

(2)b是产生式右边某个文法符号的一个继承属性并且c1,c2,…ck是A或产生式右边任何文法符号的属性在这两种情况下,我们都说属性b依赖于属性c1,c2,…,ck.

①终结符只有综合属性,它由词法分析器提供

②非终结符既可以有综合属性也可以有继承属性,文法开始符号的所有继承属性作为属性计算前的初始值

③ 产生式右边符号的继承属性和产生式左边符号的综合属性都必须提供一个计算规则

④产生式左边符号的继承属性和产生式右边符号的综合属性不由所给的产生式的属性计算规则进行计算,它们由其它产生式的属性规则计算

4.  语法制导翻译法:这种由源程序的语法结构所驱动的处理办法就是语法制导翻译法

5.依赖图

在一颗语法树中的结点的继承属性和综合属性之间的相互依赖关系可以用称作依赖图的一个有向图来描述

如果在一棵语法树中一个结点的属性b依赖于属性c,那么这个结点处计算b的属性规则必须在确定c的语义规则之后使用

在为一棵语法树构造依赖图以前,我们为每一个包含过程调用的语义规则引入一个虚综合属性b,这样把每一个语义规则都写成

b:= f(c1,c2, …ck)依赖图中为每一个属性设置一个结点,如果属性b依赖属性c,则从属性c的结点有一条有向边连到属性b的结点

6.依赖图的构造算法

for分析树中每一个结点n

          for 结点的文法符号的每一个属性a

                    为a在依赖图中建立一个结点;


for分析树中每一个结点n

                  for结点n所用产生式对应的每一个语义规则

b:=f(c1,c2,…ck)

                                 for i :=1 to k

从ci结点到b结点构造一条有向边

7.如果一属性文法不存在属性之间的循环依赖关系,那么该文法为良定义的。为了设计编译程序,我们只处理良定义的属性文法

8.属性的计算次序

 一个有向非循环图的拓扑序是图中结点的任何顺序m1,m2, …mk,使得边必须是从序列中前面的结点指向后面的结点。也就是

说,如果mi→mj是mi到mj的一条边,那么在序列中mi必须出现在mj之前

一个依赖图的任何拓扑排序都给出一个语法树中结点的语义规则计算的有效顺序。这就是说,在拓扑排序中,在一个结点上,语

义规则b:=f(c1,c2,…ck)中的属性c1,c2…ck在计算b以前都是可用的

9. S属性的自下而上计算

S—属性文法,它只含有综合属性

综合属性可以在分析符号串的同时由自上而下的分析器来构造

分析器可以保存与栈中文法符号有关的综合属性值

每当进行归约时,新的属性值就由栈中正在归约的产生式右边符号的属性值来计算

可以通过扩充分析器中的栈来存放这些综合属性值

S-属性文法的翻译器通常可借助于LR分析器实现

10.L-属性文法的自顶向下翻译     

L-属性文法

如果每个产生式A →X1 X2 … Xn 的每条语义规则计算的属性是A的综合属性;或者是Xj 的继承属性, 1 ≦j ≦ n, 但它仅依赖:该

产生式中Xj左边符号X1, X2, …, Xj-1的属性;A的继承属性

11. 翻译模式

翻译模式是语法制导定义的一种便于翻译的书写形式。其中属性与文法符号相对应,语义规则或语义动作用花括号{ }括起来,

可被插入到产生式右部的任何合适的位置上

这是一种语法分析和语义动作交错的表示法,他表达在按深度优先遍历分析树的过程中何时执行语义动作

翻译模式给出了使用语义规则进行计算的顺序。可看成是分析过程中翻译的注释

12.设计翻译模式(根据语法制导定义)

条件:语法制导定义是L-属性定义

保证语义动作不会引用还没有计算的属性值

(1)只需要综合属性的情况

为每一个语义规则建立一个包含赋值的动作,并把这个动作放在相应的产生式右边的末尾

(2)既有综合属性又有继承属性     

①产生式右边的符号的继承属性必须在这个符号以前的动作中计算出来

②一个动作不能引用这个动作右边符号的综合属性

③产生式左边非终结符号的综合属性只有在它所引用的所有属性都计算出来以后才能计算。计算这种属性的动作通常可放在产生

式右端的未尾

CHP7

1.语义分析&中间语言

语义分析的任务:审查每一个语法结构的静态语义,即验证语法正确的结构是否有意义;在语义正确的基础上生成一种中间代码

或目标代码

语义分析的范围

1.确定类型:确定标识符所关联的数据类型

2.类型检查:按语言的类型规则,检查运算的合法性与运算分量类型的一致性,必要时作类型转换

3.识别含义:根据语言的语义定义(形式或非形式),识别程序中各构造成分组合到一起的含义,并作相应的语义处理(生成中

间代码或目标代码)

4.控制流检查:控制流语句必须转移到合法的地方。如C中,break语句规定跳出最内层的循环或switch语句

5.一致性检查:在很多场合要求对象只能被说明一次。如:pascal语言规定同一个标识符在一个分程序中只能被说明一次等

6.相关名字检查:如:Ada,循环或块可以有一个名字,它出现在这些结构的开头或结尾。编译程序必须检查这两个地方用的名

字是否相同

其它:如名字的作用域分析等也是语义分析的工作

中间语言

其任务把经过语法分析和语义分析而获得的源程序中间表示翻译为中间代码表示

分为语法树,后缀式,三地址代码表示

2.后缀式(逆波兰表示)转换方法

从左至右逐字读取中缀式:

a.当当前字符为数字时,直接输出

b.当当前字符为"("时,将其压栈

c.当当前字符为")"时,则弹出堆栈中最上的"("之前的所有运算符并输出,然后删除堆栈中的"("

d.当当前字符为运算符时,则依次弹出堆栈中优先级大于等于当前运算符的(到"("之前为止),输出,再将当前运算符压栈

3.图表示法

DAG与抽象语法树

都是一个父结点表示一个操作符,它的孩子表示操作数

两者所不同的是,在一个DAG中代表公共子表达式的结点具有多个父结点,而在一棵抽象语法树中公共子表达式被表示为重复

子树

程序设计语言——编译原理 第六、七章总结_第1张图片

4.三地址码

由三个部分组成:算符:OP,第一运算分量:ARG1,,第二运算分量:ARG2

三地址语句的种类

(1)赋值语句 x:=y op z,op为二目算术算符或逻辑算符

(2)赋值语句 x:=op y ,op为一目算符,如一目减uminus、逻辑非not、移位算符及转换算符

(3)无条件转移语句goto L

(4)条件转移语句 if x relop y goto L,关系运算符号relop(< ,=,>= 等等)

(5)复制语句  x:=y

(6)过程调用语句 param x 和 call p, n,过程返回语句 return y

(7)索引赋值 x:=y[i] 及 x[i] :=y

(8)地址和指针赋值 x=&y,x=* y 和  * x=y

三地址代码的具体实现

①三元式 op, arg1, arg2

②间接三元式  间接码表+三元式表

③四元式  op, arg1, arg2,result

5.三元式

由操作符op,两个运算对象arg1,arg2组成。表示为(op,arg1,arg2)

程序设计语言——编译原理 第六、七章总结_第2张图片

6.间接三元式

在三元式的基础上附加一张指示器表─间接码表,按运算的先后顺序列出有关三元式在三元式表中的位置。这种表示方法称为间

接三元式

程序设计语言——编译原理 第六、七章总结_第3张图片

7.四元式

一个四元式是一个带有四个域的记录结构:op,arg1,arg2及result。它实际上就是一条三地址的指令,表示为(op,arg1,arg2,result)

程序设计语言——编译原理 第六、七章总结_第4张图片

8.树、后缀式与三元式关系:后缀式实际上是抽象语法树的线性表示形式(后序表示);树是三元式的翻版,每个三元式对应一

棵(二叉)子树,最后的三元式对应树根

9.常用语句的翻译

分为说明语句的翻译,赋值语句的翻译,布尔表达式的翻译,控制语句的翻译,数组的的翻译

10.说明语句的翻译

对每个局部名字,在符号表中建立相应的表项,填写有关的信息,如类型、嵌套深度、相对地址,内情向量等

11.赋值语句的翻译

表达式的成分可以是整型量、实型量、数组 元素和记录。其语义规则描述

①E有两个属性,E.place存放E的名字,id.name存放id所代表的名字本身

②函数newtemp:每次调用它时,返回一个不同临时变量

③过程lookup(id.name)检查是否在符号表中存在此名字的入口,如有,则返回一个指向该表项的指针,否则,返回nil表示未找到

④过程emit将生成的三地址语句发送到输出文件中

程序设计语言——编译原理 第六、七章总结_第5张图片

12.布尔表达式的翻译

对布尔表达式有两种方法

①由表达式各部分计算出整个表达式的值

②采取某种优化措施,只计算部分表达式

A∨B  可理解为 if A then true else B

A∧B  可理解为 if A then B else false

┐A   可理解为 if A then false else true


可以把作为控制条件的任何布尔表达式表示成仅含下列三种形式的四元式的序列:

(jnz,a,--,p)  表示 if  a goto  p

(jrop,x,y,p)  表示 if  x rop y  goto p

(j,--,--,p)   表示 goto  p

在一遍扫描中,生成跳转语句时,不知道控制要转向的语句标号。解决方法:生成跳转语句时,将其E.true和E.false链成一个链

表,记录在E.truelist和E.falselist中等到转移目标确定以后,再将转移出口填入E.truelist和E.falselist中

13.数组的的翻译

数组元素的地址计算公式

若数组A的元素存放在一片连续单元里,则可以较容易的访问数组的每个元素。假定数组的每个元素的宽度为w,则一维数组A[i] 

这个元素的起始地址为:base + (i – low)*w           low为数组下标的下界, base是分配给数组的相对地址,即base为A的第一

个元素A[low]的相对地址

若二维数组A按行存放,则可用如下公式计算A[i1,i2]的相对地址: base + (( i1 – l1)*d2 + i2 – l2) *w。其中,l1、l2分别为i1、

i2的下界;di界差。若ui为i的上界,则di=ui – li +1

假定i1,i2是编译时唯一尚未知道的值,我们可以重写上述表达式为:( base –( (l1 *d2) + l2) *w)+ ( (i1*d2) + i2) *w

其中:前一项子表达式( base – ((l1 *d2) + l2) *w )的值是可以在编译时确定的记为常数CONSPART。后一子项随i1, i2 而改变

是一个变数记VARPART

总结

在学习中感觉第六章比较难以理解,前面还可以到了后面就有困难,第七章比较好理解,在做题中就可以理解并掌握,第六章因为考试不考,也就没复习。




你可能感兴趣的:(程序设计语言——编译原理)