Home L属性定义
L属性定义
取消

L属性定义

一、L属性的自上而下计算

1、边分析边计算

    由于属性的计算次序受分析方法所限定的分析树节点建立次序(自左向右的)的限制,所以,只有当属性是自左向右流动时才能边分析边计算

2、L属性定义

   (1) A—>X1X2...Xn

    每条规则计算的属性是A的综合属性或者Xj的继承属性

    而且Xj的继承属性只依赖于节点和左兄弟节点

    (2)S属性定义属于L属性定义

    (3)非L属性定义:1.父节点依赖于子节点,2.某节点依赖于右兄弟节点

3、翻译方案

    (1)区别于L属性和S属性的就是执行的时机

            因为S属性是将产生式作为一个整体来看

            而L属性定义与属性嵌入的位置有关

    (2)定义:给出了使用语义规则进行计算的次序,体现实现细节

    (3)表示:使用{ } 

 

语法树

    (4)启发方式

            a、产生式右边的符号的继承属性必须先于这个符号的动作

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

            c、产生式左边非终结符的综合属性放在右边的末尾

            这两条在写翻译方案的时候经常要注意到

    (5)消除左递归

            自上而下分析需要消除左递归,引起了继承属性

            

 

 4、设计递归下降翻译器

    每个继承属性:设置一个形参

    每个综合属性:获取一个函数的返回值

    每个属性都有一个局部变量

 

 5、使用综合属性代替继承属性(改写文法)

 

 这个方法的重点是,要所有的符号定义完了才表示出类型


 二、L属性的自下而上计算

1、区别于自上而下计算

S属性的自上而下计算局限于LL(1)文法

L属性的自下而上计算基于任何LL(1)文法和许多LR(1)文法


两种特殊情况:

2、删除翻译方案中嵌入的动作

可以使用M—>ε解决问题

比如

修改为

 3、分析栈上的继承属性

即:所依赖的属性在分析栈上的位置能静态确定(知道其相对位置)

对于不能确定的属性也可以通过修改文法来确定


4、模拟继承属性的计算

当规则不是简单的复写规则(如函数)时

方法:增加一个非终结符,将函数的计算移到该非终结符归约时进行

从而保证:每次使用继承属性时,刚好都在文法符号的正下方

原文法:

            S——>aAC    C.i = f(A.s)        (这里C.i不等于复写规则)

            C——>c        C.c = g(C.i)

改写为:

            S——>aANC     C.i = N.s, N.i = A.s

            N——>ε            N.s = f(N.i)

            C——>c            C.c = g(C.i)

5、引进非终结符对基础文法的影响

1、基础文法是LL(1)文法

    无影响:标记非终结符是唯一的,而且只有唯一一个的ε产生式

                  任何LL(1)文法一定是LR(1)的所以不会引起冲突

2、基础文法是LR(1)文法

    可能使修改后的文法变成非LR(1)文法

eg.    L—>Lb|a

修改为:L—>MLb|a

              M—>ε

本来这个文法产生 abbbb...串

修改后,空归约和b的个数一样,在面临a后,后面有多少个b是不知道的

因此会产生移进-归约冲突

假设栈中有a,b此时不能判断是移进还是归约

在a进入栈之前,栈中是否应该已经有一个M?(造成了冲突)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

    

该博客文章由作者通过 CC BY 4.0进行授权。