#include <bits/stdc++.h>
using namespace std;
#define EPSILON char(222)
enum state_type{
START, FINAL, INTERMEDIATE, START_AND_FINAL, DEAD, NONE
};
struct edge{
struct state * to;
char input;
edge(struct state * t, char i = EPSILON){
to = t; input = i;
}
};
struct state{
int id;
state_type type;
vector<edge *> edges;
vector<state *> eps_closure;
state(int &c, state_type t = INTERMEDIATE){
id = c++;
type = t;
}
state(){ }
};
ostream & operator <<(ostream & out, edge * e){
out<<"Edge: ";
if(e->input == EPSILON)
out<<"epsilon";
else
out<<e->input;
out<<" -> "<<e->to->id<<endl;
return out;
}
ostream & operator <<(ostream & out, state * s){
out<<"State: "<<s->id<<endl;
out<<"Type: ";
switch(s->type){
case 0: out<<"START";
break;
case 1: out<<"FINAL";
break;
case 2: out<<"INTERMEDIATE";
break;
case 3: out<<"START_AND_FINAL";
break;
case 4: out<<"DEAD";
break;
case 5: out<<"NONE";
break;
}
out<<endl;
for(int i=0; i<s->edges.size(); i++){
out<<s->edges[i];
}
return out;
}
struct state_set{
state *start, *end;
state_set(int &counter){ start = new state(counter); end = new state(counter); }
state_set(state *s, state *e){ start = s; end = e; }
};
class NFA{
int counter = 0;
vector<state *> states;
public:
NFA(string s){
cout<<"Initializing NFA: "<<s<<endl;
state_set * ss = concat(
OR(
transition('a'),
transition('b')
),
concat(
transition('a'),
concat(
transition('b'),
transition('b')
)
)
);
ss->start->type = START;
ss->end->type = FINAL;
}
void print(bool closure = false){
cout<<"Printing NFA\n"<<endl;
for(int i=0; i<states.size(); i++){
cout<<states[i];
if(closure){
cout<<"Epsilon closure: ";
for(int j=0; j<states[i]->eps_closure.size(); j++)
cout<<states[i]->eps_closure[j]->id<<" ";
}
cout<<endl<<endl;
}
}
void insert_states(state_set * ss){
states.push_back(ss->start);
states.push_back(ss->end);
return;
}
state_set * transition(char input){
state_set * ss = new state_set(counter);
ss->start->edges.push_back(new edge(ss->end, input));
insert_states(ss);
return ss;
}
state_set * star(state_set * input_ss){
state_set * ss = new state_set(counter);
ss->start->edges.push_back(new edge(input_ss->start));
ss->start->edges.push_back(new edge(ss->end));
input_ss->end->edges.push_back(new edge(ss->end));
input_ss->end->edges.push_back(new edge(input_ss->start));
insert_states(ss);
return ss;
}
state_set * concat(state_set * ss1, state_set * ss2){
ss1->end->edges.push_back(new edge(ss2->start));
return new state_set(ss1->start, ss2->end);
}
state_set * OR(state_set * ss1, state_set * ss2){
state_set * ss = new state_set(counter);
ss->start->edges.push_back(new edge(ss1->start));
ss->start->edges.push_back(new edge(ss2->start));
ss1->end->edges.push_back(new edge(ss->end));
ss2->end->edges.push_back(new edge(ss->end));
insert_states(ss);
return ss;
}
void get_closures(){
for(int i=0; i<states.size(); i++){
for(int j=0; j<states[i]->edges.size(); j++){
states[i]->eps_closure.push_back(states[i]);
if(states[i]->edges[j]->input == EPSILON){
states[i]->eps_closure.push_back(states[i]->edges[j]->to);
}
}
}
bool change = true;
while(change){
change = false;
for(int i=0; i<states.size(); i++){
for(int j=0; j<states[i]->eps_closure.size(); j++){
for(int k=0; k<states[i]->eps_closure[j]->eps_closure.size(); k++){
if(find(states[i]->eps_closure.begin(), states[i]->eps_closure.end(), states[i]->eps_closure[j]->eps_closure[k]) == states[i]->eps_closure.end()){
states[i]->eps_closure.push_back(states[i]->eps_closure[j]->eps_closure[k]);
change = true;
}
}
}
}
}
}
};
int main() {
string s;
s = "(a/b)*abb";
// cin>>s;
NFA nfa(s);
// nfa.print();
nfa.get_closures();
nfa.print(true);
return 0;
}