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@tokenfont{\ttfamily\upshape}
196 \def\rail@termfont{\ttfamily\upshape}
197 \def\rail@nontfont{\rmfamily\upshape}
198 \def\rail@annofont{\rmfamily\itshape}
199 \def\rail@namefont{\rmfamily\itshape}
200 \def\rail@indexfont{\rmfamily\itshape}
202 \newcommand\railtermfont[1]{
203 \def\rail@termfont{#1}
206 \newcommand\railnontermfont[1]{
207 \def\rail@nontfont{#1}
210 \newcommand\railannotatefont[1]{
211 \def\rail@annofont{#1}
214 \newcommand\railnamefont[1]{
215 \def\rail@namefont{#1}
218 \newcommand\railindexfont[1]{
219 \def\rail@indexfont{#1}
222 % railroad read/write macros
224 % \begin{rail} TEXT \end{rail} : TEXT is written out to the .rai file,
225 % as \rail@i{NR}{TEXT}. Then the matching
226 % \rail@o{NR}{FMT} from the .rao file is
227 % executed (if defined).
229 % \railoptions{OPTIONS} : OPTIONS are written out to the .rai file,
230 % as \rail@p{OPTIONS}.
232 % \railterm{IDENT,IDENT,...} : format IDENT as terminals. writes out
233 % \rail@t{IDENT} to the .rai file
235 % \railalias{IDENT}{TEXT} : format IDENT as TEXT. defines \rail@t@IDENT as
238 % \rail@nr : railroad diagram counter
240 % \ifrail@match : current \rail@i{NR}{TEXT} matches
242 % \rail@first : actions to be done first. read in .rao file,
243 % open .rai file if \@filesw true, undefine \rail@first.
244 % executed from \begin{rail} and \railtoken.
246 % \rail@i{NR}{TEXT} : defines \rail@i@NR as TEXT. written to the .rai
247 % file by \rail, read from the .rao file by
250 % \rail@t{IDENT} : tells Rail that IDENT is to be custom formatted,
251 % written to the .rai file by \railterm.
253 % \rail@o{NR}{TEXT} : defines \rail@o@NR as TEXT, read from the .rao
254 % file by \rail@first.
256 % \rail@p{OPTIONS} : pass options to rail, written to the .rai file by
259 % \rail@write{TEXT} : write TEXT to the .rai file
261 % \rail@warn : warn user for mismatching diagrams
263 % \rail@endwarn : either \relax or \rail@warn
265 % \ifrail@all : checked at the end of the document
276 \InputIfFileExists{\jobname.rao}{}{\PackageInfo{rail}{No file \jobname.rao}}
280 \immediate\openout\tf@rai=\jobname.rai
282 \global\let\rail@first=\relax
285 \long\def\rail@body#1\end{
289 \rail@write{\string\rail@i{\number\rail@nr}{\rail@i@}}
294 \newenvironment{rail}{
295 \global\advance\rail@nr by 1
300 \@ifundefined{rail@o@\number\rail@nr}{\rail@matchfalse}{}
301 \expandafter\ifx\csname rail@i@\number\rail@nr\endcsname\rail@i@
306 \csname rail@o@\number\rail@nr\endcsname
308 \PackageWarning{rail}{Railroad diagram {\number\rail@nr} doesn't match}
309 \global\let\rail@endwarn=\rail@warn
310 \begin{list}{}{\rail@param}
312 \rail@setbox{\bfseries ???}
319 \newcommand\railoptions[1]{
321 \rail@write{\string\rail@p{#1}}
324 \newcommand\railterm[1]{
327 \rail@write{\string\rail@t{\rail@@}}
331 \newcommand\railalias[2]{
332 \expandafter\def\csname rail@t@#1\endcsname{#2}
335 \long\def\rail@i#1#2{
336 \expandafter\gdef\csname rail@i@#1\endcsname{#2}
340 \expandafter\gdef\csname rail@o@#1\endcsname{
341 \begin{list}{}{\rail@param}#2\end{list}
349 \def\rail@write#1{\@ifundefined{tf@rai}{}{\immediate\write\tf@rai{#1}}}
352 \PackageWarningNoLine{rail}{Railroad diagram(s) may have changed.
353 Use 'rail' and rerun}
356 \let\rail@endwarn=\relax
358 \AtEndDocument{\rail@endwarn}
362 % \rail@index{IDENT} : add index entry for IDENT
365 \index{\rail@indexfont#1}
368 % railroad formatting primitives
370 % \rail@x : current x
371 % \rail@y : current y
372 % \rail@ex : current end x
373 % \rail@sx : starting x for \rail@cr
374 % \rail@rx : rightmost previous x for \rail@cr
376 % \rail@tmpa : temporary count
377 % \rail@tmpb : temporary count
378 % \rail@tmpc : temporary count
380 % \rail@put : put at (\rail@x,\rail@y)
382 % \rail@eline : end line by drawing from \rail@ex to \rail@x
384 % \rail@sety{LEVEL} : set \rail@y to level LEVEL
396 \def\rail@put{\put(\number\rail@x,\number\rail@y)}
400 \advance\rail@tmpb by -\rail@ex
401 \rail@put{\line(-1,0){\number\rail@tmpb}}
406 \multiply\rail@y by -\rail@boxsp
407 \advance\rail@y by -\rail@boxht
410 % \rail@begin{HEIGHT}{NAME} : begin a railroad diagram of height HEIGHT
412 % \rail@end : end a railroad diagram
414 % \rail@expand{IDENT} : expand IDENT
418 \begin{minipage}[t]{\linewidth}
420 {\rail@namefont \rail@expand{#2}}\\*[\railnamesep]
422 \unitlength=\railunit
424 \multiply\rail@tmpa by \rail@boxsp
425 \begin{picture}(0,\number\rail@tmpa)(0,-\number\rail@tmpa)
434 \advance\rail@x by \rail@extra
440 \def\rail@expand#1{\@ifundefined{rail@t@#1}{#1}{\csname rail@t@#1\endcsname}}
442 % \rail@token{TEXT}[ANNOT] : format token TEXT with annotation
444 % \rail@ctoken{TEXT}[ANNOT] : format token TEXT centered with annotation
446 % \rail@nont{TEXT}[ANNOT] : format nonterminal TEXT with annotation
448 % \rail@cnont{TEXT}[ANNOT] : format nonterminal TEXT centered with annotation
450 % \rail@term{TEXT}[ANNOT] : format terminal TEXT with annotation
452 % \rail@cterm{TEXT}[ANNOT] : format terminal TEXT centered with annotation
454 % \rail@annote[TEXT] : format TEXT as annotation
456 \def\rail@token#1[#2]{
458 {\rail@tokenfont \rail@expand{#1}}\ifx\@empty#2\else\ {\rail@annofont #2}\fi
463 \def\rail@ctoken#1[#2]{
465 {\rail@tokenfont \rail@expand{#1}}\ifx\@empty#2\else\ {\rail@annofont #2}\fi
470 \def\rail@nont#1[#2]{
472 {\rail@nontfont \rail@expand{#1}}\ifx\@empty#2\else\ {\rail@annofont #2}\fi
477 \def\rail@cnont#1[#2]{
479 {\rail@nontfont \rail@expand{#1}}\ifx\@empty#2\else\ {\rail@annofont #2}\fi
484 \def\rail@term#1[#2]{
486 {\rail@termfont #1}\ifx\@empty#2\else\ {\rail@annofont #2}\fi
491 \def\rail@cterm#1[#2]{
493 {\rail@termfont #1}\ifx\@empty#2\else\ {\rail@annofont #2}\fi
498 \def\rail@annote[#1]{
499 \rail@setbox{\rail@annofont #1}
503 % \rail@box : temporary box for \rail@oval and \rail@frame
505 % \rail@setbox{TEXT} : set \rail@box to TEXT, set \rail@tmpa to width
507 % \rail@oval : format \rail@box of width \rail@tmpa inside an oval
509 % \rail@coval : same as \rail@oval, but centered between \rail@x and
512 % \rail@frame : format \rail@box of width \rail@tmpa inside a frame
514 % \rail@cframe : same as \rail@frame, but centered between \rail@x and
517 % \rail@text : format \rail@box of width \rail@tmpa above the line
522 \setbox\rail@box\hbox{\strut#1}
523 \rail@tmpa=\wd\rail@box
524 \divide\rail@tmpa by \railunit
528 \advance\rail@x by \rail@boxlf
530 \advance\rail@tmpa by \rail@ovalsp
531 \ifnum\rail@tmpa<\rail@boxht\rail@tmpa=\rail@boxht\fi
532 \rail@tmpb=\rail@tmpa
533 \divide\rail@tmpb by 2
534 \advance\rail@y by -\rail@boxhht
535 \rail@put{\makebox(\number\rail@tmpa,\number\rail@boxht){\box\rail@box}}
536 \advance\rail@y by \rail@boxhht
537 \advance\rail@x by \rail@tmpb
538 \rail@put{\oval(\number\rail@tmpa,\number\rail@boxht)}
539 \advance\rail@x by \rail@tmpb
541 \advance\rail@x by \rail@boxrt
545 \rail@tmpb=\rail@tmpa
546 \advance\rail@tmpb by \rail@ovalsp
547 \ifnum\rail@tmpb<\rail@boxht\rail@tmpb=\rail@boxht\fi
548 \advance\rail@tmpb by \rail@boxlf
549 \advance\rail@tmpb by \rail@boxrt
551 \advance\rail@tmpc by -\rail@x
552 \advance\rail@tmpc by -\rail@tmpb
553 \divide\rail@tmpc by 2
555 \advance\rail@x by \rail@tmpc
561 \advance\rail@x by \rail@boxlf
563 \advance\rail@tmpa by \rail@framesp
564 \ifnum\rail@tmpa<\rail@boxht\rail@tmpa=\rail@boxht\fi
565 \advance\rail@y by -\rail@boxhht
566 \rail@put{\framebox(\number\rail@tmpa,\number\rail@boxht){\box\rail@box}}
567 \advance\rail@y by \rail@boxhht
568 \advance\rail@x by \rail@tmpa
570 \advance\rail@x by \rail@boxrt
574 \rail@tmpb=\rail@tmpa
575 \advance\rail@tmpb by \rail@framesp
576 \ifnum\rail@tmpb<\rail@boxht\rail@tmpb=\rail@boxht\fi
577 \advance\rail@tmpb by \rail@boxlf
578 \advance\rail@tmpb by \rail@boxrt
580 \advance\rail@tmpc by -\rail@x
581 \advance\rail@tmpc by -\rail@tmpb
582 \divide\rail@tmpc by 2
584 \advance\rail@x by \rail@tmpc
590 \advance\rail@x by \rail@textlf
591 \advance\rail@y by \rail@textup
592 \rail@put{\box\rail@box}
593 \advance\rail@y by -\rail@textup
594 \advance\rail@x by \rail@tmpa
595 \advance\rail@x by \rail@textrt
600 % \rail@jx \rail@jy : current join point
602 % \rail@gx \rail@gy \rail@gex \rail@grx : global versions of \rail@x etc,
603 % to pass values over group closings
605 % \rail@mx : maximum x so far
607 % \rail@sy : starting \rail@y for alternatives
609 % \rail@jput : put at (\rail@jx,\rail@jy)
611 % \rail@joval[PART] : put \oval[PART] with adjust
625 \put(\number\rail@jx,\number\rail@jy)
629 \advance\rail@jx by \rail@joinadj
630 \rail@jput{\oval(\number\rail@joinsz,\number\rail@joinsz)[#1]}
631 \advance\rail@jx by -\rail@joinadj
634 % \rail@barsplit : incoming split for '|'
636 % \rail@plussplit : incoming split for '+'
640 \advance\rail@jy by -\rail@joinhsz
642 \advance\rail@jx by \rail@joinhsz
646 \advance\rail@jy by -\rail@joinhsz
647 \advance\rail@jx by \rail@joinsz
649 \advance\rail@jx by -\rail@joinhsz
652 % \rail@alt{SPLIT} : start alternatives with incoming split SPLIT
659 \advance\rail@x by \rail@joinsz
661 \let\rail@list=\@empty
662 \let\rail@comma=\@empty
669 % \rail@nextalt{FIX}{Y} : start next alternative at vertical position Y
673 \def\rail@nextalt#1#2{
674 \global\rail@gx=\rail@x
675 \global\rail@gy=\rail@y
676 \global\rail@gex=\rail@ex
677 \global\rail@grx=\rail@rx
680 \ifnum\rail@gx>\rail@mx\rail@mx=\rail@gx\fi
681 \ifnum\rail@grx>\rail@mx\rail@mx=\rail@grx\fi
682 \edef\rail@list{\rail@list\rail@comma\number\rail@gex:\number\rail@gy}
685 \let\rail@split=\@empty
688 \advance\rail@tmpa by -\rail@y
689 \advance\rail@tmpa by -\rail@joinhsz
690 \rail@jput{\line(0,-1){\number\rail@tmpa}}
692 \advance\rail@jy by \rail@joinhsz
693 \advance\rail@jx by \rail@joinhsz
695 \advance\rail@jx by -\rail@joinhsz
702 % \rail@barjoin : outgoing join for first '|' alternative
704 % \rail@plusjoin : outgoing join for first '+' alternative
706 % \rail@altjoin : join for subsequent alternative
710 \ifnum\rail@y<\rail@sy
711 \global\rail@gex=\rail@jx
713 \global\rail@gex=\rail@ex
715 \advance\rail@jy by -\rail@joinhsz
717 \advance\rail@jx by -\rail@joinhsz
718 \ifnum\rail@y<\rail@sy
724 \global\rail@gex=\rail@ex
725 \advance\rail@jy by -\rail@joinhsz
726 \advance\rail@jx by -\rail@joinsz
728 \advance\rail@jx by \rail@joinhsz
734 \advance\rail@tmpa by -\rail@y
735 \advance\rail@tmpa by -\rail@joinhsz
736 \rail@jput{\line(0,-1){\number\rail@tmpa}}
738 \advance\rail@jy by \rail@joinhsz
739 \advance\rail@jx by -\rail@joinhsz
741 \advance\rail@jx by \rail@joinhsz
744 % \rail@eltsplit EX:Y; : split EX:Y into \rail@ex \rail@y
746 % \rail@endalt{JOIN} : end alternatives with outgoing join JOIN
748 \def\rail@eltsplit#1:#2;{\rail@ex=#1\rail@y=#2}
751 \global\rail@gx=\rail@x
752 \global\rail@gy=\rail@y
753 \global\rail@gex=\rail@ex
754 \global\rail@grx=\rail@rx
756 \ifnum\rail@gx>\rail@mx\rail@mx=\rail@gx\fi
757 \ifnum\rail@grx>\rail@mx\rail@mx=\rail@grx\fi
758 \edef\rail@list{\rail@list\rail@comma\number\rail@gex:\number\rail@gy}
762 \advance\rail@jx by \rail@joinsz
764 \@for\rail@elt:=\rail@list\do{
765 \expandafter\rail@eltsplit\rail@elt;
767 \let\rail@join=\rail@altjoin
772 \advance\rail@x by \rail@joinsz
775 % \rail@bar : start '|' alternatives
777 % \rail@nextbar : next '|' alternative
779 % \rail@endbar : end '|' alternatives
783 \rail@alt\rail@barsplit
791 \rail@endalt\rail@barjoin
794 % \rail@plus : start '+' alternatives
796 % \rail@nextplus: next '+' alternative
798 % \rail@endplus : end '+' alternatives
802 \rail@alt\rail@plussplit
806 \rail@nextalt\rail@fixplus
810 \ifnum\rail@gy<\rail@sy
816 \ifnum\rail@x<\rail@rx
822 \advance\rail@jy by \rail@joinhsz
824 \advance\rail@jx by \rail@joinhsz
826 \advance\rail@tmpa by -\rail@joinhsz
827 \advance\rail@tmpa by -\rail@jy
828 \rail@jput{\line(0,1){\number\rail@tmpa}}
830 \advance\rail@jy by -\rail@joinhsz
831 \advance\rail@jx by \rail@joinhsz
833 \advance\rail@jy by \rail@joinhsz
834 \global\rail@gx=\rail@jx
835 \global\rail@gy=\rail@jy
836 \global\rail@gex=\rail@gx
837 \global\rail@grx=\rail@rx
843 \rail@endalt\rail@plusjoin
846 % \rail@cr{Y} : carriage return to vertical position Y
850 \advance\rail@tmpa by \rail@joinsz
851 \ifnum\rail@x<\rail@tmpa\rail@x=\rail@tmpa\fi
855 \advance\rail@x by \rail@joinsz
856 \ifnum\rail@x>\rail@rx\rail@rx=\rail@x\fi
857 \advance\rail@jy by -\rail@joinhsz
859 \advance\rail@jx by \rail@joinhsz
862 \advance\rail@tmpa by -\rail@y
863 \advance\rail@tmpa by -\rail@boxsp
864 \advance\rail@tmpa by -\rail@joinhsz
865 \rail@jput{\line(0,-1){\number\rail@tmpa}}
867 \advance\rail@jy by \rail@boxsp
868 \advance\rail@jy by \rail@joinhsz
869 \advance\rail@jx by -\rail@joinhsz
871 \advance\rail@jy by -\rail@joinhsz
873 \advance\rail@tmpa by -\rail@sx
874 \advance\rail@tmpa by -\rail@joinhsz
875 \rail@jput{\line(-1,0){\number\rail@tmpa}}
877 \advance\rail@jx by \rail@joinhsz
878 \advance\rail@jy by -\rail@joinhsz
880 \advance\rail@jx by -\rail@joinhsz
881 \rail@tmpa=\rail@boxsp
882 \advance\rail@tmpa by -\rail@joinsz
883 \rail@jput{\line(0,-1){\number\rail@tmpa}}
884 \advance\rail@jy by -\rail@tmpa
885 \advance\rail@jx by \rail@joinhsz