第三章 词法分析...

Post on 15-Mar-2016

170 Views

Category:

Documents

3 Downloads

Preview:

Click to see full reader

DESCRIPTION

第三章 词法分析 词法分析是编译的第一个阶段,它的主要任务是从左至右逐个字符地对源程序进行扫描,产生一个个单词序列,用以语法分析。执行词法分析的程序称为词法分析程序或扫描程序。 3.1 词法分析的基本概念 3.1.1 词法分析的意义 词法分析程序完成的是编译第一阶段的工作。词法分析工作可以是独立的一遍,把字符流的源程序变为单同序列,输出在一个中间文件上,这个文件做为语法分析程序的输入而继续编译过程、为减少与外存储器交换数据,将词法分析程序设计成一个子程序,每当语法分析程序需要一个单词时,则调用该子程序。词法分析程序每得到一次调用,便从. - PowerPoint PPT Presentation

TRANSCRIPT

第三章 词法分析 词法分析是编译的第一个阶段,它的主要任务是从左至右逐个字符地对源程序进行扫描,产生一个个单词序列,用以语法分析。执行词法分析的程序称为词法分析程序或扫描程序。 3.1 词法分析的基本概念3.1.1 词法分析的意义 词法分析程序完成的是编译第一阶段的工作。词法分析工作可以是独立的一遍,把字符流的源程序变为单同序列,输出在一个中间文件上,这个文件做为语法分析程序的输入而继续编译过程、为减少与外存储器交换数据,将词法分析程序设计成一个子程序,每当语法分析程序需要一个单词时,则调用该子程序。词法分析程序每得到一次调用,便从

源程序文件中读入一些字符,直到识别出一个单词。停留在空格、回车、制表符或下一单词的第一个字符为止。这样把词法分析程序和语法分析程序是放在同一遍里,而省掉了中间文件,节省了运行时间。 正如前面所说,正则文法是上下文无关文法的特例,也就是说,词法分析可以看作语法分析的的一部分,词法描述完全可以归并到语法描述中去,。那么为什么将词法分析做为一个独立的阶段?为什么把编译过程的分析上作划分成词法分析和语法分析两个阶段?主要的考虑因素为:1 .使整个编译程序的结构更简洁、清晰和条理化。词法分析比语法分析简单的多,由于源程序结构上的一些细节,常使得识别单词的工作交给语法分析处理比较曲折和费时。例如,空白和注释的处理;早期的 FORTRAN 受书写格式限制,需在识别单词时进行特殊处理等等。如果这些工作都在语法分析时一并考虑,显然会使得分析程序的结构变得十分复杂。

2 .编译程序的工作效率也是要考虑的。正则文法和上下文无关文法采用的识别器是不同的,把词法分析从语法分析独立出来,采用专门的读字符和分离单词的技术可大大加快编译速度。由于单词的结构可采用与正则文法对应的有限自动机进行识别,进而可建立词法分析程序的自动构造工具。 3 .可增强编译程序的可移植性。在同一个语言的不同实现中,或多或少地会涉及到与设备有关的特征,比如采用 ASCII还是 EBCDIC 字符编码。另外语言的字符集的特殊性的处理,一些专用符号,如 PASCAL 中的“↑”的表示等等,都可置于词法分析程序中解决而不影响编译程序其它成分的设计。

词法分析程序的主要功能是从字符流的源程序中识别单词,它要从左至右逐个字符地扫描源程序,有时还可完成其它一些任务。如:滤掉源程序中的注释和空白(由空格,制表或回车换行字符引起的空白)、为了使编译程序能将发现的错误信息与源程序的出错位置联系起来,同法分析程序负责记录新读入的字符行的行号,以便行号与出错信息相联;在支持宏处理功能的源语自中,可以由词法分析程序完成其预处理等等。也可完成一些语法分析的工作,如:说明部分的处理。

