此时的每条规则后面会对应一条语义动作,即制导翻译。
一、中间语言
中间语言就是和源程序等价的一种编码方式,复杂性也是介于源程序和机器语言中间。
为什么要中间语言?
我们经常可能会遇到过代码优化的选项,中间语言其中就有便于目标代码的优化以及便于目标代码的生成。后面会慢慢介绍到。
二、逆波兰式
逆波兰式也称后缀表达式
后缀表达式结合了栈对运算表达式进行了变换使之便于机器运算,它是无括号的表达式,在数据结构中我们也学习过。
①.后缀表达式可以根据优先级函数和栈来求,这是其中一种办法:
从左到右扫描运算表达式,如果是运算对象则直接出来,如果是运算符那么需要和栈中的运算符优先级进行比较,如果比栈中的高,那么入栈,否则先将栈中运算符出栈,然后再进行比较。
栈内<栈外:入栈操作符
栈内>栈外:出栈操作符
栈内=栈外:出栈 栈内的操作符,并入栈 栈外的操作符
遇到 ‘(’:直接入栈
遇到 ‘)’:出栈所有操作符直达遇到 ‘(’ ;
如果用栈,运算表达式首尾都加上终止符#,其优先级最低
比如a+b*c,我们知道*的优先级是大于+的。
先加终止符: #a+b*c#
#入栈,a,+优先级大于#所以入栈,b,*优先级大于+所以入栈,c,#优先级小于*所以*出栈,#优先级小于+所以+出栈,#遇到#结束。此时外面是ab*+即后缀表达式。
和我们的直观感觉一致:先求出优先级高的整体,想求整体,就得从优先级高的整体部分中的优先级低的部分开始算起。
②.老师还给了一种快速写出的办法:
在每个运算外面加上一对括号,然后将括号内的运算符提到括号外面,最后再去掉括号即可。
a+b*c -------> (a+(b*c))------>(a(bc)*)+ ------->abc*+
应用:上面说到语法制导翻译,就是在每条规则后面加上对应的语义动作,我们可以将语义动作写成后缀表达式的形式便于机器执行相应的语义动作。比如E->E+T {E.code:=E.code+T.code}将大括号中的语义动作写成{E.code:=E.code T.code+}就会便于机器识别。
实例待填:——
三、三元式
一般形式(运算符,参数1,参数2)
a+b*c对应的三元式{
1.(*,b,c)
2.(+,a,1)
}
对于一目运算符,我们可以规定只用参数1
间接三元式
有时如果用三元式来表达,会发现有许多重复的部分但是却不能去掉。
所以间接三元式就有一个三元式表,表中的三元式不同。然后就是调用三元式表即可。
这样便于后面的代码优化和节省空间。
四、树形表示
如果一个运算表达式用树来表示,我们进行后序遍历,发现得到的就是后缀表达式。
表达式的三元式可以看成是树的直接表示
五、四元式表示
形式(运算符,参数1,参数2,运算结果)
可以看到,上面三元式的顺序是不能轻易改变的,引入临时变量可以更改四元式的相对位置,这样又能进一步方便代码优化。