题目要求
本题目为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;
}