static FA _Determinize(FA fa, IProgress <FAProgress> progress = null)
        {
            if (null != progress)
            {
                progress.Report(new FAProgress(FAStatus.DfaTransform, 0));
            }
            var p       = new HashSet <int>();
            var closure = new List <FA>();

            fa.FillClosure(closure);
            for (int ic = closure.Count, i = 0; i < ic; ++i)
            {
                var ffa = closure[i];
                p.Add(0);
                foreach (var t in ffa.InputTransitions)
                {
                    p.Add(t.Key.Key);
                    if (t.Key.Value < 0x10ffff)
                    {
                        p.Add((t.Key.Value + 1));
                    }
                }
            }

            var points = new int[p.Count];

            p.CopyTo(points, 0);
            Array.Sort(points);

            var comparer = _SetComparer.Default;

            var sets    = new Dictionary <HashSet <FA>, HashSet <FA> >(comparer);
            var working = new Queue <HashSet <FA> >();
            var dfaMap  = new Dictionary <HashSet <FA>, FA>(comparer);
            var initial = new HashSet <FA>();

            fa.FillEpsilonClosure(initial);
            sets.Add(initial, initial);
            working.Enqueue(initial);
            var result = new FA();

            foreach (var afa in initial)
            {
                if (afa.IsAccepting)
                {
                    result.IsAccepting  = true;
                    result.AcceptSymbol = afa.AcceptSymbol;
                    break;
                }
            }
            dfaMap.Add(initial, result);
            var j = 1;

            while (working.Count > 0)
            {
                var s   = working.Dequeue();
                var ecs = FillEpsilonClosure(s);
                FA  dfa;
                dfaMap.TryGetValue(s, out dfa);
                foreach (FA q in ecs)
                {
                    if (q.IsAccepting)
                    {
                        dfa.IsAccepting  = true;
                        dfa.AcceptSymbol = q.AcceptSymbol;
                        break;
                    }
                }

                for (var i = 0; i < points.Length; i++)
                {
                    var set = new HashSet <FA>();
                    foreach (FA c in ecs)
                    {
                        foreach (var trns in c.InputTransitions)
                        {
                            if (trns.Key.Key <= points[i] && points[i] <= trns.Key.Value)
                            {
                                foreach (var efa in trns.Value.FillEpsilonClosure())
                                {
                                    set.Add(efa);
                                }
                            }
                        }
                    }
                    if (!sets.ContainsKey(set))
                    {
                        sets.Add(set, set);
                        working.Enqueue(set);
                        dfaMap.Add(set, new FA());
                    }

                    FA dst;
                    dfaMap.TryGetValue(set, out dst);
                    int first = points[i];
                    int last;
                    if (i + 1 < points.Length)
                    {
                        last = (points[i + 1] - 1);
                    }
                    else
                    {
                        last = 0x10ffff;
                    }
                    dfa.InputTransitions.Add(new KeyValuePair <int, int>(first, last), dst);
                }
                if (null != progress)
                {
                    progress.Report(new FAProgress(FAStatus.DfaTransform, j));
                }

                ++j;
            }
            // remove dead transitions
            foreach (var ffa in result.FillClosure())
            {
                var itrns = new List <KeyValuePair <KeyValuePair <int, int>, FA> >(ffa.InputTransitions);
                foreach (var trns in itrns)
                {
                    if (null == trns.Value.FirstAcceptingState)
                    {
                        ffa.InputTransitions.Remove(trns.Key);
                    }
                }
                if (null != progress)
                {
                    progress.Report(new FAProgress(FAStatus.DfaTransform, j));
                }
                ++j;
            }
            return(result);
        }
Beispiel #2
0
        /// <summary>
        /// Returns a DFA table that can be used to lex or match
        /// </summary>
        /// <param name="symbolTable">The symbol table to use, or null to just implicitly tag symbols with integer ids</param>
        /// <returns>A DFA table that can be used to efficiently match or lex input</returns>
        public DfaEntry[] ToDfaStateTable(IList <int> symbolTable = null, IProgress <FAProgress> progress = null)
        {
            // only convert to a DFA if we haven't already
            // ToDfa() already checks but it always copies
            // the state information so this performs better
            FA dfa = null;

            if (!IsDfa)
            {
                dfa = ToDfa(progress);
                dfa.TrimDuplicates(progress);
            }
            else
            {
                dfa = this;
            }
            var closure = new List <FA>();

            dfa.FillClosure(closure);
            var symbolLookup = new Dictionary <int, int>();

            // if we don't have a symbol table, build
            // the symbol lookup from the states.
            if (null == symbolTable)
            {
                // go through each state, looking for accept symbols
                // and then add them to the new symbol table is we
                // haven't already
                var i = 0;
                for (int jc = closure.Count, j = 0; j < jc; ++j)
                {
                    var fa = closure[j];
                    if (fa.IsAccepting && !symbolLookup.ContainsKey(fa.AcceptSymbol))
                    {
                        if (0 > fa.AcceptSymbol)
                        {
                            throw new InvalidOperationException("An accept symbol was never specified for state q" + jc.ToString());
                        }
                        symbolLookup.Add(fa.AcceptSymbol, i);
                        ++i;
                    }
                }
            }
            else             // build the symbol lookup from the symbol table
            {
                for (int ic = symbolTable.Count, i = 0; i < ic; ++i)
                {
                    symbolLookup.Add(symbolTable[i], i);
                }
            }

            // build the root array
            var result = new DfaEntry[closure.Count];

            for (var i = 0; i < result.Length; i++)
            {
                var fa = closure[i];
#if DEBUG
                if (fa.IsAccepting)
                {
                    System.Diagnostics.Debug.Assert(-1 < fa.AcceptSymbol, "Illegal accept symbol " + fa.AcceptSymbol.ToString() + " was found on state state q" + i.ToString());
                }
#endif
                // get all the transition ranges for each destination state
                var trgs = fa.FillInputTransitionRangesGroupedByState();
                // make a new transition entry array for our DFA state table
                var trns = new DfaTransitionEntry[trgs.Count];
                var j    = 0;
                // for each transition range
                foreach (var trg in trgs)
                {
                    // add the transition entry using
                    // the packed ranges from CharRange
                    trns[j] = new DfaTransitionEntry(
                        trg.Value,
                        closure.IndexOf(trg.Key));

                    ++j;
                }

                // now add the state entry for the state above
#if DEBUG
                if (fa.IsAccepting && !symbolLookup.ContainsKey(fa.AcceptSymbol))
                {
                    try
                    {
                        dfa.RenderToFile(@"dfastatetable_crashdump_dfa.jpg");
                    }
                    catch
                    {
                    }
                    System.Diagnostics.Debug.Assert(false, "The symbol table did not contain an entry for state q" + i.ToString());
                }
#endif
                result[i] = new DfaEntry(
                    fa.IsAccepting ? symbolLookup[fa.AcceptSymbol] : -1,
                    trns);
            }
            return(result);
        }