声明:本系列文章,是根据中国大学MOOC网 哈工大的编译原理 这门课学习而成的学习笔记。
一、正则表达式
正则表达式
- 语言是一个集合,因此我们可以在语言上进行多种集合运算。比如说并运算,乘积运算(即连接运算),闭包运算等等。接下来我们看一个语言的例子,如下图所示:
这个语言的字首是字母 a,接下来连接一个任意长度的 a,b串,再接下来连接一个空串。连接一个空串就代表句子已经结束了。除此之外,我们还可以连接一个点号(.)或者下划线(_)或者一个长度大于等于1 的 a,b串。
正则表达式的定义
- 十进制整数的正则表达式:第一个符号是1~9中的一个数字,接下来连接若干个 0~9 的数字,或者连接符号 0。
- 八进制整数的正则表达式:第一个符号是数字0,第二个符号是1~7中的一个数字,接下来连接若干个 0~7 中的数字。
- 十六进制整数的正则表达式:第一个符号是0,第二个符号是 x,第三个符号是1f中的符号,接下来连接若干个0f 中的符号。
正则语言
- 可以用RE定义的语言叫做正则语言(regular language)或正则集合(regular set)
- 正则表达式也遵循一些代数定律,如下图所示:
正则文法与正则表达式等价
- 对任何正则文法 G,存在定义同一语言的 正则表达式 r
- 对任何正则表达式 r,存在生成同一语言的 正则文法 G
二、正则定义(Regular Definition)
- 为了方便起见,我们可以给某些正则表达式命名,像使用字母表中的符号一样,使用这些名字来构造正则表达式。
- digit,表示0~9中的某个数字
- letter_,表示一个字母(小写字母或大写字母)和一个下划线。
- id,首先是一个 letter_,接下来连接一个 letter _ 或 digit 构成的字符串。这个表达式表示的是字母打头的字符数字串。(正是标识符的定义)
- digit,表示一个数字
- digits,digit 连接上一个 digit 的克林闭包,表示的是一个长度>=1 的数字串。
- optionalFraction,点号(.)后面连接一个 digits 或 这个表达式是一个空串。(这个符号表示的是一个小数部分,或一个空串)代表可选的小数部分。
- optionalExponent,大写字母 E 后面连接一个 + (正号)或 一个 -(负号)或直接连接一个长度大于等于1 的数字串(digits),或者这个表达式为空串。可选的指数部分。
- number,长度大于等于1 的数字串,连接一个可选的小数部分,连接一个可选的指数部分。
三、有穷自动机 ( Finite Automata,FA )
- 一类处理系统建立的数学模型
- 具有一系列离散的输入输出信息和有穷数目的内部状态(状态:概括了对过去输入信息处理的状况)
- 系统只需要根据当前所处的状态和当前面临的输入信息就可以决定系统的后继行为。每当系统处理了当前的输入后,系统的内部状态也将发生改变。
FA模型
- 输入带:用来存放输入符号串
- 读头:从左向右逐个读取输入符号,不能修改(只读),不能往返移动
- 有穷控制器:具有有穷个状态数,根据当前的状态和当前输入符号控制转入下一状态。
FA 的表示:转换图
- 结点:FA 的状态
初始状态(开始状态):只有一个,由 start 箭头指向
终止状态:可以由多个,用双圈表示 - 带标记的有向边:如果对于输入 a ,存在一个从状态 p 到状态 q 的转换,就在 p、q 之间画一条有向边,并标记上 a。
FA定义(接受)的语言
- 给定输入串 x,如果存在一个对应于 串 x 的从初始状态到某个终止状态的转换序列,则称 串 x 被该 FA 接受。
- 由一个有穷自动机 M 接受的所有串构成的集合称为是该 FA定义(或接收)的语言,记为 L(M)。
最长子串匹配原则
- 当输入串的多个前缀与一个或多个模式匹配时,我们总是选择最长的前缀进行匹配。
- 在到达某个终态之后,只要输入带上还有符号,就继续前进,以便找到尽可能长的匹配。
四、有穷自动机的分类
- 确定的有穷自动机(DFA)
- 不确定的有穷自动机(NFA)
确定的有穷自动机(DFA)
DFA 的算法实现
- 输入:以文件结束符 eof 结尾的字符串 x,DFA 的开始状态为 s0,接受状态集 F,转换函数 move
- 输出:如果 D 接受x,则回答“yes”,否则回答“no”
- 方法:将下述算法应用于输入串 x
不确定的有穷自动机(NFA)
NFA和DFA的唯一的区别是:从状态 s 出发,能到达的状态可能有多个。
转换函数为集合而不是元素。
带有ε边的NFA
- 在状态 a,不需要遇到任何符号,即可进入状态 b,在状态 b,不需要任何符号,即可进入状态 c。
- 一旦进入状态 b,就不再接受符号 0,同理,一旦进入状态 c,就不在接受符号 1。
带有ε边和不带有ε边的NFA的等价性
DFA 和 NFA 的等价性
- 对任何非确定的有穷自动机N,存在定义同一语言的确定的有穷自动机D。
- 对任何确定的有穷自动机D,存在定义同一语言的非确定的有穷自动机 N。
DFA 和 NFA 可以识别相同的语言
DFA 和NFA 都识别的是以 abb结尾的 a,b 串。
五、从正则表达式到有穷自动机。
根据 RE 构造 NFA
例子:r=(a|b)*abb 对应的 NFA
可以看出不停的分解子表达式,即可求得最终的 NFA。
六、从NFA 到DFA 的转换
从NFA 到DFA 的转换
从带有ε边的NFA到DFA的转换
子集构造法
计算ε-closure 空闭包函数
七、识别单词的 DFA
识别标识符的DFA
识别无符号数的DFA
识别各进制无符号整数的 DFA
识别注释的 DFA
识别 token 的 DFA
词法分析阶段的错误处理
词法分析阶段可检测错误的类型
- 单词拼写错误,例:int i=0x3G,float j=1.05e
- 非法字符,例:~@
词法错误检测
- 如果当前状态与当前输入符号在转换表对应项中的信息为空,而当前状态又不是终止状态,则调用错误处理程序。
错误处理
- 查找已扫描字符串中最后一个对应于某终态的字符
- 如果找到了,将该字符与其前面的字符识别成一个单词。然后将输入指针退回到该字符,扫描器重新回到初始状态,继续识别下一个单词
- 如果没找到,则确定出错,采用错误恢复策略。
错误恢复策略
- 最简单的错误恢复策略:“恐慌模式”恢复
- 从剩余的输入中不断删除字符,直到词法分析器能够在剩余输入的开头发现一个正确的字符为止。