根据文法规则,判断文法类型

根据文法规则,判断文法类型

1、实验要求

输入:文法规则

输出:文法类型

2、实验原理

文法规则:
以四元组的形式展示出来:
文法G 定义为四元组G={Vn,Vt ,P,S}
Vn :非终结符集
Vt :终结符集
P :产生式集合(规则集合)
S :开始符号(识别符号)

文法类型:
文法类型分为四种:0型文法、1型文法、2型文法和3型文法

  • 0型文法:通俗的说,写出来的文法规则都输出0型文法
  • 1型文法:又称上下文有关文法。
    满足条件:0型文法的基础上,右边字符个数不小于左边字符个数
    例如:S->aBC
    a->Bb
    C->c
  • 2型文法:又称上下文无关文法。
    满足条件:在1型文法的基础上,左部只有一个非终结符
    例如:S->aBC
    B->b
    C->c
  • 3型文法:又称规范文法。
    满足条件:在2型文法的基础上,产生式的右边字符数不超过2个且所有产生式要么都是左递归,要么都是右递归
    例如:S->aB
    B->bC
    C->c
    注:
    S->aB
    B->Cb
    C->c
    不成立,因为字符串既有左递归,又有右递归

四种文法的关系可用如下图表示:
在这里插入图片描述

3、实验步骤

  1. 从键盘上输入文法规则(字符串)
  2. 对字符串进行按行比较,判断其所属的文法类型(先逐行判断文法类型1,然后再逐行判断文法类型2,最后在整个字符串判断文法类型3)
  3. 显示出结果(文法类型)

4、实验过程

  1. 首先是进行结构体的构建,并且为了方便实用定义了全局变量
//结构体 
struct Rule{
	char str[10];
	int k;//记录局部文法类型 
	int left;//记录产生式左边长度 
	int right;//记录产生式右边长度 
}r[10];

int temp;//记录字符串行数 
int level=0;//记录文法类型 

  1. 主函数运到了5个调用函数,分别是输入板块、文法类型1判断板块、文法类型2判断板块、文法类型3判断板块和输出板块
//主函数 
int main(){
	Input();//输入文法规则 
	Transform1();//类型1判断 
	Transform2();//文法类型2判断 
	Transform3();//文法类型3判断 
    Output();//输出文法类型 
	return 0;
} 
  1. 在输入板块进行了文法规则的输入,一字符串的形式从键盘输入,存储到结构体中
//输入文法规则 
void Input(){
	int i,j;
	printf("输入文法规则:\n");
	printf("大写字母为非终止符,小写字母为终止符,第一个产生式左边为开始符,结束用$表示\n");
	for(i=0;i<10;i++){
		scanf("%s",r[i].str);
		j=0;
		if(r[i].str[j]=='$')
		break;
	}
	temp=i; 
}
  1. 文法类型1板块时进行判断文法规则的类型是否符合类型1,符合之后才能进行类型2的判断
//判断文法类型1
void Transform1(){
	int i,j;
	int length;
	for(i=0;i<temp;i++){
		r[i].k=0;
		length=strlen(r[i].str);//字符串长度 
		r[i].left=0;
		for(j=0;r[i].str[j]!='-';j++)//左边长度 
		r[i].left++;
		r[i].right=length-r[i].left-2;//右边长度,减2表示减去字符'-'和'>' 
		if(r[i].right>=r[i].left)
		r[i].k=1;
	}
}
  1. 文法类型2板块时进行判断文法规则的类型是否符合类型2,符合之后才能进行类型3的判断
//判断文法类型2
void Transform2(){
	int i,j,ss=0;
	for(i=0;i<temp;i++){//判断是否字符串是否都为类型1 
		if(r[i].k!=1)
		ss=1;
	}
	if(ss==0)//字符串都为类型1,进行类型2的判断 
	for(i=0;i<temp;i++){
		j=0;
	    if(r[i].left==1)//左边只有一个且是非终结符的类型1,则为类型2 
	    if(r[i].str[j]>='A'&&r[i].str[j]<='Z')
	    r[i].k=2;
	}
	level=1;	
}
  1. 文法类型3板块时进行判断文法规则的类型是否符合类型3
//判断文法类型3
void Transform3(){
	int i,j,t,m,n=0,sum=0,ss=0;
	for(i=0;i<temp;i++){//判断是否字符串是否都为类型2 
		if(r[i].k!=2)
		ss=1; 
	} 
	if(ss==0){//字符串都为类型2,进行类型3的判断 
		level=2;
    	for(i=0;i<temp;i++){
	    	m=r[i].left+2;//产生式右边第一个字符 
     	    if(r[i].str[m]>='a'&&r[i].str[m]<='z')
	    	t=1;
	    	if(r[i].str[m]>='A'&&r[i].str[m]<='Z')
	    	t=0;
	    	sum+=t;
	    	if(r[i].right>2)
	    	n=1;
    	}
     	if(n==0)//保证产生式右边不超过2个字符 
    	if(sum==temp|sum==0)//保证产生式右边是左递归或右递归 
    	level=3;
    }
}

7.在输出板块需要注意的是,不仅要将文法的类型输出,小编也将该四元组进行显示出来

