C6 语法制导翻译-编译原理

词法分析:。词法分析任务是:从左到右逐个字符扫描输入的源程序,按照构词规则,检查词法错误识别出正确的单词,并输出单词的内部表示形式。如果识别过程中发现错误或无法识别的单词,则输出有关错误信息

语法分析:语法分析的任务就是在词法分析识别出正确的单词符号串是否符合语言的语法规则,分析并识别各种语法成分,同时进行语法检查和错误处理,为语义分析和代码生成做准备。

 语义翻译就是语义分析+中间代码生成;在语法分析的过程中顺便完成语义的玩意工作,这种技术就叫做语法制导翻译

语法制导翻译使用CFG来引导对对语言的翻译,是一种面向文法的翻译技术

语法制导翻译:

前端:符号表的建立-词法-语法-语义分析-中间代码生成-与机器无关的中间代码生成;

后端:与机器有关的代码优化-目标代码的生成+错误处理,符号表的访问。

将静态检查和中间代码生成结合到语法分析中一同进行的技术称为语法制导翻译

语法制导定义:

 *****上图

固有属性是词法分析器赋予的值。比如终结符的综合属性值。 

使用继承属性解决不匹配问题: 

这里不匹配指的是?

这个例子放在这里其实不是很好,已经涉及到SDD的设计层面。

其实也很好理解,在计算一个继承/综合属性之前,这个继承/综合属性所依赖的属性必须要全已知。对于第一条产生式对应的语义规则来说,T‘继承属性需要的F的综合属性由词法分析器给的lexval可以知道;而T的综合属性需要T’的综合属性,T'的综合属性又需要接着往下推——T1’的综合属性 可以看出来这个SDD是借文法符号的继承属性来一步步算出结果,在最底层得到答案之后通过综合属性传到根节点上来。

PS.这种计算叫做分析树法,通过构造节点间的拓扑顺序来计算。对计算顺序有疑问的没关系,继续看下去。

属性计算:

这里的数字标号就代表拓扑排序的号 也是计算顺序。

S/L-属性定义:

预先判断依赖图中是否存在循环依赖很难。可以缩小要求,对属性进行要求实现特殊的属性文法,分析树的依赖图肯定不会出现循环依赖。

这种范围的缩小前面也有过,比如文法的无二义性包括了我们构造的各种确定性文法。

S-属性定义:

直接就是后根遍历,计算N的所有综合属性,自底向上计算。 

L:

就是之前那个例子~

注意L文法定义里的继承属性如果继承父亲的属性的话只能继承父亲的inh,也就是继承属性;依赖于自身或兄弟节点的时候就无所谓是继承属性还是综合属性。

算法很重要!明确L属性文法就是这样计算的。也算是后根遍历,挨个计算孩子的继承属性,最后计算综合属性。 

抽象语法树:

指针的简单应用。

之前那个例子,做了消除左递归的产生式子集(below)

L计算算法得出的顺序。 

翻译模式SDT:

具体实现: 

情况2在情况1上做改动即可,一个动作右边符号的综合属性都没算出来呢 怎么能引用呢?

盒子排版:

(1)point size用于表示盒子中文本的尺寸。如果标准盒子的尺寸为ps,则下标盒子的尺寸为0.7 ×ps。属性B .ps 表示盒子B的尺寸,该属性是继承属性 。

⑵ 每个盒子都有一个基线(baseline),用来表示每个文本底部的垂直位置。

⑶ height用来表示从盒子的顶部到基线的距离。属性 B .ht表示盒子B的高度height,该属性是综合属性 。

⑷ depth用来表示从基线到盒子底部的距离。用属性 B .dp表示盒子B的深度depth,该属性也是综合属性。

这个算法其实很好理解,可以把推导式左边的B看成是一个完整的盒子,我们知道他的ht和dp,但是它是个黑盒,具体这个盒子是由什么组成的还要看产生式的右边。

继承属性的计算在它的最后一次出现之前,综合属性的计算在产生式末尾。

S属性的自底向上计算:

ntop=top-r+1 ntop是新的栈顶的位置。

调用语义子程序的时间:规约前

L属性定义的自顶向下翻译:

这里是将做好的SDD修改变成SDT。

复习一下消除左递归:http://t.csdnimg.cn/JU1wl

想要进行自底向上分析的同时翻译就得引入继承属性帮助向下传计算完成的答案,而使用综合属性向上传。

