NAME
MarpaX::Grammar::GraphViz2 - Convert a Marpa grammar into an image
Synopsis
use MarpaX::Grammar::GraphViz2;
my(%option) =
( # Inputs:
legend => 1,
marpa_bnf_file => 'share/metag.bnf',
user_bnf_file => 'share/stringparser.bnf',
# Outputs:
output_file => 'html/stringparser.svg',
);
MarpaX::Grammar::GraphViz2 -> new(%option) -> run;
See share/*.bnf for input files and html/*.svg for output files.
For more help, run:
shell> perl -Ilib scripts/bnf2graph.pl -h
Note: Installation includes copying all files from the share/ directory, into a dir chosen by File::ShareDir. Run scripts/find.grammars.pl to display the name of the latter dir.
See also the demo page.
Description
For a given BNF, process the cooked tree output by MarpaX::Grammar::Parser, and turn it into an image.
The tree holds a representation of the user's BNF (SLIF-DSL), and is managed by Tree::DAG_Node.
This modules uses MarpaX::Grammar::Parser internally. It does not read that module's output file.
Installation
Install MarpaX::Grammar::GraphViz2 as you would for any Perl
module:
Run:
cpanm MarpaX::Grammar::GraphViz2
or run:
sudo cpan MarpaX::Grammar::GraphViz2
or unpack the distro, and then either:
perl Build.PL
./Build
./Build test
sudo ./Build install
or:
perl Makefile.PL
make (or dmake or nmake)
make test
make install
Note: Installation includes copying all files from the share/ directory, into a dir chosen by File::ShareDir. Run scripts/find.grammars.pl to display the name of the latter dir.
Constructor and Initialization
Call new()
as my($parser) = MarpaX::Grammar::GraphViz2 -> new(k1 => v1, k2 => v2, ...)
.
It returns a new object of type MarpaX::Grammar::GraphViz2
.
Key-value pairs accepted in the parameter list (see also the corresponding methods [e.g. "marpa_bnf_file([$bnf_file_name])"]):
- o driver aGraphvizDriverName
-
The name of the Graphviz program to provide to GraphViz2.
Default: 'dot'.
- o format => $format_name
-
This is the format of the output file, to be passed to GraphViz2.
Default: 'svg'.
- o graph => $graphviz2_object
-
Provides an object of type GraphViz2, to do the rendering.
Default:
GraphViz2 -> new ( edge => {color => 'grey'}, global => {directed => 1, driver => $self -> driver, format => $self -> format}, graph => {label => basename($self -> user_bnf_file), rankdir => 'TB'}, logger => $self -> logger, node => {shape => 'rectangle', style => 'filled'}, );
- o legend => $Boolean
-
Add a legend (1) to the graph, or omit it (0).
Default: 0.
- o logger => $logger_object
-
Specify a logger object.
The default value triggers creation of an object of type Log::Handler which outputs to the screen.
To disable logging, just set logger to the empty string.
The value for logger is passed to GraphViz2.
Default: undef.
- o marpa_bnf_file aMarpaBNFFileName
-
Specify the name of Marpa's own BNF file. This file ships with Marpa::R2. It's name is metag.bnf.
A copy, as of Marpa::R2 V 2.096000, ships with
MarpaX::Grammar::GraphViz2
. See share/metag.bnf.This option is mandatory.
Default: ''.
- o maxlevel => $level
-
This option is only used if an object of type Log::Handler is created. See logger above.
See also Log::Handler::Levels.
Default: 'notice'. A typical value is 'debug'.
- o minlevel => $level
-
This option is only used if an object of type Log::Handler is created. See logger above.
See also Log::Handler::Levels.
Default: 'error'.
No lower levels are used.
- o output_file => $output_file_name
-
Write the image to this file.
Use the
format
option to specify the type of image desired.If '', the file is not written.
Default: ''.
- o user_bnf_file aUserBNFFileName
-
Specify the name of the file containing your Marpa::R2-style grammar.
See share/stringparser.bnf for a sample.
This option is mandatory.
Default: ''.
Methods
add_legend()
Adds a legend to the graph if new() was called as new(legend => 1)
.
add_node(%attributes)
Adds (once only) a node to the graph. The node's name is $attributes{name}
.
Also, adds that name to the hashref of node names seen, which is returned by "nodes_seen()".
clean_name($name, $skip_symbols)
Cleans the given name to escape or replace characters special to dot.
Note: GraphViz2 also escapes some characters.
$skip_symbols is used by the caller in 1 case to stop a regexp being activated.
See the "FAQ" for details.
Returns the cleaned-up name.
clean_tree()
Calls "clean_name($name, $skip_symbols)" for each node in the tree.
default_count()
Returns the number of :default
' rules in the user's input.
discard_count()
Returns the number of :discard
rules in the user's input.
driver([$executable_name])
Here, the [] indicate an optional parameter.
Get or set the name of the Graphviz program to provide to GraphViz2.
Note: driver
is a parameter to new().
event_count()
Returns the number of event
rules in the user's input.
format([$format])
Here, the [] indicate an optional parameter.
Get or set the format of the output file, to be created by the renderer.
Note: format
is a parameter to new().
graph([$graph])
Get of set the GraphViz2 object which will do the graphing.
See also "output_file([$output_file_name])".
Note: graph
is a parameter to new().
legend([$Boolean])
Here, the [] indicate an optional parameter.
Get or set the option to include (1) or exclude (0) a legend from the image.
Note: legend
is a parameter to new().
lexeme_count()
Returns the number of :lexeme
rules in the user's input.
lexemes()
Returns a hashref keyed by the clean name, of lexemes seen in the user's input.
The value for each key is an arrayref of hashrefs suitable for forcing GraphViz2 to plot the node as a record structure. See http://www.graphviz.org/content/node-shapes#record for the gory details.
log($level, $s)
Calls $self -> logger -> log($level => $s) if ($self -> logger).
logger([$logger_object])
Here, the [] indicate an optional parameter.
Get or set the logger object.
To disable logging, just set logger to the empty string.
This logger is passed to GraphViz2.
Note: logger
is a parameter to new().
marpa_bnf_file([$bnf_file_name])
Here, the [] indicate an optional parameter.
Get or set the name of the file to read Marpa's grammar from.
Note: marpa_bnf_file
is a parameter to new().
maxlevel([$string])
Here, the [] indicate an optional parameter.
Get or set the value used by the logger object.
This option is only used if an object of type Log::Handler is created. See Log::Handler::Levels.
Note: maxlevel
is a parameter to new().
minlevel([$string])
Here, the [] indicate an optional parameter.
Get or set the value used by the logger object.
This option is only used if an object of type Log::Handler is created. See Log::Handler::Levels.
Note: minlevel
is a parameter to new().
new()
The constructor. See "Constructor and Initialization".
nodes_seen()
Returns a hashref keyed by the node name, of nodes passed to GraphViz2.
This is simply used to stop nodes being plotted twice.
output_file([$output_file_name])
Here, the [] indicate an optional parameter.
Get or set the name of the file to which the renderer will write the resultant graph.
If no output file is supplied, nothing is written.
See also graph([$graph]).
Note: output_file
is a parameter to new().
parser()
Returns the Marpa::Grammar::Parser object which will do the analysis of the user's grammar.
This object is created automatically during the call to "new()".
rectify_node($node)
For the given $node, which is an object of type Tree::DAG_Node, clean it's real name.
Then it adds the node's quantifier ('', '*' or '+') to that name, to act as the label (visible name) of the node, when the node is finally passed to GraphViz2.
Returns a 2-element list of ($name, $label).
root_name()
Returns a string which is the name of the root node of graph.
run()
The method which does all the work.
See "Synopsis" and scripts/bnf2graph.pl for sample code.
user_bnf_file([$bnf_file_name])
Here, the [] indicate an optional parameter.
Get or set the name of the file to read the user's grammar from.
Note: user_bnf_file
is a parameter to new().
Files Shipped with this Module
Data Files
-
This is part of MarpaX::Languages::C::AST, by Jean-Damien Durand. It's 1,565 lines long.
- o html/c.ast.svg
-
This is the image from c.ast.bnf.
See the next point for how this file is created.
-
It is part of MarpaX::Demo::JSONParser, written as a gist by Peter Stuifzand.
See https://gist.github.com/pstuifzand/4447349.
See the next point for how this file is created.
- o html/json.1.svg
-
This is the image from json.1.bnf.
-
It also is part of MarpaX::Demo::JSONParser, written by Jeffrey Kegler as a reply to the gist above from Peter.
- o html/json.2.svg
-
This is the image from json.2.bnf.
See the previous point for how this file is created.
-
It also is part of MarpaX::Demo::JSONParser, and is written by Jeffrey Kegler.
- o html/json.3.svg
-
This is the image from json.3.bnf.
-
This is a copy of Marpa::R2's BNF, as of Marpa::R2 V 2.096000.
- o html/metag.svg
-
This is the image from metag.bnf.
-
This BNF was extracted from MarpaX::Demo::SampleScripts's examples/ambiguous.grammar.01.pl.
- o html/numeric.expressions.svg
-
This is the image from numeric.expressions.bnf.
See the next point for how this file is created.
-
This is a copy of MarpaX::Demo::StringParser's BNF.
- o html/stringparser.svg
-
This is the image from stringparser.bnf.
See the next point for how this file is created.
-
It also is part of MarpaX::Database::Terminfo, written by Jean-Damien Durand.
- o html/termcap.info.svg
-
This is the image from termcap.info.bnf.
See the next point for how this file is created.
Scripts
- o scripts/bnf2graph.pl
-
This is a neat way of using the module. For help, run:
shell> perl -Ilib scripts/bnf2graph.pl -h
Of course you are also encouraged to include this module directly in your own code.
- o scripts/bnf2graph.sh
-
This is a quick way for me to run bnf2graph.pl.
- o scripts/find.grammars.pl
-
This prints the path to a grammar file. After installation of the module, run it with:
shell> perl scripts/find.grammars.pl (Defaults to json.1.bnf) shell> perl scripts/find.grammars.pl c.ast.bnf shell> perl scripts/find.grammars.pl json.1.bnf shell> perl scripts/find.grammars.pl json.2.bnf shell> perl scripts/find.grammars.pl stringparser.bnf shell> perl scripts/find.grammars.pl termcap.inf.bnf
It will print the name of the path to given grammar file.
- o scripts/generate.demo.pl
-
Generates html/index.html.
- o scripts/generate.demo.sh
-
This calls generate.demo.pl for each grammar shipped with the module.
Actually, it skips c.ast by default, since it takes 6 m 47 s to run that. But if you pass any command line parameter to the script, it includes c.ast.
Then it copies html/* to my web server's doc root (which is in Debian's default RAM disk) at /dev/shm/html.
- o scripts/pod2html.sh
-
This lets me quickly proof-read edits to the docs.
FAQ
Why are some characters in the images replaced by Unicode versions?
Firstly, the Perl module GraphViz2 escapes some characters. Currently, these are:
[ ] " (in various circumstances)
We let GraphViz2 handle these.
Secondly, Graphviz itself treats some characters specially. Currently, these are:
< > : "
We use this code to handle these:
$name =~ s/\\/\\\\/g; # Escape \.
$name =~ s/</\\</g; # Escape <.
$name =~ s/>/\\>/g; # Escape >.
$name =~ s/:/\x{a789}/g; # Replace : with a Unicode :
$name =~ s/\"/\x{a78c}\x{a78c}/g; # Replace " with 2 copies of a Unicode ' ...
# ... because I could not find a Unicode ".
Why do some images have a tiny sub-graph, whose root is, e.g., '<comma>'?
This is due to the author using both 'comma' and '<comma>' as tokens within the grammar.
So far this module does not notice the two are the same.
A similar thing can happen elsewhere, e.g. with named event statements, when the rhs name uses (say) '<xyz>' and the rule referred to uses just 'xyz'.
In all such cases, there will be 2 nodes, with 2 names differing in just the brackets.
Why do some nodes have (or lack) a quantifier when I use it both with and without one?
There is simply no way to plot a node both with and without the quantifier. The one which appears is chosen arbitrarily, depending on how the code scans the grammar. This means it is currently beyond control.
Why do the nodes on the demo page lack rule numbers?
I'm undecided as to whether or not they are a good idea. I documented it on the demo page to indicate it was easy (for some nodes), and await feedback.
Can I control the format or placement of the legend?
No, but you can turn it off with the legend
option to new()
.
ToDo
- o Perhaps add rule # to each node
-
This is the rule # within the input stream. Doing this is simple for some nodes, and difficult for others.
Machine-Readable Change Log
The file Changes was converted into Changelog.ini by Module::Metadata::Changes.
Version Numbers
Version numbers < 1.00 represent development versions. From 1.00 up, they are production versions.
Repository
https://github.com/ronsavage/MarpaX-Grammar-GraphViz2
Support
Email the author, or log a bug on RT:
https://rt.cpan.org/Public/Dist/Display.html?Name=MarpaX::Grammar::GraphViz2.
Author
MarpaX::Grammar::GraphViz2 was written by Ron Savage <ron@savage.net.au> in 2013.
Home page: http://savage.net.au/.
Copyright
Australian copyright (c) 2013, Ron Savage.
All Programs of mine are 'OSI Certified Open Source Software';
you can redistribute them and/or modify them under the terms of
The Perl License, a copy of which is available at:
http://www.opensource.org/licenses/index.html