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

预备知识

源语言->中间代码->目标语言

中间代码(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($1);//输出E1.place
    printf("=");//输出‘=’
    emit($3);//输出E2.place
    printf("\n");
    }

|Exp AND Exp        /*逻辑与运算:需要建立临时变量*/
    {
    $$->t=newtemp();//E.place等于新创建的临时变量
	emit($$);//输出E.place
    printf("=");//输出‘=’
    emit($1);//输出E1.place
    printf("&&");//输出‘&&’
    emit($3);//输出E2.place
    printf("\n");
    }

|Exp OR Exp /*逻辑或运算:需要建立临时变量*/
    {
    $$->t=newtemp();//E.place等于新创建的临时变量
	emit($$);//输出E.place
    printf("=");//输出‘=’
    emit($1);//输出E1.place
    printf("||");//输出‘||’
    emit($3);//输出E2.place
    printf("\n");
    }

    |Exp PLUS Exp       /*加法运算:需要建立临时变量*/
    {
    $$->t=newtemp();//E.place等于新创建的临时变量
emit($$);//输出E.place
    printf("=");//输出‘=’
    emit($1);//输出E1.place
    printf("+");//输出‘+’
    emit($3);//输出E2.place
    printf("\n");
    }

    |Exp MINUS Exp  /*减法运算:需要建立临时变量*/
    {
    $$->t=newtemp();//E.place等于新创建的临时变量
emit($$);//输出E.place
    printf("=");//输出‘=’
    emit($1);//输出E1.place
    printf("-");//输出‘-’
    emit($3);//输出E2.place
    printf("\n");
    }

    |Exp STAR Exp       /*乘法运算:需要建立临时变量*/
    {
    $$->t=newtemp();//E.place等于新创建的临时变量
emit($$);//输出E.place
    printf("=");//输出‘=’
    emit($1);//输出E1.place
    printf("*");//输出‘*’
    emit($3);//输出E2.place
    printf("\n");
    }

    |Exp DIV Exp    /*除法运算:需要建立临时变量*/
    {
        $$->t=newtemp();//E.place等于新创建的临时变量
	emit($$);//输出E.place
        printf("=");//输出‘=’
        emit($1);//输出E1.place
        printf("/");//输出‘/’
        emit($3);//输出E2.place
        printf("\n");
        }

    |ID  /*E->ID,不需要建立临时变量*/
    {
    strcpy($$->id,$1->content);//E.place=ID的名字
	$$->ptag=3;//记录E.place的类型为3
    }

    |INTEGER     /*E->INTEGER,不需要建立临时变量*/
    {
    $$->i=$1->value;//E.place=value
	$$->ptag=1;//记录E.place的类型为1
    }

    |FLOAT      /*E->FLOAT,不需要建立临时变量*/
    {
    $$->f=$1->value;//E.place=value
	$$->ptag=2;//记录E.place的类型为2
    }

/*
*Name:gramtree_v1.y
*Author:WangLin
*Created on:2015-10-03
*Version3.0
*Function:bison语法分析&语义分析&基本表达式的中间代码生成(四元式)
*/
%{
#include<unistd.h>
#include<stdio.h>
# include<string.h>
#include "gramtree_v1.h"
%}

%union{
struct ast* a;
double d;
}
/*declare tokens*/
%token  <a> INTEGER FLOAT
%token <a> TYPE STRUCT RETURN IF ELSE WHILE ID SPACE SEMI COMMA ASSIGNOP RELOP PLUS
MINUS STAR DIV AND OR DOT NOT LP RP LB RB LC RC AERROR
%token <a> EOL
%type  <a> Program ExtDefList ExtDef ExtDecList Specifire StructSpecifire
OptTag  Tag VarDec  FunDec VarList ParamDec Compst StmtList Stmt DefList Def DecList Dec Exp Args

/*priority*/
%right ASSIGNOP
%left OR
%left AND
%left RELOP
%left PLUS MINUS
%left STAR DIV
%right NOT
%left LP RP LB RB DOT
%%
Program:ExtDefList {$$=newast("Program",1,$1);}
	;
