编译原理课程设计一个简单文法的编译器的设计与实现.docx
《编译原理课程设计一个简单文法的编译器的设计与实现.docx》由会员分享,可在线阅读,更多相关《编译原理课程设计一个简单文法的编译器的设计与实现.docx(53页珍藏版)》请在冰豆网上搜索。
![编译原理课程设计一个简单文法的编译器的设计与实现.docx](https://file1.bdocx.com/fileroot1/2023-2/1/2a8d2ebf-fc91-495e-8929-3db4b85b05f8/2a8d2ebf-fc91-495e-8929-3db4b85b05f81.gif)
编译原理课程设计一个简单文法的编译器的设计与实现
课程设计报告
设计题目:
一个简单文法的编译器的设计与实现
班级:
运算机1206班
组长学号:
2021XXX
组长姓名:
XXX
指导教师:
XXX
设计时刻:
2014年12月
设计分工
组长学号及姓名:
2021XXXXXX
分工:
1)读取源文件进行词法分析
2)进行LL
(1)分析生成份析表
3)设计顶层自动机将源程序分段
4)生成可执行的汇编程序
组员1学号及姓名:
2021XXXXXX
分工:
1)设计第二层自动机处置程序片段
2)生成中间语言四元式
3)源程序错误处置
组员2学号及姓名:
2021XXXXXX
分工:
1)设计第三层自动机处置复合表达式
2)设计带动作的LL
(1)文法
3)源程序错误处置
摘要
编译原理课程具有很强的理论性和实践性,是运算机专业的一门超级重要的专业基础课程,在系统软件中也是占有十分重要的地位。
本次课程设计咱们是在VisualC++的平台上应用了词法分析、语法分析、语义分析、中间语言生成和目口号言生成的知识设计了一个简单的编译器前端。
其中设计了一个简单的有限自动机来扫描源程序即进行语法分析,并生成了关键字表、标志符表、界符表、常数表和Token串;设计了一个LL
(1)文法和一个带动作的文法来实现语法分析,并生成了Select集和LL
(1)分析表;采纳了四元式序列的设计来生成中间语言;通过汇编语言设计来生成目口号言。
最后为了使该编译器加倍完善,咱们设计了简单的的错误检查机制,能够对源程序进行比较全面的错误检查同时也能够指犯错误显现的大致位置,增强了该编译器的健壮性。
关键字:
编译器,前端,有限自动机,LL
(1)文法,汇编语言,错误处置
摘要3
一、概述5
二、课程设计任务及要求5
2.1设计任务5
2.2设计要求6
3、算法与数据结构6
3.1词法分析器的算法6
3.2语法分析器的算法12
LL
(1)文法设计算法12
递归下降子程序设计算法19
3.3中间语言生成器算法20
3.4处置复合表达式算法24
3.5目口号言生成器算法30
3.6数据结构39
4、程序设计与实现39
4.1编译程序设计与实现39
4.2程序实验结果39
待测源程序39
词法分析结果40
语法分析结果41
中间语言生成结果42
目口号言生成结果43
程序错误处置结果44
五、参考文献44
一、概述
本次课程设计的编译程序要紧包括了词法分析器、语法分析器、中间代码生成器和目标代码生成器四部份,编译程序的输出结果包括了词法分析后的关键字表、界符表、标识符表和Token串,语法分析后的Select集和LL
(1)分析表;中间代码生成器产生的四元式序列。
最后除完成设计所要求的内容之外,咱们还做了一些扩展例如:
设计了目标代码生成器来生成可执行的汇编程序;还设计了错误检查机制来查找源程序的错误并指犯错误产生的大致位置。
词法分析是编译程序的第一步操作,它的任务是:
从左至右扫描源程序的字符串,依照必然的词法规那么识别出一个个正确的字符,并转换成该字符相对应的Token码,最终生成一个完整的Token串以供语法分析利用。
由此可知,词法分析是整个编译程序的基础,而执行词法分析的一系列操作的确实是词法分析器。
语法分析是编译程序的第二步操作也是编译程序的核心部份,其要紧任务是:
分析语法内容,确信语法结构同时生成Select集和LL
(1)分析表。
中间代码和目标代码的生成是对源程序的进一步操作,其任务是:
依照词法分析产生的Token串和语法分析确信的语法结构来生成中间语言——四元式和目口号言——汇编语言程序。
二、课程设计任务及要求
一个简单文法的编译器前端的设计与实现
●概念一个简单程序设计语言文法(包括变量说明语句、算术运算表达式、赋值语句;扩展包括逻辑运算表达式、If语句、While语句等);
●扫描器设计实现;
●语法分析器设计实现;
●中间代码设计;
●中间代码生成器设计实现。
●目标代码生成器设计实现
●给出一个源程序文件,作为编译器前端的输入
●输出相关编译时期的运行结果
●词法分析时期:
●生成Token序列;
●生成关键字表、界符表、符号表系统。
●中间代码生成时期:
●生成四元式序列;
●生成符号表系统。
3、算法与数据结构
1)一个简单有限自动机(扫描器)的设计:
①
②
③
④
⑤
n
?
ℓ
ℓ
d
≮
-
d
d
.
d
d
≮
-
-
-
≮
≮
⑥
⑦
=
=
≮
-
…
#
-
d
其中:
⑴ℓ(字母),d(数字),#(源程序终止符)
(2)?
(空格,回车,换行)需要滤掉
(3)≮(泛指单词的后继附)
(4)……(表示省略了其他界符的处置)
2)一个简单词法分析器设计:
开始
结束
调用识别器
关键字/标识符
算术常数
结束符#
查KT表
查到
查填IT表
查填CT表
常数处理
查PT表
y
n
查到
ere:
非法界符
y
n
y
y
n
n
n
y
算法实现如下:
Voidmain(){//词法分析部份代码
charp[10];
stringTOKEN;
stringSource;
stringtemp;
FILE*fp;
fp=fopen("D:
\\MySourceFile.txt","r");
if(!
fp)Source="Cannotopenfile";
else
{
inti;
charc;
while(!
feof(fp))
{
c=fgetc(fp);
Source+=c;
}
fclose(fp);
for(i=0;i{
if(Source[i]==13||Source[i]==9||Source[i]==10||Source[i]==-1)
{
Source.replace(i,1,"");
}
}
}
Source+='#';
cout<<"处置后源程序\n"<initKTPT();
inti,j;
for(i=0;i{
switch(kindofchar(Source[i]))
{
case'e':
{
cout<<"\n非法字符!
位置:
"<
for(intk=0;k<=i;k++)cout<exit(0);
}
case's':
break;
case'd':
{
temp+=Source[i];
for(j=1;Source[i+j]=='.'||kindofchar(Source[i+j])=='d';j++)temp+=Source[i+j];
i=i+j-1;
if(inCT(temp)==-1)
{
temp="N"+temp;
CT.push_back(temp);
}
TOKEN+="itoa(inCT(temp),p,10);
TOKEN+=p;
TOKEN+=">";
temp="";
break;
}
case'w':
{
temp+=Source[i];
for(j=1;kindofchar(Source[i+j])=='w'||kindofchar(Source[i+j])=='d'||Source[i+j]=='_';j++)temp+=Source[i+j];
i=i+j-1;
if(inKT(temp)!
=-1)
{
TOKEN+="itoa(inKT(temp),p,10);
TOKEN+=p;
TOKEN+=">";
temp="";
break;
}
if(inIT(temp)==-1)IT.push_back(temp);
TOKEN+="itoa(inIT(temp),p,10);
TOKEN+=p;
TOKEN+=">";
temp="";
break;
}
case'f':
{
temp+=Source[i];
if(kindofchar(Source[i+1])=='f'&&inPT(temp+Source[i+1])>=0)
{
temp+=Source[i+1];
i++;
}
TOKEN+="itoa(inPT(temp),p,10);
TOKEN+=p;
TOKEN+=">";
temp="";
break;
}
case'\"':
{
i++;
for(j=0;Source[i+j]!
='\"'&&(i+j)<(Source.size()-1);j++)
{
if(Source[i+j]=='\\'&&Source[i+j+1]=='\"')
{
temp+='\"';
j++;
}
if(Source[i+j]=='\\'&&Source[i+j+1]=='\'')
{
temp+='\'';
j++;
}
if(Source[i+j]=='\\'&&Source[i+j+1]=='\\')
{
temp+='\\';
j++;
}
if(Source[i+j]=='\\'&&Source[i+j+1]=='\0')
{
temp+='\0';
j++;
}
elsetemp+=Source[i+j];
}
if((i+j)>=(Source.size()-1))
{
cout<<"未找到可匹配的双引号,位置:
"<
for(intk=0;k<=i;k++)cout<exit(0);
}
i=i+j;
if(inCT(temp)==-1)
{
temp="S"+temp;
CT.push_back(temp);
}
TOKEN+="itoa(inCT(temp),p,10);
TOKEN+=p;
TOKEN+=">";
temp="";
break;
}
case'\'':
{
if((i+3)<(Source.size()-1)&&Source[i+1]=='\\'&&Source[i+3]=='\'')
{
switch(Source[i+2])
{
case'\\':
temp+='\\';break;
case'\'':
temp+='\'';break;
case'\"':
temp+='\"';break;
case'0':
temp+="\\0";break;
default:
cout<<"错误的单引号利用(转义错误),位置:
"<
}
i+=3;
}
else
{
if((i+2)>=(Source.size()-1))
{
cout<<"错误的单引号利用(越界),位置:
"<
for(intk=0;k<=i;k++)cout<exit(0);
}
temp+=Source[i+1];
i+=2;
}
if(inCT(temp)==-1)
{
temp="C"+temp;
CT.push_back(temp);
}
TOKEN+="itoa(inCT(temp),p,10);
TOKEN+=p;
TOKEN+=">";
temp="";
break;
}
case'#':
break;
default:
break;
}
}
第一介绍一下整个课程设计中咱们利用到的一些文法。
C--文件->voidmain()C<--程序体→
C->{Y<--语句-->}
Y->S<--声明语句-->;I<--语句后继-->|Z<--赋值语句-->;I|V<--条件语句-->N<--if后继-->{B}I|W<--循环语句-->I
I->Y|空
S->类型标识符声明后继
类型->int|float|char
声明后继->,标识符声明后继|空
Z->标识符=表达式
V->if(E)C
N->elseC|空
W->while(表达式)程序体
E->详见rull.txt源文件。
语法分析主若是对LL
(1)文法和递归下降子程序的设计,其算法设计如下:
LL
(1)文法的设计
1)算法原理如下:
●利用一个分析表,记录如何选择产生式的知识;
●利用一个分析栈,记录分析进程;
●此分析法要求文法必需知足LL
(1)文法形式。
2)
#Z
开始:
栈
;NEXT(w)
算法设计如下:
重复执行①、②、③,直到栈中只剩#为止:
(1)
(2)
①若栈顶符=A且当前符w=a且有产生式:
Aàaa,则POP,PUSH(aa)R;
②若栈顶符=a且当前符为a;则pop,NEXT(w);
③否则,错误处理!
#
栈
结束:
;当前符w=#
(3)
算法实现如下:
voidmaketable()//////////////////////////////////////////需要参数指明所需文法
{
//打开文件
//switch()///////////////////////////////////////依照参数选择文法
FILE*fp=fopen("D:
/rull.txt","r");
if(fp==NULL)
{
cout<<"打开文件失败"<getchar();
exit(0);
}
//读取文件
stringsource="";
charreadchar;
do
{
readchar=fgetc(fp);
source+=readchar;
}
while(readchar!
=EOF);
fclose(fp);
//cout<<"----source流----"<//从source流中提取有效数据
Vs=source[3];
Vn+=Vs;
inti,j,k,l;
stringps="";
for(i=8;source[i]!
=';';i++)Vn+=source[i];
i+=4;
for(;source[i]!
=';';i++)Vt+=source[i];
i++;
while(source[i]!
=';')
{
for(;source[i]!
=''&&source[i]!
=';';i++)
{
ps+=source[i];
}
QRULL.push_back(ps);
ps="";
if(source[i]=='')i++;
}
//拆分或符号
stringps2="";
intflag;
for(i=0;i{
flag=0;
for(j=0;j{
if(QRULL[i][j]=='|')
{
flag=1;
break;
}
}
if(flag==0)continue;
ps2+=QRULL[i][0];
ps2+="->";
for(j=0;QRULL[i][j]!
='|';j++)ps+=QRULL[i][j];
for(j++;jQRULL[i]=ps;
QRULL.push_back(ps2);
ps="";
ps2="";
}
cout<<"----有效四元产生式表----"<for(i=0;i{
cout<}
cout<//从四元产生式转化为一般产生式
ps="";
for(i=0;i{
k=0;ps="";
for(j=0;j{
if(QRULL[i][j]!
='{')ps+=QRULL[i][j];
elsej+=2;
}
RULL.push_back(ps);
}
cout<<"----有效一般产生式表----"<for(i=0;i{
cout<}
cout<//检测直接左递归
flag=0;
for(i=0;i{
if(RULL[i][0]==RULL[i][3])flag=1;
}
if(flag==1)
{
system("cls");
system("colorCF");
cout<<"检测到直接左递归文法,系统已停止运行,请更正产生式。
"<getchar();
exit(0);
}
//产生SELECT表
Vt+='#';
MAXITERATE=RULL.size()*RULL.size();
vectorSELECT;
SELECT=Select();
cout<<"----SELECT集----"<for(i=0;i{
cout<