一、明确定义
- 0型文法:对任一产生式α→β,都有α∈(VN∪VT)+, β∈(VN∪VT)*
- 1型文法:对任一产生式α→β,都有|β|≥|α|, 仅仅 α→ε除外
- 2型文法:对任一产生式α→β,都有α∈VN , β∈(VN∪VT)*
- 3型文法:任一产生式α→β的形式都为A→aB或A→a,其中A∈VN,B∈VN,a∈VT。上述叫做右线性文法,另有左线性文法,二者等价。
二、基本思路
- 0型文法
- 首先字符串
α
的是
(Vn⋃Vt)+
,是全符号集的一个正闭包,那么包含符号集中所有符号的一个任一组合,但不包含
ε
元素。
- 字符串
β
的是
(Vn⋃Vt)∗
,是全符号集的一个闭包,那么它比
α
会多一个
ε
元素。
- 那么我们想要判断一个文法是否为0型文法,只需要判断左侧非空即可
- 任何0型语言都是递归可枚举的,故0型语言又称递归可枚举集
- 1型文法
- 首先1型文法必须是0型文法
- 1型文法除了
α→ε
这一个特例外,其他情况都满足
β
的长度大于
α
的长度
- 1型文法也叫作上下文相关文法
- 2型文法
- 首先2型文法必须是1型文法
- 2型文法左边必须是一个非终结字符
- 2型文法也叫做上下文无关文法
- 3型文法
- 首先3型文法必须是2型文法
- 3型文法必须是线性文法
- 也就是在A,B为非终结符,a是终结符的情况下,产生式只满足如下两种形式(如下为右线性的例子):
三、代码实现:
- 提供两个实现方案:
- 根据产生式,自己判断
Vn,Vt
,然后判断文法的类型,支持产生式的缩写版本,是最早实现的版本,可能代码的安排上有些混乱,冗余代码也比较多
#include<iostream>
#include<string>
#include <cstdlib>
#include <cstdio>
#include <map>
#include <vector>
#include <cctype>
using namespace std;
typedef struct CSS
{
string left;
string right;
}CSS;
bool Zero (CSS *p, int n)
{
int i,j;
for(i=0;i<n;i++)
{
for(j=0;j<p[i].left.length();j++)
{
if(p[i].left[j]>='A'&&p[i].left[j]<='Z')
break;
}
if(j==p[i].left.length())
{
cout<<"该文法不是0型文法"<<endl;
return 0;
break;
}
}
if(i==n)
return 1;
}
bool First(CSS *p , int n )
{
int i;
if(Zero(p,n))
{
for(i=0;i<n;i++)
{
if((p[i].left.length()>p[i].right.length())&&p[i].right.length()!=NULL)
break;
}
if (i == n )
return 1;
else
{
cout<<"该文法是0型文法"<<endl;
return 0;
}
}
else
return 0;
}
bool Second( CSS*p,int n)
{
int i;
if(First(p,n))
{
for(i=0;i<n;i++)
{
if((p[i].left.length()!=1)||!(p[i].left[0]>='A'&&p[i].left[0]<='Z'))
break;
}
if(i==n)
return 1;
else
{
cout<<"该文法是1型文法"<<endl;
return 0;
}
}
else
return 0;
}
void Third(CSS *p,int n)
{
int i;
if(Second(p,n))
{
for(i=0;i<n;i++)
{
if((p[i].right.length()==0)||(p[i].right.length()>=3)||(p[i].right[0]>='A'&&p[i].right[0]<='Z'))
break;
}
if(i==n)
{
for(i=0;i<n;i++)
{
if(p[i].right.length()==2)
{
if(!(p[i].right[1]>='A'&&p[i].right[1]<='Z'))
break;
}
}
if(i==n)
{
cout<<"该文法属于3型文法"<<endl;
}
else
cout<<"该文法属于2型文法"<<endl;
}
else
cout<<"该文法属于2型文法"<<endl;
}
else
cout<<"结束"<<endl;
}
int main ( )
{
CSS *p = new CSS[100];
map<char,bool> dic;
map<char,bool> dic2;
vector<char> VN;
vector<char> VT;
string input1,input2,input3;
cout <<"请输入文法:"<<endl;
cin >> input1;
cout << "请输入VN: "<<endl;
cin >> input2;
for ( int i = 0 ; i < input2.length() ; i++ )
if ( isalnum ( input2[i] ) )
{
VN.push_back ( input2[i] );
dic[input2[i]]=true;
}
cout <<"请输入产生式规则的个数:"<<endl;
int n;
cin >> n;
cout <<"请输入产生式规则:"<<endl;
int cnt = 0;
for ( int i = 0 ; i < n ; i++ )
{
input3.erase ();
cin >> input3;
bool flag = false;
for ( int j = 0 ; j < input3.length() ; j++ )
if ( input3[j] =='|' ) flag = true;
if ( flag )
{
string temp;
int j;
for ( j = 0 ; j < input3.length(); j++ )
{
if ( input3[j] ==':' )
{
temp = input3.substr(0,j);
j = j+3;
break;
}
}
for ( int k =j ; k < input3.length() ; k++ )
{
if ( isalnum ( input3[k] ) )
{
p[cnt].left = temp;
int tt = k;
for ( ;tt < input3.length(); tt++ )
if ( input3[tt]=='|' ) break;
if ( input3[tt] == '|' ) tt--;
p[cnt].right = input3.substr( k , tt-k+1 );
if ( dic[input3[k]] == false )
{
VT.push_back ( input3[k] );
dic[input3[k]] = true;
}
cnt++;
k = tt;
}
}
continue;
}
for ( int j = 0 ; j < input3.length() ; j++ )
{
if ( input3[j]== ':' )
{
p[cnt].left=input3.substr(0,j);
p[cnt].right=input3.substr(j+3,input3.length());
cnt++;
break;
}
}
for ( int j = 0 ; j < input3.length() ; j++ )
{
if ( isalnum( input3[j] ) )
{
if ( dic[input3[j]] ) continue;
VT.push_back ( input3[j] );
dic[input3[j]] = true;
}
}
}
cout << input1 << " = ( {";
for ( int i = 0 ; i < VN.size()-1 ; i++ )
cout << VN[i] << ",";
cout << VN[VN.size()-1] <<"},{";
for ( int i = 0 ; i < VT.size()-1 ; i++ )
cout << VT[i] << ",";
cout << VT[VT.size()-1] << "},";
cout << "P," << input1[2] << " )"<<endl;
cout << "P : " << endl;
vector<string> output;
vector<string> head[500];
string pre[500];
for ( int i = 0 ; i < cnt ; i++ )
{
int x = p[i].left[0];
head[x].push_back ( p[i].right );
pre[x] = p[i].left;
}
for ( int i = 0 ; i < 500 ; i++ )
{
if ( head[i].size() == 0 ) continue;
string temp = pre[i]+" ::= ";
for ( int j = 0 ; j < head[i].size() ; j++ )
{
temp += head[i][j];
if ( j != head[i].size() - 1 ) temp += " | ";
}
output.push_back ( temp );
}
for ( int i = 0 ; i < output.size() ; i ++ )
cout << output[i] << endl;
Third ( p , cnt );
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
- 192
- 193
- 194
- 195
- 196
- 197
- 198
- 199
- 200
- 201
- 202
- 203
- 204
- 205
- 206
- 207
- 208
- 209
- 210
- 211
- 212
- 213
- 214
- 215
- 216
- 217
- 218
- 219
- 220
- 221
- 222
- 223
- 224
- 225
- 226
- 227
- 228
- 229
- 230
- 231
- 232
- 233
- 234
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
- 192
- 193
- 194
- 195
- 196
- 197
- 198
- 199
- 200
- 201
- 202
- 203
- 204
- 205
- 206
- 207
- 208
- 209
- 210
- 211
- 212
- 213
- 214
- 215
- 216
- 217
- 218
- 219
- 220
- 221
- 222
- 223
- 224
- 225
- 226
- 227
- 228
- 229
- 230
- 231
- 232
- 233
- 234
- 第二个版本则是代码和注释风格比较清楚的实现版本,是周末整理之后的一个缩减的版本,不支持缩写,需要提前设定字符集,但是给出了一个更良好的实现方案,适合理解这4种文法类型。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string>
#include <vector>
#include <cstring>
#include <cctype>
using namespace std;
const int VSIZE= 300;
class Principle
{
public:
string left;
string right;
Principle ( const char* , const char* );
};
vector<char> VN;
vector<char> VT;
vector<Principle> principle;
int type[VSIZE];
void init();
int get_type(char);
bool set_type(char,int);
int get_result ( );
int main ( )
{
char buf[1000];
char ** elements;
while ( true )
{
puts("输入VN:");
gets( buf );
for ( int i = 0 ; i < strlen(buf); i++ )
{
char ch = buf[i];
if ( !isupper(ch) ) continue;
if ( get_type(ch) ) continue;
VN.push_back ( ch );
set_type(ch,1);
}
puts("输入VT:");
gets( buf );
for ( int i = 0 ; i < strlen(buf); i++ )
{
char ch = buf[i];
if ( !islower(ch) ) continue;
if ( get_type(ch) ) continue;
VT.push_back ( ch );
set_type(ch,2);
}
puts("输入产生式:(格式为[A::=...a...]), 输入\"exit\"作为结束");
while ( true )
{
gets ( buf );
if ( !strcmp(buf , "exit" ) ) break;
int i;
for ( i = 0 ; i < strlen(buf) ; i++ )
if ( buf[i] == ':' )
{
buf[i] = 0;
i = i+3;
break;
}
principle.push_back ( Principle( buf , buf+i ) );
printf ( "%s|%s|\n" , buf , buf+i );
}
int flag = get_result();
switch ( flag )
{
case -1:
puts("产生式中出现未知字符");
break;
case 0:
puts("该文法为0型文法");
break;
case 1:
puts("该文法为1型文法");
break;
case 2:
puts("该文法为2型文法");
break;
case 3:
puts("该文法为左线性型文法");
break;
case 4:
puts("该文法为右线性型文法");
break;
}
}
return 0;
}
Principle::Principle ( const char*l , const char* r )
{
left = l;
right = r;
}
bool hasError ( const string& s )
{
for ( int i = 0 ; i < s.length() ; i++ )
if ( !get_type(s[i]) ) return true;
return false;
}
bool isZero ( )
{
for ( int i = 0 ; i < principle.size() ; i++ )
if ( hasError(principle[i].left) ) return false;
else if ( hasError(principle[i].right)) return false;
return true;
}
bool isOne ( )
{
for ( int i = 0 ; i < principle.size(); i++ )
if ( principle[i].left.length() > principle[i].right.length() )
return false;
return true;
}
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;
}
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;
}
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;
}
void init ( )
{
VN.clear();
VT.clear();
principle.clear();
memset ( type , 0 , sizeof ( type ) );
}
int get_type ( char ch )
{
return type[ch];
}
bool set_type ( char ch , int x )
{
type[ch] = x;
return true;
}