LL1文法判断程序
实验三 LL(1)文法判断程序
一、 实验目的
首先能让用户输入一个文法,然后让计算机自动判断是否是一个LL(1)文法,通过实验教学,加深学生对所学的关于编译的理论知识的理解,增强学生对所学知识的综合应用能力,并通过实践达到对所学的知识进行验证。
二、 实验内容
让计算机接受一个文法,示例如(仅供参考):
G[S] 为:
S→AB S→bC
A→ε A→b
B→ε B→aD
C→AD C→b
D→aS D→c
1.编程实现对上述文法是否是LL(1)文法的判断,是则给出肯定回答,否则给出否定回答。
2.判别是否是LL(1)文法
实验流程图如下:
三、 实验环境
Windows7系统下的PC机,DEV C++软件,语言:C++。
四、 算法与实验原理
1、LL(1)文法的描述
(1)一个上下文无关文法是LL(1)文法的充分必要条件是:对每个非终结符A的两个不同产生式,A→α, A→β,满足SELECT(A→α)∩SELECT(A→β)= Φ( 其中α,β不同时能推导出ε)。
(2)LL(1)文法的含义:
第一个L即从左到右扫描输入串。
第二个L即生成的是最左推导向右看一个输入符号便可决定选择哪个产生式。
(3)LL(1)文法的判别:当我们需选用自顶向下分析技术时,首先必须判别所给文法是否是LL(1)文法。因而我们对任给文法需计算FIRST、FOLLOW、SELECT集,进而判别文法是否为LL(1)文法。函数代码如下:
int isLL1(Prod p)
{
int i=0;
int j;
for(i=0;i<p->len-1;i++)
for(j=i+1;j<p->len;j++){
if(p->pro[i]->front==p->pro[j]->front)
if(strcmp(p->select[i],p->select[j])!=0)
if(p->select[i] !=0)
{
printf("\nThis is not LL1\n");
return 0;
}
}
printf("\nThis is LL1\n");
return 1;
}
2、FIRST集
(1)定义:
设G=(VT,VN,S,P)是上下文无关文法 ,FIRST(α)={a|α→aβ,a∈VT,α,β∈V*}特别的,若α→ε,则规定ε∈FIRST(α)。
结构体如下:
typedef struct {
char T[length];
char first[length][length];
int len;
} ter,*Ter;
(2)根据定义求解FIRST集(对每一文法符号X∈VN 计算FIRST(X)):
① 若X∈VT,则FIRST(X)={X}。
② 若X∈VN,且有产生式X→a…,a∈VT, 则 a∈FIRST(X)X→ε,则ε∈FIRST(X)。
③ X→Y…是一个产生式且Y ∈VN 则把FIRST(Y)中的所有非空符号串ε元素都加入到FIRST(X)中。
④ 若X∈VN;Y1,Y2,…,Yi∈VN,且有产生式X→Y1 Y2 … Yn;当Y1 Y2 … Yn-1→ε时,则FIRST(Y1)、FIRST(Y2)、…、FIRST(Yn-1)的所有非空元素和FIRST(Yn) 包含在FIRST(X)中。
⑤ 当(4)中所有Yi→ε,(i=1,2,…n),则
FIRST(X)=(FIRST(Y1)-{ε})∪(FIRST(Y2)- {ε}∪…∪(FIRST(Yn) -{ε})∪{ε}
反复使用上述(2)~(5)步直到每个符号的FIRST集合不再增大为止。Fist()函数的实现代码如下:
void get_first_set(Prod p,NTer n,Ter t)
{
int i,j,k,temp;
int flag,a,b;
int m;
int tags[n->len];
//int lock[n->len];
int loop=1;
int judge[n->len];
printf("\nBeging finding first set\n");
for(i=0; i<t->len; i++) {
t->first[i][0]=t->T[i];
}
3、FOLLOW集
(1)定义:
设G=(VT,VN,S,P)是上下文无关文法,A∈VN,S是开始符号
需要注意的是,FOLLOW(A)集是针对非终结符A的,集合中的元素是终结符,是A的全部后跟符号的集合,当A是文法G的开始符(识别符)时,把‘#也加入其中‘。数据结构定义如下:
typedef struct {
char N[length];
char first[length][length];
char follow[length][length];
char p_emp[length];
char n_emp[length];
int len;
}*NTer,nter;
(2) 根据定义求解FOLLOW集(对每一文法符号S∈VN 计算FOLLOW(S)):
① 设S为文法中开始符号,把{#}加入FOLLOW(S)中(这里“#”为句子括号)。
② 若A→αBβ是一个产生式,则把FIRST(β)的非空元素加入FOLLOW(B)中。如果β→ε则把FOLLOW(A)也加入FOLLOW(B)中。
③ 反复使用(b)直到每个非终结符的FOLLOW集不再增大为止。
实现函数代码如下:
void get_follow_set(Prod p,NTer n,Ter t,char s_syb)
{
int i,j,k,len,m,x,loop;
int tags[n->len];
int flags[n->len];
for(i=0; ilen; i++) {
tags[i]=0;
flags[i]=0;
}
printf(“start finding follow set\n”);
for(i=0; ilen; i++)
if(s_sybn->N[i]) {
n->follow[i][0]=’#’;
tags[i]++;
break;
}
loop=1;
while(loop1) {
loop=0;
for(i=0; ilen; i++)
flags[i]=tags[i];
for(i=0; ilen; i++) {
j=0;
while(p->pro[i]->back[j]!=’#’) {
if(belong_N(p->pro[i]->back[j],n)) {
for(k=0; klen; k++)
if(n->N[k]==p->pro[i]->back[j])
break;
if(p->pro[i]->back[j+1]!=’#’) {
if(belong_N(p->pro[i]->back[j+1],n)) {
for(m=0; mlen; m++)
if(n->N[m]==p->pro[i]->back[j+1])
break;
tags[k]=join_arr(n->follow[k],n->first[m]);
if(belong_Arr(n->N[m],n->p_emp)) {
for(x=0; xlen; x++)
if(n->N[x]==p->pro[i]->front)
break;
tags[k]=join_arr(n->follow[k],n>follow[x]);
}
} else if(belong_T(p->pro[i]->back[j+1],t)) {
if(!belong_Arr(p->pro[i]->back[j+1],n->follow[k])) {
len=strlen(n->follow[k]);
n->follow[k][len]=p->pro[i]>back[j+1];
tags[k]++;
}
}
}
else {
for(x=0; x<n->len; x++)
if(n->N[x]==p->pro[i]->front)
break;
tags[k]=join_arr(n->follow[k],n->follow[x]);
}
}
j++;
}
}
for(i=0; i<n->len; i++)
if(flags[i]!=tags[i]) {
loop=1;
break;
}
}
printf("The not terminal symbols follow sets are:\n");
for(i=0; i<n->len; i++) {
j=0;
printf("Follow(%c)={",n->N[i]);
while(n->follow[i][j]!='\0') {
printf("%c ",n->follow[i][j]);
j++;
}
printf("}\n");
}
}
4、SELECT集
定义:给定上下文无关文法的产生式A→α, A∈VN,α∈V*:若α不能推导出ε,则SELECT(A→α)=FIRST(α) 如果α能推导出ε则:
SELECT(A→α)=(FIRST(α) –{ε})∪FOLLOW(A)需要注意的是,SELECT集是针对产生式而言的。
数据结构如下:
- typedef struct {
-
Pro pro[length];
-
char string_first[length][length];
-
char select[length][length];
-
int len;
函数实现代码如下:
- void get_select_set(Prod p, NTer n, Ter t) {
-
int i, j, k;
-
int flag = 0;
-
for (i = 0; i < p->len; i++) {
-
if (p->pro[i]->back[0] == '#') {
-
for (k = 0; k < n->len; k++)
-
if (n->N[k] == p->pro[i]->front)
-
break;
-
join_arr(p->select[i], n->follow[k]);
-
continue;
-
}
-
j = 0;
-
flag = 0;
-
while (p->pro[i]->back[j] != '#') {
-
if (!belong_Arr(p->pro[i]->back[j], n->p_emp)) {
-
//flag=1;
-
break;
-
}
-
j++;
-
}
-
if (p->pro[i]->back[j] == '#') {
-
flag = 1;
-
}
-
if (flag == 0) {
-
join_arr(p->select[i], p->string_first[i]);
-
} else if (flag == 1) {
-
join_arr(p->select[i], p->string_first[i]);
-
for (k = 0; k < n->len; k++)
-
if (n->N[k] == p->pro[i]->front)