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;
}