2 --[[--------------------------------------------------------------------
4 Gazelle: a system for building fast, reusable parsers
8 A script for generating graphics for the manual. It parses Gazelle
9 language excerpts in manual.txt and emits pngs using graphviz.
11 Copyright (c) 2007-2008 Joshua Haberman. See LICENSE for details.
13 --------------------------------------------------------------------]]--
15 require "bootstrap/rtn"
16 require "fa_algorithms"
19 return str:gsub("[\"\\]", "\\%1")
22 grammar = parse_grammar(CharStream:new(io.stdin:read("*a")))
23 if grammar.rtns:count() ~= 1 then
24 error("This filter can only deal with grammars that have a single nonterminal")
26 for _nonterm, _rtn in grammar.rtns:each() do
31 rtn = hopcroft_minimize(nfa_to_dfa(rtn))
33 outfile = io.popen("dot -Tpng -o " .. arg[1], "w")
35 outfile:write("digraph untitled {\n")
36 outfile:write("rankdir=LR;\n")
37 outfile:write("fontsize=10;\n")
38 for state in each(rtn:states()) do
41 if state.final then peripheries = 2 end
42 if rtn.start == state then extra_label = "Start" end
43 outfile:write(string.format(' "%s" [label="%s" peripheries=%d]\n', tostring(state), extra_label, peripheries))
44 for edge_val, target_state in state:transitions() do
45 if fa.is_nonterm(edge_val) then
46 outfile:write(string.format(' "%s" -> "%s" [label="<%s>"]\n', tostring(state), tostring(target_state), escape(edge_val.name)))
48 if grammar.attributes.regex_text[edge_val] then
49 edge_val = "/" .. grammar.attributes.regex_text[edge_val] .. "/"
51 outfile:write(string.format(' "%s" -> "%s" [label="%s"]\n', tostring(state), tostring(target_state), escape(edge_val)))