这种语言并不重要,但我需要弄清楚如何将正则表达式转换为NFA表。
例如"(ab)* + ba"变成了
T | a | b | ^
0 | N | 1 | 2
1 | 3 | N | ñ
2 | 4 | N | 3
3 | N | N | ñ
4 | N | 2 | Ñ
如果有人能帮助我指出正确的方向,或者告诉我如何做到这一点,我将不胜感激。
编辑:我看了一眼:http://www.cs.may.ie/staff/jpower/Courses/Previous/parsing/node5.html,但我仍然无法了解如何编程
答案 0 :(得分:1)
首先,找到最外面的操作。在您的示例中,它是+
。当你有一个+
时,就意味着你可以接受左边的东西或者右边的东西。我们可以使用空(lambda或epsilon)转换在NFA中对此进行编码,如下所示:
Q s Q'
q0 - M1
q0 - M2
我们以q0
为起点,我们使用M1
和M2
来表示接受分别由LHS和RHS生成的正则表达式字符串的机器。当我们说q0
在lambda / epsilon上转换为M1
和M2
- 空转换时 - 我们的意思是我们不确定地选择哪条路径下降。转换将从q0
转换为初始状态M1
和M2
,无论这些状态如何。
现在我们在每个LHS和RHS上递归重复该过程。我们可以从RHS开始,因为它更简单。这里最外面的操作是连接(符号a
和b
)。连接很容易表示:
Q s Q'
q2 - M3
M3 - M4
此处,q2
是之前M2
的初始状态,而M3
和M4
代表尚未确定的接受LHS和RHS的机器,分别为a
和b
的串联。当我们说q2
转换为M3
时,我们的意思是它转换为M3
的初始状态;当我们说M3
转换为M4
时,我们指的是M3
所有接受状态都转换为M4
的初始状态。
递归地进行,我们现在需要a
和b
的机器。这两种都有以下形式:
Q s Q'
q x q'
q
是初始状态,x
是符号,q'
是接受状态。所以我们得到:
Q s Q'
q3 b q4 (q3 initial, q4 accepting)
和
Q s Q'
q5 a q6 (q5 initial, q6 accepting)
我们已经触及了这个递归分支的底部,可以退后一步,根据我们定义的具体机器在转换表中生成具体条目。我们有这个:
Q s Q'
q2 - M3
M3 - M4
现在我们知道M3
和M4
的样子,所以我们可以替代:
Q s Q'
q2 - q3
q3 b q4
q4 - q5
q5 a q6 (q2 initial, q6 accepting)
现在我们已准备好从+
操作执行LHS。最外面的操作是*
。我们在NFA中处理这些问题的方式如下:
Q s Q'
q7 - M5
M5 - M5
我们现在考虑下一个操作,连接。我们已经涵盖了这一点,我们知道我们得到了这个:
Q s Q'
q8 - M6
M6 - M7
现在我们需要a
和b
。同样,我们知道这些看起来像:
Q s Q'
q9 a q10
和
Q s Q'
q11 b q12
我们把它们全部重新组合在一起:
Q s Q'
q8 - q9
q9 a q10
q10 - q11
q11 b q12 (q8 initial, q12 accepting)
然后我们做了Kleene明星:
Q s Q'
q7 - q8
q8 - q9
q9 a q10
q10 - q11
q11 b q12
q12 - q8 (q8 initial, q8 and q12 accepting)
最后,我们将所有规则合并到一个大转换表中:
Q s Q'
q0 - q2
q0 - q7
q2 - q3
q3 b q4
q4 - q5
q5 a q6
q7 - q8
q8 - q9
q9 a q10
q10 - q11
q11 b q12
q12 - q8 (q0 initial, q6, q8 and q12 accepting)
因此,您可以为任何正则表达式递归构造NFA。在一般情况下,生成的NFA将具有一些不必要的状态,但NFA优化是一个微妙的主题。您始终可以使用此(或任何)NFA,使用已知算法转换为DFA,然后使用已知算法最小化。然后你有一个可证明最小的DFA,虽然它可能比这个填充的NFA大得多!