收藏 分享(赏)

第2章 词法分析.ppt

上传人:gnk289057 文档编号:8306163 上传时间:2019-06-19 格式:PPT 页数:57 大小:2.17MB
下载 相关 举报
第2章 词法分析.ppt_第1页
第1页 / 共57页
第2章 词法分析.ppt_第2页
第2页 / 共57页
第2章 词法分析.ppt_第3页
第3页 / 共57页
第2章 词法分析.ppt_第4页
第4页 / 共57页
第2章 词法分析.ppt_第5页
第5页 / 共57页
点击查看更多>>
资源描述

1、2019/6/19,1,2.1 词法分析器的设计考虑及 手工构造,词法分析任务:从文件读入源程序,去除源程序中与编译无关的编辑字符、注释等,由字符拼接单词。每当识别出一个单词,就用单词的内部码(单词二元式)替换。执行词法分析任务的程序称为词法分析器。,2019/6/19,2,2.1.1 单词类型及二元式编码,单词类型任何程序设计语言的单词都可将其分为5种类型,它们是: 基本字 real、integer、 标识符 通常为以字母开始的数字字母串(简单变量、标号、) 常数 整常数(123)、实常数(123.456)、 运算符 +、*、/、 界符 ; 、(、)、,单词的性质 基本字、运算符和界符对于某

2、一程序设计语言来说是确定的,而源程序中的标识符和常数的个数是不确定的,随源程序而异。 有些单词由单个字符构成,而有些单词由多个字符构成。,2019/6/19,3,单词二元式编码经词法分析后,单词用二元式 (code,val) 表示。 code表示单词的种别,用整数码表示。单词种别表示单词的语法特性,在语法分析时使用。 val表示单词的值,在本书中用字符串表示。单词值表示了单词的语义特性,在语义分析时使用。,编码原则 通常将标识符归为一种,常数按类型分种,基本字、运算符及界符采用一符一种。 如果一个种别仅包含一个单词,那么单词种别就可代表该单词,无需给出单词值。为了输入和处理的方便,无意义的单词

3、值用字符串“NUL“表示。若一个种别含有多个单词,除给出种别外,还需给出它的值。,2019/6/19,4,实例设有某一程序设计语言,其部分单词二元式编码如下所示:,计算园柱体表面积的源程序(输入输出略)如下所示: Begin/*S=2*3.14* R* R +2*3.14* R*H */ Real r,h,s;s=2*3.14*r*(r+h) End根据单词二元式编码,上述程序的单词二元式序列应为:(,“NUL“) ,2019/6/19,5,2.1.2 源程序的输入及预处理,源程序的输入 分段读入处理(早期) 全部读入后处理,源程序以文件形式存于外存,首先要将其读入内存才可进行词法分析。早期计

4、算机内存较小,只能在内存设置长度有限的缓冲区,分段读入源程序进行处理。在编制程序时,必须考虑由于源程序分段读入所产生的问题。例如,由多个字符构成的单词有可能被缓冲区边界所打断(留作习题)。目前计算机所使用的的内存已超过若干年前硬盘容量,计算机内存足以容纳源程序的全部,故源程序可一次全部读入内存进行处理。,2019/6/19,6,设源程序如下所示,其中为续行符。,源程序读入后,输入缓冲区的内容如下所示:,2019/6/19,7,预处理词法分析器通常由二个部分构成:预处理程序扫描器(单词识别程序),分成二部分的理由 目前使用的程序设计语言大都采用自由格式书写,允许在单词之间存在多余的空格、换行和制

5、表符(TAB)。 源程序通常带有注释,注释不是程序的必要组成部分。 有些语言还提供续行功能(例C语言中的续行符),当一个单词过长(例字符串常数),可分多行列出。 对于Fortran和Cobol之类语言,源程序还受到书写格式的限制。,词法分析器可在输入缓冲区上直接识别单词,但从程序设计的角度来看,若把源程序预处理一下,则单词识别就比较容易。,2019/6/19,8,预处理主要工作 删除注释 删除续行符,以及后续换行符(0AH)。 换行符、TAB和空格具有界符作用,预处理时通常予以保留。在后面的分析中可以看到,它们的存在反而给后续的单词识别带来方便。为了简化判断,可在预处理时,将换行符和TAB统一

