% 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