示例#1
0
        /// <summary>
        /// Fills a collection with the result of moving each of the specified <paramref name="states"/> on the specified input.
        /// </summary>
        /// <param name="states">The states to examine</param>
        /// <param name="input">The input to use</param>
        /// <param name="result">The states that are now entered as a result of the move</param>
        /// <returns><paramref name="result"/> or a new collection if it wasn't specified.</returns>
        public static ICollection <FA> FillMove(IEnumerable <FA> states, int input, ICollection <FA> result = null)
        {
            var inputs = new KeyValuePair <int, int>(input, input);

            if (null == result)
            {
                result = new List <FA>();
            }
            foreach (var fa in states)
            {
                // examine each of the states reachable from this state on no input
                foreach (var efa in fa.FillEpsilonClosure())
                {
                    // see if this state has this input in its transitions
                    foreach (var trns in efa.InputTransitions)
                    {
                        if (RangeUtility.Intersects(trns.Key, inputs))
                        {
                            if (!result.Contains(trns.Value))
                            {
                                foreach (var ofa in trns.Value.FillEpsilonClosure())
                                {
                                    if (!result.Contains(ofa))                                     // if it does, add it if it's not already there
                                    {
                                        result.Add(ofa);
                                    }
                                }
                            }
                        }
                    }
                }
            }
            return(result);
        }
示例#2
0
        public IDictionary <FA, int[]> FillInputTransitionRangesGroupedByState(IDictionary <FA, int[]> result = null)
        {
            var working = new Dictionary <FA, List <KeyValuePair <int, int> > >();

            foreach (var trns in InputTransitions)
            {
                List <KeyValuePair <int, int> > l;
                if (!working.TryGetValue(trns.Value, out l))
                {
                    l = new List <KeyValuePair <int, int> >();
                    working.Add(trns.Value, l);
                }
                l.Add(trns.Key);
            }
            if (null == result)
            {
                result = new Dictionary <FA, int[]>();
            }
            foreach (var item in working)
            {
                item.Value.Sort((x, y) => { var c = x.Key.CompareTo(y.Key); if (0 != c)
                                            {
                                                return(c);
                                            }
                                            return(x.Value.CompareTo(y.Value)); });
                RangeUtility.NormalizeSortedRangeList(item.Value);
                result.Add(item.Key, RangeUtility.FromPairs(item.Value));
            }
            return(result);
        }
示例#3
0
 public void AddInputTransition(KeyValuePair <int, int> range, FA dst)
 {
     foreach (var trns in InputTransitions)
     {
         if (RangeUtility.Intersects(trns.Key, range))
         {
             throw new ArgumentException("There already is a transition to a different state on at least part of the specified input range");
         }
     }
     InputTransitions.Add(range, dst);
 }
示例#4
0
        public static FA Set(int[] ranges, int accept = -1)
        {
            var result = new FA();
            var final  = new FA(true, accept);
            var pairs  = new List <KeyValuePair <int, int> >(RangeUtility.ToPairs(ranges));

            pairs.Sort((x, y) => { return(x.Key.CompareTo(y.Key)); });
            RangeUtility.NormalizeSortedRangeList(pairs);
            foreach (var pair in pairs)
            {
                result.AddInputTransition(pair, final);
            }
            return(result);
        }
