% 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 . % fast(er) versions of stack access functions \catcode`\@=11 \def\yyinitstack#1{% #1 is the name of the stack \csname \expandafter\eatone\string#1\endcsname\m@ne } % stacks will be defined as pairs ( \s t a c k n a m e [n u m b e r], \s t a c k n a m e ) % where \s t a c k n a m e [n u m b e r] is an associative array of control sequences % and \s t a c k n a m e is a \count register % % note that in the implementaion below the stack grows `the wrong % way'; this is done for convenience, since there is no `memory read % with increment' operation, the `usual' (say, hardware) stack % implementations take advantage of, and our stack can grow % unrestricted this way; also note that while the array is namespace specific, % the stack pointer is not, so special effort is required to preserve it \let\yyinitarray\yyinitstack % using the stack as an array only makes sense for the optimized version \def\getstackpointer#1{% expands to the value of the current top of the stack position \expandafter\the\csname \expandafter\eatone\string#1\endcsname } \def\gettopofstackcs#1{% expands to the control sequence (a member of the associative array) % that holds the value of the current element at the top of the stack \csname \expandafter\eatone\string#1[\getstackpointer#1]\parsernamespace \endcsname } \def\gettopofstackcsx#1{% a version of the above to be used with \romannumeral 0\expandafter\noexpand\csname \expandafter\eatone\string#1[\getstackpointer#1]\parsernamespace \endcsname } \def\gettopofstackcsxx#1{% to be used with \romannumeral, expands to the contents of the top stack element 0\expandafter\expandafter\expandafter\space\csname \expandafter\eatone\string#1[\getstackpointer#1]\parsernamespace \endcsname } \def\getmidstackcs#1#2{% expands to the control sequence (a member of the associative array) % that holds the value of the current element at the specified (#2) position \csname \expandafter\eatone\string#1[#2]\parsernamespace\endcsname } \def\getmidstackcsx#1#2{% a version of the above to be used with \romannumeral, safe to use with \edef 0\expandafter\noexpand\csname \expandafter\eatone\string#1[#2]\parsernamespace\endcsname } \def\movestackpointer#1\by#2{% this assumes that #1 is a control sequence \expandafter\advance\csname \expandafter\eatone\string#1\endcsname#2% } \def\yypopstack#1\by#2{% removes the top #2 elements from the top of the stack #1 \movestackpointer#1\by{-#2}\relax } % \def\yypop#1\into#2{% pops the stack #1, stores the top element in token register #2 #2\expandafter{\romannumeral\gettopofstackcsxx#1}% \movestackpointer#1\by\m@ne } % pushing stuff on a stack: \yypush{t o k e n s}\on\yyvs or \expandafter\yypush\number\yystate\on\yyss \long\def\yypush#1\on#2{% \movestackpointer#2\by\@ne \expandafter\expandafter\expandafter\def\gettopofstackcs#2{#1}% } \long\def\yypushx#1\on#2{% push with expand \movestackpointer#2\by\@ne \expandafter\expandafter\expandafter\edef\gettopofstackcs#2{#1}% } \long\def\yypushg#1\on#2{% global push with expand: do not use this for anything other than index macros \expandafter\global\romannumeral0\movestackpointer#2\by\@ne \expandafter\expandafter\expandafter\xdef\gettopofstackcs#2{#1}% } % push register contents on a stack: #1 is a register, #2 is a stack \def\yypushr#1\on#2{% \movestackpointer#2\by\@ne \expandafter\expandafter\expandafter\edef\gettopofstackcs#2{\the#1}% } % the first parameter is the stack, the second is the location from the top (a nonnegative number), the third is % the control sequence that will hold the value; \def\yyreadstack#1\at#2\to#3{% \expandafter\advance\csname \expandafter\eatone\string#1\endcsname-#2\relax % \expandafter\let\expandafter#3\csname \expandafter\eatone\string#1[\expandafter\the \csname \expandafter\eatone\string#1\endcsname]\parsernamespace\endcsname % \expandafter\advance\csname \expandafter\eatone\string#1\endcsname#2\relax } % same as above but reads the value into a register \def\yyreadstackr#1\at#2\to#3{% \expandafter\advance\csname \expandafter\eatone\string#1\endcsname-#2\relax % #3\csname \expandafter\eatone\string#1[\expandafter\the \csname \expandafter\eatone\string#1\endcsname]\parsernamespace\endcsname\relax % \expandafter\advance\csname \expandafter\eatone\string#1\endcsname#2\relax } % the macros below use general purpose registers and have a chance to interfere with % the user namespace; they have been replaced by the macros that only use expandable % arithmetic which leads to about 3 percent slowdown. thus the original macros were left % in the package in case such a slowdown is undesirable \def\yyreadvstack#1\upto#2{% assume that #2 > 0 \tempca=#2\relax \tempcb\toptoks \advance\tempcb\@ne \yyreadvst@ck{#1}% } \def\yyreadvst@ck#1{% \expandafter\toksdef\csname$$'\the\tempca\endcsname=\tempcb% \expandafter\yypop\expandafter#1\expandafter\into\csname$$'\the\tempca\endcsname%$ \expandafter\expandafter\expandafter\def \expandafter\expandafter\csname$'\the\tempca\endcsname\expandafter{\the\toks\tempcb}%$ \ifnum\tempca=\@ne %we have read the values \yybreak\relax \else \advance\tempcb\@ne \advance\tempca\m@ne \yybreak{\yyreadvst@ck{#1}}% \yycontinue } % the macros below replace the two macros above to only use expandable arithmetic \def\yyreadvstack#1\upto#2{% assume that #2 > 0 \expandafter\yyr@@dvst@ck\expandafter{\number#2}{#1}% } \def\yyr@@dvst@ck#1#2{% \expandafter\yyr@@@vst@@k\expandafter{\number\toptoks}{#1}{#2}% } \def\yyr@@@vst@@k#1#2#3{% \yyr@@dvst@@k{#2}{#1}{#3}% } \def\yyreadvst@ck#1#2#3{% \expandafter\toksdef\csname$$'#2\endcsname=#1\relax % \expandafter\yypop\expandafter#3\expandafter\into\csname$$'#2\endcsname%$ % the portion below is redundant if the \yn macro below is used and no symbolic switch % is implemented \expandafter\expandafter\expandafter\def \expandafter\expandafter\csname$'#2\endcsname\expandafter{\the\toks#1}%$ \ifnum#2=\@ne %we have read the values \yybreak\relax \else \yybreak{\expandafter\yyr@@dvst@@k\expandafter{\number\xdecrement{#2}}{#1}{#3}}% \yycontinue } \def\yyr@@dvst@@k#1#2#3{% \expandafter\yyreadvst@ck\expandafter{\number\xincrement{#2}}{#1}{#3}% } % macros to read the stack from top to bottom (i.e.~in `reverse' order) \def\yyreadustack#1{% we do not compute anything unless the postprocessor % detected an implicit rule \ifnum\number\yycomputeilength{\number\yyn}>\z@ \yybreak{\expandafter\yyr@@@ust@@k\expandafter{\number\toptoks}{1}{#1}}% \else \yybreak{}% \yycontinue } \def\yyr@@@ust@@k#1#2#3{% \yyr@@dust@@k{#2}{#1}{#3}% } \def\yyreadust@ck#1#2#3{% \expandafter\toksdef\csname$$$'#2\endcsname=#1\relax % \expandafter\yypop\expandafter#3\expandafter\into\csname$$$'#2\endcsname%$ \ifnum\number\yycomputeilength{\number\yyn}>#2 % \yybreak{\expandafter\yyr@@dust@@k\expandafter{\number\xincrement{#2}}{#1}{#3}}% \else \yybreak\relax \yycontinue } \def\yyr@@dust@@k#1#2#3{% \expandafter\yyreadust@ck\expandafter{\number\xincrement{#2}}{#1}{#3}% } % end of replacement macros \def\yypeekvstack#1\upto#2{% assume that #2 > 0 \yyreadvstack#1\upto{#2}\relax \movestackpointer#1\by#2\relax } \def\yypeekustack#1{% \yyreadustack#1% \movestackpointer#1\by\number\yycomputeilength{\number\yyn}\relax } % macros for reading the state stack (needed if using bison version 3.0 and above) \def\yyreadsstack#1\upto#2\withprefix#3{% assume that #2 > 0 \expandafter\yyr@@dsst@ck\expandafter{\number#2}{#1}{#3}% } \def\yyr@@dsst@ck#1#2#3{% \expandafter\yyr@@@sst@@k\expandafter{\number\toptoks}{#1}{#2}{#3}% } \def\yyr@@@sst@@k#1#2#3#4{% \yyr@@dsst@@k{#2}{#1}{#3}{#4}{}% } \def\yyr@@dsst@@k#1#2#3#4#5{% \expandafter\yyreadsst@ck\expandafter{\number\xincrement{#2}}{#1}{#3}{#4}{#5}% } \def\yyreadsst@ck#1#2#3#4#5{% \ifnum#2=\z@ %we have read the values \yybreak{#5}% \else \yybreak{\expandafter\yyr@@dsst@@@\expandafter{\number\gettopofstackcs#3}{#1}{#2}{#3}{#4}{#5}}% \yycontinue } \def\yyr@@dsst@@@#1#2#3#4#5#6{% \movestackpointer#4\by\m@ne \expandafter\yyr@@dsst@@k\expandafter{\number\xdecrement{#3}}{#2}{#4}{#5}{#5{#1}#6}% } \def\yypeeksstack#1\upto#2\withprefix#3{% assume that #2 > 0 \yyreadsstack#1\upto{#2}\withprefix{#3}\relax \movestackpointer#1\by#2\relax } % faster array access macros \def\fastgetelemof#1\at#2{% \csname #1\parsernamespace\number#2\endcsname } \def\fgetelemof#1\at#2{% this definition allows mixing optimized and unoptimized tables \expandafter\ifx\csname optopt[#1]\parsernamespace\endcsname\relax \getelemof{#1}\at{#2}% \else \csname #1\parsernamespace\number#2\endcsname \fi } % new stack access macros that read the stack directly (to reduce namespace pollution) % these are here more as an example \def\yn#1#{% \ifnum#1<\@ne \yybreak{\yyvalx}% \else \yybreak{\p@tyyassignment{#1}}% \yycontinue } \def\p@tyyassignment#1{% \expandafter\advance\csname yyvsa\endcsname-\yylen \expandafter\advance\csname yyvsa\endcsname#1\relax % \expandafter\expandafter\expandafter \p@@yyassignment \expandafter\expandafter\expandafter{% \csname yyvsa[\expandafter\the \csname yyvsa\endcsname]\parsernamespace\endcsname }{% \expandafter\advance\csname yyvsa\endcsname-#1\relax \expandafter\advance\csname yyvsa\endcsname\yylen }% } % new \bb macro implementation \def\p@twwassignment#1{% \expandafter\advance\csname yyvsa\endcsname-#1\relax \expandafter\advance\csname yyvsa\endcsname\@ne % \expandafter\expandafter\expandafter \p@@yyassignment \expandafter\expandafter\expandafter{% \csname yyvsa[\expandafter\the \csname yyvsa\endcsname]\parsernamespace\endcsname }{% \expandafter\advance\csname yyvsa\endcsname#1\relax \expandafter\advance\csname yyvsa\endcsname\m@ne }% } \def\p@@yyassignment#1#2#3{% #2\yystringempty{#3}{#1}{#3{#1}}% } % dysplaying stack contents (\yyparse specific) \def\showstack#1{% \begingroup \let\stackcs\empty \count\z@\csname \expandafter\eatone\string#1\endcsname \ifnum\count\z@<\z@ \else \bloop \count\@ne\csname \expandafter\eatone\string#1[\the\count\z@]\parsernamespace\endcsname \count\tw@=\fgetelemof{yystos}\at{\count\@ne}% \edef\stackcs{\stackcs^^J \space\space\fgetelemof{yytname}\at{\count\tw@}}% \ifnum\count\z@>\z@ \advance\count\z@\m@ne \repeat \fi \tokreturn{}{}{\def\noexpand\stackcs{\stackcs}}% } % saving token registers \def\newtable@generic#1{% \expandafter\ifx\csname #1\endcsname\relax \toksa{\csname newtoks\endcsname}% \expandafter\the\expandafter\toksa\csname #1\endcsname \fi \csname #1\endcsname=% } \let\newtable\newtable@generic % TODO: right now this is done either for all tables or none of them % macros to support `hardwired' optimized tables \def\appendtoyy@generic#1{% \toksa{\or}% \expandafter\ifx\csname optopt[#1]\parsernamespace\endcsname\relax \expandafter\concat\csname#1\endcsname\toksb \expandafter\concat\csname#1\endcsname\toksa \else \expandafter\edef\csname #1\parsernamespace\the\tempca\endcsname{\the\toksb}% \fi } \def\appendtoyy@genericlast#1{% \expandafter\ifx\csname optopt[#1]\parsernamespace\endcsname\relax \expandafter\concat\csname#1\endcsname\toksb \else \expandafter\edef\csname #1\parsernamespace\the\tempca\endcsname{\the\toksb}% \fi } \def\beginoptimizednonnumeric#1{% \tempca\z@ \def\appendtoyytname{\appendtoyy@generic{#1}}% \def\appendtoyytnamelast{\appendtoyy@genericlast{#1}}% }