编译原理——中间代码生成

预备知识

源语言->中间代码->目标语言
中间代码(Intermediate Representation或者IR):复杂性介于源程序语言和机器语言的一种表示形式。


编译程序锁使用的中间代码有多种形式。常见的有逆波兰记号,三元式。四元式。和树形表示。四元式是一种普遍採用的中间代码形式,非常相似于三地址指令,有时把这类中间表示称为“三地址代码”,这样的表示能够看作是一种虚拟三地址机的通用汇编码,每条”指令“包括操作符和三个地址,两个是为运算对象的,一个是为结果的。
基本表达式的翻译模式:
(1)
Exp:Exp ASSIGNOP Exp
|Exp AND Exp
|Exp OR Exp
|Exp PLUS Exp
|Exp MINUS Exp
|Exp STAR Exp
|Exp DIV Exp
|ID
|INTEGER
|FLOAT
;
分析:
(1)要给每个语法树结点添加一个place属性,这个place属性的值依据下面规则计算。
1)假设EXP->ID,不须要为ID建立暂时变量,place的值就等于变量ID的名字;
2)假设EXP->INTEGER|FLOAT,即推出常数。不须要为常数建立暂时变量,place的值就等于常数值。
3)E->E1=E2,E1->ID

emit($1);printf("=");emit($3);

step1:输出ID;
step2:输出=
step3:输出E2.place

4)i+1;E->E1+E2。newtemp,建立一个暂时变量,E.place=E1.place+E2.place,

$$>t=newtemp();//创建暂时变量
emit($$);//输出创建E.place
printf("=");//输出=
emit($1);//输出E1.place
printf("+");//输出+
emit($3);//输出E2.place

也就是说,在语法树的叶子结点存在两种place,一种是ID,即变量名,一种是整数或者浮点数。这两种place值都和暂时变量无关,不须要建立暂时变量的操作。
place的值相应到四元式中:
1)常数
2)源程序中变量名ID
3)为生成四元式而建立的暂时变量名。


方法一:变量名採用t加上数字的形式。为全部的暂时变量名创建一个符号表,记其在符号表中的位置,这个位置是一个在整数v。从0開始。输出时,输出’t’+v,就能够输出t0,t1这样的形式,并且有效地避免了变量名的反复。
方法二:直接将place设置成整数类型,再设置一个标记数组used[],用了一个整数i。就在标记数组中将used[i]=-1,表示ti已经被用过了。这样一来。创建一个暂时变量。相当于设置place的值,然后更改used[]数组的值。

place应该是一个Union,有3种可能值。
1)int i(相应INTEGER)
2)char* (相应变量名ID)
3)float (相应FLOAT)
4)int t;相应暂时变量编号
为了能识别place的值是4种中哪一种,再为语法树结点增添一个ptag,1为int,2为float。3为char,4为暂时变量编号。

union
{
int i;
char* s;
float f;
}place;
int tag;//标志位

int main()
{
place.s="ID";
tag=1;
if(tag==1)
printf("%s",place);
}

除了EXP->ID,EXP->常数,每一条基本表达式规则要有一个输出四元式的操作,emit。

代码更改:
因为用union导致了内存的错乱(详细什么原因,过后还须要研究),因此将union去掉,4种类型都设置为语法树结点的成员。这样一来可能浪费了空间,可是能保证代码的正确性。

一、【实验目的】

通过在词法分析。语法分析和语义分析程序的基础上,将C—源码翻译成中间代码。认识中间代码的表示形式和生成中间代码的原理和技巧。掌握对简单赋值语句的翻译过程。从而达到对编译器的编译原理有更深的理解。提高代码能力和代码修养。

二、【实验任务】

在词法分析,语法分析和语义分析程序的基础上。将C—源码翻译成中间代码,中间代码的表示採用四元式,本实验中仅仅对基本表达式进行翻译,即将下面规则翻译成四元式:表达式赋值语句,两个表达式的逻辑与,逻辑或,加。减,乘。除。

Exp:Exp ASSIGNOP Exp 
|Exp AND Exp 
|Exp OR Exp 
|Exp PLUS Exp 
|Exp MINUS Exp 
|Exp STAR Exp 
|Exp DIV Exp 
|ID 
|INTEGER 
|FLOAT 
;

三、【实验程序】

1,程序的编译说明