ExtDefList:ExtDef ExtDefList {$$=newast("ExtDefList",2,$1,$2);}
	| {$$=newast("ExtDefList",0,-1);}
	;
ExtDef:Specifire ExtDecList SEMI
	{
	$$=newast("ExtDef",3,$1,$2,$3);
	if(exitvar($2))
	printf("Error type 3 at Line %d:Redefined Variable ‘%s‘\n",yylineno,$2->content);
	else newvar(2,$1,$2);
	}
	|Specifire SEMI	{$$=newast("ExtDef",2,$1,$2);}
	|Specifire FunDec Compst
	{
	$$=newast("ExtDef",3,$1,$2,$3);
	 newfunc(4,$1);
	}
	;
ExtDecList:VarDec {$$=newast("ExtDecList",1,$1);}
	|VarDec COMMA ExtDecList {$$=newast("ExtDecList",3,$1,$2,$3);}
	;
/*Specifire*/
Specifire:TYPE {$$=newast("Specifire",1,$1);}
	|StructSpecifire {$$=newast("Specifire",1,$1);}
	;
StructSpecifire:STRUCT OptTag LC DefList RC
	{
	$$=newast("StructSpecifire",5,$1,$2,$3,$4,$5);
	if(exitstruc($2))
		printf("Error type 16 at Line %d:Duplicated name ‘%s‘\n",yylineno,$2->content);
	else newstruc(1,$2);
	}
	|STRUCT Tag {
	$$=newast("StructSpecifire",2,$1,$2);
	if(!exitstruc($2))
	printf("Error type 17 at Line %d:undefined structure ‘%s‘\n",yylineno,$2->content);
	}
	;
OptTag:ID {$$=newast("OptTag",1,$1);}
	|{$$=newast("OptTag",0,-1);}
	;
Tag:ID {$$=newast("Tag",1,$1);}
	;
/*Declarators*/
VarDec:ID {$$=newast("VarDec",1,$1);$$->tag=1;}
	| VarDec LB INTEGER RB {$$=newast("VarDec",4,$1,$2,$3,$4);$$->content=$1->content;$$->tag=4;}
	;
FunDec:ID LP VarList RP
	{$$=newast("FunDec",4,$1,$2,$3,$4);$$->content=$1->content;
	if(exitfunc($1))printf("Error type 4 at Line %d:Redefined Function ‘%s‘\n",yylineno,$1->content);
	else newfunc(2,$1);}
	|ID LP RP
	 {$$=newast("FunDec",3,$1,$2,$3);$$->content=$1->content;
	if(exitfunc($1))printf("Error type 4 at Line %d:Redefined Function ‘%s‘\n",yylineno,$1->content);
        else newfunc(2,$1);}
	;
VarList:ParamDec COMMA VarList {$$=newast("VarList",3,$1,$2,$3);}
	|ParamDec {$$=newast("VarList",1,$1);}
	;
ParamDec:Specifire VarDec {$$=newast("ParamDec",2,$1,$2);newvar(2,$1,$2);newfunc(1);}
    ;

/*Statement*/
Compst:LC DefList StmtList RC {$$=newast("Compst",4,$1,$2,$3,$4);}
	;
StmtList:Stmt StmtList{$$=newast("StmtList",2,$1,$2);}
	| {$$=newast("StmtList",0,-1);}
	;
Stmt:Exp SEMI {$$=newast("Stmt",2,$1,$2);}
	|Compst {$$=newast("Stmt",1,$1);}
	|RETURN Exp SEMI {$$=newast("Stmt",3,$1,$2,$3);
		newfunc(3,$2);}
	|IF LP Exp RP Stmt {$$=newast("Stmt",5,$1,$2,$3,$4,$5);}
	|IF LP Exp RP Stmt ELSE Stmt {$$=newast("Stmt",7,$1,$2,$3,$4,$5,$6,$7);}
	|WHILE LP Exp RP Stmt {$$=newast("Stmt",5,$1,$2,$3,$4,$5);}
	;
/*Local Definitions*/
DefList:Def DefList{$$=newast("DefList",2,$1,$2);}
	| {$$=newast("DefList",0,-1);}
	;