3.1.2 词法分析的输入输出 词法分析程序的功能是读入源程序,输出单词符号。词法分析是读入文本文件的源程序 , 读入文本文件可采用从文件中逐个读入符号 , 或者建立一个缓冲区 ,先将字符读入缓冲区 , 然后从缓冲区中读入字符,使用缓冲区也可以采用双区域方式,即将缓冲区分成二部分一部分在分析时,更换另一部数据,从而提高词法分析的效率。 单词符号是一个程序设计语言的基本语法符号。程序设计语言的单同符号大致可分成 5种: 1. 基本字,也称关键字,如 PASCAL 语言中的 begin, end, if; while 和 var 等。 2.标识符,用来表示各种名字,如常量名、变量名、类型名、函数名和过程名等。 3. 常数,各种类型的常数,如 25, 3.1415, TRUE和“ ABC” 等。

4. 运算符,如 +,-,*,/,<= 等。 5.界符,如逗点,分号,括号 ,冒号等。 词法分析程序所输出的单词符号常常采用以下二元式表示(单词种别,单词自身的值)。单词的种别是语法分析需要的信息,而单词自身的值则是编译其它阶段需要的信息。比如在 PASCAL 的语句 const i=25 , yes=1 ;中的单词 25 和 1 的种别都是常数,常数的值 25和 1 ;对于代码生成来说,是必不可少的、有时,对某些单词来说,不仅仅需要它的值 , 还需要其它一些信息以便编译的进行。比如,对于标识符来说,还需要记载它的类别。层次还有其它属性,如果这些属性统统收集在符号表中,那么可以将单词的二元式表示设计成如下形式(标识符 ,指向该标识符所在符号表中位置的指什),如上述语句中的单词 i和 yes 的表示为:

(标识符,指向 i 的表项的指针)(标识符,指向 yes 的表项的指针) 单词的种别可以用整数编码表示,设标识符编码为 1 ,常数为 2 ,保留字为 3 ,运算符为 4 ,界符为 5.

这种码称为机内码。例:写出程序段 if i=5 then x:=y;在经词法分析器扫描后输出的单词符号和它们的表示

答: 保留字 if ( 3 ,‘ if’) 标识符 i ( 1 ,指向 i 的符号表入口) 等号 = ( 4 ,‘ =’) 常数 5 ( 2 .‘ 5’) 保留字 then ( 3 ,‘ then’) 标识符 x ( 1 ,指向 x 的符号表入口) 赋值号 := ( 4‘:=’) 标识符 y ( 1 ,指向 y 的符号表入口) 分号; ( 5 ,‘;’)综上所述可以把单词表示为:(内部码,属性)的二元式。

3.1.3 词法分析的实现方法 词法分析的实现主要有二种方法,一是将词法分析单独写成一个独立的程序,其工作作为独立的一遍,把字符流的源程序变为单同序列,输出在一个某个中间文件上(也可直接存放在内存中),另一种方法是将词法分析程序设计成一个子程序,每当语法分析程序需要一个单词时,则调用该子程序。词法分析程序每得到一次调用,便从源程序文件中读入一些字符,直到识别出一个单词。停留在空格、回车、制表符或下一单词的第一个字符为止。这样把词法分析程序和语法分析程序是放在同一遍里,而省掉了中间文件,节省了运行时间。

3.2 正规式自动机和状态图3.2.1 正规式的表示 在编译程序设计时,应尽量减少语法规则,从而提高编译程序的效率,那么如何使设计的正规规则最少,或者当一个语言较复杂时,怎样能够判定它是否能用正规文法表示,以及如何自动生词法分析程序等到,都需要用一种新的表示方法,为些引进了正规式和正则集。在这里可以用正规式来描述单词符号语言中的基本语法符号,井且基于正规式这类描述工具,可以建立词法分析技术,进而可以建立词法分析程序的自动构造方法。

