编译原理教程_3 词法分析

文章原稿
https://gitee.com/fakerlove/fundamentals-of-compiling

文章目录

3. 词法分析

3.1 设计——状态转换图

3.1.1 词法分析概述

  • 词法分析的任务:从左至右逐个字符地对源程序进行扫描,产生一个个单词符号。

  • 词法分析器(Lexical Analyzer) / 扫描器(Scanner)
    功能:输入源程序、输出单词符号
    单词符号的种类:基本字、标识符、常数、运算符、界符。
    输出的单词符号的表示形式:(单词种别,单词自身的值)

  • 词法分析器在编译器中地位

    编译原理教程_3 词法分析

3.1.2 词法分析器的设计

词法分析程序自动生成有哪些困难?

  • 编程过程的设计以及二义性问题。

1) 词法分析器的结构

编译原理教程_3 词法分析

  • 为保证可以扫描完全,我们将扫描缓冲区分为两个半区,互补使用。
  • 比如有些语言规定,标识符长度不能超过128,我们就可以推断出编译器的扫描缓冲区总长度为256。

2) 超前搜索

  • 某些语言允许程序员编写程序时,不写空格,或可以将基本字再定义。给程序员带来了便利,却给词法分析带来的困难。
    编译原理教程_3 词法分析
  • 比如上述的例子,必须超前搜索到“,”与“.” 处,才能分辨出两条语句的不同,才能确定哪些是基本字。
  • 几点限制——不必使用超前搜索
    所有基本字都是保留字;用户不能用它们作自己的标识符
    基本字作为特殊的标识符来处理,使用保留字表
    如果基本字、标识符和常数(或标号)之间没有确定的运算符或界符作间隔,则必须使用一个空白符作间隔

3) 状态转换图

  • 状态转换图是一张有限方向图
  • 结点代表状态,用圆圈表示
  • 状态之间用箭弧连结,箭弧上的标记(字符)代表射出结状态下可能出现的输入字符或字符类
  • 一张转换图只包含有限个状态,其中有一个为初态,至少要有一个终态
    编译原理教程_3 词法分析
    编译原理教程_3 词法分析

4) 状态转换图的实现

编译原理教程_3 词法分析

不含回路的分叉结点
  • 可用一个CASE语句或一组IF-THEN-ELSE语句实现
    编译原理教程_3 词法分析
含回路的分叉结点
  • 对应一段由WHILE结构和IF语句构成的程序
    编译原理教程_3 词法分析
终态结点
  • 表示识别出某种单词符号,对应返回语句
    编译原理教程_3 词法分析
    其中,C为单词种别,VAL为单词自身值

3.2 正规集和正规式

3.2.1概念

设A是非空的有限字母表,A={ai| i=1,2,……n},正规式和正规集的递归定义,对给定的字母表Σ:

  • ε和∅都是Σ上的正规式,它们所表示的正规集为{ε}和∅;
  • 任何a∈Σ ,a是Σ上的正规式,它所表示的正规集为{a} ;
  • 假定e1和e2都是Σ上的正规式,它们所表示的正规集为L(e1)和L(e2),则:
    • (e1|e2)为正规式,它所表示的正规集为L(e1)∪L(e2)
    • (e1.e2)为正规式,它所表示的正规集为L(e1)L(e2)
    • (e1)*为正规式,它所表示的正规集为(L(e1))*仅由有限次使用上述三步骤而定义的表达式才是Σ上的正规式,仅由这些正规式表示的字集才是Σ上的正规集。

3.2.2 正规式性质

对正规式,下列等价成立:

若α、β、γ是字母表A上的正规式,且ε∉L(γ),则

α= β| α γ 当且仅当 α= β γ*

α= β| γ α当且仅当 α= γ* β

编译原理教程_3 词法分析

3.2.3 正规文法-> 正规式⭐️

  • 由正规文法G的各个产生式写出对应的正规方程式,得到联立方程组。
  • 把方程组中的非终结符当作变元。
  • 求此正规式方程组的解,得到关于开始符号S的解:S=w , w ∈VT*,w就是所求正规式。
文法产生式 正规式
A → x B , B → y A \to xB,B\to y A→xB,B→y A=xy
A → x A ∣ y A \to xA\mid y A→xA∣y A = x ∗ y A=x^*y A=x∗y
A → x , A → y A\to x ,A \to y A→x,A→y A = x ∣ y A=x\mid y A=x∣y

