% Copyright 2012-2020, Alexander Shibakov
% This file is part of SPLinT
%
% SPLinT is free software: you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% SPLinT is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with SPLinT.  If not, see <http://www.gnu.org/licenses/>.

% `data structure access' macros: picking the n-th undelimited parameter
% in a parameter list inside a token register
% it is assumed that none of the arguments is \end, and that there are enough
% parameters to pick the desired one

\def\getfirst#1\to#2{%
    #2\expandafter\expandafter\expandafter{\expandafter\g@tfirst\the#1\end}%
}

\def\g@tfirst#1#2\end{#1}

\def\getsecond#1\to#2{%
    #2\expandafter\expandafter\expandafter{\expandafter\g@tsecond\the#1\end}%
}

\def\g@tsecond#1#2#3\end{#2}

\def\getthird#1\to#2{%
    #2\expandafter\expandafter\expandafter{\expandafter\g@tthird\the#1\end}%
}

\def\g@tthird#1#2#3#4\end{#3}

\def\getfourth#1\to#2{%
    #2\expandafter\expandafter\expandafter{\expandafter\g@tfourth\the#1\end}%
}

\def\g@tfourth#1#2#3#4#5\end{#4}

\def\getfifth#1\to#2{%
    #2\expandafter\expandafter\expandafter{\expandafter\g@tfifth\the#1\end}%
}

\def\g@tfifth#1#2#3#4#5#6\end{#5}

\def\getsixth#1\to#2{%
    #2\expandafter\expandafter\expandafter{\expandafter\g@tsixth\the#1\end}%
}

\def\g@tsixth#1#2#3#4#5#6#7\end{#6}

\def\getseventh#1\to#2{%
    #2\expandafter\expandafter\expandafter{\expandafter\g@tseventh\the#1\end}%
}

\def\g@tseventh#1#2#3#4#5#6#7#8\end{#7}

\def\geteightth#1\to#2{%
    #2\expandafter\expandafter\expandafter{\expandafter\g@teightth\the#1\end}%
}

\def\g@teightth#1#2#3#4#5#6#7#8#9\end{#8}

\def\getninth#1\to#2{% the `.' is necessary since \TeX's scanning mechanism will
                     % strip any potential braces surrounding the last parameter
                     % (assuming there are exactly nine) twice:
                     %  o first, expanding \g@tninth,
                     %  o second, expanding \g@tfirst
    #2\expandafter\expandafter\expandafter{\expandafter\g@tninth\the#1.\end}%
    #2\expandafter\expandafter\expandafter{\the#2}%
}

\def\g@tninth#1#2#3#4#5#6#7#8#9\end{\g@tfirst#9\end}

\def\gettenth#1\to#2{% no need for `.' (or any other placeholder) here,
                     % since the #9-th parameter to \g@ttenth is a list of
                     % at least two parameters itself, thus any existing braces
                     % have survived intact
    #2\expandafter\expandafter\expandafter{\expandafter\g@ttenth\the#1\end}%
    #2\expandafter\expandafter\expandafter{\the#2}%
}

\def\g@ttenth#1#2#3#4#5#6#7#8#9\end{\g@tsecond#9\end}

% removing the first element of a token register if it has more than one;

\def\sansfirst#1{%
    \expandafter\s@nsfirst\expandafter{\the#1}{#1}%
}

\def\s@nsfirst#1#2{%
    \expandafter\s@nsf@rst\expandafter{\eatone#1}{#2}%
}

\def\s@nsf@rst#1#2{%
    \yystringempty{#1}{}{%
        #2{#1}%
    }%
}

% a version of the macro above that expands to the original argument with the first element removed

\def\sansfirstx#1{%
    \expandafter\yystringempty\expandafter{\eatone#1}{#1}{\eatone#1}%
}

% string replacement: all arguments are registers, nothing is expanded, no \next is defined
% note that this is not a greedy replacement: this could be arranged with a more sophisticated macro
% also note that the string being replaced cannot have any braces in it

\newif\ifyytracereplacements
\newif\ifyyreplaced

\yytracereplacementstrue

\def\yyreplacestring#1\in#2\with#3{%
      \expandafter\def\expandafter\r@placestring\expandafter##\expandafter1\the#1##2\end{%
          \def\r@placestring{##2}% is this the string at the very end?
          \ifx\r@placestring\empty % then it is the one we inserted,
                                   % report
              \yyreplacedfalse
              \ifyytracereplacements
                  \errmessage{string <\the#1> not present in \the#2}% do not change the register if the string is not there
              \fi
          \else % remove the extra copy of #1\end at the end
              \yyreplacedtrue
              \expandafter#2\expandafter\expandafter\expandafter
                  {\expandafter\r@plac@string\expandafter{\the#3}{##1}##2\end}%
      \fi}% end of \r@placestring definition
      \expandafter\def\expandafter\r@plac@string
          \expandafter##\expandafter1%
          \expandafter##\expandafter2%
          \expandafter##\expandafter3%
          \the#1\end{##2##1##3}%
      \expandafter\expandafter\expandafter\r@placestring\expandafter\the\expandafter#2\the#1\end
}

% creating a sequence containing all pairs from the two given sequences;
% the (long) string produced by the \diagprod macro
% lists all the elements so that each ordered pair ab where a and b are
% different elements from each of the two sets appears exactly once;
% a simple strategy for creating such strings is to build them recursively so that if
% S is a string that lists n values in this manner and s is a new item type,
% start with sSs and then add each symbol from S on either side 
% in such a way that among any two consecutive symbols exactly one is s

% these macros are used to create switch statements that use such ordered pairs
% and are not particularly general or robust; 
% they are supposed to be used once in the setup stage;
% the assumption made by these mactos is that `.' or `;' never appear as elements 
% of the two sets

\def\gnxtelem#1\to#2\and#3{%
    \expandafter\gnxtel@m\expandafter#2\expandafter#3\the#1.;%
}

\def\gnxtel@m#1#2#3#4;{%
    \def\next{#4}%
    \ifx\next\empty
        #1{}%
    \else
        #1{#3}%
        \gnxt@l@m#2#4%
    \fi
}

\def\gnxt@l@m#1#2.{%
    #1{#2}%
}

\def\pairup{%
    \gnxtelem\toksa\to\toksc\and\toksa % get the first remaining element of set A (\toksa)
    \edef\elemofA{\the\toksc}%
    \ifx\elemofA\empty % no more elements in A
         \let\next\relax
    \else
        \ifx\elemofA\lastelemofB % the current element of A is the same as the last element of B
            \edef\next{\the\toksa}%
            \ifx\next\empty % it is the last remaining element of A
                \expandafter\p@ir@p\the\toksb.% form all pair of \the\toksc with elements in B except the first one
            \else
                \concat\toksa\toksc % move it to the end of A
            \fi
            \let\next\pairup
        \else
            \expandafter\pair@p\the\toksb.% form all pairs of \the\toksc with elements in B
            \let\next\pairup
        \fi
    \fi
    \next
}

\def\dotcontainer{.}

