一、实验原理
了解0123型文法的定义并会判断各个文法,会编写并利用程序进行0123型文法的判断
二、实验目的
由于不同文法的判断归根结底是对产生式中不同终结符和非终结符个数的判断,所以在程序中先放置三个字符串集合用以存储终结符、非终结符、产生式,然后利用正则表达式进行产生式左右部的比对与判断
三、实验内容
1.自由输入一种文法进行待判断;
2.通过键盘输入的文法程序进行自我判断,之后将判断好的结果在控制台进行展示;
四、实验步骤
//chomsky文法判断
//0型文法 : 只需要判断左侧非空
//1型文法 :|a| < |b| 左侧长度小于右侧长度
//2型文法 : 左边必须是一个非终结符
//3型文法 : A→aB
// A→a
//注:层层递进
#include<iostream>
#include<vector> //vector容器
#include<string>
#include<string.h> //memset()函数,进行清理工作
#include<cstdio>
#include<cctype> //用于测试和映射字符
using namespace std;
const int SIZE = 300;
class Principle
{
public:
string left; //表达式左侧
string right; //表达式右侧
Principle(const char *,const char *); //构造函数
~Principle(); //析构函数
};
//const修饰函数参数:对于函数的入参,
//不管是什么数据类型,也不管是 指针传递,
//还是 引用传递,只要加了 const 修饰,就可以防止函数内意外修改该参数,起到保护作用。
Principle::Principle(const char *l,const char *r)
{
left = l;
right = r;
}
Principle::~Principle()
{
}
//仅考虑所有元素仅有一个字符的情况
vector<char> VN; //非终结符
vector<char> VT; //终结符
vector<Principle> principle; //产生式的集合
int type[SIZE]; //每个字符的类型
void input(); //输入数据
void judge(); //判断文法
void init(); //清理工作/初始化
int get_type(char); //1是非终结符,2是终结符
bool set_type(char,int); //设置一个字符的类型
int get_result();//获取输入文法的类型
int main()
{
while (true)
{
input();
judge();
}
getchar();
getchar();
return 0;
}
//输入函数
void input()
{
char buffer[1000];
char ** elements;
cout<<"输入VN:"<<endl;
cin>>buffer;
for (int i = 0; i < strlen(buffer); i++)
{
char ch = buffer[i];
if (! isupper(ch)) continue; //判断大写字母
if (get_type(ch)) continue;
VN.push_back(ch);
set_type(ch,1);
}
cout<<"输入VT:"<<endl;
cin>>buffer;
for (int i = 0; i < strlen(buffer); i++)
{
char ch = buffer[i];
if (! islower(ch)) continue; //判断小写字母
if (get_type(ch)) continue;
VT.push_back(ch);
set_type(ch,2);
}
cout<<"输入产生式:(格式为[A::=...a..]),输入exit作为结束"<<endl;
while (true)
{
cin>>buffer;
if (! strcmp(buffer,"exit"))
{
break;
}
int i;
for (i = 0; i < strlen(buffer); i++)
{
if (buffer[i] == ':')
{
buffer[i] = 0;
i = i+3;
break;
}
}
principle.push_back(Principle(buffer,buffer+i));
cout<<buffer<<buffer+i<<endl;
}
}
void judge()
{
int flag = get_result();
switch (flag)
{
case -1:
cout<<"产生式中出现未知字符"<<endl;
break;
case 0:
cout<<"该文法为0型文法"<<endl;
break;
case 1:
cout<<"该文法为1型文法"<<endl;
break;
case 2:
cout<<"该文法为2型文法"<<endl;
break;
case 3:
cout<<"该文法为左线性型文法"<<endl;
break;
case 4:
cout<<"该文法为右线性型文法"<<endl;
break;
}
}
void init()
{
VN.clear();
VT.clear();
principle.clear();
memset(type,0,sizeof(type));
}
bool set_type(char ch,int x)
{
type[ch] = x;
return true;
}
int get_type(char ch)
{
return type[ch];
}
//判断字符串是否包含未知字符
bool hasError(const string &s)
{
for (int i = 0; i < s.length(); i++)
{
if (! get_type(s[i]))
{
return true;
}
}
return false;
}
//判断是否为0型文法
bool isZero()
{
for (int i = 0; i < principle.size(); i++)
{
if(hasError(principle[i].left) || hasError(principle[i].right)) return false;
}
return true;
}
//判断是否为1型文法
bool isOne()
{
for (int i = 0; i < principle.size(); i++)
{
if (principle[i].left.size() > principle[i].right.size() )
{
return false;
}
}
return true;
}
//判断是否为2型文法
bool isTwo()
{
for ( int i = 0 ; i < principle.size() ; i++ )
{
string left = principle[i].left;
if ( left.size() != 1 ) return false;
if ( get_type(left[0]) != 1 ) return false;
}
return true;
}
//判断一个2型文法是否为左线性文法
bool isLeftThree ()
{
for ( int i = 0 ; i < principle.size() ; i++ )
{
string right = principle[i].right;
for ( int j = 1; j < right.length() ; j++ )
if ( get_type(right[j]) != 2 ) return false;
}
return true;
}
//判断一个2型文法是否为右线性文法
bool isRightThree ()
{
for ( int i = 0 ; i < principle.size() ; i++ )
{
string right = principle[i].right;
for ( int j = 0 ; j < right.length()-1; j++ )
if ( get_type(right[j]) != 2 )
return false;
}
return true;
}
int get_result ( )
{
if ( !isZero() ) return -1;
if ( !isOne() ) return 0;
if ( !isTwo() ) return 1;
if ( isLeftThree() ) return 3;
if ( isRightThree() ) return 4;
return 2;
}