实验五编译用语法制导方式生成中间代码生成器Word格式文档下载.docx
《实验五编译用语法制导方式生成中间代码生成器Word格式文档下载.docx》由会员分享,可在线阅读,更多相关《实验五编译用语法制导方式生成中间代码生成器Word格式文档下载.docx(16页珍藏版)》请在冰豆网上搜索。
="
>
!
=="
{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);
+"
+'
);
-"
-'
*"
*'
/"
/'
='
{"
{'
}"
}'
["
['
]"
]'
("
('
)"
)'
;
{ws}{}
{id}{filllexeme(&
return(ID);
{number}{filllexeme(&
return(NUMBER);
{real}{filllexeme(&
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
myyacc.h"
#defineYYSTYPEnode
intyyerror();
intyyerror(char*msg);
externintyylex();
codelist*list;
%tokenBASICNUMBERREALIDTRUEFALSE
%tokenINTLONGCHARBOOLFLOATDOUBLE
%tokenREL
%tokenIFELSEWHILEDOBREAKFORSWITCHCASEDEFAULT
%tokenORAND
%leftOR
%leftAND
%right'
%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'
Mstatement{backpatch(list,$3.truelist,$5.instr);
$$.nextlist=merge($3.falselist,$6.nextlist);
|WHILEM'
Mstatement{backpatch(list,$7.nextlist,$2.instr);
backpatch(list,$4.truelist,$6.instr);
$$.nextlist=$4.falselist;
gen_goto(list,$2.instr);
|DOMstatementMWHILE'
M'
{backpatch(list,$3.nextlist,$4.instr);
backpatch(list,$7.truelist,$9.instr);
$$.nextlist=$7.falselist;
|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'
|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;
{$$.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"
|FALSE{copyaddr(&
FALSE"
|expression{copyaddr_fromnode(&
$$,$1);
M:
{$$.instr=nextinstr(list);
N:
{$$.nextlist=new_instrlist(nextinstr(list));
expression:
expression'
expression{new_temp(&
$$,get_temp_index(list));
gen_3addr(list,$$,$1,"
$3);
|expression'
expression%precUMINUS{new_temp(&
gen_2addr(list,$$,"
$2);
|loc{copyaddr_fromnode(&
|NUMBER{copyaddr(&
|REAL{copyaddr(&
intyyerror(char*msg)
{
printf("
\nERRORwithmessage:
%s\n"
msg);
return0;
}
intmain()
list=newcodelist();
freopen("
text.in"
"
rt+"
stdin);
text.out"
wt+"
stdout);
yyparse();
print(list);
fclose(stdin);
fclose(stdout);
在代码中,先定义一些头文件,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<
stdio.h>
string.h>
malloc.h>
typedefstructlistele
intinstrno;
structlistele*next;
}listele;
listele*new_listele(intno)
{
listele*p=(listele*)malloc(sizeof(listele));
p->
instrno=no;
next=NULL;
returnp;
typedefstructinstrlist
listele*first,*last;
}instrlist;
instrlist*new_instrlist(intinstrno)
instrlist*p=(instrlist*)malloc(sizeof(instrlist));
first=p->
last=new_listele(instrno);
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;
last=list2->
last;
}elselist1->
last->
next=list2->
list2->
last=NULL;
free(list2);
}
p=list1;
}
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)
lexeme,yytext);
intcopyaddr(node*dst,char*src)
addr,src);
intnew_temp(node*dst,intindex)
sprintf(dst->
addr,"
t%d"
index);
intcopyaddr_fromnode(node*dst,nodesrc)
addr,src.addr);
typedefstructcodelist
intlinecnt,capacity;
inttemp_index;
char**code;
}codelist;
codelist*newcodelist()
codelist*p=(codelist*)malloc(sizeof(codelist));
linecnt=0;
capacity=1024;
temp_index=0;
code=(char**)malloc(sizeof(char*)*1024);
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;
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);
linecnt],str);
linecnt++;
chartmp[1024];
intgen_goto_blank(codelist*dst)
sprintf(tmp,"
goto"
Gen(dst,tmp);
intgen_goto(codelist*dst,intinstrno)
goto%d"
instrno);
intgen_if(codelist*dst,nodeleft,char*op,noderight)
if%s%s%sgoto"
left.addr,op,right.addr);
intgen_1addr(codelist*dst,nodeleft,char*op)
%s%s"
left.addr,op);
intgen_2addr(codelist*dst,nodeleft,char*op,noderight)
%s=%s%s"
Gen(dst,tmp