R这里承担的是一个匿名的变量 他代表很多个运算数。具体有多少个就看输入了,具体结构如下:

注意进栈的顺序,F后进的栈。 

3识别出来了,不再进栈。

语法栈顶为动作时直接调用。

可以看出每加入一个新的op就会产生一个F.node,符合前面的抽象语法树

语义栈里出现的内容其实就是当前分析进度的注释分析树的节点。

L属性定义的自底向上分析:

拿上面那个例子来说,N承担的是什么工作?其实就是计算T1’的继承属性值。N所在的动作就是把原动作语义规则右部的属性全部作为N的继承属性值,左部属性(也就是待求属性)作为N的综合属性值。

先不论为啥右部设置成继承属性,左部设置成综合属性,这里有一个大问题:N对应的语义动作调用了这条产生式里没有的属性。这是不被允许的,为了合理化这项操作,我们对每个非终结符的继承属性的位置都做了规定,让分析器能够知道这些属性在什么地方,能够正确的调用。

可以证明如果一个文法是LL的,那么可以向它的产生式右部任意位置插入语法动作来产生LR文法。

构造这个文法的SLR自动机状态图:

此时为0号初始状态。

第一个输入为3,采取移进操作,进入状态3:

下方的3代表的是d的词法值。

接着输入指针指向乘号,3号状态碰到乘号时采取的是归约动作,使用4号产生式进行归约。

于是d出栈,F进栈,因为F的综合属性值等于3.所以词法值不变:

2号状态碰到乘号时采取归约,可以看到采用的是构造出来的M的空产生式进行归约:

于是M进栈,从语义动作可以看出M的属性值等于F的属性值。而F是M左兄弟,已经进栈了,于是我们只需要将栈顶的属性值赋给top+1的位置。

这里找各个值和值的位置的逻辑其实很简单:如果找的是产生式右部的某个值,那么看它和目前分析语法变量的相对位置,比如M要进栈,此时要求F.val,而其为M的左兄弟(左边=已经进栈,左兄弟=分析栈顶),所以去找栈顶的属性值。如果要找的是产生式左部某个语法变量的继承属性值,那么需要找这个语法变量在分析栈中将要被归约出来的位置的左边/下面(更靠近栈底的位置)

而M.s实际上就是T'inh:

二号状态遇到M进入4号状态,4号状态碰到当前输入为乘号时采取移进操作,进入6号状态。

6号状态碰到当前输入为5时采取移进操作进入三号状态。

而3号状态碰到$符号时使用第四个产生式进行归约,d出栈,F进栈,属性值保持不变,6号状态碰到F进入7号状态。

而7号状态碰到$时使用N的空产生式进行归约,N即将进栈,根据语义动作,因F的综合属性已知,我们现在需要T'.inh。T'将要归约出来的位置就是乘号此时所在的位置,其左部就储存了T'的继承属性值。

于是得到N的综合属性值15;这个值实际上就是T1'.inh。7号状态碰到N进入8号状态:

8号遇到$使用3号产生式进行归约,T'的继承属性值在哪呢?还是它将要被归约出来的位置的左部,就是N现在所在。

8号状态碰到T’进入9号,遇到$使用2号产生式进行归约:

由产生式

可知T’的综合属性值由它最右边的孩子的综合属性值决定

注意:此时栈顶的T’和将要归约出的T’显然不是一个

因此我们将15赋给新入栈的T’的综合属性。

4号遇到T’进入5号,5号碰到$继续归约。

而根据

可知T的综合属性值等于T最右边孩子的综合属性值~也就是栈顶的属性值。

于是进入了1号状态,也就是接收状态,成功完成分析。

再来看看ppt:

这段话已经很好理解了,归约B1之前B.ps在哪?由第一个动作:

我们知道要创建一个标记性非终结符来进行:保存B.ps的值10。因为后面的所有产生式都要用到B.ps,肯定是提前把这个值存进分析栈的。

B1.ps肯定能找到B.ps,实际上B.ps就在分析栈的底部,B2为啥找不到 留个栈底不就行喽~(问题留待解决)

这个代码段好写, 就拿B推导为B1MB2来说吧 归约的时候才执行代码,所以取max的时候B2为栈顶B1为Top-2。

还有栈顶坐标的改变上上图没写出来,可见上图。

小结:

注释分析树:节点带有属性值的分析树。

依赖图:

抽象语法树:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值