之前学习编译原理的时候老师有讲过子集构造法,当时我以为自己听懂了,信心满满。可是这两天我做了一些题目,发现自己实际上还是太嫩了,学习浮于表面。之后又重新看了龙书和虎书,对子集构造法有了更深层次的了解。特此发出一篇文章分享我的经验。
1 概念
概念是我们学习编译原理的重中之重,虽然他很晦涩难懂,但我有必要将其放在最开始。
1.1 虎书概念
虎书的概念更偏向于理论化,我当时看的时候一头雾水,但是不要担心,之后会一点一点解释的。
首先,我们形式化定义 ϵ \epsilon ϵ闭包如下:
- e d g e ( s , c ) edge(s,c) edge(s,c):状态 s s s沿着标有 c c c的边可到达的所有NFA状态的集合;
- c l o s u r e ( S ) closure(S) closure(S): 对于状态集合 S S S,从 S S S出发,只通过 ϵ \epsilon ϵ边可以达到的状态集合;
- 这种经过 ϵ \epsilon ϵ边的概念可以用数学方法表述,即 c l o s u r e ( S ) closure(S) closure(S)是满足如下条件的最小集合 T T T:
T = S ∪ ( ⋃ s ∈ T e d g e ( s , ϵ ) ) T=S \cup \left( \bigcup_{s \in T}edge(s,\epsilon) \right) T=S∪(⋃s∈Tedge(s,ϵ)) - 我们可以用迭代法来算出 T T T:
T ← S r e p e a t T ′ ← T T ← T ′ ∪ ( ⋃ s ∈ T ′ e d g e ( s , ϵ ) ) u n t i l T = T ′ T \leftarrow S \\ repeat \ T' \leftarrow T \\ \qquad \quad T \leftarrow T' \cup \left( \bigcup_{s \in T'}edge(s,\epsilon) \right) \\ until \ T=T' T←Srepeat T′←TT←T′∪(⋃s∈T′edge(s,ϵ))until T=T′
- 这种经过 ϵ \epsilon ϵ边的概念可以用数学方法表述,即 c l o s u r e ( S ) closure(S) closure(S)是满足如下条件的最小集合 T T T:
解释一下:当我们位于一个状态集合 S S S, S S S里任意状态经过若干 ϵ \epsilon ϵ能够到达的状态,都将包含在 c l o s u r e ( S ) closure(S) closure(S) 里。
- 龙书里将这个操作定义为 ϵ − c l o s u r e ( T ) \epsilon-closure(T) ϵ−closure(T)( T T T为状态集合)。
现在,假设我们位于由NFA状态 s i , s k , s l s_i,s_k,s_l si,sk,sl组成的集合 d = { s i , s k , s l } d= \lbrace s_i,s_k,s_l \rbrace d={ si,sk,sl}中。从 d d d中的状态出发,输入符号 c c c,将到达NFA新的状态集;我们称这个状态集为 D F A e d g e ( d , c ) DFAedge(d,c) DFAedge(d,c):
- D F A e d g e ( d , c ) = c l o s u r e ( ⋃ s ∈ d e d g e ( s , c ) ) DFAedge(d,c)=closure \left( \bigcup_{s \in d}edge(s,c) \right) DFAedge(d,c)=closure(⋃s∈dedge(s,c))
解释一下:将遍历集合 d d d中的所有状态,得到 d d d 关于 T = e d g e ( s , c ) T=edge(s,c) T=edge(s,c)的状态集,并对 T T T 求 c l o s u r e ( T ) closure(T) closure(T),得到的即为 D F A e d g e ( d , c ) DFAedge(d,c) DFAedge(d,c)。简而言之,就是从一个状态集,经过一个输入到达的状态集为 T ′ = D F A e d g e ( d , c ) T'=DFAedge(d,c) T′=DFAedge(d,c)。
利用 D F A