\def\pair@p#1{%
    \def\next{#1}%
    \ifx\next\elemofA % the next element of B is the current element of A
        \ifx\next\lastelemofB % it is the last element of B
                              % we can arrive here only if 1) B has more than one element and 
                              % 2) \elemofA is the last remaining element of A
            \edef\next{\toksd{\the\toksd\the\tokse}}\next
            \let\next\eatone % eat the remaining dot     
        \else
            \removeelem\elemofA\from\toksb % remove it from B
            \let\next\pair@p
        \fi
    \else
        \ifx\next\dotcontainer % no more elements in B
            \let\next\relax
        \else
            \toksf{#1}%
            \edef\next{\toksd{\the\toksd\the\toksc\the\toksf}}\next
            %\showthe\toksd
            \let\next\pair@p
        \fi
    \fi
    \next
}

\def\p@ir@p#1{%
    \def\next{#1}%
    \ifx\next\elemofA % the next element of B is the current element of A
                      % this can only happen if B consists of a single element
        \let\next\eatone
    \else
        \toksf{#1}%
        \edef\next{\toksd{\the\toksd\the\toksf}}\next
        \let\next\pair@p
    \fi
    \next
}

\def\removeelem#1\from#2{% #1 should be a sequence containing the element
                         % #2 is the token register
    \expandafter\def\expandafter\r@moveelem\expandafter##\expandafter1#1##2.{%
        \def\next{##2}%
        \ifx\next\empty % there was no such element
            \errmessage{Could not find \expandafter\string#1 in \the#2}%
        \else
            \expandafter\def\expandafter\r@mov@elem\expandafter####\expandafter1#1{%
                #2{##1####1}%
            }\r@mov@elem##2%
       \fi
    }%
    \expandafter\expandafter\expandafter\r@moveelem\expandafter\the\expandafter#2#1.%
}

% the intersection of A and B should be at the end of A:

\def\pushintersect{%
    \gnxtelem\toksf\to\toksc\and\toksf % get the first remaining element of set A (\toksa)
    \edef\next{\the\toksc}%
    \ifx\next\empty % there are no elements left in A
        \let\next\relax
    \else
        \expandafter\def\expandafter\p@shintersect\expandafter##\expandafter1\the\toksc##2.{%
            \def\next{##2}%
            \ifx\next\empty % there was no such element in the other set
                \edef\next{\toksa{\the\toksc\the\toksa}}\next % append it to the front
            \else
                \edef\next{\toksa{\the\toksa\the\toksc}}\next % append it to the back
            \fi
        }%
        \expandafter\expandafter\expandafter\p@shintersect\expandafter\the\expandafter\toksb\the\toksc.%
        \let\next\pushintersect
    \fi
    \next
}

\def\diagprod#1#2\in#3{%
    \toksa\expandafter{#1}%
    \toksb\expandafter{#2}%
    \gnxtelem\toksb\to\tokse\and\toksb % \tokse is a selected element in set B (\toksb)
    \concat\toksb\tokse % now \tokse is the last element of B 
    \toksf\toksa\toksa{}%
    \pushintersect % prepare the sequence representing set A so that the intersection elements are in the tail
    \edef\lastelemofB{\the\tokse}% the last element of B
    \toksd\expandafter{\the\tokse}% future sequence pairs
    \pairup
    \edef#3{\the\toksd}%
}

% namespace management for macros
% note that if one of the sequences were made \let\name. the macros would break;
% this can be fixed by using a more sophisticated comparison but was decided against
% in the interest of efficiency; the old version (that used a control sequence
% as a `stop marker') was more prone to this bug.

% the next sequence is not merely a convenient abbreviation; it is useful if one
% wants to look at an `alternative' value stored for the sequence without restoring
% it to the curent namespace; it also sets up the naming convention for namespaces

\def\restorecsname#1#2{% get the name of the sequence in storage
                       % note that #2 can be a string beginning with an arbitrary
                       % character as a placeholder for the escape character
    '#1'[\expandafter\eatone\string#2]%
}

% save macros listed in #2 in namespace #1

\def\savecs#1#2{\s@vecs{#1}#2.}

\def\s@vecs#1#2{%
    \ifx#2.%
        \yybreak{}%
    \else
        \yybreak{%
            \expandafter\let\csname\restorecsname{#1}{#2}\endcsname#2%
            \s@vecs{#1}%
        }%
    \yycontinue
}

% similar to the macro above but the list is a control sequence

\def\savecslist#1#2{%
    \expandafter\s@vecslist\expandafter{#2}{#1}%
}

\def\s@vecslist#1#2{%
    \savecs{#2}{#1}%
}

\def\restorecs#1#2{\r@storecs{#1}#2.}

\def\r@storecs#1#2{%
    \ifx#2.%
        \yybreak{}%
    \else
        \yybreak{%
            \expandafter\let\expandafter#2\csname\restorecsname{#1}{#2}\endcsname
            \r@storecs{#1}%
        }%
    \yycontinue
}

\def\restorecslist#1#2{%
    \expandafter\r@storecslist\expandafter{#2}{#1}%
}

\def\r@storecslist#1#2{%
    \restorecs{#2}{#1}%
}

\def\hidecs#1{\h@decs#1.}

\def\h@decs#1{%
  \ifx#1.%
      \yybreak{}%
  \else
      \yybreak{%
          \let#1\relax
          \h@decs
      }%
  \yycontinue
}

\def\hidecslist#1{\expandafter\hidecs\expandafter{#1}}

\def\savehcs#1#2{\savecs{#1}{#2}\hidecs{#2}}

\def\savehcslist#1#2{%
    \expandafter\s@vehcslist\expandafter{#2}{#1}%
}

\def\s@vehcslist#1#2{%
    \savehcs{#2}{#1}%
}

% a twist on the macros above: save control sequences with a postfix

\def\savecsx#1#2{\s@vecsx{#1}#2.} % there is no \savecsxlist macro

\def\s@vecsx#1#2{% #1 is the namespace, #2 is a control sequence without the postfix or prefix
  \ifx#2.%
      \yybreak{}%
  \else
      \yybreak{%
          \expandafter\s@vecsxlet\csname\expandafter\defprefix\expandafter\eatone\string#2\defpostfix\endcsname#2{#1}%
          \s@vecsx{#1}%
      }%
  \yycontinue
}

\def\s@vecsxlet#1#2#3{% #1 is the control sequence augmented by prefix and postfix,
                      % #2 is the control sequence without prefix or postfix
                      % #3 is the namespace
    \expandafter\let\expandafter#1\csname\restorecsxname{#3}{#2}\endcsname
}

\def\restorecsx#1#2{\r@storecsx{#1}#2.}

% see remarks about \restorecsname above

\def\restorecsxname#1#2{%
    '#1'[\expandafter\defprefix\expandafter\eatone\string#2\defpostfix]%
}

\def\r@storecsx#1#2{%
  \ifx#2.%
      \yybreak{}%
  \else
      \yybreak{%
          \expandafter\r@storecsxlet\expandafter#2\csname\restorecsxname{#1}{#2}\endcsname
          \r@storecsx{#1}%
      }%
  \yycontinue
}

\def\restorecsxlist#1#2{%
    \expandafter\r@storecsxlist\expandafter{#2}{#1}%
}

\def\r@storecsxlist#1#2{%
    \restorecsx{#2}{#1}%
}

\def\r@storecsxlet#1{%
  \expandafter\let\csname\expandafter\defprefix\expandafter\eatone\string#1\defpostfix\endcsname
}