正规式也称正则表达式,也是表示正现集的工具。 对于字母表 Σ, Σ 上的正规式和它所表示的正现集是递归定义的: 1. ε和 φ是 Σ 上的正规式,它们所表示的正规集分别为 {ε}和 φ ; 2 .任何 a Σ∈ , a是 Σ 上的一个正规式,它所表示的正规集为{a} ; 3 .假定 e1和 e2 都是 Σ 上的正规式,它们所表示的正现集分别为 L(e1)和 L(e2) ,那么, (e1)、 e1|e2、 e1·e2和 e1* 也都是正规式,它们所表示的正规集分别为 L(e1), L(e1) L(e∪ 2), L(e1)L(e2)和 L( e1) * 由有限次使用上述三步骤而定义而构成的表达式就是 Σ 上的正规式,由这些正规式所表示的字符串集就是 Σ 上的正规集。

例:令 Σ={a,b} ,则 ba* a(a|b)* (a|b)*(aa|bb)(a|b)* 都是正规式,它们的正规集为: {ban|n≥0} {以 a 为首的字 } {含有两个相继的 a 或两个相继的 b 的字 }例:设 Σ1={0, 1} ,则( 0|1)( 0|1) * 是 Σ1 上的正规式 设 Σ2={A, B, 0, 1}* ,则( A|B)( A|B|0|1) *是 Σ2 上的正规式 定义 3.1若两个正规式 e1和 e2 所表示的正规集相同,则说 e1和

e2 是等价,记作 e1=e2 。例:a|b=b|a b(ab)*=(ba)*b , (a|b)*=(a*|b*)*

设 r, s, t 为正规式,则:( 1) r|s=s|r( 2) r|(s|t)=(r|s)|t( 3) (rs)t=r(st)( 4) r(s|t)=rs|rt (r|s)t=rt|st( 5) εr=rε=r( 6) (r*)*=r*下面以(1)为例,证明之证:∵ L(r|s)= L(r) ∪L(s)= L(s) ∪L(r)= L(s|r) ∴ r|s=s|r证毕。

1 .将 Σ 的一个正规式转换成文法 G=( Vn, Vt, P, S),令其中的 Vt =Σ ,确定产生式和 Vn 的元素用如下办法。 对任何正规式 r ,选择一个非终结符 S 生成产生式 S→r ,并将 S定为 G 的识别符号。 若 x和 y 都是正规式,对形如 A→xy 的产生式,重写 :A→xB,B→y 两产生式,其中 B 是新选择的非终结符,即 B Vn ∈ 。 对已转换的文法中的形如 A→x*y 的产生式,重写为 A→xB A→y B→xB B→y 其中 B 为一新非终结符。或 A→xA A→y 对形如 A→x|y 的产生式,重写为; A→x A→y不断利用上述规则做变换,直到每个产生式最多含有一个终结符为止。

例:将 R=a(a|d)*转换成相应的正规文法,令 S 是文法的开始符号、首先形成 S→a(a|d)* ,然后形成 S→aA 和 A→(a|d)* .再重写第二条产生式形成 : S→aA A→(a|d)A A→ε 即: S→aA A→aA A→dA A→ε 严格来说,正规文法不含 ε规则,故消去之。改为: S→aA|a A→aA|dA|a|d2. 将正视文法转换成正规式。基本上是上述过程的逆过程,最后只剩下一个开始符号定义的产生式,并且该产生式的右部不含非终结符。其转换规则下:(1) 产生式 A→xB,B→y 有正规式 A=xy(2) 产生式 A→xA|y 有正规式 A=x*y (3) 产生式 A→x, A→y 有正规式 A=x|y

例 : 文法 G[ S] S→aA S→a A→aA A→dA A→a A→d 先有: S=aA|a A=( aA|dA) |(a|d)再将 A 的正规式变换为 A=(a|d)A|(a|d)据表中规则 2 变换为: A=(a|d)*(a|d) 再将 A 右端代入 S 的正规式得: S=a((a|d )*(a|d))|a 再利用正规式的代数变换可依次得到 S=a((a|d)* (a|d ) |ε) S= a( a|d) *即 a( a|d) * 为所求。