例题

已知正规文法G1的产生式,求出它

所定义的正规式。

产生式为:S → aS | aB

B → bB|bA

A → cA | c

解:

1.由产生式写出对应的联立方程组

S = aS | aB ……(1)

B = bB|bA ……(2)

A = cA | c ……(3)

2.根据定理2,

由(1) S = aS | aB得: S=a*aB=a+B ……(4)

同理,由(2) B = bB|bA得: B=b+A ……(5)

同理,由(3) A = cA | c得: A=c*c=c+ ……(6)

将(6)代入(5)得:B=b+c+ ……(7)

将(7)代入(4)得:S=a+b+c+ ……(8)

3.故:正规式为S=a+b+c+

3.2.4 正规式-> 正规文法⭐️

需要借助有限自动机

3.3 有限自动机(FA)

  • 有限自动机是一种识别装置,它能准确地识别正规集。它为词法分析程序的构造提供了方法和工具。
  • 有限自动机是具有离散输入输出系统的数学模型。它具有有限数目的内部状态,系统可以根据当前所处的状态和面临的输入字符决定系统的后继行为。其当前状态概括了过去输入处理的信息。

3.3.1 确定有限自动机(DFA)

  • 对状态图进行形式化定义
  • 确定有限自动机(Deterministic Finite Automata,DFA)
    M是一个五元式 M=(S,Σ, f, S0, F),其中:
    (1)S: 有穷状态集
    (2)Σ:输入字母表(有穷)
    (3)f: 状态转换函数,为S×Σ→S的单值部分映射,f(s,a)=s’表示:当现行状态为s,输入字符为a时,将状态转换到下一状态s’,s’称为s的一个后继状态
    (4)S0∈S是唯一的一个初态
    (5)F⊆S:终态集(可空)
  • 例:DFA M=( {0,1,2,3},{a,b},f,0,{3}),其中f定义如下:
    f(0,a)=1 f(0,b)=2
    f(1,a)=3 f(1,b)=2
    f(2,a)=1 f(2,b)=3
    f(3,a)=3 f(3,b)=3
  • 上题对应状态转换矩阵与状态转换图:

编译原理教程_3 词法分析

  • 对于Σ*中的任何字α,若存在一条从初态到某一终态的道路,且这条路上所有弧上的标记符连接成的字等于α,则称α为DFA M所识别(接收)
  • DFA M所识别的字的全体记为L(M)
    编译原理教程_3 词法分析
    L(M)={含aa或bb的字}
    编译原理教程_3 词法分析

3.3.2 非确定有限自动机(NFA)

  • 一个非确定有限自动机(Nondeterministic Finite Automata,NFA)
    M是一个五元式
    (1)M=(S,Σ, f, S0, F),其中:
    (2)S: 有穷状态集
    (3)Σ :输入字母表(有穷)
    (4)f: 状态转换函数,为S×Σ*→2S的部分映射S0⊆S是非空的初态集
    (5)F⊆S :终态集(可空)
  • 从状态图看NFA 和DFA的区别
    (1)NFA可以有多个初态
    (2)弧上的标记可以是Σ*中的一个字(甚至可以是一个正规式),而不一定是单个字符
    (3)同一个字可能出现在同状态射出的多条弧上
    (4)DFA是NFA的特例
    编译原理教程_3 词法分析
  • 对于Σ*中的任何字α,若存在一条从初态到某一终态的道路,且这条路上所有弧上的标记字连接成的字等于α(忽略那些标记为ε的弧),则称α为NFA M所识别(接收)。
  • 例题:
    编译原理教程_3 词法分析
    答:L(M1)={含aa或bb的字}
    编译原理教程_3 词法分析
    答:L(M2)={ambn | m,n≥1}

3.2.3 DFA和NFA 等价条件

  • 定义:对于任何两个有限自动机M和M’,如果L(M)=L(M’),则称M与M’等价
  • 自动机理论中一个重要的结论:判定两个自动机等价性的算法是存在的
  • 对于每个NFA M存在一个DFA M’,使得L(M)=L(M’)
  • DFA与NFA识别能力相同!
  • DFA很容易用程序来实现,但设计较难
  • NFA设计更容易
    编译原理教程_3 词法分析

3.4 NFA 确定化⭐️

编译原理教程_3 词法分析