\def\hidecsx#1{\h@decsx#1.}

\def\h@decsx#1{%
  \ifx#1.%
      \yybreak{}%
  \else
      \yybreak{%
          \expandafter\let\csname\expandafter\defprefix\expandafter\eatone\string#1\defpostfix\endcsname\relax
          \h@decsx
      }%
  \yycontinue
}

\def\savehcsx#1#2{\savecsx{#1}{#2}\hidecsx{#2}}

\def\defx#1{% defining sequences as above
  \toksa\expandafter{%
  \csname\expandafter\defprefix\expandafter\eatone\string#1\defpostfix\endcsname}%
  \afterassignment\d@fx
  \expandafter\def\the\toksa
}

\def\d@fx#1{%
  \toksb{#1}\edef\next{\noexpand\savehcs{\the\toksb}\the\toksa}\next
}

\def\defy#1#2#{% in addition to the definition of the contorl sequence
               % in the appropriate namespace, this macro adds a
               % preamble, a postamble and a `this' type macro; this
               % will mostly be used with indexing \TeX\ control sequences
  \toksf{\def\thisname{#1}\edef\thisnamex{\expandafter\eatone\string#1}}%
  \toksa\expandafter{%
      \csname\expandafter\defprefix\expandafter\eatone\string#1\defpostfix\endcsname}%
  \toksc\expandafter{\expandafter\def\the\toksa#2}%
  \afterassignment\d@f@
  \toksd=%
}

\def\d@f@{%
   \tokse{\defypreamble}%
   \concatl\tokse\toksd
   \concatl\toksf\toksd
   \tokse{\defypostamble}%
   \concat\toksd\tokse
   \toksd\expandafter{\expandafter{\the\toksd}}%
   \concat\toksc\toksd
   \afterassignment\d@fy
   \the\toksc
}

\def\d@fy#1{%
  \toksb{#1}\edef\next{\noexpand\savehcs{\the\toksb}\the\toksa}\next
}

% dynamic typing macros

\def\defp#1#2#{% flexible dynamic type checking
    \toksa\expandafter\expandafter\expandafter{\yyuniontag#1}%
    \expandafter\edef\yyuniontag{\the\toksa}% add the sequence to the current union
    \def#1#2{\errmessage{unexpected type: \string#1 in namespace <\currentyyunionnamespace>}}%
    \savecs\parserstrictnamespace#1%
    \toksa{#2}%
    \edef#1{\the\toksa}% save the prototype
    \savecs\parserprototypesnamespace#1%
    \let#1\relax
    \savecs\parserdebugnamespace#1% save the debug sequence for outputting the AST
    \def#1#2%
}

% define the macro with checking of the prototype

\def\defu#1#2#{%
    \restorecs\parserprototypesnamespace#1%    
    \toksa{#2}%
    \edef\next{\the\toksa}%
    \ifx#1\next
        \yybreak{\def#1#2}%
    \else
        \toksb\expandafter{#1}%
        \yybreak{%
            {\newlinechar=`^^J%
            \errhelp{the prototype of #1is from <parser-strict:headers>^^J%
                     you might want to look for a \defp#1line... somewhere}%
            \errmessage{macro definition of \noexpand#1 
                        does not match its prototype:^^J 
                        \the\toksa\space (should be \the\toksb)}%
            }%
        }%
    \yycontinue
}

% define the macro with an automatic prototype

\def\defc#1{%
    \restorecs\parserprototypesnamespace#1%    
    \expandafter\def\expandafter#1#1%
}

\def\t@yyunion#1#2{\def\currentyyunionnamespace{#2}\savecslist{#2}#1}
\def\toyyunion#1{\expandafter\t@yyunion\yyuniontag{#1}}

{\catcode`\ =13 \aftergroup\def\aftergroup\activespace\aftergroup{\aftergroup \aftergroup}}% active space
{\catcode`\% =12 \aftergroup\def\aftergroup\harmlesscomment\aftergroup{\aftergroup%\aftergroup}}% not really a comment
{\catcode`\{ =12 \catcode`\[=1 \aftergroup\def\aftergroup\lbchar\aftergroup[\aftergroup{\aftergroup}}% not really a brace
{\catcode`\} =12 \catcode`\]=2 \aftergroup\def\aftergroup\rbchar\aftergroup{\aftergroup}\aftergroup]]% not really a brace
{\catcode`\_=12 \aftergroup\def\aftergroup\uscoreletter\aftergroup{\aftergroup_\aftergroup}}
{\catcode`\^^M=12 \aftergroup\def\aftergroup\eolletter\aftergroup{\aftergroup^^M\aftergroup}}% end of line, ... not really
{\catcode`\|=0\catcode`\\=12 |aftergroup|def|aftergroup|benignescape|aftergroup{|aftergroup\|aftergroup}}% not an escape
{\catcode`\#=12 \aftergroup\def\aftergroup\hashletter\aftergroup{\aftergroup#\aftergroup}}% not a parameter token
{\catcode`\~=12 \aftergroup\def\aftergroup\safetilde\aftergroup{\aftergroup~\aftergroup}}% inactive tie
{\catcode`\$=12 \aftergroup\def\aftergroup\safemath\aftergroup{\aftergroup$\aftergroup}}% not really a start math character

\let\uscore\_ % the canonical underscore for the fonts that do not have the character

% remove the brackets from the namespace string;
% the parameter is the control sequence that expands to the namespace string

\def\stripbrackets#1{\expandafter\stripbr@ckets#1[]\end}

\def\stripbr@ckets#1[#2]#3\end{\yystringempty{#3}{#1}{#1#2}}

% token name input

\def\doascii#1{%
  \tempca=\z@ \tempcb=\@cclvi
  \let\yyasciicc\empty
  \let\sts\relax
  \loop
      \edef\yyasciicc{\sts{\the\catcode\tempca}\yyasciicc}%
      \catcode\tempca=#1
      \advance\tempca\@ne
  \ifnum\tempca<\tempcb\relax
  \repeat
  \catcode`\ =10 % keep normal spaces (otherwise \string will convert the category to 10)
  %\catcode`\^^M=5 % if newline is to be preserved
  \catcode`\^^M=12 % to match \eolletter
}

\def\undoascii{%
  \tempca=\@cclv
  \let\sts\undoacatcode
  \yyasciicc\def\yyasciicc{}%
}

\def\undoacatcode#1{\catcode\tempca=#1\advance\tempca\m@ne}

% yytname macros

\def\endcontainer{\end}%
\def\aaddname{\addname}

\def\addname{%
    \toksb{}%
    \@ddname
}

