basic functions
parent
bc40182eba
commit
00b817ff04
@ -0,0 +1,4 @@
|
||||
/file1.txt
|
||||
/CMakeLists.txt
|
||||
/cmake-build-debug/
|
||||
/.idea/
|
@ -0,0 +1,512 @@
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include <stack>
|
||||
#include <list>
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
|
||||
#define EPSILON '`'
|
||||
using namespace std;
|
||||
|
||||
class NFANode
|
||||
{
|
||||
int state;
|
||||
map<char,set<NFANode*>> nextMap;
|
||||
public:
|
||||
NFANode(int state)
|
||||
{
|
||||
this->state=state;
|
||||
}
|
||||
void addNext(char c,NFANode* next)
|
||||
{
|
||||
this->nextMap[c].insert(next);
|
||||
}
|
||||
void setNext(map<char,set<NFANode*>> existNextMap)
|
||||
{
|
||||
this->nextMap=std::move(existNextMap);
|
||||
}
|
||||
bool isEnd()
|
||||
{
|
||||
if(nextMap.empty())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
NFANode* getEnd()
|
||||
{
|
||||
set<int> outedStates;
|
||||
NFANode* ptr=this;
|
||||
while(!ptr->isEnd())
|
||||
{
|
||||
outedStates.insert(ptr->getState());
|
||||
for(const auto& itr:ptr->getNextMap())
|
||||
{
|
||||
for(auto it:itr.second)
|
||||
{
|
||||
if(!outedStates.count(it->getState()))
|
||||
{
|
||||
ptr=it;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
NFANode* next()
|
||||
{
|
||||
auto itr=nextMap.begin();
|
||||
return *(itr->second.begin());
|
||||
}
|
||||
map<char,set<NFANode*>> getNextMap()
|
||||
{
|
||||
return nextMap;
|
||||
}
|
||||
int getState()
|
||||
{
|
||||
return state;
|
||||
}
|
||||
};
|
||||
|
||||
class NFA
|
||||
{
|
||||
public:
|
||||
map<char,set<int>> nfaTable[1000];
|
||||
vector< set<int> > dfaStates;
|
||||
set<int> endStates;
|
||||
set<char> charSet;
|
||||
stack<char> operatorStack;
|
||||
stack<NFANode*> nfaMapStack;
|
||||
set<int> outedStateSet;
|
||||
int maxState=0;
|
||||
NFA()
|
||||
{
|
||||
nfaTable[0][EPSILON].insert(1);
|
||||
nfaTable[1]['a'].insert(1);
|
||||
nfaTable[1]['b'].insert(1);
|
||||
nfaTable[1][EPSILON].insert(2);
|
||||
nfaTable[2]['b'].insert(3);
|
||||
nfaTable[3]['b'].insert(4);
|
||||
nfaTable[4]['>'].insert(5);
|
||||
nfaTable[4]['<'].insert(5);
|
||||
nfaTable[4]['!'].insert(6);
|
||||
nfaTable[4]['='].insert(6);
|
||||
nfaTable[5]['='].insert(7);
|
||||
nfaTable[5][EPSILON].insert(7);
|
||||
nfaTable[6]['='].insert(7);
|
||||
nfaTable[7]['1'].insert(8);
|
||||
endStates.insert(8);
|
||||
charSet={'a','b','<','>','=','!','1'};
|
||||
}
|
||||
NFA(const string& regex)
|
||||
{
|
||||
for(int i=0;i<regex.length();i++)
|
||||
{
|
||||
char c=regex[i];
|
||||
if(c=='('||c=='+'||c=='|')
|
||||
{
|
||||
operatorStack.push(c);
|
||||
}
|
||||
else if(c=='*')
|
||||
{
|
||||
NFANode* node=nfaMapStack.top();
|
||||
NFANode* start=nfaMapStack.top();
|
||||
nfaMapStack.pop();
|
||||
auto* startNode=new NFANode(++maxState);
|
||||
auto* endNode=new NFANode(++maxState);
|
||||
startNode->addNext(EPSILON,start);
|
||||
startNode->addNext(EPSILON,endNode);
|
||||
node=node->getEnd();
|
||||
node->addNext(EPSILON,start);
|
||||
node->addNext(EPSILON,endNode);
|
||||
nfaMapStack.push(startNode);
|
||||
if(i+1<regex.length()&®ex[i+1]!=')'&®ex[i+1]!='|'&®ex[i+1]!='*')
|
||||
{
|
||||
operatorStack.push('~');
|
||||
}
|
||||
}
|
||||
else if(c==')')
|
||||
{
|
||||
char op=operatorStack.top();
|
||||
operatorStack.pop();
|
||||
while(op!='(')
|
||||
{
|
||||
calculate(op);
|
||||
op=operatorStack.top();
|
||||
operatorStack.pop();
|
||||
}
|
||||
if(i+1<regex.length()&®ex[i+1]!=')'&®ex[i+1]!='|'&®ex[i+1]!='*')
|
||||
{
|
||||
operatorStack.push('~');
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!charSet.count(c)&&c!=EPSILON)
|
||||
{
|
||||
charSet.insert(c);
|
||||
}
|
||||
auto* startNode=new NFANode(++maxState);
|
||||
auto* endNode=new NFANode(++maxState);
|
||||
startNode->addNext(c,endNode);
|
||||
nfaMapStack.push(startNode);
|
||||
if(i+1<regex.length()&®ex[i+1]!=')'&®ex[i+1]!='|'&®ex[i+1]!='*')
|
||||
{
|
||||
operatorStack.push('~');
|
||||
}
|
||||
}
|
||||
}
|
||||
while(!operatorStack.empty())
|
||||
{
|
||||
char op=operatorStack.top();
|
||||
if(op=='(')
|
||||
{
|
||||
cout<<"regex error: cause by '('"<<endl;
|
||||
return;
|
||||
}
|
||||
operatorStack.pop();
|
||||
calculate(op);
|
||||
}
|
||||
if(nfaMapStack.size()!=1)
|
||||
{
|
||||
cout<<"regex error:internal error"<<endl;
|
||||
return;
|
||||
}
|
||||
NFANode* nfaNode=nfaMapStack.top();
|
||||
endStates.insert(nfaNode->getEnd()->getState());
|
||||
nfaTable[0][EPSILON].insert(nfaNode->getState());
|
||||
}
|
||||
void output()
|
||||
{
|
||||
list<NFANode*> outputList;
|
||||
outputList.push_back(nfaMapStack.top());
|
||||
outedStateSet.insert(nfaMapStack.top()->getState());
|
||||
while(!outputList.empty())
|
||||
{
|
||||
NFANode* nfaNode=outputList.front();
|
||||
outputList.pop_front();
|
||||
cout<<setw(5)<<nfaNode->getState();
|
||||
for(const auto& itr:nfaNode->getNextMap())
|
||||
{
|
||||
for(auto it:itr.second)
|
||||
{
|
||||
/*输出过程中将链表形式的nfa表转换为状态转换表*/
|
||||
nfaTable[nfaNode->getState()][itr.first].insert(it->getState());
|
||||
if(itr.first==EPSILON)
|
||||
{
|
||||
cout<<"EPSILON"<<"->"<<it->getState()<<" ";
|
||||
}
|
||||
else
|
||||
{
|
||||
cout<<"'"<<itr.first<<"'->"<<it->getState()<<" ";
|
||||
}
|
||||
}
|
||||
}
|
||||
if(nfaNode->isEnd())
|
||||
{
|
||||
cout<<"(END)";
|
||||
}
|
||||
cout<<endl;
|
||||
for(const auto& itr:nfaNode->getNextMap())
|
||||
{
|
||||
for(auto it:itr.second)
|
||||
{
|
||||
if(!outedStateSet.count(it->getState()))
|
||||
{
|
||||
outputList.push_back(it);
|
||||
outedStateSet.insert(it->getState());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
cout<<endl;
|
||||
}
|
||||
void calculate(char op)
|
||||
{
|
||||
if(op=='~')
|
||||
{
|
||||
NFANode* secondNode=nfaMapStack.top();
|
||||
nfaMapStack.pop();
|
||||
NFANode* prevNode=nfaMapStack.top();
|
||||
prevNode=prevNode->getEnd();
|
||||
prevNode->setNext(secondNode->getNextMap());
|
||||
}
|
||||
if(op=='|'||op=='+')
|
||||
{
|
||||
auto* startNode=new NFANode(++maxState);
|
||||
auto* endNode=new NFANode(++maxState);
|
||||
NFANode* secondNode=nfaMapStack.top();
|
||||
nfaMapStack.pop();
|
||||
NFANode* prevNode=nfaMapStack.top();
|
||||
nfaMapStack.pop();
|
||||
startNode->addNext(EPSILON,prevNode);
|
||||
startNode->addNext(EPSILON,secondNode);
|
||||
prevNode=prevNode->getEnd();
|
||||
secondNode=secondNode->getEnd();
|
||||
secondNode->addNext(EPSILON,endNode);
|
||||
prevNode->addNext(EPSILON,endNode);
|
||||
nfaMapStack.push(startNode);
|
||||
}
|
||||
}
|
||||
set<int> epsilonExtend(const set<int>& states)
|
||||
{
|
||||
set<int> stateSet;
|
||||
stateSet.insert(states.begin(), states.end());
|
||||
for(int i:states)
|
||||
{
|
||||
if(!nfaTable[i][EPSILON].empty())
|
||||
{
|
||||
set<int> result=epsilonExtend(nfaTable[i][EPSILON]);
|
||||
stateSet.insert(result.begin(), result.end());
|
||||
}
|
||||
}
|
||||
return stateSet;
|
||||
}
|
||||
set<int> move(const set<int>& stateSet,char c)
|
||||
{
|
||||
set<int> result;
|
||||
for(int state : stateSet)
|
||||
{
|
||||
if(!nfaTable[state][c].empty())
|
||||
{
|
||||
result.insert(nfaTable[state][c].begin(), nfaTable[state][c].end());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
int getNextState(const set<int>& state,char c)
|
||||
{
|
||||
set<int> result=move(state,c);
|
||||
if(result.empty())
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
set<int> newState;
|
||||
set<int> epsilonExtendedState=epsilonExtend(result);
|
||||
newState.insert(epsilonExtendedState.begin(), epsilonExtendedState.end());
|
||||
int i;
|
||||
for(i=0;i<dfaStates.size();i++)
|
||||
{
|
||||
if(newState==dfaStates[i])
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
dfaStates.push_back(newState);
|
||||
return i;
|
||||
}
|
||||
};
|
||||
|
||||
class DFA
|
||||
{
|
||||
public:
|
||||
map<char,int> dfaTable[1000];
|
||||
set<int> endStates;
|
||||
set<char> charSet;
|
||||
DFA(NFA& nfa)
|
||||
{
|
||||
this->charSet=nfa.charSet;
|
||||
nfa.dfaStates.push_back(nfa.epsilonExtend({0}));
|
||||
int listLength=1;
|
||||
int current=0;
|
||||
int maxState=0;
|
||||
int list[10000];
|
||||
list[0]=0;
|
||||
while(listLength!=0)
|
||||
{
|
||||
map<char,int> nextState;
|
||||
for(char c:charSet)
|
||||
{
|
||||
nextState[c]=nfa.getNextState(nfa.dfaStates[list[current]],c);
|
||||
this->dfaTable[list[current]][c]=nextState[c];
|
||||
if(nextState[c]==-1)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
for(int i:nfa.dfaStates[nextState[c]])
|
||||
{
|
||||
if(nfa.endStates.count(i))
|
||||
{
|
||||
endStates.insert(nextState[c]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(nextState[c]>maxState)
|
||||
{
|
||||
maxState=nextState[c];
|
||||
list[current+listLength]=nextState[c];
|
||||
listLength++;
|
||||
}
|
||||
}
|
||||
listLength--;
|
||||
current++;
|
||||
}
|
||||
}
|
||||
int move(int currentState,char c)
|
||||
{
|
||||
if(currentState==-1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
if(!charSet.count(c))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
return dfaTable[currentState][c];
|
||||
}
|
||||
void output()
|
||||
{
|
||||
int state=-1;
|
||||
for(const map<char,int>& dfaLine:dfaTable)
|
||||
{
|
||||
state++;
|
||||
if(dfaLine.count(EPSILON))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if(dfaLine.empty())
|
||||
{
|
||||
break;
|
||||
}
|
||||
cout<<setw(5)<<state;
|
||||
for(auto & itr : dfaLine)
|
||||
{
|
||||
if(itr.second==-1)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
cout<<"'"<<itr.first<<"'->"<<itr.second<<" ";
|
||||
}
|
||||
cout<<endl;
|
||||
}
|
||||
cout<<endl;
|
||||
}
|
||||
void outputEndStates()
|
||||
{
|
||||
cout<<"endStates:";
|
||||
for(auto itr:endStates)
|
||||
{
|
||||
cout<<itr<<" ";
|
||||
}
|
||||
cout<<endl;
|
||||
cout<<endl;
|
||||
}
|
||||
void outputCharSet()
|
||||
{
|
||||
for(auto itr:charSet)
|
||||
{
|
||||
cout<<itr<<" ";
|
||||
}
|
||||
cout<<endl;
|
||||
cout<<endl;
|
||||
}
|
||||
void simplify()
|
||||
{
|
||||
for(int i=0;i<100;i++)
|
||||
{
|
||||
if(dfaTable[i].empty())
|
||||
{
|
||||
break;
|
||||
}
|
||||
if(dfaTable[i].count(EPSILON))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
for(int j=0;j<100;j++)
|
||||
{
|
||||
if(dfaTable[j].empty())
|
||||
{
|
||||
break;
|
||||
}
|
||||
if(dfaTable[j].count(EPSILON)||i==j)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
int repeat=true;
|
||||
for(auto k:dfaTable[i])
|
||||
{
|
||||
if(dfaTable[j][k.first]!=k.second)
|
||||
{
|
||||
repeat=false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(repeat)
|
||||
{
|
||||
dfaTable[j][EPSILON]=-1;
|
||||
for(map<char,int>& dfaLine:dfaTable)
|
||||
{
|
||||
for(auto & itr : dfaLine)
|
||||
{
|
||||
if(itr.second==j)
|
||||
{
|
||||
itr.second=i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
void match(const string& temp)
|
||||
{
|
||||
int currentState=0;
|
||||
for(char c:temp)
|
||||
{
|
||||
if(c==';')
|
||||
{
|
||||
break;
|
||||
}
|
||||
if(c==' ')
|
||||
{
|
||||
continue;
|
||||
}
|
||||
currentState=move(currentState,c);
|
||||
}
|
||||
if(endStates.count(currentState))
|
||||
{
|
||||
cout<<temp<<"--yes"<<endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
cout<<temp<<"--no"<<endl;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
string regex="(a|b)*bb(((>|<)(=|`))|((!|=)=))1";
|
||||
cout<<"please input regex(use '`' to represent EPSILON):";
|
||||
cin>>regex;
|
||||
cout.setf(ios::left);
|
||||
NFA nfa=NFA(regex);
|
||||
cout<<"NFA:"<<endl;
|
||||
nfa.output();
|
||||
DFA dfa=DFA(nfa);
|
||||
cout<<"DFA:"<<endl;
|
||||
dfa.output();
|
||||
dfa.simplify();
|
||||
cout<<"simplified DFA:"<<endl;
|
||||
dfa.output();
|
||||
dfa.outputEndStates();
|
||||
cout<<"supported char:"<<endl;
|
||||
dfa.outputCharSet();
|
||||
|
||||
while(true)
|
||||
{
|
||||
cout<<"please input string to test(input 'exit' to quit):";
|
||||
string temp;
|
||||
cin>>temp;
|
||||
if(temp=="exit")
|
||||
{
|
||||
break;
|
||||
}
|
||||
dfa.match(temp);
|
||||
}
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue