文法的类型

Chomsky将文法分成4中类型

文法G 定义为四元组(VN ,VT ,P,S)

VN :非终结符集

VT :终结符集

P :规则集合

S :开始符

首先定义一个产生式

α→β

0型文法:

α∈(VN∪VT)* ,且至少含一个VN,β∈(VN∪VT)*

0型文法的能力相当于图灵机(Turing),或者说,任何0型语言都是递归可枚举的;反之,递归可枚举集必定是一个0型语言

1型文法(上下文有关文法context-sensitive):

对任一产生式α→β,都有|β|>=|α|,仅仅 S→ε除外

产生式的形式描述:α1Aα2→α1βα2

(其中,α1、α2、β∈(VN∪VT)*,β≠ε,A∈VN)

即:A只有出现在α1α2的上下文中,才允许用β替换。

产生的语言称“上下文有关语言”

2型文法( 上下文无关文法context-free):

对任一产生式α→β,都有α∈VN,β∈(VN∪VT)*

产生式的形式描述:A→β(A∈VN),即β取代A时,与A所处的上下文无关。

3型文法:正规文法

每个产生式均为“A→aB”或“A→a”—— 右线性

“A→Ba”或“A→a”—— 左线性

其中,A、B∈VN,a∈VT*

下面用C语言模拟文法类型的判断

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
char vn[26];//非终结符,默认为大写字符
char vt[26];//终结符,默认为小写字符
int len1,len2;//非终结符和终结符的个数
int num;//规则的数目
int ans;//判断是几型文法
struct guize
{
	char s1[20];//规则的左部
	char s2[20];//规则的右部
}guize[100];
int hash[200];//哈希标记非终结字符和终结字符
void init()
{
	int i;
	len1=strlen(vn);
	len2=strlen(vt);
	memset(hash,0,sizeof(hash));
	for(i=0;i<len1;i++)
	hash[vn[i]]=-1;//非终结符标记为-1
	for(i=0;i<len2;i++)
	hash[vt[i]]=1;//终结符标记为1
}
//判断该文法是否合法
int judge(char s[20]) 
{
	int len=strlen(s);
	int i;
	for(i=0;i<len;i++)
	{
		if(hash[s[i]]==0) //产生式中的字母未在终结和非终结符号中出现
		{
			return 0;
		}
	}
	return 1;
}
//判断该文法是否是0型文法,即s1中应含有非终结符
int judge0(char s[20])
{
	int i,len=strlen(s);
	for(i=0;i<len;i++)
	if(hash[s[i]]==-1)
	return 1;
	return 0;
}
//判断是否为1型文法,即s2的长度大于等于s1的长度
int judge1(char s1[20],char s2[20])
{
	int l1,l2;
	l1=strlen(s1);
	l2=strlen(s2);
	return (l2>=l1?1:0);
}
//判断是否为2型文法,即s1为非终结符
int judge2(char s1[20],char s2[20])
{
	if(strlen(s1)==1&&hash[s1[0]]==-1)
	return 1;
	return 0;
}
//判断是否为3型文法,即A->aB||A->a或A->Ba||A->a(A,B∈VN,a∈VT*)
int judge3(char s1[20],char s2[20])
{
	int i,len,tnum,size;
	if(strlen(s1)==1&&hash[s1[0]]==-1) //左部是非终结符
	{
		len=strlen(s2);
		//记录非终结符的个数和出现的位置
        tnum=0;
		size=-1;
		for(i=0;i<len;i++)
		if(hash[s2[i]]==-1)
		{
			tnum++;
			size=i;
		}
		if(tnum==0)
		return 1;//A->a
		if(tnum==1&&size==(len-1))
		return 2;//A->aB
		if(tnum==1&&size==0)
		return 3;//A->Ba
		return 0;//非3型文法
	}
    return 0;
}
int main()
{
	int i,temp,flag2,flag3;
	printf("G=(VN,VT,P,S)\n");
	printf("please input VN\n");
	scanf("%s",vn);
	printf("please input VT\n");
	scanf("%s",vt);
	init();
	printf("please input P\n");
	printf("please input the num of the P ");
	scanf("%d",&num);
	for(i=0;i<num;i++)
	scanf("%s -> %s",guize[i].s1,guize[i].s2);
    ans=3;
	flag2=flag3=0;
	for(i=0;i<num;i++)
	{
		if(!judge(guize[i].s1)||!judge(guize[i].s2))//如果文法非法,直接跳出循环
		{
		    ans=-1;
	    	break;
		}
		temp=judge3(guize[i].s1,guize[i].s2);//判断是否为3型文法
	    if(temp==2)//A->aB
		flag2++;
		if(temp==3)//A->Ba
		flag3++;
		if(temp==0||(flag2&&flag3)) //A->aB与A->Ba不能同时出现
		{
			ans=2;
			if(!judge2(guize[i].s1,guize[i].s2))//判断是否为2型文法
			{
				ans=1;
				if(!judge1(guize[i].s1,guize[i].s2))//判断是否为1型文法
				{
				    ans=0;
					if(!judge0(guize[i].s1))
					{
						ans=-1;
						break;
					}
				}
			}
		}
	}
	switch(ans)
	{
         case -1:printf("该文法非法\n");break;
		 case 0:printf("该文法为0型文法\n");break;
		 case 1:printf("该文法为1型文法\n");break;
		 case 2:printf("该文法为2型文法\n");break;
		 case 3:printf("该文法为3型文法\n");break;
	}
	return 0;
}
		


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值