3.4.1 解决初始状态唯一性

  • 引进新的初态结点X和终态结点Y,X,Y∉S,从X到S0中任意状态结点连一条ε箭弧, 从F中任意状态结点连一条ε箭弧到Y。
    编译原理教程_3 词法分析

3.4.2 简化弧上的标记

  • 对M的状态转换图进一步施行替换,其中k是新引入的状态。
    编译原理教程_3 词法分析

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BYNAetcR-1621077529511)(picture/20210116225405705.png)]

3.4.3 对含有ε的NFA 确定化⭐️

  • 设I是的状态集的一个子集,定义I的ε-闭包,ε-closure(I)为:ε-closure(I)=I∪{s’|从某个s∈I出发经过任意条ε弧能到达s’}
  • 设a是Σ中的一个字符,定义Ia=ε-closure(J) 其中,J为I中的某个状态出发经过一条a弧而到达的状态集合。
  • 例题:
    编译原理教程_3 词法分析
  • Ia=ε-closure(J)其中,J为I中的某个状态出发经过一条a弧而到达的状态集合
    编译原理教程_3 词法分析
  • 对于上一部分的NFA M’,有:

编译原理教程_3 词法分析

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pKABcvB0-1621077529516)(picture/20210117142223517.png)]

  • 这样就得到了状态集之间的关系转换表
  • 把表看成状态转换矩阵,子集视为状态,于是转换表唯一刻划了一个DFA
  • 初态是ε-closure({X})
    终态是含有原终态Y的子集
  • 于是:NFA和DFA等价
  • 对刚刚的转换表以及M’进行化简,就将NFA转换为了一个DFA:
    编译原理教程_3 词法分析

3.5 FA 化简⭐️

1) 状态的等价性

  • DFA的化简(最小化)就是:对于给定的DFA M,寻找一个状态数比M少的DFA M’,使得L(M)=L(M’)
  • 状态的等价性定义:如果从状态s出发能读出某个字α而停止于终态,那么同样,从t出发也能读出α而停止于终态;反之亦然两个状态不等价,则称它们是可区别的
  • DFA化简基本思想:把M的状态集划分为一些不相交的子集,使得任何两个不同子集的状态是可区别的,而同一子集的任何两个状态是等价的。最后,让每个子集选出一个代表,同时消去其他状态。

2) 化简算法

  • 首先,把S划分为终态和非终态两个子集,形成基本划分Π。
  • 一般地,对某个a和I(i),若Ia(i) 落入现行Π中 N个不同子集,则应把I(i)划分成N个不相交的组,使得每个组J的Ja都落入的Π同一子集。重复上述过程,直到Π所含子集数不再增长
  • 我们对刚刚得到的DFA进行化简:
    编译原理教程_3 词法分析
  1. 划分终态与非终态:
    I(1)={0, 1, 2},I(2)={3, 4, 5, 6}
  2. 写出Ia(1)={1, 3} ,发现分别落入两个子集,说明第一个子集应该继续划分:
    I(11)={0, 2},I(12)={1},I(2)={3, 4, 5, 6}
  3. 写出Ia(11) ={1},Ib(11)={2, 4},发现Ib(11)落入两个子集,应该继续划分:
    I(111) ={0},I(112) ={2},I(12) ={1},I(2)={3, 4, 5, 6}
  4. 前三个子集都只有一个元素,不需要看了,看最后一个子集
    写出Ia(2) ={3, 6},Ib(2) ={4, 5}
    发现这两个子集都在划分的这一子集中
    划分完毕,新子集为:{0} {1} {2} {3, 4, 5, 6}
    用3来代表4,5,6,对图进行化简:
    (所谓代表,就是456射出的弧,都由3来射出,射入也一样)
    编译原理教程_3 词法分析

至此,由NFA等价变换为DFA,并将得到的DFA化简的内容结束。

3.6 正规式和有限自动机的等价性

  • 一个正规式r与一个有限自动机M等价
    L®=L(M)
  • FA ->正规式
    对任何FA M,都存在一个正规式r,使得L( r )=L(M)。
  • 正规式 -> FA
    对任何正规式r,都存在一个FA M,使得L(M)=L®。
  • 由于NFA与DFA是等价的,所以这里的FA具体是哪个并不重要,后续的讨论将使用NFA。

