编译原理(十)语法制导翻译

语法制导定义 Syntax-Driect Definition SDD

语法制导的翻译方案Syntax-driected translation scheme SDT,可以看作SDD的具体实现方案,SDD是抽象宏观的,用伪代码,SDT用的是C语言什么的。

综合属性:从前面语句中获取属性,由底向上的,终结符只有综合属性,它从词法分析器分析来的属性被归为综合属性。

继承属性:从后面语句中获取属性,由顶向下的

SDD就是把简要规则放在末尾,SDT就是把代码插入到产生式内。

一个没有副作用的SDD也叫属性文法,副作用就是print什么东西吧,如果没有,就直接把属性给根节点了,什么也不输出,它爱叫什么叫什么。

如果一个文法同时有综合属性和继承属性,那么就不能保证有一个拓扑排序,因为有环,如果没环的话,就会有一个拓扑排序。但很难确定有没有环。

但是,有两种SDD,可以保证没有环,一个是SSDD,一个是LSDD。

仅仅使用综合属性的SDD称为S属性的SDD,或S-属性定义、S-SDD。它用自底向上的分析是绝对没问题的。

一个SDD是L-属性定义,当且仅当它的每个属性要么是一个综合属性,要么是满足如下条件的继承属性:假设存在一个产生式$A\rightarrow{X_1X_2...X_n}$其右部符号$X_i$的继承属性仅依赖于下列属性:
A的继承属性
产生式中$X_i$左边的符号$X_1,X_2,...,X_{i-1}$的属性
$X_i$本身的属性,但$X_i$的全部属性不能在依赖图中形成环路

白话讲,就是左边非终结符的继承属性,左边同伴的所有属性,本身的属性,但本身的属性不能形成环路,这样做的唯一目的就是避免产生环路,左边非终结符的综合属性就是下面来的,因此必出现环路,就是这样。对于右边同伴的,在语法制导翻译中,根本就没有扫描到,反正就不是右边的。

L-属性定义(也称为L属性的SDD或L-SDD)的直观含义:依赖图的边的直观含义:在一个产生式所关联的各属性之间,依赖图的边可以从左到右,但不能从右到左(因此称为L属性的,L是Left的首字母)。

这是什么意思呢?实际上LSDD也可以用在LR分析的。

这其中用到了select集,并不是很懂。LL1文法的判别就是看select集。。。

这里与bison是不一样的,bison只能过去了之后才能用$$来调用它,因此bison里只能放到右边。但是这样的动作很有参考价值,将综合属性放到末尾,为什么呢?因为都要用上吧。但是按理来说,就像ppt讲的那样,继承属性是符号即将出现时赋值,综合属性是完全规约完毕时赋值。

继承属性如果在符号即将出现前赋值,那么它就无法实现自底向上翻译的。放在前面只是为了符合LL文法。那么就要改一下,添加标记非终结符,来完成。

虽然标记非终结符的出现把语句移到末尾,但空产生式的语句却用到了别的非终结符,这实际上可以用栈来获取。没有关系的。栈中位置是已知的。

那么下面是关于栈的,栈的话现在还是完全不懂。看看进栈出栈到底是什么关系。

T->FT' {$$=$2;}

T'->*FT'_1 {T'=} // 没法算的,但的确是可以的,文法没问题,那么你要看bison的$到底是什么呢?它是我们自己定义的,int,char都可,没定义就不能用,可以叫做唯一属性吧,支持结构体那么就可以多种属性了,它本质上是属性,这个属性是它自己维护的栈。那么这个神仙产生式。。。它的确可能需要两个属性。。。那么就需要自己维护栈了,属性是如何放置需要自己定义。这个产生式是没办法用bison解的。解不出来,即便用bison的话,也要自行添加一个,在F和T'之间进行压栈,栈中是继承属性,综合属性用$就可以了。甚至可以说,完全不用$。其实一个符号栈也可以的。严格遵循规律即可。你应该很清楚之前压了几个,弹出几个,就是这样。如果这个乘法是普通那种乘法的话(单个的),那么用SSDD就足可以完成。

T'->空 {T'=1}

F->digit {F=digit}

你看,这个产生式明显是LSDD,既然是LSDD,那么继承属性的定义就要插在前面执行的要记住,然后下面的才是有意义的别忘了。继承属性在初始化前完成的意义是综合属性要使用继承属性。标记非终结符为什么可以取消掉继承属性呢?是因为它本身是一个空串,这样继承属性和综合属性就结合到一起了。并且标记非终结符不仅有属性,而且还占了它表示的后面符的位置,占了一个位置,就是为了使用它的属性的,妙啊。。。如果没有标记符的话,那么规约多少,就弹出多少,并把非终结符压入,但是现在,标记符就表示非终结符,那么。。。

