DFA与NFA.docx

上传人:b****8 文档编号:9364211 上传时间:2023-02-04 格式:DOCX 页数:25 大小:441.70KB
下载 相关 举报
DFA与NFA.docx_第1页
第1页 / 共25页
DFA与NFA.docx_第2页
第2页 / 共25页
DFA与NFA.docx_第3页
第3页 / 共25页
DFA与NFA.docx_第4页
第4页 / 共25页
DFA与NFA.docx_第5页
第5页 / 共25页
点击查看更多>>
下载资源
资源描述

DFA与NFA.docx

《DFA与NFA.docx》由会员分享,可在线阅读,更多相关《DFA与NFA.docx(25页珍藏版)》请在冰豆网上搜索。

DFA与NFA.docx

DFA与NFA

DFA与NFA

词法分析是编译的第一个时期,前面简介中也谈到过词法分析器的义务确实是:

字符流------>词法记号流

那个地点词法分析和语法分析会交错进行,也确实是说,词法分析器可不能读取所有的词法记号再应用语法分析器来处理,平日情形下,每取一个词法记号,就送入语法分析器进行分析,图解:

词法分析器是编译器中与源法度榜样直截了当接触的部分,是以词法分析器能够做诸如

1).去掉落注释,主动生成文档(c#中的///注释)

2).供给缺点地位(能够经由过程记录行号来供给),当字符流变成词法记号流今后,就没有了行的概念

3).完成预处理,比如宏定义

1.词法记号,词法单位(lexeme),模式

模式是一种规矩

每个词法单位都有一个特定记号

比如inta=3,那个地点int,a,=,3差不多上词法单位,每个词法单位都属于某个词法记号,比如3确实是"num"那个词法记号的一个词法单位,而模式规定了什么样的字符串的词法记号是什么样的(模式是一种规矩)

某一特定模式规定了某个词法记号下的一类词法单位,比如:

模式:

用字母开首的包含字母和数字的串

上面模式的词法记号:

id(所有相符上面模式的字符串的记号差不多上id)

词法单位:

a123或者aabc等

词法记号举例(简称为记号):

1)每个的关键字都有属于本身的一个记号,比如关键字for,它能够应用记号for;关键字int,能够应用记号int

2)所有的关系运算符只有一个记号,比如>=,<=都用记号relation

3)所有的标识符只有一个记号,比如a123,aab应用记号id

4)所有的常数只有一个记号,比如123,22,32.3,23E10应用记号num

5)所有的字符串只有一个记号,比如"123","ab1"应用记号literal

在实际的编译器设计中,词法记号,一样用一个整形数字表示

词法记号的属性:

我们爱好用<词法记号,属性>那个二元组来描述一个词法单位,比如,关于源代码:

position:

=initial+rate*60

关于词法单位+,我们能够应用来表示。

有些情形,加倍复杂一点,比如关于position,我们表示是如许的,,具体来说应当是如许的,假定属性是一个字符串,那么id将指向如许一个字符串"position\0",我们把存放那个字符串的处所叫做符号表。

有些时刻,属性是不须要的,比如:

=,表示赋值,我们能够应用如许的表示那个词法单位,只是那个显得有些多于,因为assign_op和词法单位是一对一的,也确实是assign_op只对应了:

=,因此额外信息(属性)就显得余外的了

词法缺点:

词法分析器是专门难(有些缺点照样能够检测)检测缺点的,因为词法分析器的目标是产生词法记号流,它没有才能去分析法度榜样构造,是以无法检测到和法度榜样构造有关的缺点,比如:

fi(a==b)

词法分析器可不能找到那个缺点,它认为fi是一个标识符,而不是一个关键字,只有在后面的时期中,那个缺点才会被发明,这是一个与法度榜样构造有关的缺点

词法分析器,只能检测到词法单位上的问题,比如12.ab,作为一个词法单位,却不没有对应的模式,那么确实是产生一个缺点。

2.正规式:

前面说过模式是一种规矩,为了应用,我们须要一种规范的方法来表达模式,这确实是正规式

1)串和说话

字符类(又叫字母表):

关于字符的有限集合

串:

字符类上字符的有穷序列,串那个概念,具体来说是,某个字符类上的串

串的长度:

串中字符的个数,比如串s=abc,那么串的长度为3,用|s|表示串的长度

空串:

用ε表示

说话:

某字符类上的串的集合,属于说话的串,成为说话的句子或字

比如:

{abc,a}这确实是一个说话,abc和a确实是句子。

别的空集也是属于说话

连接:

x是串,y是串,x和y连接,成果确实是xy那个串。

假如x是串,x^3为xxx。

