00001 """ @package antlr3.dottreegenerator
00002 @brief ANTLR3 runtime package, tree module
00003
00004 This module contains all support classes for AST construction and tree parsers.
00005
00006 """
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041 from tree import CommonTreeAdaptor
00042 import stringtemplate3
00043
00044 class DOTTreeGenerator(object):
00045 """
00046 A utility class to generate DOT diagrams (graphviz) from
00047 arbitrary trees. You can pass in your own templates and
00048 can pass in any kind of tree or use Tree interface method.
00049 """
00050
00051 _treeST = stringtemplate3.StringTemplate(
00052 template=(
00053 "digraph {\n" +
00054 " ordering=out;\n" +
00055 " ranksep=.4;\n" +
00056 " node [shape=plaintext, fixedsize=true, fontsize=11, fontname=\"Courier\",\n" +
00057 " width=.25, height=.25];\n" +
00058 " edge [arrowsize=.5]\n" +
00059 " $nodes$\n" +
00060 " $edges$\n" +
00061 "}\n")
00062 )
00063
00064 _nodeST = stringtemplate3.StringTemplate(
00065 template="$name$ [label=\"$text$\"];\n"
00066 )
00067
00068 _edgeST = stringtemplate3.StringTemplate(
00069 template="$parent$ -> $child$ // \"$parentText$\" -> \"$childText$\"\n"
00070 )
00071
00072 def __init__(self):
00073
00074 self.nodeToNumberMap = {}
00075
00076
00077 self.nodeNumber = 0
00078
00079
00080 def toDOT(self, tree, adaptor=None, treeST=_treeST, edgeST=_edgeST):
00081 if adaptor is None:
00082 adaptor = CommonTreeAdaptor()
00083
00084 treeST = treeST.getInstanceOf()
00085
00086 self.nodeNumber = 0
00087 self.toDOTDefineNodes(tree, adaptor, treeST)
00088
00089 self.nodeNumber = 0
00090 self.toDOTDefineEdges(tree, adaptor, treeST, edgeST)
00091 return treeST
00092
00093
00094 def toDOTDefineNodes(self, tree, adaptor, treeST, knownNodes=None):
00095 if knownNodes is None:
00096 knownNodes = set()
00097
00098 if tree is None:
00099 return
00100
00101 n = adaptor.getChildCount(tree)
00102 if n == 0:
00103
00104
00105 return
00106
00107
00108 number = self.getNodeNumber(tree)
00109 if number not in knownNodes:
00110 parentNodeST = self.getNodeST(adaptor, tree)
00111 treeST.setAttribute("nodes", parentNodeST)
00112 knownNodes.add(number)
00113
00114
00115 for i in range(n):
00116 child = adaptor.getChild(tree, i)
00117
00118 number = self.getNodeNumber(child)
00119 if number not in knownNodes:
00120 nodeST = self.getNodeST(adaptor, child)
00121 treeST.setAttribute("nodes", nodeST)
00122 knownNodes.add(number)
00123
00124 self.toDOTDefineNodes(child, adaptor, treeST, knownNodes)
00125
00126
00127 def toDOTDefineEdges(self, tree, adaptor, treeST, edgeST):
00128 if tree is None:
00129 return
00130
00131 n = adaptor.getChildCount(tree)
00132 if n == 0:
00133
00134
00135 return
00136
00137 parentName = "n%d" % self.getNodeNumber(tree)
00138
00139
00140 parentText = adaptor.getText(tree)
00141 for i in range(n):
00142 child = adaptor.getChild(tree, i)
00143 childText = adaptor.getText(child)
00144 childName = "n%d" % self.getNodeNumber(child)
00145 edgeST = edgeST.getInstanceOf()
00146 edgeST.setAttribute("parent", parentName)
00147 edgeST.setAttribute("child", childName)
00148 edgeST.setAttribute("parentText", parentText)
00149 edgeST.setAttribute("childText", childText)
00150 treeST.setAttribute("edges", edgeST)
00151 self.toDOTDefineEdges(child, adaptor, treeST, edgeST)
00152
00153
00154 def getNodeST(self, adaptor, t):
00155 text = adaptor.getText(t)
00156 nodeST = self._nodeST.getInstanceOf()
00157 uniqueName = "n%d" % self.getNodeNumber(t)
00158 nodeST.setAttribute("name", uniqueName)
00159 if text is not None:
00160 text = text.replace('"', r'\\"')
00161 nodeST.setAttribute("text", text)
00162 return nodeST
00163
00164
00165 def getNodeNumber(self, t):
00166 try:
00167 return self.nodeToNumberMap[t]
00168 except KeyError:
00169 self.nodeToNumberMap[t] = self.nodeNumber
00170 self.nodeNumber += 1
00171 return self.nodeNumber - 1
00172
00173
00174 def toDOT(tree, adaptor=None, treeST=DOTTreeGenerator._treeST, edgeST=DOTTreeGenerator._edgeST):
00175 """
00176 Generate DOT (graphviz) for a whole tree not just a node.
00177 For example, 3+4*5 should generate:
00178
00179 digraph {
00180 node [shape=plaintext, fixedsize=true, fontsize=11, fontname="Courier",
00181 width=.4, height=.2];
00182 edge [arrowsize=.7]
00183 "+"->3
00184 "+"->"*"
00185 "*"->4
00186 "*"->5
00187 }
00188
00189 Return the ST not a string in case people want to alter.
00190
00191 Takes a Tree interface object.
00192
00193 Example of invokation:
00194
00195 import antlr3
00196 import antlr3.extras
00197
00198 input = antlr3.ANTLRInputStream(sys.stdin)
00199 lex = TLexer(input)
00200 tokens = antlr3.CommonTokenStream(lex)
00201 parser = TParser(tokens)
00202 tree = parser.e().tree
00203 print tree.toStringTree()
00204 st = antlr3.extras.toDOT(t)
00205 print st
00206
00207 """
00208
00209 gen = DOTTreeGenerator()
00210 return gen.toDOT(tree, adaptor, treeST, edgeST)