标记非符的出现,意味着非终结符也可用于移入了,虽然它是一个空串,非常特殊的存在。而且后面的非终结符,就没有继承属性了,进程属性完全靠栈来解决。

既然都放在后面,那么bison为什么可以把代码嵌入表达式中呢?实际上,并不是嵌入,而是它智能创建了一个空产生式,下拉出一个新的产生式,不对不对,原理好像不大一样。它呢,就好像在中间的时候进行综合属性的计算。这个是怎么回事呢?虽然放在后面,它仍然产生一个空产生式,这与继承属性有什么关系呢?你说bison的话,对于上述乘法的东西,因为有$$的存在,它一般是最后一个简单赋值,非常方便,它隐藏了细节。它的原理是

往下走是继承属性,往上走是综合属性,这样分得开,很直观对吧。

我应该把栈都看全了,都会了。

动作符号。。。

LL拓展的顺序是怎么样的?它没有符号表,出现了什么终结符,如果是非终结符,就将相应的产生式入栈,直到出现终结符,匹配成功出栈,然后遇到非终结符时同样进行扩展,就是这样的。如果出现的是动作符的话,就执行动作并出栈就好了。即便是LL推导,你也要记住属性继承的位置。当非终结符出栈时,要将属性寄托给动作符。栈位要根据产生式一个一个自己数。

在LL中,综合属性单独一个栈位,继承属性与文法符号一个栈位。。。LL的问题就在于一直要倒腾栈位。

然后用上面的M,N,就可以实现全部末尾了。但是要使用没有出现的非终结符是非法的,但是栈的存在可以改变这一点。

那么有空产生式的文法就会与这个标记产生式产生规约-规约冲突,这也就是为什么不能有空产生式的原因。

再重申一遍分析顺序->

读取指针字符,查表,发现是移进字符,指针+1,然后符进栈,属性进栈,并给符添加一个新状态

再读取指针字符,查表,发现是规约,用相应表达式规约,删除规约的所有状态,添加这个非终结符,并查表,根据之前的状态和这个非终结符添加它的状态,指针不变,完毕

再读取指针字符,查表,是移进是规约由上面的方式来。

按理说,规约的时候,符的属性也要出栈全部删掉的,因为用这些属性创造了一个新的非终结符属性,而不是说不变知道吧。虽然说属性跟符号是匹配关系,但是往往它们不是出栈,而是更换主人,例如标记非终结符实际上就是后面的那个符,只是为了解决继承属性的原因。标记非终结符的属性就是后面符号的属性,所以可以直接写为后面的属性。

每个S-属性定义都是L-属性定义

也就是说,L属性定义随便弄,S属性定义只允许继承呗,弄了这么长,真难受。

那么举一个例子呗,

因为父节点的综合属性可以依赖于子节点的综合属性和继承属性(上图两橙色箭头);若子节点的继承属性再依赖于父节点的综合属性就会造成循环依赖(如上图);因此子节点的继承属性只能依赖于父节点的继承属性而不能依赖于父节点的综合属性。这肯定是没错的。

如果Xi可以同时依赖其左右两侧符号的属性,则会形成循环依赖。假如存在X1X2X3,若X3的属性依赖左侧的X2的属性同时X2的属性又可以依赖右侧的X3属性,则会形成循环依赖。因此Xi的继承属性只能依赖于其左边的符号的属性。

L属性定义对综合属性没有限制,它只限制继承属性,因此此SDD是否为L-SDD取决于继承属性所依赖的属性值。第一个T'.inh依赖的是它左边兄弟的值,因此它不违反LSDD对继承属性的限制。第二个T'.inh依赖于其父亲节点的继承属性和其兄弟节点的值,也不违反LSDD对继承属性的限制。所以下图SDD是LSDD。

Q的继承属性依赖了它有边兄弟节点的综合属性,因此违法了LSDD的继承属性的限制。因此此SDD不是LSDD。

仅仅使用综合属性的SDD称为S属性的SDD,或S-属性定义、S-SDD。

 

如果一个SDD是S属性的,可以按照语法分析树节点的任何自底向上顺序来计算它的各个属性值。

S-属性定义可以在自底向上的语法分析过程中实现。

只用综合属性的话,Pascal?那种?

SDD是关于语言翻译的高层次规格说明,隐藏了许多实现细节;SDT可以看做是对SDD的一个补充,它显式地指明了语义规则的计算顺序,以便说明某些实现细节。

譬如SDD的例子:

SDT是在产生式体中嵌入了称为语义动作的程序片段的CFG,对文法符号的属性值进行计算。譬如:

做题方法就是根据语法,先拆分成单个的,然后写出SDD,然后写出SDT,就是这样。

 

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值