示例#5
0
        internal static FA Parse(LexContext pc, int accept = -1)
        {
            FA  result = null, next = null;
            int ich;

            pc.EnsureStarted();
            while (true)
            {
                switch (pc.Current)
                {
                case -1:
#if MINIMIZE
                    result = result.ToDfa();
                    result.TrimDuplicates();
#endif
                    return(result);

                case '.':
                    var dot = FA.Set(new int[] { 0, 0x10ffff }, accept);
                    if (null == result)
                    {
                        result = dot;
                    }
                    else
                    {
                        result = FA.Concat(new FA[] { result, dot }, accept);
                    }
                    pc.Advance();
                    result = _ParseModifier(result, pc, accept);
                    break;

                case '\\':

                    pc.Advance();
                    pc.Expecting();
                    var isNot = false;
                    switch (pc.Current)
                    {
                    case 'P':
                        isNot = true;
                        goto case 'p';

                    case 'p':
                        pc.Advance();
                        pc.Expecting('{');
                        var  uc  = new StringBuilder();
                        int  uli = pc.Line;
                        int  uco = pc.Column;
                        long upo = pc.Position;
                        while (-1 != pc.Advance() && '}' != pc.Current)
                        {
                            uc.Append((char)pc.Current);
                        }
                        pc.Expecting('}');
                        pc.Advance();
                        int uci = 0;
                        switch (uc.ToString())
                        {
                        case "Pe":
                            uci = 21;
                            break;

                        case "Pc":
                            uci = 19;
                            break;

                        case "Cc":
                            uci = 14;
                            break;

                        case "Sc":
                            uci = 26;
                            break;

                        case "Pd":
                            uci = 19;
                            break;

                        case "Nd":
                            uci = 8;
                            break;

                        case "Me":
                            uci = 7;
                            break;

                        case "Pf":
                            uci = 23;
                            break;

                        case "Cf":
                            uci = 15;
                            break;

                        case "Pi":
                            uci = 22;
                            break;

                        case "Nl":
                            uci = 9;
                            break;

                        case "Zl":
                            uci = 12;
                            break;

                        case "Ll":
                            uci = 1;
                            break;

                        case "Sm":
                            uci = 25;
                            break;

                        case "Lm":
                            uci = 3;
                            break;

                        case "Sk":
                            uci = 27;
                            break;

                        case "Mn":
                            uci = 5;
                            break;

                        case "Ps":
                            uci = 20;
                            break;

                        case "Lo":
                            uci = 4;
                            break;

                        case "Cn":
                            uci = 29;
                            break;

                        case "No":
                            uci = 10;
                            break;

                        case "Po":
                            uci = 24;
                            break;

                        case "So":
                            uci = 28;
                            break;

                        case "Zp":
                            uci = 13;
                            break;

                        case "Co":
                            uci = 17;
                            break;

                        case "Zs":
                            uci = 11;
                            break;

                        case "Mc":
                            uci = 6;
                            break;

                        case "Cs":
                            uci = 16;
                            break;

                        case "Lt":
                            uci = 2;
                            break;

                        case "Lu":
                            uci = 0;
                            break;
                        }
                        if (isNot)
                        {
                            next = FA.Set(CharacterClasses.UnicodeCategories[uci], accept);
                        }
                        else
                        {
                            next = FA.Set(CharacterClasses.NotUnicodeCategories[uci], accept);
                        }
                        break;

                    case 'd':
                        next = FA.Set(CharacterClasses.digit, accept);
                        pc.Advance();
                        break;

                    case 'D':
                        next = FA.Set(RangeUtility.NotRanges(CharacterClasses.digit), accept);
                        pc.Advance();
                        break;

                    case 's':
                        next = FA.Set(CharacterClasses.space, accept);
                        pc.Advance();
                        break;

                    case 'S':
                        next = FA.Set(RangeUtility.NotRanges(CharacterClasses.space), accept);
                        pc.Advance();
                        break;

                    case 'w':
                        next = FA.Set(CharacterClasses.word, accept);
                        pc.Advance();
                        break;

                    case 'W':
                        next = FA.Set(RangeUtility.NotRanges(CharacterClasses.word), accept);
                        pc.Advance();
                        break;

                    default:
                        if (-1 != (ich = _ParseEscapePart(pc)))
                        {
                            next = FA.Literal(new int[] { ich }, accept);
                        }
                        else
                        {
                            pc.Expecting();                                          // throw an error
                            return(null);                                            // doesn't execute
                        }
                        break;
                    }
                    next = _ParseModifier(next, pc, accept);
                    if (null != result)
                    {
                        result = FA.Concat(new FA[] { result, next }, accept);
                    }
                    else
                    {
                        result = next;
                    }
                    break;

                case ')':
#if MINIMIZE
                    result = result.ToDfa();
                    result.TrimDuplicates();
#endif
                    return(result);

                case '(':
                    pc.Advance();
                    pc.Expecting();
                    next = Parse(pc, accept);
                    pc.Expecting(')');
                    pc.Advance();
                    next = _ParseModifier(next, pc, accept);
                    if (null == result)
                    {
                        result = next;
                    }
                    else
                    {
                        result = FA.Concat(new FA[] { result, next }, accept);
                    }
                    break;

                case '|':
                    if (-1 != pc.Advance())
                    {
                        next   = Parse(pc, accept);
                        result = FA.Or(new FA[] { result, next }, accept);
                    }
                    else
                    {
                        result = FA.Optional(result, accept);
                    }
                    break;

                case '[':
                    var seti = _ParseSet(pc);
                    var set  = seti.Value;
                    if (seti.Key)
                    {
                        set = RangeUtility.NotRanges(set);
                    }
                    next = FA.Set(set, accept);
                    next = _ParseModifier(next, pc, accept);

                    if (null == result)
                    {
                        result = next;
                    }
                    else
                    {
                        result = FA.Concat(new FA[] { result, next }, accept);
                    }
                    break;

                default:
                    ich = pc.Current;
                    if (char.IsHighSurrogate((char)ich))
                    {
                        if (-1 == pc.Advance())
                        {
                            throw new ExpectingException("Expecting low surrogate in Unicode stream", pc.Line, pc.Column, pc.Position, pc.FileOrUrl, "low-surrogate");
                        }
                        ich = char.ConvertToUtf32((char)ich, (char)pc.Current);
                    }
                    next = FA.Literal(new int[] { ich }, accept);
                    pc.Advance();
                    next = _ParseModifier(next, pc, accept);
                    if (null == result)
                    {
                        result = next;
                    }
                    else
                    {
                        result = FA.Concat(new FA[] { result, next }, accept);
                    }
                    break;
                }
            }
        }