Def:Specifire DecList SEMI {$$=newast("Def",3,$1,$2,$3);
	if(exitvar($2)||exitarray($2))  printf("Error type 3 at Line %d:Redefined Variable ‘%s‘\n",yylineno,$2->content);
        else if($2->tag==4) newarray(2,$1,$2);
	else newvar(2,$1,$2);}
	;
DecList:Dec {$$=newast("DecList",1,$1);}
	|Dec COMMA DecList {$$=newast("DecList",3,$1,$2,$3);$$->tag=$3->tag;}
	;
Dec:VarDec {$$=newast("Dec",1,$1);}
	|VarDec ASSIGNOP Exp {$$=newast("Dec",3,$1,$2,$3);$$->content=$1->content;}
	;
/*Expressions*/
Exp:Exp ASSIGNOP Exp/*E1->ID,不需要建立临时变量*/
	{$$=newast("Exp",3,$1,$2,$3);
    if($1->type!=NULL&&$3->type!=NULL&&strcmp($1->type,$3->type)){printf("Error type 5 at Line %d:Type mismatched for assignment.\n ",yylineno);}
    if($1->tag==3)printf("Error type 6 at Line %d:the left-hand side of an  assignment must be a variable.\n ",yylineno);
    emit($1);//输出E1.place
    printf("=");//输出‘=’
    emit($3);//输出E2.place
    printf("\n");
    }

    |Exp AND Exp /*与运算:需要建立临时变量*/
    {$$=newast("Exp",3,$1,$2,$3);
	$$->t=newtemp();//E.place等于新创建的临时变量
    emit($$);//输出E.place
    printf("=");//输出‘=’
    emit($1);//输出E1.place
    printf("&&");//输出‘&&’
    emit($3);//输出E2.place
    printf("\n");
    }

    |Exp OR Exp/*或运算:需要建立临时变量*/
    {$$=newast("Exp",3,$1,$2,$3);
	$$->t=newtemp();//E.place等于新创建的临时变量
    emit($$);//输出E.place
    printf("=");//输出‘=’
    emit($1);//输出E1.place
    printf("||");//输出‘||’
    emit($3);//输出E2.place
    printf("\n");
    }

    |Exp RELOP Exp{$$=newast("Exp",3,$1,$2,$3);}

    |Exp PLUS Exp/*加法运算:需要建立临时变量*/
    {$$=newast("Exp",3,$1,$2,$3);
	if($1->type!=NULL&&$3->type!=NULL&&strcmp($1->type,$3->type)){printf("Error type 7 at Line %d:Type mismatched for operand.\n ",yylineno);}
	$$->t=newtemp();//E.place等于新创建的临时变量
    emit($$);//输出E.place
    printf("=");//输出‘=’
    emit($1);//输出E1.place
    printf("+");//输出‘+’
    emit($3);//输出E2.place
    printf("\n");
    }

    |Exp MINUS Exp/*减法运算:需要建立临时变量*/
    {$$=newast("Exp",3,$1,$2,$3);
	if($1->type!=NULL&&$3->type!=NULL&&strcmp($1->type,$3->type)){printf("Error type 7 at Line %d:Type mismatched for operand.\n ",yylineno);}
	$$->t=newtemp();//E.place等于新创建的临时变量
    emit($$);//输出E.place
    printf("=");//输出‘=’
    emit($1);//输出E1.place
    printf("-");//输出‘-’
    emit($3);//输出E2.place
    printf("\n");
    }

    |Exp STAR Exp/*乘法运算:需要建立临时变量*/
     {$$=newast("Exp",3,$1,$2,$3);
	if($1->type!=NULL&&$3->type!=NULL&&strcmp($1->type,$3->type)){printf("Error type 7 at Line %d:Type mismatched for operand.\n ",yylineno);}
	$$->t=newtemp();//E.place等于新创建的临时变量
    emit($$);//输出E.place
    printf("=");//输出‘=’
    emit($1);//输出E1.place
    printf("*");//输出‘*’
    emit($3);//输出E2.place
    printf("\n");
    }

    |Exp DIV Exp/*除法运算:需要建立临时变量*/
     {$$=newast("Exp",3,$1,$2,$3);
	if($1->type!=NULL&&$3->type!=NULL&&strcmp($1->type,$3->type)){printf("Error type 7 at Line %d:Type mismatched for operand.\n ",yylineno);}
	$$->t=newtemp();//E.place等于新创建的临时变量
    emit($$);//输出E.place
    printf("=");//输出‘=’
    emit($1);//输出E1.place
    printf("/");//输出‘/’
    emit($3);//输出E2.place
    printf("\n");
    }

    |LP Exp RP{$$=newast("Exp",3,$1,$2,$3);}
	|MINUS Exp {$$=newast("Exp",2,$1,$2);}
    |NOT Exp {$$=newast("Exp",2,$1,$2);}
    |ID LP Args RP {$$=newast("Exp",4,$1,$2,$3,$4);
	if((!exitfunc($1))&&(exitvar($1)||exitarray($1)))printf("Error type 11 at Line %d:‘%s‘is not a function.\n ",yylineno,$1->content);
	else if(!exitfunc($1)){printf("Error type 2 at Line %d:undefined Function %s\n ",yylineno,$1->content);}
	else if(pnumfunc($1)!=rpnum)printf("Error type 9 at Line %d:parameters num mismatched for function: %s\n ",yylineno,$1->content);}
    |ID LP RP {$$=newast("Exp",3,$1,$2,$3);}
    |Exp LB Exp RB
	{$$=newast("Exp",4,$1,$2,$3,$4);
	if(strcmp($3->type,"int"))printf("Error type 12 at Line %d:%.1f is not a integer.\n",yylineno,$3->value);
	if((!exitarray($1))&&(exitvar($1)||exitfunc($1)))printf("Error type 10 at Line %d:‘%s‘is not an array.\n ",yylineno,$1->content);
    else if(!exitarray($1)){printf("Error type 2 at Line %d:undefined Array %s\n ",yylineno,$1->content);}}
    |Exp DOT ID
	{$$=newast("Exp",3,$1,$2,$3);if(!exitstruc($1))printf("Error type 13 at Line %d:Illegal use of ‘.‘.\n",yylineno);}

    |ID /*E->ID,不需要建立临时变量*/
    {$$=newast("Exp",1,$1);
	if(!exitvar($1)&&!exitarray($1))
	{printf("Error type 1 at Line %d:undefined variable %s\n ",yylineno,$1->content);}
	else $$->type=typevar($1);
    strcpy($$->id,$1->content);//E.place=ID的名字
	$$->ptag=3;//记录E.place的类型为3
    }

    |INTEGER /*E->INTEGER,不需要建立临时变量*/
    {$$=newast("Exp",1,$1);$$->tag=3;$$->type="int";
	$$->i=$1->value;//E.place=value
    $$->ptag=1;//记录E.place的类型为1
    }

    |FLOAT/*E->FLOAT,不需要建立临时变量*/
    {$$=newast("Exp",1,$1);$$->tag=3;$$->type="float";$$->value=$1->value;
    $$->f=$1->value;//E.place=value
	$$->ptag=2;//记录E.place的类型为2
    }
    ;

