一、实验目的
1. 学习和掌握语法制导翻译和中间代码生成
2. 实现TINY+语言的语法制导翻译及赋值语句的中间代码生成
二、实验内容与要求
- 实验内容
任务:实现语法制导翻译及赋值语句的中间代码生成
在前序实验中已实现了TINY+语言的词法分析及语法分析,本次实验要求基
于前序实验基础,实现TINY+语言的语法制导翻译及赋值语句的中间代码生成。
具体要求:
对于输入赋值语句a := b * c + d,应翻译成以下三地址码序列:
t1 := b * c
t2 := t1 + d
a := t2
请修改TINY+的语法分析程序,添加语义翻译代码,实现对任意TINY+赋值语句的语义翻译及中间代码的生成。
三、实验步骤与过程
1. 理解三地址码
在前序实验中,我们已实现了TINY+语言的词法分析及语法分析,本次实验要求基
于前序实验基础,实现TINY+语言的语法制导翻译及赋值语句的中间代码生成。
根据要求,中间代码的生成采用的是三地址法的形式进行,对于三地址码,是指这种代码的每条指令最多只能包含三个地址,即两个操作数地址和一个结果地址。下面我们来看一个例子,赋值语句a:=(-b)*(c+d)-(c+d)的三地址码如下图所示:
三地址码中地址的形式包括名字、常量、编译器生成的临时变量。
2. 实现思路
对于语法制导翻译功能以及中间代码生成,我们可以添加到规约的时候进行,因为在语法树构建时,已经确定了语法树的构造,赋值语句的层级结构也已经确定,所以可以对其进行分析,每个简单式都为中间代码的产生,如a*(/)b或a+(-)b为最基本单元,即为t1,然后判断其是否为其余形式的匹配。
具体实现思路如下:
首先判断递归到的赋值语句是否为表达式,如果为表达式,则对其进行标号,从t1开始,而本次实验只要求输出,所以不对其进行进行存储,不存储其值也可以降低其内存开销。如果需要存储,可以设置四个队列,即arg1,arg2,op3,result,用来存储中间过程产生的式子。
然后判定优先级,要对exp的两个child结点均判定。由于exp的两个子节点都可以是exp,所以在输出的时候需要对其进行判定,直到进入到最底层进行输出。一般而言,乘除的优先级是高于加减的,也就是说,如果一个式子同时含有加减乘除,乘除会因为语法树在更底层,所以会优先运算。即其在最底层的子节点内,所以需要等待所有子节点进行判断,在进行输出。
具体流程如下:
- 判定当前输出的语法树是否为exp表达式,赋值语句后肯定跟随表达式类型。
- 判定表达式的child结点是否为exp
- 如果为exp结点,则其已经被访问过,则其应该用之间访问过后代表的ti来代表。
- 如果子节点不为exp,则输出其对应变量的值/name。以及对应的操作
3. 具体实现
我们在utlc.c中的printTree函数对于输出语法树的过程中,如果子节点已经完全被递归执行,则其已经到达最底层。获取exp结点的操作符,即加减乘除。
接下来对它的孩子结点的类型进行判断,执行不同的输出。其中用变量count来计数,从1开始,区分不同的ti。
最后再对赋值语句的结点进行判断,如果为赋值语句所产生的结点,则只会是两种状态形如 a:=b 或 a:=exp中其中一种,对其进行分别输出,如果a:=b则此时不会产生新的ti,则count此时等于0,输出name以及其孩子结点的name,如果count不等于0,则将最后的ti (i=count)赋值给tree->attr.name,即将其输出。
下面我们对程序进行测试:
首先对于赋值语句a:=b*c+d进行测试,得出结果如下:
可见符合给定的结果。
以下编写另一个的 TINY+ 测试程序。
\
得出结果如下:
其中复杂语句a:=a*a*c+b*d/a+b+a的翻译如下:
可见结果符合我们所预想的。
至此,我们完成了拓展语言 TINY+ 的语法制导翻译及赋值语句的中间代码生成的实现。
四、实验结论或心得体会
顺利的完成了实验,通过这次实验,我学习和掌握了语法制导翻译和中间代码生成,并根据以上知识完成了对拓展语言TINY+的语法制导翻译及赋值语句的中间代码生成。
这是本课程的最后一个实验,纵观整个学期,我们透过拓展语言TINY+实现了词法分析器、语法分析器等等的内容,对自顶向下的语法分析、自底向上的语法分析程序设计、语法制导翻译和中间代码生成有了更深入的了解,总的来说是一次不错的体验,让我学到了很多有趣的知识。