语义分析与中间代码生成

前言

在之前的语法制导翻译中,我们学习了翻译模式,为文法定义匹配的语义动作,通过这个“动作”可以生成代码,但为了进行与机器无关的代码优化工作,选择生成中间代码(四元式),而不是机器代码。下面对每一类语句设计翻译模式,这里一个翻译模式就是一个“算法”。

说明语句

过程中的说明语句

过程中的说明语句: i d 1 , i d 2 , i d 3 , . . . , i d n : t y p e id_1, id_2, id_3, ..., id_n: type id1,id2,id3,...,idn:type M → ϵ M\rightarrow \epsilon Mϵ通过引入非终结符号将语义动作移至产生式最后,即可以归约之后才进行该动作。enter操作将符号填入符号表中,offset指示符号变量在数据区中的位置,后面生成中间代码时则指示四元式在代码区中的位置。

在这里插入图片描述

保留作用域的信息

编程时可能会出现嵌套过程,为了保留变量的作用域信息,我们使用层次化的符号表,对于一个子过程调用,offset域指向子过程符号表,同时子符号表在Header部分设置指回父过程符号表,在完成子过程后返回父符号表继续添加表项。

在这里插入图片描述

两个产生 ϵ \epsilon ϵ的产生式的作用均是创建一张新的符号表,将新表加入tblptr栈,将0加入offset, m k t a b l e ( x ) mktable(x) mktable(x)指示了 x x x是新创建表的父表。增加了 D → p r o c   i d   N D ; S D\rightarrow proc\ id\ ND;S Dproc id ND;S中enterproc用于产生子过程的表项,addwidth操作将当前表的offset保存在符号表的Header。

在这里插入图片描述

至此完成了符号表的构建,下面开始生成中间代码。

赋值语句的翻译

简单算术表达式及赋值语句

lookup操作从当前符号表中查找名字,找不到则转到外围符号表继续查找。

在这里插入图片描述

数组元素的引用

这里假设数组第 i i i维度从 l o w i low_{i} lowi开始编号,因此元素 A [ i 1 , i 2 , . . . i k ] A[i_1,i_2,...i_k] A[i1,i2,...ik]的地址为
b a s e + ( ( . . . ( ( i 1 − l o w 1 ) × n 2 + i 2 − l o w 2 ) . . . ) × n k + i k − l o w k ) × w base+((...((i_1-low_1)\times n_2+i_2-low_2)...)\times n_k+i_k-low_{k})\times w base+((...((i1low1)×n2+i2low2)...)×nk+iklowk)×w
i i i l o w low low进行分离得到不会改变的基准地址,可以提前计算出来,存储至符号表中以及动态地址。

在这里插入图片描述