(1)程序总共包括4个文件gramtree_v1.h gramtree_v1.c gramtree.l gramtree_v1.y
gramtree_v1.h gramtree_v1.c定义和实现了:
1)语法树结构体,语法树创建函数,语法树遍历函数
2)变量符号表结构体,变量符号表的建立函数,查找变量是否已定义的函数。查找变量类型的函数
3)函数符号表结构体,函数符号表的建立函数,查找函数是否已定义。查找函数类型,查找函数形參个数。
4)数组符号表,数组符号表的建立函数,查找数组是否已定义的函数,查找数组类型的函数
5)结构体符号表,结构体符号表的建立函数,查找结构体是否已定义的函数
6)关于生成中间表达式的2个函数:newtemp()和emit()。newtemp生成了一个暂时变量,emit将一个语法结点的place属性输出到屏幕。
(2)gramtree.l是flex词法分析模块
(3)gramtree_v1.y是bison语法分析模块。


在bison文件里。在相应的变量定义,函数定义,数组定义 ,结构体定义,变量调用,函数调用,数组调用。结构体调用相应的语法规则中,建立或者查询相应的符号表。实现语义分析和特定错误的检測 然后输出错误类型和错误行号。


(4)编译时使用Makefile文件:
1)编写Makefile文件内容,运行:vim Makefile

2,实验分析

(1)要给每个语法树结点添加一个place属性,这个place属性的值依据下面规则计算。
1)假设EXP->ID,不须要为ID建立暂时变量。place的值就等于变量ID的名字。
2)假设EXP->INTEGER|FLOAT,即推出常数,不须要为常数建立暂时变量。place的值就等于常数值。
3)对于规则E->E1=E2,(E1->ID), E->E1&&E2。E->E1||E2,E->E1+E2。E->E1-E2,E->E1*E2,E->E1/E2:
step1:生成一个暂时变量.
暂时变量的名字符合t加上一个数字的表示形式,E.place的值就等于生成的暂时变量;
step2:输出E.place->输出E1.place->输出操作符->输出E2.place。
这样就完毕了一条四元式的生成和输出。

(2)属性place的设置
在语法树的叶子结点存在两种place,一种是ID。即变量名;还有一种是整数或者浮点数,这两种place值都和暂时变量无关。不须要建立暂时变量的操作。
place的值相应到四元式中。有下面3种情况:
1)常数
2)源程序中变量名ID
3)为生成四元式而建立的暂时变量名。

生成暂时变量的方法
直接将place设置成整数类型。再设置一个标记数组used[],用了一个整数i。就在标记数组中将used[i]=-1,表示ti已经被用过了。这样一来,创建一个暂时变量,相当于设置place的值,然后更改used[]数组的值。
于是place的数据类型有下面3种可能值。


1)int i(相应INTEGER)
2)char* (相应变量名ID)
3)float (相应FLOAT)
4)int t;相应暂时变量编号
为了能识别place的值是4种中哪一种,再为语法树结点增添一个ptag,1为int,2为float,3为char,4为暂时变量编号。

3,实验代码

(1)在语法树结点中添加下面5个成员:place的4种数据类型。和一个用以标志类型的整型变量ptag。

struct ast
{
/*用于生成中间代码的变量,place的4种类型,*/
    int i;//Integer
    float f;//FLOAT
    char id[30];//变量名ID
    int t;//暂时变量t编号

    int ptag;//用以标志place的类型1,2,3,4
}

(2)生成暂时变量的函数newtemp()和输出E.place的函数emit()

/*关于中间代码的实现函数:创建暂时变量&输出四元式*/
int newtemp()//创建暂时变量
{
    int i=0;
    for(i=0; i<100; ++i)//在used[]中找到一个没有被用过的编号
    {
        if(used[i]==0)
        {
            used[i]=i+1;
            return i;//返回的编号就是t的编号
        }
    }
}

void emit(struct ast* tp)//输出四元式
{
    if(tp->ptag==1)//place的值是INTEGER
        printf("%d",tp->i);
    else if(tp->ptag==2)
        printf("%2f",tp->f);//place的值是FLOAT
    else if(tp->ptag==3)
        printf("%s",tp->id);//place的值是ID变量名字
    else//place的值是暂时变量编号
        printf("t%d",tp->t);
}

(3)在基本表达式的语义规则中添加:

/*Expressions*/
Exp:Exp ASSIGNOP Exp        /*E1->ID,不须要建立暂时变量*/
{
emit(
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值