编译原理课程设计LL1文法分析器设计C++语言实现.docx
《编译原理课程设计LL1文法分析器设计C++语言实现.docx》由会员分享,可在线阅读,更多相关《编译原理课程设计LL1文法分析器设计C++语言实现.docx(37页珍藏版)》请在冰豆网上搜索。
编译原理课程设计LL1文法分析器设计C++语言实现
集美大学计算机工程学院
编译原理课程设计报告
选题名称:
LL
(1)文法分析
院(系):
计算机工程学院
专业:
计算机科学和技术
班级:
计算1412
指导教师:
付永刚
学年学期:
2016~2017学年第2学期
2017年06月29日
摘要:
选题要求:
根据某一文法编制调试LL
(1)文法语法分分析程序,以便对任意输入的符号串进行分析。
本次课程设计的目的主要是加深对预测分析LL
(1)文法语法分析法的理解。
具体如下:
1、对语法规则有明确的定义;2、编写的分析程序能够对给定文法进行正确的语法分析;3、对输入给定的文法,手工计算FIRST、FOLLOW集合和select集合,应能判断识别是否为给定文法的句子,并给出推导过程。
4、对输入给定的文法,由程序自动构造FIRST、FOLLOW集合。
5、对于遇到的语法错误,能够做出简单的错误处理,给出简单的错误提示,保证顺利完成语法分析过程。
关键词:
语法分析;FIRST集合;FOLLOW集合;分析表
一、设计内容及要求
(1)基于PL/0语言,通过编程判断该文法是否为LL
(1)文法;
(2)计算出文法的First()Follow()
(3)构造相应文法的预测分析表
(4)对某个输入句子进行语法分析
二、实现原理
1.LL
(1)文法
LL
(1)文法是一类可以进行确定的自顶向下语法分析的文法。
就是要求描述语言的文法是无左递归的和无回溯的。
根据LL
(1)文法的定义,对于同一非终结符A的任意两个产生式A:
=a和A:
=b,都要满足:
SELECT(A:
=a)∩SELECT(A:
=b)=Ø。
(1)文法的左递归
当一个文法是左递归文法时,采用自顶向下分析法会使分析过程进入无穷循环之中。
所以采用自顶向下语法分析需要消除文法的左递归性。
文法的左递归是指若文法中对任一非终结符A有推导A⇒A…,则称该文法是左递归的。
左递归又可以分为直接左递归和间接左递归。
●直接左递归
若文法中的某一产生式形如A→Aα,α∈V*,则称该文法是直接左递归的。
消除直接左递归的方法:
设有产生式是关于非终结符A的直接左递归:
A→Aα|β(α,β∈V*,且β不以A开头)
对A引入一个新的非终结符A′,把上式改写为:
A→βA′
A′→αA′|ε
●间接左递归
若文法中存在某一非终结符A,使得A⇒A…至少需要两步推导,则称该文法是间接左递归的。
消除间接左递归的方法:
【方法一】采用代入法把间接左递归变成直接左递归。
【方法二】直接改写文法:
设有文法G10[S]:
S→Aα|β⑴
A→Sγ⑵
因为S⇒Aα⇒Sγα,所以S是一个间接递归的非终结符。
为了消除这种间接左递归,将⑵式代入⑴式,即可得到和原文法等价的文法(可以证明):
S→Sγα|β⑶
⑶式是直接左递归的,可以采用前面介绍的消除直接左递归的方法,对文法进行改写后可得文法:
S→βS′
S′→γαS′|ε
2.计算First集
(1)若X∈VT,则First(X)={X}
(2)若X∈VN,且有产生式X→a…,a∈VT则First(X)={X}
(3)若X∈VN,且有产生式X→ε,则First(X)={X}
(4)若X,Y1,Y2,…,Yn都∈VN,而由产生式X→Y1Y2…Yn。
当Y1,Y2,…,Yi-1都能推导出ε时,(其中1≤i≤n),则First(Y1)-{ε},First(Y2)-{ε},…,First(Yi)都包含在First(X)中
(5)当(4)中所有Yi都能推导出ε,(i=1,2,…,n),则First(X)=First(Y1)∪First(Y2)∪…First(Yn)∪{ε}
反复使用上述步骤直到每个符合的First集合不再增大为止。
3.计算Follow集
对文法中的每个A∈VN,计算Follw(A):
(1)设S为文法的开始符合,把{#}加入Follow(S)中;
(2)若A→αBβ是一个产生式,则把First(β)的非空元素加入Follow(B)中,如果β能推导出ε,则把Follow(A)也加入(B)中;
(3)反复使用以上步骤直到每个非终结符号的Follow集不再增大为止。
4.预测分析方法
预测分析方法是自顶向下分析的另一种方法,一个预测分析器是由三个部分组成:
预测分析程序;先进后出栈;预测分析表。
预测分析程序的框图如下:
正文:
1.系统分析
1.1选题要求
根据某一文法编制调试LL
(1)文法语法分分析程序,以便对任意输入的符号串进行分析。
本次课程设计的目的主要是加深对预测分析LL
(1)文法语法分析法的理解。
1.2预期目标
构造LL
(1)文法语法分析程序,任意输入一个文法符号串,并判断它是否为文法的一个句子。
程序要求为该文法构造预测分析表,并按照预测分析算法对输入串进行语法分析,判别程序是否符合已知的语法规则,如果不符合(编译出错),则输出错误信息。
2.程序流程图
2.1.总流程图
2.2.First集和Follow集的流程图
2.3.预测分析表流程:
3.代码编写
3.1检查左递归:
Parser&Parser:
:
DelLeft(inti)
{
intn=StrNum(content[i]);
charc=RandChar();
charz=content[i][0];
ints=0;
for(intk=1;k<=n;k++)
{
stringtmp=GetSub(k,content[i],'|');
if(z==tmp[0])s=1;
}
if(s==0)return*this;
cout<<"文法句"<while
(1)
{
if(Findchar(c,non)==-1)break;
elsec=RandChar();
}
cout<<"随机产生非终结符为:
"<non.append(1,c);
stringtemp;
temp+=z;
temp+="->";
stringnext;
next+=c;
next+="->";
for(intk=1;k<=n;k++)
{
stringt=GetSub(k,content[i],'|');
if(z==t[0])
{
t.erase(0,1);
t+=c;
next+=t;
next+='|';
}
else
{
if(t=="^")t.clear();
t+=c;
temp+=t;
temp+='|';
}
}
next+='^';
temp.erase(temp.size()-1,1);
content[i]=temp;
num=num+1;
content[num]=end;
for(intj=num-1;j>i;j--)
content[j]=content[j-1];
content[i+1]=next;
return*this;
}
3.2first集合
stringParser:
:
First(charx)
{
stringch="";
if(Findchar(x,ter)!
=-1)
{ch.append(1,x);
ch.append(1,'');
}
elseif(Findchar(x,non)!
=-1)
{
inti=Findid(x);
if(i!
=-1)
{
stringq=content[i];
unsignedintk=3;
while(k{
if(q[k-1]=='|'||k==3)
{
if(Findchar(q[k],ter)!
=-1||q[k]=='^')
{
ch.append(1,q[k]);
ch.append(1,'');
}else
{
if(k==3||q[k+1]=='|'||k==q.size()-1)ch+=First(q[k]);
else
{
stringtemp=First(q[k-1]);
if(Findchar('^',temp)!
=-1)ch+=First(q[k]);
}
}
k++;
}
elsek++;
}
}
}
returnch;
}
3.3follow集合
stringParser:
:
Follow(charx)
{
stringch;
if(Findchar(x,non)!
=-1)
{
if(!
Findid(x))
{
ch+="$";
ch+='';
}
inti=0;
while(i{
stringq=content[i];
unsignedintk=3;
charc=content[i][0];
while(k{
while(q[k]==x)
{
if(k='|')
{
stringtemp=Delchar('^',First(q[k+1]));
if(ch.find(temp)==string:
:
npos)ch+=temp;
if(Findchar('^',First(q[k+1]))!
=-1)
{
stringfollow_c=Follow(c);
if(ch!
=follow_c&&ch.find(follow_c)==std:
:
string:
:
npos)
ch+=follow_c;
}
}
elseif(k==q.size()-1)
{
stringfollow_c=Follow(c);
if(ch.find(follow_c)==std:
:
string:
:
npos)ch+=follow_c;
}
k++;
}
k++;
}
i++;
}
}
returnch;
}
3.4分析表输出
intParser:
:
Analysis()
{
stack.append("$");
charchose;
cout<<"是否输入分析串(yorn):
";
cin>>chose;
while(chose=='y')
{
stack+=non[0];
cout<<"请输入分析串<退出(q)>:
";
cin>>instack;
if(instack=="q")exit(0);
if(instack[instack.size()-1]!
='$')instack+="$";
intk=1,flag=0;
charx=Top();
charc=Ip();
cout<<"分析栈\t当前输入\t动作"<while(x!
='$')
{
x=Top();
c=Ip();
cout<if(Findchar(x,ter)!
=-1)
{
if(Mate(x,c))
{
k++;
cout<<"匹配"<}
else
{
cout<<"["<"<flag=1;
if(x==')')Pop();
elseinstack.erase(0,1);
k++;
}
}
elseif(Findchar(x,non)!
=-1)
{
intidf=Findchar(x,non);
intidz=Findchar(c,ter);
if(idz==-1)idz=int(ter.size());
stringtemp=table[idf][idz];
if(temp.empty())
{
cout<<"["<"<flag=1;
instack.erase(0,1);
k++;
}
else
{
Pop();
if(temp!
="^")
{
Push(temp);
cout<"<}
elsecout<"<}
}
elseif(x=='$'&&c=='$')
{
if(flag==0)cout<<"正确"<elsecout<<"错误"<}
else
{
cout<<"["<"<flag=1;
instack.erase(0,1);
k++;
}
}
}
}
4.程序调试
导入正确的文法:
符合文法的串
不符合文法的串
导入有左递归的文法:
串分析:
总结
通过这次课程设计,对于LL1文法的认识有了进一步的提升,特别是对于FIRST集合和FOLLOW集合的求取,前面对于求取者两个集合理解还不是很好,经过这次课程设计,逐渐理解了求解的过程,并且懂得了如何通过代码,自动生成某LL1文法的FIRST集合和FOLLOW集合,在刚开始做时,根本不知道求,通过网上查找资料,同学的请教,慢慢地懂得了如何做,最终正确地求出FIRST集合和FOLLOW集合。
并且能够使用者两个集合构建预测分析表以及对一段输入的串进行分析是否是该文法的串,出错的地方能够做出错处理,总的来说,完成了课程设计要求的大部分内容,对于GUI的使用没有能够实现,暴露了自身在这方面的不足,需要在以后的学习和工作中进行沉入学习提高。
在实现的功能中还有存在着,对于不含直接左递归的文法没法正确找出,提示错误。
在判断是否是LL1文法上还有很大的不足,没法使用代码实现当两个FIRST有存在交集判断不是LL1文法的功能,这点要求自己对于代码的编程能力有着必要的提高。
这次课程设计使用C++来实现LL1文法分析的功能,自己对于C++语言的使用有了很大的提高。
特别是对于一些C++的语法要求,有了很大的认识。
但存在的不足还是比较多的。
都是需要在今后的学习中认真总结,以使自己能更好地语言的使用,提升自身的技能。
这次课程设计总的收获是不少的。
每一次的实践都是提高自身能力的机会,在今后的生活中,要抓住实践的机会,实践是验证真理最好的途径。
对于一个计算机专业的学生来说,更应该注重实践的机会,只有实践多了,一些理论知识才能被自己正真的认识,不然,值懂理论,没有对于正确性进行验证,还是会有问题的,特别是计算机机器,总存在未知的错误,只有不断地探索,才能更好地去使用我们的工具。
指导教师评语
学号
姓名
班级
选题
名称
序号
评价内容
权重(%)
得分
1
考勤记录、学习态度、工作作风和表现。
5
2
自学情况:
上网检索机时数、文献阅读情况(笔记)。
10
3
论文选题是否先进,是否具有前沿性或前瞻性。
5
4
成果验收:
是否完成设计任务;能否运行、可操作性如何等。
20
5
报告的格式规范程度、是否图文并茂、语言规范及流畅程度;主题是否鲜明、重心是否突出、论述是否充分、结论是否正确;是否提出了自己的独到见解。
30
6
文献引用是否合理、充分、真实。
5
7
答辩情况:
自我陈述、回答问题的正确性、用语准确性、逻辑思维、是否具有独到见解等。
25
合计
指导教师(签章):
年月日
源码:
LL1.h
#include
#include
#include
#include
usingnamespacestd;
classParser
{
public:
Parser();
Parser(constParser&);
friendostream&operator<<(ostream&output,constParser&rs);
friendistream&operator>>(istream&input,Parser&rs);
intFindid(char);
intCheck();
stringCheckstr(string&);
stringDelchar(char,string);
intFindchar(char,string);
intStrNum(conststring&);
charRandChar();
stringGetSub(int,conststring&,char);
Parser&DelLeft(int);
stringFirst(char);
stringFirst(conststring&);
stringFollow(char);
Parser&FirstAndFollow();
Parser&CreateTable();
~Parser();
charPop();
intMate(char,char);
charTop();
charIp();
Parser&Push(conststring&);
intAnalysis();
private:
intnum;
stringter,non,end,stack,instack;
string*content;
string*first;
string*follow;
string**table;
};
LL1.cpp
#include"LL1.h"
Parser:
:
Parser()
{
content=newstring[255];
first=newstring[255];
follow=newstring[255];
table=newstring*[255];
}
Parser:
:
Parser(constParser&rs)
{
ter=rs.ter;
non=rs.non;
end=rs.end;
num=rs.num;
content=newstring[255];
first=newstring[255];
follow=newstring[255];
table=newstring*[255];
for(inti=0;i<=num;i++)
content[i]=rs.content[i];
FirstAndFollow();
CreateTable();
}
ostream&operator<<(ostream&output,constParser&rs)
{
output<<"文法内容(共"<"<inti=0;
while(i{
output<}
output<<"结终符:
"<output<<"非结终符:
"<cout<<"非终结符的FIRST集合"<for(unsignedintj=0;jcout<<"FIRST("<cout<<"非终结符的FOLLOW集合"<for(unsignedintj=0;jcout<<"FOLLOW("<output<<"预测分析表:
"<for(unsignedintj=0;joutput<output<<"$"<for(unsignedintj=0;j{
output<for(unsignedintk=0;k<=rs.ter.size();k++)
cout<output<}
returnoutput;
}
istream&operator>>(istream&input,Parser&rs)
{
unsignedintj=0;
char[255];
cout<<"请输入文件名:
";
input>>;
ifstreamin);
if(!
infile){
cout<<"无法打开文件!
"<exit(0);
}
while
(1)
{
unsignedinti=0;
infile>>rs.end;
rs.content[j++]=rs.end;
if(in())break;
while(i{
if(rs.end[i]=='|'||rs.end[i]=='^');
elseif(i==1||i==2)i++;
elseif(rs.end[i]>='A'&&rs.end[i]<='Z'){
if(std:
:
string:
:
npos==rs.non.find(rs.end[i]))rs.non.append(1,rs.end[i]);
}
elseif(std:
:
string:
:
npos==rs.ter.find(rs.end[i]))rs.ter.append(1,rs.end[i]);
i++;
}
}
rs.num=j-1;
if(rs.Check()