编译原理课程设计NFA转化为DFA的转换算法及实现.docx
《编译原理课程设计NFA转化为DFA的转换算法及实现.docx》由会员分享,可在线阅读,更多相关《编译原理课程设计NFA转化为DFA的转换算法及实现.docx(20页珍藏版)》请在冰豆网上搜索。
![编译原理课程设计NFA转化为DFA的转换算法及实现.docx](https://file1.bdocx.com/fileroot1/2022-12/12/0141ff2e-5e93-48cd-b0ae-c4f31c6fd6a9/0141ff2e-5e93-48cd-b0ae-c4f31c6fd6a91.gif)
编译原理课程设计NFA转化为DFA的转换算法及实现
编译原理课程实践报告
设计名称:
NFA转化为DFA的转换算法及实现
二级学院:
数学与计算机科学学院
专业:
计算机科学与技术
班级:
计科本091班
****************
学号:
**********
********************************
日期:
2012年6月
摘要
确定有限自动机确定的含义是在某种状态,面临一个特定的符号只有一个转换,进入唯一的一个状态。
不确定的有限自动机则相反,在某种状态下,面临一个特定的符号是存在不止一个转换,即是可以允许进入一个状态集合。
在非确定的有限自动机NFA中,由于某些状态的转移需从若干个可能的后续状态中进行选择,故一个NFA对符号串的识别就必然是一个试探的过程。
这种不确定性给识别过程带来的反复,无疑会影响到FA的工作效率。
而DFA则是确定的,将NFA转化为DFA将大大提高工作效率,因此将NFA转化为DFA是有其一定必要的。
对于任意的一个不确定有限自动机(NFA)都会存在一个等价的确定的有限自动机(DFA),即L(N)=L(M)。
本文主要是介绍如何将NFA转换为与之等价的简化的DFA,通过具体实例,结合图形,详细说明转换的算法原理。
关键词:
有限自动机;确定有限自动机(DFA),不确定有限自动机(NFA)
Abstract
Finiteautomataisdeterminateandindeterminatetwoclass.Determinethemeaningisinacertainstate,facesaparticularsymbolonlyoneconversion,enteronlyonestate.Notdeterministicfiniteautomataistheopposite,inacertainstate,facesaparticularsymbolisthepresenceofmorethanoneconversion,thatistobeallowedtoenterastateset.
NondeterministicfinitestateautomataNFA,becauseofsomestatearetransferredfromanumberofpossiblefollow-upstatearechosen,soaNFAsymbolstringrecognitionmustbeatrialprocess.Thisuncertaintytotherecognitionprocessbroughtaboutbyrepeated,willundoubtedlyaffecttheefficiencyoftheFA.WhiletheDFAisdetermined,convertingNFAtoDFAwillgreatlyimprovetheworkingefficiency,thusconvertingNFAtoDFAisitsnecessary.
Foranyanondeterministicfiniteautomaton(NFA)canbeanequivalentdeterministicfiniteautomaton(DFA),L(N)=L(M).ThispapermainlyintroduceshowtoconvertNFAtoequivalentsimplifiedDFA,throughconcreteexamples,combinedwithgraphics,adetaileddescriptionofthealgorithmprincipleofconversion.
Keywords:
:
finiteautomata;deterministicfiniteautomaton(DFA),nondeterministicfiniteautomaton(NFA
1.前言:
1.1背景
有限自动机作为一种识别装置,它能准确地识别正规集,即识别正规文法所定义的语言和正规式所表示的集合,引入有穷自动机这个理论,正是为词法分析程序的自动构造寻找特殊的方法和工具。
有限自动机(FiniteAutomate)是用来模拟实物系统的数学模型,它包括如下五个部分:
∙有穷状态集States
∙输入字符集Inputsymbols
∙转移函数Transitions
∙起始状态Startstate
∙接受状态Acceptingstate(s)
1.2实践目的
(1)设计、编制、调式一个有穷自动机程序,加深对NFA转换为DFA的原理的理解。
(2)掌握NFA确定化的过程。
1.2课程实践的意义
通过本课程设计教学所可以使我们充分理解和掌握NFA,DFA以及NFA确定化过程的相关概念和知识,理解和掌握子集法的相关知识和应用,编程实现对输入NFA转换成DFA输出的功能。
2.NFA和DFA的概念
2.1不确定有限自动机NFA
NFA(nondeterministicfinite-stateautomata)即非确定有限自动机,一个非确定的有限自动机NFAM’是一个五元式:
NFAM’=(S,Σ∪{ε},δ,S0,F)
其中S—有限状态集,Σ∪{ε}—输入符号加上ε,即自动机的每个结点所射出的弧可以是Σ中一个字符或是ε.
S0—初态集F—终态集
δ—转换函数S×Σ∪{ε}→2S
(2S--S的幂集—S的子集构成的集合)
例1:
NFAM=({S,P,Z},{0,1},f,{s,p},{z})
其中
f(s,0)={p}f(z,0)={p}f(p,1)={z}
f(z,1)={p}f(s,1)={s,z}
①NFA的状态图表示如下:
②NFA矩阵表示:
状态字符
0
1
S
P
S,Z
0
P
{}
Z
0
Z
P
P
1
2.2确定有限自动机DFA
DFA(deterministicfinite-stateautomata)即确定有限自动机,一个确定的有限自动机DFAM是一个五元式:
M=(S,Σ,δ,S0,Z)
其中:
S—有限状态集
Σ—输入字母表
δ—映射函数(也称状态转换函数)
S×Σ→S
δ(s,a)=S’,S,S’∈S,a∈Σ
S0—初始状态S0∈S
Z—终止状态集ZS
例2:
DFAM=({S,U,V,Q},{a,b},f,s,{Q})其中f的定义为:
f(S,a)=Uf(S,b)=Vf(U,a)=Qf(U,b)=V
f(V,a)=Uf(V,b)=Qf(Q,a)=Qf(Q,b)=Q
1DFA的状态图表示:
假如DFAM含有m个状态,n个输入符,那么这个状态含有m个节点,每个节点最多有n个弧射出,整个图整个图含有唯一一个初态结点和若干个终态结点,初态结点冠以双箭头“=>”或标以“-”,终态结点用双圈表示或标以“+”,若f(ki,a)=kj,则从状态结点ki到状结点kj画标记为a的弧:
2DFA矩阵表示:
一个DFA还可以用一个矩阵表示,该矩阵的行表示状态,列表示输入字符,矩阵元素表示相应状态行和输入字符列下的新状态,即k行a列为f(k,a)的值。
用双箭头=>标明初态;否则第一行即是初态,相应终态行在表的右端标以1,非终态标以0.
状态字符
a
b
S
U
V
0
U
Q
V
0
V
U
Q
0
Q
Q
Q
1
3.从NDF到DFA的等价变化步骤
事实已经证明了不管是非确定的有限自动机M还是具有ε-转移的非确定的有限自动机,都可以找到一个与之等价的确定有限自动机,使得L(M)=L(M’)。
3.1转换思路
由非确定的有限自动机出发构造与之等价的确定的有限自动机的办法是确定的有限自动机的状态对应于非确定的有限自动机的状态集合,即要使转换后的DFA的每一个状态对应NFA的一组状态。
该DFA使用它的状态去记录在NFA读入一个输入符号后可能到达的所有状态,也就是说,在读入符号串a1a2a3…an之后,该DFA处在这样一个状态,该状态表示这个NFA的状态的一个子集T,而T是从NFA的开始状态沿着某个标记为a1a2a3…an的路径可以到达的那些状态。
3.2.消除空转移
.消除N
形式的产生式,即消除空转移。
状态集合I的a弧转换Ia:
定义为一状态集,是指从状态集I出发先经过a弧后再经过若干条ε弧而能到达的状态的集合。
可以写作:
Ia=ε-closure(J),J=move(I,a),其中,J是从I中任一状态出发经过一条a弧到达的状态集合,记为move(I,a)。
s表示NFA的状态,T表示NFA的状态集合,a表示一个inputsymbol
ε-transition(ε转换)就是说inputsymbol为ε时的transition(转换)
操作(operation)
描述(description)
ε-closure(s)
从NFA的状态s出发,只通过ε-transition到达的NFA的状态集合
ε-closure(T)
NFA的集合T中的状态p,只通过ε-transition到达的NFA的状态集合,再求这些集合的交集。
用数学表达就是{p|p属于ε-closure(t),t属于T}
move(T,a)
NFA的集合,这个集合在inputsymbol为a,状态为T中任意状态情况下,通过一个转换得到的集合
例如:
对于以下状态图中:
ε-closure({0})={0,1,2,4,7}
在这里设I={0,1,2,4,7},则因为有move(I,a)={3,8}=J,所以
Ia=ε-closure(J)=ε-closure({3,8})={1,2,3,4,6,7,8}
3.3子集构造法
确定化每个多重转移,即拆分多值函数为单位函数,具体转换,采用子集构造法。
以下面的基于字母表Σ={a,b}上的具有ε-转移的非确定有限自动机M为例。
步骤1:
以I,Ia、Ib等为列做表,其中I列第一行的内容是初态的ε-闭包所得到的状态集合。
并以此为I计算Ia、Ib等,而且在所计算出的Ia、Ib等中若有新的状态集产生,就重复以此新的集合为I再此计算Ia、Ib等,直到在所得的Ia、Ib等中不再产生新的状态集为止。
I
Ia
Ib
{x,5,1}
{5,1,3}
{5,1,4}
{5,1,3}
{5,1,3,2,6,y}
{5,1,4}
{5,1,4}
{5,1,3}
{5,1,4,2,6,y}
{5,1,3,2,6,y}
{5,1,3,2,6,y}
{5,1,4,6,y}
{5,1,4,2,6,y}
{5,1,3,6,y}
{5,1,4,2,6,y}
{5,1,4,6,y}
{5,1,3,6,y}
{5,1,4,2,6,y}
{5,1,3,6,y}
{5,1,3,2,6,y}
{5,1,4,6,y}
步骤2:
在上表中将原NFA初态的ε-闭包作为转换后的DFA的初态,包含原NFA终态的状态作为转换后的DFA的终态,并进行重新编号得到转换后的DFA的状态转移矩阵如下:
a
b
{x,5,1}1
{5,1,3}2
{5,1,4}3
{5,1,3}2
{5,1,3,2,6,y}4
{5,1,4}3
{5,1,4}3
{5,1,3}2
{5,1,4,2,6,y}5
{5,1,3,2,6,y}4
{5,1,3,2,6,y}4
{5,1,4,6,y}6
{5,1,4,2,6,y}5
{5,1,3,6,y}7
{5,1,4,2,6,y}5
{5,1,4,6,y}6
{5,1,3,6,y}7
{5,1,4,2,6,y}5
{5,1,3,6,y}7
{5,1,3,2,6,y}4
{5,1,4,6,y}6
步骤3:
画出转换后的DFA的状态图:
4程序实现
4.1程序框架图
4.2数据流程图
4.3实现代码
(见附录)
4.4运行环境
(1)开发平台:
MicrosoftvisualC++6.0
(2)运行平台:
Windowsxp/Windows2000
4.5程序实现结果
实现NFA例题为:
NFAM=({S,P,Z},{0,1},f,{s,p},{z})
其中
f(s,0)={p}f(z,0)={p}f(p,1)={z}
f(z,1)={p}f(s,1)={s,z}
根据例题输入NFA各边的信息得出结果如下图:
5.用户手册
本程序应在MicrosoftVisualC++6.0下运行。
NFA的确定化是编译过程中一个重要的部分,由于本程序的输入很多,而且有多种格式的输入,所以输入时必须非常小心细致。
对于状态转换矩阵的表示,冒号前的是新状态名,冒号后的是旧状态名。
对于转化后的DFA表示,3个数据分别表示为起始状态、接受字符和到达状态,例如(0,1,1)表示为新状态0接受字符1到达新字符状态1。
运行结果因为转换字符输入顺序的不同,得出的结果有可能与笔算得出的顺序有所不同,但是结果依然是正确。
6.课程总结:
通过这次课程实践设计,让我对课堂上老师所讲到的不确定和确定有限自动机有了更深的理解,理解了它们的构造和怎样相互转化。
很好的理解了子集法的演算过程。
经过多次试验,在正确输入相关数据的情况下,程序能正常运行,当错误操作或输入错误数据时,程序将应错误自动关闭。
经过这次课程设计,也让我深刻的认识到实践才是最重要的。
书本只能教给我们基础知识,要怎样运用,将那些知识真正吸收,转化为自己的智慧,只有通过实践才能达到。
编译原理是一门实用性很强,对我们的专业很有帮助的科目,我将会继续努力,不断增加自己的知识面,把编译原理学习的更好。
同时我也发现自己对于有限自动机的知识掌握得还不是很多,在这次课程实践中,我懂得了怎样去和别人交流,更好地掌握和熟练了所学的知识。
7.参考文献
(1)杨路明、郭浩志.C语言程序设计教程.2003年12月第1版.北京:
北京邮电大学出版社.2005
(2)陈火旺.程序设计语言编译原理.2000年1月第3版.北京:
国防工业出版社.2006.46-51
(3)严蔚敏、吴伟民.数据结构(C语言版).1997年4月第1版.北京:
清华大学出版社.2005
(4)王晓东编著.计算机算法设计与分析.电子工业出版社.2004
8.附录
NFA转换为DFA采用C++编程实现代码如下
#include
#include
#defineMAXS100
usingnamespacestd;
stringNODE;//结点集合
stringCHANGE;//终结符集合
intN;//NFA边数
structedge{
stringfirst;
stringchange;
stringlast;
};
structchan{
stringltab;
stringjihe[MAXS];
};
voidkong(inta)
{
inti;
for(i=0;icout<<'';
}
//排序
voidpaixu(string&a)
{
inti,j;
charb;
for(j=0;jfor(i=0;iif(NODE.find(a[i])>NODE.find(a[i+1]))
{
b=a[i];
a[i]=a[i+1];
a[i+1]=b;
}
}
voideclouse(charc,string&he,edgeb[])
{
intk;
for(k=0;k{
if(c==b[k].first[0])
if(b[k].change=="*")
{
if(he.find(b[k].last)>he.length())
he+=b[k].last;
eclouse(b[k].last[0],he,b);
}
}
}
voidmove(chan&he,intm,edgeb[])
{
inti,j,k,l;
k=he.ltab.length();
l=he.jihe[m].length();
for(i=0;ifor(j=0;jif((CHANGE[m]==b[j].change[0])&&(he.ltab[i]==b[j].first[0]))
if(he.jihe[m].find(b[j].last[0])>he.jihe[m].length())
he.jihe[m]+=b[j].last[0];
for(i=0;ifor(j=0;jif((CHANGE[m]==b[j].change[0])&&(he.jihe[m][i]==b[j].first[0]))
if(he.jihe[m].find(b[j].last[0])>he.jihe[m].length())
he.jihe[m]+=b[j].last[0];
}
//输出
voidoutputfa(intlen,inth,chan*t)
{
inti,j,m;
cout<<"I";
for(i=0;icout<<'I'<cout<for(i=0;i{
cout<<''<m=t[i].ltab.length();
for(j=0;j{
kong(8-m);
m=t[i].jihe[j].length();
cout<}
cout<}
}
voidmain()
{
edge*b=newedge[MAXS];
inti,j,k,m,n,h,x,y,len;
boolflag;
stringjh[MAXS],endnode,ednode,sta;
cout<<"请输入NFA各边信息,分别为:
起点条件[空为*]终点,最后以#结束:
"<for(i=0;i{
cin>>b[i].first;
if(b[i].first=="#")break;
cin>>b[i].change>>b[i].last;
}
N=i;
/*for(j=0;jcout<
for(i=0;i{
if(NODE.find(b[i].first)>NODE.length())
NODE+=b[i].first;
if(NODE.find(b[i].last)>NODE.length())
NODE+=b[i].last;
if((CHANGE.find(b[i].change)>CHANGE.length())&&(b[i].change!
="*"))
CHANGE+=b[i].change;
}
len=CHANGE.length();
cout<<"结点中属于终态的是:
"<cin>>endnode;
for(i=0;iif(NODE.find(endnode[i])>NODE.length())
{
cout<<"所输终态不在集合中,错误!
"<return;
}
//cout<<"endnode="<chan*t=newchan[MAXS];
t[0].ltab=b[0].first;
h=1;
eclouse(b[0].first[0],t[0].ltab,b);//求e-clouse
//cout<for(i=0;i{
for(j=0;jfor(m=0;meclouse(t[i].ltab[j],t[i].jihe[m],b);//求e-clouse
for(k=0;k{
//cout<";
move(t[i],k,b);//求move(I,a)
//cout<for(j=0;jeclouse(t[i].jihe[k][j],t[i].jihe[k],b);//求e-clouse
}
for(j=0;j{
paixu(t[i].jihe[j]);//对集合排序以便比较
for(k=0;k{
flag=operator==(t[k].ltab,t[i].jihe[j]);
if(flag)
break;
}
if(!
flag&&t[i].jihe[j].length())
t[h++].ltab=t[i].jihe[j];
}
}
cout<"<outputfa(len,h,t);//输出状态转换矩阵
//状态重新命名
string*d=newstring[h];
NODE.erase();
cout<"<for(i=0;i{
sta=t[i].ltab;
t[i].ltab.erase();
t[i].ltab='A'+i;
NODE+=t[i].ltab;
cout<<'{'<for(j=0;jif(sta.find(endnode[j])d[1]=ednode+=t[i].ltab;
for(k=0;kfor(m=0;m