Args:Exp COMMA Args {$$=newast("Args",3,$1,$2,$3);rpnum+=1;}
    |Exp {$$=newast("Args",1,$1);rpnum+=1;}
    ;
%%

四、 【实验结果】

1.输入内容: test1.c的内容如下:

[[email protected] IR]# cat test1.c
int main()
{
float x;
float y;
float z;
x=1.5;
y=1.6;
z=x+y;
z=x-y;
z=x*y;
z=x/y;
z=x&&y;
z=x||y;

z=x+y-1.0-2.0/y;
z=x*2.5+x*y-x/2.0;

z=x||y+x&&y;
}

2.输出内容:注释和空行都是为了直观加上的,不是输出的一部分。

[[email protected] IR]# cat test1.c|./a.out
x=1.500000      /*对应x=1.5;*/
y=1.600000      /*对应y=1.6;*/    

t0=x+y          /*对应z=x+y;*/
z=t0

t1=x-y          /*对应z=x-y;*/
z=t1

t2=x*y          /*对应z=x*y;*/
z=t2

t3=x/y          /*对应z=x/y;*/
z=t3

t4=x&&y     /*对应z=x&&y;*/
z=t4

t5=x||y         /*对应z=x||y;*/
z=t5

t6=x+y          /*对应z=x+y-1.0-2.0/y;*/
t7=t6-1.000000
t8=2.000000/y
t9=t7-t8
z=t9

