资源描述
正规文法与有限自动机的相互转换
二零一五年十二月二十七日
目 录
摘要 1
关键词 1
1课题综述 1
1.1目的 1
1.2设计内容 1
1.3设计原则 1
2系统分析 2
2.1正规式 2
2.2有限自动机(有穷自动机) 2
2.3NFA向DFA的转换 3
2.4正规式与有限自动机之间的转换 3
3系统设计 4
3.1从正规文法到有限自动机 4
3.11正规文法到有限自动机的等价性证明 4
3.12 正规文法到有限自动机的构造方法 5
3.2从有限自动机到正规文法 6
3.21 有限自动机到正规文法的等价性证明 6
3.22 有限自动机到正规文法的构造方法 7
4 运行与测试 7
总结 9
参考文献 9
附录 10
摘要:正规文法包括左线性文法和右线性文法。由于正规文法和正规表达式在描述语言的能力上是等价的,而正规表达式和有限自动机在描述语言的能力上也是等价的,因此,正规文法和有限自动机之间也存在着等价性。通常,对于正规文法G和有限自动机M,G所定义的语言记作L(G),M所能识别的语言记作L(M),如果有L(G)=L(M),则称G和M是等价的。
关键词:正规文法;有限自动机;等价性;构造方法
1课题综述
1.1目的
1.理解正规文法与有限自动机(FA)的本质联系;
2.掌握正规文法与有限自动机之间相互转化的算法原理;
3.学会使用Visual C++等编程工具实现正规文法与有限自动机之间的相互转化;
1.2设计内容
使用Visual C++/Visual C#等工具,设计软件MySoft_3,可以实现以下功能:
1.根据用户输入的文本文件(*.txt)的名称,打开文件,并从文件中获取文法的产生式、非终结符、终结符、开始符等基本信息;
2.判断该文法是否为正规文法,若是,则将其转化为有限自动机;
3.根据用户输入的文本文件(*.txt)的名称,打开文件,并从文件中获取有限自动机的状态集、字母表、初态、终态集、转移函数等基本信息;
4.判断该自动机是否合法,若合法,则将其转化为正规文法;
1.3设计原则
正规文法与有穷自动机有着特殊的关系,采用下面的规则可从正规文法G直接构造一个有穷自动机NFA M;使得L(M)=L(G):
(1)M的字母表与G的终结符相同;
(2)为G中的每一个非终结符生成M的一个状态,G的开始符S是开始状态;
(3)增加一个新状态Z,作为NFA的终态;
(4)对G中的形如A->tB的规则(其中T为终结符或,A为非终结符的产生式),构造M的一个转换函数f(A,t)=B;
(5)对G中形如A->t的产生式,构造M的一个转换函数f(A,t)=Z。
2系统分析
2.1正规式
正规式:正则表达式,表示正规集的工具。
一个正规式对应一个正规文法(3型文法)之间能够进行准换三个基本规则:
A->xB,B->y 则 A=xy。
A->xA|y 则A=x*y (x*代表x从1到无穷多个)
A->x,A->y 则A=x|y
正规式主要用到了递归的思想,无论遇到多复杂的正规式都可以拆分成上面这三种形式,然后进行解题。
2.2有限自动机(有穷自动机)
DFA(Deterministic Finite Automation ):确定的有限自动机表达式:M=(S,∑,f,So,Z)
1.S为一个有限状态集合
2.∑是一个字母表,它所包含的的每个元素称为一个输入字符;
3.f是一个从SX∑(笛卡尔乘积)至S的单值部分映射。f(S,a)=s'意味着当现在的状态为s,输入字符a时,将转换到下一状态s'.s'为s的一个后继状态。
4.So∈S,是唯一的初态;
5.Z⊆S,是一个终态集。
NFA(Nondeterministic Finite Automata):不确定的有限自动机如果理解了有限自动机,则无限自动机和它的区别就是上面的第四项。So⊆S,它的初态不是唯一的,而是一个集合。
2.3NFA向DFA的转换
这个转换是一个比较简单的过程。
1.如果有一个不确定的有限自动机,则可以转化为图的方式。此处不详述怎样转图的方式。
2.先将初态确定,然后根据输入的每个元素可以得到哪些状态,依次列表。
3.这些状态集合可以称为这个有限状态集合n个子集。按0,1,2……的顺序编号。
4.因为这些子集之间的关系是输入一个确定值确定的,所以这些子集之间存在一些关系,即把这些子集的关系写出来完成NFA向DFA的转换。
如果不懂可以从网上找一个例子进行理解。
2.4正规式与有限自动机之间的转换
若
a
b
若
任意的正规式都可以转换为上述三种的表现形式。
在一个有限自动机转换为正规式时,就是考虑从初态到终态可以输入哪些数据到达。而这些数据可以用哪种正规式概括进来。
3系统设计
3.1从正规文法到有限自动机
3.11正规文法到有限自动机的等价性证明
定理1:对于每一个右线性正规文法GR和左线性正规文法GL,都存在一个有限自动机M与之等价。
证明:
1.设右线性文法GR=(VT,VN,S,P),将VN中每个非终结符视为状态符号,并增加一个新的终止符号f,(f VN)。令M=(VN {f},VT,d,S,{f}),其中状态转换函数d由以下规则定义:①若对某个A VN及a VT {ε},P中有产生式A→a,则令d(A,a)=f;
②对任意的A VN及a VT {ε},设P中左端为A右端第一个符号为a的所有产生式为A→aA1∣aA2∣…∣aAk(不包括A→a),则令d(A,a)={ A1,A2,…,Ak}。
显然上述得到的M为一个NFA。到此,已说明存在一个FAM与该右线性文法对应,下面说明它们的等价性(L(GR)=L(M) )。
对右线性正规文法GR,在S W的最左推导过程中,利用A→aB一次就相当于在M中从状态A出发经标记为a的箭弧到达状态B(包括a=ε的情形)。在推导过程的最后,利用A→a一次则相当于在M中从状态A出发经标记为a的箭弧到达终态f(包括a=ε的情形)。
综上所述,在正规文法GR中,S W的充要条件是:在M中,从状态S到状态f有一条通路,其上所有箭弧的标记符号依次连接起来恰好等于W,这就是说,W L(GR)当且仅当W L(M),故L(GR)=L(M)。
2. 设左线性文法GL=(VT,VN,S,P),将VN中每个非终结符视为状态符号,并增加一个新的初始状态符号q,(q VN)。令M=(VN {q},VT,d,q,{S}),其中状态转换函数d由以下规则定义:
①若对某个A VN及a VT {ε},P中有产生式A→a,则令d(q,a)=A;
②对任意的A VN及a VT {ε},设P中所有右端第一个符号为A,第二个符号为a的所有产生式为A1→Aa,A2→Aa,…,AK→Aa,则令d(A,a)={ A1,A2,…,Ak}。
显然上述得到的M为一个NFA。到此,已说明存在一个FAM与该左线性文法对应,下面说明它们的等价性(L(GL)=L(M) )。
对左线性正规文法GL,在S W的最左推导过程中,利用B→Aa一次就相当于从状态A出发经标记为a的箭弧到达状态B(包括a=ε的情形)。在推导的最后,利用A→a一次则相当于在M中从状态q出发经标记为a的箭弧到达状态A(包括a=ε的情形)。综上所述,在正规文法GL中,S W的充要条件是:在M中,从状态q到状态S有一条通路,其上所有箭弧的标记符号依次连接起来恰好等于W,这就是说,W L(GL)当且仅当W L(M),故L(GL)=L(M)。
3.12 正规文法到有限自动机的构造方法
上述定理的证明采用了构造性的证明方法,由此可以得出由正规文法到有限自动机的构造方法。
从右线性正规文法GR=(VT,VN,S,P)构造有限自动机M=( VN {f},VT,d,S,{f})的方法如下:
①将VN中每个符号视为一个状态符号,增加一个新的终态符号f,f VN;
②对于产生式A→a(a VT {ε}),则构造d(A,a)=f;
③对于产生式A→aA1(a VT {ε}),则构造d(A,a)= A1。
从左线性正规文法GL=(VT,VN,S,P)构造有限自动机M=( VN {q},VT,d,q,{S})的方法如下:
①将VN中每个符号视为一个状态符号,增加一个新的初态符号q,q VN;
②对于产生式A→a(a VT {ε}),则构造d(q,a)=A;
③对于产生式A1→Aa(a VT {ε}),则构造d(A,a)= A1。
3.2从有限自动机到正规文法
3.21 有限自动机到正规文法的等价性证明
定理2:对于每一个有限自动机M,都存在一个右线性正规文法GR和左线性正规文法GL与之等价。
证明:
1.设DFAM=(S,∑,d,S0,F),分以下两种情况进行证明:
(1)若S0 F,则令GR=(∑,S, S0, P),其中P是由以下规则定义的产生式集合,对任何a ∑及A,B S,若d(A,a)=B,则:
①当B F时,令A→aB;
②当B F时,令A→aB∣a;
显然,上述得到的文法为一个右线性正规文法,下面说明它们的等价性(L(M)=L(GR) )。
在DFAM中,对任何w ∑*,不妨设w=a1a2…ak,其中ai ∑(i=1,2,…,k),若S W,则存在一个最左推导:S0 a1A1 a1a2A2 … a1…aiAi a1…aiai+1Ai+1 … a1…ak,因而,在M中存在一条从S0出发一次经过A1,…,Ak-1到达终态的通路,该通路上所有箭弧的标记依次为a1,…,ak。反之亦然。所以,w L(GR)当且仅当w L(M),故L(M)=L(GR)。
(2)若S0 F,因为d(S0,ε)= S0,所以ε L(M),但上面构造的L(GR)中不含ε。因此,需在文法中添加产生式S0→ε,这样,就有L(M)=L(GR)。
2. 设DFAM=(S,∑,d,S0,F),分以下两种情况进行证明:
(1)若S0 F,则令GL=(∑,S, X, P),其中X F,P是由以下规则定义的产生式集合,对任何a ∑及A,B S,若d(A,a)=B,则:
①当A≠S0时,令B→Aa;
②当A=S0时,令B→a∣Aa;
显然,上述得到的文法为一个左线性正规文法,下面说明它们的等价性(L(M)=L(GL) )。
在DFAM中,对任何w ∑*,不妨设w=a1a2…ak,其中ai ∑(i=1,2,…,k),若存在一条从S0到X的通路,通路上所有箭弧的标记依次为a1,…,ak,则在GL中一定存在一个最左推导:X Akak Ak-1ak-1ak … A2a2…ak … a1…ak,即w L(GL)。反之亦然。所以,w L(GL)当且仅当w L(M),故L(M)=L(GL)。
(2)若S0 F,则ε L(M),但上面构造的L(GL)中不含ε。因此,需在文法中添加产生式X→ε,这样,就有L(M)=L(GL)。
3.22 有限自动机到正规文法的构造方法
上述定理的证明采用了构造性的证明方法,由此可以得出由有限自动机到正规文法的构造方法。
从有限自动机M=( S,∑,d,S0,F)构造右线性正规文法GR的方法如下:
令GR=(∑,S, S0,P),其中P是由以下规则定义的产生式集合:
对任何d(A,a)=B,
①若B F,则令A→aB;
②若B F,并且B状态有箭弧射出,则令A→aB∣a;若B F,并且B状态没有箭弧射出,则令A→a;
③若S0 F,则令S0→ε。
从有限自动机M=( S,∑,d,S0,F)构造左线性正规文法GL的方法如下:
令GL=(∑,S, X,P),其中P是由以下规则定义的产生式集合:
对任何d(A,a)=B,
①若A不是初始状态,则令B→Aa;
②若A是初始状态,并且A状态有箭弧射入,则令B→Aa∣a;若A是初始状态,并且A状态没有箭弧射入,则令B→a;
③若S0 F,则令X→ε。
4 运行与测试
测试程序使用的自动机用例:
开始状态:A;
中间状态:1个,为B;
终态:2个,分别为C、D;
终结符:2个,分别为a、b;
装换关系为:
Stat
A
B
C
D
A
0
a
0
b
B
0
0
b
0
C
a
0
0
b
D
0
b
0
b
(6)得到的结果如图:
总结
经过一周的努力,终于把《编译原理》这门课的大作业做完了,由于学习理论的时候总是感觉这门课程特别的复杂,有许多繁琐的东西,起初以为课程设计的内容会更加的复杂,后来认真看了题目,和相对应于课本上的内容,我的这个题目还真的很简单,只是用到了“数组”、“图”这两个数据结构,再就是有两个二层嵌套的循环就能够应对这个题目了。
有限自动机用于构造词法分析程序,正规文法用于构造语法分析程序,它们分别是语言的识别工具和定义工具,在构造高级程序设计语言的编译程序时占有举足轻重的地位。有限自动机作为语言词法的识别工具,必须能够识别由文法定义的所有词法范畴;而文法作为语言语法的定义工具,也必须有能力定义有限自动机能识别的所有词法范畴的规则。从这一意义上讲,有限自动机和正规文法在描述语言的能力上就存在着等价性,而由这些等价性推导出来的相互转换方法,在构造编译程序时具有一定的检测和指导作用。
由于时间有限,这次的课程设计中我没有考虑到不确定的自动机转换成正规文法的情况,在以后的学习中一定将这种更加复杂的情况考虑进去,让自己的程序更加的完整。
经过一学期的编译原理这门课程的学习,我们深深的了解到了编译器结构的复杂程度,更了解了我们学习的高级语言的强大功能,我们做的课程设计只是一个完整编译器的冰山一角。后面还有更多需要我们更加需要懂得的东西。
参考文献
[1]陈火旺等.程序设计语言编译原理(第3版)[M].北京:国防工业出版社,2000. 7
[2]胡元义.编译原理教程(第二版)[M].西安:西安电子科技大学出版社,2006.8
[3]刘坚.编译原理基础[M].西安:西安电子科技大学出版社,2002. 4
[4]吕映芝.编译原理[M].北京:清华大学出版社,1998 .5
附录
#include<iostream>
using namespace std;
int main()
{
int n, m;
//n为自动机状态的总数目
//m为自动机终结符的数目
int n_midd_stat, n_final_stat;
//n_midd_stat为中间状态的数目
//n_final_stat为终态的数目
cout << "请输入自动机共有的状态数目:";
cin >> n;
char* stat = new char[n];
cout << "请输入开始状态:";
cin >> stat[0];
cout << "请输入中间状态的个数:";
cin >> n_midd_stat;
cout << "请输入分别中间状态:" << endl;
for(int i1 = 0; i1 < n_midd_stat; i1++)
{
cin >> stat[i1 + 1];
}
n_final_stat = n - n_midd_stat - 1;
cout << "最后分别输入终态:" << endl;
for(int i2 = 0; i2 < n_final_stat; i2++)
{
cin >> stat[n_midd_stat + 1 + i2];
}
cout << "请输入终结符的数目:";
cin >> m;
char* terminal = new char[m];
cout << "请分别输入终结符:" << endl;
for(int i3 = 0; i3 < m; i3++)
{
cin >> terminal[i3];
}
cout << endl;
//构造自动机
int i, j,k;
char** f = new char*[n];
for(k=0;k<n;k++)
{
f[k]=new char[n];
}
cout << "构造自动机:" << endl;
for(i = 0; i < n; i++)
{
for(j = 0; j < n; j++)
{
cout << "状态" << stat[i] << "能否直接推出状态"
<< stat[j];
if((i == 0) && (j == 0))
{
cout << "? (若能则输入相应的终结符,否则输入\"0\")";
}
else
{
cout << "?";
}
cin >> f[i][j];
}
}
cout << endl;
//转换成对应的文法
cout << "由此自动机转换成的对应的文法为:" << endl;
cout << "G=({";//<< stat[0];
for(int i4 = 0; i4 < n; i4++)
{
if(i4 != 0)
{
cout << ",";
}
cout << stat[i4];
}
cout << "},";
cout << "{";
for(int i5 = 0; i5 < m; i5++)
{
if(i5 != 0)
{
cout << ",";
}
cout <<terminal[i5];
}
cout << "},";
cout << "P,";
cout << stat[0] << "),";
cout << "其中P为:" << endl;
for(i = 0; i < n; i++)
{
for(j = 0; j < n; j++)
{
if(f[i][j] != '0')
{
cout << stat[i] << "->" << f[i][j] << stat[j] <<endl;
}
}
}
第 13 页 共 13 页
展开阅读全文