1 % rail.sty - style file to support railroad diagrams
3 % 09-Jul-90 L. Rooijakkers
4 % 08-Oct-90 L. Rooijakkers fixed centering bug when \rail@tmpc<0.
5 % 07-Feb-91 L. Rooijakkers added \railoptions command, indexing
6 % 08-Feb-91 L. Rooijakkers minor fixes
7 % 28-Jun-94 K. Barthelmann turned into LaTeX2e package
8 % 08-Dec-96 K. Barthelmann replaced \@writefile
9 % 13-Dec-96 K. Barthelmann cleanup
11 % This style file needs to be used in conjunction with the 'rail'
12 % program. Running LaTeX as 'latex file' produces file.rai, which should be
13 % processed by Rail with 'rail file'. This produces file.rao, which will
14 % be picked up by LaTeX on the next 'latex file' run.
16 % LaTeX will warn if there is no file.rao or it's out of date.
18 % The macros in this file thus consist of two parts: those that read and
19 % write the .rai and .rao files, and those that do the actual formatting
20 % of the railroad diagrams.
22 \NeedsTeXFormat{LaTeX2e}
23 \ProvidesPackage{rail}[1996/12/13]
25 % railroad diagram formatting parameters (user level)
26 % all of these are copied into their internal versions by \railinit
28 % \railunit : \unitlength within railroad diagrams
29 % \railextra : extra length at outside of diagram
30 % \railboxheight : height of ovals and frames
31 % \railboxskip : vertical space between lines
32 % \railboxleft : space to the left of a box
33 % \railboxright : space to the right of a box
34 % \railovalspace : extra space around contents of oval
35 % \railframespace : extra space around contents of frame
36 % \railtextleft : space to the left of text
37 % \railtextright : space to the right of text
38 % \railtextup : space to lift text up
39 % \railjoinsize : circle size of join/split arcs
40 % \railjoinadjust : space to adjust join
42 % \railnamesep : separator between name and rule body
46 \newlength\railboxheight
47 \newlength\railboxskip
48 \newlength\railboxleft
49 \newlength\railboxright
50 \newlength\railovalspace
51 \newlength\railframespace
52 \newlength\railtextleft
53 \newlength\railtextright
55 \newlength\railjoinsize
56 \newlength\railjoinadjust
57 \newlength\railnamesep
59 % initialize the parameters
61 \setlength\railunit{1sp}
62 \setlength\railextra{4ex}
63 \setlength\railboxleft{1ex}
64 \setlength\railboxright{1ex}
65 \setlength\railovalspace{2ex}
66 \setlength\railframespace{2ex}
67 \setlength\railtextleft{1ex}
68 \setlength\railtextright{1ex}
69 \setlength\railjoinadjust{0pt}
70 \setlength\railnamesep{1ex}
73 \setlength\railboxheight{16pt}
74 \setlength\railboxskip{24pt}
75 \setlength\railtextup{5pt}
76 \setlength\railjoinsize{16pt}
79 \setlength\railboxheight{16pt}
80 \setlength\railboxskip{24pt}
81 \setlength\railtextup{5pt}
82 \setlength\railjoinsize{16pt}
85 \setlength\railboxheight{20pt}
86 \setlength\railboxskip{28pt}
87 \setlength\railtextup{6pt}
88 \setlength\railjoinsize{20pt}
94 % internal versions of the formatting parameters
96 % \rail@extra : \railextra
97 % \rail@boxht : \railboxheight
98 % \rail@boxsp : \railboxskip
99 % \rail@boxlf : \railboxleft
100 % \rail@boxrt : \railboxright
101 % \rail@boxhht : \railboxheight / 2
102 % \rail@ovalsp : \railovalspace
103 % \rail@framesp : \railframespace
104 % \rail@textlf : \railtextleft
105 % \rail@textrt : \railtextright
106 % \rail@textup : \railtextup
107 % \rail@joinsz : \railjoinsize
108 % \rail@joinhsz : \railjoinsize / 2
109 % \rail@joinadj : \railjoinadjust
111 % \railinit : internalize all of the parameters.
118 \newcount\rail@boxhht
119 \newcount\rail@ovalsp
120 \newcount\rail@framesp
121 \newcount\rail@textlf
122 \newcount\rail@textrt
123 \newcount\rail@textup
124 \newcount\rail@joinsz
125 \newcount\rail@joinhsz
126 \newcount\rail@joinadj
128 \newcommand\railinit{
129 \rail@extra=\railextra
130 \divide\rail@extra by \railunit
131 \rail@boxht=\railboxheight
132 \divide\rail@boxht by \railunit
133 \rail@boxsp=\railboxskip
134 \divide\rail@boxsp by \railunit
135 \rail@boxlf=\railboxleft
136 \divide\rail@boxlf by \railunit
137 \rail@boxrt=\railboxright
138 \divide\rail@boxrt by \railunit
139 \rail@boxhht=\railboxheight
140 \divide\rail@boxhht by \railunit
141 \divide\rail@boxhht by 2
142 \rail@ovalsp=\railovalspace
143 \divide\rail@ovalsp by \railunit
144 \rail@framesp=\railframespace
145 \divide\rail@framesp by \railunit
146 \rail@textlf=\railtextleft
147 \divide\rail@textlf by \railunit
148 \rail@textrt=\railtextright
149 \divide\rail@textrt by \railunit
150 \rail@textup=\railtextup
151 \divide\rail@textup by \railunit
152 \rail@joinsz=\railjoinsize
153 \divide\rail@joinsz by \railunit
154 \rail@joinhsz=\railjoinsize
155 \divide\rail@joinhsz by \railunit
156 \divide\rail@joinhsz by 2
157 \rail@joinadj=\railjoinadjust
158 \divide\rail@joinadj by \railunit
161 \AtBeginDocument{\railinit}
163 % \rail@param : declarations for list environment
165 % \railparam{TEXT} : sets \rail@param to TEXT
169 \newcommand\railparam[1]{
173 % \rail@tokenfont : format setup for \railtoken identifiers
175 % \rail@termfont : format setup for terminals
177 % \rail@nontfont : format setup for nonterminals
179 % \rail@annofont : format setup for annotations
181 % \rail@rulefont : format setup for rule names
183 % \rail@indexfont : format setup for index entry
185 % \railtermfont{TEXT} : set terminal format setup to TEXT
187 % \railnontermfont{TEXT} : set nonterminal format setup to TEXT
189 % \railannotatefont{TEXT} : set annotation format setup to TEXT
191 % \railnamefont{TEXT} : set rule name format setup to TEXT
193 % \railindexfont{TEXT} : set index entry format setup to TEXT
195 \def\rail@termfont{\ttfamily\upshape}
196 \def\rail@nontfont{\rmfamily\upshape}
197 \def\rail@annofont{\rmfamily\itshape}
198 \def\rail@namefont{\rmfamily\itshape}
199 \def\rail@indexfont{\rmfamily\itshape}
201 \newcommand\railtermfont[1]{
202 \def\rail@termfont{#1}
205 \newcommand\railnontermfont[1]{
206 \def\rail@nontfont{#1}
209 \newcommand\railannotatefont[1]{
210 \def\rail@annofont{#1}
213 \newcommand\railnamefont[1]{
214 \def\rail@namefont{#1}
217 \newcommand\railindexfont[1]{
218 \def\rail@indexfont{#1}
221 % railroad read/write macros
223 % \begin{rail} TEXT \end{rail} : TEXT is written out to the .rai file,
224 % as \rail@i{NR}{TEXT}. Then the matching
225 % \rail@o{NR}{FMT} from the .rao file is
226 % executed (if defined).
228 % \railoptions{OPTIONS} : OPTIONS are written out to the .rai file,
229 % as \rail@p{OPTIONS}.
231 % \railterm{IDENT,IDENT,...} : format IDENT as terminals. writes out
232 % \rail@t{IDENT} to the .rai file
234 % \railalias{IDENT}{TEXT} : format IDENT as TEXT. defines \rail@t@IDENT as
237 % \rail@nr : railroad diagram counter
239 % \ifrail@match : current \rail@i{NR}{TEXT} matches
241 % \rail@first : actions to be done first. read in .rao file,
242 % open .rai file if \@filesw true, undefine \rail@first.
243 % executed from \begin{rail} and \railtoken.
245 % \rail@i{NR}{TEXT} : defines \rail@i@NR as TEXT. written to the .rai
246 % file by \rail, read from the .rao file by
249 % \rail@t{IDENT} : tells Rail that IDENT is to be custom formatted,
250 % written to the .rai file by \railterm.
252 % \rail@o{NR}{TEXT} : defines \rail@o@NR as TEXT, read from the .rao
253 % file by \rail@first.
255 % \rail@p{OPTIONS} : pass options to rail, written to the .rai file by
258 % \rail@write{TEXT} : write TEXT to the .rai file
260 % \rail@warn : warn user for mismatching diagrams
262 % \rail@endwarn : either \relax or \rail@warn
264 % \ifrail@all : checked at the end of the document
275 \InputIfFileExists{\jobname.rao}{}{\PackageInfo{rail}{No file \jobname.rao}}
279 \immediate\openout\tf@rai=\jobname.rai
281 \global\let\rail@first=\relax
284 \long\def\rail@body#1\end{
288 \rail@write{\string\rail@i{\number\rail@nr}{\rail@i@}}
293 \newenvironment{rail}{
294 \global\advance\rail@nr by 1
299 \@ifundefined{rail@o@\number\rail@nr}{\rail@matchfalse}{}
300 \expandafter\ifx\csname rail@i@\number\rail@nr\endcsname\rail@i@
305 \csname rail@o@\number\rail@nr\endcsname
307 \PackageWarning{rail}{Railroad diagram {\number\rail@nr} doesn't match}
308 \global\let\rail@endwarn=\rail@warn
309 \begin{list}{}{\rail@param}
311 \rail@setbox{\bfseries ???}
318 \newcommand\railoptions[1]{
320 \rail@write{\string\rail@p{#1}}
323 \newcommand\railterm[1]{
326 \rail@write{\string\rail@t{\rail@@}}
330 \newcommand\railalias[2]{
331 \expandafter\def\csname rail@t@#1\endcsname{#2}
334 \long\def\rail@i#1#2{
335 \expandafter\gdef\csname rail@i@#1\endcsname{#2}
339 \expandafter\gdef\csname rail@o@#1\endcsname{
340 \begin{list}{}{\rail@param}#2\end{list}
348 \def\rail@write#1{\@ifundefined{tf@rai}{}{\immediate\write\tf@rai{#1}}}
351 \PackageWarningNoLine{rail}{Railroad diagram(s) may have changed.
352 Use 'rail' and rerun}
355 \let\rail@endwarn=\relax
357 \AtEndDocument{\rail@endwarn}
361 % \rail@index{IDENT} : add index entry for IDENT
364 \index{\rail@indexfont#1}
367 % railroad formatting primitives
369 % \rail@x : current x
370 % \rail@y : current y
371 % \rail@ex : current end x
372 % \rail@sx : starting x for \rail@cr
373 % \rail@rx : rightmost previous x for \rail@cr
375 % \rail@tmpa : temporary count
376 % \rail@tmpb : temporary count
377 % \rail@tmpc : temporary count
379 % \rail@put : put at (\rail@x,\rail@y)
381 % \rail@eline : end line by drawing from \rail@ex to \rail@x
383 % \rail@sety{LEVEL} : set \rail@y to level LEVEL
395 \def\rail@put{\put(\number\rail@x,\number\rail@y)}
399 \advance\rail@tmpb by -\rail@ex
400 \rail@put{\line(-1,0){\number\rail@tmpb}}
405 \multiply\rail@y by -\rail@boxsp
406 \advance\rail@y by -\rail@boxht
409 % \rail@begin{HEIGHT}{NAME} : begin a railroad diagram of height HEIGHT
411 % \rail@end : end a railroad diagram
413 % \rail@expand{IDENT} : expand IDENT
417 \begin{minipage}[t]{\linewidth}
419 {\rail@namefont \rail@expand{#2}}\\*[\railnamesep]
421 \unitlength=\railunit
423 \multiply\rail@tmpa by \rail@boxsp
424 \begin{picture}(0,\number\rail@tmpa)(0,-\number\rail@tmpa)
433 \advance\rail@x by \rail@extra
439 \def\rail@expand#1{\@ifundefined{rail@t@#1}{#1}{\csname rail@t@#1\endcsname}}
441 % \rail@token{TEXT}[ANNOT] : format token TEXT with annotation
443 % \rail@ctoken{TEXT}[ANNOT] : format token TEXT centered with annotation
445 % \rail@nont{TEXT}[ANNOT] : format nonterminal TEXT with annotation
447 % \rail@cnont{TEXT}[ANNOT] : format nonterminal TEXT centered with annotation
449 % \rail@term{TEXT}[ANNOT] : format terminal TEXT with annotation
451 % \rail@cterm{TEXT}[ANNOT] : format terminal TEXT centered with annotation
453 % \rail@annote[TEXT] : format TEXT as annotation
455 \def\rail@token#1[#2]{
457 {\rail@termfont \rail@expand{#1}}\ifx\@empty#2\else\ {\rail@annofont #2}\fi
462 \def\rail@ctoken#1[#2]{
464 {\rail@termfont \rail@expand{#1}}\ifx\@empty#2\else\ {\rail@annofont #2}\fi
469 \def\rail@nont#1[#2]{
471 {\rail@nontfont \rail@expand{#1}}\ifx\@empty#2\else\ {\rail@annofont #2}\fi
476 \def\rail@cnont#1[#2]{
478 {\rail@nontfont \rail@expand{#1}}\ifx\@empty#2\else\ {\rail@annofont #2}\fi
483 \def\rail@term#1[#2]{
485 {\rail@termfont #1}\ifx\@empty#2\else\ {\rail@annofont #2}\fi
490 \def\rail@cterm#1[#2]{
492 {\rail@termfont #1}\ifx\@empty#2\else\ {\rail@annofont #2}\fi
497 \def\rail@annote[#1]{
498 \rail@setbox{\rail@annofont #1}
502 % \rail@box : temporary box for \rail@oval and \rail@frame
504 % \rail@setbox{TEXT} : set \rail@box to TEXT, set \rail@tmpa to width
506 % \rail@oval : format \rail@box of width \rail@tmpa inside an oval
508 % \rail@coval : same as \rail@oval, but centered between \rail@x and
511 % \rail@frame : format \rail@box of width \rail@tmpa inside a frame
513 % \rail@cframe : same as \rail@frame, but centered between \rail@x and
516 % \rail@text : format \rail@box of width \rail@tmpa above the line
521 \setbox\rail@box\hbox{\strut#1}
522 \rail@tmpa=\wd\rail@box
523 \divide\rail@tmpa by \railunit
527 \advance\rail@x by \rail@boxlf
529 \advance\rail@tmpa by \rail@ovalsp
530 \ifnum\rail@tmpa<\rail@boxht\rail@tmpa=\rail@boxht\fi
531 \rail@tmpb=\rail@tmpa
532 \divide\rail@tmpb by 2
533 \advance\rail@y by -\rail@boxhht
534 \rail@put{\makebox(\number\rail@tmpa,\number\rail@boxht){\box\rail@box}}
535 \advance\rail@y by \rail@boxhht
536 \advance\rail@x by \rail@tmpb
537 \rail@put{\oval(\number\rail@tmpa,\number\rail@boxht)}
538 \advance\rail@x by \rail@tmpb
540 \advance\rail@x by \rail@boxrt
544 \rail@tmpb=\rail@tmpa
545 \advance\rail@tmpb by \rail@ovalsp
546 \ifnum\rail@tmpb<\rail@boxht\rail@tmpb=\rail@boxht\fi
547 \advance\rail@tmpb by \rail@boxlf
548 \advance\rail@tmpb by \rail@boxrt
550 \advance\rail@tmpc by -\rail@x
551 \advance\rail@tmpc by -\rail@tmpb
552 \divide\rail@tmpc by 2
554 \advance\rail@x by \rail@tmpc
560 \advance\rail@x by \rail@boxlf
562 \advance\rail@tmpa by \rail@framesp
563 \ifnum\rail@tmpa<\rail@boxht\rail@tmpa=\rail@boxht\fi
564 \advance\rail@y by -\rail@boxhht
565 \rail@put{\framebox(\number\rail@tmpa,\number\rail@boxht){\box\rail@box}}
566 \advance\rail@y by \rail@boxhht
567 \advance\rail@x by \rail@tmpa
569 \advance\rail@x by \rail@boxrt
573 \rail@tmpb=\rail@tmpa
574 \advance\rail@tmpb by \rail@framesp
575 \ifnum\rail@tmpb<\rail@boxht\rail@tmpb=\rail@boxht\fi
576 \advance\rail@tmpb by \rail@boxlf
577 \advance\rail@tmpb by \rail@boxrt
579 \advance\rail@tmpc by -\rail@x
580 \advance\rail@tmpc by -\rail@tmpb
581 \divide\rail@tmpc by 2
583 \advance\rail@x by \rail@tmpc
589 \advance\rail@x by \rail@textlf
590 \advance\rail@y by \rail@textup
591 \rail@put{\box\rail@box}
592 \advance\rail@y by -\rail@textup
593 \advance\rail@x by \rail@tmpa
594 \advance\rail@x by \rail@textrt
599 % \rail@jx \rail@jy : current join point
601 % \rail@gx \rail@gy \rail@gex \rail@grx : global versions of \rail@x etc,
602 % to pass values over group closings
604 % \rail@mx : maximum x so far
606 % \rail@sy : starting \rail@y for alternatives
608 % \rail@jput : put at (\rail@jx,\rail@jy)
610 % \rail@joval[PART] : put \oval[PART] with adjust
624 \put(\number\rail@jx,\number\rail@jy)
628 \advance\rail@jx by \rail@joinadj
629 \rail@jput{\oval(\number\rail@joinsz,\number\rail@joinsz)[#1]}
630 \advance\rail@jx by -\rail@joinadj
633 % \rail@barsplit : incoming split for '|'
635 % \rail@plussplit : incoming split for '+'
639 \advance\rail@jy by -\rail@joinhsz
641 \advance\rail@jx by \rail@joinhsz
645 \advance\rail@jy by -\rail@joinhsz
646 \advance\rail@jx by \rail@joinsz
648 \advance\rail@jx by -\rail@joinhsz
651 % \rail@alt{SPLIT} : start alternatives with incoming split SPLIT
658 \advance\rail@x by \rail@joinsz
660 \let\rail@list=\@empty
661 \let\rail@comma=\@empty
668 % \rail@nextalt{FIX}{Y} : start next alternative at vertical position Y
672 \def\rail@nextalt#1#2{
673 \global\rail@gx=\rail@x
674 \global\rail@gy=\rail@y
675 \global\rail@gex=\rail@ex
676 \global\rail@grx=\rail@rx
679 \ifnum\rail@gx>\rail@mx\rail@mx=\rail@gx\fi
680 \ifnum\rail@grx>\rail@mx\rail@mx=\rail@grx\fi
681 \edef\rail@list{\rail@list\rail@comma\number\rail@gex:\number\rail@gy}
684 \let\rail@split=\@empty
687 \advance\rail@tmpa by -\rail@y
688 \advance\rail@tmpa by -\rail@joinhsz
689 \rail@jput{\line(0,-1){\number\rail@tmpa}}
691 \advance\rail@jy by \rail@joinhsz
692 \advance\rail@jx by \rail@joinhsz
694 \advance\rail@jx by -\rail@joinhsz
701 % \rail@barjoin : outgoing join for first '|' alternative
703 % \rail@plusjoin : outgoing join for first '+' alternative
705 % \rail@altjoin : join for subsequent alternative
709 \ifnum\rail@y<\rail@sy
710 \global\rail@gex=\rail@jx
712 \global\rail@gex=\rail@ex
714 \advance\rail@jy by -\rail@joinhsz
716 \advance\rail@jx by -\rail@joinhsz
717 \ifnum\rail@y<\rail@sy
723 \global\rail@gex=\rail@ex
724 \advance\rail@jy by -\rail@joinhsz
725 \advance\rail@jx by -\rail@joinsz
727 \advance\rail@jx by \rail@joinhsz
733 \advance\rail@tmpa by -\rail@y
734 \advance\rail@tmpa by -\rail@joinhsz
735 \rail@jput{\line(0,-1){\number\rail@tmpa}}
737 \advance\rail@jy by \rail@joinhsz
738 \advance\rail@jx by -\rail@joinhsz
740 \advance\rail@jx by \rail@joinhsz
743 % \rail@eltsplit EX:Y; : split EX:Y into \rail@ex \rail@y
745 % \rail@endalt{JOIN} : end alternatives with outgoing join JOIN
747 \def\rail@eltsplit#1:#2;{\rail@ex=#1\rail@y=#2}
750 \global\rail@gx=\rail@x
751 \global\rail@gy=\rail@y
752 \global\rail@gex=\rail@ex
753 \global\rail@grx=\rail@rx
755 \ifnum\rail@gx>\rail@mx\rail@mx=\rail@gx\fi
756 \ifnum\rail@grx>\rail@mx\rail@mx=\rail@grx\fi
757 \edef\rail@list{\rail@list\rail@comma\number\rail@gex:\number\rail@gy}
761 \advance\rail@jx by \rail@joinsz
763 \@for\rail@elt:=\rail@list\do{
764 \expandafter\rail@eltsplit\rail@elt;
766 \let\rail@join=\rail@altjoin
771 \advance\rail@x by \rail@joinsz
774 % \rail@bar : start '|' alternatives
776 % \rail@nextbar : next '|' alternative
778 % \rail@endbar : end '|' alternatives
782 \rail@alt\rail@barsplit
790 \rail@endalt\rail@barjoin
793 % \rail@plus : start '+' alternatives
795 % \rail@nextplus: next '+' alternative
797 % \rail@endplus : end '+' alternatives
801 \rail@alt\rail@plussplit
805 \rail@nextalt\rail@fixplus
809 \ifnum\rail@gy<\rail@sy
815 \ifnum\rail@x<\rail@rx
821 \advance\rail@jy by \rail@joinhsz
823 \advance\rail@jx by \rail@joinhsz
825 \advance\rail@tmpa by -\rail@joinhsz
826 \advance\rail@tmpa by -\rail@jy
827 \rail@jput{\line(0,1){\number\rail@tmpa}}
829 \advance\rail@jy by -\rail@joinhsz
830 \advance\rail@jx by \rail@joinhsz
832 \advance\rail@jy by \rail@joinhsz
833 \global\rail@gx=\rail@jx
834 \global\rail@gy=\rail@jy
835 \global\rail@gex=\rail@gx
836 \global\rail@grx=\rail@rx
842 \rail@endalt\rail@plusjoin
845 % \rail@cr{Y} : carriage return to vertical position Y
849 \advance\rail@tmpa by \rail@joinsz
850 \ifnum\rail@x<\rail@tmpa\rail@x=\rail@tmpa\fi
854 \advance\rail@x by \rail@joinsz
855 \ifnum\rail@x>\rail@rx\rail@rx=\rail@x\fi
856 \advance\rail@jy by -\rail@joinhsz
858 \advance\rail@jx by \rail@joinhsz
861 \advance\rail@tmpa by -\rail@y
862 \advance\rail@tmpa by -\rail@boxsp
863 \advance\rail@tmpa by -\rail@joinhsz
864 \rail@jput{\line(0,-1){\number\rail@tmpa}}
866 \advance\rail@jy by \rail@boxsp
867 \advance\rail@jy by \rail@joinhsz
868 \advance\rail@jx by -\rail@joinhsz
870 \advance\rail@jy by -\rail@joinhsz
872 \advance\rail@tmpa by -\rail@sx
873 \advance\rail@tmpa by -\rail@joinhsz
874 \rail@jput{\line(-1,0){\number\rail@tmpa}}
876 \advance\rail@jx by \rail@joinhsz
877 \advance\rail@jy by -\rail@joinhsz
879 \advance\rail@jx by -\rail@joinhsz
880 \rail@tmpa=\rail@boxsp
881 \advance\rail@tmpa by -\rail@joinsz
882 \rail@jput{\line(0,-1){\number\rail@tmpa}}
883 \advance\rail@jy by -\rail@tmpa
884 \advance\rail@jx by \rail@joinhsz