t10=x*2.500000      /*对应z=x*2.5+x*y-x/2.0;*/
t11=x*y
t12=t10+t11
t13=x/2.000000
t14=t12-t13
z=t14

t15=y+x             /*对应z=x||y+x&&y;*/
t16=t15&&y
t17=x||t16
z=t17

3.实验结果分析:

1)从输出结果可以看出,程序正确处理了E->ID,E->常数,E->E1操作符E2的各种情况;E->ID时,输出的E.place就是ID的名字,E->常数时输出的E.place就是常数的值,如表达式x=1.5和y=1.6。E->E1操作符E2时,E.place是临时变量名。

2)正确处理表达式中的优先级。

如 z=x*2.5+x*y-x/2.0;由于乘法和除法的优先级高于加法和减法,因此先对乘法和除法进行计算,最后算加和减。对于表达式z=x||y+x&&y;由于加减的优先级高于逻辑与和逻辑或,因此程序先计算加和减,再计算逻辑与和逻辑或。

3)正确处理了临时变量的编号。

五、【实验总结】

1.place的设置—Union的舍弃

由于place的数据类型可能有4种,但这4种并不是同时出现的,一次只是一种类型,这和Union(共同体)的思想恰好一致,因此一开始想把place应该是一个Union。

union

{

int i;//Integer

float f;//FLOAT

char id[30];//变量名ID

int t;//临时变量t编号

}place;

但在实践的过程中,union导致了内存的错乱(具体什么原因,过后还需要研究),因此只能将union舍弃掉,4种类型都直接设置为语法树结点的成员,这样一来可能浪费了空间,但是能保证代码的正确性。

2.临时变量编号数组used[]的使用

used[]的使用是一个比较巧妙的设计,既不占用空间,操作也很简单,但是这只是针对于本次实验只对基本表达式进行翻译的设计,如果提升实验难度,要求对语句等进行翻译,这种设计多半是行不通的,需要再寻求一种更强大更健壮的设计。

时间: 2024-07-30 23:52:36

编译原理——中间代码生成的相关文章

编译原理实验代码(词法分析,语法分析,中间代码生成)

花了一天写出的程序没有顾及很多层面,但对于理解基本的实验道理和交上实验还是有点帮助的.代码实现了基于有限自动机的词法分析,采用递归下降分析法和EBNF文法实现语法分析并生成中间代码. lexAnalysis.h /* * lexAnalysis.h * * Created on: 2014-12-2 * Author: liuqiushan */ #ifndef LEXANALYSIS_H_ #define LEXANALYSIS_H_ #include <stdio.h> #include

编译原理123

1.编译原理就是什么? 个人理解,编译就是像翻译一样,将一种语言翻译成另一种语言,编译就是将高级语言或汇编语言翻译成电脑能识别的二进制机器语言,编译原理就是讲解这 个编译的过程.内容包括语言和文法.词法分析.语法分析.语法制导翻译.中间代码生成.存储管理.代码优化和目标代码生成. 编译原理是计算机专业设置的一门重要的专业课程.虽然只有少数人从事编译方面的工作,但是这门课在理论.技术.方法上都对学生提供了系统而有效的训练,有 利于提高软件人员的素质和能力. 2.学习编译原理有什么好处? 学习编译原

编译原理的理解

编译原理内容包括语言和文法.词法分析.语法分析.语法制导翻译.中间代码生成.存储管理.代码优化和目标代码生成.大一点的应用可以做到一定的技术先进性,从而让你在本行业站稳脚跟:分析和分解用户输入的SQL语句,理解是否有害和是否有SQL注入等.如果不学,对于不是不是本行业的人来说就没损失,如果是本行业的专业人士,不学只会令自己的编译理解更慢.