示例#6
0
        /// <summary>
        /// Writes a Graphviz dot specification of the specified closure to the specified <see cref="TextWriter"/>
        /// </summary>
        /// <param name="closure">The closure of all states</param>
        /// <param name="writer">The writer</param>
        /// <param name="options">A <see cref="DotGraphOptions"/> instance with any options, or null to use the defaults</param>
        static void _WriteDotTo(IList <FA> closure, TextWriter writer, DotGraphOptions options = null)
        {
            if (null == options)
            {
                options = new DotGraphOptions();
            }
            string spfx = null == options.StatePrefix ? "q" : options.StatePrefix;

            writer.WriteLine("digraph FA {");
            writer.WriteLine("rankdir=LR");
            writer.WriteLine("node [shape=circle]");
            var finals    = new List <FA>();
            var neutrals  = new List <FA>();
            var accepting = closure[0].FillAcceptingStates();

            foreach (var ffa in closure)
            {
                if (ffa.IsFinal && !ffa.IsAccepting)
                {
                    finals.Add(ffa);
                }
            }


            int i = 0;

            foreach (var ffa in closure)
            {
                if (!finals.Contains(ffa))
                {
                    if (ffa.IsAccepting)
                    {
                        accepting.Add(ffa);
                    }
                    else if (ffa.IsNeutral)
                    {
                        neutrals.Add(ffa);
                    }
                }
                var rngGrps = ffa.FillInputTransitionRangesGroupedByState();
                foreach (var rngGrp in rngGrps)
                {
                    var di = closure.IndexOf(rngGrp.Key);
                    writer.Write(spfx);
                    writer.Write(i);
                    writer.Write("->");
                    writer.Write(spfx);
                    writer.Write(di.ToString());
                    writer.Write(" [label=\"");
                    var sb    = new StringBuilder();
                    var rngs  = rngGrp.Value;
                    var nrngs = RangeUtility.NotRanges(rngs);
                    var isNot = false;
                    if (nrngs.Length < rngs.Length || (nrngs.Length == rngs.Length && 0x10ffff == rngs[rngs.Length - 1]))
                    {
                        isNot = true;
                        if (0 != nrngs.Length)
                        {
                            sb.Append("^");
                        }
                        else
                        {
                            sb.Append(".");
                        }
                        rngs = nrngs;
                    }
                    for (var r = 0; r < rngs.Length; r += 2)
                    {
                        _AppendRangeTo(sb, rngs, r);
                    }
                    if (isNot || sb.Length != 1 || (char.IsWhiteSpace(sb.ToString(), 0)))
                    {
                        writer.Write('[');
                        writer.Write(_EscapeLabel(sb.ToString()));
                        writer.Write(']');
                    }
                    else
                    {
                        writer.Write(_EscapeLabel(sb.ToString()));
                    }
                    writer.WriteLine("\"]");
                }
                // do epsilons
                foreach (var fffa in ffa.EpsilonTransitions)
                {
                    writer.Write(spfx);
                    writer.Write(i);
                    writer.Write("->");
                    writer.Write(spfx);
                    writer.Write(closure.IndexOf(fffa));
                    writer.WriteLine(" [style=dashed,color=gray]");
                }
                ++i;
            }
            string delim = "";

            i = 0;
            foreach (var ffa in closure)
            {
                writer.Write(spfx);
                writer.Write(i);
                writer.Write(" [");

                writer.Write("label=<");
                writer.Write("<TABLE BORDER=\"0\"><TR><TD>");
                writer.Write(spfx);
                writer.Write("<SUB>");
                writer.Write(i);
                writer.Write("</SUB></TD></TR>");


                if (ffa.IsAccepting)
                {
                    writer.Write("<TR><TD>");
                    writer.Write(Convert.ToString(ffa.AcceptSymbol).Replace("\"", "&quot;"));
                    writer.Write("</TD></TR>");
                }
                writer.Write("</TABLE>");
                writer.Write(">");
                bool isfinal = false;
                if (accepting.Contains(ffa) || (isfinal = finals.Contains(ffa)))
                {
                    writer.Write(",shape=doublecircle");
                }
                if (isfinal || neutrals.Contains(ffa))
                {
                    writer.Write(",color=gray");
                }
                writer.WriteLine("]");
                ++i;
            }
            delim = "";
            if (0 < accepting.Count)
            {
                foreach (var ntfa in accepting)
                {
                    writer.Write(delim);
                    writer.Write(spfx);
                    writer.Write(closure.IndexOf(ntfa));
                    delim = ",";
                }
                writer.WriteLine(" [shape=doublecircle]");
            }
            delim = "";
            if (0 < neutrals.Count)
            {
                foreach (var ntfa in neutrals)
                {
                    writer.Write(delim);
                    writer.Write(spfx);
                    writer.Write(closure.IndexOf(ntfa));
                    delim = ",";
                }
                writer.WriteLine(" [color=gray]");
                delim = "";
            }
            delim = "";
            if (0 < finals.Count)
            {
                foreach (var ntfa in finals)
                {
                    writer.Write(delim);
                    writer.Write(spfx);
                    writer.Write(closure.IndexOf(ntfa));
                    delim = ",";
                }
                writer.WriteLine(" [shape=doublecircle,color=gray]");
            }

            writer.WriteLine("}");
        }