\def\@ddname#1{%
    \def\next{#1}%
    \ifx\next\aaddname
        \expandafter\edef\csname term\parsernamespace\the\toksb \endcsname{\the\tempca}%
        \appendtoyytname
        \advance\tempca1\relax
        \let\next\addname
    \else
        \ifx\next\endcontainer
            \expandafter\edef\csname term\parsernamespace\the\toksb \endcsname{\the\tempca}%
            \appendtoyytnamelast
            \let\next\relax
        \else
            \ifnum#1=`\_\relax
                \uccode`\.=#1\relax
                \uppercase{\toksa{.}}%
                \uccode`\.=`\.%
            \else
                \ifnum#1=`\-\relax
                    \toksa{-}%
                \else
                    \ifnum#1=`\ \relax
                        \toksa{ }%
                    \else
                        \uccode`\@=#1\relax
                        \uppercase{\toksa{@}}%
                        \uccode`\@=`\@\relax
                    \fi
                \fi
            \fi
            \concat\toksb\toksa
            \let\next\@ddname
        \fi
    \fi
    \next
}

\def\appendtoyytname{%
    \concat\yytname\toksb
    \toksa{\or}%
    \concat\yytname\toksa
}

\def\appendtoyytnamelast{%
    \concat\yytname\toksb
}

\def\print#1{{\endlinechar=`\^^J\immediate\write16{#1}}}

% token and state setup
% these are defined for a specific (though dynamic) namespace only

\def\tokenset#1#2{%
    \expandafter\edef\csname token\parsernamespace \fgetelemof{yytname}\at{#1}\endcsname{#2}%
}

\def\settokens{%
    \tempca=1\relax
    \loop
        \tempcb=\fgetelemof{yytranslate}\at\tempca\relax % important \relax!
        \tokenset\tempcb{\the\tempca}%
        \advance\tempca\@ne
    \ifnum\YYTRANSLATESIZE>\tempca
    \repeat
    \relax
}

\def\stateset#1#2{%
    \expandafter\def\csname flexstate\parsernamespace #1\endcsname{#2}%
}

% token equivalence for bootstrap

\def\tokeneq#1#2{%
    \toksa{}%
    \numberstochars#2\end
    \toksa\expandafter{\csname token\parsernamespace\the\toksa\endcsname}%
    \toksb\expandafter{\csname token\parsernamespace#1\endcsname}%
    \edef\next{\let\the\toksb\the\toksa}\next
}%

\def\numberstochars#1{%
    \ifx\end#1%
        \yybreak{}%
    \else
        \uccode`.=#1\relax
        \uppercase{\toksa\expandafter{\the\toksa.}}%
        \uccode`.=`\.%
        \yybreak{\numberstochars}%
    \yycontinue
}

\def\numberstocharsandspaces#1{% same as above but turn \number`\ into a real space token
    \ifx\end#1%
        \yybreak{}%
    \else
        \ifnum#1=` \relax
            \yybreak@{%
                \expandafter\expandafter\expandafter
                \toksa\expandafter\expandafter\expandafter{\expandafter\the\expandafter\toksa\space}\numberstocharsandspaces}%
        \else
            \uccode`.=#1\relax
            \uppercase{\toksa\expandafter{\the\toksa.}}%
            \uccode`.=`\.%
        \fi
        \yybreak{\numberstocharsandspaces}%
    \yycontinue
}


% other parser and lexer variables

\newtoks\pinittoks % a token register to hold the code that switches the parser to a different namespace

% tables

\def\newtable@full#1{%
    \expandafter\expandafter\csname newtoks\endcsname\csname #1\parsernamespace\endcsname
    \expandafter\expandafter\expandafter\let\expandafter
        \expandafter\csname #1\endcsname\csname #1\parsernamespace\endcsname
    \appendr\pinittoks{\let\expandafter\noexpand\csname #1\endcsname
        \expandafter\noexpand\csname #1\parsernamespace\endcsname}%
    \csname #1\parsernamespace\endcsname=%
}

\let\newtable\newtable@full % optimization can change this

% constants

\def\constset#1#2{%
    % a \mathchardef would be nicer but it cannot handle negative numbers
    \expandafter\def\csname #1\parsernamespace\endcsname{#2}%
    \expandafter\expandafter\expandafter\let\expandafter
        \expandafter\csname #1\endcsname\csname #1\parsernamespace\endcsname
    \appendr\pinittoks{\let\expandafter\noexpand\csname #1\endcsname
        \expandafter\noexpand\csname #1\parsernamespace\endcsname}%
}

\def\uconstset#1#2{%
    % a \mathchardef for positive constants
    \expandafter\mathchardef\csname #1\parsernamespace\endcsname=#2 %
    \expandafter\expandafter\expandafter\let\expandafter
        \expandafter\csname #1\endcsname\csname #1\parsernamespace\endcsname
    \appendr\pinittoks{\let\expandafter\noexpand\csname #1\endcsname
        \expandafter\noexpand\csname #1\parsernamespace\endcsname}%
}

\def\charset#1#2{%
    \expandafter\chardef\csname #1\parsernamespace\endcsname=#2\relax%
    \expandafter\expandafter\expandafter\let\expandafter
        \expandafter\csname #1\endcsname\csname #1\parsernamespace\endcsname
    \appendr\pinittoks{\let\expandafter\noexpand\csname #1\endcsname
        \expandafter\noexpand\csname #1\parsernamespace\endcsname}%
}

% parser and lexer state control

\def\settokreg#1{% do not create individual token registers for each parser namespace
    \expandafter\ifx\csname #1\endcsname\relax
        \expandafter\expandafter\csname newtoks\endcsname\csname #1\endcsname
    \fi
}

\def\setcntreg#1{% do not create individual count registers for each parser namespace
    \expandafter\ifx\csname #1\endcsname\relax
        \expandafter\expandafter\csname newcount\endcsname\csname #1\endcsname
    \fi
}

\def\setnulstack#1{%
    \expandafter\let\csname #1\parsernamespace\endcsname\empty % for the unoptimized stack
    \appendr\pinittoks{\let\expandafter\noexpand\csname #1\endcsname
        \expandafter\noexpand\csname #1\parsernamespace\endcsname}%
    \setcntreg{#1<count>}% this is only (as well as the only action that is) needed for the accelerated stack
}

\def\setcurrentcs#1{%
    \expandafter\expandafter\expandafter\let\expandafter
        \expandafter\csname #1\parsernamespace\endcsname\csname #1\endcsname
    \appendr\pinittoks{\let\expandafter\noexpand\csname #1\endcsname
        \expandafter\noexpand\csname #1\parsernamespace\endcsname}%
}

% switch macro

\let\stashswitch\setcurrentcs

\def\newparserstate{%
  \setcntreg{yytoken}%
  \setcntreg{yystate}%
  \setcntreg{yyn}%
  \setcntreg{yylen}%
  %
  \setcntreg{yyilen}% depth of stack before an inline action
  % \yyval and \yylval will be token registers
  \settokreg{yyval}%
  \settokreg{yylval}%
  \setnulstack{astarray}% an array of AST nodes
  \setnulstack{yyssa}%
  \setnulstack{yyvsa}%
}

\def\newlexerstate{%
  \settokreg{yytext@}% `dirty' buffer (contains stash and formatting)
  \settokreg{yytext@seen}% read `dirty' buffer
  \settokreg{yytext}%
  \settokreg{yytextseen}%
  \settokreg{yybyte}%
  \settokreg{yysubtext}% stash between characters
  \settokreg{yyfutureyytext}%    token register used to save read text in eob macros
  %
  \settokreg{yytextpure}%      % the registers that serve the same role
  \settokreg{yytextseenpure}%  % as \yytext et al except they collect characters
  \settokreg{yybytepure}%      % with category code 11 (letter) and the same character code
  %
  \settokreg{yyformat}%        % the registers that serve the same role
  \settokreg{yyformatseen}%    % as \yytext et al except they collect format
  \settokreg{yyfbyte}%         % commands
  %
  \settokreg{yystash}%         % the registers that serve the same role
  \settokreg{yystashseen}%     % as \yytext et al except they collect stashed
  \settokreg{yysbyte}%         % tokens
  %
  \setcntreg{yycurrentstate}%
  \setcntreg{yycurrentstatelocal}% a state variable used in eob macros
  \setcntreg{yyc}%
  \setcntreg{yyclocal}% another eob macro variable
  \setcntreg{yyact}%
  \setcntreg{yyg@yyinit}%
  \setcntreg{yyg@yystart}%
  \setcntreg{yyg@yylastacceptingstate}%
  \setcntreg{yycp@}%
  \setcntreg{YYATBOL}%
  \setcntreg{yychar}%
  %
  \setcntreg{yytextlastchar}%
  \setcntreg{yytextseenlastchar}%
  %
  \setcntreg{yyfmark}%        % the last marker in the current token
  \setcntreg{yyfmarklast}%
  \setcntreg{yyfmark@accept}%
  \setcntreg{yysmark}%
  \setcntreg{yysmarklast}%
  \setcntreg{yysmark@accept}%
  \setnulstack{yystatestack}%
  \setcurrentcs{setflexstates}%
  \setcurrentcs{ifyytextbackup}% this is purely to record the recovery command in \pinittoks
}

% use \pinittoks to compose a `parser restore' macro along with 
% \let\yyvsa\yyvsa[parser namespace] and \let\yyssa\yyssa[parser namespace];
% `parser save' macro only has to set up \yy?sa[parser namespace]'s;
%
% this mechanism creates parsers that (barely) survive namespace switches (such as when a local
% parser is used to extract information about the tokens) and does not result in a reentrant parser;
% if a fully reentrant parser is required, either use the macros above to save the contents of
% all the variables by redefining \settokreg and \setcntreg and saving \yy?sa stacks or, better still,
% take advantage of the grouping mechanism provided by \TeX; note that the grouping approach seems
% to be the only viable solution if the stack mechanism is `optimized'

% optimization options

\def\optimizeall{%
        % lexer
    \ifnum\optimization>\z@
        \optimize{yynxt}%
        \optimize{yyaccept}%
        \optimize{yydef}%
        \optimize{yychk}%
        \optimize{yybase}%
        \optimize{yyec}%
        \optimize{yymeta}%
        \tracingstats=\@ne
    \fi
        % parser
    \ifnum\optimization>\@ne
        \optimize{yytranslate}%
        \optimize{yyrone}%
        \optimize{yyrtwo}%
        \optimize{yyrthree}%
        \optimize{yydefact}%
        \optimize{yydefgoto}%
        \optimize{yypact}%
        \optimize{yypgoto}%
        \optimize{yytable}%
        \optimize{yycheck}%
        \optimize{yyprhs}%
        \optimize{yyrhs}%
        \optimize{yytoknum}%
        \optimize{yystos}%
        \optimizetext{yytname}%
    \fi
}

% parser and lexer initialization, token prettyfying

\def\genericparser name: #1, ptables: #2, ltables: #3, tokens: #4, asetup: #5, dsetup: #6, rsetup: #7, optimization: #8;{%
    % parser initialization
    %
    \expandafter\def\csname #1namespace\endcsname{[#1]}%
    \savecs{local-namespace}\parsernamespace
    \expandafter\let\expandafter\parsernamespace\csname #1namespace\endcsname
    \pinittoks{}%
    \input #2 % load main parser table
    \settokens % set the values of all tokens
    \yystringempty{#4}{}{%
        \input #4 % use token equivalence table to set the values of non-string tokens
    }%
    #5% (a)dditional setups
    %
    \input #3 % load lexer tables
    %
    % at this point the macros inside the table files (\newtable, \constset, 
    % \yybigswitch, \stashswitch, \addname, \yydoactionswitch, \setflexstates, 
    % \stateset, \tokeneq) have set up the corresponding stuctures in 
    % the `parser namespace' (e.g. if the parser namespace is `main', 
    % \newtable{yyaccept} created a token register \yyaccept[main]), 
    % assigned the `generic' names to them (to continue 
    % the example above, \newtable does \let\yyaccept\yyaccept[main]) and 
    % recorded the corresponding commands in \pinittoks for future use.
    %
    % lexer state macros are namespace specific (just like token names) 
    % so they have to be set in each namespace.
    %
    \setflexstates
    #8% possible optimization
    %
    % finally, we add the definitions for the variables used in running 
    % the lexer and the parser.
    \newparserstate
    \newlexerstate
    #6% additional (d)ata setup (say, \newlexerstateextra)
    %
    % we record all the commands necessary to switch to the desired namespace 
    % in a convenient macro
    {%
        \toks0{#7}% additional setup before switching namespaces
        \edef\next{%
            \the\toks0 % additional namespace setups
            \let\noexpand\parsernamespace\expandafter\noexpand\csname #1namespace\endcsname 
            \the\pinittoks % restore all the tables, tokens and constants, and stacks
            \let\noexpand\getcurrentparser\expandafter\noexpand\csname to#1parser\endcsname
        }%
        \toks0\expandafter{\next}%
        \edef\next{\toks0{\def\expandafter\noexpand\csname to#1parser\endcsname{\the\toks0}}}\next
        \expandafter
    }\the\toks0
    \restorecs{local-namespace}\parsernamespace
}

\def\genericprettytokens namespace: #1, tokens: #2, correction: #3, host: #4;{%
    \savecs{local-namespace}{\parsernamespace\tokeneq}%
        \yystringempty{#2}{}{%
            \expandafter\let\expandafter\parsernamespace\csname #1namespace\endcsname
            \def\tokeneq##1##2{\prettytoken{##1}}%
            \let\tokenpp\prettytoken
            \input #2 % /* re-use token equivalence table to set the typesetting of tokens */
        }%
        \yystringempty{#3}{}{%
            \expandafter\let\expandafter\parsernamespace\csname #1namespace\endcsname
            \input #3 % input customized typesetting rules for tokens
        }%
        \yystringempty{#4}{}{%
            \expandafter\let\expandafter\hostparsernamespace\csname #4namespace\endcsname
        }%
    \restorecs{local-namespace}{\parsernamespace\tokeneq}%
}

% switch and dfa macros

%% character class checking: #1 is the character, #2 is the character class control sequence

\newif\ifinclass

\def\ifclassof#1\is#2{%
  \tempca#1\relax
  \expandafter\checkclass#2\end
}

\def\checkclass#1{%
  \ifx#1\end
      \let\next\relax
      \inclassfalse
  \else
      \ifnum`#1=\tempca
          \let\next\classend
          \inclasstrue
      \else
          \let\next\checkclass
      \fi
  \fi
  \next
}

