编译原理乔姆斯基(Chomsky)文法类型判别程序设计(C++)

编译原理乔姆斯基(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;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值