3.2.2 有限自动机 形式语言的识别在编译理论中起着重要的作用。语言识别器是一个程序,它以串 x 作为输入, x 是语言的句子是回答“是”,否则回答“不是”。有限自动机(也称有穷自动机)它也是一种识别程序,它能准确地识别正现集,即识别正规文法所定义的语言和正规式所表示的集合,引人有穷自动机这个理论,正是为了词法分析程序的自动构造寻找的特殊方法和工具。 有限自动机分为两类;确定的有限自动机( Deterministic Finite Automata)和不确定的有限自动机( Nondeterministic Finite Automata),虽然确定有限自动机和非确定有限自动机面都能识别正规集,前者任一状态对于某输入符号只存在一种状态的转换,后者有些状态对于某输入符号可能存在多种状态的转换。前者执行效率高,占存储空间大,后者反之。下面我们给出确定的有穷自动机和不确定的有穷自动机的定义,有关概念及不确定的有穷自动机的确定化算法。

1.确定的有限自动机( DFA)定义 3.2一个确定的有限自动机( DFA)M 是一个五元组: M=(K,Σ,f, S, Z)其中(1) K 是一个有穷集,它的每个元素称为一个状态(2) Σ 是一个有穷字母表,它的每个元素称为一个输入字符(3) f 是一个从 K×Σ→K 的单值映象(4) S K∈ ,是唯一的初始状态(开始状态)(5) Z K ,是非空的终止状态集,终止状态也称接受状态或结束状态。

f(S,a)=S’ 意味着,当现行状态为 S ,输入字符为 a 是时,将转换到下一个状态 S’ 。这里把 S’ 称为 S 的一个后继状态。 一个 DFA 可以也可以表示成一个状态图(或称状态转换图简称转换图)。假定 DFA M含有 m 个状态, n 个输入字符,那么这个状态图含有 m 个结点,每个结点最多有 n 个弧射出,整个图含有唯—的一个初态结点和若干个终态结点,初态结点以“ =>” ,终态结点用双圈表示。若 f(S, a)=S’ 则从状态结点 S 到状态结点 S’画标记为 a 的弧;

例:上述状态图的五元式的 DFA 为:DFA M=({S0,S1,S2 , S3},{a,b},f,S0 , {S3,})其中: f (S0 , a) = S1 f (S0 , b) = S0

f (S1 , a) = S1 f (S1 , b) = S2 f (S2 , a) = S1 f (S2 , b) = S3 f (S3 , a) = S1 f (S3 , a) = S0

例:接受语言( a|b) *abb的 DFA状态图

另外一个 DFA 还可以用矩阵表示,该矩阵的行表示状态,列表示输入字符,矩阵元素表示相应状态行和输入字符列下的新状态,即 k行 a 列为 f( k, a)的值。其中用“ =>”标明初态;否则第一行即是初态,相应终态行在表的右端标以 1 ,非终态标以 0 。则上例中可表示成: 字符状态

a b

S0 S1 S0 0

S1 S1 S2 0

S2 S1 S3 0

S3 S1 S0 1

定义 3.3 扩充了映象 f定义如下: f(R,ε)=R,其中 R 为任意状态, f(R,tα)=f(f(R,t),α) 其中 α ∑*∈ , t ∑ ∈定义 3.4 对于某个 DFA M=(K,Σ, f, S, Z),如有 f ( S, α) =P, P Z ,∈ 则称字符串 α 可被 DFA 所接受 若M 是又初始状态,又是终止状态,显然 ε 也是可以被接受的。 DFA M 所能接受的全体记为 L(M)

例:试证 abaaba 为上述的 DFA 所接受。

f(S,abaaba)=f(U,baaba)=f(V,aaba)=f(U,aba)=f(Q,ba)=f(Q,a)=Q

∵Q Z ∈ ∴ 得证。 结论 :∑ 上的一个字符串集 V

∑* 是正规的,当且仅当存在一个∑上的确定有穷自动机M ,使得 V=L(M)。

2. 不确定的有穷自动机( NFA)定义 3.5 一个不确定的有穷自动机( NFA)M 是一个五元组M=(K,Σ,f, S, Z)其中 1. K 是一个有穷状态集 2. Σ 是一个有穷输入字符字母表 3. f 是个从 K×Σ到 K 的子集的映象。 4 S K ,是一个非空初态 (开始状态 ) 集; 5. Z K ,是一个非空终态 (终止状态 ) 集。 一个 NFA 可用带标记的有向图来表示,这张有向图又称状态转换图,简称转换图。它的结点是状态,有标记的边代表转换函数,这种转换图,从一个状态出发的不同边可以有相同的标记,该转换图的边可以用 ε标记。

例:试根据如下状态图构造相应的 NFA

M=( {S,A,B,Z},{a,b},f,{S},{Z})其中 f: f( S, a)= {A} f( S, b)= {B} f( A, a)= {Z} f( A, b)= {B} f( B, a)= {A,B} f( B, b)= {Z} f( Z, a)= {A,Z} f( Z, b)= Φ

显然该自动机能接受字符串baaaabaabaaaaabababa定义 3.6扩充了映象 f定义如下: f(R,ε)={R},其中 R 为任意状态, f(R,tα) 是所有集合 f(Qi,α)日并集,即 f(R,tα)= f(Q1,α) f(Q∪ 2,α) f(Q∪ 3,α), ··· f(Q∪ n,α) 其中 α ∑*∈ , t ∑ ∈ 而f(R,t)={Q1, Q2, Q3, ···Qn}

直观起见 f({Q1, Q2, Q3, ···Qn},α)= f(Qi,t)因而,假如 f(R,t)={Q1, Q2, Q3, ···Qn}, 则f(R,tα) =f({Q1, Q2, Q3, ···Qn},α)

定义 3.7 对于某个 NFA M=(K,Σ, f, S, Z),如对于某个 NFA 存在状态 P, P Z∈ ,且 P f(S∈ 0, α),S0 S ,∈ 则称字符串 α 可被该 NFA 所接受定义 3.8 对于任何两个有限自动机 M和M’ ,如果L(M) =L(M’) , 则称 M和M’ 是等价的。

3. NFA到 DFA 的转换 对于一个 NFA总是存在与之对应的 DFA 。新的 DFA 的每个状态对应 NFA 的一个状态集 ,其中 NFA 的状态集是输入各种符号串所能到达的状态集 ,用 DFA 的状态来保存 NFA 在读入符号后能到达的所有状态踪迹。这样 NFA转换表里,每个条目是一个状态集,在 DFA 的转换表中,每个条目只有一个状态。若 NFA有 n 个状态 , 所有的状态集个数为 2n-1( 不能出现空集 ), DFA到 NFA转换的思想是让 DFA 的每个状态代表 NFA 的状态集,这个 DFA 也就是用它的状态去保持 NFA 在读入符号后能到达的所有状态踪迹。也就是说,在读入输入串 a1a2a3···an后 ,DFA 到达一个氏表 NFA状态子集 T 的状态,这个子集 T 是从 NFA 的开始状态沿着某些标有 a1a2a3···an 的路径的状态数集合,一般来说,当某个 NFA 的状态集合 K包含 n 个状态时,相应的 DFA 的状态集合 K’ 将包含 2n-1 个状态。但事实上其中很多状态是达不到的。

