实验五编译用语法制导方式生成中间代码生成器.docx
- 文档编号:4433514
- 上传时间:2022-12-01
- 格式:DOCX
- 页数:16
- 大小:162.72KB
实验五编译用语法制导方式生成中间代码生成器.docx
《实验五编译用语法制导方式生成中间代码生成器.docx》由会员分享,可在线阅读,更多相关《实验五编译用语法制导方式生成中间代码生成器.docx(16页珍藏版)》请在冰豆网上搜索。
实验五编译用语法制导方式生成中间代码生成器
实验5用语法制导方式生成中间代码生成器
一、实验目的
掌握语法制导定义和翻译的原理和技术,在语法分析器的基础上,加上语义分析,构造一个中间代码生成器。
二、实验内容
在实验四生成的语法分析器基础上加入语义动作,将源程序翻译为对应的中间代码序列。
三、实验要求
1.个人完成,提交实验报告。
实验报告必须包括设计的思路,以及测试报告(输入测试例子,输出结果)。
2.实验报告中给出采用测试源代码片断,及其对应的三地址码形式(内部表示形式可以自行考虑)。
例如,程序片断
对应的中间代码为:
四、实验过程
本次实验运用flex和bison工具进行中间代码的生成。
并自动生成中间代码。
1.首先创建一个example文件夹,该文件夹中包含有flex.exe
2.用文本编译器编辑相应的flex文件mylex.l,此次mylex.l可以在上次实验的l文件上做一些修改,再利用flex将l文件生成相应的lex.yy.c程序,mylex.l的代码如下所示:
mylex.l
%{
#include"myyacc.tab.h"
%}
delim[\t\n\r]
ws{delim}+
letter[A-Za-z]
digit[0-9]
id{letter}({letter}|{digit})*
integer{digit}+
exponentE[+-]?
{integer}
number{integer}{exponent}?
realinteger(\.integer)?
{exponent}?
%optionnoyywrap
%%
"<"|"<="|">"|">="|"!
="|"=="{filloperator(&yylval,yytext);return(REL);}
if{return(IF);}
else{return(ELSE);}
while{return(WHILE);}
do{return(DO);}
for{return(FOR);}
switch{return(SWITCH);}
case{return(CASE);}
default{return(DEFAULT);}
break{return(BREAK);}
true{return(TRUE);}
false{return(FALSE);}
int{return(INT);}
long{return(LONG);}
char{return(CHAR);}
bool{return(BOOL);}
float{return(FLOAT);}
double{return(DOUBLE);}
"&&"{return(AND);}
"||"{return(OR);}
"!
"{return('!
');}
"++"{return(INC);}
"--"{return(DEC);}
"+"{return('+');}
"-"{return('-');}
"*"{return('*');}
"/"{return('/');}
"="{return('=');}
"{"{return('{');}
"}"{return('}');}
"["{return('[');}
"]"{return(']');}
"("{return('(');}
")"{return(')');}
";"{return(';');}
{ws}{}
{id}{filllexeme(&yylval,yytext);return(ID);}
{number}{filllexeme(&yylval,yytext);return(NUMBER);}
{real}{filllexeme(&yylval,yytext);return(REAL);}
%%
在代码中,先定义正则定义,即对letter,digit,专用符号,空格进行声明;接着在转换规则中,定义一些识别规则的代码。
完成词法分析后,就可以将获取的每一个词素用于语法分析器使用。
将mylex.l与myyacc.y相结合的方法是在每获得一个词素,则用return语句返回,即如果获得的是if,则return(if),并且在头文件中加入#include"myYacc.tab.h",则在myyacc中定义的类型在mylex中可利用,否则会出现返回的单元未定义的错误。
3.用文本编译器编辑相应的bison文件myyacc.y,myyacc.y文件中,在每个生成式后加上语法制导翻译,主要是依据truelist和falselist来实现回填功能。
编写完后,在myyacc.y中以头文件的方式加入自己编写的myyacc.h文件,编译即可。
Myyacc.y的代码如下所示:
Myyacc.y
%{
#include"myyacc.h"
#defineYYSTYPEnode
#include"myyacc.tab.h"
intyyerror();
intyyerror(char*msg);
externintyylex();
codelist*list;
%}
%tokenBASICNUMBERREALIDTRUEFALSE
%tokenINTLONGCHARBOOLFLOATDOUBLE
%tokenREL
%tokenIFELSEWHILEDOBREAKFORSWITCHCASEDEFAULT
%tokenORAND
%leftOR
%leftAND
%right'!
'
%left'+''-'
%left'*''/'
%rightUMINUS
%rightINCDEC
%%
program:
block{}
;
block:
'{'declsstatementlist'}'{}
;
decls:
declsdecl{}
|{}
;
decl:
typeID';'{}
;
type:
type'['NUMBER']'{}
|BASIC{}
;
statementlist:
statementlistMstatement{backpatch(list,$1.nextlist,$2.instr);
$$.nextlist=$3.nextlist;}
|statement{$$.nextlist=$1.nextlist;}
;
Statement:
IF'('boolean')'MstatementELSENMstatement{backpatch(list,$3.truelist,$5.instr);
backpatch(list,$3.falselist,$9.instr);
$6.nextlist=merge($6.nextlist,$8.nextlist);
$$.nextlist=merge($6.nextlist,$10.nextlist);}
|IF'('boolean')'Mstatement{backpatch(list,$3.truelist,$5.instr);
$$.nextlist=merge($3.falselist,$6.nextlist);}
|WHILEM'('boolean')'Mstatement{backpatch(list,$7.nextlist,$2.instr);
backpatch(list,$4.truelist,$6.instr);
$$.nextlist=$4.falselist;
gen_goto(list,$2.instr);}
|DOMstatementMWHILE'('boolean')'M';'{backpatch(list,$3.nextlist,$4.instr);
backpatch(list,$7.truelist,$9.instr);
$$.nextlist=$7.falselist;
gen_goto(list,$2.instr);}
|FOR'('assignment';'Mboolean';'Massignment')'NMstatement{backpatch(list,$6.truelist,$12.instr);
backpatch(list,$11.nextlist,$5.instr);
backpatch(list,$13.nextlist,$8.instr);
$$.nextlist=$6.falselist;
gen_goto(list,$8.instr);}
|BREAK';'{}
|'{'statementlist'}'{$$.nextlist=$2.nextlist;}
|assignment';'{$$.nextlist=NULL;}
;
assignment:
ID'='boolean{copyaddr(&$1,$1.lexeme);gen_assignment(list,$1,$3);}
;
loc:
loc'['boolean']'{}
|ID{copyaddr(&$$,$1.lexeme);}
;
boolean:
booleanORMboolean{backpatch(list,$1.falselist,$3.instr);
$$.truelist=merge($1.truelist,$4.truelist);
$$.falselist=$4.falselist;}
|booleanANDMboolean{backpatch(list,$1.truelist,$3.instr);
$$.truelist=$4.truelist;
$$.falselist=merge($1.falselist,$4.falselist);}
|'!
'boolean{$$.truelist=$1.falselist;
$$.falselist=$1.truelist;}
|'('boolean')'{$$.truelist=$1.truelist;
$$.falselist=$1.falselist;}
|expressionRELexpression{$$.truelist=new_instrlist(nextinstr(list));
$$.falselist=new_instrlist(nextinstr(list)+1);
gen_if(list,$1,$2.oper,$3);
gen_goto_blank(list);}
|TRUE{copyaddr(&$$,"TRUE");
gen_goto_blank(list);}
|FALSE{copyaddr(&$$,"FALSE");
gen_goto_blank(list);}
|expression{copyaddr_fromnode(&$$,$1);}
;
M:
{$$.instr=nextinstr(list);}
;
N:
{$$.nextlist=new_instrlist(nextinstr(list));
gen_goto_blank(list);}
;
expression:
expression'+'expression{new_temp(&$$,get_temp_index(list));gen_3addr(list,$$,$1,"+",$3);}
|expression'-'expression{new_temp(&$$,get_temp_index(list));gen_3addr(list,$$,$1,"-",$3);}
|expression'*'expression{new_temp(&$$,get_temp_index(list));gen_3addr(list,$$,$1,"*",$3);}
|expression'/'expression{new_temp(&$$,get_temp_index(list));gen_3addr(list,$$,$1,"/",$3);}
|'-'expression%precUMINUS{new_temp(&$$,get_temp_index(list));gen_2addr(list,$$,"-",$2);}
|loc{copyaddr_fromnode(&$$,$1);}
|NUMBER{copyaddr(&$$,$1.lexeme);}
|REAL{copyaddr(&$$,$1.lexeme);}
;
%%
intyyerror(char*msg)
{
printf("\nERRORwithmessage:
%s\n",msg);
return0;
}
intmain()
{
list=newcodelist();
freopen("text.in","rt+",stdin);
freopen("text.out","wt+",stdout);
yyparse();
print(list);
fclose(stdin);
fclose(stdout);
return0;
}
在代码中,先定义一些头文件,externintyylex();externintyyerror();这两个语句是必须的,引用全局变量是为了能够使用之前词法分析器所获取的词素。
并且调用一个yyerror函数用来当发生错误时能够报告错误。
接着定义一些终结符号,比如说%tokenNUM。
yacc规定每个终结符都有一个唯一的编号(tokennumber)。
当我们用上面的方式定义终结符时,终结符的编号由yacc内部决定,其编号规则是从257开始依次递增,每次加1。
为了能够联合词法分析器和语法分析器,词法分析程序名字必须是yylex,调法分析程序向语法分析程序提供当前输入的单词符号。
yylex提供给yyparse的不是终结符本身,而是终结符的编号,即tokennumber,如果当前的终结符有语义值,yylex必须把它赋给yylval。
接着是翻译规则部分,这个翻译规则由一个文法产生式和一个相关联的语义动作组成,在这里在每个生成式后边加上语法制导翻译以实现回填的功能。
4.另外编写一个头文件myyacc.h将其加入到myyacc.y文件中去
文件如下所示:
Myyacc.h
#ifndefCP_H
#defineCP_H
#include
#include
#include
typedefstructlistele
{
intinstrno;
structlistele*next;
}listele;
listele*new_listele(intno)
{
listele*p=(listele*)malloc(sizeof(listele));
p->instrno=no;
p->next=NULL;
returnp;
}
typedefstructinstrlist
{
listele*first,*last;
}instrlist;
instrlist*new_instrlist(intinstrno)
{
instrlist*p=(instrlist*)malloc(sizeof(instrlist));
p->first=p->last=new_listele(instrno);
returnp;
}
instrlist*merge(instrlist*list1,instrlist*list2)
{
instrlist*p;
if(list1==NULL)p=list2;
else
{
if(list2!
=NULL)
{
if(list1->last==NULL)
{
list1->first=list2->first;
list1->last=list2->last;
}elselist1->last->next=list2->first;
list2->first=list2->last=NULL;
free(list2);
}
p=list1;
}
returnp;
}
typedefstructnode
{
instrlist*truelist,*falselist,*nextlist;
charaddr[256];
charlexeme[256];
charoper[3];
intinstr;
}node;
intfilloperator(node*dst,char*src)
{
strcpy(dst->oper,src);
return0;
}
intfilllexeme(node*dst,char*yytext)
{
strcpy(dst->lexeme,yytext);
return0;
}
intcopyaddr(node*dst,char*src)
{
strcpy(dst->addr,src);
return0;
}
intnew_temp(node*dst,intindex)
{
sprintf(dst->addr,"t%d",index);
return0;
}
intcopyaddr_fromnode(node*dst,nodesrc)
{
strcpy(dst->addr,src.addr);
return0;
}
typedefstructcodelist
{
intlinecnt,capacity;
inttemp_index;
char**code;
}codelist;
codelist*newcodelist()
{
codelist*p=(codelist*)malloc(sizeof(codelist));
p->linecnt=0;
p->capacity=1024;
p->temp_index=0;
p->code=(char**)malloc(sizeof(char*)*1024);
returnp;
}
intget_temp_index(codelist*dst)
{
returndst->temp_index++;
}
intnextinstr(codelist*dst){returndst->linecnt;}
intGen(codelist*dst,char*str)
{
if(dst->linecnt>=dst->capacity)
{
dst->capacity+=1024;
dst->code=(char**)realloc(dst->code,sizeof(char*)*dst->capacity);
if(dst->code==NULL)
{
printf("shortofmemeory\n");
return0;
}
}
dst->code[dst->linecnt]=(char*)malloc(strlen(str)+20);
strcpy(dst->code[dst->linecnt],str);
dst->linecnt++;
return0;
}
chartmp[1024];
intgen_goto_blank(codelist*dst)
{
sprintf(tmp,"goto");
Gen(dst,tmp);
return0;
}
intgen_goto(codelist*dst,intinstrno)
{
sprintf(tmp,"goto%d",instrno);
Gen(dst,tmp);
return0;
}
intgen_if(codelist*dst,nodeleft,char*op,noderight)
{
sprintf(tmp,"if%s%s%sgoto",left.addr,op,right.addr);
Gen(dst,tmp);
return0;
}
intgen_1addr(codelist*dst,nodeleft,char*op)
{
sprintf(tmp,"%s%s",left.addr,op);
Gen(dst,tmp);
return0;
}
intgen_2addr(codelist*dst,nodeleft,char*op,noderight)
{
sprintf(tmp,"%s=%s%s",left.addr,op,right.addr);
Gen(dst,tmp);
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 实验 编译 用语 法制 方式 生成 中间 代码 生成器