LL1文法分析.docx
《LL1文法分析.docx》由会员分享,可在线阅读,更多相关《LL1文法分析.docx(21页珍藏版)》请在冰豆网上搜索。
LL1文法分析
编译原理课程设计报告
选题名称:
LL
(1)语法分析
系(院):
ﻩ计算ﻩ机工程系ﻩﻩﻩﻩﻩ
专业:
ﻩﻩ计算机科学与技术ﻩﻩﻩ
学年学期:
ﻩ2010 ~2011ﻩ学年 第1 学期ﻩ
ﻩ2010ﻩﻩ年 12ﻩ月30日
ﻬ设计任务书
课题
名称
LL(1)语法分析
设计
目的
LL
(1)分析法的基本思想是:
自顶向下分析时从左向右扫描输入串,分析过程中将采用最左推导,并且只需向右看一个符号就可决定如何推导。
通过对给定的文法构造预测分析表和实现某个符号串的分析,掌握LL(1)分析法的基本思想和实现过程。
实验
环境
1。
微型电子计算机(PC)
2。
WindowsXP操作系统,Visual C++6。
0开发工具
任务
要求
1。
录入合法的LL
(1)文法
2。
构造并输出预测分析表
3. 对输入的符号串进行语法分析
工作进度计划
序号
起止日期
工作内 容
1
10.12.27—10.12。
27
选定题目,明确题目要求
2
10。
12。
28-10.12。
28
课题深入调研、细化工作,系统方案设计
3
10.12.29-10。
12。
29
程序录入、调试、整合
4
10.12。
30—10。
12.31
上机演示,课程设计分组答辩,完成课程设计报告
指导教师(签章):
年 月 日
摘要:
语法分析是编译程序的核心部分。
语法分析的作用是识别由词法分析给出的单词符号序列是否是给定的文法的正确句子。
目前语法分析常用的方法右自顶向下分析和自底向上分析两大类。
确定的自顶向下方法,是从文法的开始符号,考虑如何根据当前的输入符号(单词)唯一的确定选用哪个产生式替换相应非终结符往下推导.LL
(1)文法是一种确定的自顶向下的分析方法.LL
(1)分析法的功能是利用LL(1)控制程序根据显示栈顶内容、向前看符号以及LL
(1)分析表,对输入符号串自上而下的分析过程。
可通过消除左递归、提取左因子把非LL(1)文法改造成LL
(1)文法。
当文法满足条件后,分别构造出文法的每个非终结符的FIRST、FOLLOW集合和SELECT集,根据SELECT集合判断是否是LL
(1)文法。
在LL(1)预测分析程序设计过程中,最重要的两个问题是预测分析表的构造和相关数据结构的设计。
而预测分析表的构造首先必须计算文法每个非终结符的FIRST集和FOLLOW集。
要知道一串符号是不是该文法的一个句子,只要判断是否能从文法的开始符号出发推导出这个输入串.语法分析可以分为两类,一类是自上而下的分析法,一类是自下而上的分析法.自上而下的主旨是,对任何输入串,试图用一切可能的办法,从文法开始符号出发,自上而下的为输入串建立一棵语法树.或者说,为输入串寻找一个最左推倒,这种分析过程的本质是一种试探过程,是反复使用不同产生式谋求匹配输入串的过程我主要是自上而下的过程.
关键词:
语法分析;LL
(1)分析;FIRST集合;FOLLOW集合;自上而下分析
目录
1课题综述ﻩ1
1.1课题来源和意义1
1。
2预期目标1
1.3解决问题ﻩ1
2系统分析ﻩ1
2。
1.1LL(1)文法……………………………………………………………………………………。
.1
2。
1。
2确定的自顶向下分析思想…………………………………………………………………。
。
2。
2。
1。
3 左递归的消除………………………………………………………………………………。
。
3
2.1。
4消除回溯、提左因子…………………………………………………………………………4
2.1。
5计算FIRST集合、FOLLOW集合和SELECT集合……………………………………………….4
2。
2解决问题的基本思路……………………………………………………………………………...5
2.3 功能模块框图……………………………………………………………………………………….5
3系统设计ﻩ5
3.1LL
(1)文法输入设计ﻩ6
3.2LL
(1)语法分析详细流程图ﻩ6
3.3算法描述……………………………………………………………………………………………7
3.3.1消除左递归的算法…………………………………………………………………………….7
3。
4系统流程图…………………………………………………………………………………………。
.8
4 代码编写………………………………………………………………………………。
.9
4.1相关代码…………………………………………………………………………………………。
.9
4.4运行结果ﻩ12
总 结ﻩ14
致谢15
参考 文 献16
1课题综述
编译原理的设计一般都是从文法和语言的基础知识开始,沿着词法分析、语法分析、语义分析、语法翻译、中间代码生成及符号表组织序列进行。
本课题的总体设计完全依据编译原理的教学内容,即上下文无关文法基础及词法分析、语法分析技术研究、语法推导的语义翻译、代码优化及目标代码生成。
但是在本课题中只涉及到了关于文法分析的相关知识.
1。
1课题来源和意义
LL(1)文法是一种简单易行的,自顶向下的,且较易实现的文法.它的原理在编译原理的书上已有详细叙述,本文着重于介绍其实现过程中的一些细节及思考。
LL(1)表明自顶向下分析技术是从左向右扫描输入串,分析过程中将用最左推导,以及只需向右看一个符号便可决定如何推导的一种文法。
首先必须判断所给文法是否是LL
(1)文法,然后编写构造LL
(1)语法分析程序。
因而对任给文法需计算FIRST、FOLLOW、SELECT集合,进而判别文法是否为LL
(1)文法。
设计中实现语法分析使用的语言是C++,使程序能达到上述目标。
1。
2预期目标
熟练掌握运用VC++建立工程,并用VC++语言进行程序编写,掌握编程思想和算法。
熟练掌握LL
(1)文法的分析方法,利用FIRST集合、FOLLOW集合以及SELECT集合得到预测分析表,并且各集合的计算方法也是设计的目标.
1。
3解决问题
(1)对于一个输入文法,消除文法的左递归;
(2)理解计算FIRST、FOLLOW集合和SELECT集合的方法;
(3)理解文法分析表的构造。
2系统分析
2。
1涉及的知识基础
2.1.1LL
(1)文法
LL
(1)文法是一类可以进行确定的自顶向下语法分析的文法。
一个用来描述语言语法结构的文法G[2]可形式地定义如下:
一个文法G[S]可表示成形如(VN,VT,P,S)的四元式。
其中VN,VT,P均为非空的有限集,分别称为非终结符集、终结符集和产生式集。
具体来说:
VN,一系列需要定义的语法范畴.
VT,若干基本符号,不需要进一步定义.
P,用“—〉“连接起来的有序对(A,α)的集合,称为规则,也叫产生式。
其中A是一个非终结符,α是一个由终结符或非终结符组成的符号串,即α∈(VN∪VT)*.
S,是文法的开始符号。
S∈VN
此外,我们还将出现在产生式左、右侧的全部符号的集合称为词汇表,记为V。
显然:
V=VN∪VT;VN∩VT=φ。
更确切地说,上面给出的是上下文无关文法的定义。
这是因为由符号串a去替换A时,并不考虑A所处的环境,即与A的上下文无关。
除非另做说明,我们以后所说的文法均指上下文无关文法。
LL(1)的含义:
●第一个L表示从左至右扫描输入符号串
●第二个L表示生成输入串的一个最左推导
●1表示在决定分析程序的每步动作时,向前看一个符号
2。
1。
2确定的自顶向下分析思想
LL
(1)文法是一类可以进行确定的自顶而下语法分析的文法。
而自顶而下分析法的基本思想是从文法的开始符号出发采用最左推导,根据当前的输入符号(单词符号)惟一地确定选用哪个产生式替换相应非终结符以下推导。
这种分析过程实质是一种试探过程,是反复使用不同产生式匹配输入符号串的过程。
若有文法:
S->cAd
A—〉ab|a
输入串W=cad。
为建立分析树,首先建立只有标记S单个结点树,输入指针指向W的第一个符号c。
然后用S的第一个产生式来扩展该树,得到的树如图2。
1所示:
图2。
1.1语法分析树
最左边的叶子标记为c,匹配W的第一个符号。
于是,推进输入指针到W的第二个符号a,并考虑下一个标记为A的叶子。
用A的第一个选择来扩展A,得到如图(b)的树.现在匹配第二个输入符号a,再推进输入指针到d,把它和下一个标记为b的叶子比较。
因为b和d不匹配,报告失败,回到A,看它是否还有别的选择尚未尝试.在回到A时,必须重置指针于第二个符号,即第一次进入A的位置。
现在尝试A的第二个选择,得到图(c)的分析树.叶子a匹配W的第二个符号,叶子d匹配W的第三个符号.这样,产生了W的分析树,从而宣告分析完全成功。
2。
1.3 左递归的消除
直接消除产生式中的左递归是比较容易的.假定关于非终结符P的规则为P-〉Pa|b其中,P是开头。
那么我们可以把P的规则改写为如下的非直接左递归形式:
P->bR
R-〉aR|ε(ε为空字)
这种形式和原来的形式是等价的,也就是说,从P推出的符号串是相同的.
一般而言,假定P关于的全部产生式是P-〉Pα1|Pα2|…|Pαm|1|2|…|n其中,每个αi(1≤i≤m)都不等于ε,1~n都不以P开头,那么消除P的直接左递归就是把这些规则改写成:
P-〉1R|2R|…| nR
R—>α1R|α2R|…αmR|ε
使用这个方法,我们容易把见诸于表面的所有直接左递归都消除掉,也就是说,把直接左递归都改成直接右递归。
对于间接左递归的消除需先通过产生式非终结符置换,把间接左递归变成直接左递归。
例如有文法:
S—〉Aα| β
(1)
A-〉Sγ
(2)
因为S=>Aα=>Sγα,所以S是一个间接递归的非终结符。
为了消除这种间接左递归将
(2)式代人(1)式,即可得到与原方法等价的方法:
S-〉Sγα|β (3)
(3)式是直接左递归的,可以采用消除直接左递归的方法对文法进行改写,可的文法:
S-〉βS’
S’—>γαS’|ε
由此可见,为了消除间接左递归,可首先查出那些具有左递归的非终结符号,然后对以这些非终结符为左部的产生式,通过逐步置换有关产生式的方法将它们化为直接左递归的产生式。
最后在消除其中的全部直接左递归.
2.1。
4消除回溯、提左因子
为了消除回溯就必须保证:
对文法的任何非终结符,当要它去匹配输入串时,能够根据它所面临的输入符号准确地指派它的一个侯选去执行任务,并且次侯选的工作结果是确信无疑的。
也就是说,若此侯选获得成功匹配,那么,这种匹配不会是虚假的;若此侯选无法完成任务,则任何其它侯选也肯定也无法完成任务.换句话说,假定现在轮到非终结符A去执行匹配任务,A共有n个侯选α1,α2,……αn,即A-〉α1|α2|……αn。
A能够根据不同的输入符号指派相应的αi作为全权代表去执行任务,那就肯定无需回溯了。
在这里A已不再是让某个侯选去试探地执行任务,而是根据所面临的输入符号α准确地指派唯一的一个侯选。
其次,被指派侯选的工作成败也完全代表了A.
2.1.5计算FIRST集合、FOLLOW集合和SELECT集合
FIRST集合:
令G[S]=(VT,VN,S,P),则
FIRST(α)={a|a⇒*ab,a∈VT,α、β∈V*}、
-若α⇒*ε,则ε∈FIRST(α)
-对每以文法符号X,计算FIRST(X)过程如下:
(a)若X∈VT,则FIRST(X)={X};
(b)若X∈VN,且有产生式X→a…,a∈VT,则把a加入到FIRST(X)中;
(c)若X∈VN,若X→ε也是一条产生式,则把ε也加到FIRST(X)中;
(d)若X∈VN,有产生式X→Y1Y2…Yn,Y1,…Yi都是非终结符,对于任何j,1≤j≤i-1,FIRST(Yj)都含有ε,则把FIRST(Yj)中的所有非ε元素都加到FIRST(X)中; FIRST(Yi)的元素加入到FIRST(X)
-特别地,若所有的FIRST(Yj, j=1,2,…,n)均含有ε,则把e,FIRST(Yj)中的所有非ε元素都加到FRIST(X)中。
FOLLOW集合:
设G[S]=(VT,VN,S,P)是上下文无关文法,
(a)设S为开始符号,则#∈FOLLOW(S)
(b)若有产生式A→ αBβ,b*⇒ε
则FIRST(β)⊂FOLLOW(B)
(C)若β⇒ε(可理解为A→aB)则FIRST(β)—{ε}∪FOLLOW(A)⊂FOLLOW(B)
SELECT集合:
A→a的可选集SELECT
a⇒ε,则SELECT(A→a)=FIRST(α)
a⇒ε,则SELECT(A→α)=(FIRST(α)—{ε})∪FOLLOW(A)
2。
2解决问题的基本思路
首先根据一定的规则输入一个合法的文法,化简成LL
(1)文法,利用一定的算法消除文法中的左递归,然后再利用首先预定的规则计算出FIRST和FOLLOW集合,以及算出SELECT集合,然后就是显示出LL(1)文法的分析表。
最后一步是输入一串字符串,然后对字符串进行分析,输出分析过程表,这样系统就成形了。
2.3功能模块框图
3系统设计
语法分析是编译过程的核心部分。
他的任务是在词法分析识别单词符号串的基础上,分析并判断程序的的语法结构是否符合语法规则。
语言的语法结构是用上下文无关文法描述的.因此语法分析器的工作的本质上就是按文法的产生式,识别输入符号串是否为一个句子.对于一个文法,当给你一串符号是,如何知道它是不是该文法的一个句子,这是这个课程设计所要解决的一个问题。
其实要知道一串符号是不是该文法的一个句子,只要判断是否能从文法的开始符号出发推导出这个输入串。
语法分析可以分为两类,一类是自上而下的分析法,一类是自下而上的分析法。
自上而下的主旨是,对任何输入串,试图用一切可能的办法,从文法开始符号出发,自上而下的为输入串建立一棵语法树。
或者说,为输入串寻找一个最左推倒,这种分析过程的本质是一种试探过程,是反复使用不同产生式谋求匹配输入串的过程我主要是自上而下的过程。
3.1LL
(1)文法输入设计
标准的文法有一定的规则,若在设计过程中,输入的文法不正确,则不能正确的实现程序功能,所以首先在编写程序时,要对输入文法进行限制,规则如下:
(1)大写英文字母表示非终结符,所以产生式左部一定要输入大写字母;
(2) e表示空产生式;
(3)除大写字母、#、’、|外的单字符表示终结符,所以产生右部不能包括以上几个字符;
(4)不能出现递归文法.(如 S-〉S或S-〉A, A—〉S;);
(5) 不能出现多余文法规则。
(如S->A,A不是非终结符);
(6)文法产生式长度不超过10个字符。
3。
2LL
(1)语法分析详细流程图
我们知道一个文法要能进行LL
(1)分析,那么这个文法应该满足:
无二义性,无左递归,无左公因子.当文法满足条件后,再分别构造文法每个非终结符的FIRST和FOLLOW集合,然后根据FIRST和FOLLOW集合构造LL(1)分析表,最后利用分析表,根据LL(1)语法分析构造一个分析器。
LL(1)的语法分析程序包含了三个部分,总控程序,预测分析表函数,先进先出的语法分析栈,本程序也是采用了同样的方法进行语法分析,其结构图如图3。
2.
3。
3算法描述
3.3。
1消除左递归的算法
(1)把文法G的所有非终结符按任一种顺序排列成P1,P2,……Pn;按此顺序执行;
(2) FOR i:
=1 TO n DO
BEGIN
FOR j:
=1 TO i-1 DO
把形如Pi—>Pjγ产生式变为Pj->δ1|δ2|…|δk关于Pj的所有规则
消除关于Pi规则的直接左递归性
END
(3)化简由
(2)所得的文法。
即去除那些从开始符号出发永远也无法到达的非终结符的产生规则。
3.4系统流程图
整个程序可分为如下几步:
(1) 读入文法;
(2)判断正误;
(3)若无误,判断是否为LL
(1)文法;
(4)若是,构造分析表;
(5)由总控算法判断输入符号串是否为该文法的句型。
图3。
4.1程序主流程图 图3.4.2消除左递归流程图
4代码编写
4.1相关代码
/*******************************************
分解含有左递归的产生式
********************************************/
void recur(char*point)
{/*完整的产生式在point[]中*/
intj,m=0,n=3,k;
ﻩchar temp[20],ch;
ch=c();/*得到一个非终结符*/
k=strlen(non_ter); /*非终结符号长度*/
ﻩnon_ter[k]=ch;//得到最后一个非终结符号
ﻩnon_ter[k+1]=’\0';
ﻩfor(j=0;j<=strlen(point)—1;j++)
{ﻩ
ﻩﻩif(point[n]==point[0])
ﻩﻩ{ /*如果‘|’后的首符号和左部相同,含直接左递归*/
ﻩﻩfor(j=n+1;j〈=strlen(point)-1;j++)
ﻩ{
ﻩ ﻩwhile(point[j]!
='|’&&point[j]!
=’\0’)
ﻩ temp[m++]=point[j++];
ﻩﻩleft[count]=ch;
ﻩﻩmemcpy(right[count],temp,m);
ﻩﻩﻩright[count][m]=ch;
ﻩﻩﻩright[count][m+1]='\0';
ﻩﻩm=0;
ﻩﻩﻩcount++;
ﻩﻩﻩﻩif(point[j]==’|’)
ﻩﻩ{
ﻩﻩﻩn=j+1;
break;
ﻩ}
ﻩﻩﻩ}
ﻩﻩ}
ﻩﻩelse
ﻩﻩ{ /*如果‘|’后的首符号和左部不同*/
ﻩﻩleft[count]=ch;
ﻩright[count][0]='^';
ﻩright[count][1]=’\0';
ﻩcount++;
ﻩﻩfor(j=n;j〈=strlen(point)-1;j++)
ﻩﻩ{
ﻩﻩﻩ if(point[j]!
='|’)
ﻩﻩﻩ temp[m++]=point[j];
ﻩ else
ﻩ{
ﻩﻩﻩﻩleft[count]=point[0];
ﻩﻩ memcpy(right[count],temp,m);
ﻩ right[count][m]=ch;
ﻩﻩ right[count][m+1]='\0';
ﻩﻩprintf(”count=%d",count);
ﻩﻩﻩm=0;
ﻩﻩcount++;
ﻩﻩﻩ}
ﻩ}
left[count]=point[0];
ﻩ memcpy(right[count],temp,m);
ﻩﻩ right[count][m]=ch;
right[count][m+1]=’\0’;
ﻩcount++;
ﻩ m=0;
ﻩﻩ}
}
}
/*******************************************
分解不含有左递归的产生式
********************************************/
voidnon_re(char *point)
{
intm=0,j;
ﻩchartemp[20];
for(j=3;j<=strlen(point)-1;j++)
ﻩ{
if(point[j]!
=’|')
temp[m++]=point[j];
ﻩelse
{
ﻩ left[count]=point[0];
ﻩ memcpy(right[count],temp,m);
ﻩright[count][m]=’\0’;
ﻩm=0;
count++;
ﻩﻩ}
}
left[count]=point[0];
memcpy(right[count],temp,m);
right[count][m]='\0’;
count++;
ﻩm=0;
}
/*******************************************
总控算法
********************************************/
voidsyntax()
{
inti,j,k,m,n,p,q;
charch;
charS[50],str[50];
printf(”请输入该文法的句型:
");
ﻩscanf(”%s",str);
ﻩgetchar();
i=strlen(str);
str[i]='#’;
ﻩstr[i+1]=’\0’;
ﻩS[0]='#’;
S[1]=start;
ﻩS[2]='\0’;
ﻩj=0;
ch=str[j];
while
(1)
{
ﻩﻩif(in(S[strlen(S)—1],termin)==1)
ﻩﻩ{
if(S[strlen(S)—1]!
=ch)
ﻩﻩ{
ﻩﻩprintf(”该符号串不是文法的句型!
");
return;
ﻩ}
else if(S[strlen(S)—1]==’#’)
ﻩﻩ{
printf(”该符号串是文法的句型。
");
return;
ﻩﻩ}
ﻩﻩelse
ﻩﻩ{
S[strlen(S)-1]=’\0';
ﻩﻩﻩj++;
ﻩﻩch=str[j];
}
}
ﻩelse
ﻩ{
for(i=0;;i++)
ﻩﻩif(non_ter[i]==S[strlen(S)-1])
ﻩﻩﻩbreak;
ﻩﻩfor(k=0;;k++)
ﻩ{
ﻩﻩﻩif(termin[k]==ch)
ﻩﻩbreak;
ﻩif(k==strlen(termin))
ﻩﻩﻩ{
ﻩﻩprintf(”词法错误!
”);
ﻩﻩﻩreturn;
ﻩﻩﻩ}
ﻩ}
ﻩﻩif(M[i][k]==-1)
ﻩﻩ{
ﻩprintf(”语法错误!
”);
ﻩﻩﻩreturn;
ﻩﻩ}
ﻩﻩelse
ﻩﻩﻩ{
m=M[i][k];
if(right[m][0]=='^')
ﻩS[strlen(S)-1]=’\0';
ﻩﻩelse
ﻩ{
ﻩp=strlen(S)-1;
ﻩﻩﻩq=p;
ﻩfor(n=strlen(right[m])—1;n>=0;n——)