
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                           %
% Grammars and grammar-like alignments                                      %
%                                                                           %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\RequirePackage{mak-namespace}

\newenvironment{grammar}[1][to\linewidth]{\par
        \ifinner \else \medbreak \fi
        \usenamespace{grammar}
        \def\par{\noalign{\penalty-150\let\par\endgraf\relax\medskip}}
        \advance\linewidth by\@totalleftmargin
        \advance\@totalleftmargin by\parindent
        \tabskip=\@totalleftmargin plus1fil
        \ALIGN@{to \linewidth}}
        {\crcr\egroup
         \let\par\endgraf
         \ifinner \else
               \medbreak
               \aftergroup\noindent
               \aftergroup\ignorespaces
         \fi}
\def\OR{~|~}

\namespace{grammar}
  \def\ALIGN@#1{
        \upshape
        \offinterlineskip
        \halign#1\bgroup
            \tabskip0pt\relax
            ##&\hfil$\;##\;$\hfil&%
            \setbox0\hbox{$##$}%
            \dimen0=\ht0 \advance\dimen0by.2ex \ht0=\dimen0
            \dimen0=\dp0 \advance\dimen0by.1ex \dp0=\dimen0
            \box0\strut\hfil
            \tabskip\parindent plus1fil minus\parindent &##\tabskip0pt\cr}

  \def\CLASS#1:#2#3{\SHIP@{#1: \hfil$#2$&}%
                    \ifx\BNF#3 \SHIP@{::=} \else
                    \ifx\SET#3 \SHIP@{\in} \else
                    \ifx\UNDEFINED#3 \else
                       \errormsg{\noexpand\CLASS should be followed by
                                 \noexpand\BNF or \noexpand\SET} \fi\fi\fi
                    \RHS@}
  \def\BNF{\SHIP@{\noalign{\penalty700}\hfil&|}\RHS@}
  \def\SET{\errormsg{Lone \noexpand\SET}%
           \SHIP@{\noalign{\penalty700}\hfil&\cup}\RHS@}
  \def\UNDEFINED{\undefined}
  \def\RHS@{\futurelet\next\RHS@A}
  \def\RHS@A{\ifx\next*\expandafter\RHS@C\else\expandafter\RHS@B\fi}
  \def\RHS@B{\RHS@C-}
  \def\RHS@C#1{\def\changebar@p{#1}\futurelet\next\RHS@D}
  \def\RHS@D{\ifx\next[\iffalse]\fi \expandafter\RHS@Ea
             \else \expandafter\RHS@Eb\fi}
  \def\RHS@Ea[#1]{\RHS@F{\relax\quad(#1)}}
  \def\RHS@Eb{\RHS@F{}}
  \def\RHS@F#1{\if -#1\changebar@p \let\next\RHS@Ga
               \else \def\next{\expandafter\RHS@Gb\changebar@p{#1\;}}%
               \fi\next}
  \def\RHS@Ga#1{\SHIP@{&#1}\SHIP@LINE}
  \def\RHS@Gb#1#2#3{\SHIP@{&#3\phantom{#2}&\llap{$#2$}}
                    \ifx#1*\SHIP@{\kern-.4pt\vrule width.4pt}\fi
                    \SHIP@LINE}

  \def\SHIP@#1{#1}
  \def\SHIP@LINE{\cr}

  \def\COLLECT@#1{\toks0=\expandafter{\the\toks0 #1}}
  \def\COLLECT@LINE{\advance\count0 by 1
                    \edef\next{\toks2={\the\toks2
                                       \the\toks0
                                       \noexpand\LINEBREAK@\the\count0@}}
                    \next
                    \toks0={}}
  \def\SPLIT@SAVED#1{%
     \def\extract##1\LINEBREAK@#1@##2\ENDGRAMMAR@@
         {\global\toks1={##1\cr} \global\toks3={##2}}
     \expandafter\extract\the\toks2 \ENDGRAMMAR@@}
  \def\LINEBREAK@#1@{\cr}
\endgroup

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                           %
% Grammars in two columns                                                   %
%                                                                           %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\newenvironment{twogrammar}{\par
  \ifinner \else \medbreak \fi
  \usenamespace{grammar}
  \bgroup
    \let\SHIP@=\COLLECT@
    \let\SHIP@LINE=\COLLECT@LINE
    \count0=0 \toks0={} \toks2={}
    \def\par{\xdef\SPLITAT@{\the\count0}}
    \gdef\SPLITAT@{\count0}
}{  \ifnum\count0=0 \toks2={\LINEBREAK@1@} \fi
    \advance\count0 by 1
    \divide\count0 by 2
    \count0=\SPLITAT@
    {\expandafter\SPLIT@SAVED\expandafter{\the\count0}}
  \egroup
  %
  \setbox0\vtop{\ALIGN@{}\the\toks1 \crcr\egroup
                \global\toks1={}
                \global\dimen1=\prevdepth}
  \setbox2\vtop{\ALIGN@{}\the\toks3 \crcr\egroup
                \global\toks3={}
                \global\dimen3=\prevdepth}
  \dimen0=\dp0 \advance\dimen0by-\dimen1
  \dimen2=\dp2 \advance\dimen2by-\dimen3
  \ifdim \dimen0<\dimen2 \dimen0=\dimen2 \fi
  \dimen4=\dp0 \ifdim\dimen4<\dp2 \dimen4=\dp2 \fi
  \advance \dimen4 by-\dimen0
  %
  \noindent \hskip\parfillskip
    \box0
    \ifdim\parindent<1pt \parindent=1em\fi
    \nobreak\hskip\parindent plus1fil
    \box2
  \par
  \prevdepth=\dimen4
  \ifinner \else
      \medbreak
      \aftergroup\noindent
      \aftergroup\ignorespaces
  \fi
}

