简单说两句
在前两天的内容中,我们初步了解了文法和自动的相关知识。
其中讲到了文法可以定义词法和语法的构成规则,自动机可以帮我们识别出词法或语法。
识别成正确的语义后,编译器就可以将源码翻译成中间代码,接下来我们就结合教材中的例子对语法制导翻译的关键点加些备注。
一、中间代码
中间代码有四种表现形式,最常用的为四元式。
如x = a + b
就可以表示成(+,a,b,x)。
再比如x = a
就可以表示成(:=,a,_,x)。
二、常见语言结构翻译
1.布尔表达式的翻译
布尔表达式的文法为:
先看E and E
为了方便描述,不妨令第一个E为E1,第二个E为E2,则"E1 and E2"表示先判断E1,如果E1为true再判断E2,否则不处理E2。
关于tc、fc、拉链等名词教材中解释的很清楚,这里不再赘述。
从上图中可以看出,E1有两个箭头:
左边表示true,这时把tc指向E2在字符表中的位置,如果E2也为true,整个表达式为真,则整个表达式E的真跳转就是E2的真跳转位置;
右边表示false,这时表达式E为假,不仅如此,E1为true,E2为false的时候表达式E也为假,所以E1.fc和E2.fc指向同一个位置,如果说这个位置在翻译的时候还不明确,就可以把它们合在一起,俗称拉链,这样只要这个fc在后面的翻译过程中确定位置的话,整条链上fc都可以明确。
// 为了描述方便,把E -> E1 and E2作了拆分
if(E1) {
// E.tc = E1.tc
if(E2) {
// E.tc = E2.tc
} else {
// E.fc = E2.fc
}
} else {
// E.fc = E1.fc
}
关于E or E就跟上面一样,就不分析了。
重点看看:
上面是赋值和运算结果赋值,分别对应类似下面的语句:
true或者a > b
为什么一个简单的赋值,在翻译过程中添加了这么多代码呢?
而在教材中对算术表达式的赋值却很简单:
就这点把我想了一晚上都没想通,最后早上跑步的时候灵机一想:
可以把布尔表达式看成一个类,这个类有两个属性tc和fc,也就是说,在制导翻译的过程中无论布尔产生式为哪种文法,都必须提供tc和fc。
那么,赋值语句怎么产生tc和fc呢?
其实就是把NXQ(指向下一个产生的四元式)给tc,把NXQ + 1给fc。
请注意!!!
这时候tc和fc指向的四元式都没创建,待GEN调用才会真正生成。
其中**GEN(jnz, Entry(id), _, 0)就表示先从符号表中拿到id对应的位置,通过jnz(jump not zero)函数判断位置是否为0,不为0表示确实有这么个id,跳转到符号表中的0位置,即不跳(0表示无效位置)。
而GEN(j, _, _, 0)**就表示直接j(jump)到0,无条件的。
所以综合来看,就是生成了两个不指向任何地址的四元式,一个引用是tc,一个引用是fc。
这样,如果这个布尔出现在if或while中的话,在翻译if或while语句时就可以拿到布尔的fc和tc,而不管其产生式的形式。
2.真实的粟子
在教材例2.8中就展示了语句if a < b then while a < b do a: = a + b的翻译过程。
相信看完了上面布尔的制导翻译过程,应该不难看懂下面这个表格。
其中【语义处理及结果】以用【四元式】两栏中的数字即NXQ,也就是四元式的次序。
右边四元式就是由GEN生成的。
总结
对于没学过编译的同学们来说,这一章节内容不多但很抽象,想仅仅看懂教材中就已经很吃力了。
尽管这些东西看起来费力不讨好,毕竟从真题来看,没有这方面的考试内容,但是知难而上的精神还是要有的。