关于x^n(n>=0),x^0=ε

说话的运算(假定L和M是说话):

1.LUM={s|s属于L或者M},例如:

L={1,2}M={3,4}那么LUM={1,2,3,4}

2.LM={st|s属于L且t属于M},例如:

L={a,b}M={1,2}那么LM={a1,a2,b1,b2} ML={1a,1b,2a,2b}

3.L^n=LLL...LLL(n个L),例如:

L={a,b}那么L^3={aaa,aab,aba,abb,baa,bab,bbb,bba}

留意n可认为0,L^0={ε}

4.L*=L^0UL^1UL^2UL^3U...

L*表示,说话L中,所有的句子(串)以随便率性数量随便率性次序构成的句子的集合,包含ε,例如:

{a,b}*={ε,a,b,ab,ba,aab,aba,baa,bba,bab,abb,aaa,bbb...}

L*叫做L的闭包

5.L+=L^1UL^2UL^3U...

L+表示,说话L中,所有的句子(串)以随便率性数量随便率性次序构成的句子的集合,然则不包含ε

L+中的句子和L*中的句子比拟少一个ε

那么,我们经由过程上面的常识就能够表示一个标识符了,我们明白一样说话规定标识符是由字母开首,后接若干个字母或数字,我们能够如许来表示:

L={a-zA-Z}N={0-9},那么标识符确实是L(LUN)*

2)正规式

正规式又叫正规表达式,正规式是模式得一种规范的表达情势,正规式描述了一个集合,那个集合是由串构成的,事实上那个集合确实是我们前面说过的说话,只是那个地点大年夜家爱好应用正规集那个术语。

正规式r表示正规集L(r)

正规式的运算:

1.闭包运算,运算优先级最高,(r)*表示(L(r))*

2.连接运算,运算优先集合低于闭包,(r)(s)表示(L(r))(L(s))

3.或运算,运算优先集合最低,(r)|(s)表示(L(r))U(L(s))

例如:

a|b表示集合(说话,正规集){a,b}

(a|b)(a|b)表示集合(说话,正规集){aa,ab,ba,bb}

a*表示由一切a字符构成的集合(说话,正规集),包含ε

(a|b)表示由a,b构成的集合(说话,正规集),包含ε

等价的正规式:

(a|b)=(b|a)

正规式的代数性质:

1.r|s=s|r

2.r|(s|t)=(r|s)|t

3.(rs)t=r(st)

4.r(s|t)=rs|rt

5.εr=r

6.r**=r*

7.r*=(r|ε)*

留意,rs!

=sr因为连接运确实是有次序的,记住并明白得2个最全然的运算:

a|b表示{a,b},ab表示{ab}

 

3.正规定义

我们能够应用名字->正规式这种表示,来说明一个等价的代替,比如:

dight->0|1|2|3|4|5|6|7|8|9

那个地点,我们就能够应用名字digit来代替后面的正规表达式

 

我们能够对某个串集进行正规定义,比如我们对标识符集合进行正规定义:

letter->A|B|...|Z|a|b|...|z

dight->0|1|2|3|4|5|6|7|8|9

id->letter(letter|dight)*

 

请经由过程上面的例子明白得正规定义。

 

在我们表达正规表达式的时刻,能够应用一些符号使得表达简化

1)+,表示一个或者多个实力,比如,a+表示{a,aa,aaa,aaaa,...}。

差别一下*,他们的关系是那个地点r+=r*|ε

2)字符组,[abc]表示a|b|c,还能够如许表示[a-zA-Z]表示字母表中的字符

4.状况转换图

状况转换图是对词法分析器进行分析过程的描述,我们看一个确信关系运算的状况转化图:

 

1)图中圆圈表示状况

2)箭头叫做边。

X状况的边,一样指的是由X状况动身,指向其他状况的边

3)边上的符号叫做标记

若何来应用那个图?

假定输入字符串是<=,那么辨认开端时,发明<和状况0与状况1间的边上的标记一样,那么就进入1状况,下一个输入字符为=,将进入2状况,辨认停止,返回二元组

 

上图中2,3,4,5,7,8状况,他们表示辨认了一个关系运算符,那个状况叫做接收状况

状况4上面有一个*,表示说,输入指针须要回移。

所谓的输入指针,确实是指向输入字符串中现在被读入的字符的地位,4状况会多读取一个字符,因此须要回移,也确实是要留意的是,辨认完成之后,输入指针指向的是被辨认对象的最后一个字符,而不是待辨认对象的第一个字符,如许的规定在实现词法分析器时,是有必定的意义,举例说明:

输入字符串为:

a>b

