#include <iostream>
#include <cstring>
#include <vector>
#include <stack>
#include <map>
#include <string>
#include <algorithm>
using namespace std;
const int maxn = 200; // 状态数的最多数
const int maxm = 27; // a-z和E共27个字母
unsigned N, M; //N表示状态数,M表示输入正则表达式含有的字母数
string s; //s是输入的正则表达式
string alphabet( "abcdefghijklmnopqrstuvwxyzE)*+?" );//正则表达式中需要构造子NFA的字符
stack<char> char_operator; //存储操作符
stack< pair<int, int> > nfa;
vector<int> NFA[ maxn ][ maxm ];//NFA的状态转移表
/*******正则表达式转NFA*********/
/*遇到闭包运算符*/
void star_NFA() {
pair<int, int> new_nfa; //新建一个NFA
new_nfa.first = N++; //这行和下面一行表明总状态数加2
new_nfa.second = N++;
pair<int, int> s = nfa.top();//从栈中弹出一个NFA
nfa.pop();
NFA[ new_nfa.first ][ 26 ].push_back( s.first ); /*new_nfa的头通过ε指向s的头*/
NFA[ new_nfa.first ][ 26 ].push_back( new_nfa.second ); /*new_nfa的头通过ε指向new_nfa的尾*/
NFA[ s.second ][ 26 ].push_back( s.first ); /*s的尾通过ε指向s的头*/
NFA[ s.second ][ 26 ].push_back( new_nfa.second );/*s的尾通过ε指向new_nfa的尾*/
nfa.push( new_nfa ); /*最后将新生成的NFA入栈*/
}
/*遇到或运算符*/
void or_NFA() {
char_operator.pop();
pair<int, int> new_nfa; //新建一个NFA
new_nfa.first = N++; //这行和下面一行表明总状态数加2
new_nfa.second = N++;
pair<int, int> s = nfa.top(); //从栈中弹出两个NFA
nfa.pop();
pair<int, int> t = nfa.top();
nfa.pop();
NFA[ new_nfa.first ][ 26 ].push_back( s.first ); /*new_nfa的头通过ε指向s的头*/
NFA[ new_nfa.first ][ 26 ].push_back( t.first ); /*new_nfa的头通过ε指向t的头*/
NFA[ s.second ][ 26 ].push_back( new_nfa.second ); /*s的尾通过ε指向new_nfa的尾*/
NFA[ t.second ][ 26 ].push_back( new_nfa.second ); /*t的尾通过ε指向new_nfa的尾*/
nfa.push( new_nfa ); /*最后将新生成的NFA入栈*/
}
/*遇到&运算符*/
void connect_NFA() {
char_operator.pop();
pair<int, int> t = nfa.top(); //从栈中弹出两个NFA
nfa.pop();
pair<int, int> s = nfa.top();
nfa.pop();
pair<int, int> r( s.first, t.second ); //新建的NFA的头为s的头,尾为t的尾
NFA[ s.second ][ 26 ].push_back( t.first ); /*s的尾通过ε指向t的头*/
nfa.push( r );
}
/*遇到操作数*/
void alp_NFA( int i ) { //0-25表示a-z,26表示E
pair<int, int> new_nfa; //新建一个NFA
new_nfa.first = N++; //NFA状态总数加1
new_nfa.second = N++; //NFA状态总数加1
NFA[ new_nfa.first ][ i ].push_back( new_nfa.second );//NFA的头指向尾,弧上的值为i对应的字母
nfa.push( new_nfa );
}
/*遇到?运算符*/
void question_NFA() {
pair<int, int> new_nfa; //新建一个NFA
new_nfa.first = N++; //这行和下面一行表明总状态数加2
new_nfa.second = N++;
pair<int, int> s = nfa.top(); //从栈中弹出NFA
nfa.pop();
NFA[ new_nfa.first ][ 26 ].push_back( s.first ); /*new_nfa的头通过ε指向s的头*/
NFA[ new_nfa.first ][ 26 ].push_back( new_nfa.second ); /*t的头通过ε指向new_nfa的尾*/
NFA[ s.second ][ 26 ].push_back( new_nfa.second ); /*s的尾通过ε指向new_nfa的尾*/
nfa.push( new_nfa );
}
/*遇到+运算符*/
void plus_NFA() {
pair<int, int> new_nfa;
new_nfa.first = N++;
new_nfa.second = N++;
pair<int, int> s = nfa.top();
nfa.pop();
NFA[ new_nfa.first ][ 26 ].push_back( s.first ); /*new_nfa的头通过ε指向s的头*/
NFA[ s.second ][ 26 ].push_back( s.first ); /*s的尾通过ε指向s的头*/
NFA[ s.second ][ 26 ].push_back( new_nfa.second ); /*s的尾通过ε指向new_nfa的尾*/
nfa.push( new_nfa );
}
void REtoNFA() {
//先将上个表达式的数据清除
N = 0;
for ( int i = 0; i < maxn; i++ ) {
for ( int j = 0; j < maxm; j++ )
NFA[ i ][ j ].clear();
}
while ( !char_operator.empty() )
char_operator.pop();
while ( !nfa.empty() )
nfa.pop();
//遍历正则表达式并对相应字符做出处理
for ( unsigned i = 0; i < s.size(); i++ ) {
if ((s[i] >= 'a' && s[i] <= 'z')||s[i]=='E') {
if ( i != 0 && alphabet.find( s[ i - 1 ] ) != string::npos ) {
if ( !char_operator.empty() && char_operator.top() == '&' )
connect_NFA();
char_operator.push( '&' );
}
if(s[i] >= 'a' && s[i] <= 'z')
alp_NFA( s[ i ] - 'a' ); //操作数在a-z之间
else
{
alp_NFA(26);//空串E对应的数字为26
}
}
else if ( s[ i ] == '|' ) {
while ( !char_operator.empty() && char_operator.top() != '(' ) {
if ( char_operator.top() == '|' )
or_NFA();
else if ( char_operator.top() == '&' )
connect_NFA();
}
char_operator.push( '|' );
}
else if ( s[ i ] == '?' )
question_NFA();
else if ( s[ i ] == '*' )
star_NFA();
else if ( s[ i ] == '+' )
plus_NFA();
else if ( s[ i ] == '(' ) {
if ( i != 0 && alphabet.find( s[ i - 1 ] ) != string::npos ) {
if ( !char_operator.empty() && char_operator.top() == '&' )
connect_NFA();
char_operator.push( '&' );
}
char_operator.push( '(' );
}
else if ( s[ i ] == ')' ) {
while ( char_operator.top() != '(' ) {
if ( char_operator.top() == '|' )
or_NFA();
else if ( char_operator.top() == '&' )
connect_NFA();
}
char_operator.pop();
}
}
while ( !char_operator.empty() ) {
if ( char_operator.top() == '|' )
or_NFA();
else if ( char_operator.top() == '&' )
connect_NFA();
}
}
/*********NFA转DFA*********/
map< vector<int>, int > trans;//转换表
//求一个状态集的ε-cloure(T)
vector<int> e_Closure( vector<int> T ) {
stack<int> temp;
vector<int>::iterator it;
int t;
for ( it = T.begin(); it != T.end(); it++ ) //将T的所有状态压入栈中
temp.push( *it );
while ( !temp.empty() ) { //当栈非空时
t = temp.top(); //将栈顶元素t弹出栈中
temp.pop();
for ( it = NFA[ t ][ 26 ].begin(); it != NFA[ t ][ 26 ].end(); it++ ) {//对每个满足如下条件的it:从 t出发有一个标号为E的转换到达状态it
if ( find( T.begin(), T.end(), *it ) == T.end() ) {//如果it不在ε-cloure(T)中
T.push_back( *it );//将it加入ε-cloure(T)中
temp.push( *it ); //将it压入栈中
}
}
}
sort( T.begin(), T.end() );
return T;
}
//计算move(T,a)
vector<int> move( vector<int> T, int a ) {
vector<int>::iterator it1, it2;
vector<int> Set;
for ( it1 = T.begin(); it1 != T.end(); it1++ ) {
for ( it2 = NFA[ *it1 ][ a ].begin(); it2 != NFA[ *it1 ][ a ].end(); it2++ ) {
if ( find( Set.begin(), Set.end(), *it2 ) == Set.end() )
Set.push_back( *it2 );
}
}
return Set;
}
//子集构造法将NFA转为DFA
void NFAtoDFA(int dfa[maxn][maxm],bool isFinal[maxn]) {
//初始数据
M = 0;
trans.clear();
pair<int, int> r = nfa.top();
vector<int> T, Set;
T.push_back( r.first );
Set = e_Closure( T );
vector< vector<int> > Dstates;
stack< vector<int> > s;
Dstates.push_back( Set );
s.push( Set );
trans[ Set ] = M++;
if ( find( Set.begin(), Set.end(), r.second ) != Set.end() )
{
isFinal[M-1]=true;
}
while ( !s.empty() ) {
T = s.top();
s.pop();
for ( int a = 0; a < maxm; a++ ) {
Set = e_Closure( move( T, a ) );
if ( find( Dstates.begin(), Dstates.end(), Set ) == Dstates.end() ) {
Dstates.push_back( Set );
s.push( Set );
trans[ Set ] = M++;
if ( find( Set.begin(), Set.end(), r.second ) != Set.end() )
{
isFinal[M-1]=true;
}
}
dfa[ trans[ T ] ][ a ] = trans[ Set ];
}
}
}
bool visit[maxn][maxn];
//将状态取反 ,用于求一个dfa的补集
void back(bool isFinal[maxn],bool noFinal[maxn])
{
for(int i=0;i<maxn;i++)
{
if(isFinal[i])
noFinal[i]=false;
else
noFinal[i]=true;
}
}
//判断当两个DFA此时的状态都为接受态时,返回true
bool receive(int start1,int start2,bool isFinal1[maxn],bool isFinal2[maxn])
{
return isFinal1[start1]&&isFinal2[start2];
}
//判断两个dfa是否相交
bool judge(int dfa1[maxn][maxm], int dfa2[maxn][maxm],int start1,int start2,bool isFinal1[maxn],bool isFinal2[maxn],bool visit[maxn][maxn])
{
visit[start1][start2]=true;
if (receive(start1,start2,isFinal1,isFinal2))
return true;
for(int i=0;i<26;i++)
{
int next1=dfa1[start1][i];
int next2=dfa2[start2][i];
if(!visit[next1][next2])
{
if(judge(dfa1,dfa2,next1,next2,isFinal1,isFinal2,visit))
return true;
visit[next1][next2]=false;
}
}
return false;
}
int main(){
int dfa1[maxn][maxm],dfa2[maxn][maxm];
bool isFinal1[maxn],isFinal2[maxn];//是否为终态,终态为true;
bool noFinal1[maxn],noFinal2[maxn];//状态的的补集
int counts;
cin>>counts;
while(counts>0)
{
//初始化
for(int i=0;i<maxn;i++)
{
for(int j=0;j<maxm;j++)
{
dfa1[i][j]=0;
dfa2[i][j]=0;
}
isFinal1[i]=false;
noFinal1[i]=true;
isFinal2[i]=false;
noFinal2[i]=true;
}
int start1=0,start2=0; //两个dfa开始状态
cin>>s;//输入第一个表达式
REtoNFA();
NFAtoDFA(dfa1,isFinal1);
cin>>s;//输入第二个表达式
REtoNFA();
NFAtoDFA(dfa2,isFinal2);
back(isFinal1,noFinal1);//对DFA的状态取补集
back(isFinal2,noFinal2);
memset(visit, false, sizeof(visit));
bool yes1=judge(dfa1,dfa2,start1,start2,noFinal1,isFinal2,visit);
memset(visit, false, sizeof(visit));
bool yes2=judge(dfa1,dfa2,start1,start2,isFinal1,noFinal2,visit);
//判断这两个表达式的关系
if(yes1&&yes2) //如果dfa1的补和dfa2相交且dfa1和dfa2的补相交,则两个dfa不是等价关系也不是子集关系
printf("!\n");
else if(yes1) //如果dfa1的补和dfa2相交且dfa1和dfa2的补不相交,则dfa1是dfa2的子集
printf("<\n");
else if(yes2)
printf(">\n"); //如果dfa1的补和dfa2不相交且dfa1和dfa2的补相交,则dfa2是dfa1的子集
else
printf("=\n"); //如果dfa1的补和dfa2不相交且dfa1和dfa2的补不相交,则两个dfa是等价关系
counts--;
}
return 0;
}
编译原理林瀚期末大作业-Source code
最新推荐文章于 2024-01-16 14:36:36 发布