//输出文法类型
void Output(){
	int i,j,m=0,n=0;
	int t,p,ss;
	char S,V1[100],V2[100],Vn[10]={},Vt[10]={};
	S=r[0].str[0];//开始符 
	for(i=0;i<temp;i++){
		for(j=0;j<strlen(r[i].str);j++){
			if(r[i].str[j]>='a'&&r[i].str[j]<='z')
			V1[m++]=r[i].str[j];
			if(r[i].str[j]>='A'&&r[i].str[j]<='Z')
			V2[n++]=r[i].str[j]; 
		}
	}
	t=0;
	for(i=0;i<m;i++){//终止符 
		ss=1;
		for(j=0;j<t;j++){
     		if(V1[i]==Vt[j])
	    	ss=0;
	    }
	    if(ss==1)
	    Vt[t++]=V1[i];
	}
	p=0;
	for(i=0;i<n;i++){//非终止符 
		ss=1;
		for(j=0;j<p;j++){
     		if(V2[i]==Vn[j])
	    	ss=0;
	    }
	    if(ss==1)
	    Vn[p++]=V2[i];
	}
	printf("该文法为第%d类型\n",level);//输出 
	printf("该文法的四元组为:\n");
	printf("S:%c\n",S); 
	printf("Vn=");
	for(i=0;i<p;i++)
	printf("%2c",Vn[i]);
	printf("\nVt=");
	for(i=0;i<t;i++)
	printf("%2c",Vt[i]);
	printf("\nP:\n");
	for(i=0;i<temp;i++)
	printf("%s\n",r[i].str);	
} 

5、源代码和截图

代码已经过调试,无编译错误

#include<stdio.h>
#include<string.h>

//结构体 
struct Rule{
	char str[10];
	int k;//记录局部文法类型 
	int left;//记录产生式左边长度 
	int right;//记录产生式右边长度 
}r[10];

int temp;//记录字符串行数 
int level=0;//记录文法类型 

//输入文法规则 
void Input(){
	int i,j;
	printf("输入文法规则:\n");
	printf("大写字母为非终止符,小写字母为终止符,第一个产生式左边为开始符,结束用$表示\n");
	for(i=0;i<10;i++){
		scanf("%s",r[i].str);
		j=0;
		if(r[i].str[j]=='$')
		break;
	}
	temp=i; 
}

//输出文法类型
void Output(){
	int i,j,m=0,n=0;
	int t,p,ss;
	char S,V1[100],V2[100],Vn[10]={},Vt[10]={};
	S=r[0].str[0];//开始符 
	for(i=0;i<temp;i++){
		for(j=0;j<strlen(r[i].str);j++){
			if(r[i].str[j]>='a'&&r[i].str[j]<='z')
			V1[m++]=r[i].str[j];
			if(r[i].str[j]>='A'&&r[i].str[j]<='Z')
			V2[n++]=r[i].str[j]; 
		}
	}
	t=0;
	for(i=0;i<m;i++){//终止符 
		ss=1;
		for(j=0;j<t;j++){
     		if(V1[i]==Vt[j])
	    	ss=0;
	    }
	    if(ss==1)
	    Vt[t++]=V1[i];
	}
	p=0;
	for(i=0;i<n;i++){//非终止符 
		ss=1;
		for(j=0;j<p;j++){
     		if(V2[i]==Vn[j])
	    	ss=0;
	    }
	    if(ss==1)
	    Vn[p++]=V2[i];
	}
	printf("该文法为第%d类型\n",level);//输出 
	printf("该文法的四元组为:\n");
	printf("S:%c\n",S); 
	printf("Vn=");
	for(i=0;i<p;i++)
	printf("%2c",Vn[i]);
	printf("\nVt=");
	for(i=0;i<t;i++)
	printf("%2c",Vt[i]);
	printf("\nP:\n");
	for(i=0;i<temp;i++)
	printf("%s\n",r[i].str);	
} 

//判断文法类型3
void Transform3(){
	int i,j,t,m,n=0,sum=0,ss=0;
	for(i=0;i<temp;i++){//判断是否字符串是否都为类型2 
		if(r[i].k!=2)
		ss=1; 
	} 
	if(ss==0){//字符串都为类型2,进行类型3的判断 
		level=2;
    	for(i=0;i<temp;i++){
	    	m=r[i].left+2;//产生式右边第一个字符 
     	    if(r[i].str[m]>='a'&&r[i].str[m]<='z')
	    	t=1;
	    	if(r[i].str[m]>='A'&&r[i].str[m]<='Z')
	    	t=0;
	    	sum+=t;
	    	if(r[i].right>2)
	    	n=1;
    	}
     	if(n==0)//保证产生式右边不超过2个字符 
    	if(sum==temp|sum==0)//保证产生式右边是左递归或右递归 
    	level=3;
    }
} 

//判断文法类型2
void Transform2(){
	int i,j,ss=0;
	for(i=0;i<temp;i++){//判断是否字符串是否都为类型1 
		if(r[i].k!=1)
		ss=1;
	}
	if(ss==0)//字符串都为类型1,进行类型2的判断 
	for(i=0;i<temp;i++){
		j=0;
	    if(r[i].left==1)//左边只有一个且是非终结符的类型1,则为类型2 
	    if(r[i].str[j]>='A'&&r[i].str[j]<='Z')
	    r[i].k=2;
	}
	level=1;	
}

//判断文法类型1
void Transform1(){
	int i,j;
	int length;
	for(i=0;i<temp;i++){
		r[i].k=0;
		length=strlen(r[i].str);//字符串长度 
		r[i].left=0;
		for(j=0;r[i].str[j]!='-';j++)//左边长度 
		r[i].left++;
		r[i].right=length-r[i].left-2;//右边长度,减2表示减去字符'-'和'>' 
		if(r[i].right>=r[i].left)
		r[i].k=1;
	}
}	

//主函数 
int main(){
	Input();//输入文法规则 
	Transform1();//类型1判断 
	Transform2();//文法类型2判断 
	Transform3();//文法类型3判断 
    Output();//输出文法类型 
	return 0;
} 





在这里插入图片描述

在这里插入图片描述

  • 17
    点赞
  • 102
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值