题记:写这篇博客要主是加深自己对型文法文法的认识和总结实现算法时的一些验经和训教,如果有错误请指出,万分感谢。
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; }
文章结束给大家分享下程序员的一些笑话语录: 程序语言综述
CLIPPER 程序员不去真的猎捕大象,他们只是购买大象部分的库然后花几年的时间试图综合它们。
DBASE 程序员只在夜间猎捕大象,因为那时没人会注意到他们还在使用石弓。
FOXPRO 程序员开始使用更新更好的步枪,这使他们花掉比实际狩猎更多的时间学习新的射击技术。
C 程序员拒绝直接购买步枪,宁可带着钢管和一个移动式机器车间到非洲,意欲从零开始造一枝完美的步枪。
PARADOX 程序员去非洲时带着好莱坞关于猎捕大象的电影剧本,他们认为照剧本行事就会逮到一头大象。
ACCESS 程序员在没有任何猎象经验的经验下就出发了,他们穿着华丽的猎装、带着全部装备,用漂亮的望远镜找到了大象,然后发觉忘了带扳机。
RBASE 程序员比大象还要稀少,事实上,如果一头大象看到了一个RBASE程序员,对他是个幸运日。
VISUAL ACCESS 程序员装上子弹、举起步枪、瞄准大象,这使大象感到可笑,究竟谁逃跑。他们无法抓住大象,因为由于他们对多重控制的偏爱,他们的吉普车有太多的方向盘因而无法驾驶。
ADA、APL和FORTRAN 程序员与圣诞老人和仙女一样是虚构的。
COBOL 程序员对和自己一样濒临灭绝的大象寄予了深切的同情。
--------------------------------- 原创文章 By
型文法和文法
---------------------------------