3.6.1 NFA–>正规式⭐️

  • 定理:对Σ上任一NFA M,都存在一个Σ上的正规式r,使得L®=L(M)。
  • 假定NFA M=<S,Σ,δ, S0, F>,我们对M的状态转换图进行以下改造:
    编译原理教程_3 词法分析
  1. 在M的转换图上加进两个状态X和Y,从X用ε弧连接到M的所有初态结点,从M的所有终态结点用ε弧连接到Y,从而形成一个新的NFA,记为M’,它只有一个初态X和一个终态Y,显然L(M)=L(M’)。
    编译原理教程_3 词法分析
  2. 然后,反复使用下面的三条规则,逐步消去结点,直到只剩下X和Y为止。
    编译原理教程_3 词法分析
    即:增加弧上的标记,减少状态的数量。
  3. 最后,X到Y的弧上标记的正规式即为所构造的正规式r
    编译原理教程_3 词法分析
    显然L( r )=L(M’)=L(M)
  • 得证: 对Σ上任一NFA M,都存在一个Σ上的正规式r,使得L®=L(M)。

3.6.2 数学归纳法

  • 定理: 对于Σ上的正规式r,都存在一个NFA M,使L(M)=L®,并且M只有一个初态和一个终态,而且没有从终态出发的箭弧。
  • 对给定正规式r中的运算符数目进行归纳:

1) 验证r中的运算符数目为0时,结论成立。

若r具有零个运算符,则r=ε或r=φ或r=a,其中a∈Σ。
编译原理教程_3 词法分析
结论成立

2) 假设结论对于运算符数目少于k(k≥1)的正规式成立

  • 假设对于运算符数目少于k(k≥1)的正规式成立。
  • 当r中含有k个运算符时,r有三种情形:
r = r1|r2
  • 由归纳假设,对ri存在Mi=<Si,Σi,δi, qi, {fi}>,使得L(Mi)=L(ri),并且Mi没有从终态出发的箭弧(i=1,2)。
  • 不妨设S1∩S1=φ,在S1∪S2中加入两个新状态q0,f0。
  • 令M=<S1∪S2∪{q0,f0},Σ1∪Σ2,δ, q0, {f0}>,其中δ定义如下:编译原理教程_3 词法分析

编译原理教程_3 词法分析
于是:L(M)=L(M1)∪L(M2)=L(r1)∪L(r2)=L(r1|r2)= L( r )

r = r1·r2
  • 令M=<S1∪S2,Σ1∪Σ2,δ, q1, {f2}>,其中δ定义如下:
    编译原理教程_3 词法分析

编译原理教程_3 词法分析

于是:L(M)=L(M1)L(M2)=L(r1)L(r2)=L(r1·r2)=L( r )

r = r1*
  • 令M=<S1∪{q0, f0},Σ1,δ, q0,{f0}>,其中q0, f0∉S1,δ定义如下(M的状态转换如右图) :
    编译原理教程_3 词法分析
    编译原理教程_3 词法分析

于是:L(M) = L(M1)* = L(r1)* = L(r1*)= L( r )
至此,基于该假设,证明结论对于运算符数目为k的正规式成立。

3.6.3 算法与示例

  • 现给一个正规式:(a|b)* (aa|bb) (a|b) *
  • 构造一个等价的NFA

编译原理教程_3 词法分析

最后得到:
编译原理教程_3 词法分析
我们还可以根据之前学到的子集法,把上面这个NFA化简为一个DFA。
编译原理教程_3 词法分析

有了这些等价关系,我们可以实现词法分析的自动生成。

3.7 正规文法和有限自动机的等价性

3.8 词法分析程序自动生成LEX

编译原理教程_3 词法分析
LEX的工作过程:

  1. 对每条识别规则Pi构造一个相应的非确定有限自动机Mi;
  2. 引进一个新初态X,通过ε弧,将这些自动机连接成一个新的NFA;
  3. 把M确定化、最小化,生成该DFA的状态转换表和控制执行程序。
    编译原理教程_3 词法分析
  • 词法分析程序的自动产生——理论和实践相结合的典范:经典理论是我们进行实践操作的理论支撑。先进技术工具是我们要提高自身能力必须使用的方式。二者结合才能综合提高自身能力。

3.9 总结

  • 正规文法、正规集与正规式的概念和关系;
  • 如何由正规文法得到正规式;
  • NFA的确定化;
  • DFA的最小化;
  • 对含有ε弧的NFA进行确定化;
  • 正规文法、正规式和自动机之间的相互转换
上一篇:【编译原理】关于NFA和DFA-集合定义的探索


下一篇:Java-ThreadPool线程池总结