编译原理简单介绍

编译原理学习导论 大学课程为什么要开设编译原理呢?这门课程关注的是编译器方面的产生原理和技术问题,似乎和计算机的基础领域不沾边,可是编译原理却一直作为大学本科的必修课程,同时也成为了研究生入学考试的必考内容.编译原理及技术从本质上来讲就是一个算法问题而已,当然由于这个问题十分复杂,其解决算法也相对复杂.我们学的数据结构与算法分析也是讲算法的,不过讲的基础算法,换句话说讲的是算法导论,而编译原理这门课程讲的就是比较专注解决一种的算法了.在20世纪50年代,编译器的编写一直被认为是十分困难的事情,第

python实现算术表达式的词法语法语义分析(编译原理应用)

本学期编译原理的一个大作业,我的选题是算术表达式的词法语法语义分析,当时由于学得比较渣,只用了递归下降的方法进行了分析. 首先,用户输入算术表达式,其中算术表达式可以包含基本运算符,括号,数字,以及用户自定义变量. 词法分析,检查单词变量是否正确:语法分析,检查算术表达式语法是否正确并输出生成语法树:语义分析,输出四元表达式. 最终效果图: 例如输入: 词法分析结果: 语法分析结果: 语义分析结果: 算术表达式的组成语法如下: 无符号整数 = 〈数字〉{〈数字〉} 〈标识符〉= 〈字母〉{〈字母

编译原理随笔

最近初步接触到了编译原理这门课程,通过老师提供的一些链接,以及课上的知识,对这门课有了一些认识与了解. 编译原理旨在介绍编译程序构造的一般原理和基本方法.内容包括语言和文法.词法分析.语法分析.语法制导翻译.中间代码生成.存储管理.代码优化和目标代码生成.从源语言提取需要的信息:把源语言翻译成目标语言:自动生成满足一定规范的文本... 学习编译原理可以更加容易的理解在一个语言种哪些写法是等价的,哪些是有差异的可以更加客观的比较不同语言的差异,更不容易被某个特定语言的宣扬者忽悠,学习新的语言是效率

编译原理之我见

经过网上的调查,我发现编译原理并不像我所想象的那样简单,我以为编译原理其实就是像塑造一个翻译师一样,赋予它翻译的架构即可,但是经过调查后,结果却不是我所想,编译原理就是将高级语言翻译成计算机语言(即计算机所能识别的二进制代码)所遵守的规律,让电脑可以懂得高级语言所能表达的东西,内容包括语言和文法,词法分析,语法分析,语法制导编译,中间代码生成,存储管理,代码优化和目标代码生成.编辑原理是计算机专业的一门重要课,旨在介绍编译程序构造的一般原理和方法.编译原理及技术从本质上来讲就是一个算法问题而已,

学习编译原理

刚刚进入大二,初学习到编译原理,一门新的技术,而且学习起来会比较抽象,不过好在大一曾学习到VC这一门东西,在学习此门课程之前,已在网上了解到不少学习这门课该提前遇到道德东西,也了解到很多人学习这门课的问题,在他们的经验中知道了不少学习方法,希望自己能在日后中用得上.例如这个就觉得很不错:删繁就简,避重就轻.网上流传较广的一篇<编译原理学习导论>(作者四川大学唐良)就基本是这种思路,对于词法分析,作者避免了自动机理论和集合论推演的介绍,直接搬出源码来,大大降低了理解难度,对于语法分析,作者介绍了

对编译原理的看法

1.编译原理是什么? 编译原理是一门可以用于介绍编译程序构造的一般原理和基本方法的专业课. 内容包括语言和文法.词法分析.语法分析.语法制导翻译.中间代码生成.存储管理.代码优化和目标代码生成. 2.学习编译原理有什么好处? 可以加深对不同语言的理解,对不同语言的差异能够更加清楚的体会出来. 在学习了编译原理之后,对新的语言的学习能更加有效率,另外对语言的转化也更加游刃有余. 对语言的认识会更加深刻,不会轻易被其他语言混乱思维. 3.不学有什么损失? 相对而言,也就是如若不学习编译原理的话,那么