Skip to content

Allow pgen to produce a DOT format dump of the grammar #18005

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 14, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion Parser/pgen/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,19 @@ def main():
)

parser.add_argument("--verbose", "-v", action="count")
parser.add_argument(
"--graph",
type=argparse.FileType("w"),
action="store",
metavar="GRAPH_OUTPUT_FILE",
help="Dumps a DOT representation of the generated automata in a file",
)

args = parser.parse_args()

p = ParserGenerator(args.grammar, args.tokens, verbose=args.verbose)
p = ParserGenerator(
args.grammar, args.tokens, verbose=args.verbose, graph_file=args.graph
)
grammar = p.make_grammar()
grammar.produce_graminit_h(args.graminit_h.write)
grammar.produce_graminit_c(args.graminit_c.write)
Expand Down
29 changes: 29 additions & 0 deletions Parser/pgen/automata.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,26 @@ def dump(self, writer=print):
else:
writer(" %s -> %d" % (label, j))

def dump_graph(self, writer):
"""Dump a DOT representation of the NFA"""
writer('digraph %s_nfa {\n' % self.name)
todo = [self.start]
for i, state in enumerate(todo):
writer(' %d [label="State %d %s"];\n' % (i, i, state is self.end and "(final)" or ""))
for arc in state.arcs:
label = arc.label
next = arc.target
if next in todo:
j = todo.index(next)
else:
j = len(todo)
todo.append(next)
if label is None:
writer(" %d -> %d [style=dotted label=ε];\n" % (i, j))
else:
writer(" %d -> %d [label=%s];\n" % (i, j, label.replace("'", '"')))
writer('}\n')


class NFAArc:
"""An arc representing a transition between two NFA states.
Expand Down Expand Up @@ -301,6 +321,15 @@ def dump(self, writer=print):
for label, next in sorted(state.arcs.items()):
writer(" %s -> %d" % (label, self.states.index(next)))

def dump_graph(self, writer):
"""Dump a DOT representation of the DFA"""
writer('digraph %s_dfa {\n' % self.name)
for i, state in enumerate(self.states):
writer(' %d [label="State %d %s"];\n' % (i, i, state.is_final and "(final)" or ""))
for label, next in sorted(state.arcs.items()):
writer(" %d -> %d [label=%s];\n" % (i, self.states.index(next), label.replace("'", '"')))
writer('}\n')


class DFAState(object):
"""A state of a DFA
Expand Down
7 changes: 6 additions & 1 deletion Parser/pgen/pgen.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ def __repr__(self):


class ParserGenerator(object):
def __init__(self, grammar_file, token_file, verbose=False):
def __init__(self, grammar_file, token_file, verbose=False, graph_file=None):
with open(grammar_file) as f:
self.grammar = f.read()
with open(token_file) as tok_file:
Expand All @@ -141,6 +141,7 @@ def __init__(self, grammar_file, token_file, verbose=False):
self.opmap["<>"] = "NOTEQUAL"
self.verbose = verbose
self.filename = grammar_file
self.graph_file = graph_file
self.dfas, self.startsymbol = self.create_dfas()
self.first = {} # map from symbol name to set of tokens
self.calculate_first_sets()
Expand All @@ -152,11 +153,15 @@ def create_dfas(self):
if self.verbose:
print("Dump of NFA for", nfa.name)
nfa.dump()
if self.graph_file is not None:
nfa.dump_graph(self.graph_file.write)
dfa = DFA.from_nfa(nfa)
if self.verbose:
print("Dump of DFA for", dfa.name)
dfa.dump()
dfa.simplify()
if self.graph_file is not None:
dfa.dump_graph(self.graph_file.write)
rule_to_dfas[dfa.name] = dfa

if start_nonterminal is None:
Expand Down