从 NFA 构造相应的 DFA 的算法 :(1) 将全部开始状态,以及从这些状态用 ε弧能到达的状态集作为 DFA 的开始状态。(2) 对于每个新添的 DFA状态作: 对每个输入符号 a ,作移动集合( {f(T,a)|T S∈ i})以及移动集合用 ε弧能到达的状态集作为 DFA 的状态。(3) 重复 2 直至没有新的状态 添入为止(4) 包含原 NFA 的终止状态的状态为新的终止状态。

例:试构造上例中的相应的 DFA 。解:列出 DFA 的状态 :

a b{S} {A} {B}{A} {Z} {B}{B} {A,B} {Z}{Z} {A,Z}

{A,B} {A,B,Z} {B,Z}{A,Z} {A,Z} {B}

{A,B,Z} {A,B,Z} {B,Z}{B,Z} {A,B,Z} {Z}

令 {S},{A},{B},{Z},{A,B},{A,Z},{A,B,Z},{B,Z} 分别为 S0, S1, S2, S3, S4, S5, S6, S7 。则相应的 DFA M‘ 为:M’=( {S0, S1, S2, S3, S4, S5, S6, S7}, {a,b},f’,S0,{S3, S5, S6, S7})其中 f’见图:

例:将如图表示的 NFA确定化

a b{X,5,1} {5,3,1} {5,4,1}{5,3,1} {5,3,1,2,6,Y} {5,4,1}{5,4,1} {5,3,1} {5,4,1,2,6,Y }{5,3,1,2,6,Y} {5,3,1,2,6,Y} {5,4,1,6,Y }{5,4,1,2,6,Y } {5,3,1,6,Y} {5,4,1,2,6,Y }{5,4,1,6,Y } {5,3,1,6,Y} {5,4,1,2,6,Y }{5,3,1,6,Y} {5,3,1,2,6,Y} {5,4,1,6,Y }

令状态 {X,5,1}、 {5,3,1}、 {5,4,1}、 {5,3,1,2,6,Y}、{5,4,1,2,6,Y }、 {5,4,1,6,Y }、 {5,3,1,6,Y} 分别为 0, 1, 2,3, 4, 5, 6 则

4. 确定自动机的化简 为提高语言的识别效率,应该尽量压缩 DFA 的状态,这里需要研究 DFA状态所谓最小化问题,也就是能不能找到一个状态数最少的 DFA, 可以证明在不考虑同构的前提下 ,最小化的 DFA 是唯一的。所谓确定自动机 M 的最小化实际上是找一个状态数最少的 M’使 L(M) =L(M’)。定义 3.9 如果 DFA M 从状态 S 出发,输入是 ω ,它可以停在某个终止状态,但是从 T 出发同样的输入,它停在一个非终止状态,或者相反,称为串 ω 可区分(可区别)状态 S和 T 。例: ε 可区分任何终止和非终止状态。 最小化 DFA状态数的算法就是把 DFA 的状态数分成一些不相交的子集,每一子集的状态都是不可区别的。每个子集合并成一个状态。终止状态和非终止状态是可区分的 , 因此最初应划分成两个组,终止状态组和非终止状态组。

极小化 DFA 的状态数算法:(1) 构造状态集合的初始划分 Π ,分成两组,终止状态 F 和非终止状态 K-F 。(2) 应用下面的过程对 Π 构造新的划分 Πnew

