这种方法是根据布尔运算的某些特殊性质采用优化措施进行的。就或运算E1 or E2而言,只要E1为真,则E1 or E2肯定为真,此时就不必再对E2做计算;只有当E1为假时才读取E2,此时E1 or E2的值由E2决定。同理,就与运算E1 and E2而言,只要E1为假,则E1 and E2肯定为假,此时就不必再对E2做计算;只有当E1为真时才读取E2,此时E1 and E2的值由E2决定。或运算E1 or E2和与运算E1 and E2的中间代码结构如图6-17所示。
图6-17 布尔运算的中间代码结构
在图6-17中,用E.ture表示布尔表达式E的真出口,即E为真时应转向执行的中间代码位置,用E.false表示E的假出口,即E为假时应转向执行的中间代码位置。
基于上述中间代码结构,下面探讨如何通过一遍扫描方式对布尔表达式进行翻译。为了便于讨论,这里将采用四元式形式实现三地址代码,并把四元式存入一个数组中,数组下标代表四元式的标号。常见的四元式形式有:
(1)(jnz,E,_,P):表示当E为真时,跳转到四元式P;
(2)(jrop,id1,id2,P):表示当id1 rop id2为真时转向四元式P,其中rop代表六种关系运算之一;
(3)(j,_,_,P):表示无条件跳转到四元式P。
通过一遍扫描来产生布尔表达式的中间代码时,对于生成的某些转移语句,可能还不知道该语句的具体转向位置。为了解决这个问题,可以把这些转移方向相同的四元式链在一起,形成四元式链表,当目标确定之后再回填。
按照这个思想,我们对E的两个综合属性true和false的意义进行拓展,规定E.ture不仅表示E的真出口,而且表示E中具有相同真出口的四元式链表的链首;类似地,规定E.false不仅表示E的假出口,而且表示E中具有相同假出口的四元式链表的链首。具体实现时,可以借助于需要回填的四元式的第4分量来构造该链表。例如,假定E的四元式中需回填“真”出口的有p、q和r三个四元式,则这三个四元式可连成如图6-18所示的一条“真”链,且链首r将作为E.true之值。
图6-18 含有p、q和r三个四元式的真链表
在布尔表达式的翻译过程中,要用到下面几个变量、函数和过程:
(1)变量nextquad:指向下一条将要产生但尚未产生的四元式的编号,其初值为1,每执行一次emit过程,nextquad将自动加1。
(2)函数merge(pl,p2):把以pl和p2为首的两条链合二为一,返回合并后的链首。
(3)过程backpatch(p,t):完成回填功能,将把链首p所链接的每个四元式的第4分量都改写为地址t。
综上考虑,现给出如表6-14所示的翻译模式,以便在自下而上的分析过程中生成布尔表达式的四元式代码。其中,M为标记非终结符,用来记录将要产生的四元式编号。
表6-14 布尔表达式的自下而上翻译模式
考虑产生式E→E1 or E2。若E1为真,则E也为真;若E1为假,则需进一步验证E2。若E2为真则E就为真,若E2为假则E就为假。因此,E1.false所指向的链表中的四元式待填转向目标应为E2代码第一条语句的编号,该编号是利用标记非终结符M得到的。记录着E2代码开始语句编号的属性M.quad值在分析完产生式E→E1 or E2的其余部分之后,将被回填到E1.false所指向的链表中。
对于产生式E→id1 relop id2而言,执行其语义动作将生成两条语句:一条是条件转移语句,另—条是无条件转移语句,二者的转向目标当前均无法确定,暂且以0表示。同时,第1条语句将被放入新构建的真链表E.true中,而第2条语句则被放入新构建的假链表E.false中。
例6.7 布尔表达式a<b or c<d and e<f的翻译过程可用图6-19中带注释的语法分析树来表示,它依据表6-14中的翻译模式,在自下而上语法分析中随着对产生式的归约来逐步执行语义动作的。(www.xing528.com)
需要注意的是,为了方便起见,在图6-19中采用了一些简记手段来表示属性值。比如,用E.t={100,104}表示E的真链表中含有两个四元式,其编号分别为100和104,应与E.true所代表的链首值区分开来。
图6-19 a<b or c<d and e<f的带注释的语法分析树
首先,关系表达式a<b依据产生式E→id1 relop id2被归约为E,同时生成了如下两个四元式(假定语句编号从100开始):
100(j<,a,b,0)
101(j,_,_,0)
其次,利用产生式E→E1 or ME2中的标记非终结符M记录了下一个将要产生的四元式的编号,此时是102。并且,通过产生式E→id1 relop id2把c<d归约为E,同时生成下面两个四元式:
102(j<,c,d,0)
103(j,_,_,0)
接着,利用产生式E→E1 and ME2中的M记录下当前的nextquad值,现为104。并且,通过产生式E→id1 relop id2把e<f归约为E,同时产生四元式:
104(j<,e,f,0)
105(j,_,_,0)
最后,将E1 and ME2归约为E,其语义动作backpatch(102,104)将把编号104回填到E1.true所指向的真链表中唯一一个四元式(编号为102)的第4分量中;将E1 or ME2归约为E,其语义动作backpatch(101,102)将把编号102回填到E1.false所指向的假链表中唯一一个四元式(编号为101)的第4分量中。此时,得到如下的代码形式:
100(j<,a,b,0)
101(j,_,_,102)
102(j<,c,d,104)
103(j,_,_,0)
104(j<,e,f,0)
105(j,_,_,0)
这就是布尔表达式a<b or c<d and e<f的最终翻译结果,所留下的两个真出口(100和104)和两个假出口(103和105)要等到该布尔表达式之后的可执行语句地址确定后才能给出。
免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。