根据文法规则,判断文法类型
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,最后在整个字符串判断文法类型3)
- 显示出结果(文法类型)
4、实验过程
- 首先是进行结构体的构建,并且为了方便实用定义了全局变量
//结构体
struct Rule{
char str[10];
int k;//记录局部文法类型
int left;//记录产生式左边长度
int right;//记录产生式右边长度
}r[10];
int temp;//记录字符串行数
int level=0;//记录文法类型
- 主函数运到了5个调用函数,分别是输入板块、文法类型1判断板块、文法类型2判断板块、文法类型3判断板块和输出板块
//主函数
int main(){
Input();//输入文法规则
Transform1();//类型1判断
Transform2();//文法类型2判断
Transform3();//文法类型3判断
Output();//输出文法类型
return 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;
}
- 文法类型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;
}
}
- 文法类型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;
}
- 文法类型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;
}