6、替换为空格。 大多数语言(除C语言)不区分大小写,可在预处理时,将大写字母变换成小写字母,或相反,以方便后续处理。 对于受书写格式限制的语言(例Fortran和Cobol),还应识别标号区,正确给出语句标号。识别续行标志,把相继行捻接在一起,给出语句结束符。,上述源程序经预处理后,扫描缓冲区中的内容如下所示:,2019/6/19,9,预处理例用伪代码编写一个预处理程序,要求如下: 去除源程序中注释(源程序中的注释用/*/标记,不允许嵌套使用) 去除源程序中续行符() 将TAB和换行符替换为空格 将大写字母变换成小写 在源程序尾部添加字符#,这是编译程序内部的一个特殊的单词,以示源程序结束。 每

7、调用一次,将经预处理的源程序全部送入内存中的扫描缓冲区,供扫描器识别单词。,2019/6/19,10,算法说明 用伪代码编写预处理程序,输入和预处理可同时进行,无需输入缓冲区,将读入后经预处理的源程序直接送扫描缓冲区buf1n。 定义布尔变量 in_comment,记录当前处理字符是否处于注释。 若in_comment 的值为false,则表示当前读入字符未处于注释中,此时应将当前处理字符存入扫描缓冲区;若in_comment 的值为true,则表示当前处理字符处于注释中,此时无需将该字符存入buf中,相当于掉弃。 当读入“/*”,布尔变量in_comment的值由false变为true;当读

8、入“*/”,布尔变量in_comment的值由true变为false。可用变量cur_c记录当前正在处理的字符,用old_c记录刚处理过的字符。,/*/ in_comment: f f / t t / f f,2019/6/19,11,0. procedure pro_process() /扫描缓冲区buf 和扫描缓冲区指针i 1. old_c0:in_commentfalse:cur_c文件第一个字符:i1 2. while not eof(“source.txt”) do /文件尚未处理完 3. if not in_comment then /当前字符未处于注释中 4. if old_c=

9、/ and cur_c=* then /进入注释 5. ii-1:in_commenttrue 6. else 7. if old_c= and cur_c=换行符 then ii-1 /是续行符 8. else 9. if cur_cA and cur_cZ then cur_ccur_c+32 10. if cur_c=制表符 or cur_c=换行符 then cur_c空格 11. ii+1:buficur_c /送入扫描缓冲区 12. end if 13. end if 14. else /当前字符处于注释中 15. if old_c=* and cur_c=/ then in_co

10、mmentfalse /离开注释 16. end if 17. old_ccur_c:cur_c文件下一个字符 18. end while 19. ii+1:bufi # 20. end procedure,2019/6/19,12,2.1.3 基本字的识别和超前搜索,程序设计语言单词以基本字识别最为困难,原因如下:有些语言对基本字不加保护,用户可用作普通标识符。基本字、用户定义的标识符和常数之间可能没有分隔符。,例标准Fortran对基本字不加保护,用户可以把它们用作普通标识符。让我们来观察下面三个Fortran语言语句。 IF(5.EQ.M)GOTO55逻辑IF,当M等于5转标号为55的语

11、句。 IF(5)=55IF为数组名,IF(5)为下标变量 IF(X+Y)110,120,130 算术IF,当X+Y0,转标号为130的语句显然仅根据IF无法判断其为何种单词,可能是基本字,也可能是标识符。,2019/6/19,13,解决办法是超前搜索,一直扫描到右括号后面的字符。若该字符为字母G或g,则为逻辑IF;若为数字,则为算术IF;若为=,则为标识符。超前搜索导致词法分析器实现困难。为了降低词法分析器的复杂性,避免超前搜索,在实际实现中,大多数语言的编译程序对用户采取了二条限制措施:所有基本字均为保留字,用户不得使用它们作为标识符。将空格、TAB和换行符视为界符。在基本字、用户定义的标识

12、符和常数之间,若没有运算符或界符,则至少用一个空格(或TAB、换行符)加以分隔。,这样空格、TAB和换行符不再是没有意义的了,这也就是为什么在词法分析预处理中将空格、TAB和换行符保留下来的原因。采用上述二条限制措施,对用户来讲是完全可接受的,并且已成为程序员进行程序设计的惯例。词法分析器对于所有单词的识别,最多只要向前看一个字符就足够了。,2019/6/19,14,2.1.4 遍,遍的基本概念由外存获得前一遍的工作结果(对于第一遍而言,从外存获得源程序),完成它所含的有关阶段工作之后,再把结果存于外存。,遍引入的历史背景早期的计算机内存较小,编译程序相对而言体积较大。使用遍技术的优点在于,可

13、根据当前遍的工作,装入相应的工作程序。当一遍工作完之后,内存空间大部分被释放。当下一遍进入后,几乎可以使用全部存储空间。遍数多一点还有一个好处,即整个编译程序的逻辑结构较为清晰。但是,遍数多势必增加输入输出所耗费的时间。,遍和编译程序的结构遍决定了编译程序的结构。在本书中,词法分析器是以函数形式书写的,函数的返回值是一个单词的二元式。词法分析不作为独立一遍词法分析作为独立一遍(本书采用),2019/6/19,15,2.1.5 状态转换图和词法分析器手工构造,引入状态转换图的必要性若不考虑科学计数法形式,程序设计语言的无符号实型常数有三种书写形式,它们是:无小数部分形式 134. 无整数部分形式

14、 .12 完全形式 3.14如果考虑科学计数法形式,则无符号实型常数识别更复杂。 直接编写识别无符号实型常数的程序有一定难度,状态转换图是构造单词识别程序(扫描器)的一种较好工具。,状态转换图基本概念及应用 状态转换图是一个有向图。在状态转换图中,结点代表状态,用园圈表示。状态之间用箭弧连接。箭弧上的标记代表在射出结状态下可能出现的合法的输入字符。,2019/6/19,16,一个状态转换图包含若干个状态(结点),其中有一个是初态,用符号指示,是识别字符串的起点。状态转换图至少有一个终态,表示已识别出一个字符串(单词),终态用双圈表示。例,识别标识符的状态转换图如下所示:,其中0为初态,2为终态

15、。,2019/6/19,17,若当前状态是1,只有当输入字符为非字母数字,才可能到达状态2,显然多读了一个字符,这就是终态结2上星号*的含义,它并不是正在识别的标识符的组成部分。此时应将其退回,下次识别单词从该字符开始。单词的尾部空格作为单词的结束标志,单词的前导空格在识别单词前滤去,所以在初态0有一个标记为空格的自回路。在词法分析预处理中,空格作为界符被保留下来。由于空格不是任何单词的组成部分(除字符串常数),故在识别单词前,应将单词的前导空格滤去。由于空格的特殊性,状态转换图中用虚线表示(若当前输入字符是空格,重新进入1状态)。在识别标识符的过程中,当读入的字符不是字母或数字,可能是空格,

16、说明当前正在识别的单词已完全读入。为程序处理方便起见,不管是什么字符,均将其退回。若退回的是空格,该空格将成为下一个单词的前导空格。,2019/6/19,18,一个状态转换图可用于识别单词,从初态出发,经一条通路到达某一终态,路径上的标记依次连接而成的字符串,即为状态转换图识别出的单词。,例,识别实常数和整常数的状态转换图如下所示:,2019/6/19,19,设输入串为“134.+ “,从初态0出发,经路径,到达终态5,路径上标记依次连接而成的字符串为“134.+“,退回多读的字符+,识别出的字符串(单词)为“134.“。,2019/6/19,20,一个程序设计语言单词的识别,可以用若干张状态

17、转换图予以描述,虽然用一张图也可以,但用若干张图,有时会有助于概念的清晰化。,将上述三个图合并视为一个图,初始状态为0。从初态0出发,若当前输入字符是字母,则进入状态1;若为数字,则进入状态3;若为小数点,则进入状态7。若为加号,则进入状态10。否则,或进入其它单词的识别(若有的话),或出错(非法字符)。,下图是识别“#“、“+“和“+“的状态转换图。,2019/6/19,21,利用状态转换图识别单词状态转换图每次只能识别一个单词,若源程序中有N个单词,则需使用状态转换图N次。设源程序为“x+y#“(#是预处理程序添加的),单词识别程序(扫描器)共使用状态转换图5次。,从初态0出发,读入x进入

18、状态1,在状态1读入+,进入终态2,识别出标识符“x“,退回+; 从初态0出发,读入+进入状态10,在状态10读入+,进入终态11,识别出运算符“+“; 从初态0出发,读入+进入状态10,在状态10读入y,进入终态12,识别出运算符“+“,退回y; 从初态0出发,读入y进入状态1,在状态1读入#,进入终态2,识别出标识符“y“,退回#; 从初态0出发,读入#进入状态13,识别出单词“#“,识别出单词“#“意味着整个源程序中字符处理完毕。,2019/6/19,22,根据状态转换图编制程序状态转换图就是程序控制流程图,每个结点对应一段程序。 分叉结点:if语句或switch语句 含自回路结点:wh

19、ile语句 终态结点:return语句返回单词的二元式。若终态结点带有星号*,则缓冲区指针值不变;否则缓冲区指针值加1,指向下一字符。,下面是根据识别标识符的状态转换图编制的部分扫描程序。struct code_val /结构用于存放单词二元式char code;char val20; struct code_val scanner(char *buf); /单词识别程序(扫描器),每调用一次返回一个单词的二元式。void concat(char token,char c); /拼接单词函数char reserve(char token); /查基本字表函数,2019/6/19,23,stru

20、ct code_valchar code;char val20; ; struct code_val scanner(char *buf) /每调用一次返回一个单词的二元式 /buf为扫描缓冲区存放经预处理的源程序。 static int i=0; /静态局部变量,扫描缓冲区指示器。 struct code_val t=0,“NUL“;/用于存放单词二元式,识别前清空。 char token20=“; /用于拼接单词的字符数组,识别前清空。 /去除前导空格while(bufi= ) i+; /进入标识符或基本字的识别if(bufi=a /返回标识符或基本字的二元式 /其余单词识别程序略 /en

21、d of scanner,2019/6/19,24,拼接函数concat(token,ch) concat为拼接函数,它有二个参数。设在调用前token内容为“beg“, 输入字符ch为i,则调用拼接函数concat后,token的内容为“begi“。 void concat(char token,char c) for(int i=0;tokeni!=0;i+); /找到尾tokeni=c;token+i=0; ,查基本字表函数reserve(token) 基本字通常是由字母构成,符合标识符规则。考虑简化程序设计,将基本字作为一种特殊标识符来处理。设置一个基本字表(包括相应二元式编),当状态

22、转换图识别出一个标识符时,就去查对这张表,确定它是基本字还是标识符。 char reserve(char token) /基本字及编码表const char *table=“begin“,“end“,“integer“,“real“; const char code=“ac“;for(int i=0;istrlen(code);i+)if(strcmp(token,tablei)=0) return codei;return i; /标识符的单词种别为i ,0 1 2 3,2019/6/19,25,2.2 正规式、自动机及词法分析器的自动生成,2019/6/19,26,2.2.1 基本概念,有

23、穷字母表符号有限集,它的每个元素称为字符。,字(字符串)上字符所构成的有限序列。,空字不包含任何字符的字,称为空字,记为(空字相当于高级语言中的空串“”)。 空字 空集 集合仅有一个元素,*上所有字的全体,包括。例:=0,1*=,0,1,00,01,10,11,000,001,,2019/6/19,27,(集合的)积运算定义:设U、V*,U和V的积记为UV(或UV)且定义为UV=|(U)(V) 积不满足交换律 UVVU 积满足结合律 (UV)W=U(VW) 证明见本书38页 积满足分配律 X(YZ)=XYXZ,(集合的)闭包设V*,V的闭包记为V*且定义为V自身的任意有限次积,即V*= V0V

24、1V2Vn,规定V0 = 。设V=0,1,则V*=, 0, 1, 00, 01, 10, 11, 000, 001, 闭包V*中的每个字都是由V中的字经有限次连接而成。,(集合的)正则闭包定义:设V*,V的正则闭包记为V+,且定义V+=VV*。 根据定义可以证明V+ = V1V2Vn(详见本书18页)。设V=0, 1,则V+ = V1V2Vn= 0, 1, 00, 01, 10, 11,000,001, ,V+可理解为二进制数的全体。,若V=U,则UV=VV=V2,2019/6/19,28,2.2.2 正规式与正规集,正规式和正规集的定义: 和是上的正规式,相应的正规集为、 。 若字符a,则字

25、符a是正规式,相应正规集为a。 若、为正规式,相应正规集分别记为L()和L(),则|是正规式,其相应正规集记为L(|) ,且令L(|)=L()L()。 若、为正规式,相应正规集分别记为L()和L(),则(或)是正规式,其相应正规集记为L(),且令L()= L()L()。若=,则 L()= L()= L(2)=L()2。推广到一般,正规式自身的n次积是正规式,可记为n,其相应正规集记为L(n),显然L(n)= L() n。) 若为正规式,相应正规集记为L(),则*= 0|1| 2 | |n是正规式,规定0 =,其相应正规集记为L(*),且令L(*) =L() *。 正规式运算符优先性依次为:*、

26、,可用园括号改变运算顺序。,例子详见本书第21页,2019/6/19,29,实际意义 有穷字母表是程序设计语言所使用的字符集的抽象 正规集是程序设计语言单词集的抽象 正规式是程序设计语言构词规则的抽象,正规式相等原理二个正规式是相等的,当且仅当二个正规式所表示的正规集是相等的。 例:设是正规式,求证| = 。 证: L(|) = L()L() = L()L(|) = L() | =,正规式满足下列关系 交换律:| = | 结合律:|(|) = (|)|,() = () 分配律:(|) = |,(|) = | = = ,2019/6/19,30,例设 =a|b|z, = 0|1|9。 描述标识符

27、的正规式: (|)* 描述二进制数的正规式: (0|1)(0|1) * 描述无符号整常数的正规式:* 描述无符号实常数的正规式: *.*|.* |(*.*|.*|* )(E|e) (+|-|) *,123.45 123.,2019/6/19,31,2.2.3 确定有限自动机(DFA),DFA定义一个确定有限自动机M是一个五元式M = ( S,f,s0,Z ) S是一个有限集,它的每一个元素称为状态。 是一个有穷字母表,它的每个元素称为一个输入字符。 f是一个从S至S的映照,即f:SS(单值函数)例f (si,a) = sj,表示当现行状态为si,若输入字符为a,则转移到下一状态sj,sj称为s

28、i的后继状态。 s0S,是唯一的一个初态。 ZS,是一个终态集。,例:一个识别二进制数的确定有限自动机M=(0,1,0,1,f,0,1) 其中f的定义如下:f(0, 0) = 1、f(0, 1) = 1、f(1, 0) = 1、f(1, 1) = 1,2019/6/19,32,状态转换矩阵函数f可用矩阵表示,行表示状态,列表示输入字符,该矩阵称为状态转换矩阵。只要对初态和终态作适当标记,可用一个状态转换矩阵来表示DFA。,DFA M可用一个(确定的)状态转换图表示例识别二进制数的DFA可用(确定的)状态转换图表示如下:,接上例,2019/6/19,33,字可为DFA M识别 对于一个字,若存在

29、一条从初态结到某一终态结的路径,且路径上的所有弧的标记依序连接成的字为,则称可为DFA M所识别或接受。 若DFA M的初态结同时又是终态结,则称空字可为DFA M所识别或接受。 DFA M所识别的字全体记为L(M)。,设= 1012 = 5,因从初态0出发,存在一条到终态1的路径。路径上的标记依次连接为101,则称= 101可为M所识别或接受。L(M) = |为二进制数。,2019/6/19,34,2.2.4 非确定有限自动机(NFA),NFA定义一个非确定的有限自动机M是一个五元式M=(S,f,S0,Z) S是一个有限集,它的每一个元素称为状态。 是一个有穷字母表,它的每个元素称为一个输入

30、字符。 f是一个从S*到S的子集映照,即f:S*2S(多值函数) 2S表示幂集,若S=0,1,则2S = ,0,1,0,1。 S0S,是一个非空初态集,即NFA的初态不一定唯一。 ZS,是一个终态集。,DFA和NFA的主要区别为:映照f(函数),DFA的映照f是从“状态字符“映射到“状态“,f为单值函数;而NFA的映照f是从“状态字“映射到“状态子集“,f为多值函数。,2019/6/19,35,例某一非确定有限自动机M=(1,2,3,4,5,6,a,b,f,1,2,3) 其中f的定义为:f(1,“a“)=4,5、f(5,)=6、f(6,)=2、f(2,“ab“)=3 其余情况f(si,) =

31、(*,siS),NFA M可用一个(非确定的)状态转换图表示,2019/6/19,36,字可为NFA M识别 对于*中的一个字,若在NFA M中存在一条从某一初态到某一终态的路径,且路径上的所有标记依序连接成的字为,则称可为NFA M所识别或接受。 若M的某些结既是初态结又是终态结,或者存在一条从某个初态结到某个终态结的道路,那么空字可为M所接受。 非确定有限自动机M所识别的字全体记为L(M)。 对于任何二个有限自动机M和M,若L(M) = L(M),则称二个有限自动机M和M等价。 DFA是NFA的特例,对于每个NFA M存在一个DFA M,使得L(M)=L(M)。,2019/6/19,37,

32、2.2.5正规式与确定有限自动机的等价性,对于上的每个正规式V,存在一个上的确定有限自动机M,使得L(V)=L(M)。,VNFA 将V表示成拓广NFA,根据下面三条规则对V进行分裂(规则基于识别的语言不变),直至每条弧上的标记为上的一个字符或。, V ,2019/6/19,38,例,已知正规式(a|b)*(aa|bb)构造它的NFA。,2019/6/19,39,NFADFA为了便于描述NFA确定化算法,我们引进二个概念。 I的闭包I的闭包记为_CLOSURE(I)或CLOSURE(I),设I是NFA M状态集的一个子集,I的闭包定义为: 若状态sI,则s_CLOSURE(I)。 若状态sI,则

33、从状态s出发,经一条或多条弧所能到达的状态s也属于_CLOSURE(I)。 IaI NFA M状态集的一个子集Ja 从I出发经一条a弧所能到达的状态全体Ia _CLOSURE(Ja),2019/6/19,40,设I=1,则CLOSURE(I)= CLOSURE(1)=1,2。 设I=5,4,3,则CLOSURE(I) = CLOSURE(5,4,3) = 5, 4, 3, 6, 2, 8, 7。 接上例设I=1,2,则Ja =4,53=3,4,5Ia = CLOSURE (3,4,5)=5,4,3,6,2,8,7,NFA确定化算法,1)数据结构及初始状态,手工计算,2019/6/19,41,2

34、)算法描述 0. procedure NFA_TO_DFA 1. p_cur1 /当前指针,指示当前处理的状态子集。 2. p_end1 /表尾指针 3. I1CLOSURE(X) 4. while p_curp_end 5. for i1 to n /设=x1,x2,xn 6. if IXip_cur and IXip_curI1p_end then 7. p_endp_end+1 8. Ip_endIXip_cur 9. end if 10. end for 11. p_curp_cur+1 12. end while 13. end procedure,2019/6/19,42,根据上述

35、算法对NFA M进行确定化。 因NFA M具有6个状态,状态子集个数(包括空集)最多为64,故表的长度不会超过26-1=63,循环必然在有限步中结束。,3)结果处理 将I中的每个子集视为DFA M的一个状态。 _CLOSURE(X)视为DFA M的初态。 将所有含有原NFA终态(即Y)的DFA M状态视为终态。 将I、Ia、Ib、视为DFA M状态转换矩阵,即函数f。,4)重新标记,0是初态,3和4为终态。,2019/6/19,43,5)用(确定的)状态转换图表示,构造过程采用子集法,从字的识别角度来看,DFA M和NFA M是等价的。,2019/6/19,44,2.3 词法分析器的自动生成,

36、输入正规式(构词规则),经自动生成器加工,其结果为DFA。,词法分析器 的 自动生成器,输入正规式,输出DFA (状态转换矩阵),自动生成过程概述 构造描述每个单词的正规式Pi(1iN)。 根据正规式Pi构造NFA Mi(1iN),假定初态均为0。在构造NFA Mi的同时,逐步并且最终形成识别全部单词的NFA M。 NFA M确定化 重新标记,构造DFA M。,2019/6/19,45,实例(模型语言的词法) 模型语言字符集 az,09,+,=,*,, ,; ,(,),# 模型语言单词集 基本字:begin、end、integer、real 标识符:以字母开始的数字字母串 无符号整常数:数字串

37、 运算符:+、* 、+、= 界符: , 、; 、( 、) 、#,单词编码 基本字:begin (,“NUL“、end(,“NUL“)、integer (a,“NUL“)、real (c,“NUL“) 标识符:(i,字符串) 无符号整常数:(x,字符串) 运算符:=(=,“NUL“)、+(+,“NUL“)、*(*,“NUL“)、+($,“NUL“) 界符:,(,“NUL“)、;(;,“NUL“)、( ( (,“NUL“)、) ( ),“NUL“)、#(#,“NUL“),2019/6/19,46,构造NFA M,实例解: 构造正规式 (令= a|b|c|d|z、 = 0|1|2|3|4|5|6|7

38、|8|9) 标识符 (|)* 无符号整常数 * 运算符 单词本身(例=的正规式为=,“+“的正规式为“+“) 界符 单词本身(例;的正规式为;) 基本字通常是由字母构成,符合标识符规则,将基本字作为一种特殊标识符来处理(可设置保留字表,二者区分可通过查表)。,2019/6/19,47,NFA M确定化,2019/6/19,48,重新标记,构造DFA M。,注:0为初态,其余均为终态。,2019/6/19,49,扫描器控制程序工作原理 每次识别单词,控制程序总是从初态出发,不断读入字符,进入下一状态,寻求最长匹配,直到无法前进为止,这样始终多读一个字符。 在状态迁移过程中,需用Token数组保存

39、读入字符。 在无法前进时,若发现当前状态为终态,则认为识别出一个单词,反之出错,即Token数组所保存的字符串不构成一个单词,而是源程序中的一个错误词形。 事先设置一个单词二元式编码表,它包括除标识符和整常数以外的所有单词(基本字、运算符和界符)。当DFA识别出一个单词,就根据Token数组所保存的字符串去查表。 若该单词在表中存在,即可获得二元式编码;若不存在,则该单词必为标识符和整常数二者之一,只要稍加判断即可区分。首字符为字母的是标识符,首字符为数字的是无符号整常数。,2019/6/19,50,DFA每次只能识别一个单词,需多次使用DFA来识别源程序中单词,直到源程序中的字符全部处理完。

40、 由于构造的方法不同,在DFA某一个终态中,有可能包含原NFA中的二个终态或更多,即在该状态可识别出二个词形相似的单词,这就存在一个优先匹配问题。此时,需调整单词二元式编码表中的单词排列顺序,将需优先匹配的单词排在表的较前面,这样在单词查找过程,让其先得到匹配。,设源程序为“x+y#”(#是预处理程序添加的),扫描器共使用确定有限自动机5次(见下页)。,2019/6/19,51,从初态0出发,读入x进入状态1,在状态1读入+,无法前进。因当前所处状态1为终态,故识别出一个单词。查表未果,由于首字符为字母,故单词“x“为标识符,返回单词二元式编码(i,“x“)并退回+。 从初态0出发,读入+进入

41、状态4,在状态4读入+,进入终态13,在状态13读入+,无法前进。因当前所处状态13为终态,故识别出一个单词。查表,确认识别出单词为“+“,返回单词二元式编码($,“NUL“)并退回+。 从初态0出发,读入+进入状态4,在状态4读入y,无法前进。因当前所处状态4为终态,故识别出一个单词。查表,确认识别出单词为“+“,返回单词二元式编码(+,“NUL“)并退回y; 从初态0出发,读入y进入状态1,在状态1读入#,无法前进。因当前所处状态1为终态,故识别出一个单词。查表未果,由于首字符为字母,故单词“y“为标识符,返回单词二元式编码(i,“y“)并退回#。 从初态0出发,读入#,进入状态10。由于

42、无法再读入字符,即查表,确认识别出单词为“#“,返回单词二元式编码(#,“NUL“)。识别出单词“#“意味着整个源程序中字符全部处理完毕。,2019/6/19,52,扫描器控制程序的实现 状态转换矩阵的数字化 控制程序是根据DFA来工作的,首先要将状态转换矩阵数字化,空白用0表示。 在预处理中,空格作为界符被保留下来。单词的前导空格在识别一个单词前被滤去,单词的尾部空格用作单词的终止标志,故在状态转换矩阵中,应增加空格列,该列每个元素的值均标记为0。 因26个字母作用相同,故可用一列表示。在查表时可将26个字母转换成1个,例a。 因10个数字作用相同,故可用一列表示。在查表时可将10个数字转换

43、成1个,例0。,状态转换矩阵经数字化后如下页所示:,2019/6/19,53,状态转换矩阵经数字化后如右所示:,2019/6/19,54,转换函数 0procedure Tra(c) 1. if c是字母 then ca 2. if c是数字 then c0 3. return c 4. end procedure,DFA终态集 Z=1,2,3,4,5,6,7,8,9,10,11,12,13 在上例中,除初态0外,其余状态均为终态,故终态集可不设置。但此情况属于特例,通常需设置终态集,供程序判断。,单词二元式编码表,2019/6/19,55,0. procedur scanner( ) 1.

44、t.code :t.val“Nul“:Token“ 2. ii+1:cbufi:当前状态初态 3 while DFA当前状态,c0 do 4. TokenToken,c /将Token中字符串拼接字符c后送Token 5. 当前状态DFA当前状态,Tra(c) 6. ii+1 /指向下一字符 7. if bufi为空 then break 8. else cbufi 9. end if 10. end while 11 if not(当前状态终态集) then output “Error“:exit 12. t.code根据Token查表的结果 13. if t.code=? then /?表

45、示单词二元式编码表中无 14. if Token首字符是字母 then t.code=i /是标识符 15. if Token首字符是数字 then t.code=x /是整常数 16. t.valToken /此时单词有值 17. end if 18. return t 19. end procedure,2019/6/19,56,控制程序的工作原理和手工构造相类似,差异在于如何实现状态迁移。手工构造的扫描器是利用程序控制流程的改变来实现状态迁移,而使用DFA的控制程序是利用状态转换矩阵来实现状态迁移。 使用DFA的控制程序远较手工构造的扫描器简单,并且控制程序与源语言的单词集无关。所谓自动构造词法分析器,实际上就是构造DFA。所以,自动构造词法分析器的难点在于构造DFA,对于实际程序设计语言来说,用人工构造DFA是不可能的,必须由程序来实现。 借助于上述原理(正规式NFADFA),1972年贝尔实验室的M.E.Lesk和E.Schmid在Unix操作系统上首先实现了这样的程序,称之为词法分析器生成工具,简称LEX。 用户可使用LEX提供的语言编写源程序,源程序由描述单词的正规式和单词的二元式编码构成。LEX源程序经LEX编译程序(词法分析器生成工具)加工,编译的结果就是与正规式等价的确定有限自动机(状态转换矩阵形式)。,结论,2019/6/19,57,结 束,

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

当前位置:首页 > 企业管理 > 管理学资料

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报