识其余时刻,从>开端,读入下一个字符b时,进入4状况,那个时刻,输入指针指向b,这时刻须要回移

我们在须要回移的状况上加一个*

每个状况后面有一个return(relop,XX)那个是状况的行动,那个地点具体来说确实是返回一个二元组的行动,词法分析器分析的成果确实是获得二元组(词法记号和属性的二元组),那个二元组能够表示一个特定的字符串。

事实上上面的*,也是表示行动,也确实是输入指针回移的行动,我们能够看见,只有在接收状况才会有行动显现

 

对一门典范的说话来说状况可能有几百个

 

5.若何编写一个词法分析器

1)依照须要写出正规定义

2)依照正规定义画出转换图

3)依照转换图写出词法分析器

那个地点具体评论辩论面向过程的说话来实现一个词法分析器(比如c说话),同时重要评论辩论的是第3步

1)我们须要一个nextchar()函数,取得缓存中下一个等待分析的字符,那个函数完成年2个义务

1.      让输入指针向前移动一位

2.      返回输入指针指向的字符

2)定义一个变量token_beginning,在每个状况转换图开端的时刻,记录输入指针的地位,定义forward变量作为输入指针

3)状况转换图被实现成为代码之后,每个状况都有属于本身的一块代码,这些代码按次序完成以下工作:

1.      读取一个字符,经由过程nextchar()函数

2.      读取的字符(标记),假如它和当前状况的边上的标记雷同,那么状况将转换到边所指向的状况,具体实现只须要一个语句确实是state=xxx(xxx为目标状况);假如当前状况的所有边的标记和那个读取字符不一样,那么表示没有找到token(词法记号),这时刻须要调用fail()函数

3.      fail()函数完成如许的功能:

a.指针回移,完成forward=token_beginning的操作b.找到恰当的开端状况(也确实是查找别的一个转换图的开端状况)。

假定所有的转换图都被测验测验过,同时无法匹配,这时刻会调用一个发明缺点的小法度榜样,来申报缺点

4.      请不要随便添加行动到各个状况所持有的代码中,应当以转换图中表示的行动为准

4)定义一个全局变量lexical_value,用于储存一个指针,那个指针由install_id()和install_num()两个函数中的一个返回

5)定义两个整形变量start,state,分别表示一个转换图的开端状况和当前的状况

6)nexttoken(),这是词法分析器的主法度榜样,能够说,我们经由过程调用nexttoken()就完成了词法分析,那个函数必定是如许的格局:

while

(1){

  switch(state){

  casexx:

     ...

  caseyy:

     ...

  default:

     ...

  }

}

关于具体的设计那个地点就不说了,举例说明一个转换图若何转换成为法度榜样:

这是一个辨认浮点数的例子,看下面的代码:

#include

#include

#include

char*nexttoken();

charnextchar();

voidnext();

voidback();

char*gettoken();

charcbuf[]="12.3*********klj12.2e2jj778";

intforward=-1;

intmain(){

   while

(1){

       printf("%s\n",nexttoken());

       if(forward>=strlen(cbuf)-1){

           getchar();

           return0;

       }

   }

}

intstate;

intstart;

char*nexttoken(){

   charc;

   state=12;

   while

(1){

       switch(state){

       case12:

           c=nextchar();

           start=forward;

           if(isdigit(c)){

               state=13;

           }else{

               next();

           }

           break;

       case13:

           c=nextchar();

           if(isdigit(c))

               state=13;

           elseif(c=='e'||c=='E') 

               state=16;

           elseif(c=='.')

               state=14;

           else

               state=19;

           break;

       case14:

           c=nextchar();

           if(isdigit(c))

               state=15;

           break;

       case15:

           c=nextchar();

           if(isdigit(c))

               state=15;

           elseif(c=='e'||c=='E')

               state=16;

           else

               state=19;

           break;

       case16:

           c=nextchar();

           if(isdigit(c))

               state=18;

           elseif(c=='+'||c=='-')

               state=17;

           break;

       case17:

           c=nextchar();

           if(isdigit(c))

               state=18;

           break;

       case18:

           c=nextchar();

           if(isdigit(c))

               state=18;

           else

               state=19;

           break;

       case19:

           back();

           returngettoken();

       }

   }

}

charnextchar(){

   forward++;

   returncbuf[forward];

}

voidback(){

   forward--;

}

voidnext(){

   forward++;

}

chartoken_buf[128];

char*gettoken(){

   inti,j=0;

   for(i=start;i<=forward;i++){

       token_buf[j++]=cbuf[i];

   }

   token_buf[j]='\0';

   returntoken_buf;

}

 

 

 

词法分析

(2)---NFA

