What is JSyntrax?
JSyntrax is a railroad diagram generator. It creates a visual illustration of the grammar used for programming languages. A specification file describes the syntax as a hierarchy of basic elements. This is processed into an image representing the same syntax with interconnected nodes.
The specification is a set of nested Groovy function calls:
indentstack(10, line(opt('-'), choice('0', line('1-9', loop(None, '0-9'))), opt('.', loop('0-9', None))), line(opt(choice('e', 'E'), choice(None, '+', '-'), loop('0-9', None))) )
This is processed by JSyntrax to generate an SVG image:
JSyntrax can render to PNG bitmap images or SVG vector images. The SVG output can have hyperlinked text allowing users to quickly navigate to documentation of different syntax elements.
The original Syntrax was a heavily modified version of the railroad diagram generator used for the SQLite documentation implemented in Python. Then in JSyntrax it has been reimplemented in Java in order to simplify installation, get rid of required libraries and make it easily portable to any operating system.
JSyntrax vs. Syntrax
- Why did you reimplement Syntrax in Java?
The problem with Syntrax is that it requires Pycairo and Pango which may be difficult to install, especially on Windows. JSyntrax requires only JDK 11, which is easily available for many platforms.
- What output formats are supported?
JSyntrax produces SVG and PNG images. The original Syntrax can also produce PDF, PS, and EPS, these formats are not yet supported by JSyntrax.
- Can I build my Syntrax specs with JSyntrax?
Yes, after only a couple of minor tweaks. If you use url maps, refer to Hyperlinked SVG section for Groovy-specific DSL which is a bit different from what was in original Syntrax (in short: you will have to replace
jsyntraxwrapper function). Also,
text_modattribute in Styling diagrams is not supported (the author of the original Syntrax warned about potential security issues with this attribute). Instead, if a style regexp pattern contains a capturing group, the node text will contain the contents of the first capturing group only.
- Why your executable file is called
This is made intentionally in order to use AsciiDoctor Diagram integration facility. JSyntrax executable has exactly the same command line arguments as Syntrax and can be used as a replacement for the original
JSyntrax is licensed for free commercial and non-commercial use under the terms of the MIT license.
Requirements, download and installation
JSyntrax requires JDK 11+. No other software is required to run JSyntrax.
jsyntrax-XXX.zip file to any convenient folder.
/bin directory will contain executable
JSyntrax is a command line tool. You pass it an input specification file and it will generate a diagram in any of the supported output formats.
usage: syntrax [--get-style] [-h] [-i <arg>] [-o <arg>] [-s <arg>] [--scale <arg>] [-t] [--title <arg>] [-v] Railroad diagram generator. Options --get-style Create default style .ini -h,--help Show this help message and exit -i,--input <arg> Diagram spec file -o,--output <arg> Output file -s,--style <arg> Style config .ini file --scale <arg> Scale image -t,--transparent Transparent background --title <arg> Diagram title -v,--version JSyntrax version
Any argument not associated with a flag is assumed to be the input file name. The default output format is PNG.
> syntrax spec Output file spec.png was created Done!
You can specify the specific out file you want with the
The extension determines the format.
You can also pass just the extension to
-o and Syntrax will use the input file base name for the output image:
>syntrax -i spec -o result.svg Output file result.svg was created Done! >syntrax -i spec -o svg Output file spec.svg was created Done!
By default the images have a white background. If you want a transparent background pass the
You can control the scale of the resulting image with the
It takes a floating point scale factor.
This is most useful for the PNG output to increase the resolution of the image or create thumbnails with less blurring than conventional bitmap resizing.
> syntrax -i scaling.spec -o small.svg --scale 0.5
> syntrax -i scaling.spec -o big.svg --scale 2.0
You can include a title in the generated diagram by passing a string to the
The position of the title is controlled by the
title_pos entry in the styling configuration.
It defaults to the top left.
title_font entry is used to style the font.
> syntrax -i titling.spec -o svg --title="Diagram with title"
JSyntrax diagrams are created using a Groovy-based specification language. A series of nestable function calls generate specific diagram elements. Nodes in the diagram are represented by quoted strings. Nodes default to rounded bubbles but will change to a box when prefixed with "/". Note that this is the reverse of how the original SQLite generator works. The rounded bubbles are typically used for literal tokens. Boxes are typically place holders for syntactic elements too complex to include in the current diagram. Nodes starting with a non-alphanumeric character are rendered with their own font style so that punctuation tokens can be made more distinct.
The following functions are available for creating diagrams:
line() creates a series of nodes arranged horizontally from left
line('[', 'foo', ',', '/bar', ']')
loop() represents a repeatable section of the syntax diagram. It
takes two arguments. The first is the line of nodes for the forward path
and the second is the nodes for the backward path. The backward path is
rendered with nodes ordered from right to left.
loop(line('/forward', 'path'), line('backward', 'path'))
Either the forward or backward path can be
None to represent no
nodes on that portion of the loop.
toploop() is a variant of
loop() that places the backward path
above the forward path.
toploop(line('(', 'forward', ')'), line('(', 'backward', ')'))
choice() element represents a branch between multiple syntax
choice('A', 'B', 'C')
opt() element specifies an optional portion of the syntax. The
main path bypasses the optional portion positioned below.
opt('A', 'B', 'C')
opt() is a special case of the
choice() function where the first
None and the remaining nodes are put into a single line
for the second choice. The example above is equivalent the following:
choice(None, line('A', 'B', 'C'))
optx() element is a variant of
opt() with the main path
passing through the nodes.
optx('A', 'B', 'C')
The elements described above will concatenate indefinitely from left to
right. To break up long sections of a diagram you use the
element. Each of its arguments forms a separate line that is stacked
from top to bottom.
stack( line('top', 'line'), line('bottom', 'line') )
When an inner element of a stack argument list is an
opt() or an
optx() it will be rendered with a special vertical bypass.
stack( line('A', 'B'), opt('bypass'), line('finish') )
For more control of the stacking you can use the
element. It shifts lower lines to the right relative to the top line of
the stack. Its first argument is an integer specifing the amount of
indentstack(3, line('top', 'line'), line('bottom', 'line') )
rightstack() element will right align successive lines without
needing to determine the indentation.
rightstack( line('top', 'line', 'with', 'more', 'code'), line('bottom', 'line') )
You can control the styling of the generated diagrams by passing in a
style INI file with the
You can use the
--get-style option to generate a copy of the default
styles in the current directory so you can quickly make modifications.
Here is the default styling:
[style] line_width = 2 outline_width = 2 padding = 5 line_color = (0, 0, 0) max_radius = 9 h_sep = 17 v_sep = 9 arrows = True title_pos = 'tl' bullet_fill = (255, 255, 255) text_color = (0, 0, 0) shadow = True shadow_fill = (0, 0, 0, 127) title_font = ('Sans', 22, 'bold') [bubble] pattern = '(^\w+)' shape = 'bubble' font = ('Sans', 14, 'bold') text_color = (0, 0, 0) fill = (179, 229, 252) [box] pattern = '^/(.+)' shape = 'box' font = ('Times', 14, 'italic') text_color = (0, 0, 0) fill = (144, 164, 174) [token] pattern = '(.*)' shape = 'bubble' font = ('Sans', 16, 'bold') text_color = (0, 0, 0) fill = (179, 229, 252)
Here is the same diagram with modified styling:
[style] ; Thicker lines line_width = 3 outline_width = 3 padding = 5 line_color = (0, 0, 0) ; Larger radii max_radius = 29 h_sep = 17 v_sep = 9 ; Remove arrows arrows = False title_pos = 'tl' ; yellow bullet_fill = (255,255,0) text_color = (0, 0, 0) shadow = True shadow_fill = (0, 0, 0, 127) title_font = ('Sans', 22, 'bold') ; User-defined style name [hex_bubble] pattern = '(^\w+)' ; Hexagon shape for node shape = 'hex' font = ('Sans', 14, 'bold') ; Alpha component for transparent fills fill = (255,0,0,127) [box] pattern = '^/(.*)' shape = 'box' font = ('Sans', 14, 'bold') text_color = (100, 100, 100) fill = (144, 164, 174) [token] pattern = '(.*)' shape = 'bubble' font = ('Times', 16, 'italic') fill = (0,255,0,127)
The style configuration file has a main section named "[style]" followed by user-defined sections for various node types. The node style is chosen based on a regex pattern applied to the text. The first matched pattern sets the style for a node. Patterns are tested in the same order they appear in the configuration file. The first node style is used by default if no pattern matched the text. If the pattern contains a capturing group, then the resulting text in the node will be equal to the contents of this group (otherwise, the full text will be used).
[style] section contains the following keys:
Connecting line width in pixels. Default is 2.
Node outline width in pixels. Default is 2.
Additional padding around each edge of the image in pixels. Default is5.
Color of the connecting lines and node outlines. Default is (0,0,0) Black.
Maximum radius for turnbacks on loops and stacked connections.
Horizontal separation between nodes.
Vertical separation between line elements.
Boolean used to control rendering of line arrows. Default is True.
Position of the title text. String containing one of 'left', 'center', or 'right' for horizontal position and 'top' or 'bottom' for vertical. These can be abbreviated as 'l', 'c', 'r', 't', and 'b'. Other characters are ignored. Examples are 'top-left', 'bottom center', 'cr', and 'rt'.
Fill color for small bullets at start and end of the diagram.
Default color of all text. Can be overridden with
text_colorin a node style section
Boolean controlling the rendering of node shadows. Default is True.
Fill color for shadows.
Font for image title.
Nodes are styled with a user-defined section name.
The built-in sections are
[bubble] for tokens that start with an alphanumeric character,
[box] for symbols drawn with a boxed outline, and
[token] for tokens that consist of a single punctuation character.
You are not limited to these three node styles.
Any number of node types can be defined provided they have distinct patterns to match against the node text in your specification file.
The node sections contain the following keys:
A regex pattern to match the node text to a style. Notes about pattern format:
Must satisfy regex java semantics
Matches the whole input sequence exclusively (input
"</>Hello"corresponds to this:
"</>.*", not this:
You may not want to see control characters of your regex in diagram output. To omit them, use capture groups to wrap the content you want to display. Examples:
<b>my_text</b>and will display
If given input sequence does not match specified expression, default style will be used.
Node outline shape. Must be "bubble", "box", or "hex".
Font style for the node.
Optional font color for the node. If omitted, the
[style]section is used.
Shape fill color for the node.
The various keys controlling coloration can use a variety of color formats. The primary color representation is a 3 or 4-tuple representing RGB or RGBA channels. All channels are an integer ranging from 0 to 255.
; Supported color formats: (255,100,0) ; RGB (255,100,0,100) ; RGBA
Fonts are specified as a tuple of three items in the following order:
Font family (Helvetica, Times, Courier, etc.)
Point size (12, 14, 16, etc.)
Style ('normal', 'bold', 'italic')
title_font = ('Helvetica', 14, 'bold')
SVG images can have hyperlinked node text. This is implemented by adding a
url_map parameter to
jsyntrax wrapper function.
The keys of the dictionary are the text identifying the node and their values are the URL for the link.
The text key should not include any leading "/" character for the box nodes.
jsyntrax(stack( line('attribute', '/(attribute) identifier', 'of'), line(choice(toploop('/entity_designator', ','), 'others', 'all'), ':'), line('/entity_class', 'is', '/expression', ';') ), [ 'entity_class': 'https://www.google.com/#q=vhdl+entity+class', '(attribute) identifier': 'http://en.wikipedia.com/wiki/VHDL' ])
Note for Syntrax (Python) users
Note that in Groovy, unlike Python, maps are enclosed in brackets
Current browser policies lump SVG hyperlinks together with embedded
Because of this they do not support hyperlinks when an SVG
is referenced through an HTML
To get functional links on a web page you must use an
<object> tag instead:
<object type="image/svg+xml" data="path/to/your.svg"></object>
In Asciidoctor diagrams, we should put set
opts=inline on the diagram block:
[syntrax,hyperlinked,svg,opts=interactive] .... jsyntrax( ... , [ ... ]) ....