第一种的文法很容易想到,但是在翻译过程中没有办法追踪Elist属于哪个数组对象,无法排查数组越界错误(语法错误),因此使用第二种文法,先将 i d [ E id[E id[E归约为 E l i s t Elist Elist

在这里插入图片描述

以下翻译模式主要是将数组元素的地址计算出来。

(6)用offset属性表示一个变量是简单变量还是数组,是数组,要通过数组引用将数组元素L.place[L.offset]赋值给E.place。

(7)此时动态地址已经储存在Elist.place中,乘上字宽 w w w,得到偏移量赋给L.offset,将Elist.array减去C得到数组的起始地址赋给L.place。

在这里插入图片描述

(9)中 g e n ( ∗ , E l i s t 1 . p l a c e , l i m i t ( E l i s t 1 . a r r a y , m ) , t ) gen(*,Elist_1.place,limit(Elist_1.array,m),t) gen(,Elist1.place,limit(Elist1.array,m),t)产生的四元式查询当前这一维度的长度和 E 1 . p l a c e E_1.place E1.place(存储 e k − 1 e_{k-1} ek1)相乘,再加上 E . p l a c e E.place E.place,递推地计算 e k = e k − 1 × n k + i k e_k=e_{k-1}\times n_k+i_k ek=ek1×nk+ik,最后将 e k e_k ek赋给 E . p l a c e E.place E.place。完成动态地址的计算。

(10)中 E l i s t . a r r a y = i d . p l a c e Elist.array=id.place Elist.array=id.place,正如我们上面提到,将id数组对象绑定到Elist上,方能调用 l i m i t limit limit方法获取数组每一维长度。

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

布尔表达式的翻译

数值表示法

在这里插入图片描述

作为条件控制的布尔式翻译

生成跳转四元式时并不能确定第四区块,也就是跳转的目的地址,因此利用第四区块构造出一条链表,表示等待填入,而且这条链表链接的跳转指令均将跳转至同一个目的地址。Merge操作发生在确定两条链表的目的地址相同时,backpatch操作发生在确定了跳转的目的地址的时刻。(这里可以深刻体会到:一个翻译模式是一个算法!)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

(1)E是一个布尔表达式,或操作,只要一个为真就从真出口出去,因此,两个布尔表达式为真对应跳转语句的目的地址应该是一个,但此时还无法确定,通过Merge操作将两个链表合并,等待填入。 E 1 . f a l s e l i s t E_1.falselist E1.falselist进行回填,因为 E 1 E_1 E1为假,应该跳转至 E 2 E_2 E2所对应的布尔表达式进行判断,而这个表达式的首地址通过非终结符M记录下来了,因此用属性M.quad回填 E 1 E_1 E1为假的情况下对应的链表。
(2)类同(1)。
(6)出现一个布尔表达式,生成两条跳转语句(真/假出口),但这两条语句的目的地址都无法确定,因此创建链表链接它们,等待填入。

在这里插入图片描述
在这里插入图片描述

控制语句的翻译

控制流语句

为语句S增加属性nextlist,表示S之后要执行的语句。E是已经归约完成的布尔表达式。
(1)用该产生进行归约时, M 1 , M 2 M_1,M_2 M1,M2通过空字归约得到,它们分别记录了代码段 S 1 , S 2 S_1,S_2 S1,S2的首地址,也就是布尔表达式E的真/假出口,回填。最后将 S 1 , N , S 2 S_1,N,S_2 S1,N,S2的nextlist进行合并。
(5)nextlist属性在这里使用,因为while语句的执行逻辑是执行完S之后,返回入口表达式进行判断,所以**并不是所有的语句S执行完都继续执行下一句!**因此引入了nextlist属性。
(6)begin,end语法    ⟺    \iff C/C++中的大括号。
(7)A是赋值语句,通过产生式 S → A S\rightarrow A SA归约成代码段,并通过mklist创建链表,等待填入代码段之后的下一条语句的地址。
(8)识别到分号,表示这是顺序执行的两条语句,用M.quad回填前面一条语句的nextlist,并将S.nextlist赋给L.nextlist。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

标号与goto语句

在符号表中记录标号和地址的关系,遇到标号则查找标号表中是否包含该标号,若有则标号重定义,报语法错误;若没有则将标号将入符号表。遇到goto语句可能有3中情况:
(1)标号已存在且已经定义,生成四元式(j,-,-,p);
(2)标号不存在,符号表中增加标号,其地址设置为nxq,生成四元式(j,-,-,-),等待回填;
(3)标号已存在但没有定义,由于符号表中只有一项,无法构造出链表,因此直接生成四元式(j,-,-,x),x为符号表中该标号暂时对应地址,这个位置可能还是一条跳转四元式,最后通过(2)产生的四元式跳转到标号处,通过多次跳转跳转到标号处。

在这里插入图片描述

Case语句的翻译

在goto语句的基础上实现, I → A S I\rightarrow AS IAS,将一个case和相应的statement归约,不同于之前的Merge操作,这里查表next,获取地址a,将标号next的地址修改为nxq(即后面生成四元式的地址),生成一条四元式(j,-,-,a),跳转到该地址。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

reference
山东大学编译原理郑艳伟老师ppt

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

u小鬼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值