一、实验目的
在实验《文法构造一》的基础上,改进文法数据结构的设计,实现First集、Follow集和Select集的计算,进一步加深对文法的理解。
二、实验内容
1)实现First集、Follow集和Select集的计算;
2)输入文法:文法描述存储在文本文件中,文件名作为命令行参数输入;
3)输出每个非终结符的First集到标准输出设备;
4)输出每个非终结符的Follow集到标准输出设备;
5)输出每个产生式的Select集到标准输出设备;
附件:样例
描述:
算术表达式文法G =(VN,VT,P,S)其中:
VN = { S, T, T’ }
VT = { a, ^, (, ) ,}
P = { S → a | ^ |(T)
T → ST’
T’ → ,ST’ | e }
S = S
输入(文法描述文件):
3
S T T'
5
a ^ ( ) ,
6
S -> a
S -> ^
S -> ( T )
T -> S T'
T' -> , S T'
T' -> ε
S
输出(标准输出设备):
CFG=(VN,VT,P,S)
VN: S T T'
VT: a ^ ( ) ,
Production:
0: S -> a
1: S -> ^
2: S -> ( T )
3: T -> S T'
4: T' -> , S T'
5: T' -> ε
StartSymbol: S
[First Set]
S : ^ ( a
T : ^ ( a
T' : ε ,
[Follow Set]
S : # , )
T : )
T' : )
[Select Set]
0:S -> a : a
1:S -> ^ : ^
2:S -> ( T ) : (
3:T -> S T' : ^ ( a
4:T' -> , S T' : ,
5:T' -> ε : )
三、代码
#include <fstream>
#include <sstream>
#include "iostream"
#include "set"
#include "string"
#include "map"
#include "vector"
using namespace std;
#ifndef BIANYI_WENFA_H
#define BIANYI_WENFA_H
class VN{ //非终结符集
private:
int n;
set<string> vn;
public:
int getN() const {
return n;
}
const set<string> &getVn() const {
return vn;
}
void setVn(const set<string> &vn) {
VN::vn = vn;
}
void setN(int n) {
VN::n = n;
}
};
class VT{ //终结符集
private:
int n;
set<string> vt;
public:
int getN() const {
return n;
}
void setN(int n) {
VT::n = n;
}
const set<string> &getVt() const {
return vt;
}
void setVt(const set<string> &vt) {
VT::vt = vt;
}
};
class P{ //产生式
private:
int n;
vector<string> p1; //存放左部
vector<vector<string>> p2; //存放右部
public:
const vector<vector<string>> &getP2() const {
return p2;
}
void setP2(const vector<vector<string>> &p2) {
P::p2 = p2;
}
const vector<string> &getP1() const {
return p1;
}
void setP1(const vector<string> &p1) {
P::p1 = p1;
}
int getN() const {
return n;
}
void setN(int n) {
P::n = n;
}
};
class S{ //开始符号
private:
string s;
public:
const string &getS() const {
return s;
}
void setS(const string &s) {
S::s = s;
}
};
class CFG{
private:
string filename;
VN vn;
VT vt;
P p;
S s;
public:
void setFilename(const string &filename) {
CFG::filename = filename;
}
void fileop() { //读文件
string fileline;
string str;
set<string> middle;
vector<string> p1;
vector<string> mid;
vector<vector<string>> p2;
ifstream fout(filename);
for (int i = 1; getline(fout, fileline); i++) {
if (i == 1) {
vn.setN(atoi(fileline.c_str()));//非终结符个数
} else if (i == 2) { //非终结符集合
istringstream is(fileline);
while (is >> str) {
middle.insert(str);
}
vn.setVn(middle);
middle.clear();
} else if (i == 3) { //终结符个数
vt.setN(atoi(fileline.c_str()));
} else if (i == 4) { //终结符集合
istringstream is(fileline);
while (is >> str) {
middle.insert(str);
}
vt.setVt(middle);
middle.clear();
} else if (i == 5) { //规则个数
p.setN(atoi(fileline.c_str()));
} else if (i == p.getN() + 6) { //指定开始符
s.setS(fileline.c_str());
} else{
istringstream is(fileline);
for(int j=0;is>>str;j++){
if(j==0){
p1.push_back(str);
} else if(j==1);
else {
mid.push_back(str);
}
}
p2.push_back(mid);
mid.clear();
}
}
p.setP1(p1);
p.setP2(p2);
}
void output(){ //输出CFG
cout<<"CFG=(VN,VT,P,S)"<<endl;
cout<<"VN: ";
for(set<string>::iterator it=vn.getVn().begin();it!=vn.getVn().end();it++){
cout<<*it<<" ";
}
cout<<endl<<"VT: ";
for(set<string>::iterator it=vt.getVt().begin();it!=vt.getVt().end();it++){
cout<<*it<<" ";
}
cout<<endl<<"Production:"<<endl;
for(int i=0;i<p.getP1().size();i++){
cout<<" "<<i<<":"<<p.getP1()[i]<<" -> ";
for(int j=0;j<p.getP2()[i].size();j++){
cout<<p.getP2()[i][j];
}
cout<<endl;
}
cout<<"StartSymbol: ";
cout<<s.getS()<<endl;
}
set<string> First1(string str){ //求单个非终结符First集
set<string> first;
set<string> second; //中间集合
if(vt.getVt().count(str)==1){ //终结符本身即为其First集
first.insert(str);
return first;
}
for(int i=0;i<p.getP1().size();i++){
if(str==p.getP1()[i]){ //在左部集找到该非终结符
if(vt.getVt().count(p.getP2()[i][0])==1 || p.getP2()[i][0]=="ε"){ //如果产生式右部第一个字符为终结符或ε,则直接加入其First集
first.insert(p.getP2()[i][0]);
}
else if(vn.getVn().count(p.getP2()[i][0])==1){ //右部第一个为非终结符
for(int j=0;j<p.getP2()[i].size();j++){ //产生式右部遍历
if(vt.getVt().count(p.getP2()[i][j])==1){ //如果是终结符,加入first集,结束遍历
first.insert(p.getP2()[i][j]);
break;
}else if(vn.getVn().count(p.getP2()[i][j])==1 && j!=p.getP2()[i].size()-1){ //如果是非终结符
second =First1(p.getP2()[i][j]); //递归调用
if(second.count("ε")==0){
first.insert(second.begin(),second.end());
second.clear();
break;
}
else{
second.erase("ε");
first.insert(second.begin(),second.end());
second.clear();
}
} else if(vn.getVn().count(p.getP2()[i][j])==1 && j==p.getP2()[i].size()-1){
second =First1(p.getP2()[i][j]);
first.insert(second.begin(),second.end());
second.clear();
}
}
}
}
}
return first;
}
void First(){ //求每一个非终结符First集
map<string,set<string>> first;
for(set<string>::iterator it=vn.getVn().begin();it!=vn.getVn().end();it++){
first.emplace(*it, First1(*it));
}
cout<<"[First Set]"<<endl; //输出First集
for(map<string,set<string>>::iterator it=first.begin();it!=first.end();it++){
cout<<it->first<<" :";
for(set<string>::iterator jj=it->second.begin();jj!=it->second.end();jj++){
cout<<*jj<<" ";
}
cout<<endl;
}
}
set<string> Follow1(string str) { //求单个非终结符的Follow集
set<string> follow;
set<string> second;
if (str == s.getS()) {
follow.insert("#"); //若是开始符,则将#加入
}
for (int i = 0; i < p.getP2().size(); i++) { //遍历产生式右部
for (int j = 0; j < p.getP2()[i].size(); j++) {
if (str == p.getP2()[i][j]) {
if (j == p.getP2()[i].size()-1) { //若其后无元素,则将产生式左部follow集加入
if(p.getP1()[i]!=str){
second = Follow1(p.getP1()[i]); //递归调用
follow.insert(second.begin(), second.end());
second.clear();
}
}
else{
if(vn.getVn().count(p.getP2()[i][j+1])==1){
for(int k=j+1;k<p.getP2()[i].size();k++){
second =First1(p.getP2()[i][k]);
if(second.count("ε")==0){
follow.insert(second.begin(),second.end());
second.clear();
break;
} else {
if(k==p.getP2()[i].size()-1){
second.erase("ε");
follow.insert(second.begin(),second.end());
second.clear();
if(p.getP1()[i]!=p.getP2()[i][k]){
second = Follow1(p.getP1()[i]); //递归调用
follow.insert(second.begin(), second.end());
second.clear();
}
} else{
second.erase("ε");
follow.insert(second.begin(),second.end());
second.clear();
}
}
}
} else if(vt.getVt().count(p.getP2()[i][j+1])){
follow.insert(p.getP2()[i][j+1]);
break;
}
}
}
}
}
return follow;
}
void Follow(){ //求所有非终结符的follow
map<string,set<string>> follow;
for(set<string>::iterator it=vn.getVn().begin();it!=vn.getVn().end();it++){
follow.emplace(*it, Follow1(*it));
}
cout<<"[Follow Set]"<<endl;
for(map<string,set<string>>::iterator it=follow.begin();it!=follow.end();it++){
cout<<it->first<<" : ";
for(set<string>::iterator jj=it->second.begin();jj!=it->second.end();jj++){
cout<<*jj<<" ";
}
cout<<endl;
}
}
void Select(){ //Select集
map<int,set<string>> select;
set<string> second;
set<string> sle;
for(int i=0;i<p.getP2().size();i++){ //遍历产生式右部
if(p.getP2()[i][0]=="ε"){ //若为空串,则将左部follow加入
second= Follow1(p.getP1()[i]);
sle.insert(second.begin(), second.end());
second.clear();
select.emplace(i,sle);
sle.clear();
continue;
}
for(int j=0;j<p.getP2()[i].size();j++){ // 计算产生式右部first集
second=First1(p.getP2()[i][j]);
if(second.count("ε")==0){
sle.insert(second.begin(),second.end());
second.clear();
break;
} else{
if(j==p.getP2()[i].size()-1){
sle.insert(Follow1(p.getP1()[i]).begin(), Follow1(p.getP1()[i]).end());
}
second.erase("ε");
sle.insert(second.begin(),second.end());
second.clear();
}
}
select.emplace(i,sle);
sle.clear();
}
cout<<"[Select Set]"<<endl; //输出select集
for(int i=0;i<p.getP1().size();i++){
cout<<i<<" : "<<p.getP1()[i]<<"->";
for(int k=0;k<p.getP2()[i].size();k++){
cout<<p.getP2()[i][k]<<" ";
}
cout<<" : ";
for(set<string>::iterator j=select[i].begin();j!=select[i].end();j++){
cout<<*j<<" ";
}
cout<<endl;
}
}
};
#endif //BIANYI_WENFA_H
int main(){
string filename;
CFG cfg;
cout<<"Please input file(absolute path; eg: D://filename.txt):"<<endl; //E://by//exp5.txt
cin>>filename;
cfg.setFilename(filename);
cfg.fileop();
cfg.output();
cfg.First();
cfg.Follow();
cfg.Select();
return 0;
}