doc-src/rail.sty
author nipkow
Fri, 23 Sep 2005 00:11:10 +0200
changeset 17591 33d409318266
parent 13044 c049910774cb
permissions -rw-r--r--
renamed rules to iprover

% rail.sty - style file to support railroad diagrams
%
% 09-Jul-90 L. Rooijakkers
% 08-Oct-90 L. Rooijakkers	fixed centering bug when \rail@tmpc<0.
% 07-Feb-91 L. Rooijakkers	added \railoptions command, indexing
% 08-Feb-91 L. Rooijakkers	minor fixes
% 28-Jun-94 K. Barthelmann	turned into LaTeX2e package
% 08-Dec-96 K. Barthelmann	replaced \@writefile
% 13-Dec-96 K. Barthelmann	cleanup
% 22-Feb-98 K. Barthelmann	fixed catcodes of special characters
% 18-Apr-98 K. Barthelmann	fixed \par handling
% 19-May-98 J. Olsson		Added new macros to support arrow heads.
% 26-Jul-98 K. Barthelmann	changed \par to output newlines
%
% This style file needs to be used in conjunction with the 'rail'
% program. Running LaTeX as 'latex file' produces file.rai, which should be
% processed by Rail with 'rail file'. This produces file.rao, which will
% be picked up by LaTeX on the next 'latex file' run.
%
% LaTeX will warn if there is no file.rao or it's out of date.
%
% The macros in this file thus consist of two parts: those that read and
% write the .rai and .rao files, and those that do the actual formatting
% of the railroad diagrams.

\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{rail}[1998/05/19]

% railroad diagram formatting parameters (user level)
% all of these are copied into their internal versions by \railinit
%
% \railunit : \unitlength within railroad diagrams
% \railextra : extra length at outside of diagram
% \railboxheight : height of ovals and frames
% \railboxskip : vertical space between lines
% \railboxleft : space to the left of a box
% \railboxright : space to the right of a box
% \railovalspace : extra space around contents of oval
% \railframespace : extra space around contents of frame
% \railtextleft : space to the left of text
% \railtextright : space to the right of text
% \railtextup : space to lift text up
% \railjoinsize : circle size of join/split arcs
% \railjoinadjust : space to adjust join
%
% \railnamesep : separator between name and rule body

\newlength\railunit
\newlength\railextra
\newlength\railboxheight
\newlength\railboxskip
\newlength\railboxleft
\newlength\railboxright
\newlength\railovalspace
\newlength\railframespace
\newlength\railtextleft
\newlength\railtextright
\newlength\railtextup
\newlength\railjoinsize
\newlength\railjoinadjust
\newlength\railnamesep

% initialize the parameters

\setlength\railunit{1sp}
\setlength\railextra{4ex}
\setlength\railboxleft{1ex}
\setlength\railboxright{1ex}
\setlength\railovalspace{2ex}
\setlength\railframespace{2ex}
\setlength\railtextleft{1ex}
\setlength\railtextright{1ex}
\setlength\railjoinadjust{0pt}
\setlength\railnamesep{1ex}

\DeclareOption{10pt}{
  \setlength\railboxheight{16pt}
  \setlength\railboxskip{24pt}
  \setlength\railtextup{5pt}
  \setlength\railjoinsize{16pt}
}
\DeclareOption{11pt}{
  \setlength\railboxheight{16pt}
  \setlength\railboxskip{24pt}
  \setlength\railtextup{5pt}
  \setlength\railjoinsize{16pt}
}
\DeclareOption{12pt}{
  \setlength\railboxheight{20pt}
  \setlength\railboxskip{28pt}
  \setlength\railtextup{6pt}
  \setlength\railjoinsize{20pt}
}

\ExecuteOptions{10pt}
\ProcessOptions

% internal versions of the formatting parameters
%
% \rail@extra   : \railextra
% \rail@boxht   : \railboxheight
% \rail@boxsp   : \railboxskip
% \rail@boxlf   : \railboxleft
% \rail@boxrt   : \railboxright
% \rail@boxhht  : \railboxheight / 2
% \rail@ovalsp  : \railovalspace
% \rail@framesp : \railframespace
% \rail@textlf  : \railtextleft
% \rail@textrt  : \railtextright
% \rail@textup  : \railtextup
% \rail@joinsz  : \railjoinsize
% \rail@joinhsz : \railjoinsize / 2
% \rail@joinadj : \railjoinadjust
%
% \railinit : internalize all of the parameters.

\newcount\rail@extra
\newcount\rail@boxht
\newcount\rail@boxsp
\newcount\rail@boxlf
\newcount\rail@boxrt
\newcount\rail@boxhht
\newcount\rail@ovalsp
\newcount\rail@framesp
\newcount\rail@textlf
\newcount\rail@textrt
\newcount\rail@textup
\newcount\rail@joinsz
\newcount\rail@joinhsz
\newcount\rail@joinadj

