PageRenderTime 59ms CodeModel.GetById 36ms RepoModel.GetById 0ms app.codeStats 0ms

/runtime/CSharp3/Sources/Antlr3.Runtime/Tree/DotTreeGenerator.cs

https://bitbucket.org/jwalton/antlr3
C# | 216 lines | 118 code | 24 blank | 74 comment | 14 complexity | 36699cf6cf275e7a073504a8f677c699 MD5 | raw file
  1. /*
  2. * [The "BSD licence"]
  3. * Copyright (c) 2005-2008 Terence Parr
  4. * All rights reserved.
  5. *
  6. * Conversion to C#:
  7. * Copyright (c) 2008 Sam Harwell, Pixel Mine, Inc.
  8. * All rights reserved.
  9. *
  10. * Redistribution and use in source and binary forms, with or without
  11. * modification, are permitted provided that the following conditions
  12. * are met:
  13. * 1. Redistributions of source code must retain the above copyright
  14. * notice, this list of conditions and the following disclaimer.
  15. * 2. Redistributions in binary form must reproduce the above copyright
  16. * notice, this list of conditions and the following disclaimer in the
  17. * documentation and/or other materials provided with the distribution.
  18. * 3. The name of the author may not be used to endorse or promote products
  19. * derived from this software without specific prior written permission.
  20. *
  21. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  22. * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  23. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  24. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  25. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  26. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  27. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  28. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  29. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  30. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  31. */
  32. namespace Antlr.Runtime.Tree
  33. {
  34. using System.Collections.Generic;
  35. using StringBuilder = System.Text.StringBuilder;
  36. /** A utility class to generate DOT diagrams (graphviz) from
  37. * arbitrary trees. You can pass in your own templates and
  38. * can pass in any kind of tree or use Tree interface method.
  39. * I wanted this separator so that you don't have to include
  40. * ST just to use the org.antlr.runtime.tree.* package.
  41. * This is a set of non-static methods so you can subclass
  42. * to override. For example, here is an invocation:
  43. *
  44. * CharStream input = new ANTLRInputStream(System.in);
  45. * TLexer lex = new TLexer(input);
  46. * CommonTokenStream tokens = new CommonTokenStream(lex);
  47. * TParser parser = new TParser(tokens);
  48. * TParser.e_return r = parser.e();
  49. * Tree t = (Tree)r.tree;
  50. * System.out.println(t.toStringTree());
  51. * DOTTreeGenerator gen = new DOTTreeGenerator();
  52. * StringTemplate st = gen.toDOT(t);
  53. * System.out.println(st);
  54. */
  55. public class DotTreeGenerator
  56. {
  57. readonly string[] HeaderLines =
  58. {
  59. "digraph {",
  60. "",
  61. "\tordering=out;",
  62. "\tranksep=.4;",
  63. "\tbgcolor=\"lightgrey\"; node [shape=box, fixedsize=false, fontsize=12, fontname=\"Helvetica-bold\", fontcolor=\"blue\"",
  64. "\t\twidth=.25, height=.25, color=\"black\", fillcolor=\"white\", style=\"filled, solid, bold\"];",
  65. "\tedge [arrowsize=.5, color=\"black\", style=\"bold\"]",
  66. ""
  67. };
  68. const string Footer = "}";
  69. const string NodeFormat = " {0} [label=\"{1}\"];";
  70. const string EdgeFormat = " {0} -> {1} // \"{2}\" -> \"{3}\"";
  71. /** Track node to number mapping so we can get proper node name back */
  72. Dictionary<object, int> nodeToNumberMap = new Dictionary<object, int>();
  73. /** Track node number so we can get unique node names */
  74. int nodeNumber = 0;
  75. /** Generate DOT (graphviz) for a whole tree not just a node.
  76. * For example, 3+4*5 should generate:
  77. *
  78. * digraph {
  79. * node [shape=plaintext, fixedsize=true, fontsize=11, fontname="Courier",
  80. * width=.4, height=.2];
  81. * edge [arrowsize=.7]
  82. * "+"->3
  83. * "+"->"*"
  84. * "*"->4
  85. * "*"->5
  86. * }
  87. *
  88. * Takes a Tree interface object.
  89. */
  90. public virtual string ToDot( object tree, ITreeAdaptor adaptor )
  91. {
  92. StringBuilder builder = new StringBuilder();
  93. foreach ( string line in HeaderLines )
  94. builder.AppendLine( line );
  95. nodeNumber = 0;
  96. var nodes = DefineNodes( tree, adaptor );
  97. nodeNumber = 0;
  98. var edges = DefineEdges( tree, adaptor );
  99. foreach ( var s in nodes )
  100. builder.AppendLine( s );
  101. builder.AppendLine();
  102. foreach ( var s in edges )
  103. builder.AppendLine( s );
  104. builder.AppendLine();
  105. builder.AppendLine( Footer );
  106. return builder.ToString();
  107. }
  108. public virtual string ToDot( ITree tree )
  109. {
  110. return ToDot( tree, new CommonTreeAdaptor() );
  111. }
  112. protected virtual IEnumerable<string> DefineNodes( object tree, ITreeAdaptor adaptor )
  113. {
  114. if ( tree == null )
  115. yield break;
  116. int n = adaptor.GetChildCount( tree );
  117. if ( n == 0 )
  118. {
  119. // must have already dumped as child from previous
  120. // invocation; do nothing
  121. yield break;
  122. }
  123. // define parent node
  124. yield return GetNodeText( adaptor, tree );
  125. // for each child, do a "<unique-name> [label=text]" node def
  126. for ( int i = 0; i < n; i++ )
  127. {
  128. object child = adaptor.GetChild( tree, i );
  129. yield return GetNodeText( adaptor, child );
  130. foreach ( var t in DefineNodes( child, adaptor ) )
  131. yield return t;
  132. }
  133. }
  134. protected virtual IEnumerable<string> DefineEdges( object tree, ITreeAdaptor adaptor )
  135. {
  136. if ( tree == null )
  137. yield break;
  138. int n = adaptor.GetChildCount( tree );
  139. if ( n == 0 )
  140. {
  141. // must have already dumped as child from previous
  142. // invocation; do nothing
  143. yield break;
  144. }
  145. string parentName = "n" + GetNodeNumber( tree );
  146. // for each child, do a parent -> child edge using unique node names
  147. string parentText = adaptor.GetText( tree );
  148. for ( int i = 0; i < n; i++ )
  149. {
  150. object child = adaptor.GetChild( tree, i );
  151. string childText = adaptor.GetText( child );
  152. string childName = "n" + GetNodeNumber( child );
  153. yield return string.Format( EdgeFormat, parentName, childName, FixString( parentText ), FixString( childText ) );
  154. foreach ( var t in DefineEdges( child, adaptor ) )
  155. yield return t;
  156. }
  157. }
  158. protected virtual string GetNodeText( ITreeAdaptor adaptor, object t )
  159. {
  160. string text = adaptor.GetText( t );
  161. string uniqueName = "n" + GetNodeNumber( t );
  162. return string.Format( NodeFormat, uniqueName, FixString( text ) );
  163. }
  164. protected virtual int GetNodeNumber( object t )
  165. {
  166. int i;
  167. if ( nodeToNumberMap.TryGetValue( t, out i ) )
  168. {
  169. return i;
  170. }
  171. else
  172. {
  173. nodeToNumberMap[t] = nodeNumber;
  174. nodeNumber++;
  175. return nodeNumber - 1;
  176. }
  177. }
  178. protected virtual string FixString( string text )
  179. {
  180. if ( text != null )
  181. {
  182. text = System.Text.RegularExpressions.Regex.Replace( text, "\"", "\\\\\"" );
  183. text = System.Text.RegularExpressions.Regex.Replace( text, "\\t", " " );
  184. text = System.Text.RegularExpressions.Regex.Replace( text, "\\n", "\\\\n" );
  185. text = System.Text.RegularExpressions.Regex.Replace( text, "\\r", "\\\\r" );
  186. if ( text.Length > 20 )
  187. text = text.Substring( 0, 8 ) + "..." + text.Substring( text.Length - 8 );
  188. }
  189. return text;
  190. }
  191. }
  192. }