LL(1)文法判断程序

实验三 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(loop
1) {
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集是针对产生式而言的。
数据结构如下:

  1. typedef struct {
  2.  Pro pro[length];  
    
  3.  char string_first[length][length];  
    
  4.  char select[length][length];  
    
  5.  int len;  
    

函数实现代码如下:

  1. void get_select_set(Prod p, NTer n, Ter t) {
  2.  int i, j, k;  
    
  3.  int flag = 0;  
    
  4.  for (i = 0; i < p->len; i++) {  
    
  5.      if (p->pro[i]->back[0] == '#') {  
    
  6.          for (k = 0; k < n->len; k++)  
    
  7.              if (n->N[k] == p->pro[i]->front)  
    
  8.                  break;  
    
  9.         join_arr(p->select[i], n->follow[k]);  
    
  10.         continue;  
    
  11.     }  
    
  12.     j = 0;  
    
  13.     flag = 0;  
    
  14.     while (p->pro[i]->back[j] != '#') {  
    
  15.         if (!belong_Arr(p->pro[i]->back[j], n->p_emp)) {  
    
  16.             //flag=1;  
    
  17.             break;  
    
  18.         }  
    
  19.         j++;  
    
  20.     }  
    
  21.     if (p->pro[i]->back[j] == '#') {  
    
  22.         flag = 1;  
    
  23.     }  
    
  24.     if (flag == 0) {  
    
  25.         join_arr(p->select[i], p->string_first[i]);  
    
  26.     } else if (flag == 1) {  
    
  27.         join_arr(p->select[i], p->string_first[i]);  
    
  28.         for (k = 0; k < n->len; k++)  
    
  29.             if (n->N[k] == p->pro[i]->front)  
    
  • 2
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值