/// <summary>
        /// Writes a Graphviz dot specification to the specified <see cref="TextWriter"/>
        /// </summary>
        /// <param name="writer">The writer</param>
        /// <param name="options">A <see cref="DotGraphOptions"/> instance with any options, or null to use the defaults</param>
        public void WriteDotTo(TextWriter writer, DotGraphOptions options = null)
        {
            var closure = new List <FA>();

            FillClosure(closure);
            _WriteDotTo(closure, writer, options);
        }
        /// <summary>
        /// Renders Graphviz output for this machine to the specified file
        /// </summary>
        /// <param name="filename">The output filename. The format to render is indicated by the file extension.</param>
        /// <param name="options">A <see cref="DotGraphOptions"/> instance with any options, or null to use the defaults</param>
        public void RenderToFile(string filename, DotGraphOptions options = null)
        {
            if (null == options)
            {
                options = new DotGraphOptions();
            }
            string args = "-T";
            string ext  = Path.GetExtension(filename);

            if (0 == string.Compare(".png", ext, StringComparison.InvariantCultureIgnoreCase))
            {
                args += "png";
            }
            else if (0 == string.Compare(".jpg", ext, StringComparison.InvariantCultureIgnoreCase))
            {
                args += "jpg";
            }
            else if (0 == string.Compare(".bmp", ext, StringComparison.InvariantCultureIgnoreCase))
            {
                args += "bmp";
            }
            else if (0 == string.Compare(".svg", ext, StringComparison.InvariantCultureIgnoreCase))
            {
                args += "svg";
            }
            if (0 < options.Dpi)
            {
                args += " -Gdpi=" + options.Dpi.ToString();
            }

            args += " -o\"" + filename + "\"";

            var psi = new ProcessStartInfo("dot", args)
            {
                CreateNoWindow        = true,
                UseShellExecute       = false,
                RedirectStandardInput = true
            };

            using (var proc = Process.Start(psi))
            {
                WriteDotTo(proc.StandardInput, options);
                proc.StandardInput.Close();
                proc.WaitForExit();
            }
        }
        /// <summary>
        /// Renders Graphviz output for this machine to a stream
        /// </summary>
        /// <param name="format">The output format. The format to render can be any supported dot output format. See dot command line documation for details.</param>
        /// <param name="copy">True to copy the stream, otherwise false</param>
        /// <param name="options">A <see cref="DotGraphOptions"/> instance with any options, or null to use the defaults</param>
        /// <returns>A stream containing the output. The caller is expected to close the stream when finished.</returns>
        public Stream RenderToStream(string format, bool copy = false, DotGraphOptions options = null)
        {
            if (null == options)
            {
                options = new DotGraphOptions();
            }
            string args = "-T";

            args += string.Concat(" ", format);
            if (0 < options.Dpi)
            {
                args += " -Gdpi=" + options.Dpi.ToString();
            }

            var psi = new ProcessStartInfo("dot", args)
            {
                CreateNoWindow         = true,
                UseShellExecute        = false,
                RedirectStandardInput  = true,
                RedirectStandardOutput = true
            };

            using (var proc = Process.Start(psi))
            {
                WriteDotTo(proc.StandardInput, options);
                proc.StandardInput.Close();
                if (!copy)
                {
                    return(proc.StandardOutput.BaseStream);
                }
                else
                {
                    var stm = new MemoryStream();
                    proc.StandardOutput.BaseStream.CopyTo(stm);
                    proc.StandardOutput.BaseStream.Close();
                    proc.WaitForExit();
                    return(stm);
                }
            }
        }
        /// <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 <FFA> closure, TextWriter writer, DotGraphOptions options = null)
        {
            if (null == options)
            {
                options = new DotGraphOptions();
            }
            string spfx = null == options.StatePrefix ? "q" : options.StatePrefix;

            writer.WriteLine("digraph FFA {");
            writer.WriteLine("rankdir=LR");
            writer.WriteLine("node [shape=circle]");
            var finals = new List <FFA>();

            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);
                    }
                }
                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();
                    IList <KeyValuePair <int, int> > rngs = _ToPairs(rngGrp.Value);
                    var nrngs = new List <KeyValuePair <int, int> >(_NotRanges(rngs));
                    var isNot = false;
                    if (nrngs.Count < rngs.Count || (nrngs.Count == rngs.Count && 0x10ffff == rngs[rngs.Count - 1].Value))
                    {
                        isNot = true;
                        if (0 != nrngs.Count)
                        {
                            sb.Append("^");
                        }
                        else
                        {
                            sb.Append(".");
                        }
                        rngs = nrngs;
                    }
                    var rpairs = _FromPairs(rngs);
                    for (var r = 0; r < rpairs.Length; r += 2)
                    {
                        _AppendRangeTo(sb, rpairs, 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("\"]");
                }

                ++i;
            }

            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)
                {
                    writer.Write(",color=gray");
                }
                writer.WriteLine("]");
                ++i;
            }
            string 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 < 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("}");
        }
 public void WriteDotTo(TextWriter writer, DotGraphOptions options = null)
 {
     _WriteDotTo(FillClosure(), writer, options);
 }
        /// <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.InputTransitions;
                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();
                    for (var r = 0; r < rngGrp.Value.Length; r += 2)
                    {
                        _AppendRangeTo(sb, rngGrp.Value, r);
                    }
                    if (sb.Length != 1 || " " == sb.ToString())
                    {
                        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("}");
        }
