Generating syntax diagrams using the LaTeX rail package

If you ever had the need to add syntax specifications to your document, you basically have two options: Either write down the syntax in the Backus-Naur form (BNF) (or one of its derivatives) or opt for a more graphical approach by adding “railroad diagrams”. In my opinon, the latter are easier to grasp for less experienced readers and also look quite nice.

In LaTeX, you can use the rail package to generate those diagrams from EBNF rules:

\begin{rail}
decl : 'def' identifier '=' ( expression + ';' )
     | 'type' identifier '=' type
     ;
\end{rail}

This will result in something like this:

Railroad diagram

To archieve this, the package first generates a *.rai file. We then have to convert the rai file to a *.rao by invoking the accompanying C program named rail.

However, the rail package is fairly old. It has been written by Luc Rooijakkers in 1991 (!) and was updated by Klaus Barthelmann until 1998. Thus, the code is – at least – 19 years old and that really shows: Trying to compile it on modern systems yields a bunch of compilation errors.

Most of the issues stem from missing return types in function declarations and also missing forward declarations. I stepped up and fixed these issues, so that it works with a up-to-date compiler (I tested with gcc (GCC) 6.3.1 on Arch Linux. You can find the result on Github.

I also threw in some Makefile improvements into the mix: You can now use DESTDIR and PREFIX (defaults to /usr/local) when running make install.

Installation

Installation should be fairly straighforward. Here’s an example which will install rail into /usr:

$ curl -L https://github.com/Holzhaus/latex-rail/archive/v1.2.1.tar.gz | tar xzvf -

$ cd latex-rail-1.2.1

$ make
bison -y  -dv gram.y
gram.y: warning: 2 reduce/reduce conflicts [-Wconflicts-rr]
cmp -s gram.c y.tab.c || cp y.tab.c gram.c
cmp -s gram.h y.tab.h || cp y.tab.h gram.h
gcc -DYYDEBUG -O   -c -o rail.o rail.c
gcc -DYYDEBUG -O   -c -o gram.o gram.c
flex  -t lex.l > lex.c
gcc -DYYDEBUG -O   -c -o lex.o lex.c
gcc -DYYDEBUG -O rail.o gram.o lex.o -o rail

$ sudo make PREFIX=/usr install
$ sudo mktexlsr

Please note that installing stuff using sudo make install will circumvent your package manager and is usually not a good idea. If you’re using Arch Linux you should use the AUR package instead:

$ pacaur -S latex-rail

Manual compilation and Latexmk support

To generate a document manually, you need to run multiple commands:

  1. Run latex mydoc, which will create mydoc.rai
  2. Run rail mydoc to generate mydoc.rao from mydoc.rai
  3. Run latex mydoc for the final document

If you don’t want to bother with running LaTeX multiple times, you can use latexmk, a perl script to automate the document generation.

To make it work with the rail package, you should create a .latexmkrc in your document folder with this content:

push @file_not_found, '^Package .* Info: No file (.+) on input line \d+\.';
add_cus_dep('rai', 'rao', 0, 'rail');
sub rail {
   my ($base_name, $path, $ext) = fileparse( $_[0], qr/\.[^.\/]*/ );
   pushd $path;
   my $return = system "rail $base_name";
   popd;
   return $return;
}

The first line will add the appropriate RegEx to Latexmk’s missing file detection, the second line will instruct latexmk to run the rail subroutine with a *.rai file as input and *.rao file as output.

Alternatives

I you don’t quite like the rail package, you might want to look into one of these alternative packages:

These also an online tool to generate railroad diagrams if you don’t want to do it in LaTeX.