直接从正则表达式到DFA
直接从正则表达式到DFA
详解NULLABLE、FIRSTPOS、LASTPOS和FOLLOWPOS
的计算规则
引入
正在上编译原理的课程,为了对抗遗忘,写下这篇文章
加强自己的记忆,同时也希望能给大家带来帮助。
在编译原理中,要把正则表达式转化为DFA,其中有一
步就是要计算语法分析树上各结点的nullable、firstpos、
lastpos和followpos。如果不理解其中的原理去背计算规则,
这是一件非常痛苦的事情,本文的目的就是希望能说清楚两
个问题,为什么要计算,如何计算。
前置知识:
句子:给定文法G[Z],若有Z + >x,且x∈VT*;则称x
是文法G[Z] 的句子 。
or 结点:标号为并运算符|的内部结点。
cat 结点:标号为连接运算符·的内部结点。
star 结点:标号为星号运算符*的内部结点。
位置:每个终结符对应一个位置。如图1。
计算NULLABLE(N)
说完了前置知识,我们先说一下比较容易理解的
nullable(n),为什么要计算nullable(n)呢?那是因为我们要根
据结点n 的nullable(n)函数的取值而采取不同的方法去计算
firstpos和lastpost。说到这里可能有人要骂我了,“你这说了
等于没说嘛”。希望大家稍安勿躁,因为问题是环环相扣的,
我只是把解答放到后面了呵呵。
nullable(n)表示以n 为根结点推导出的句子集合是否包
括 空 串,当推 导 出的句子集合包含 空 串,那 么
nullable(n) true;如果不包含空串,那么nullable(n) false。
现在我们针对结点n 的五种情况进行分析:
1、当结点n 是叶子结点并且取值为空,此时以n 为根
结点推导出的句子肯定为空,所以此时nullable(n)为true。如
图2 所示。
2、当结点n 是叶子结点并且取值为id,此时以n 推导
出的句子有非空值id,所以此时nullable(n)为false。
3、当结点n 是or 结点,此时n 结点肯定为内部结点。
由于是或运算,当结点n 的左子树(c1)或者右子树(c2)能推导
出 空 串 时 , 结 点 n 也 能 推 导 出 空 串 。 即
nullable(n) nullable(c1) ornullable(c2)。以下三种情况都会使
nullable(n) true。(c1->ε表示c1能推导出空串ε,下同)
4、当结点n 是cat 结点,此时n 结点肯定为内部结点。
由于是连接运算,当结点n 的左子树 (c1)和右子树 (c2)
能同时推导出空串,则结点 n 能推导出空串,即
nullable(n) nullable(c1) and nullable(c2) 。以下一种情况
nullable(n) true。
5、当结点n 是star 结点,此时n 结点肯定为内部结点,
由Kleene闭包运算的定义可知结点n推导出的句子集合
包括空串,因此nullable(n) true。
计算FIRSTPOS(N)
说完了nullable 的计算规则,我们来说下firstpos(n)。为
什么要算firstpos?那是因为我们在为计算followpos 做准
备:)不要郁闷,继续往下看,你一定会知道终极的原因!
firstpos(n)函数定义了以结点n 为根的子树中的位置集合。这
些位置对应于以结点n 为根推导出的某个句子的第一个符号
(“某个”代表可能有多个,因此firstpos 的计算结果是位置的
集合)。我们还是按照nullable 的分析方法,以五种结点类
型说明firstpos(n)的计算规则。
1、当结点n 为叶子结点并且为空串,因为是空串,所
以此时没有第一个符号,即firstpos(n) {Ø}。
2、当结点n 为位置i 的叶子结点。此时结点n 只能推导
出位置i 的终结符,因此firstpos(n) {i}
3、当结点n 为or 结点(内部结点),此时进行or 运算,
左子树(c1)推导出的第一个位置的集合firstpos(c1)包含于
firstpos(n),同样右子树(c1)推导出的第一个位置的集合
firstpos(c2)包含于firstpos(n)。因此firstpos(n)等于左右子树
firstpos 的并集。即firstpos(n) fi