\newcommand\railinit{
\rail@extra=\railextra
\divide\rail@extra by \railunit
\rail@boxht=\railboxheight
\divide\rail@boxht by \railunit
\rail@boxsp=\railboxskip
\divide\rail@boxsp by \railunit
\rail@boxlf=\railboxleft
\divide\rail@boxlf by \railunit
\rail@boxrt=\railboxright
\divide\rail@boxrt by \railunit
\rail@boxhht=\railboxheight
\divide\rail@boxhht by \railunit
\divide\rail@boxhht by 2
\rail@ovalsp=\railovalspace
\divide\rail@ovalsp by \railunit
\rail@framesp=\railframespace
\divide\rail@framesp by \railunit
\rail@textlf=\railtextleft
\divide\rail@textlf by \railunit
\rail@textrt=\railtextright
\divide\rail@textrt by \railunit
\rail@textup=\railtextup
\divide\rail@textup by \railunit
\rail@joinsz=\railjoinsize
\divide\rail@joinsz by \railunit
\rail@joinhsz=\railjoinsize
\divide\rail@joinhsz by \railunit
\divide\rail@joinhsz by 2
\rail@joinadj=\railjoinadjust
\divide\rail@joinadj by \railunit
}

\AtBeginDocument{\railinit}

% \rail@param : declarations for list environment
%
% \railparam{TEXT} : sets \rail@param to TEXT
%
% \rail@reserved : characters reserved for grammar

\newcommand\railparam[1]{
\def\rail@param{
  \setlength\leftmargin{0pt}\setlength\rightmargin{0pt}
  \setlength\labelwidth{0pt}\setlength\labelsep{0pt}
  \setlength\itemindent{0pt}\setlength\listparindent{0pt}
  #1
}
}
\railparam{}

