7-1 LL(1)分析-判断非终结符是否可以推出空

题目要求

本题目为LL(1)分析程序第一步,判断各非终结符是否可以推出空

输入格式:

输入一个上下文无关文法,先输入文法产生式条数,再输入各个产生式,字符“ε”用“@”表示

输出格式:

输出各非终结符是否可以推出空,"1"代表可以推出空,“0”代表不可以推出空。输出顺序按文法左部非终结符出现的顺序。

输入样例:

在这里给出一组输入。例如

9
S->MH 
S->a 
H->LSo
H->@ 
K->dML
K->@ 
L->eHf
M->K
M->bLM

输出样例:

在这里给出相应的输出。例如

S-1
H-1
K-1
L-0
M-1

实现代码

#include<iostream>
#include<vector>
#include<sstream>
#include<string>
#include<unordered_set>
#include<unordered_map>
#include <algorithm>
#include <cctype>

using namespace std;

struct LL {
    char left;
    string right;
    LL(const char& k, const string& v) : left(k), right(v) {}
};

vector<LL> ll;
vector<char> ll1;


// 去除字符串末尾的空格
void trimRight(std::string& str) {
    str.erase(std::find_if(str.rbegin(), str.rend(), [](int ch) {
        return !std::isspace(ch);
    }).base(), str.end());
}

void init(int n) {
	cin.ignore(); // 忽略前面的换行符
    for (int i = 0; i < n; ++i) {
        string line;
        getline(cin, line);
        trimRight(line);
        char left = line[0];  // 左侧非终结符
        string right = line.substr(3);  // 右侧产生式
        ll.emplace_back(left, right);
        ll1.emplace_back(left);
    }
}

//去重左部
void removeSampleLeft(vector<char>& ll2) {
    unordered_set<char> seen;
    vector<char> uniqueVec;
    
    for (const char elem : ll2) {
        if (seen.insert(elem).second) { // 检查插入是否成功
            uniqueVec.push_back(elem);
        }
    }
    
    ll2 = move(uniqueVec); // 将去重后的向量赋值回原向量
}

// 判断字符是否为大写字母
bool isNonEnd(char c) {
    return c >= 'A' && c <= 'Z';
}


// 判断产生式列表中的非终结符是否可以推出空串
unordered_set<char> judgeNull(const vector<LL>& productions) {
    unordered_set<char> nullable;  // 可以推出空串的非终结符
    unordered_map<char, vector<string>> prod_map;  // 非终结符和它们的产生式映射
    unordered_set<char> output_set;  // 记录已经处理过的非终结符

    // 初始化产生式映射
    for (const LL& prod : productions) {
        if (prod.right == "@") {
            // 如果右侧是空串,左侧非终结符可以推出空串
            nullable.insert(prod.left);
        } else {
            prod_map[prod.left].push_back(prod.right);
        }
    }

    bool changed = true;
    while (changed) {
        changed = false;

        // 检查每个非终结符的产生式
        for (const auto& pair : prod_map) {
            char lhs = pair.first;  // 非终结符
            //cout<<lhs<<endl;
            if (nullable.count(lhs)) {
            	//cout<<lhs<<endl;
                continue;  // 已经知道该非终结符可以推出空串
            }
            //printNullable(nullable);
            const auto& rhs_list = pair.second;  // 该非终结符的产生式列表
            for (const string& rhs : rhs_list) {
            	//cout<<rhs<<endl;
                // 判断右侧是否可以全部推出空串
                bool can_derive_empty = true;
                //cout<<can_derive_empty<<endl;
                for (char c : rhs) {
                	//cout<<c<<' ';
                    if (nullable.find(c) == nullable.end()) {
                        can_derive_empty = false;
                        break;
                    }
                    //cout<<can_derive_empty<<endl;
                }
                if (can_derive_empty) {
                    nullable.insert(lhs);
                    changed = true;
                    break;
                }
            }
        }
    }
    return nullable;  // 返回可以推出空串的非终结符集合
}

//测试输出
//void print() {
//    for (const char pair : ll1) {
//        cout << "left: " << pair << endl;
//    }
//}

//输出
void printNullable(const unordered_set<char>& nullable) {
    //cout << "可以推出@的非终结符有:" << endl;
    for(const char pair : ll1){
    	int flag = 0;
    	for (char c : nullable) {
    			if(pair == c){
    				flag=1;
    				cout<<pair<<"->1"<<endl;
    				break;
				}
    	}
    	if(flag == 0){
    		cout<<pair<<"->0"<<endl;
		}
    }
}

int main() {
    int n;
    cin >> n;
    init(n);
    removeSampleLeft(ll1);
    //print();
    unordered_set<char> nullable = judgeNull(ll);
    printNullable(nullable);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值