码迷,mamicode.com
首页 > 其他好文 > 详细

实现一个 DFA 正则表达式引擎 - 2. NFA 的构建

时间:2015-05-17 10:41:38      阅读:203      评论:0      收藏:0      [点我收藏+]

标签:

语法树如何实现对于之后步骤的繁琐程度有着举足轻重的影响。因为我们已经有了一棵简单优雅的语法树,所以我们的 NFA 很容易就可以构建出来。下面来回顾一下我们拥有的节点种类:

分支节点:Concat, Or, Many

叶子节点:Closure, Char

以下是转换的核心代码:

    public void visit(LChar lChar) {
        NFAState i = stateStack.pop();
        NFAState f = stateStack.pop();
        i.transitionRule(lChar.c, f);
    }

    public void visit(LNull lNull) {
        // do nothing
    }

    public void visit(BOr bOr) {
        NFAState i = stateStack.pop();
        NFAState f = stateStack.pop();
        stateStack.push(f);
        stateStack.push(i);
        stateStack.push(f);
        stateStack.push(i);
    }

    public void visit(BConcat bConcat) {
        NFAState i = stateStack.pop();
        NFAState f = stateStack.pop();
        NFAState n = newState();
        stateStack.push(f);
        stateStack.push(n);
        stateStack.push(n);
        stateStack.push(i);
    }

    public void visit(BMany bMany) {
        NFAState i = stateStack.pop();
        NFAState f = stateStack.pop();
        NFAState n = newState();
        i.directRule(n);
        n.directRule(f);
        stateStack.push(n);
        stateStack.push(n);
    }

    public void visit(LClosure lClosure) {
        NFAState i = stateStack.pop();
        NFAState f = stateStack.pop();
        i.directRule(f);
    }

遍历顺序为整个语法树的深搜。

这里用了一个栈来存储搜索中非第一优先级的节点。以我们上节中的语法树为例:

                |---------------[O]-------------|               

        |-------[C]-----|               |-------[C]-----|       

    |---[M]             b               a           |---[M]     

    a                                               b         

 

我们先把整个 NFA 的第一要素初态 0 和终态 1 压入栈,这时栈中有元素:

[1] [0]

自上而下开始搜索,首先我们遇到了 Or 节点,根据 Or 的规则:

技术分享

 

于是我们先 pop 出栈顶的两个状态,再按顺序 push 两遍:

[1] [0] [1] [0]

继续深搜遇到根节点的左儿子 Concat,按照 Concat 的规则:

技术分享

创建两个新状态 2 和 3,并插入栈顶的两个状态中:

[1] [0] [1] [3] [2] [0]

遇到一个 Many,按照 Many 的规则:

技术分享

 

先弹出栈顶的两个状态,创建一个新状态 4, 用栈顶的状态 0 和状态 4 建立双向的 closure 连接 (状态 0 可以直接转换到状态 4,反之亦然),并把状态 4 push 两遍入栈。

[1] [0] [1] [3] [4] [4]

遇到一个字符 a,那么就弹出栈顶的两个状态,然后建立两个状态的字符连接 (就是先弹出的状态接受字符 a 转换为后弹出的状态):

[1] [0] [1] [3]

又遇到一个字符 b:

[1] [0]

至此,根节点的左子树已经遍历完了,而我们也介绍完了构建这个 NFA 所用到的所有规则。

下面直接给出遍历右子树时栈的状态:

Concat:

[1] [6] [5] [0]

a:

[1] [6]

Many:

[7] [7]

b:

Nil

因此,一棵结构正确的语法树经过这种 NFA 的构造后会留下一个空栈。

这样,我们就完成了 DFA 正则引擎的第二步: NFA 的构建。

实现一个 DFA 正则表达式引擎 - 2. NFA 的构建

标签:

原文地址:http://www.cnblogs.com/zbdzzg/p/4509171.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!