编译原理乔姆斯基(Chomsky)文法类型判别程序设计(C++)
样例输入1
A->Bc
A->a
$
样例输出1
该文法为3型文法
样例输入2
S->0A
S->1B
S->0
A->0A
A->0S
A->1B
B->1B
B->1
B->0
$
样例输出2
该文法为3型文法
样例输入3
S->1S0
S->A
A->0A1
S->#
$
样例输出3
该文法为2型文法
样例输入4
S->aSBE
S->aBE
EB->BE
aB->ab
bB->bb
bE->be
eE->ee
$
样例输出4
该文法为1型文法
样例输入5
S->Ap
S->Bq
A->a
A->cA
B->b
B->dB
$
样例输出5
该文法为2型文法
解题思路
参考Python实现、4种文法类型判别定义分析、终结符和非终结符
代码
#include<bits/stdc++.h>
using namespace std;
#define ll int
#define pii pair<ll,ll>
#define inf 0x3f3f3f3f
#define IOS ios::sync_with_stdio(0), cin.tie(0)
const ll N = 1e5 * 2 + 5;
struct node {
string l, r; //字符串左右两部分l->r
};
//st_vn标记非终结符号集成员[A-Z],st_vt标记终结符符合集成员[a-zA-Z0-9]
unordered_map<char, ll> st_vn, st_vt;
//特殊字符ε定义为string进行判别
//string esp = "#";
//初始化函数
void init() {
char c1 = 'A', c2 = 'a';
for (int i = 0; i < 26; ++i) {
st_vn[c1 + i] = 1;//[A-Z]
st_vt[c2 + i] = 1;//[a-z]
st_vt[c1 + i] = 1;//[A-Z]
}
for (int i = 0; i < 10; ++i) {
st_vt[i + '0'] = 1;//[0-9]
}
st_vt['#'] = 1;//ε
}
/**
* 判断3型文法
* @param word_rule
* @return
*/
bool ck3(vector<node> &word_rule) {
ll len = word_rule.size();
//f1标记右边是否出现非终结符+终结符的格式(比如Ba)
//f2标记右边是否出现终结符+非终结符的格式(比如aB)
//ct统计格式出现的次数
bool f1 = false, f2 = false;
ll ct = 0;
for(auto it : word_rule) {
string l = it.l, r = it.r;
//左边必须只有一个字符,且必须是非终结符
if (l.size() != 1 || l.size() == 1 && !st_vn.count(l[0])) {
return false;
}
//右边最多只能有两个字符
if (r.size() > 2) {
return false;
}
//右边只有一个字符时只能是终结符
if (r.size() == 1 && !st_vt.count(r[0])) {
return false;
}
//右边有两个字符时要么是非终结符+终结符,或者是终结符+非终结符
if (r.size() == 2) {
++ ct;
//非终结符+终结符
if (st_vn.count(r[0]) && st_vt.count(r[1])) {
f1 = true;
//格式必须统一
if (ct > 1 && f2) {
return false;
}
}
//终结符+非终结符
else if (st_vt.count(r[0]) && st_vn.count(r[1])) {
f2 = true;
if (ct > 1 && f1) {
return false;
}
}
else {
return false;
}
}
}
//没有问题就是第3类型
return true;
}
/**
* 判断2型文法
* @param word_rule
* @return
*/
bool ck2(vector<node> &word_rule) {
ll len = word_rule.size();
for(auto it : word_rule) {
string l = it.l, r = it.r;
//左边必须只有一个字符,且必须是非终结符
if (l.size() != 1 || l.size() == 1 && !st_vn.count(l[0])) {
return false;
}
//如果r是ε那么跳过
if (r[0] != '#') {
for(auto c : r) {
//右边可以含有若干个终结符和非终结符,其他字符则不是
if (!st_vn.count(c) && !st_vt.count(c)) {
return false;
}
}
}
}
//没有问题就是第2类型
return true;
}
/**
* 判断1型文法
* @param word_rule
* @return
*/
bool ck1(vector<node> &word_rule) {
ll len = word_rule.size();
for(auto it : word_rule) {
string l = it.l, r = it.r;
bool f1 = false;
//左边可以含有一个、两个或两个以上的字符,但其中必须至少有一个非终结符
for(auto c : l) {
//非终结符或终结符
if (st_vn.count(c) || st_vt.count(c)) {
if (st_vn.count(c)) {
f1 = true;//至少有一个非终结符
break;
}
} else {
return false;
}
}
//一个非终结符都没有
if (!f1) {
return false;
}
//右边必须符合|α| ≤ |β|,而且r不为 ε
if (l.size() > r.size() && r[0] != '#') {
return false;
}
//如果r是ε那么跳过
if (r[0] != '#') {
for(auto c : r) {
//右边可以含有若干个终结符和非终结符,其他字符则不是
if (!st_vn.count(c) && !st_vt.count(c)) {
return false;
}
}
}
}
//没有问题就是第1类型
return true;
}
void solve() {
init();
vector<string> ve;
vector<node> word_rule;
string s;
//读入文法规则,直到$结束
cout << "请输入文法规则:" << endl;
cout << "提示:大写字母为非终止符,字母或数字0-9为终止符,ε用#代替,第一个产生式左边为开始符,用->分隔,结束用$表示" << endl;
while (cin >> s, s[0] != '$') {
ve.push_back(s);
}
for(auto it : ve) {
ll p = it.find("->");
string l = it.substr(0, p), r = it.substr(p + 2);
word_rule.push_back({l, r});
}
//从3到1型逐一排查,右边符合|α| ≤ |β|
if (ck3(word_rule)) {
cout << "该文法为3型文法" << endl;
} else if(ck2(word_rule)) {
cout << "该文法为2型文法" << endl;
} else if(ck1(word_rule)) {
cout << "该文法为1型文法" << endl;
} else {
cout << "该文法为0型文法" << endl;
}
}
int main( ){
IOS;
// ll t; cin >> t;
ll t = 1;
while (t--) solve();
return 0;
}