\newtoks\rail@reserved
\rail@reserved={:;|*+?[]()'"}

% \rail@termfont : format setup for terminals
%
% \rail@nontfont : format setup for nonterminals
%
% \rail@annofont : format setup for annotations
%
% \rail@rulefont : format setup for rule names
%
% \rail@indexfont : format setup for index entry
%
% \railtermfont{TEXT} : set terminal format setup to TEXT
%
% \railnontermfont{TEXT} : set nonterminal format setup to TEXT
%
% \railannotatefont{TEXT} : set annotation format setup to TEXT
%
% \railnamefont{TEXT} : set rule name format setup to TEXT
%
% \railindexfont{TEXT} : set index entry format setup to TEXT

\def\rail@termfont{\ttfamily\upshape}
\def\rail@nontfont{\rmfamily\upshape}
\def\rail@annofont{\rmfamily\itshape}
\def\rail@namefont{\rmfamily\itshape}
\def\rail@indexfont{\rmfamily\itshape}

\newcommand\railtermfont[1]{
\def\rail@termfont{#1}
}

\newcommand\railnontermfont[1]{
\def\rail@nontfont{#1}
}

\newcommand\railannotatefont[1]{
\def\rail@annofont{#1}
}

\newcommand\railnamefont[1]{
\def\rail@namefont{#1}
}

\newcommand\railindexfont[1]{
\def\rail@indexfont{#1}
}

% railroad read/write macros
%
% \begin{rail} TEXT \end{rail} : TEXT is written out to the .rai file,
%                                as \rail@i{NR}{TEXT}. Then the matching
%                                \rail@o{NR}{FMT} from the .rao file is
%                                executed (if defined).
%
% \railoptions{OPTIONS} : OPTIONS are written out to the .rai file,
%                         as \rail@p{OPTIONS}.
%
% \railterm{IDENT,IDENT,...} : format IDENT as terminals. writes out
%                              \rail@t{IDENT} to the .rai file
%
% \railalias{IDENT}{TEXT} : format IDENT as TEXT. defines \rail@t@IDENT as
%                           TEXT.
%
% \railtoken{IDENT}{TEXT} : abbreviates \railalias{IDENT}{TEXT}\railterm{IDENT}
%                           (for backward compatibility)
%
% \rail@setcodes : guards special characters
%
% \rail@makeother{CHARACTER} : sets \catcode of CHARACTER to "other"
%                              used inside a loop for \rail@setcodes
%
% \rail@nr : railroad diagram counter
%
% \ifrail@match : current \rail@i{NR}{TEXT} matches
%
% \rail@first : actions to be done first. read in .rao file,
%               open .rai file if \@filesw true, undefine \rail@first.
%               executed from \begin{rail}, \railoptions and \railterm.
%
% \rail@i{NR}{TEXT} : defines \rail@i@NR as TEXT. written to the .rai
%                     file by \rail, read from the .rao file by
%                     \rail@first
%
% \rail@t{IDENT} : tells Rail that IDENT is to be custom formatted,
%                  written to the .rai file by \railterm.
%
% \rail@o{NR}{TEXT} : defines \rail@o@NR as TEXT, read from the .rao
%                     file by \rail@first.
%
% \rail@p{OPTIONS} : pass options to rail, written to the .rai file by
%                    \railoptions
%
% \rail@write{TEXT} : write TEXT to the .rai file
%
% \rail@warn : warn user for mismatching diagrams
%
% \rail@endwarn : either \relax or \rail@warn
%
% \ifrail@all : checked at the end of the document

\def\rail@makeother#1{
  \expandafter\catcode\expandafter`\csname\string #1\endcsname=12
}

\def\rail@setcodes{
\let\par=\relax
\let\\=\relax
\expandafter\@tfor\expandafter\rail@symbol\expandafter:\expandafter=%
  \the\rail@reserved
\do{\expandafter\rail@makeother\rail@symbol}
}

\newcount\rail@nr

\newif\ifrail@all
\rail@alltrue

\newif\ifrail@match

\def\rail@first{
\begingroup
\makeatletter
\rail@setcodes
\InputIfFileExists{\jobname.rao}{}{\PackageInfo{rail}{No file \jobname.rao}}
\makeatother
\endgroup
\if@filesw
\newwrite\tf@rai
\immediate\openout\tf@rai=\jobname.rai
\fi
\global\let\rail@first=\relax
}

\long\def\rail@body#1\end{
{
\newlinechar=`^^J
\def\par{\string\par^^J}
\rail@write{\string\rail@i{\number\rail@nr}{#1}}
}
\xdef\rail@i@{#1}
\end
}

\newenvironment{rail}{
\global\advance\rail@nr by 1
\rail@first
\begingroup
\rail@setcodes
\rail@body
}{
\endgroup
\rail@matchtrue
\@ifundefined{rail@o@\number\rail@nr}{\rail@matchfalse}{}
\expandafter\ifx\csname rail@i@\number\rail@nr\endcsname\rail@i@
\else
\rail@matchfalse
\fi
\ifrail@match
\csname rail@o@\number\rail@nr\endcsname
\else
\PackageWarning{rail}{Railroad diagram {\number\rail@nr} doesn't match}
\global\let\rail@endwarn=\rail@warn
\begin{list}{}{\rail@param}
\rail@begin{1}{}
\rail@setbox{\bfseries ???}
\rail@oval
\rail@end
\end{list}
\fi
}

\newcommand\railoptions[1]{
\rail@first
\rail@write{\string\rail@p{#1}}
}

\newcommand\railterm[1]{
\rail@first
\@for\rail@@:=#1\do{
\rail@write{\string\rail@t{\rail@@}}
}
}

\newcommand\railalias[2]{
\expandafter\def\csname rail@t@#1\endcsname{#2}
}

\newcommand\railtoken[2]{\railalias{#1}{#2}\railterm{#1}}

\long\def\rail@i#1#2{
\expandafter\gdef\csname rail@i@#1\endcsname{#2}
}

\def\rail@o#1#2{
\expandafter\gdef\csname rail@o@#1\endcsname{
\begin{list}{}{\rail@param}
#2
\end{list}
}
}

\def\rail@t#1{}

\def\rail@p#1{}

\long\def\rail@write#1{\@ifundefined{tf@rai}{}{\immediate\write\tf@rai{#1}}}

\def\rail@warn{
\PackageWarningNoLine{rail}{Railroad diagram(s) may have changed.
                            Use 'rail' and rerun}
}

\let\rail@endwarn=\relax

\AtEndDocument{\rail@endwarn}

% index entry macro
%
% \rail@index{IDENT} : add index entry for IDENT

\def\rail@index#1{
\index{\rail@indexfont#1}
}

% railroad formatting primitives
%
% \rail@x : current x
% \rail@y : current y
% \rail@ex : current end x
% \rail@sx : starting x for \rail@cr
% \rail@rx : rightmost previous x for \rail@cr
%
% \rail@tmpa : temporary count
% \rail@tmpb : temporary count
% \rail@tmpc : temporary count
%
% \rail@put : put at (\rail@x,\rail@y)
% \rail@vput : put vector at (\rail@x,\rail@y)
%
% \rail@eline : end line by drawing from \rail@ex to \rail@x
%
% \rail@vreline : end line by drawing a vector from \rail@x to \rail@ex
%
% \rail@vleline : end line by drawing a vector from \rail@ex to \rail@x
%
% \rail@sety{LEVEL} : set \rail@y to level LEVEL

\newcount\rail@x
\newcount\rail@y
\newcount\rail@ex
\newcount\rail@sx
\newcount\rail@rx

\newcount\rail@tmpa
\newcount\rail@tmpb
\newcount\rail@tmpc

\def\rail@put{\put(\number\rail@x,\number\rail@y)}

\def\rail@vput{\put(\number\rail@ex,\number\rail@y)}

\def\rail@eline{
\rail@tmpb=\rail@x
\advance\rail@tmpb by -\rail@ex
\rail@put{\line(-1,0){\number\rail@tmpb}}
}

\def\rail@vreline{
\rail@tmpb=\rail@x
\advance\rail@tmpb by -\rail@ex
\rail@vput{\vector(1,0){\number\rail@tmpb}}
}

\def\rail@vleline{
\rail@tmpb=\rail@x
\advance\rail@tmpb by -\rail@ex
\rail@put{\vector(-1,0){\number\rail@tmpb}}
}

\def\rail@sety#1{
\rail@y=#1
\multiply\rail@y by -\rail@boxsp
\advance\rail@y by -\rail@boxht
}

% \rail@begin{HEIGHT}{NAME} : begin a railroad diagram of height HEIGHT
%
% \rail@end : end a railroad diagram
%
% \rail@expand{IDENT} : expand IDENT

\def\rail@begin#1#2{
\item
\begin{minipage}[t]{\linewidth}
\ifx\@empty#2\else
{\rail@namefont \rail@expand{#2}}\\*[\railnamesep]
\fi
\unitlength=\railunit
\rail@tmpa=#1
\multiply\rail@tmpa by \rail@boxsp
\begin{picture}(0,\number\rail@tmpa)(0,-\number\rail@tmpa)
\rail@ex=0
\rail@rx=0
\rail@x=\rail@extra
\rail@sx=\rail@x
\rail@sety{0}
}

\def\rail@end{
\advance\rail@x by \rail@extra
\rail@eline
\end{picture}
\end{minipage}
}

\def\rail@vend{
\advance\rail@x by \rail@extra
\rail@vreline
\end{picture}
\end{minipage}
}

\def\rail@expand#1{\@ifundefined{rail@t@#1}{#1}{\csname rail@t@#1\endcsname}}

% \rail@token{TEXT}[ANNOT] : format token TEXT with annotation
% \rail@ltoken{TEXT}[ANNOT] : format token TEXT with annotation, arrow left
% \rail@rtoken{TEXT}[ANNOT] : format token TEXT with annotation, arrow right
%
% \rail@ctoken{TEXT}[ANNOT] : format token TEXT centered with annotation
% \rail@lctoken{TEXT}[ANNOT] : format token TEXT centered with annotation, arrow left
% \rail@rctoken{TEXT}[ANNOT] : format token TEXT centered with annotation, arrow right
%
% \rail@nont{TEXT}[ANNOT] : format nonterminal TEXT with annotation
% \rail@lnont{TEXT}[ANNOT] : format nonterminal TEXT with annotation, arrow left
% \rail@rnont{TEXT}[ANNOT] : format nonterminal TEXT with annotation. arrow right
%
% \rail@cnont{TEXT}[ANNOT] : format nonterminal TEXT centered with annotation
% \rail@lcnont{TEXT}[ANNOT] : format nonterminal TEXT centered with annotation,
%                             arrow left
% \rail@rcnont{TEXT}[ANNOT] : format nonterminal TEXT centered with annotation,
%                             arrow right
%
% \rail@term{TEXT}[ANNOT] : format terminal TEXT with annotation
% \rail@lterm{TEXT}[ANNOT] : format terminal TEXT with annotation, arrow left
% \rail@rterm{TEXT}[ANNOT] : format terminal TEXT with annotation, arrow right
%
% \rail@cterm{TEXT}[ANNOT] : format terminal TEXT centered with annotation
% \rail@lcterm{TEXT}[ANNOT] : format terminal TEXT centered with annotation, arrow left
% \rail@rcterm{TEXT}[ANNOT] : format terminal TEXT centered with annotation,
%                             arrow right
%
% \rail@annote[TEXT] : format TEXT as annotation

\def\rail@token#1[#2]{
\rail@setbox{%
{\rail@termfont \rail@expand{#1}}\ifx\@empty#2\else\ {\rail@annofont #2}\fi
}
\rail@oval
}

\def\rail@ltoken#1[#2]{
\rail@setbox{%
{\rail@termfont \rail@expand{#1}}\ifx\@empty#2\else\ {\rail@annofont #2}\fi
}
\rail@vloval
}

\def\rail@rtoken#1[#2]{
\rail@setbox{%
{\rail@termfont \rail@expand{#1}}\ifx\@empty#2\else\ {\rail@annofont #2}\fi
}
\rail@vroval
}

\def\rail@ctoken#1[#2]{
\rail@setbox{%
{\rail@termfont \rail@expand{#1}}\ifx\@empty#2\else\ {\rail@annofont #2}\fi
}
\rail@coval
}

\def\rail@lctoken#1[#2]{
\rail@setbox{%
{\rail@termfont \rail@expand{#1}}\ifx\@empty#2\else\ {\rail@annofont #2}\fi
}
\rail@vlcoval
}

\def\rail@rctoken#1[#2]{
\rail@setbox{%
{\rail@termfont \rail@expand{#1}}\ifx\@empty#2\else\ {\rail@annofont #2}\fi
}
\rail@vrcoval
}

\def\rail@nont#1[#2]{
\rail@setbox{%
{\rail@nontfont \rail@expand{#1}}\ifx\@empty#2\else\ {\rail@annofont #2}\fi
}
\rail@frame
}

\def\rail@lnont#1[#2]{
\rail@setbox{%
{\rail@nontfont \rail@expand{#1}}\ifx\@empty#2\else\ {\rail@annofont #2}\fi
}
\rail@vlframe
}

\def\rail@rnont#1[#2]{
\rail@setbox{%
{\rail@nontfont \rail@expand{#1}}\ifx\@empty#2\else\ {\rail@annofont #2}\fi
}
\rail@vrframe
}

\def\rail@cnont#1[#2]{
\rail@setbox{%
{\rail@nontfont \rail@expand{#1}}\ifx\@empty#2\else\ {\rail@annofont #2}\fi
}
\rail@cframe
}

\def\rail@lcnont#1[#2]{
\rail@setbox{%
{\rail@nontfont \rail@expand{#1}}\ifx\@empty#2\else\ {\rail@annofont #2}\fi
}
\rail@vlcframe
}

\def\rail@rcnont#1[#2]{
\rail@setbox{%
{\rail@nontfont \rail@expand{#1}}\ifx\@empty#2\else\ {\rail@annofont #2}\fi
}
\rail@vrcframe
}

\def\rail@term#1[#2]{
\rail@setbox{%
{\rail@termfont #1}\ifx\@empty#2\else\ {\rail@annofont #2}\fi
}
\rail@oval
}

\def\rail@lterm#1[#2]{
\rail@setbox{%
{\rail@termfont #1}\ifx\@empty#2\else\ {\rail@annofont #2}\fi
}
\rail@vloval
}

\def\rail@rterm#1[#2]{
\rail@setbox{%
{\rail@termfont #1}\ifx\@empty#2\else\ {\rail@annofont #2}\fi
}
\rail@vroval
}

\def\rail@cterm#1[#2]{
\rail@setbox{%
{\rail@termfont #1}\ifx\@empty#2\else\ {\rail@annofont #2}\fi
}
\rail@coval
}

\def\rail@lcterm#1[#2]{
\rail@setbox{%
{\rail@termfont #1}\ifx\@empty#2\else\ {\rail@annofont #2}\fi
}
\rail@vlcoval
}

\def\rail@rcterm#1[#2]{
\rail@setbox{%
{\rail@termfont #1}\ifx\@empty#2\else\ {\rail@annofont #2}\fi
}
\rail@vrcoval
}

\def\rail@annote[#1]{
\rail@setbox{\rail@annofont #1}
\rail@text
}

% \rail@box : temporary box for \rail@oval and \rail@frame
%
% \rail@setbox{TEXT} : set \rail@box to TEXT, set \rail@tmpa to width
%
% \rail@oval : format \rail@box of width \rail@tmpa inside an oval
% \rail@vloval : format \rail@box of width \rail@tmpa inside an oval, vector left
% \rail@vroval : format \rail@box of width \rail@tmpa inside an oval, vector right
%
% \rail@coval : same as \rail@oval, but centered between \rail@x and
%               \rail@mx
% \rail@vlcoval : same as \rail@oval, but centered between \rail@x and
%                 \rail@mx, vector left
% \rail@vrcoval : same as \rail@oval, but centered between \rail@x and
%                 \rail@mx, vector right
%
% \rail@frame : format \rail@box of width \rail@tmpa inside a frame
% \rail@vlframe : format \rail@box of width \rail@tmpa inside a frame, vector left
% \rail@vrframe : format \rail@box of width \rail@tmpa inside a frame, vector right
%
% \rail@cframe : same as \rail@frame, but centered between \rail@x and
%                \rail@mx
% \rail@vlcframe : same as \rail@frame, but centered between \rail@x and
%                  \rail@mx, vector left
% \rail@vrcframe : same as \rail@frame, but centered between \rail@x and
%                  \rail@mx, vector right
%
% \rail@text : format \rail@box of width \rail@tmpa above the line

\newbox\rail@box

\def\rail@setbox#1{
\setbox\rail@box\hbox{\strut#1}
\rail@tmpa=\wd\rail@box
\divide\rail@tmpa by \railunit
}

\def\rail@oval{
\advance\rail@x by \rail@boxlf
\rail@eline
\advance\rail@tmpa by \rail@ovalsp
\ifnum\rail@tmpa<\rail@boxht\rail@tmpa=\rail@boxht\fi
\rail@tmpb=\rail@tmpa
\divide\rail@tmpb by 2
\advance\rail@y by -\rail@boxhht
\rail@put{\makebox(\number\rail@tmpa,\number\rail@boxht){\box\rail@box}}
\advance\rail@y by \rail@boxhht
\advance\rail@x by \rail@tmpb
\rail@put{\oval(\number\rail@tmpa,\number\rail@boxht)}
\advance\rail@x by \rail@tmpb
\rail@ex=\rail@x
\advance\rail@x by \rail@boxrt
}

\def\rail@vloval{
\advance\rail@x by \rail@boxlf
\rail@eline
\advance\rail@tmpa by \rail@ovalsp
\ifnum\rail@tmpa<\rail@boxht\rail@tmpa=\rail@boxht\fi
\rail@tmpb=\rail@tmpa
\divide\rail@tmpb by 2
\advance\rail@y by -\rail@boxhht
\rail@put{\makebox(\number\rail@tmpa,\number\rail@boxht){\box\rail@box}}
\advance\rail@y by \rail@boxhht
\advance\rail@x by \rail@tmpb
\rail@put{\oval(\number\rail@tmpa,\number\rail@boxht)}
\advance\rail@x by \rail@tmpb
\rail@ex=\rail@x
\advance\rail@x by \rail@boxrt
\rail@vleline
}

\def\rail@vroval{
\advance\rail@x by \rail@boxlf
\rail@vreline
\advance\rail@tmpa by \rail@ovalsp
\ifnum\rail@tmpa<\rail@boxht\rail@tmpa=\rail@boxht\fi
\rail@tmpb=\rail@tmpa
\divide\rail@tmpb by 2
\advance\rail@y by -\rail@boxhht
\rail@put{\makebox(\number\rail@tmpa,\number\rail@boxht){\box\rail@box}}
\advance\rail@y by \rail@boxhht
\advance\rail@x by \rail@tmpb
\rail@put{\oval(\number\rail@tmpa,\number\rail@boxht)}
\advance\rail@x by \rail@tmpb
\rail@ex=\rail@x
\advance\rail@x by \rail@boxrt
}

\def\rail@coval{
\rail@tmpb=\rail@tmpa
\advance\rail@tmpb by \rail@ovalsp
\ifnum\rail@tmpb<\rail@boxht\rail@tmpb=\rail@boxht\fi
\advance\rail@tmpb by \rail@boxlf
\advance\rail@tmpb by \rail@boxrt
\rail@tmpc=\rail@mx
\advance\rail@tmpc by -\rail@x
\advance\rail@tmpc by -\rail@tmpb
\divide\rail@tmpc by 2
\ifnum\rail@tmpc>0
\advance\rail@x by \rail@tmpc
\fi
\rail@oval
}

\def\rail@vlcoval{
\rail@tmpb=\rail@tmpa
\advance\rail@tmpb by \rail@ovalsp
\ifnum\rail@tmpb<\rail@boxht\rail@tmpb=\rail@boxht\fi
\advance\rail@tmpb by \rail@boxlf
\advance\rail@tmpb by \rail@boxrt
\rail@tmpc=\rail@mx
\advance\rail@tmpc by -\rail@x
\advance\rail@tmpc by -\rail@tmpb
\divide\rail@tmpc by 2
\ifnum\rail@tmpc>0
\advance\rail@x by \rail@tmpc
\fi
\rail@vloval
}

\def\rail@vrcoval{
\rail@tmpb=\rail@tmpa
\advance\rail@tmpb by \rail@ovalsp
\ifnum\rail@tmpb<\rail@boxht\rail@tmpb=\rail@boxht\fi
\advance\rail@tmpb by \rail@boxlf
\advance\rail@tmpb by \rail@boxrt
\rail@tmpc=\rail@mx
\advance\rail@tmpc by -\rail@x
\advance\rail@tmpc by -\rail@tmpb
\divide\rail@tmpc by 2
\ifnum\rail@tmpc>0
\advance\rail@x by \rail@tmpc
\fi
\rail@vroval
}

\def\rail@frame{
\advance\rail@x by \rail@boxlf
\rail@eline
\advance\rail@tmpa by \rail@framesp
\ifnum\rail@tmpa<\rail@boxht\rail@tmpa=\rail@boxht\fi
\advance\rail@y by -\rail@boxhht
\rail@put{\framebox(\number\rail@tmpa,\number\rail@boxht){\box\rail@box}}
\advance\rail@y by \rail@boxhht
\advance\rail@x by \rail@tmpa
\rail@ex=\rail@x
\advance\rail@x by \rail@boxrt
}

\def\rail@vlframe{
\advance\rail@x by \rail@boxlf
\rail@eline
\advance\rail@tmpa by \rail@framesp
\ifnum\rail@tmpa<\rail@boxht\rail@tmpa=\rail@boxht\fi
\advance\rail@y by -\rail@boxhht
\rail@put{\framebox(\number\rail@tmpa,\number\rail@boxht){\box\rail@box}}
\advance\rail@y by \rail@boxhht
\advance\rail@x by \rail@tmpa
\rail@ex=\rail@x
\advance\rail@x by \rail@boxrt
\rail@vleline
}

\def\rail@vrframe{
\advance\rail@x by \rail@boxlf
\rail@vreline
\advance\rail@tmpa by \rail@framesp
\ifnum\rail@tmpa<\rail@boxht\rail@tmpa=\rail@boxht\fi
\advance\rail@y by -\rail@boxhht
\rail@put{\framebox(\number\rail@tmpa,\number\rail@boxht){\box\rail@box}}
\advance\rail@y by \rail@boxhht
\advance\rail@x by \rail@tmpa
\rail@ex=\rail@x
\advance\rail@x by \rail@boxrt
}

\def\rail@cframe{
\rail@tmpb=\rail@tmpa
\advance\rail@tmpb by \rail@framesp
\ifnum\rail@tmpb<\rail@boxht\rail@tmpb=\rail@boxht\fi
\advance\rail@tmpb by \rail@boxlf
\advance\rail@tmpb by \rail@boxrt
\rail@tmpc=\rail@mx
\advance\rail@tmpc by -\rail@x
\advance\rail@tmpc by -\rail@tmpb
\divide\rail@tmpc by 2
\ifnum\rail@tmpc>0
\advance\rail@x by \rail@tmpc
\fi
\rail@frame
}

\def\rail@vlcframe{
\rail@tmpb=\rail@tmpa
\advance\rail@tmpb by \rail@framesp
\ifnum\rail@tmpb<\rail@boxht\rail@tmpb=\rail@boxht\fi
\advance\rail@tmpb by \rail@boxlf
\advance\rail@tmpb by \rail@boxrt
\rail@tmpc=\rail@mx
\advance\rail@tmpc by -\rail@x
\advance\rail@tmpc by -\rail@tmpb
\divide\rail@tmpc by 2
\ifnum\rail@tmpc>0
\advance\rail@x by \rail@tmpc
\fi
\rail@vlframe
}

\def\rail@vrcframe{
\rail@tmpb=\rail@tmpa
\advance\rail@tmpb by \rail@framesp
\ifnum\rail@tmpb<\rail@boxht\rail@tmpb=\rail@boxht\fi
\advance\rail@tmpb by \rail@boxlf
\advance\rail@tmpb by \rail@boxrt
\rail@tmpc=\rail@mx
\advance\rail@tmpc by -\rail@x
\advance\rail@tmpc by -\rail@tmpb
\divide\rail@tmpc by 2
\ifnum\rail@tmpc>0
\advance\rail@x by \rail@tmpc
\fi
\rail@vrframe
}

\def\rail@text{
\advance\rail@x by \rail@textlf
\advance\rail@y by \rail@textup
\rail@put{\box\rail@box}
\advance\rail@y by -\rail@textup
\advance\rail@x by \rail@tmpa
\advance\rail@x by \rail@textrt
}

% alternatives
%
% \rail@jx \rail@jy : current join point
%
% \rail@gx \rail@gy \rail@gex \rail@grx : global versions of \rail@x etc,
%                                         to pass values over group closings
%
% \rail@mx : maximum x so far
%
% \rail@sy : starting \rail@y for alternatives
%
% \rail@jput : put at (\rail@jx,\rail@jy)
%
% \rail@joval[PART] : put \oval[PART] with adjust

\newcount\rail@jx
\newcount\rail@jy

\newcount\rail@gx
\newcount\rail@gy
\newcount\rail@gex
\newcount\rail@grx

\newcount\rail@sy
\newcount\rail@mx

\def\rail@jput{
\put(\number\rail@jx,\number\rail@jy)
}

\def\rail@joval[#1]{
\advance\rail@jx by \rail@joinadj
\rail@jput{\oval(\number\rail@joinsz,\number\rail@joinsz)[#1]}
\advance\rail@jx by -\rail@joinadj
}

% \rail@barsplit : incoming split for '|'
%
% \rail@plussplit : incoming split for '+'
%

\def\rail@barsplit{
\advance\rail@jy by -\rail@joinhsz
\rail@joval[tr]
\advance\rail@jx by \rail@joinhsz
}

\def\rail@plussplit{
\advance\rail@jy by -\rail@joinhsz
\advance\rail@jx by \rail@joinsz
\rail@joval[tl]
\advance\rail@jx by -\rail@joinhsz
}

% \rail@alt{SPLIT} : start alternatives with incoming split SPLIT
%

\def\rail@alt#1{
\rail@sy=\rail@y
\rail@jx=\rail@x
\rail@jy=\rail@y
\advance\rail@x by \rail@joinsz
\rail@mx=0
\let\rail@list=\@empty
\let\rail@comma=\@empty
\let\rail@split=#1
\begingroup
\rail@sx=\rail@x
\rail@rx=0
}

% \rail@nextalt{FIX}{Y} : start next alternative at vertical position Y
%                         and fix-up FIX
%

\def\rail@nextalt#1#2{
\global\rail@gx=\rail@x
\global\rail@gy=\rail@y
\global\rail@gex=\rail@ex
\global\rail@grx=\rail@rx
\endgroup
#1
\ifnum\rail@gx>\rail@mx\rail@mx=\rail@gx\fi
\ifnum\rail@grx>\rail@mx\rail@mx=\rail@grx\fi
\edef\rail@list{\rail@list\rail@comma\number\rail@gex:\number\rail@gy}
\def\rail@comma{,}
\rail@split
\let\rail@split=\@empty
\rail@sety{#2}
\rail@tmpa=\rail@jy
\advance\rail@tmpa by -\rail@y
\advance\rail@tmpa by -\rail@joinhsz
\rail@jput{\line(0,-1){\number\rail@tmpa}}
\rail@jy=\rail@y
\advance\rail@jy by \rail@joinhsz
\advance\rail@jx by \rail@joinhsz
\rail@joval[bl]
\advance\rail@jx by -\rail@joinhsz
\rail@ex=\rail@x
\begingroup
\rail@sx=\rail@x
\rail@rx=0
}

% \rail@barjoin : outgoing join for first '|' alternative
%
% \rail@plusjoin : outgoing join for first '+' alternative
%
% \rail@altjoin : join for subsequent alternative
%

\def\rail@barjoin{
\ifnum\rail@y<\rail@sy
\global\rail@gex=\rail@jx
\else
\global\rail@gex=\rail@ex
\fi
\advance\rail@jy by -\rail@joinhsz
\rail@joval[tl]
\advance\rail@jx by -\rail@joinhsz
\ifnum\rail@y<\rail@sy
\rail@altjoin
\fi
}

\def\rail@plusjoin{
\global\rail@gex=\rail@ex
\advance\rail@jy by -\rail@joinhsz
\advance\rail@jx by -\rail@joinsz
\rail@joval[tr]
\advance\rail@jx by \rail@joinhsz
}

\def\rail@altjoin{
\rail@eline
\rail@tmpa=\rail@jy
\advance\rail@tmpa by -\rail@y
\advance\rail@tmpa by -\rail@joinhsz
\rail@jput{\line(0,-1){\number\rail@tmpa}}
\rail@jy=\rail@y
\advance\rail@jy by \rail@joinhsz
\advance\rail@jx by -\rail@joinhsz
\rail@joval[br]
\advance\rail@jx by \rail@joinhsz
}

% \rail@eltsplit EX:Y; : split EX:Y into \rail@ex \rail@y
%
% \rail@endalt{JOIN} : end alternatives with outgoing join JOIN

\def\rail@eltsplit#1:#2;{\rail@ex=#1\rail@y=#2}

\def\rail@endalt#1{
\global\rail@gx=\rail@x
\global\rail@gy=\rail@y
\global\rail@gex=\rail@ex
\global\rail@grx=\rail@rx
\endgroup
\ifnum\rail@gx>\rail@mx\rail@mx=\rail@gx\fi
\ifnum\rail@grx>\rail@mx\rail@mx=\rail@grx\fi
\edef\rail@list{\rail@list\rail@comma\number\rail@gex:\number\rail@gy}
\rail@x=\rail@mx
\rail@jx=\rail@x
\rail@jy=\rail@sy
\advance\rail@jx by \rail@joinsz
\let\rail@join=#1
\@for\rail@elt:=\rail@list\do{
\expandafter\rail@eltsplit\rail@elt;
\rail@join
\let\rail@join=\rail@altjoin
}
\rail@x=\rail@mx
\rail@y=\rail@sy
\rail@ex=\rail@gex
\advance\rail@x by \rail@joinsz
}

% \rail@bar : start '|' alternatives
%
% \rail@nextbar : next '|' alternative
%
% \rail@endbar : end '|' alternatives
%

\def\rail@bar{
\rail@alt\rail@barsplit
}

\def\rail@nextbar{
\rail@nextalt\relax
}

\def\rail@endbar{
\rail@endalt\rail@barjoin
}

% \rail@plus : start '+' alternatives
%
% \rail@nextplus: next '+' alternative
%
% \rail@endplus : end '+' alternatives
%

\def\rail@plus{
\rail@alt\rail@plussplit
}

\def\rail@nextplus{
\rail@nextalt\rail@fixplus
}

\def\rail@fixplus{
\ifnum\rail@gy<\rail@sy
\begingroup
\rail@x=\rail@gx
\rail@y=\rail@gy
\rail@ex=\rail@gex
\rail@rx=\rail@grx
\ifnum\rail@x<\rail@rx
\rail@x=\rail@rx
\fi
\rail@eline
\rail@jx=\rail@x
\rail@jy=\rail@y
\advance\rail@jy by \rail@joinhsz
\rail@joval[br]
\advance\rail@jx by \rail@joinhsz
\rail@tmpa=\rail@sy
\advance\rail@tmpa by -\rail@joinhsz
\advance\rail@tmpa by -\rail@jy
\rail@jput{\line(0,1){\number\rail@tmpa}}
\rail@jy=\rail@sy
\advance\rail@jy by -\rail@joinhsz
\advance\rail@jx by \rail@joinhsz
\rail@joval[tl]
\advance\rail@jy by \rail@joinhsz
\global\rail@gx=\rail@jx
\global\rail@gy=\rail@jy
\global\rail@gex=\rail@gx
\global\rail@grx=\rail@rx
\endgroup
\fi
}

\def\rail@endplus{
\rail@endalt\rail@plusjoin
}

% \rail@cr{Y} : carriage return to vertical position Y

\def\rail@cr#1{
\rail@tmpa=\rail@sx
\advance\rail@tmpa by \rail@joinsz
\ifnum\rail@x<\rail@tmpa\rail@x=\rail@tmpa\fi
\rail@eline
\rail@jx=\rail@x
\rail@jy=\rail@y
\advance\rail@x by \rail@joinsz
\ifnum\rail@x>\rail@rx\rail@rx=\rail@x\fi
\advance\rail@jy by -\rail@joinhsz
\rail@joval[tr]
\advance\rail@jx by \rail@joinhsz
\rail@sety{#1}
\rail@tmpa=\rail@jy
\advance\rail@tmpa by -\rail@y
\advance\rail@tmpa by -\rail@boxsp
\advance\rail@tmpa by -\rail@joinhsz
\rail@jput{\line(0,-1){\number\rail@tmpa}}
\rail@jy=\rail@y
\advance\rail@jy by \rail@boxsp
\advance\rail@jy by \rail@joinhsz
\advance\rail@jx by -\rail@joinhsz
\rail@joval[br]
\advance\rail@jy by -\rail@joinhsz
\rail@tmpa=\rail@jx
\advance\rail@tmpa by -\rail@sx
\advance\rail@tmpa by -\rail@joinhsz
\rail@jput{\line(-1,0){\number\rail@tmpa}}
\rail@jx=\rail@sx
\advance\rail@jx by \rail@joinhsz
\advance\rail@jy by -\rail@joinhsz
\rail@joval[tl]
\advance\rail@jx by -\rail@joinhsz
\rail@tmpa=\rail@boxsp
\advance\rail@tmpa by -\rail@joinsz
\rail@jput{\line(0,-1){\number\rail@tmpa}}
\advance\rail@jy by -\rail@tmpa
\advance\rail@jx by \rail@joinhsz
\rail@joval[bl]
\rail@x=\rail@jx
\rail@ex=\rail@x
}