基于DFA的词法分析(二):构造DFA
字符串预处理(加上&符号分隔)
中缀转后缀(结果仍然是string)
后缀转NFA:
定义一个存NFA的栈
定义一个NFA Ans用于保存最后的答案,下面提到的状态状态数等无特殊说明均指Ans的成员
一个循环:每次读取后缀表达式的一个字符,读完为止
然后根据读到的字符串的不同,可以分为以下几种情况处理:
对操作数的定义为:从正则表达式读取到的非操作符的字符,存在一个set(All_Char)内
- –操作数:
新建一个NFA(新建两个节点即状态(状态总数+2),然后NFA的头尾分别指向它们)
修改关系:让n的头部指向的节点的出弧上的值为读到的字符,转换到的终点为尾指针指向状态的编号
n进栈 - –‘*’:
新建一个NFA,N2(新建两个节点即状态(状态总数+2),然后NFA的头尾分别指向它们)
出栈一个NFA称为N1,n1原有的结构保持不变
连接以下内容:
N2的头连接N1的头,N1的尾连接N2的尾
N2的头连接N2的尾,N1的尾连接N1的头
以上连接均是由空字符连接,(可以通过E_closure完成)
n2进栈 - –‘|’:
出栈两个元素a,b。
新建一个NFA,N(新建两个节点即状态(状态总数+2),然后NFA的头尾分别指向它们)
做以下连接:
N的头连接到a和b的头,a和b的尾连接到N的尾(a,b并联)
以上连接均是由空字符连接,(可以通过E_closure完成)
N进栈 - –‘&’:
出栈两个元素a,b。
a的尾通过空字符连接到b的头(a,b串联)
然后将a头b尾作为新NFA入栈即可
做完以上操作,栈大小就变为1,取栈顶的头尾赋给答案Ans再将其返回即可(不能直接返回栈顶因为其不含状态数等信息)
#pragma once
/*新建一个NFA(即从NFA状态数组中取出两个状态)*/
NFA creatNFA(int sum)
{
NFA New_N ;
New_N.head = &NFA_States[sum];
New_N.tail = &NFA_States[sum + 1];
return New_N;
}
/*在字符串s第n位后面插入字符ch*/
void insert_behind_n(string& s, int n, char ch)
{
s += '#';
for (int i = s.size() - 1; i > n; i--)
s[i] = s[i - 1];//n后面的都向后挪一位
s[n] = ch;
}
/*对字符串s进行预处理,在第一位是操作数、‘*’或‘)’且第二位是操作数或‘(’之间加入连接符‘&’*/
void pre_process(string& s)
{
int i = 0, length = s.size();
while (i < length)
{
int in_all_1 = 0, in_all_2 = 0;
set<char>::iterator it;
for (it = All_Char.begin(); it != All_Char.end(); it++) {
if (s[i] == *it)
in_all_1 = 1;
if (s[i + 1] == *it)
in_all_2 = 1;
}
//if ((s[i] >= 'a' && s[i] <= 'z') || (s[i] == '*') || (s[i] == ')'))
if (in_all_1 || (s[i] == '*') || (s[i] == ')'))
if (in_all_2 || s[i + 1] == '(')
{
insert_behind_n(s, i + 1, '&');
length++;
}
i++;
}
}
/*中缀转后缀时用到的优先级比较,即为每个操作符赋一个权重,通过权重大小比较优先级*/
int priority(char ch)
{
if (ch == '*')
{
return 3;
}
if (ch == '&')
{
return 2;
}
if (ch == '|')
{
return 1;
}
if (ch == '(')
{
return 0;
}
}
/*中缀表达式转后缀表达式*/
string infixToSuffix(string s)
{
pre_process(s); /*对字符串进行预处理*/
string str; /*要输出的后缀字符串*/
stack<char> oper; /*运算符栈*/
for (unsigned int i = 0; i < s.size(); i++)
{
int in_all = 0;
set<char>::iterator it;
for (it = All_Char.begin(); it != All_Char.end(); it++)
if (s[i] == *it)
in_all = 1;
if (in_all) /*如果是操作数直接输出*/
{
str += s[i];
}
else /*遇到运算符时*/
{
if (s[i] == '(') /*遇到左括号压入栈中*/
{
oper.push(s[i]);
}
else if (s[i] == ')') /*遇到右括号时*/
{
char ch = oper.top();
while (ch != '(') /*将栈中元素出栈,直到栈顶为左括号*/
{
str += ch;
oper.pop();
ch = oper.top();
}
oper.pop(); /*最后将左括号出栈*/
}
else /*遇到其他操作符时*/
{
if (!oper.empty()) /*如果栈不为空*/
{
char ch = oper.top();
while (priority(ch) >= priority(s[i])) /*弹出栈中优先级大于等于当前运算符的运算符*/
{
str += ch;
oper.pop();
if (oper.empty()) /*如果栈为空则结束循环*/
{
break;
}
else ch = oper.top();
}
oper.push(s[i]); /*再将当前运算符入栈*/
}
else /*如果栈为空,直接将运算符入栈*/
{
oper.push(s[i]);
}
}
}
}
/*最后如果栈不为空,则出栈并输出到字符串*/
while (!oper.empty())
{
char ch = oper.top();
oper.pop();
str += ch;
}
cout << "*******************************************" << endl << endl;
cout << "中缀表达式为:" << s << endl << endl;
cout << "后缀表达式为:" << str << endl << endl;
return str;
}
/*后缀表达式转nfa*/
NFA str_To_Nfa(string s)
{
s = infixToSuffix(s); /*将中缀表达式转换为后缀表达式*/
stack<NFA> NfaStack; /*定义一个NFA栈*/
NFA Ans;
for (unsigned int i = 0; i < s.size(); i++) /*读取后缀表达式,每次读一个字符*/
{
//if(i==83) cout << "测试信息" << i << endl;
int in_all = 0;
set<char>::iterator it;
for (it = All_Char.begin(); it != All_Char.end(); it++)
if (s[i] == *it)
in_all = 1;
if (in_all) /*遇到操作数*/
{
NFA n = creatNFA(Ans.N_StateNum); /*新建一个NFA*/
Ans.N_StateNum += 2; /*NFA状态总数加2*/
//add(n.head, n.tail, s[i]); /*NFA的头指向尾,弧上的值为s[i]*/
n.head->get_value = s[i];
n.head->Trans_to = n.tail->state_id;
/*
n.head->get_value = s[i];
n.head->Trans_to = n.tail->state_id;*/
NfaStack.push(n); /*将该NFA入栈*/
}
else if (s[i] == '*') /*遇到闭包运算符*/
{
NFA n2 = creatNFA(Ans.N_StateNum ); /*新建一个NFA*/
Ans.N_StateNum += 2; /*NFA状态总数加2*/
NFA n1 = NfaStack.top(); /*从栈中弹出一个NFA*/
NfaStack.pop();
//add(n2.tail, n1.head); /*n2的尾通过ε指向n1的头*/
//add(n2.tail, n1.tail); /*n2的尾通过ε指向n1的尾*/
//add(n1.head, n2.head); /*n1的头通过ε指向n2的头*/
//add(n1.head, n1.tail); /*n1的头通过ε指向n1的尾*/
n1.tail->E_closure_to.insert(n2.head->state_id); /*n2的尾通过ε指向n1的头*/
n1.tail->E_closure_to.insert(n2.tail->state_id); /*n2的尾通过ε指向n1的尾*/
n2.head->E_closure_to.insert(n1.head->state_id); /*n1的头通过ε指向n2的头*/
n2.head->E_closure_to.insert(n2.tail->state_id); /*n1的头通过ε指向n1的尾*/
NfaStack.push(n2); /*最后将新生成的NFA入栈*/
}
else if (s[i] == '|') /*遇到或运算符*/
{
NFA n1, n2; /*从栈中弹出两个NFA,栈顶为n2,次栈顶为n1*/
n2 = NfaStack.top();
NfaStack.pop();
n1 = NfaStack.top();
NfaStack.pop();
NFA n = creatNFA(Ans.N_StateNum ); /*新建一个NFA*/
Ans.N_StateNum += 2; /*NFA状态总数加2*/
n.head->E_closure_to.insert(n1.head->state_id); /*n的头通过ε指向n1的头*/
n.head->E_closure_to.insert(n2.head->state_id); /*n的头通过ε指向n2的头*/
n1.tail->E_closure_to.insert(n.tail->state_id); /*n1的尾通过ε指向n的尾*/
n2.tail->E_closure_to.insert(n.tail->state_id); /*n2的尾通过ε指向n的尾*/
NfaStack.push(n); /*最后将新生成的NFA入栈*/
}
else if (s[i] == '&') /*遇到连接运算符*/
{
NFA n1, n2, n; /*定义一个新的NFA n*/
n2 = NfaStack.top(); /*从栈中弹出两个NFA,栈顶为n2,次栈顶为n1*/
NfaStack.pop();
n1 = NfaStack.top();
NfaStack.pop();
//add(n1.tail, n2.head); /*n1的尾通过ε指向n2的尾*/
n1.tail->E_closure_to.insert(n2.head->state_id);
/*set<int> t= n1.tail->E_closure;
t.insert(n2.head->ID);
n1.tail.E_closure = t;*/
n.head = n1.head; /*n的头为n1的头*/
n.tail = n2.tail; /*n的尾为n2的尾*/
NfaStack.push(n); /*最后将新生成的NFA入栈*/
}
}
Ans.head = NfaStack.top().head;
Ans.tail = NfaStack.top().tail;
return Ans; /*最后的栈顶元素即为生成好的NFA*/
}
/*打印NFA函数*/
void printNFA(NFA &n)
{
cout << "*************** NFA ***************" << endl << endl;
cout << "NFA总共有" << n.N_StateNum << "个状态," << endl;
cout << "初态为" << n.head->state_id << ",终态为" << n.tail->state_id << "。" << endl << endl << "转移函数为:" << endl;
for (int i = 0; i < n.N_StateNum; i++) /*遍历NFA状态数组*/
{
if (NFA_States[i].get_value != '#') /*如果弧上的值不是初始时的‘#’则输出*/
{
cout << NFA_States[i].state_id << "-->'" << NFA_States[i].get_value << "'-->" << NFA_States[i].Trans_to << '\t';
}
set<int>::iterator it; /*输出该状态经过ε到达的状态*/
for (it = NFA_States[i].E_closure_to.begin(); it != NFA_States[i].E_closure_to.end(); it++)
{
cout << NFA_States[i].state_id << "-->'" << ' ' << "'-->" << *it << '\t';
}
cout << endl;
}
}
-
定义一个DFA Ans用于保存最后的答案,接受参数NFA n作为读入数据
Ans的初态为0
初态0的E_closure就等于n的E_closure
判断初态是否为终态
dfa数量加一 -
定义一个存DFA状态(int类型)的栈:把dfa的初态存入栈,只要栈不为空,就一直循环:
栈顶元素出栈
遍历有穷字母表计算每个字母的ε-cloure(move(ch))
如果求出来的状态集不为空且与之前求出来的状态集不同,则增加一个新DFA状态
将新求出来的状态集加入到状态集合中
该状态弧的输入即为当前终结符
弧转移到的状态为最后一个DFA状态
该状态弧的数目加一,更新转移矩阵
判断是否为终态
将新的状态号加入栈中
DFA状态总数加一
求出来的状态集在之前求出的某个状态集相同,不增加状态,只增加该状态的弧
遍历之前求出来的状态集合,找到与该集合相同的DFA状态
该状态弧的输入即为当前终结符
该弧转移到的状态即为i
该状态弧的数目加一,更新转移矩阵, -
遍历Ans的所有状态 ,如果该状态是NFA的终态,则将该状态号加入到Ans的终态集中
转换结束。 -
状态转移矩阵的含义:
状态1通过接收字母b到达状态二,表示为:
Ans.trans[1][(int)b-(int)*All_Char.begin()] == 2;
重点是trans的第二维的意义,由于其是int类型所以只能用ascii码来表示,
故用(int)将char类型强制类型转换成对应的ascii码,
但是由于有穷字母表一般不能包含所有ascii码表,所以会造成一定的空间的浪费(最小的ascii码前面的所有空间都被浪费)
所以我们实际上采用的是某个字符对应有穷字母表内ascii码最小字符的相对位置来判断的
所以字符b在转移矩阵中的位置应该是(int)b-(int)*All_Char.begin()
#pragma once
/*求一个状态集的ε-cloure*/
set<int> epcloure(set<int> s, NFA &n)
{
stack<int> epStack; /*(此处栈和队列均可)*/
set<int>::iterator it;
for (it = s.begin(); it != s.end(); it++)
epStack.push(*it); /*将该状态集中的每一个元素都压入栈中*/
while (!epStack.empty()) /*只要栈不为空*/
{
int temp = epStack.top(); /*从栈中弹出一个元素*/
epStack.pop();
set<int>::iterator iter;
for (iter = NFA_States[temp].E_closure_to.begin(); iter != NFA_States[temp].E_closure_to.end(); iter++)
{
if (!s.count(*iter)) /*遍历它通过ε能转换到的状态集*/
{ /*如果当前元素没有在集合中出现*/
s.insert(*iter); /*则把它加入集合中*/
epStack.push(*iter); /*同时压入栈中*/
}
}
}
return s; /*最后的s即为ε-cloure*/
}
/*求一个状态集s的ε-cloure(move(ch))*/
set<int> moveEpCloure(set<int> s, char ch, NFA &n)
{
set<int> temp;
set<int>::iterator it;
for (it = s.begin(); it != s.end(); it++) /*遍历当前集合s中的每个元素*/
{
if (NFA_States[*it].get_value == ch) /*如果对应转换弧上的值为ch*/
{
temp.insert(NFA_States[*it].Trans_to); /*则把该弧通过ch转换到的状态加入到集合temp中*/
}
}
temp = epcloure(temp ,n); /*最后求temp的ε闭包*/
return temp;
}
/*判断一个状态是否为终态*/
bool IsEnd(NFA &n, set<int> s)
{
set<int>::iterator it;
for (it = s.begin(); it != s.end(); it++) /*遍历该状态所包含的nfa状态集*/
if (*it == n.tail->state_id) /*如果包含nfa的终态,则该状态为终态,返回true*/
return true;
return false; /*如果不包含,则不是终态,返回false*/
}
/*nfa转dfa主函数*/
DFA Nfa_To_Dfa(NFA n) /*参数为nfa和后缀表达式*/
{
cout << "*************** DFA ***************" << endl << endl;
int i;
DFA Ans;//转化成的DFA(结果)
set<set<int>> states; /*定义一个存储整数集合的集合,用于判断求出一个状态集s的ε-cloure(move(ch))后是否出现新状态*/
set<int> tempSet;
Ans.Letter_List = All_Char;/*把操作数加入到dfa的有穷字母表中*/
Ans.Beg_State = 0; /*dfa的初态为0*/
tempSet.insert(n.head->state_id); /*将nfa的初态加入到集合中*/
Ans.DFA_States[0].E_closure_to = epcloure(tempSet,n); /*求dfa的初态*/
Ans.DFA_States[0].isEnd = IsEnd(n, Ans.DFA_States[0].E_closure_to); /*判断初态是否为终态*/
Ans.D_StateNum++; /*dfa数量加一*/
stack <int> q;
q.push(Ans.Beg_State); /*把dfa的初态存入栈中*/
while (!q.empty()) /*只要栈不为空,就一直循环*/
{
int num = q.top(); /*出去栈顶元素*/
q.pop();
set<char>::iterator it;
for (it = Ans.Letter_List.begin(); it != Ans.Letter_List.end(); it++) /*遍历有穷字母表*/
{
set<int> temp = moveEpCloure(Ans.DFA_States[num].E_closure_to, *it ,n); /*计算每个终结符的ε-cloure(move(ch))*/
if (!states.count(temp) && !temp.empty()) /*如果求出来的状态集不为空且与之前求出来的状态集不同,则新建一个DFA状态*/
{
states.insert(temp); /*将新求出来的状态集加入到状态集合中*/
Ans.DFA_States[Ans.D_StateNum].E_closure_to = temp;
Ans.DFA_States[num].Edges[Ans.DFA_States[num].Edge_Num].get_value = *it; /*该状态弧的输入即为当前终结符*/
Ans.DFA_States[num].Edges[Ans.DFA_States[num].Edge_Num].Trans_to = Ans.D_StateNum; /*弧转移到的状态为最后一个DFA状态*/
Ans.DFA_States[num].Edge_Num++; /*该状态弧的数目加一*/
//d.trans[num][*it - 'a'] = dfaStateNum; /*更新转移矩阵*/
Ans.trans[num][*it - (int)*All_Char.begin()] = Ans.D_StateNum; /*更新转移矩阵*/
Ans.DFA_States[Ans.D_StateNum].isEnd = IsEnd(n, Ans.DFA_States[Ans.D_StateNum].E_closure_to); /*判断是否为终态*/
q.push(Ans.D_StateNum); /*将新的状态号加入队列中*/
Ans.D_StateNum++; /*DFA状态总数加一*/
}
else /*求出来的状态集在之前求出的某个状态集相同*/
{
for (i = 0; i < Ans.D_StateNum; i++) /*遍历之前求出来的状态集合*/
{
if (temp == Ans.DFA_States[i].E_closure_to) /*找到与该集合相同的DFA状态*/
{
Ans.DFA_States[num].Edges[Ans.DFA_States[num].Edge_Num].get_value = *it; /*该状态弧的输入即为当前终结符*/
Ans.DFA_States[num].Edges[Ans.DFA_States[num].Edge_Num].Trans_to = i; /*该弧转移到的状态即为i*/
Ans.DFA_States[num].Edge_Num++; /*该状态弧的数目加一*/
//d.trans[num][*it - 'a'] = i; /*更新转移矩阵*/
Ans.trans[num][*it - (int)*All_Char.begin()] = i; /*更新转移矩阵*/
break;
}
}
}
}
}
/*计算dfa的终态集*/
for (i = 0; i < Ans.D_StateNum; i++) /*遍历dfa的所有状态*/
if (Ans.DFA_States[i].isEnd == true) /*如果该状态是终态*/
Ans.End_States.insert(i); /*则将该状态号加入到dfa的终态集中*/
return Ans;
}
/*打印dfa函数*/
void printDFA(DFA &d)
{
int i, j;
cout << "DFA总共有" << d.D_StateNum << "个状态," << "初态为" << d.Beg_State << endl << endl;
cout << "有穷字母表为{ ";
set<char>::iterator it;
for (it = d.Letter_List.begin(); it != d.Letter_List.end(); it++)
{
cout << *it << ' ';
}
cout << '}' << endl << endl;
cout << "终态集为{ ";
set<int>::iterator iter;
for (iter = d.End_States.begin(); iter != d.End_States.end(); iter++)
{
cout << *iter << ' ';
}
cout << '}' << endl << endl;
cout << "转移函数为:" << endl;
for (i = 0; i < d.D_StateNum; i++)
{
for (j = 0; j < d.DFA_States[i].Edge_Num; j++)
{
if (d.DFA_States[d.DFA_States[i].Edges[j].Trans_to].isEnd == true)
{
cout << d.DFA_States[i].state_id << "-->'" << d.DFA_States[i].Edges[j].get_value;
cout << "'--><" << d.DFA_States[i].Edges[j].Trans_to << ">\t";
}
else
{
cout << d.DFA_States[i].state_id << "-->'" << d.DFA_States[i].Edges[j].get_value;
cout << "'-->" << d.DFA_States[i].Edges[j].Trans_to << '\t';
}
}
cout << endl;
}
cout << endl << "转移矩阵为:" << endl << " ";
set<char>::iterator t;
for (t = d.Letter_List.begin(); t != d.Letter_List.end(); t++)
{
cout << *t << " ";
}
cout << endl;
for (i = 0; i < d.D_StateNum; i++)
{
if (d.End_States.count(i))
{
cout << '<' << i << "> ";
}
else
{
cout << ' ' << i << " ";
}
int n = (int)*All_Char.begin();
int m = (int)*(--All_Char.end());
for (j = 0; j < m + 2; j++)
//for (j = 0; j < 26; j++)
{
//if (d.terminator.count(j + 'a'))
if (d.Letter_List.count(j + n))
{
if (d.trans[i][j] != -1)
{
cout << d.trans[i][j] << " ";
}
else
{
cout << " ";
}
}
}
cout << endl;
}
}
DFA最小化:
#pragma once
set<int> s[MAX]; /*划分出来的集合数组*/
struct stateSet /*划分状态集*/
{
int index; /*该状态集所能转换到的状态集标号*/
set<int> s; /*该状态集中的dfa状态号*/
};
//***********************************************************************************************************
/*当前划分总数为count,返回状态n所属的状态集标号i*/
int findSetNum(int count, int n)
{
for (int i = 0; i < count; i++)
if (s[i].count(n))
return i;
}
/*最小化DFA*/
DFA min_DFA(DFA &d)
{
int i, j;
cout << endl << "************* minDFA **************" << endl << endl;
DFA minDfa;
minDfa.Letter_List = d.Letter_List; /*把dfa的终结符集赋给minDfa*/
memset(minDfa.trans, -1, sizeof(minDfa.trans)); /*初始化minDfa转移矩阵*/
/*做第一次划分,即将终态与非终态分开*/
bool endFlag = true; /*判断dfa的所有状态是否全为终态的标志*/
for (i = 0; i < d.D_StateNum; i++) /*遍历dfa状态数组*/
{
if (d.DFA_States[i].isEnd == false) /*如果该dfa状态不是终态*/
{
endFlag = false; /*标志应为false*/
minDfa.D_StateNum = 2; /*第一次划分应该有两个集合*/
s[1].insert(d.DFA_States[i].state_id); /*把该状态的状态号加入s[1]集合中*/
}
else /*如果该dfa状态是终态*/
{
s[0].insert(d.DFA_States[i].state_id); /*把该状态的状态号加入s[0]集合中*/
}
}
if (endFlag) /*如果标志为真,则所有dfa状态都是终态*/
minDfa.D_StateNum = 1; /*第一次划分结束应只有一个集合*/
bool cutFlag = true; /*上一次是否产生新的划分的标志*/
while (cutFlag) /*只要上一次产生新的划分就继续循环*/
{
int cutCount = 0; /*需要产生新的划分的数量*/
for (i = 0; i < minDfa.D_StateNum; i++) /*遍历每个划分集合*/
{
set<char>::iterator it;
for (it = d.Letter_List.begin(); it != d.Letter_List.end(); it++) /*遍历dfa的终结符集*/
{
int setNum = 0; /*当前缓冲区中的状态集个数*/
stateSet temp[20]; /*划分状态集“缓冲区”*/
set<int>::iterator iter;
for (iter = s[i].begin(); iter != s[i].end(); iter++) /*遍历集合中的每个状态号*/
{
bool epFlag = true; /*判断该集合中是否存在没有该终结符对应的转换弧的状态*/
for (j = 0; j < d.DFA_States[*iter].Edge_Num; j++) /*遍历该状态的所有边*/
{
if (d.DFA_States[*iter].Edges[j].get_value == *it) /*如果该边的输入为该终结符*/
{
epFlag = false; /*则标志为false*/
/*计算该状态转换到的状态集的标号*/
int transNum = findSetNum(minDfa.D_StateNum, d.DFA_States[*iter].Edges[j].Trans_to);
int curSetNum = 0; /*遍历缓冲区,寻找是否存在到达这个标号的状态集*/
while ((temp[curSetNum].index != transNum) && (curSetNum < setNum))
{
curSetNum++;
}
if (curSetNum == setNum) /*缓冲区中不存在到达这个标号的状态集*/
{
/*在缓冲区中新建一个状态集*/
temp[setNum].index = transNum; /*该状态集所能转换到的状态集标号为transNum*/
temp[setNum].s.insert(*iter); /*把当前状态添加到该状态集中*/
setNum++; /*缓冲区中的状态集个数加一*/
}
else /*缓冲区中存在到达这个标号的状态集*/
{
temp[curSetNum].s.insert(*iter); /*把当前状态加入到该状态集中*/
}
}
}
if (epFlag) /*如果该状态不存在与该终结符对应的转换弧*/
{
/*寻找缓冲区中是否存在转换到标号为-1的状态集
这里规定如果不存在转换弧,则它所到达的状态集标号为-1*/
int curSetNum = 0;
while ((temp[curSetNum].index != -1) && (curSetNum < setNum))
{
curSetNum++;
}
if (curSetNum == setNum) /*如果不存在这样的状态集*/
{
/*在缓冲区中新建一个状态集*/
temp[setNum].index = -1; /*该状态集转移到的状态集标号为-1*/
temp[setNum].s.insert(*iter); /*把当前状态加入到该状态集中*/
setNum++; /*缓冲区中的状态集个数加一*/
}
else /*缓冲区中存在到达这个标号的状态集*/
{
temp[curSetNum].s.insert(*iter); /*把当前状态加入到该状态集中*/
}
}
}
if (setNum > 1) /*如果缓冲区中的状态集个数大于1,表示同一个状态集中的元素能转换到不同的状态集,则需要划分*/
{
cutCount++; /*划分次数加一*/
/*为每组划分创建新的dfa状态*/
for (j = 1; j < setNum; j++) /*遍历缓冲区,这里从1开始是将第0组划分留在原集合中*/
{
set<int>::iterator t;
for (t = temp[j].s.begin(); t != temp[j].s.end(); t++)
{
s[i].erase(*t); /*在原来的状态集中删除该状态*/
s[minDfa.D_StateNum].insert(*t); /*在新的状态集中加入该状态*/
}
minDfa.D_StateNum++; /*最小化DFA状态总数加一*/
}
}
}
}
if (cutCount == 0) /*如果需要划分的次数为0,表示本次不需要进行划分*/
{
cutFlag = false;
}
}
/*遍历每个划分好的状态集*/
for (i = 0; i < minDfa.D_StateNum; i++)
{
set<int>::iterator y;
for (y = s[i].begin(); y != s[i].end(); y++) /*遍历集合中的每个元素*/
{
if (*y == d.Beg_State) /*如果当前状态为dfa的初态,则该最小化DFA状态也为初态*/
{
minDfa.Beg_State = i;
}
if (d.End_States.count(*y)) /*如果当前状态是终态,则该最小化DFA状态也为终态*/
{
minDfa.DFA_States[i].isEnd = true;
minDfa.End_States.insert(i); /*将该最小化DFA状态加入终态集中*/
}
for (j = 0; j < d.DFA_States[*y].Edge_Num; j++) /*遍历该DFA状态的每条弧,为最小化DFA创建弧*/
{
/*遍历划分好的状态集合,找出该弧转移到的状态现在属于哪个集合*/
for (int t = 0; t < minDfa.D_StateNum; t++)
{
if (s[t].count(d.DFA_States[*y].Edges[j].Trans_to))
{
bool haveEdge = false; /*判断该弧是否已经创建的标志*/
for (int l = 0; l < minDfa.DFA_States[i].Edge_Num; l++) /*遍历已创建的弧*/
{ /*如果该弧已经存在*/
if ((minDfa.DFA_States[i].Edges[l].get_value == d.DFA_States[*y].Edges[j].get_value) && (minDfa.DFA_States[i].Edges[l].Trans_to == t))
{
haveEdge = true; /*标志为真*/
}
}
if (!haveEdge) /*如果该弧不存在,则创建一条新的弧*/
{
minDfa.DFA_States[i].Edges[minDfa.DFA_States[i].Edge_Num].get_value = d.DFA_States[*y].Edges[j].get_value; /*弧的值与DFA的相同*/
minDfa.DFA_States[i].Edges[minDfa.DFA_States[i].Edge_Num].Trans_to = t; /*该弧转移到的状态为这个状态集的标号*/
//minDfa.trans[i][DfaStates[*y].Edges[j].input - 'a'] = t; /*更新转移矩阵*/
minDfa.trans[i][d.DFA_States[*y].Edges[j].get_value - (int)*All_Char.begin()] = t; /*更新转移矩阵*/
minDfa.DFA_States[i].Edge_Num++; /*该状态的弧的数目加一*/
}
break;
}
}
}
}
}
for (i = 0; i < minDfa.D_StateNum; i++)
for (j = 0; j < minDfa.DFA_States[i].Edge_Num; j++) {
if (minDfa.DFA_States[i].state_id == minDfa.Beg_State)
Beg.insert(minDfa.DFA_States[i].Edges[j].get_value);//构造首字母表
if (minDfa.End_States.find(minDfa.DFA_States[i].Edges[j].Trans_to) != minDfa.End_States.end())
End.insert(minDfa.DFA_States[i].Edges[j].get_value);//构造尾字母表
}
return minDfa;
}
void printMinDFA(DFA d)
{
int i, j;
cout << "minDFA总共有" << d.D_StateNum << "个状态," << "初态为" << d.Beg_State << endl << endl;
cout << "有穷字母表为{ ";
set<char>::iterator it;
for (it = d.Letter_List.begin(); it != d.Letter_List.end(); it++)
{
cout << *it << ' ';
}
cout << '}' << endl << endl;
cout << "终态集为{ ";
set<int>::iterator iter;
for (iter = d.End_States.begin(); iter != d.End_States.end(); iter++)
{
cout << *iter << ' ';
}
cout << '}' << endl << endl;
cout << "转移函数为:" << endl;
for (i = 0; i < d.D_StateNum; i++)
{
for (j = 0; j < d.DFA_States[i].Edge_Num; j++)
{
if (d.DFA_States[d.DFA_States[i].Edges[j].Trans_to].isEnd == true)
{
cout << d.DFA_States[i].state_id << "-->'" << d.DFA_States[i].Edges[j].get_value;
cout << "'--><" << d.DFA_States[i].Edges[j].Trans_to << ">\t";
}
else
{
cout << d.DFA_States[i].state_id << "-->'" << d.DFA_States[i].Edges[j].get_value;
cout << "'-->" << d.DFA_States[i].Edges[j].Trans_to << '\t';
}
//if (minDfaStates[i].index == d.startState)
// Beg.insert(minDfaStates[i].Edges[j].input);
}
cout << endl;
}
cout << endl << "转移矩阵为:" << endl << " ";
set<char>::iterator t;
for (t = d.Letter_List.begin(); t != d.Letter_List.end(); t++)
{
cout << *t << " ";
}
cout << endl;
for (i = 0; i < d.D_StateNum; i++)
{
if (d.End_States.count(i))
{
cout << '<' << i << "> ";
}
else
{
cout << ' ' << i << " ";
}
int n = (int)*All_Char.begin();
int m = (int)*(--All_Char.end());
for (j = 0; j < m + 2; j++)
//for (j = 0; j < 26; j++)
{
//if (d.terminator.count(j + 'a'))
if (d.Letter_List.count(j + n))
if (d.trans[i][j] != -1)
cout << d.trans[i][j] << " ";
else
cout << " ";
}
cout << endl;
}
cout << endl << "*******************************************";
}
得到由正则表达式转换而来的最小DFA之后,我们就可以利用这个DFA来识别我们的源程序,具体已经在前一篇文章中给出。
基于DFA的词法分析(一):程序框架及数据结构
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通