\tempca=\catcode`\^^A
\catcode`\^^A=12 % so that the characters inside sequences get the appropriate catcodes

\def\classend#1\end{}

\def\setspecialchars#1{%
  \toksa{}%
  \tempca=`\ %
  \loop
      \advance\tempca\@ne
      \tempcb=\fgetelemof{yytranslate}\at\tempca\relax
      \ifnum\tempcb>\tw@
          \tempcb=\uccode`^^A\uccode`^^A=\tempca
          \uppercase{\edef\next{\toksa{\the\toksa^^A}}}\next
          \uccode`^^A=\tempcb
      \fi
  \ifnum\tempca<\@cclv
  \repeat
  \edef#1{\the\toksa}%
}

\newif\iftraceswitchlabels
\traceswitchlabelstrue

\def\setspecialcharsfrom#1{%
  \toksb\expandafter{#1}%
  \iftraceswitchlabels
      \edef\next{\toksa{\expandafter\noexpand\csname <state: \expandafter\eatone\string#1>\endcsname}}\next
      \expandafter\let\the\toksa\empty
  \else
      \toksa{}%
  \fi
  \tempcb=\uccode`\^^A\relax
  \expandafter\s@tspecialcharsfrom\the\toksb\end
  \edef#1{\the\toksa}%
  \uccode`\^^A=\tempcb
}

\def\s@tspecialcharsfrom{%
  \futurelet\next\s@tsp@cialcharsfrom
}%

\def\s@tsp@cialcharsfrom{%
  \ifcat\space\noexpand\next
      \expandafter
      \s@tsp@cialch@rsfr@m
  \else
      \expandafter
      \s@tsp@cialch@rsfrom
  \fi
}

\def\s@tsp@cialch@rsfr@m{%
  \afterassignment\s@tspecialcharsfrom\let\next= % this is the optional space
}

\def\s@tsp@cialch@rsfrom#1{%
  \toksb{#1}%
  \ifx\next\bgroup % this is an action group
      \edef\next{\toksa{\the\toksa{\the\toksb}}}\next
      \let\next\s@tspecialcharsfrom
  \else
      \let\default\specchardefault
      \iftracedfa % to avoid conflicts while tracing actions
          \tracedfafalse
          \switchon{\the\toksb}\in\speccharswitch
          \tracedfatrue
      \else
          \switchon{\the\toksb}\in\speccharswitch
      \fi           
  \fi
  \next
}%

\def\speccharswitch{%
    \end {%
        \let\next\relax
    }
    \raw \rawcode \classexpand \meanit \statecomment {%
        %
    }
}

\def\specchardefault{%
    \uccode`\^^A\expandafter`\the\toksb
    \uppercase{\edef\next{\toksa{\the\toksa^^A}}}\next
    \let\next\s@tspecialcharsfrom
}

\def\raw#1\raw{%
  \toksb{#1}%
  \concat\toksa\toksb
  \s@tspecialcharsfrom
}

\def\rawcode#1{%
  \ifx#1\rawcode
      \let\next\s@tspecialcharsfrom
  \else
      \uccode`\^^A=#1\relax
      \uppercase{\edef\next{\toksa{\the\toksa^^A}}}\next
      \let\next\rawcode
  \fi
  \next
}

\def\classexpand#1{%
  \toksb\expandafter{#1}%
  \concat\toksa\toksb
  \s@tspecialcharsfrom
}

\def\meanit#1{%
  \toksb\expandafter{\meaning#1}%
  \concat\toksa\toksb
  \s@tspecialcharsfrom
}

\def\statecomment#1\statecomment{\edef\next{\toksa{\the\toksa
    \expandafter\noexpand\csname (#1)\endcsname}}\next\s@tspecialcharsfrom}

\def\putother#1\in#2{%
  \tempca=\catcode`\^^A\relax
  \tempcb=\uccode`\^^A\relax
  \uccode`\^^A=#1\relax
  \uppercase{\edef\next{#2{^^A}}}\next
  \uccode`\^^A=\tempcb         
}

% listing all the rules in a macro

\def\listrules{%
  \tempcb=\tw@ % start with a user-set rule
  \loop
      \listrule
  \ifnum\tempcb<\YYNRULES\relax
      \advance\tempcb\@ne
  \repeat
}

\catcode`\$=11

\def\listrule{%
  \tempcc=\fgetelemof{yyrone}\at\tempcb\relax % get the symbol this rule derives
  \edef\next{\toksa{\fgetelemof{yytname}\at\tempcc}}\next
  \expandafter\checkforimplicit\the\toksa $@\end%$
  \ifimplicit
      \edef\next{\toksc{\noexpand\ih{\the\toksa}}}\next
      \edef\next{\toksa{\noexpand\implicitrule[\the\toksa]}}\next
  \else
      \edef\next{\toksa{\the\tempcc}}\next
      \toksc{}%
  \fi
  \appendr\toksa{:}%
  \toksb{}%
  \tempcc=\fgetelemof{yyprhs}\at\tempcb\relax
  \tempcd=\fgetelemof{yyrhs}\at\tempcc\relax
  \listr@le
  \edef\next{\newsymswitch{\the\newsymswitch\the\toksa\def{\the\toksc:\the\tempcb}\noexpand\ruleor}}\next
}

\def\implicitsymbol#1{}%

\newif\ifimplicit

\def\listr@le{%
  \ifnum\tempcd>\m@ne
      \ifnum\tempcd<\YYNTOKENS\relax % it is a terminal
          \edef\next{\toksb{\the\tempcd}}\next
      \else
          \edef\next{\toksb{\fgetelemof{yytname}\at\tempcd}}\next
          \expandafter\checkforimplicit\the\toksb $@\end%$
          \ifimplicit
              \appendl\toksc{\noexpand\imn{\the\toksb}}
              \toksb{@implicit@}%
          \else
              \edef\next{\toksb{\the\tempcd}}\next
          \fi
      \fi
      \appendr\toksa{ }\concat\toksa\toksb
      \advance\tempcc\@ne
      \tempcd=\fgetelemof{yyrhs}\at\tempcc\relax
      \let\next\listr@le
  \else % this is the end of the rhs
      \let\next\relax
  \fi
  \next
}

\def\checkforimplicit#1$@#2\end{% $
  \def\next{#1}%
  \ifx\next\empty
      \implicittrue
  \else
      \implicitfalse
  \fi
}
\catcode`\$=3

% symbol switch macros

\newtoks\oneimplicitrule

% inline explicit symbolic names

\def\itermstack#1#2{%
  \toksa=\oneimplicitrule
  \appendl\toksa{\noexpand\lhs{#1}{#2}}%
  \expandafter
    \yypush
  \expandafter
    {\the\toksa}\on\yyirulestack
  \appendr\oneimplicitrule{\noexpand\implicitterm{#1}{#2}}%
}

\def\makeisymnames#1:#2\end{%
  \tempcc=#2\relax
  \def\next{#1}%
  \ifx\next\empty
      \relax
  \else
      \let\imn\assigninames
  \fi
  #1%
}

\def\assigninames#1{%
  \yypop\yyirulestack\into\toksc
  \def\sts##1{##1}%
  \savehcs{symn}{\term\lhs\implicitterm\onerule}%
  \edef\next{\noexpand\onerule{\the\toksc}}%
  \edef\next{\toksc{\next}}\next
  \toksb{\implicitrule[#1]:\def}%
  \yyreplacestring\toksb\in\newsymswitch\with\toksc
  \restorecs{symn}{\term\lhs\implicitterm\onerule}%
}

\def\oneruleid#1#2{%
  \oneimplicitrule{}%
  \yyinitstack\yyirulestack
  \toksb{#1}%
  #1%
  \makeisymnames#2\end
}

\def\termexsymname#1#2{%
  \appendr\oneimplicitrule{\noexpand\term{#1}{#2}}%
}

\def\iruleplaceholder#1:\def#2{}

\def\setexplicitinlinerules#1{%
  \let\onerule\oneruleid
  \let\term\termexsymname
  \let\lhs\eattwo
  \let\implicitterm\itermstack
  \let\ruleor\relax
  \let\ih\eatone
  \let\imn\eatone
  \let\implicitrule\iruleplaceholder
  \the#1% set explicit names  
}

\catcode`\^^A=\tempca

\def\makesymrefs#1{% #1 is the symbolic rule switch
    \let\ruleor\or
    \nameflagtoks{}%
    \edef\next{\setsncommands{\noexpand\or\space\harmlesscomment\space (rule 0)^^J%
                              \noexpand\or\space\harmlesscomment\space (rule 1)^^J}}\next
    \edef\next{\unsetsncommands{\noexpand\or\space\harmlesscomment\space (rule 0)^^J%
                                \noexpand\or\space\harmlesscomment\space (rule 1)^^J}}\next
    \yyn=\tw@
    \loop
        \yylen=\fgetelemof{yyrtwo}\at\yyn\relax
        \ifnum\yylen>\z@
        \else 
            \yylen=\fgetelemof{yyrthree}\at\yyn\relax
        \fi
        \xm@kesymrefs#1%
        \xm@k@symrefs#1%
        \addseparator
    \ifnum\yyn<\YYNRULES
        \advance\yyn\@ne
    \repeat
}

% these macros are here to hide \else and \fi tokens

\def\xm@kesymrefs#1{\expandafter\m@kesymrefs\expandafter\yyn\the#1\else\fi} % explicit names
\def\xm@k@symrefs#1{\expandafter\m@k@symrefs\expandafter\yyn\the#1\else\fi} % implicit names

\def\m@kesymrefs#1{%
  \let\onerule\rulesymsetup
  \ifcase#1\or\or % skip the first two rules
}

\def\m@k@symrefs#1{%
  \let\onerule\r@lesymsetup
  \ifcase#1\or\or % skip the first two rules
}

\def\addseparator{%
    \sprintrule\yyn\to\toksa
    \edef\next{\setsncommands{\the\setsncommands\noexpand\or\space\harmlesscomment\the\toksa^^J}}\next
    \edef\next{\unsetsncommands{\the\unsetsncommands\noexpand\or\space\harmlesscomment\the\toksa^^J}}\next
    \the\nameflagtoks
    \nameflagtoks{}%
}

\def\rulesymsetup#1#2{%
  \let\term\termsymname
  \let\lhs\lhssymname
  \let\implicitterm\term
  \tempca\@ne
  #1% set explicit names
}