Beispiel #7
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 <char, TAccept> > 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 <char, TAccept> >();
            var neutrals  = new List <FA <char, TAccept> >();
            var accepting = FillAcceptingStates(closure, null);

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

            IList <FA <char, TAccept> > fromStates = null;
            IList <FA <char, TAccept> > toStates   = null;

            char tchar = default(char);

            if (null != options.DebugString)
            {
                toStates = closure[0].FillEpsilonClosure();
                if (null == fromStates)
                {
                    fromStates = toStates;
                }
                foreach (char ch in options.DebugString)
                {
                    tchar    = ch;
                    toStates = FillMove(fromStates, ch);
                    if (0 == toStates.Count)
                    {
                        break;
                    }
                    fromStates = toStates;
                }
            }
            if (null != toStates)
            {
                toStates = FillEpsilonClosure(toStates, null);
            }
            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 = ((CharFA <TAccept>)ffa).FillInputTransitionRangesGroupedByState(null);
                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();
                    foreach (var range in rngGrp.Value)
                    {
                        _AppendRangeTo(sb, range);
                    }
                    if (sb.Length != 1 || " " == sb.ToString())
                    {
                        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(" [");
                if (null != options.DebugString)
                {
                    if (null != toStates && toStates.Contains(ffa))
                    {
                        writer.Write("color=green,");
                    }
                    else if (null != fromStates && fromStates.Contains(ffa) && (null == toStates || !toStates.Contains(ffa)))
                    {
                        writer.Write("color=darkgreen,");
                    }
                }
                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 (null != options.DebugString && null != options.DebugSourceNfa && null != ffa.Tag)
                {
                    var tags = ffa.Tag as IEnumerable;
                    if (null != tags || ffa.Tag is FA <char, TAccept> )
                    {
                        writer.Write("<TR><TD>{");
                        if (null == tags)
                        {
                            writer.Write(" q<SUB>");
                            writer.Write(options.DebugSourceNfa.FillClosure().IndexOf((FA <char, TAccept>)ffa.Tag).ToString());
                            writer.Write("</SUB>");
                        }
                        else
                        {
                            delim = "";
                            foreach (var tag in tags)
                            {
                                writer.Write(delim);
                                if (tag is FA <char, TAccept> )
                                {
                                    writer.Write(delim);
                                    writer.Write(" q<SUB>");
                                    writer.Write(options.DebugSourceNfa.FillClosure().IndexOf((FA <char, TAccept>)tag).ToString());
                                    writer.Write("</SUB>");
                                    // putting a comma here is what we'd like
                                    // but it breaks dot no matter how its encoded
                                    delim = @" ";
                                }
                            }
                        }
                        writer.Write(" }</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))
                {
                    if ((null == fromStates || !fromStates.Contains(ffa)) &&
                        (null == toStates || !toStates.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)
                {
                    if ((null == fromStates || !fromStates.Contains(ntfa)) &&
                        (null == toStates || !toStates.Contains(ntfa))
                        )
                    {
                        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("}");
        }