% Copyright 2012-2024, 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 .
% 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, say \name, were made \let\name. the macros would break;
% this can be fixed by using a more sophisticated comparison but was decided against
% in the interests 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
%
% (1) define a macro prototype, this also defines a few other macros to be used in
% special circumstances, such as for error checking (strict), and to use where
% expansion must be suppressed (such as diagnostic output)
\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%
}
% (2) define the macro (#1) with an automatic prototype (if the parameter list is empty) or
% with prototype checking; the prototype should have been defined earlier with \.{\\defp}
\def\defc#1#2#{%
\restorecs\parserprototypesnamespace#1%
\toksa{#2}%
\edef\next{\the\toksa}%
\ifx\next\empty
\yybreak{\expandafter\def\expandafter#1#1}%
\else
\ifx\next#1%
\yybreak@{\expandafter\def\expandafter#1#1}%
\else
\yybreak@{%
\toksb\expandafter{#1}%
{%
\newlinechar=`^^J%
\edef\next{%
\errhelp{the prototype of \string#1 is from <\parserprototypesnamespace>^^J%
you might want to look for a \expandafter\string\expandafter\defp\string#1... line somewhere}%
}\next
\errmessage{macro definition of \string#1 does not match its prototype:^^J
\the\toksa\space (should be \the\toksb)}%
}%
}%
\fi
\yycontinue
}
% (3) once a set of macros have been defined, all current definitions are added to the
% \.{\\yyunion} list in a namespace of your choosing by the \.{\\toyyunion} command
\def\t@yyunion#1#2{\def\currentyyunionnamespace{#2}\savecslist{#2}#1}
\def\toyyunion#1{\expandafter\t@yyunion\yyuniontag{#1}}
% this command sequence provides a standard set of parameters for the scheme above
% to work; note that these settings will stay unchanged till the next command
\def\yyuniondeclare#1#2{% #1 is the command sequence that holds the union
% #2 is the root of the namespace
\def#1{\currentyyunionnamespace}% subset of the global union that deals with footnotes
\def\yyuniontag{#1}%
\def\parserstrictnamespace{#2:strict}%
\def\parserprototypesnamespace{#2:headers}%
\def\parserdebugnamespace{#2:debug}%
}
{\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\tokenpp#1{} % ignore \prodstyle{\%prec}-like declarations
\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
}
% packing \write lines to avoid unnecessary expansions; it is \outer
% because it would be pretty useless inside a macro since all the category
% codes have already been set
\outer\def\packliteral{%
\begingroup
\catcode`\\=\other
\catcode`\{=\other
\catcode`\}=\other
\catcode`\$=\other
\catcode`\&=\other
\catcode`\#=\other
\catcode`\%=\other
\catcode`\~=\other
\catcode`\^=\other
\catcode`\_=\other
\catcode`\|=\other
\catcode`\ =\other
\catcode`\^^M=\other
\p@ckliteral
}
{\catcode`\%=\other\gdef\p@ckliteral#1%{\toksa{#1}\expandafter\endgroup\expandafter\p@ckl@teral\expandafter{\the\toksa}}}
\def\p@ckl@teral#1#2{#2{#1}}
% example of use: \packliteral {\crazy\sequence }% \toksa % this will save ` \crazy...' as cat 12 code characters in \toksa
% a (relatively) safe way to turn a command sequence into its name (sans the escape character) made up of nonletters
\def\csstring{%
\ifnum\escapechar>-1
\yybreak{\cs@tring}%
\else
\yybreak{}%
\yycontinue
}
\def\cs@tring{%
\ifnum\escapechar>255
\yybreak{}%
\else
\yybreak{\expandafter\eatone\string}%
\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}% 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{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
%
\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 macros: currently, the level of optimization has to be consistent throughout the
% document, i.e. \optimize macros have to be called on the same arrays after loading.
% the reason is the yyfaststack.sty file that modifies the \newtable macro once for all the tables
\def\optimize#1{%
\setoptopt{#1}%
\tempca\z@
\bloop
\tempcb=\expandafter\ifcase\expandafter\tempca\the\csname#1\endcsname\else\@MM\fi\relax
\ifnum\tempcb<\@MM %
\expandafter\edef\csname #1\parsernamespace\the\tempca\endcsname{\the\tempcb}%
\advance\tempca\@ne
\repeat
}
\def\optimizetext#1{% optimizing text arrays
\setoptopt{#1}%
\tempca\z@
\@ptimizetext{#1}
}
\def\@ptimizetext#1{%
\edef\next{\expandafter\ifcase\expandafter\tempca\the\csname#1\endcsname\else\end\fi}%
\ifx\next\endcontainer
\let\next\eatone
\else
\expandafter\edef\csname #1\parsernamespace\the\tempca\endcsname{\next}%
\advance\tempca\@ne
\let\next\@ptimizetext
\fi
\next{#1}%
}
\def\setoptopt#1{%
\expandafter\let\csname optopt[#1]\parsernamespace\endcsname\end
}
% 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{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
\expandafter\yystringempty\expandafter{#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 \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{%
{%
\uccode`\^^A=#1\relax
\uppercase{\edef\next{#2{^^A}}}%
\expandafter
}\next
}
% 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 symbolic 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}%
\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
% the number below (15) is not chosen randomly but is designed to follow the conventions
% outlined in plain.tex:
%
% The following counters are reserved:
% ...
% 10 count allocation
% 11 dimen allocation
% 12 skip allocation
% 13 muskip allocation
% 14 box allocation
% 15 toks allocation
% ...
%
% Here it is given a symbolic name for convenience. Note that this allocation is
% needed even if only the yyfaststack.sty stack macros are used (it is used in the
% mechanism that makes \yy0{\the\yy1\the\yy2} assignments possible).
\countdef\toptoks=15 % register responsible for token allocations
% value and state stack access macros: these may be replaced by the macros in yyfaststack.sty
\def\yyreadvstack#1\upto#2{% assume that #2 > 0
\edef\sts{\noexpand\splitstack{\number#2}{\expandafter\xincrement\expandafter{\number\toptoks}}}#1\stackend#1%
}
\long\def\splitstack#1#2#3{%
\expandafter\def\csname$'#1\endcsname{#3}% $
\ifnum#2<\@cclvi % we have not reached the maximum allocated number of token registers
\expandafter\toksdef\csname$$'#1\endcsname=#2
\toks#2{#3}%
\fi
\ifnum#1=\@ne %we have read the values
\let\sts\scoopupstack
\else
\edef\sts{\noexpand\splitstack{\xdecrement{#1}}{\xincrement{#2}}}%
\fi
}
\def\yypeekvstack#1\upto#2{% assume #2 > 0
\edef\sts{\noexpand\peelstack{\number#2}{\expandafter\xincrement\expandafter{\number\toptoks}}}#1\relax%
}
\long\def\peelstack#1#2#3{%
\expandafter\def\csname$'#1\endcsname{#3}% $
\ifnum#2<\@cclvi % we have not reached the maximum allocated number of token registers
\expandafter\toksdef\csname$$'#1\endcsname=#2
\toks#2{#3}%
\fi
\ifnum#1=\@ne %we have read the values
\let\sts\eatone
\else
\edef\sts{\noexpand\peelstack{\xdecrement{#1}}{\xincrement{#2}}}%
\fi
}
% macros to read the stack in `natural order' (see also yyfaststack.sty)
\def\yypeekustack#1{% we do not compute anything unless the postprocessor
% detected an implicit rule
\ifnum\number\yycomputeilength{\number\yyn}>\z@
\yybreak{\edef\sts{\noexpand\peelstackreverse{1}{\expandafter
\xincrement\expandafter{\number\toptoks}}}#1\relax}%
\else
\yybreak{}%
\yycontinue
}
\long\def\peelstackreverse#1#2#3{%
\ifnum#2<\@cclvi % we have not reached the maximum allocated number of token registers
\expandafter\toksdef\csname$$$'#1\endcsname=#2
\toks#2{#3}%
\fi
\ifnum\number\yycomputeilength{\number\yyn}>#1 %
\edef\sts{\noexpand\peelstack{\xincrement{#1}}{\xincrement{#2}}}%
\else
\let\sts\eatone
\fi
}
\def\yyimplicitlengthset#1#2{\expandafter\def\csname ilength$$[#1]\endcsname{#2}}
\def\yycomputeilength#1{%
\expandafter\ifx\csname ilength$$[#1]\endcsname\relax
\yybreak{0 }%
\else
\yybreak{\csname ilength$$[#1]\endcsname\space}%
\yycontinue
}
% macros to support new printing routines
\def\yypeeksstack#1\upto#2\withprefix#3{% assume #2 > 0
\edef\sts{\noexpand\peelsstack{\number#2}}%
\expandafter\def\expandafter\sts\expandafter{\sts{#3}{}}#1\relax%
}
\long\def\peelsstack#1#2#3#4{%
\ifnum#1=\@ne %we have read the values
#3\let\sts\eatone
\else
\edef\sts{\noexpand\peelsstack{\xdecrement{#1}}}%
\expandafter\def\expandafter\sts\expandafter{\sts{#2}{#2{#4}#3}}%
\fi
}
% 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}}% define the stack iterator
\yyvsa\empty % execute the stack
}
\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 % keep descending into the stack
\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 the direct order, i.e.\ from right to left
% no \yylen is necessary
\def\bb#1#{%
\ifnum#1<\@ne
\yybreak{\yyvalx}%
\else
\yybreak{\p@twwassignment{#1}}%
\yycontinue
}
% this macro should only be inserted by the preprocessor, it accesses
% the stack in a `natural' order which is the opposite of how `native'
% bison does it
\def\yg#1#2#3{% #1 is the `native' bison index (e.g. for a: b c d rule,
% b is $1
% #2 is the `natural' index (so b would be $3 for the
% rule above
% #3 is the implicit `yyilen' (see yyparse.sty for more information)
\ifnum\yyilen=\z@ % this is probably an inline action, so yyreduce
% will only generate the `natural' indexed token
% registers
\yybreak{\csname $$$'#2\endcsname}%
\else
\yybreak{\ym#1)}% save one level of expansion ...
\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}}}
\newif\ifbootstrapmode