\newtoks\setsncommands
\newtoks\unsetsncommands

\def\termsymname#1#2{% set the symbolic name, if it is nonempty
  \def\next{#2}%
  \ifx\next\empty
  \else % there is a symolic name
      \expandafter\ifx\csname$[#2]\endcsname\relax% i$ this name unassigned? 
          \setnameflag{#2}\end % ... this name has been explicitly set
          \setuprefs{#2}{\the\tempca}%
      \else
          \errmessage{ambiguous symbolic name: #2}%
      \fi
  \fi
  \advance\tempca\@ne
}

\newtoks\nameflagtoks

\def\setnameflag#1#2{%
    \toksa\expandafter{\csname$[#1]sym\endcsname}% $
    \edef\next{\let\the\toksa\noexpand#2}\next
    \appendr\nameflagtoks{\noexpand\unsetnameflag{#1}}%
}

\def\unsetnameflag#1{%
    \toksa\expandafter{\csname$[#1]sym\endcsname}% $
    \edef\next{\let\the\toksa\relax}\next
}

\def\unsetsymname#1{%
    \toksa\expandafter{\csname$[#1]\endcsname}% $
    \edef\next{\let\the\toksa\relax}\next
}

\def\unsetsym#1{%
    \toksa\expandafter{\csname$[#1]\endcsname}% $
    \toksb\expandafter{\csname$$[#1]\endcsname}% $
    \edef\next{\let\the\toksa\relax\let\the\toksb\relax}\next
}

\def\lhssymname#1#2{% set an explicit symbolic name for the left hand side
  \setuplhsref{#2}%
  \setnameflag{#2}\end % signal that this name has ben explicitly set
}

% the code below is just an example. One has to figure out how to record percent symbols and other 
% dangerous \TeX\ symbols; it is rather slow, a faster two stage scheme can be envisioned 
% where the first stage builds the command while iterating over the rule numbers; this is left as an exercise. 

\let\hc\harmlesscomment
\let\uu\space
\def\setuprefs#1#2{%
    \expandafter\let\csname$[#1]\endcsname.% $o the \ifx ... \relax test makes sense ...
    \appendr\nameflagtoks{\noexpand\unsetsymname{#1}}% clean it up later
    \toksa{}\expandafter\charstonumbers#1\end
    \edef\next{\toksb{\space\space\noexpand\setsym{\the\toksa}{#2}\hc^^J\uu\uu\hc\hc\hc\uu#1 --> #2^^J}}\next
    \edef\next{\toksc{\space\space\noexpand\unsetsym{\the\toksa}\hc^^J\uu\uu\hc\hc\hc\uu#1 --> \relax^^J}}\next
    \concat\setsncommands\toksb
    \concat\unsetsncommands\toksc
}%

\def\setuplhsref#1{%
    \def\next{#1}%
    \ifx\next\empty
    \else
        \expandafter\let\csname$[#1]\endcsname.% $o the \ifx ... \relax test makes sense ...
        \appendr\nameflagtoks{\noexpand\unsetsymname{#1}}% clean it up later
        \toksa{}\expandafter\charstonumbers#1\end
        \edef\next{\toksb{\uu\uu\noexpand\setlhs{\the\toksa}\hc^^J\uu\uu\hc\hc\hc\uu#1 --> $$^^J}}\next
        \edef\next{\toksc{\uu\uu\noexpand\unsetsym{\the\toksa}\hc^^J\uu\uu\hc\hc\hc\uu#1 --> \relax^^J}}\next
        \concat\setsncommands\toksb
        \concat\unsetsncommands\toksc
    \fi
}%

\def\sprintrule#1\to#2{%
    \tempcc=#1\relax  
    \tempcd=\fgetelemof{yyrone}\at\tempcc\relax
    \edef\ruleline{\space(rule \number#1)\space\fgetelemof{yytname}\at\tempcd:}%
    \tempcd=\fgetelemof{yyprhs}\at\tempcc\relax
    \tempcc=\fgetelemof{yyrhs}\at\tempcd\relax
    \ifnum\tempcc>\m@ne
        \fillruleline
    \else
        \edef\ruleline{\ruleline\space<empty>}%
    \fi
    #2\expandafter{\ruleline}%
}

\def\fillruleline{%
    \edef\ruleline{\ruleline\space\fgetelemof{yytname}\at\tempcc}%
    \advance\tempcd\@ne
    \tempcc=\fgetelemof{yyrhs}\at\tempcd\relax
    \ifnum\tempcc>\m@ne
        \let\next\fillruleline
    \else
        \let\next\relax
    \fi
    \next
}

\def\r@lesymsetup#1#2{%
  \let\term\termsymextra
  \let\lhs\lhssymextra
  \let\implicitterm\term
  \tempca=\@ne
  #1% set implicit names
}

\def\termsymextra#1#2{% set an implicit symbolic name: 
                      %   1) if it has not been defined yet, define it
                      %   2) if it is defined implicitly, make it \def
  \expandafter\let\expandafter\next\csname$[#1]\endcsname% $ this is the name we are trying to define
  \ifx\next\relax % it is not defined yet
      \setuprefs{#1}{\the\tempca}%
  \else % already defined
      \expandafter\ifx\csname$[#1]sym\endcsname\end % it i$ an existing explicit symbolic name, done
      \else
          \expandafter\ifx\csname$[#1]sym\endcsname\noindent % it i$ an existing implicit symbolic name of lhs, overwrite it
              \setuprefs{#1}{\the\tempca}%
          \else
              \edef\next{\toksa{\space\space\noexpand\locksymname{#1}\harmlesscomment^^J}}\next
              \edef\next{\toksb{\space\space\noexpand\unlocksymname{#1}\harmlesscomment^^J}}\next
              \concat\setsncommands\toksa % symbolic name defined implicitly, disallow it
              \concat\unsetsncommands\toksb
          \fi
      \fi
  \fi
  \advance\tempca\@ne
}

\def\locksymname#1{\expandafter\let\csname$[#1]\endcsname\def} %$
\def\unlocksymname#1{\expandafter\let\csname$[#1]\endcsname\relax} %$

\def\lhssymextra#1#2{% set the name of the left hand side implicitly
  \expandafter\let\expandafter\next\csname$[#1]\endcsname%$
  \ifx\next\relax % not defined yet
      \setuplhsref{#1}%
      \setnameflag{#1}\noindent % this lhs name has been implicitly set
  \fi % it is already defined
}

\catcode`\^^A=\tempca

% stack variable access

\def\ym#1){%
  \ifnum#1<\@ne
      \putyyvalt
  \else
      \ifnum#1>\yyilen
          \errmessage{parameter out of range (#1\space out of\space \the\yyilen)}%
      \else
          \expandafter\putyytoksx\csname$$'#1\endcsname
      \fi
  \fi
}

\def\yn#1#{%
  \ifnum#1<\@ne
      \putyyval
  \else
      \ifnum#1>\yyilen
          \errmessage{parameter out of range}%
      \else
          \expandafter\putyyassignment\csname$'\number#1\endcsname%$
      \fi
  \fi
}

\def\yx#1[{%
  \expandafter\ifx\csname$[#1]\endcsname\yyval%$
      \putyyvalt
  \else
      \expandafter\ifx\csname$[#1]\endcsname\def%$
          \errmessage{reference to ambiguous symbolic name: #1}%
      \else
          \expandafter\putyytoksx\csname$$[#1]\endcsname
      \fi
  \fi
}

\def\yz#1]{%
  \expandafter\ifx\csname$[#1]\endcsname\yyval%$
      \putyyval
  \else
      \expandafter\ifx\csname$[#1]\endcsname\def%$
          \errmessage{reference to ambiguous symbolic name: #1}%
      \else
          \expandafter\putyyassignment\csname$[#1]\endcsname%$
      \fi
  \fi
}

\def\putyyval\else#1\fi\fi{%
  \fi\yyvalx
}

\def\yyvalx#1{%
  \edef\next{\yyval{#1}}\next
}

\def\putyyvalt\else#1\fi\fi{%
  \fi\yyval
}

\def\putyyassignment#1\fi\fi{%
  \fi\fi\p@tyyassignment#1%
}

\def\putyytoksx#1\fi\fi{%
  \fi\fi#1%
}

\def\p@tyyassignment#1#2{%
  \yystringempty{#2}{#1}{#2\expandafter{#1}}%
}

% natural order stack access macros

\def\p@twwassignment#1#2{%
    \edef\sts{\noexpand\p@@wwassignment{\expandafter\xdecrement\expandafter{\number#1}}}%
    \expandafter\def\expandafter\sts\expandafter{\sts{#2}}%
    \yyvsa\empty
}

\def\p@@wwassignment#1#2#3{%
  \ifnum#1=\z@ %we have got to the element we need
      \yybreak{\yystringempty{#2}{#3}{#2{#3}}\let\sts\eatone}%
  \else
      \yybreak{\edef\sts{\noexpand\p@@wwassignment{\xdecrement{#1}}}%
               \expandafter\def\expandafter\sts\expandafter{\sts{#2}}}%
  \yycontinue
}

\def\yy#1{%
  \ifx#1[%
      \yybreak{\yz}%
  \else
      \ifx#1]%
          \yybreak@{\yx}%
      \else
          \ifx#1(%
              \yybreak@@{\ym}%
          \else
              \yybreak@@{\yn#1}%
          \fi
      \fi
  \yycontinue
}

% a macro to access the value stack in direct order, i.e.\ from right to left
% no \yylen is necessary

\def\bb#1#{%
  \ifnum#1<\@ne
      \yybreak{\putyyval}%
  \else
      \yybreak{\p@twwassignment{#1}}%
  \yycontinue
}

% symbolic name macros that prepare the environment for the use of the stack access macros above

\def\setsymcs#1#2{%
    \toksa{}\numberstochars#1\end
    \toksb\expandafter{\csname$[\the\toksa]\endcsname}% $
    \toksc\expandafter{\csname$'#2\endcsname}% $
    \edef\next{\let\the\toksb\the\toksc}\next
}

\def\setsymtr#1#2{%
    \toksa{}\numberstochars#1\end
    \toksb\expandafter{\csname$$[\the\toksa]\endcsname}%
    \toksc\expandafter{\csname$$'#2\endcsname}%
    \edef\next{\let\the\toksb\the\toksc}\next
}

\def\setlhs#1{%
    \toksa{}\numberstochars#1\end
    \toksb\expandafter{\csname$[\the\toksa]\endcsname}% $
    \edef\next{\let\the\toksb\yyval}\next
}

\def\setsym#1#2{%
    \setsymcs{#1}{#2}%
    \setsymtr{#1}{#2}%
}

% message output

\def\ferrmessage#1{{\newlinechar`\^^J\immediate\write16{\parsernamespace::#1^^J}}}

