属性文法
属性文法
以上下文无关文法为基础。
为每个文法符号(终结符或非终结符)配备若干相关的“值”(称为属性)。
对每个文法的每个产生式配备了一组属性的语义规则,对属性进行计算和传递。
.val属性用来存放这些非终结所对应的那部分表达式,如子表达式,项,因子等。
lexval表示,词法分析返回的单词的值。
综合属性
继承属性
属性依赖
语义规则
带注释的语法树
例:
从下到上,从左到右,一步一步。
只有综合属性,所以是一个S-属性文法,把语法树的构造过程和属性计算的过程合成一遍完成。
类型信息通过L的继承信息in,从左到右,传递到了每一个变量标识符上。
先构造好语法树,再一步步计算属性。
基于属性文法的处理过程:
输入串 → 语法树 → 依赖图 → 语义规则的计算次序 → 进行语义规则计算,得到翻译结果
依赖图
定义:
一个表示一棵语法树中结点的继承属性和综合属性之间的相互依赖关系的有向图。
示例:
良定义的属性文法
树遍历的属性计算方法
采用递归。
算法过程
示例
按照算法流程,执行。
一遍扫描的处理方法
在语法分析的同时计算属性值,而不是语法分析
构造语法树之后进行属性的计算,而且无需构造
实际的语法树。
一遍扫描的处理方法,通常与所采用的语法分析方法相关,将属性计算穿插在语法分析过程中进行,语法分析产生语法结构的顺序,决定了属性计算的次序。
L-属性文法—一遍扫描的自上而下分析
(产生式匹配输入串成功时,执行对应的语义规则)
S-属性文法—一遍扫描的自下而上分析
(归约时,执行)
抽象语法树
抽象语法树中,操作符和关键字都不作为叶结点出现。
建立表达式的抽象语法树
例
S-属性文法的自下而上计算
S-属性文法:
只含有综合属性。
在自下而上的分析器输入符号串的同时计算综合属性。
分析栈中保存语法符号和有关的综合属性值。
每当进行归约时,新的语法符号的属性值就由栈中正在归约的产生式右边符号的属性值来计算。
ntop 是 归约后的栈顶
top 是 归约前的栈顶。
E → T没有代码段,是因为归约,E弹出,T压入,不对属性进行操作,T对应的属性就是 E.val。变相实现了E.val = T.val。
S-属性文法分析过程
“ - ” 表示 无效属性
抽象语法树里, ±*等运算符是没有属性的,所以是” - “。
L-属性文法和自顶向下翻译
通过深度优先的方法对语法树进行遍历,计算属性文法的所有属性值
与LL(1):自上而下分析方法结合
深度优先建立语法树
按照语义规则计算属性
L-属性文法
S-属性文法一定是L-属性文法
一个属性文法称为L-属性文法,如果对于每个产生式A→X1X2…Xn,其每个语义规则中的每个属性或者是综合属性,或者是Xj(1≤j≤n)的一个继承属性且这个继承属性仅依赖于:
(1) 产生式Xj的左边符号X1,X2,…,Xj-1的属性;
(2) A的继承属性。
翻译模式
语义规则:
给出了属性计算的定义,没有属性计算的次序等实现细节。
翻译模式:
给出了使用语义规则进行计算的次序,这样就可把某些实现细节表示出来。
在翻译模式中,和文法符号相关的属性和语义规则(这里我们也称语义动作),用花括号{ }括起来,插入到产生式右部的合适位置上
示例:
{} 在 T 扩展之后,R拓展之前执行
设计翻译模式原则
必须保证当某个动作引用一个属性时它必须是有定义的。
L-属性文法本身就可以保证不会引用未被计算出来的属性。
建立翻译模式
前面用到的属性已经计算出来,可以往前放。
但放最后一定可行。
例:
第一个违反了上面的规则1.
翻译模式示例:
从规范到输出,就是翻译。
ps是B的继承属性,ht是B和S的综合属性。
shrink是缩小比例函数
disp是错位放置之后 最高点最低点的位置计算
属性文法改写成翻译模式
语义动作的执行时机统一
语义动作位置不同,执行时机不同,很麻烦。
消除翻译模式中的左递归
一般方法:
例:
利用原翻译模式,自下而上。
利用消除左递归的翻译模式,自上而下。
抽象语法树:
递归下降翻译器的设计
主体框架还是一个LR(1)的分析框架
例:
还是利用这个消除了左递归的抽象语法树的翻译模式。
实现对于中缀表达式进行语法分析和翻译的递归下降的翻译器。
↑AST-node : 指向抽象语法树结点的指针 , 即nptr
R.i这里的in属性,R(in:↑AST-node)
用来记录R展开之前已经分析完的那一部分表达式所翻译出来的抽象语法树的根。
R的返回结果对应R的综合属性S,也是指向抽象语法树结点的指针,它的意义是:
当R匹配完之后,到目前为止你所分析完的所以表达式的结果,也就是那个抽象语法树的根。