Πnew=Π ;do{Π=Πnew ; for(Π 中的每个组G ) {把G 划分成小组, G 的两个状态 S和 T 在同一小组中,当且 仅当对所有的输入符号 a, S和 T的 a 的转换是到 Π 的同一组中}while(Π!=Πnew

);

(3) 在最终划分中的每个状态组中选一个状态代表它。(4) 如果等价的 DFA 中有对任何字符 a 都转换到 本身,而不能从开始状态到的那些状态,以及不可能从开始状态到达的那些状态删除。从任何其它到上述状态的转换都成为无定义。例:对图表示的 DFA最小化

{0, 1, 2, 3} {4}对于状态 3 输入 b 时不在同一组,故{0, 1, 2} {3} {4}对于状态 1 输入 b 时不在同一组,故{0, 2} {1} {3} {4} 而 {0, 2} 对于任何输入都 在同一组中,故不能再分了。

a b

0 1 2

1 1 3

2 1 2

3 1 4

4 1 2

解:为了方便起见将图代表的 DFA 列一张表 ( 如下 )

状态数最小的状态图如下:

5. 正规式和有限自动机的转换 可以证明对于正规式都存在与之等价的有穷自动机,反之亦成立。从正规式到有限自动机利用转换系统构造 NFA ,把具有唯一开始状态和唯一终止状态允许标记有 ε弧的 NFA 称为转换系统转换系统的构造:Φ,ε,a 的转换系统分别是:

转换规则如下 :

令 SABZ , ABZ , BZ 分别为 S0 、 S1 和 S2 ,则相应的 DFA 为: DFA A0=({S0 , S1 , S2},{a,b},δ, S0,{S0 , S1 , S2}) 其中: δ( S0 ,a) = S1

δ( S0 ,b) = S2 δ( S1 ,a) = S1 δ( S1 ,b) = S2 δ( S2 ,b) = S2

即 :

( 2)解

a bSA AB AAB AB ACZA AB A

ACZ ABCZ ACZABCZ ABCZ ACZ

(2) (a|b)*ab(a|b)*

令 SA, AB, A, ACZ, ABCZ 分别为 S0 , S1 , S2, S3 , S4 则最小化为: { S0 , S1 , S2,}, { S3 , S4} S1 的输入 b 不在同一组中,故 { S0 , S2,}, {S1} , { S3 , S4} { S0 , S2}, {S1} , { S3 , S4} 分别为 S’ , A’ , Z’ 则相应的DFA 为:DFA A0=({ S’, A’, Z’},{a,b},δ, S’,{ Z’})其中: δ( S’,a) = A’, δ( S’ ,b) = S’ ( A’,a) = A’ δ( A’,b) = Z’ δ( Z’,a) = Z’ δ( Z‘,b) = Z’注意:据题意不必确定化和最小化,但不能含 ε弧

从有限自动机到正规式 把M 的所有状态转换图上加上两个结点 X、 Y ,从 X 结点用所有的初始结点,从 M 的所有终态结点用 ε弧连接到 Y 结点,形成只有一个开始状态和一个终止状态的转换系统。然后用下列规则逐步替换(适当可用等价的状态替换)直至只剩结点 X、 Y 为止。

例:试写出下图的正规式

解:

故 FA 的正规式为 (a|bb*a(bb*a)*a)*化简为: ( ( ε |bb*a(bb*a)*) a)*即: ((bb*a )* a)*

正规文法和有穷自动机间的转换 正规文法也可描述正规集,正规文法与有穷自动机有特殊关系,采用下面的规则可从正规文法 G 直接构造一个有穷自动机 NFA M ;使得 L(M) =L(G)(1) 右线性文法 · 字母表与 G 的终结符集相同; ·为G 中的每个非终结符生成 M 的一个状态,(不妨取成相同的名字)G 的开始符 号 S 是开始状态 S ; · 增加一个新状态 Z ,做为 NFA 的终态; ·对G 中的形如 A→tB 其中 t 为终结符, A和 B 为非终结符的产生式,构造 M 的一个转换函数 f( A,t) =B ;即:从 A到B画一条弧标记为 t 。 ·对G 中形如 A→t 的产生式,构造 M 的一个转换函数 f( A,t) =Z 。从 A到 Z画一条弧标记为 t 例 : 与文法 G[ S]等价的 NFA M 如图

G[S] : S→aA|bB|b A→aB|bA|a B→aS|bA|a则:其 NFA 如图:

( 2)左线性文法 · 字母表与 G 的终结符集相同;·为 G 中的每个非终结符生成 M 的一个状态, G 的识别符号Z 是终止状态 Z ; · 增加一个新状态 S ,做为 NFA 的开始状态; ·对 G 中的形如 A→Bt和 t 其中 t 为终结符, A和 B 为非终结符的产生式,构造 M 的一个转换函数 f( B,t) =A ;即:·对 G 中形如 A→t 的产生式,构造 M 的一个转换函数 f( S,t) =A ,即:从 B到 A画一条弧标记为 t 。

例 : 与文法 G[ Z]等价的 NFA M 如图 G[ Z]: Z→Za|Aa|Bb A→Ba|a B→Ab|b则:

下面介绍有穷自动机转换成等价的正规文法:( 1)右线性文法 对于 f(A,t)=Z 用产生式 A→t代替 ; 对于 f(A,t)=B 用产生式A→tB代替( 2)左线性文法 对于 f(S,t)=A 用产生式 A→t代替 ; 对于 f(A,t)=B 用产生式B→At代替例 : 给出与图相应的 NFA 写出等价的正规文法

解:右线性文法 G[A]: A→b B→b C→b D→b A→aB A→bD B→bC C→aA C→bD D→aB D→bD即: A→aB|bD|b B→bC|b C→aA|bD|b D→aB|bD|b 左线性文法 由于左线性文法只能有一个识别符号代表终止状态。故引进新的终止状态 Z ,分别从 C和 D 中引 ε弧至 Z ,然后消去 ε弧(凡是引非到有 ε弧射出的状态,即直接引入非 ε到 Z ,最后消去 ε弧) G[Z] : B→a D→b B→Aa D→Ab C→Bb B→Da D→Db A →Ca D →Cb Z →b Z→Ab Z →Bb Z →Cb Z →Db

3.2.3 状态图 前面说过可以用图来描述有限自动机 , 这种图也就称为状态图 , 它用箭头表示开始状态 , 用双圈表示终止状态。从状态图到正规文法和从状态图到有限自动机类似,在这里不再重复了。

3.2 词法分析程序的设计3.3.1 词法分析设计考虑的问题 设计一个词法分析的程序,除了考虑是否要将词法分析作为独立的一遍或者作为语法分析程序的一个子程序以及词法分析后各单词的处理后的输出形式(即属性字的结构)外,还应考虑下列问题:1. 程序的预处理从理论上来说,词法分析只是对单词的识别,但实际应用中,需要处理一些其它工作,如:( 1)删除源程序的无用字符; ( 2)滤掉源程序中的注释;( 3)进行宏替换;( 4)实现文件包含命令和条件编译命令的嵌入处理

2.保留字(关键字)的识别与查表算法 多数词法分析程序都是以读取标识符方法来获取保留字的,因此每读到一个标识符就要去查表。由于一个源程序中用户使用的标识符很多,如果设计保留字表在一定程度上形响到编译程序的速度。 一种最简单的方法是线性查找,但这种方法效率较低;另一种方法是折半查找,这种方法效率相对较高,而且由于一种程序设计语言的保留字是固定的,只需一次排序;由于程序设计语言的保留字一般不是很多,设计一个小的简单的散列(杂凑)函数,也是行之有效的方法。3. 单词的识别与超前搜索 在早期的 FORTRAN 语言中,对保留字是不加特保护的 , 用户可以用它们作为普通的标识符,这就使得关键字的识别变得比较麻烦。为了识别这些关键字则需要采用超前搜索的技术。

如 :1. DO99K=1,102. DO99K=1.103. IF(5.EQ.M)GOTO554. IF(5)=55要区分 1 和 2 在于等号后的第一个界限符 ;一个是逗号 ,一个是点 ;要区分 3 和 4 在于右括号后的第一个字符。要解决这些问题就提前读到能区分的字符再对前面的字符进行处理,这种技术称为超前搜索。

top related