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
8 % This style file needs to be used in conjunction with the 'rail'
9 % program. Running LaTeX as 'latex file' produces file.rai, which should be
10 % processed by Rail with 'rail file'. This produces file.rao, which will
11 % be picked up by LaTeX on the next 'latex file' run.
13 % LaTeX will warn if there is no file.rao or it's out of date.
15 % The macros in this file thus consist of two parts: those that read and
16 % write the .rai and .rao files, and those that do the actual formatting
17 % of the railroad diagrams.
19 % railroad read/write macros
21 % \begin{rail} TEXT \end{rail} : TEXT is written out to the .rai file,
22 % as \rail@i{NR}{TEXT}. Then the matching
23 % \rail@o{NR}{FMT} from the .rao file is
24 % executed (if defined).
26 % \railoptions{OPTIONS} : OPTIONS are written out to the .rai file,
27 % as \rail@p{OPTIONS}.
29 % \railterm{IDENT,IDENT,...} : format IDENT as terminals. writes out
30 % \rail@t{IDENT} to the .rai file and
31 % defines \rail@t@IDENT as \rail@termfont IDENT.
33 % \railtoken{IDENT}{TEXT} : format IDENT as terminal TEXT. writes out
34 % \rail@t{IDENT} to the .rai file and defines
35 % \rail@t@IDENT as TEXT.
37 % \rail@nr : railroad diagram counter, starts at 1
39 % \ifrail@match : current \rail@i{NR}{TEXT} matches
41 % \rail@first : actions to be done first. read in .rao file,
42 % open .rai file if \@filesw true, undefine \rail@first.
43 % executed from \begin{rail} and \railtoken.
45 % \rail@i{NR}{TEXT} : defines \rail@i@NR as TEXT. written to the .rai
46 % file by \rail, read from the .rao file by
49 % \rail@t{IDENT} : tells Rail that IDENT is to be custom formatted,
50 % written to the .rai file by \railterm and \railtoken.
52 % \rail@o{NR}{TEXT} : defines \rail@o@NR as TEXT, read from the .rao
53 % file by \rail@first.
55 % \rail@p{OPTIONS} : pass options to rail, written to the .rai file by
58 % \rail@warn : warn user for mismatching diagrams
60 % \rail@endwarn : either \relax or \rail@warn
62 % \rail@enddocument : original \enddocument
64 % \enddocument : checks \ifrail@all
80 \immediate\openout\tf@rai\jobname.rai\relax
82 \global\let\rail@first=\relax
85 \long\def\rail#1\end#2{
90 \global\edef\rail@i@{#1}
92 \@ifundefined{tf@rai}{}{
95 \immediate\write\tf@rai{\noexpand\rail@i{\number\rail@nr}{\rail@i@}}
99 \@ifundefined{rail@o@\number\rail@nr}{\rail@matchfalse}{}
100 \expandafter\ifx\csname rail@i@\number\rail@nr\endcsname\rail@i@
105 \expandafter\relax\csname rail@o@\number\rail@nr\endcsname
107 \@warning{Railroad diagram {\number\rail@nr} doesn't match}
108 \global\let\rail@endwarn=\rail@warn
110 \rail@setbox{\bf ???}
114 \global\advance\rail@nr by 1
119 \@writefile{rai}{\noexpand\rail@p{#1}}
124 \@for\rail@i@:=#1\do{
125 \@writefile{rai}{\noexpand\rail@t{\rail@i@}}
131 \@writefile{rai}{\noexpand\rail@t{#1}}
132 \expandafter\def\csname rail@t@#1\endcsname{#2}
135 \long\def\rail@i#1#2{
136 \expandafter\gdef\csname rail@i@#1\endcsname{#2}
140 \expandafter\gdef\csname rail@o@#1\endcsname{#2}
148 \@warning{Railroad diagram(s) may have changed. Use 'rail' and rerun}
151 \let\rail@endwarn=\relax
153 \let\rail@enddocument=\enddocument
162 % \rail@index{IDENT} : add index entry for IDENT
165 \index{\rail@indexfont#1}
168 % railroad diagram formatting parameters (user level)
169 % all of these are copied into their internal versions by \railinit
171 % \railunit : \unitlength within railroad diagrams
172 % \railextra : extra length at outside of diagram
173 % \railboxheight : height of ovals and frames
174 % \railboxskip : vertical space between lines
175 % \railboxleft : space to the left of a box
176 % \railboxright : space to the right of a box
177 % \railovalspace : extra space around contents of oval
178 % \railframespace : extra space around contents of frame
179 % \railtextleft : space to the left of text
180 % \railtextright : space to the right of text
181 % \railtextup : space to lift text up
182 % \railjoinsize : circle size of join/split arcs
183 % \railjoinadjust : space to adjust join
185 % \railnamesep : separator between name and rule body
189 \newdimen\railboxheight
190 \newdimen\railboxskip
191 \newdimen\railboxleft
192 \newdimen\railboxright
193 \newdimen\railovalspace
194 \newdimen\railframespace
195 \newdimen\railtextleft
196 \newdimen\railtextright
198 \newdimen\railjoinsize
199 \newdimen\railjoinadjust
200 \newdimen\railnamesep
202 % internal versions of the formatting parameters
204 % \rail@extra : \railextra
205 % \rail@boxht : \railboxheight
206 % \rail@boxsp : \railboxskip
207 % \rail@boxlf : \railboxleft
208 % \rail@boxrt : \railboxright
209 % \rail@boxhht : \railboxheight / 2
210 % \rail@ovalsp : \railovalspace
211 % \rail@framesp : \railframespace
212 % \rail@textlf : \railtextleft
213 % \rail@textrt : \railtextright
214 % \rail@textup : \railtextup
215 % \rail@joinsz : \railjoinsize
216 % \rail@joinhsz : \railjoinsize / 2
217 % \rail@joinadj : \railjoinadjust
219 % \railinit : internalize all of the parameters.
226 \newcount\rail@boxhht
227 \newcount\rail@ovalsp
228 \newcount\rail@framesp
229 \newcount\rail@textlf
230 \newcount\rail@textrt
231 \newcount\rail@textup
232 \newcount\rail@joinsz
233 \newcount\rail@joinhsz
234 \newcount\rail@joinadj
237 \rail@extra=\railextra
238 \divide\rail@extra by \railunit
239 \rail@boxht=\railboxheight
240 \divide\rail@boxht by \railunit
241 \rail@boxsp=\railboxskip
242 \divide\rail@boxsp by \railunit
243 \rail@boxlf=\railboxleft
244 \divide\rail@boxlf by \railunit
245 \rail@boxrt=\railboxright
246 \divide\rail@boxrt by \railunit
247 \rail@boxhht=\railboxheight
248 \divide\rail@boxhht by \railunit
249 \divide\rail@boxhht by 2
250 \rail@ovalsp=\railovalspace
251 \divide\rail@ovalsp by \railunit
252 \rail@framesp=\railframespace
253 \divide\rail@framesp by \railunit
254 \rail@textlf=\railtextleft
255 \divide\rail@textlf by \railunit
256 \rail@textrt=\railtextright
257 \divide\rail@textrt by \railunit
258 \rail@textup=\railtextup
259 \divide\rail@textup by \railunit
260 \rail@joinsz=\railjoinsize
261 \divide\rail@joinsz by \railunit
262 \rail@joinhsz=\railjoinsize
263 \divide\rail@joinhsz by \railunit
264 \divide\rail@joinhsz by 2
265 \rail@joinadj=\railjoinadjust
266 \divide\rail@joinadj by \railunit
269 % initialize the parameters
304 % railroad formatting primitives
306 % \rail@x : current x
307 % \rail@y : current y
308 % \rail@ex : current end x
309 % \rail@sx : starting x for \rail@cr
310 % \rail@rx : rightmost previous x for \rail@cr
312 % \rail@tmpa : temporary count
313 % \rail@tmpb : temporary count
314 % \rail@tmpc : temporary count
316 % \rail@put : put at (\rail@x,\rail@y)
318 % \rail@eline : end line by drawing from \rail@ex to \rail@x
320 % \rail@sety{LEVEL} : set \rail@y to level LEVEL
332 \def\rail@put{\put(\number\rail@x,\number\rail@y)}
336 \advance\rail@tmpb by -\rail@ex
337 \rail@put{\line(-1,0){\number\rail@tmpb}}
342 \multiply\rail@y by -\rail@boxsp
343 \advance\rail@y by -\rail@boxht
346 % \rail@list : declarations for list environment
348 % \railparam{TEXT} : sets \rail@list to TEXT
350 % \rail@begin{HEIGHT}{NAME} : begin a railroad diagram of height HEIGHT
352 % \rail@end : end a railroad diagram
364 \begin{list}{}{\rail@list}
369 \\*[\railnamesep]\nopagebreak
371 \unitlength=\railunit
373 \multiply\rail@tmpa by \rail@boxsp
374 \begin{picture}(0,\number\rail@tmpa)(0,-\number\rail@tmpa)
383 \advance\rail@x by \rail@extra
390 % \rail@tokenfont : format setup for \railtoken identifiers
392 % \rail@termfont : format setup for terminals
394 % \rail@nontfont : format setup for nonterminals
396 % \rail@annofont : format setup for annotations
398 % \rail@rulefont : format setup for rule names
400 % \rail@indexfont : format setup for index entry
402 % \railtokenfont{TEXT} : set \railtoken format setup to TEXT
404 % \railtermfont{TEXT} : set terminal format setup to TEXT
406 % \railnontermfont{TEXT} : set nonterminal format setup to TEXT
408 % \railannotatefont{TEXT} : set annotation format setup to TEXT
410 % \railnamefont{TEXT} : set rule name format setup to TEXT
412 % \railindexfont{TEXT} : set index entry format setup to TEXT
414 \let\rail@tokenfont=\tt
415 \let\rail@termfont=\tt
416 \let\rail@nontfont=\rm
417 \let\rail@annofont=\it
418 \let\rail@namefont=\it
419 \let\rail@indexfont=\it
421 \def\railtokenfont#1{
422 \def\rail@tokenfont{#1}
426 \def\rail@termfont{#1}
429 \def\railnontermfont#1{
430 \def\rail@nontfont{#1}
433 \def\railannotatefont#1{
434 \def\rail@annofont{#1}
438 \def\rail@namefont{#1}
441 \def\railindexfont#1{
442 \def\rail@indexfont{#1}
445 % \rail@token{TEXT} : format token TEXT
447 % \rail@ctoken{TEXT} : format token TEXT centered
449 % \rail@nont{TEXT} : format nonterminal TEXT
451 % \rail@cnont{TEXT} : format nonterminal TEXT centered
453 % \rail@cterm{TEXT} : format terminal TEXT
455 % \rail@cterm{TEXT} : format terminal TEXT centered
457 % \rail@annote[TEXT] : format TEXT as annotation
459 % \rail@annotebox[TEXT] : annotate box with TEXT
462 \expandafter\@ifundefined{rail@t@#1}{
463 \rail@setbox{\rail@termfont #1}
465 \rail@setbox{\rail@tokenfont \csname rail@t@#1\endcsname}
471 \rail@setbox{\rail@tokenfont \csname rail@t@#1\endcsname}
476 \rail@setbox{\rail@nontfont #1}
481 \rail@setbox{\rail@nontfont #1}
486 \rail@setbox{\rail@termfont #1}
491 \rail@setbox{\rail@termfont #1}
495 \def\rail@annote[#1]{
496 \rail@setbox{\rail@annofont #1}
500 \def\rail@annotebox[#1]{
504 % \rail@box : temporary box for \rail@oval and \rail@frame
506 % \rail@setbox{TEXT} : set \rail@box to TEXT, set \rail@tmpa to width
508 % \rail@oval : format \rail@box of width \rail@tmpa inside an oval
510 % \rail@coval : same as \rail@oval, but centered between \rail@x and
513 % \rail@frame : format \rail@box of width \rail@tmpa inside a frame
515 % \rail@cframe : same as \rail@frame, but centered between \rail@x and
518 % \rail@text : format \rail@box of width \rail@tmpa above the line
523 \setbox\rail@box\hbox{\strut#1}
524 \rail@tmpa=\wd\rail@box
525 \divide\rail@tmpa by \railunit
529 \advance\rail@x by \rail@boxlf
531 \advance\rail@tmpa by \rail@ovalsp
532 \ifnum\rail@tmpa<\rail@boxht\rail@tmpa=\rail@boxht\fi
533 \rail@tmpb=\rail@tmpa
534 \divide\rail@tmpb by 2
535 \advance\rail@y by -\rail@boxhht
536 \rail@put{\makebox(\number\rail@tmpa,\number\rail@boxht){\box\rail@box}}
537 \advance\rail@y by \rail@boxhht
538 \advance\rail@x by \rail@tmpb
539 \rail@put{\oval(\number\rail@tmpa,\number\rail@boxht)}
540 \advance\rail@x by \rail@tmpb
542 \advance\rail@x by \rail@boxrt
546 \rail@tmpb=\rail@tmpa
547 \advance\rail@tmpb by \rail@ovalsp
548 \ifnum\rail@tmpb<\rail@boxht\rail@tmpb=\rail@boxht\fi
549 \advance\rail@tmpb by \rail@boxlf
550 \advance\rail@tmpb by \rail@boxrt
552 \advance\rail@tmpc by -\rail@x
553 \advance\rail@tmpc by -\rail@tmpb
554 \divide\rail@tmpc by 2
556 \advance\rail@x by \rail@tmpc
562 \advance\rail@x by \rail@boxlf
564 \advance\rail@tmpa by \rail@framesp
565 \ifnum\rail@tmpa<\rail@boxht\rail@tmpa=\rail@boxht\fi
566 \advance\rail@y by -\rail@boxhht
567 \rail@put{\framebox(\number\rail@tmpa,\number\rail@boxht){\box\rail@box}}
568 \advance\rail@y by \rail@boxhht
569 \advance\rail@x by \rail@tmpa
571 \advance\rail@x by \rail@boxrt
575 \rail@tmpb=\rail@tmpa
576 \advance\rail@tmpb by \rail@framesp
577 \ifnum\rail@tmpb<\rail@boxht\rail@tmpb=\rail@boxht\fi
578 \advance\rail@tmpb by \rail@boxlf
579 \advance\rail@tmpb by \rail@boxrt
581 \advance\rail@tmpc by -\rail@x
582 \advance\rail@tmpc by -\rail@tmpb
583 \divide\rail@tmpc by 2
585 \advance\rail@x by \rail@tmpc
591 \advance\rail@x by \rail@textlf
592 \advance\rail@y by \rail@textup
593 \rail@put{\box\rail@box}
594 \advance\rail@y by -\rail@textup
595 \advance\rail@x by \rail@tmpa
596 \advance\rail@x by \rail@textrt
601 % \rail@jx \rail@jy : current join point
603 % \rail@gx \rail@gy \rail@gex \rail@grx : global versions of \rail@x etc,
604 % to pass values over group closings
606 % \rail@mx : maximum x so far
608 % \rail@sy : starting \rail@y for alternatives
610 % \rail@jput : put at (\rail@jx,\rail@jy)
612 % \rail@joval[PART] : put \oval[PART] with adjust
626 \put(\number\rail@jx,\number\rail@jy)
630 \advance\rail@jx by \rail@joinadj
631 \rail@jput{\oval(\number\rail@joinsz,\number\rail@joinsz)[#1]}
632 \advance\rail@jx by -\rail@joinadj
635 % \rail@barsplit : incoming split for '|'
637 % \rail@plussplit : incoming split for '+'
641 \advance\rail@jy by -\rail@joinhsz
643 \advance\rail@jx by \rail@joinhsz
647 \advance\rail@jy by -\rail@joinhsz
648 \advance\rail@jx by \rail@joinsz
650 \advance\rail@jx by -\rail@joinhsz
653 % \rail@alt{SPLIT} : start alternatives with incoming split SPLIT
660 \advance\rail@x by \rail@joinsz
662 \let\rail@list=\@empty
663 \let\rail@comma=\@empty
670 % \rail@nextalt{FIX}{Y} : start next alternative at vertical position Y
674 \def\rail@nextalt#1#2{
675 \global\rail@gx=\rail@x
676 \global\rail@gy=\rail@y
677 \global\rail@gex=\rail@ex
678 \global\rail@grx=\rail@rx
681 \ifnum\rail@gx>\rail@mx\rail@mx=\rail@gx\fi
682 \ifnum\rail@grx>\rail@mx\rail@mx=\rail@grx\fi
683 \edef\rail@list{\rail@list\rail@comma\number\rail@gex:\number\rail@gy}
686 \let\rail@split=\@empty
689 \advance\rail@tmpa by -\rail@y
690 \advance\rail@tmpa by -\rail@joinhsz
691 \rail@jput{\line(0,-1){\number\rail@tmpa}}
693 \advance\rail@jy by \rail@joinhsz
694 \advance\rail@jx by \rail@joinhsz
696 \advance\rail@jx by -\rail@joinhsz
703 % \rail@barjoin : outgoing join for first '|' alternative
705 % \rail@plusjoin : outgoing join for first '+' alternative
707 % \rail@altjoin : join for subsequent alternative
711 \ifnum\rail@y<\rail@sy
712 \global\rail@gex=\rail@jx
714 \global\rail@gex=\rail@ex
716 \advance\rail@jy by -\rail@joinhsz
718 \advance\rail@jx by -\rail@joinhsz
719 \ifnum\rail@y<\rail@sy
725 \global\rail@gex=\rail@ex
726 \advance\rail@jy by -\rail@joinhsz
727 \advance\rail@jx by -\rail@joinsz
729 \advance\rail@jx by \rail@joinhsz
735 \advance\rail@tmpa by -\rail@y
736 \advance\rail@tmpa by -\rail@joinhsz
737 \rail@jput{\line(0,-1){\number\rail@tmpa}}
739 \advance\rail@jy by \rail@joinhsz
740 \advance\rail@jx by -\rail@joinhsz
742 \advance\rail@jx by \rail@joinhsz
745 % \rail@eltsplit EX:Y; : split EX:Y into \rail@ex \rail@y
747 % \rail@endalt{JOIN} : end alternatives with outgoing join JOIN
749 \def\rail@eltsplit#1:#2;{\rail@ex=#1\rail@y=#2}
752 \global\rail@gx=\rail@x
753 \global\rail@gy=\rail@y
754 \global\rail@gex=\rail@ex
755 \global\rail@grx=\rail@rx
757 \ifnum\rail@gx>\rail@mx\rail@mx=\rail@gx\fi
758 \ifnum\rail@grx>\rail@mx\rail@mx=\rail@grx\fi
759 \edef\rail@list{\rail@list\rail@comma\number\rail@gex:\number\rail@gy}
763 \advance\rail@jx by \rail@joinsz
765 \@for\rail@elt:=\rail@list\do{
766 \expandafter\rail@eltsplit\rail@elt;
768 \let\rail@join=\rail@altjoin
773 \advance\rail@x by \rail@joinsz
776 % \rail@bar : start '|' alternatives
778 % \rail@nextbar : next '|' alternative
780 % \rail@endbar : end '|' alternatives
784 \rail@alt\rail@barsplit
792 \rail@endalt\rail@barjoin
795 % \rail@plus : start '+' alternatives
797 % \rail@nextplus: next '+' alternative
799 % \rail@endplus : end '+' alternatives
803 \rail@alt\rail@plussplit
807 \rail@nextalt\rail@fixplus
811 \ifnum\rail@gy<\rail@sy
817 \ifnum\rail@x<\rail@rx
823 \advance\rail@jy by \rail@joinhsz
825 \advance\rail@jx by \rail@joinhsz
827 \advance\rail@tmpa by -\rail@joinhsz
828 \advance\rail@tmpa by -\rail@jy
829 \rail@jput{\line(0,1){\number\rail@tmpa}}
831 \advance\rail@jy by -\rail@joinhsz
832 \advance\rail@jx by \rail@joinhsz
834 \advance\rail@jy by \rail@joinhsz
835 \global\rail@gx=\rail@jx
836 \global\rail@gy=\rail@jy
837 \global\rail@gex=\rail@gx
838 \global\rail@grx=\rail@rx
844 \rail@endalt\rail@plusjoin
847 % \rail@cr{Y} : carriage return to vertical position Y
851 \advance\rail@tmpa by \rail@joinsz
852 \ifnum\rail@x<\rail@tmpa\rail@x=\rail@tmpa\fi
856 \advance\rail@x by \rail@joinsz
857 \ifnum\rail@x>\rail@rx\rail@rx=\rail@x\fi
858 \advance\rail@jy by -\rail@joinhsz
860 \advance\rail@jx by \rail@joinhsz
863 \advance\rail@tmpa by -\rail@y
864 \advance\rail@tmpa by -\rail@boxsp
865 \advance\rail@tmpa by -\rail@joinhsz
866 \rail@jput{\line(0,-1){\number\rail@tmpa}}
868 \advance\rail@jy by \rail@boxsp
869 \advance\rail@jy by \rail@joinhsz
870 \advance\rail@jx by -\rail@joinhsz
872 \advance\rail@jy by -\rail@joinhsz
874 \advance\rail@tmpa by -\rail@sx
875 \advance\rail@tmpa by -\rail@joinhsz
876 \rail@jput{\line(-1,0){\number\rail@tmpa}}
878 \advance\rail@jx by \rail@joinhsz
879 \advance\rail@jy by -\rail@joinhsz
881 \advance\rail@jx by -\rail@joinhsz
882 \rail@tmpa=\rail@boxsp
883 \advance\rail@tmpa by -\rail@joinsz
884 \rail@jput{\line(0,-1){\number\rail@tmpa}}
885 \advance\rail@jy by -\rail@tmpa
886 \advance\rail@jx by \rail@joinhsz