语法制导翻译并产生中间代码:
概述:
-
语法分析之后,编译的任务是由已识别成功的正确源程序生成一组规格一致,便于计算加工的指令形式。
-
中间代码的生成方法:
语法制导翻译,属性文法制导翻译 -
中间代码:
- 不是机器语言,便于生成机器语言,便于代码优化。
- 中间代码的形式:
- 逆波兰式
- 树形表示法
- 三元式
- 四元式
-
翻译方法:语法制导翻译
- 在语法分析基础上边分析边翻译
- 语法制导翻译会根据文法产生式右部符号串的含义,进行翻译,翻译的结果是生成相应中间代码。
- 语法制导翻译的依据是语义子程序
- 具体做法:为每一个产生式配置一个语义子程序,当语法分析进行归约或推导时,调用语义子程序,完成一部分翻译任务。
- 语法分析完成,翻译工作也告结束。
- 语法制导翻译使用多种语法分析,但是都需要具体的语义子程序
- 语法制导翻译种类:
- 自上而下语法制导翻译(推导的方式):对每一个文法符号配以语义动作
- 自下而上语法制导翻译:主要讨论LR语法制导翻译
- 在语法分析基础上边分析边翻译
-
语义子程序:
当我们进行了一次推导或者归约,我们就调用对应的语义子程序
也就是我们定义的变量或者运算的中间过程生成的值
图中的例子:当归约a+bc,当c入栈后,归约到bc为E,其语义栈的值为bc,再归约E+E,最后得到E,并语义栈为a+(bc),语义子程序就是保证,语义栈能跟随语法栈变化而变化,且语义子程序的过程需要符合我们语法中定义的运算规则
可以总结:语义是非终结符的。 -
常见中间代码形式:
- 四元式形式:
- 三元式:
- 后缀表示式(逆波兰式):
后缀表达式在后面介绍
- 四元式形式:
简单表达式和赋值语句的翻译:
- 简单表达式和赋值语句的翻译
tmp作为中间结果,可以在比如ii+a,这就可能需要中间变量先计算i * i,存到tmp中,在计算tmp和a的加法值,因为我们在词法分析时,只给变量创建了符号表项,这里中间结果可能也需要保存
解释:
A->i=E,这是一句赋值语句,E为一个表达式的值,对应的语义子程序就是生成一个四元式(=,EPLACE,_,ENTRY(i)),也就是将E的语义值赋值给i变量的符号表对应的数值项。
E->-E,将一个值取反,赋值为一个非终结符,对应的语义子程序就是,生成一个T的临时存储空间;生成(@,右EPLACE, _ ,T),将右E的语义值取反后赋值为临时变量T,将T赋值为左E的语义栈位置。
此图不好理解,可以参考书上p140
对书上的理解:A:=-B(C+D)指针读入A的类号内码,发现是一个变量,给sym栈加入一个i,个给place栈加上一个A的符号表项,入栈到B,同样参照A,发现可以归约,对-E归约,newtem,生成一个四元式,将tem值存放到place栈中。
- 类型转换:
mode栈存放非终结符的类型信息
过程:读入Y+IJ,将I * J归约,调用语义子程序,得到四元式(,I,J,T1),将I * J的结果存放到T1,根据E*MODE知道IJ都是整形的,所有生成的T1也是整形的,然后要归约Y+T1,因为T1是整形而Y是实型,将T1转化为实型T2,然后进行Y+T2的归约,存放结果到T3中,为实型之间的运算,生成实现的结果,然后将T3的结果赋值给X。
布尔表达式的翻译:
-
布尔表达式的作用:
- 作为控制语句中的条件表达式
- 用于逻辑赋值语句中,布尔表达式演算
-
组成:
-
文法:
-
在逻辑表达式中的翻译:
-
例子:
过程:首先对X+Y进行归约,然后读入>Z,生成四元式1;对T>Z进行归约,生成四元式2;又对(~BVC)归约,生成四元式3,4;进行^运算,生成四元式5;进行V运算生成四元式6。
可以通过短路的方式来直接得到值,而不需要逐个的运算。 -
控制语句中布尔式的翻译:
算出E的值,再判断
真出口也就是条件为真跳转,一个if包含两个四元式,分别表示真出口和假出口 -
例子:
只需要将程序指针指向一个个的四元式按照执行就可以得到程序的执行结果,首先判断A是否为真,若是就跳到5号四元式执行,否则再判断后面是否为真,若是跳到5号四元式执行,否则判断else是否成立,当我们执行完if判断进入的语句,需要在最后加上一个跳过else执行语句的四元式。
也就是将需要填写相同出口的四元式进行链表,串在一起。 -
拉链法:
这样的文法对于我们来说,可以原本的E->E1vE2,只能又一个语义表达式,这对于真加出口的回填是不利的,可以通过文法的改写成为E->E0E2;E0->E1v,这我们就得到了两个归约式,可以执行两个语义表达式,在不同的语义表达式中,将语义动作细分。
ETC和EFC存放的就是应该填写真或假的出口的四元式
-
例子:
在进行E->i的布尔量归约的时候,在E的TC栈(表示为真对应的出口)填入NXQ,在FC栈(表示为假对应的出口)
扫描到A,当A为真,那么下一个执行的四元式就是B<D的开始位置,否则为2号四元式 -
回填实现:
我们可以通过E0->E1v这个新增的归约式,来定义他的语义子程序,将下一个四元式的标号回填到E1的假出口上,然后将E1的真出口赋值给E0的真出口,再通过对其他的表达式的定义,完成E0的真出口回填。
解释:BACKPATCH就是将t填入到p中;当p不为0,取出p的第四项,给q,将t填入p的第四项,再将p的第四项赋值到q,循环直到q==0。这里可能还是有疑惑,可以向下看。 -
例子
上图为对关系运算的翻译,我们将Ea1 rop Ea2的真假出口指明
我们首先对A翻译生成两个真假出口,再翻译Av回填假出口,因为当A为真的时候,我们只需要跳到if语句的结果为真的地方执行,为假则需要进行B<D的判断
我们做完,发现1号四元式为E0的TC,3号四元式为E1的TC,且这两个TC为同一个出口
MERG为合并操作
A归约为E1,E1v归约到E0,B<D归约到E2,E0E2归约到E,并完成语义动作
解释:
merg就是将p1连接到p2上;当p2为0表示p2对应的非终结符的真出口或假出口结点,就直接返回p1,否则就将p2写到p,当p的第四段内容不为0,就向后找,直达为0,说明到p2的头了,然后将p1连接到p2的尾部,返回。(感觉上面的ppt写错了)
这也是为什么backpatch操作有一个向后填写的操作我认为的实现方法:
对于这个拉链法:当我们需要填写ETC和EFC时,可以先在E对于的TC和FC栈中创建一个链表头(可以在语义子程序中完成),链表结构可以为指针域,数据域(标号,四元式字符串),当我们需要去操作回填的时候,就可以将需要回填的标号按照链表填入字符串中
过程:识别A^ Bv ~ C:首先将A入栈为i(变量),i归约为E,E生成ETC和EFC,ETF填入真出口的四元式1,EFC填入假出口的四元式2;识别E^归约为EA,调用语义子程序,将下一个四元式地址填入ETC也就是1中,同时将E ^的假出口给EA;读入B,归约为E,通过语义子程序,将真假出口四元式入栈,为3和4;将EAE归约为E,调用语义子程序,调用语义子程序将TC给TC,进行串联(merg);这时候入栈v归约为E0,进行假出口回填;将~入栈,C入栈,这时候填入TC和FC栈; ~E归约为E,反转继承TC和FC;归约到E,FC继承,TC进行串联;通过这样的步骤,我们可以发现,A和B的假出口都跳到5,也就是判断C,A的真出口跳到判断B,B的真出口,表示A^B为真,为全局的真出口,C的假出口为全局的真出口,C的真出口为全局的假出口假出口
控制语句的翻译:
goto语句的翻译
- 先定义后使用:
- 先使用后定义
当第一次goto L’,地址为0,L’填写的对应地址为当前地址,第二次遇到goto L‘,填入地址为L’对应的地址框对应地址,也就是第一次遇到goto时的位置,然后将当前地址填入L‘地址框中,依次类推,到了L‘定义的行,发现符号表中有L’且未定义,所以进行回填,直到遇到第四个框0的四元式,结束回填。
以上程序1
以上为程序2
if语句的翻译
当扫描了then就需要回填E的真出口了
当扫描了else,需要生成一个S1的跳出(J,_ ,_ ,?),同时回填假出口
S*chain表示的就是整个if else语句的结束位置。
为了能对then和else进行语义子程序的编写
描述:首先读入if E then,进行归约,读到then了,可以回填E的真出口的,并且将E的假出口串联到C的chain栈中,当翻译当else,这时候,先生成一个跳过假出口语句四元式,出口不明朗,先可以回填E的假出口的了,也就是C的chain;然后S1的chain也就是s1中产生的需要跳过else的过程的句子;再归约T S2,S2也可能是if语句,也就是S2的链也是要跳过整个if……esle的,到了S,组成的S的链就是所有需要跳过if……else的链
if () xx
else if () xx
else xxx;
斜体部分就是可能的S2,我们完成了S2的翻译,S2的链条就是需要跳出S的,所以要传回到S的chain中,当S被归约时,就将跳出S的语句进行回填。
1,2为a的真假出口;3,4为b的真假出口;扫描到第一个then回填a的真出口,第二个then回填b的真出口,第一个else,添加跳过语句6并回填b的假出口,6语句连接到if b中;第二个else,添加跳过语句8并回填a的假出口,8语句连接到if a中,这时候,就可以进行C S1的归约,这时将C的chain(if a)和S1的chain(if b)连接在一起。
9和10为c的真假出口,当扫描到then,回填9号(真)四元式,扫描到else,添加跳过四元式12,并回填10号(假)四元式,12号四元式连接到if c中,到了执行C S2归约的时候了,将S2的链条(if c)连接到C的chain(if a)上
上文中的if x表示的就是:将if x then归约到某个非终结符,这个非终结符的链条