Skip to content

Instantly share code, notes, and snippets.

@light0x00
Last active February 28, 2020 07:43
Show Gist options
  • Select an option

  • Save light0x00/6f4f64b62d3a53e112ff8371a11e795c to your computer and use it in GitHub Desktop.

Select an option

Save light0x00/6f4f64b62d3a53e112ff8371a11e795c to your computer and use it in GitHub Desktop.

Revisions

  1. light0x00 revised this gist Feb 28, 2020. No changes.
  2. light0x00 revised this gist Feb 28, 2020. 2 changed files with 55 additions and 0 deletions.
    File renamed without changes.
    55 changes: 55 additions & 0 deletions test.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,55 @@
    let subset_construct = require('./subset_construct')
    require('mocha')
    require('should')

    /**
    * 模拟《编译原理》P98
    */
    describe('============Subset Construction Test============', function () {

    //字符集
    let charset = ['a', 'b'];
    //NFA转换表
    /*
    NFA
    a b
    0 {3,8} {5}
    1 {3} {5}
    2 {3} \
    3 {3,8} {5}
    4 \ {5}
    5 {3,8} {5}
    6 {3,8} {5}
    7 {8} \
    8 \ {9}
    9 \ {10}
    */
    let Ntran = {
    0: { '': [1, 2, 4, 7], a: [3, 8], b: [5] },
    1: { '': [2, 4], a: [3], b: [5] },
    2: { '': [], a: [3], b: [] },
    3: { '': [1, 2, 4, 6, 7], 'a': [3, 8], 'b': [5] },
    4: { '': [], 'a': [], 'b': [5] },
    5: { '': [1, 2, 4, 6, 7], 'a': [3, 8], 'b': [5] },
    6: { '': [1, 2, 4, 7], 'a': [3, 8], 'b': [5] },
    7: { '': [], 'a': [8], 'b': [] },
    8: { '': [], 'a': [], 'b': [9] },
    9: { '': [], 'a': [], 'b': [10] },
    10: { '': [], 'a': [], 'b': [] },
    }

    //预期的的DFA转换表
    let expected = require('./expected_dfa.json')

    describe(`
    charset: ${JSON.stringify(charset)}
    NFA: ${JSON.stringify(Ntran)}
    `, function () {
    it(`expected ${JSON.stringify(expected)}`, function () {
    let actual = subset_construct(charset, Ntran)
    should.deepEqual(actual.Dtran, expected.Dtran)
    should.deepEqual(actual.Dstates, expected.Dstates)

    })
    })
    })
  3. light0x00 created this gist Feb 28, 2020.
    67 changes: 67 additions & 0 deletions subset-construct.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,67 @@
    const _ = require("lodash");

    /**
    * 使用子集构造法,将NFA转为DFA. 基于《编译原理》P97的伪代码的实现.
    * @param charset NFA所接受的字符集
    * @param Ntran NFA转换表
    */
    module.exports = function subset_construct(charset, Ntran) {
    let cursor = 0; //区分Dstates中的状态集是否访问过. cursor之前的为已访问, cursor之后为未访问.

    let Dstates = [] //DFA的状态集
    let Dtran = {} //DFA的转换表
    Dstates.push(e_closure([0])) //起始状态0输入e可到达的状态集

    //遍历尚未标记的DFA状态 T
    while (cursor < Dstates.length) {
    let T = Dstates[cursor];
    cursor++;
    Dtran[T] = {}
    for (let c of charset) {
    let T_c = move(T, c) //状态T 在输入c时可达的非空状态集 T_c
    let T_e = e_closure(T_c) //状态集 T_c 可达的
    let U = combine(T_c, T_e)
    //判断状态集U 是否已经存在于Dstates 不存在则放入
    let exists = Dstates.find(states => states.length == U.length && _.difference(states, T).length == 0
    ) != null
    if (!exists) {
    Dstates.push(U)
    }
    /*
    放入DFA转换表,这表示T在分别输入(charset U ε)中的每一个字符时,可达的状态集,
    */
    Dtran[T][c] = U
    }
    }

    /**
    * 返回给定状态集T输入ε可达的状态集
    * @param {*} T 状态集T
    */
    function e_closure(T) {
    let result = []
    for (let s of T) {
    result = combine(result, Ntran[s][''])
    result = combine(result, e_closure(Ntran[s][''])) //递归寻找ε
    }
    return result
    }
    /**
    * 返回给定状态集T输入c可达的状态集
    * @param {*} T 状态集T
    */
    function move(T, input) {
    let result = []
    for (let s of T) {
    result = combine(result, Ntran[s][input])
    }
    return result
    }

    return { Dstates, Dtran }
    }

    /* 工具性方法 */
    function combine(arr1, arr2) {
    return _.sortBy(_.union(arr1, arr2))
    }