Skip to content

Instantly share code, notes, and snippets.

@aanastasiou
Last active November 6, 2020 18:45
Show Gist options
  • Save aanastasiou/922a527674bce003dc9b55a0251b8fba to your computer and use it in GitHub Desktop.
Save aanastasiou/922a527674bce003dc9b55a0251b8fba to your computer and use it in GitHub Desktop.
Simple expression to parsing tree in graphviz

Expression to parse tree visualisation

Call with something like:

    > echo '11*19 + 3 * 9'|python exp2gviz.py -|dot -Earrowsize=0.4 -Nfixedsize=1 -Grankdir=BT -Tpng>gviz_out.png;feh gviz_out.png

To get something like:

image

import networkx
import pyparsing
import random
import click
import os
import sys
class ExpressionToGraph:
def __init__(self):
self._g = networkx.DiGraph()
number = pyparsing.Regex("[0-9]+").setParseAction(lambda s,loc,tok:self._add_node(int(tok[0])))
self._parser = pyparsing.infixNotation(number, [(pyparsing.oneOf("* /"), 2, pyparsing.opAssoc.LEFT, lambda s, loc, tok:self._add_expression_node(tok[0], str(tok[0][1]))),
(pyparsing.oneOf("+ -"), 2, pyparsing.opAssoc.LEFT, lambda s, loc, tok:self._add_expression_node(tok[0], str(tok[0][1])))]).setParseAction(lambda s,loc,tok:tok[0])
@property
def graph(self):
return self._g
def _add_node(self, node_label, shape="circle"):
node_id = self._get_node_id()
self._g.add_node(node_id, label = node_label, shape=shape)
return node_id
def _add_expression_node(self, operands, node_label):
p_node_id = operands[0]
for op_idx, op in filter(lambda x:x[1] in ["*","-","+","/"], enumerate(operands)):
new_node_id = self._add_node(op)
self._g.add_edge(p_node_id,new_node_id)
self._g.add_edge(operands[op_idx+1],new_node_id)
p_node_id=new_node_id
return new_node_id
@staticmethod
def _get_node_id():
return "".join(["0123456789ABCDEF"[random.randint(0,15)] for k in range(0,8)])
def __call__(self, expression):
self._parser.parseString(expression)
@click.command()
@click.argument("input_file", type=click.File())
@click.option("-o", "--output_file", type=click.Path(exists=False), default=None)
def main(input_file, output_file):
m = ExpressionToGraph()
q = m(input_file.read())
if output_file is None:
output_fd = sys.stdout
else:
output_fd = open(output_file, "w")
networkx.nx_pydot.write_dot(m.graph, output_fd)
if __name__ == "__main__":
main()
appdirs==1.4.3
backcall==0.2.0
CacheControl==0.12.6
certifi==2020.6.20
chardet==3.0.4
click==7.1.2
colorama==0.4.3
contextlib2==0.6.0
cycler==0.10.0
decorator==4.4.2
distlib==0.3.0
distro==1.4.0
fancycompleter==0.9.1
html5lib==1.0.1
idna==2.8
ipaddr==2.2.0
ipython==7.19.0
ipython-genutils==0.2.0
jedi==0.17.2
kiwisolver==1.3.1
lockfile==0.12.2
matplotlib==3.3.2
msgpack==0.6.2
networkx==2.5
numpy==1.19.4
packaging==20.3
parso==0.7.1
pdbpp==0.10.2
pep517==0.8.2
pexpect==4.8.0
pickleshare==0.7.5
Pillow==8.0.1
progress==1.5
prompt-toolkit==3.0.8
ptyprocess==0.6.0
pydot==1.4.1
Pygments==2.7.2
pyparsing==2.4.6
PyQt5==5.15.1
PyQt5-sip==12.8.1
pyrepl==0.9.0
python-dateutil==2.8.1
pytoml==0.1.21
requests==2.22.0
retrying==1.3.3
six==1.14.0
traitlets==5.0.5
urllib3==1.25.8
wcwidth==0.2.5
webencodings==0.5.1
wmctrl==0.3
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment