1、第三章 词法分析,3.1 词法分析程序的设计,3.2 单词的描述工具,3.3 有穷自动机,3.4 正规式和有穷自动机的等价性,3.5 正规文法和有穷自动机的等价性,3.6 词法分析程序的自动构造工具,3.7 典型例题及解答,知识结构,词法分析,自动构造工具,正规集,正规式,有穷自动机(NFA DFA),正规文法,知识结构,3.1 词法分析程序的设计,主要任务:读源程序,产生单词符号 其他任务: 滤掉空格,跳过注释、换行符 追踪换行标志,复制出错源程序, 宏展开,,一.词法分析程序与语法分析程序的接口方式,词法分析工作可以是独立的一遍,把字符流的源程序变为单词序列,输出在一个中间文件上,这个文件
2、作为语法分析程序的输入而继续编译过程 更通常情况,常将词法分析程序设计成一个子程序,每当语法分析程序需要一个单词时,则调用该子程序。词法分析程序每得到一次调用,便从源程序文件中读入一些字符,直到识别出一个单词,或说直到下一单词的第一个字符为止,二.词法分析程序的输出,1.单词符号一般可分为下列五种: 基本字(关键字):begin、end、if、while、var 标识符:常量名、变量名、过程名 常数(量):25、3.1415、true、“ABC” 运算符:、*、= 界符:逗点、分号、括号 2.输出表示: (单词种别,单词自身的值) 单词种别:语法分析需要的信息 单词自身的值:编译其他阶段需要的
3、信息,(标识符,指向该标识符所在符号表中位置的指针) 单词的种别可以用整数编码表示,假如标识符编码为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 ( 4,指向x的符号表入口) 赋值号:= ( 4, := ),标识符y ( 1, 指向y的符号表入口 ) 分号; ( 5, ; ),三.将词法分析工作分离的考虑,1.使整个编译程序的结构更简洁、清晰和条理化: 2.编译程序的效率会改进: 3.
4、增强编译程序的可移植性:,3.2 单词的描述工具,一.正规文法 程序设计语言中的几类单词可用下述规则描述:l|ll|d|l|dd|d+|-|*|/|=|=,|;|(|)| 其中l表示az中的任何一个英文字母,d表示09中 的任何一个数字,例3.1:d|.ed|.e| d e| d |d |sd d |其中,s表示正或负号(+,-),二.正规式 正规表达式(regular expression)是说明单词的pattern的一种重要的表示法(记号),是定义正规集的工具 定义(正规式和它所表示的正规集): 设字母表为,辅助字母表=, 和都是上的正规式,它们所表示的正规集分别为和 任何a ,a是上的一
5、个正规式,它所表示的正规集为a,假定e1和e2都是上的正规式,它们所表示的正规集分别为L(e1)和L(e2),那么,(e1), e1 e2, e1e2, e1也都是正规式,它们所表示的正规集分别为L(e1), L(e1)L(e2), L(e1)L(e2)和(L(e1) 仅由有限词使用上述三步骤而定义的表达式才是上的正规式,仅由这些正规式所表示的字集才是上的正规集,其中的“”读为“或”(也有使用“+”代替 “” 的);“ ”读为“连接”;“”读为“闭包”(即,任意有限次的自重复连接)。在不致混淆时,括号可省去,但规定算符的优先顺序为“”、“”、“”、“ ”、“” 。连接符“ ”一般可省略不写。“
6、”、“ ”和“” 都是左结合的,例3.2 令=a,b, 上的正规式和相应的正规集的例子有: 正规式 正规集 a a ab a,b ab ab (ab)(ab) aa,ab,ba,bb a ,a,a, 任意个a的串 (ab) ,a,b,aa,ab 所有由a和b组成 的串 (ab)(aabb)(ab) 上所有含有两个相继的a或两个相继的b组成的串,例3.3 =d,e,+,-,则上的正规式d(dd )(e(+- )dd ) 其中d为09的数字表示的是:无符号数的集合。 若两个正规式e1和e2所表示的正规集相同,则说e1和e2等价,写作e1=e2 例如: e1= (ab), e2 = ba 又如: e
7、1= b(ab) , e2 =(ba)b e1= (ab) , e2 =(ab),设r,s,t为正规式,正规式服从的代数规律有: rs=sr “或”服从交换律 r(st)=(rs)t “或”的可结合律 (rs)t=r(st) “连接”的可结合律 r(st)=rsrt (st)r=srtr 分配律 r=rr=r 是“连接”的恒等元素(零一律) rr=r r=rrr “或”的抽取律,三.正规文法和正规式的等价性 1.将上的一个正规式r转换成文法G=(VN,VT,P,S):令VT,确定产生式和VN的元素用如下办法: 选择一个非终结符S生成产生式S r,并将S定为G的识别符号。若x和y都是正规式 ,
8、BVN ,则: (R1) 对形如 A xy的正规产生式,重写为:A xB,B y (R2)对形如A x*y的正规产生式,重写为:A xB,A y,B xB,B y (R3)对形如A xy的正规产生式,重写为:A x,A y 不断应用R做变换,直到每个产生式右端只含一个VN,例3.4 将 r=a(a|d)*转换成相应的正规文法 令S是文法的开始符号,形成S a(a|d)*: R1 S aA A (a|d)* R2 S aA A (a|d)B A B (a|d)B B R3 S aA A A aB A dBB aB B dB B ,2.将正规文法转换成正规式:基本上是上述过程的逆过程,最后只剩下一
9、个开始符 号定义的正规式,其转换规则如表4.1所示:,例3.5 Gs:S aA S a A aAA dA A a A d S aA|a A aA|a|dA|d (a|d)A|(a|d) (a|d)*(a|d) s=a(a|d)*(a|d)|a=a(a|d)*(a|d)|)=a(a|d)*|) r=a(a|d)*,3.3 有穷自动机,一.确定的有穷自动机(DFA)(有限自动机) DFA:能准确地识别正规集 一个确定的DFA:M=(K,f,S,Z) K是一个有穷集,它的每个元素称为一个状态 是一个有穷字母表,它的每个元素称为一个输入符号,所以也称为输入符号字母表 f是转换函数,是在KK上的映射,即
10、,如f(ki,a)=kj,(kiK,kjK)就意味着,当前状态为ki,输入符为a时,将转换为下一个状态kj,我们把kj称作ki的一个后继状态,SK是唯一的一个初态 Z K是一个终态集,终态也称可接受状态或结束状态 例4.6:DFA M=(S,U,V,Q,a,b,f,S,Q)其中f定义为: f(S,a)=U f(V,a)=U f(S,b)=V f(v,b)=Q f(U,a)=Q f(Q,a)=Q f(U,b)=V f(Q,b)=Q,一个DFA可以表示成一个状态图(状态转换图) 假定DFA M含有m个状态,n个输入符号,那么这个状态图含有m个结点,每个结点最多有n个弧射出,整个图含有唯一一个初态结
11、点( )和若干个终态结点(双圈),若f(ki,a)=kj,则从状态结点ki到状态结点kj画标记为a的弧 例4.6中的DFA的状态图表示如图4.1所示:,图3.1 状态图表示,一个DFA可以表示成一个矩阵表示,该矩阵的行表示状态,列表示输入符号,矩阵元素表示相应状态和输入符号将转换成的新状态,即k行a列为f(k,a)的值。用 标明初态;否则第一行即是初态,相应终态行在表的右端标以1,非终态标以0 例4.5中的DFA的矩阵表示如图4.2所示:,图3.2 矩阵表示,若t *,f(S,t)=P,其中S为 M的开始状态,P Z,Z为终态集,则称t为DFA M所接受(识别) 设QK,函数f(Q,)=Q,一
12、个输入符号串t(t1tx,t1 ,tx *),在DFA M上运行的定义为:f(Q,t1tx)=f(f(Q,t1),tx),例如,证明t=baab被例3.6的DFA所接受 f(S,baab)=f(f(S,b),aab)=f(V,aab)=f(f(V,a),ab)=f(U,ab)=f(f(U,a),b)=f(Q,b)=Q Q属于终态 得证,DFA M所能接受的符号串的全体记为L(M) 结论:上一个符号串集V是正规的,当且仅当存在一个上的确定有穷自动机M,使得V=L(M) DFA的确定性表现在转换函数f:KK是一个单值函数,也就是说,对任何状态kK和输入符号a ,f(k,a)唯一地确定了下一个状态,
13、二.不确定的有穷自动机NFA 一个NFA:M=(K,f,S,Z) K是一个有穷集,它的每个元素称为一个状态 是一个有穷字母表,它的每个元素称为一个输入符号 f是一个从K * 到K的子集的映像,即:K* * 2 K SK是一个非空初态集 ZK是一个终态集,例3.7:一个NFA M=(0,1,2,3,4,a,b,f,0,2,4)其中 f(0,a)=0,3 f(2,b)=2 f(0,b)=0,1 f(3,a)=4 f(1,b)=2 f(4,a)=4 f(2,a)=2 f(4,b)=4 它的状态图表示如图4.3所示:,一个NFA也可以用一个矩阵表示. *上的符号串t在NFA N上运行. *上的符号串t
14、被NFA N识别(读出、接受). DFA是NFA的特例 对每个NFA N存在一个DFA ,使得L(M)=L(N) 对于任何两个有穷自动机M和N,如果L(M)=L(N),则称M与N是等价的,三.NFA转换为等价的DFA 定理:设L为一个由不确定的有穷自动机接受的集合,则存在一个接受L的确定的有穷自动机 将NFA转换成接受同样语言的DFA,这种算法称为子集法,状态集合I的几个有关运算: 定义1:集合I的-闭包: 令I是一个状态集的子集,定义-closure(I)为: 1)若sI,则s-closure(I); 2)若sI,则从s出发经过任意条弧能够到达的任何状态都属于-closure(I)。 状态集
15、-closure(I)称为I的-闭包,例:如图所示的状态图: 令I=1,求-closure(I)=?,根据定义: -closure(I)=1,3, J是从状态子集I中的每个状态出发,经过标记为a的弧而达到的状态集合., Ia是状态子集,其元素为J中的状态,加上从J中每一个状态出发通过弧到达的状态,定义2: 令I是NFA M的状态集的一个子集, a 定义: Ia=-closure(J)其中J = (s,a),SI,例:令I=1,求Ia=?,Ia=-closure(J)=-closure(1,a))=-closure(2,4)=2,4,6,例:有NFA M,求DFA M。,I=-closure(1
16、)=1,4 Ia=-closure(1,a)(4,a)= -closure(2,3)= -closure (2,3)=2,3 Ib= -closure(1,b)(4,b)= -closure()= Ic= -closure(1,c)(4,c)= I=2,3, Ia=2,Ib=4,Ic=3,4,I Ia Ib Ic,1,4 2,3 ,2,3 2 4 3,4,2 2 4 ,4 ,3,4 3,4,初态,start,符号,状态,a,b,c,0,2,3,4,1,2,2,1,_,_,_,_,_,_,_,_,3,3,4,4,DFA M状态转换矩阵,将求得的状态转换矩阵重新编号,0,1,4,2,3,1,4,2
17、,3,4,2,a,c,a,b,b,c,3,4,使用图3.4的NFA N的状态集合来理解上述两个运算:,-closure(0)=0,1,2,4,7 令A=0,1,2,4,7, move(A,a)=3,8 -closure(3,8)=1,2,3,4,6,7,8,图3.4 NFA N,对于一个NFA N=(K,f,K0,Kt)来说,若I是K的一个子集,设Is1,s2,sj,a是中的一个元素,则move(I,a)=f(s1,a) f(s2,a) f(sj,a),假设NFA N=(K, ,f,K0,Kt)按如下办法构造一个DFA M=(S, ,d,S0,St),使得L(M)=L(N):M的状态集S由K的
18、一些子集组成。用S1 S2. Sj表示S的元素,其中S1, S2,. Sj是K的状态。并且约定,状态S1, S2,. Sj是按某种规则排列的,即对于子集S1, S2= S2, S1,来说,S的状态就是S1 S2 M和N的输入字母表是相同的,即是 转换函数是这样定义的: D(S1 S2,. Sj,a)= R1R2. Ri 其中 R1,R2,. , Ri = -closure(move(S1, S2,. Sj,a),S0=-closure(K0)为M的开始状态St=Sj Sk. Se,其中Sj Sk. SeS且Sj , Sk,. Se Kt,构造NFA N的状态K的子集的算法,见图4.5: 假定所
19、构造的子集族为C,即C= (I1, I2,. Ii),其中I1, I2,. Ii为状态K的子集,例3.8 应用图3.5的算法对图3.4的NFA N构造子集,步骤如下: 1.首先计算-closure(0):令I0=-closure(0)=0,1,2,4,7,I0未被标记,它现在是子集族C的唯一成员 2.标记I0:令I1=-closure(move(I0,a)=1,2,3,4,6,7,8,将I1加入C中,I1未被标记。令I2=-closure(move(I0,b) =1,2,4,5,6,7,将I2加入C中,I2未被标记 3.标记I1:-closure(move(T1,a)=1,2,3,4,6,7,
20、8,即I1,I1已在C中。I3=-closure(move(I1,b)=1,2,4,5,6,7,9,将I3加入C中,I3未被标记,4.标记I2:-closure(move(I2,a)=1,2,3,4,6,7,8,即I1,I1已在C中。-closure(move(I2,b)=1,2,4,5,6,7,即I2,I2已在C中 5.标记I3:-closure(move(I3,a)=1,2,3,4,6,7,8,即I1。-closure(move(T3,b)=1,2,4,5,6,7,10,令其为I4,在入C中,I4未被标记 6.标记I4:-closure(move(I4,a)=1,2,3,4,6,7,8,即
21、I1。-closure(move(I4,b)=1,2,4,5,6,7,即I2,a,b,0,01247,I0=01247,38,5,38,1234678,5,124567,I1=1234678,38,59,59,1245679,I2=124567,38,5,I3=1245679,38,5 10,5 10,12456710,I4=12456710,38,5,至此,算法终止共构造了5个子集: I0=0,1,2,4,7 I1=1,2,3,4,6,7,8 I2=1,2,4,5,6,7 I3=1,2,4,5,6,7,9 I4=1,2,4,5,6,7,10 那么图4.4的NFA N构造的DFA M为: 1.
22、S= I0, I1, I2, I3, I4 2. =a,b,3. D(I0,a)=I1 D(I3,a)=I1D(I0,b)=I2 D(I3,b)=I4D(I1,a)=I1 D(I4,a)=I1D(I1,b)=I3 D(I4,b)=I2D(I2,a)=I1 D(I2,b)=I2 4.S0=I0 5.St=I4 为便于书写,将I0、 I1、 I2、 I3、 I4重新命名为A、B、C、D、E或用0、1、2、3、4分别表示,若采用后者,该DFA M的状态转换图如图4.6所示:,图3.6 DFA M,四. DFA的化简 最小状态DFA: 没有多余状态(死状态) 没有两个状态是互相等价(不可区别) 一个有
23、穷自动机可以通过消除无用状态和合并等价状态而转换成一个最小的与之等价的有穷自动机 有穷自动机的无用状态:从该自动机的开始状态出发,任何输入串也不能到达的那个状态或者从这个状态没有通路到达终态 例如图4.7的有穷自动机M中的状态s4便是无用状态,在有穷自动机中,两个状态s和t等价的条件是: 一致性条件必须同是为可接受状态或不可接受状态 蔓延性条件对于所有输入符号,必须转换到等价的状态里,分割法:把一个DFA(不含多余状态)的状态分成一些不相交的子集,使得任何不同的两子集的状态都是可区别的,而同一子集中的任何两个状态都是等价的,DFA M最小化方法: 先分成终态集合和非终态集合 对每个集合中的符号
24、分别用输出字母去查看它们到达状态的集合是否在同一个集合中 如果不在同一个集合,将它们划分在不同的集合中 直到不能再划分为止,例3.9 将图3.8中的DFA M最小化 P0=(1,2,3,4,5,6,7) a P1=(1,2,3,4,5,6,7) a P2=(1,2,3,4,5,6,7) a P3=(1,2,3,4,5,6,7) b令1代表1,2消去2,令6代表6,7,消去7,得到图4.8(b) 的DFA M,它是4.8(a)的DFA M的最小化,图3.8 DFA M和DFA M,3.4 正规式和有穷自动机的等价性,对于上的一个NFA M,可以构造一个上的正规式R,使得L(R)=L(M) 第一步
25、,在M的状态转换图上加进两个结,一个为x结点,一个为y结点。从x结点用弧连接到M的所有初始结点,从M的所有终态结点用弧连接到y结点。形成一个与M等价的M, M只有一个初态x和一个终态y 第二步,逐步消去M中的所有结点,直至只剩下x和y结点。在消结过程中,逐步用正规式来标记弧,其消结的规则如下:,最后x和y结点间的弧上的标记则为所求的正规式r,例3.10 以例4.7的NFA M为例,M的状态图在图4.3,求正规式r,使L(r)=L(M),()消除M中的所有结点,1. (a)对于正则式,所构造NFA:,x,y,(b)对于正则式,所构造NFA:,x,y,(c)对于正则式a,a,则 NFA:,x,y,
26、a,对于上的一个正规式R,可以构造一个上的NFA M,似的L(M)=L(R) 语法制导方法:按正规式的语法结构指引构造过程,首先将正规式分解成一系列子表达式,然后使用下面规则为r构造NFA,对r的各种语法结构的构造规则具体描述如下:,2. 若s,t为上的正则式,相应的NFA分别为N(s)和N(t);,(a)对于正则式R=s|t, NFA(R),(b)对正则式R=st,NFA(R),(c)对于正则式R=s*, NFA(R),(d)对R=(s),与R=S的NFA一样.,例3.11 为r=(a|b)*abb构造NFA N,使得L(N)=L(r),图3. 10 从正规式r构造NFA,3.5 正规文法和
27、有穷自动机的等价性,采用下面的规则可以从正规文法G直接构造一个有穷自动机NFA M;使得L(M)L(G): M的字母表与G的终结符集相同 为G中的每个非终结符生成M的一个状态,G的开始符S是开始状态S 增加一个新状态Z,作为NFA的终态 对G中的形如A tB的规则(其中t为终结符或,A和B为非终结符的产生式),构造M的一个转换函数f(A,t)=B 对G中形如A t的产生式,构造M的一个转换函数f(A,t)=Z,例3.12:与文法GS等价的NFA M如图4.11 GS: S a A S bB S A aBA bA B aS B bA B ,有穷自动机转换成等价的正规文法: 对转换函数f(A,t)
28、=B,可写一产生式:A tB 对可接受状态Z,增加一产生式:Z 有穷自动机的初态对应文法开始符 有穷自动机的字母表为文法的终结符集,例3.13:给出与图4.12的NFA等价的正规文法G G(A,B,C,D,a,b,P,A),其中P为: A a B C A bD D aB B bC D bD C aA D C bD,3.6 词法分析程序的自动构造工具,以LEX为例介绍如何从正规式产生识别该正规式所描述的单词的词法分析程序 LEX是一个广泛使用的工具,UNIX系统中使用lex命令调用。它用于构造各种各样语言的词法分析程序,图 3.13LEX编译系统的作用,图 3.14 使用LEX生成词法分析器,L
29、EX程序由三部分组成: 说明部分:变量说明、常量说明、正规定义 % 转换规则:Pn action n % 辅助过程:容纳的是action所需要的辅助过程,图4.15给出一个识别PL/O单词的LEX程序片断:IDENTa-zA-Z a-zA-Z0-9*NUMBER0-9 0-9*%(#include stdio.h#include “code.h“#include “symbol.h“#include “y.tab.h“extern int level;int cc=0;%)%“ cc+;“t“ tablize(); /*adjustcc to tabposition*/“n“ cc=0; li
30、ne-copy(); /*copy a line of input file*/“ cc+; return GT;“=“ cc+; return EQ;,“#“ cc+; return NE;“,“ cc+; return colon; “.“ cc+; return Period;“(“ cc+; return Lparen;“)“ cc+; return Rparen;“=“ cc+;cc+;return GE;“=“ cc+; cc+;return ASGN;“;“ cc+; return Semicolon;NUMBER intn;cc += yyleng;sscanf(yytext,
31、“%d“, ,IDENT Symbol *s;cc += yyleng;if(s=lookup(yytext)=0) /*new identifier*/s=install(yytext,VARIABLE,level,0); /* install symbol*/if (stype=C)yylval.number=s-adr;else /*its a VARIABLE or PROC*/yylval.sym=s;return s-type;%yywrap( ) ;,图 4.15 LEX程序例子-识别PL/0单词的LEX程序,3.7 典型例题及解答,1.构造正规式1(01)*101相应的DFA
32、2.将图4.18所示的DFA最小化,3.下面是用于生成词法分析器scanner的LEX的源文件,请给出scanner对输入串ababcbacaabaababaa的输出结果:%a+b*a printf( 1%sn,yytext);(ab)+c? printf( 2%sn,yytext);aa printf( 3%sn,yytext);(a|b)*c printf( 4%sn,yytext);,【本章小结】 词法分析程序是编译第一阶段的工作,它读入字符流的源程序,按照词法规则识别单词,交由语法分析程序接下去。本章讲述了词法分析程序设计原则,并介绍了正规式和有穷动机分别作为正规集描述和识别机制。在此
33、基础上给出了词法分析程序自动构造工具如LEX的原理。词法分析程序的设计技术可应用于其它领域,比如查询语言以及信息检索系统等,这种应用领域的程序设计特点是,通过字符串模式的匹配来引发动作,回想LEX,说明词法分析程序的语言,可以看成是一个模式动作语言。词法分析程序的自动构造工具也广泛应用于许多方面,如用以生成一个程序,可识别印刷电路板中的缺陷,又如开关线路设计和文本编辑的自动生成等。,作业: 1、求正则式(a|b)(a|b|0|1)*对应的正则文法(右线性文法),画状态转换图。 2、求正则文法GZ: Z 0Z| 1Z | 0AA 0BB 0对应的正则式 3、 已知有限自动机如图(1)以上状态转换图表示的语言有什么特征? (2)写出其正规式与正规文法. (3)构造识别该语言的有限自动机DFA. 4、请构造与正则式R=(a*b)*ba(a|b)* 等价的状态最少的DFA(确定有限自动机),