假定一个输入符号(symbol),能够获得2个或者2个以上的可能状况,那么那个finiteautomaton确实是不确信的,反之确实是确信的。

例如:

这确实是一个不确信的无穷自念头,在symbola输入的时刻,无法确信状况应当转向0,照样1

不论是确信的finiteautomaton照样非确信的finiteautomaton,它们都能够精确的描述正规集(regularsets)

我们能够专门便利的把正规表达式(regularexpressions)转换成为不确信finiteautomaton

2.NFA(NondeterministicFiniteAutomaton)

非确信的无穷自念头,我们用NFA那个术语表示,它是一个数学模型(model):

1.      一个关于状况的集合S

2.      一个关于输入符号(inputsymbols)的集合Σ

3.      函数move:

(状况,符号)->P(S) 

4.      一个开端状况s0,是一个独一的状况

5.      一个停止(接收)状况集合F

留意,P(S),表示S的幂集。

在NFA中,inputsymbol可认为ε

转换函数(transitionfunction)的含义确实是,一个确信的状况差不多从那个状况动身的一条边的标签(符号symbol),能够确信它的下一个状况构成的集合,比如上图(那个转换图确实是NFA的一种表示方法),0状况,a符号,确信了一个状况的集合{0,1}

3.转换图(transitiongraph)的表示

我们明白,运算机是无法直截了当表示一个图,我们应当若何来表示一个转换图?

应用表格确实是一个最简单的方法,每行表示一个状况,每列表示一个inputsymbol,这种表格被叫做transtiontable(转换表)

能够说应用表格是最简单的表示方法,然则我们能够留意到在那个图中状况1和inputsymbola,是没有下一个状况的(空集合),也确实是,关于一个大年夜的状况图,我们可能花费大年夜量的空间,而个中空聚聚会会议消费许多空间,然则这种消费又不是必须的,因此,作为最简单的一种实现方法,却不是最优的

说话(language)被NFA定义成为一个inputstring的集合,而那个集合中的元素则是被NFA受接收的所有的字符串(那些能够从开端状况到某接收状况的inputstring)

至于储备的方法,能够尝尝邻接表。

留意,应用什么样的数据构造来储存NFA按情形不合而不合,在一些专门情形下,某些数据构造会变得专门便利应用,而换入其他情形,则弗成以应用了。

 

 

词法分析(3)---DFA

1.DFA(DeterministicFiniteautomaton)

DFA确实是确信的有限自念头,因为DFA和NFA关系紧密,我们经常须要把他们拿到一路来讲,NFA能够转化成为一个DFA,DFA依旧是一个数学model,它和NFA有以下差别

1.      不存在ε-transition,也确实是说,不存在ε为inputsymbol的边

2.      关于move函数,move:

(state,symbol)->S,具体来说确实是,一个状况和一个特定的inputsymbol,可不能映射到2个不合的状况。

如许的成果是,每个状况,关于每个特定的inputsymbol,只有一条出边

下图确实是一个DFA:

接收说话(a|b)*ab,留意一下,接收说话(a|b)*ab的DFA我们前面见过,确实是这张图:

2.DFA的行动

我们用一个算法来仿照DFA的行动

s=s0;

c=nextchar();

while(c!

=EOF){

   s=move(s,c);

   c=nextchar();

}

if(s属于F)

   return"yes"

else

   return"no"

 

 

词法分析(4)---NFA与DFA的转化

1.子集构造(SubsetConstruction)

这是一个转换NFA到DFA的算法。

我们明白NFA和DFA的差别最重要的确实是一个状况和一个inputsymbol是否能够或许确信一个状况的问题,关于NFA,它将确信一个组状况,而DFA将确信一个状况,是以,我们有一个专门好的方法确实是把NFA的状况集对应每个DFA的状况,这确实是subsetconstruction的思惟,只是这只是大年夜概泛泛而论,我们须要加倍明白的熟悉

1)NFA在任何一个inputsymbol下,映射的状况集(经由过程move函数,那个集合平日用T字母表示)应当被明白

2)必须包管1)中状况集都对应了DFA中的一个状况

具体算法:

Input:

一个NFAN

Output:

接收雷同说话的DFAD

Method:

为D构架一个transitiontable(转换表)Dtran,每个DFA的状况是一个NFA的状况集合(那个地点必定要留意前面说过的1)2)两点)。

我们定义一些操作:

s表示NFA的状况,T表示NFA的状况集合,a表示一个inputsymbol

ε-transition(ε转换)确实是说inputsymbol为ε时的transition(转换)

操作(operation)

描述(description)

ε-closure(s)

从NFA的状况s动身,只经由过程ε-transition达到的N

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 高等教育 > 医学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1