帮我写一段可以将产生式计算出first集和follow集的c++代码
时间: 2023-10-11 13:23:04 浏览: 44
以下是一个简单的C++程序,用于计算给定文法的first集和follow集:
```c++
#include <iostream>
#include <vector>
#include <unordered_set>
#include <unordered_map>
#include <string>
using namespace std;
// 定义产生式
struct Production {
string lhs; // 左部
vector<string> rhs; // 右部
};
// 计算first集
unordered_map<string, unordered_set<string>> first(const vector<Production>& productions) {
unordered_map<string, unordered_set<string>> first_set;
for (const auto& production : productions) {
const auto& lhs = production.lhs;
const auto& rhs = production.rhs;
if (rhs.empty()) {
first_set[lhs].insert("");
} else if (isupper(rhs.front()[0])) {
first_set[lhs].insert(first_set[rhs.front()].begin(), first_set[rhs.front()].end());
} else {
first_set[lhs].insert(rhs.front());
}
for (size_t i = 1; i < rhs.size(); ++i) {
if (isupper(rhs[i - 1][0])) {
first_set[lhs].insert(first_set[rhs[i - 1]].begin(), first_set[rhs[i - 1]].end());
}
if (!is_nullable(first_set, rhs[i - 1])) {
break;
}
if (isupper(rhs[i][0])) {
first_set[lhs].insert(first_set[rhs[i]].begin(), first_set[rhs[i]].end());
} else {
first_set[lhs].insert(rhs[i]);
}
}
}
return first_set;
}
// 判断符号串是否可以推出空串
bool is_nullable(const unordered_map<string, unordered_set<string>>& first_set, const string& symbol) {
const auto& it = first_set.find(symbol);
if (it == first_set.end()) {
return false;
}
const auto& s = it->second;
return s.find("") != s.end();
}
// 计算follow集
unordered_map<string, unordered_set<string>> follow(const vector<Production>& productions, const unordered_map<string, unordered_set<string>>& first_set) {
unordered_map<string, unordered_set<string>> follow_set;
follow_set[productions.front().lhs].insert("$");
bool changed = true;
while (changed) {
changed = false;
for (const auto& production : productions) {
const auto& lhs = production.lhs;
const auto& rhs = production.rhs;
for (size_t i = 0; i < rhs.size(); ++i) {
if (!isupper(rhs[i][0])) {
continue;
}
const auto& symbol = rhs[i];
if (i < rhs.size() - 1) {
const auto& beta = rhs.substr(i + 1);
const auto& beta_first = first_of_string(first_set, beta);
if (beta_first.find("") != beta_first.end()) {
const auto& follow_lhs = follow_set[lhs];
changed |= follow_set[symbol].insert(follow_lhs.begin(), follow_lhs.end()).second;
}
changed |= follow_set[symbol].insert(beta_first.begin(), beta_first.end()).second;
} else {
changed |= follow_set[symbol].insert(follow_set[lhs].begin(), follow_set[lhs].end()).second;
}
}
}
}
return follow_set;
}
// 计算符号串的first集
unordered_set<string> first_of_string(const unordered_map<string, unordered_set<string>>& first_set, const string& str) {
unordered_set<string> result;
for (size_t i = 0; i < str.size(); ++i) {
if (!isupper(str[i])) {
result.insert(str.substr(i, 1));
break;
}
const auto& symbol = str.substr(i, 1);
result.insert(first_set.at(symbol).begin(), first_set.at(symbol).end());
if (!is_nullable(first_set, symbol)) {
break;
}
if (i == str.size() - 1) {
result.insert("");
}
}
return result;
}
int main() {
vector<Production> productions = {
{"E", {"T", "E'"}},
{"E'", {"+", "T", "E'"}},
{"E'", {""}},
{"T", {"F", "T'"}},
{"T'", {"*", "F", "T'"}},
{"T'", {""}},
{"F", {"(", "E", ")"}},
{"F", {"id"}},
};
const auto& first_set = first(productions);
const auto& follow_set = follow(productions, first_set);
// 输出first集
for (const auto& [lhs, set] : first_set) {
cout << "first(" << lhs << ") = { ";
for (const auto& s : set) {
cout << s << " ";
}
cout << "}" << endl;
}
// 输出follow集
for (const auto& [lhs, set] : follow_set) {
cout << "follow(" << lhs << ") = { ";
for (const auto& s : set) {
cout << s << " ";
}
cout << "}" << endl;
}
return 0;
}
```
以上程序根据给定的文法计算first集和follow集。在程序中,将文法表示为一组产生式,每个产生式包含一个左部和右部。在计算first集和follow集时,使用unordered_map和unordered_set来存储集合。