% 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 . % basic data manipulation and testing routines; these are not % specific to any parsing/lexing task and may be used independently; % register definitions from the `\TeX\ runtime' (trt1.sty) are needed % by the list and switch macros \catcode`\@=11 % a nestable loop, needed by the macros in xarithm.sty, included % immediately after the definition \def\bloop#1\repeat{#1\bl@op{#1}\repeat\fi} \def\bl@op#1\repeat\fi{\fi#1\bl@op{#1}\repeat\fi} \input xarithm.sty % (unoptimized) stacks will be defined as `list' macros, consisting of \sts{...}\sts{...}... type lists % in \yypopstack, the second parameter must be a positive number % % note: perhaps, replacing \sts with the name of the stack would allow for more economical % use of the user namespace, however, this will somewhat complicate the macros below, as well % as make it impossible to assign a different control sequence to the % stack (which may be considered a feature by itself) % note: a somewhat clumsy way in which the code below is written is due to the goal of making it % independent of general use registers (\tempc?); the result is extremely slow code \def\yyinitstack#1{% to provide consistency with the accelerated macros \let#1\empty } \long\def\scoopupstack#1#2\stackend#3{\def#3{\sts{#1}#2}} \def\stackend#1{\def#1{}} % if we got here, the stack is empty % the following macro is a mild example of expansion tricks \def\yypopstack#1\by#2{% \ifnum#2>\z@ \yyp@pst@ck{#1}{#2}% \fi } \def\yyp@pstack#1{% \expandafter\space#1% } % the definition below is here purely for clarity \catcode`\.=\active \let.\expandafter \def\yyp@pst@ck#1#2{% \let\sts\or \iffalse{\fi...\def...#1...{...\sts.\ifcase\number\number.\xincrement.{\number#2} \yyp@pstack#1}\else}\fi } \catcode`\.=12 % other character % #1 is the name of the stack, #2 is a token register \def\yypop#1\into#2{\def\sts{\consumeone{#2}}#1\stackend#1} \long\def\consumeone#1#2{% #1{#2}\let\sts\scoopupstack } % 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{\expandafter\def\expandafter#2\expandafter{\romannumeral\yyp@sh{#2}{#1}}} \long\def\yyp@sh#1#2{\expandafter\yyp@@h\expandafter{#1}{#2}} \long\def\yyp@@h#1#2{0 \sts{#2}#1} % push register contents on a stack: #1 is a register, #2 is a stack (a control % sequence that expands to a `\sts{v a l u e}\sts...' list) \def\yypushr#1\on#2{\expandafter\yypush\expandafter{\the#1}\on#2} % 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{\edef\sts{\noexpand\skipandcount{\number#2}{\noexpand#3}}#1\stackfinish#1} \def\skipandcount#1#2#3{% \ifnum#1=\z@ %we have got to the element we need \def#2{#3}% \yybreak\ignorestack \else \yybreak{\edef\sts{\noexpand\skipandcount{\xdecrement{#1}}{\noexpand#2}}}% \yycontinue } % same as above except read the value into a register \def\yyreadstackr#1\at#2\to#3{\edef\sts{\noexpand\skipandcountr{\number#2}{#3}}#1\stackfinish#1} \def\skipandcountr#1#2#3{% \ifnum#1=\z@ %we have got to the element we need #2#3% \yybreak\ignorestack \else \yybreak{\edef\sts{\noexpand\skipandcountr{\xdecrement{#1}}{\noexpand#2}}}% \yycontinue } \long\def\ignorestack#1\stackfinish#2{} \def\stackfinish#1{\def#1{0\message{:stack empty:}}} % (unoptimized) arrays of integers are represented by a string of tokens `element0 \or element1 \or ...' % #2 is a register (otherwise the case and the integer from the array `coalesce'); % the following macro was designed to make something like % \tempca=\getelemof\yytable\at\yyn\relax possible so it has to expand to a number; % incidentally, some care should be taken using the above assignment to make sure that % it is not followed by an expandable token (such as \if) as in this case the token might be % expanded prematurely while the assignment is looking for the first non-expandable token which % is not part of the number; this is the reason for the \relax \def\getelemof#1\at#2{% #1 is the name of the token register containing the array, #2 is the index \expandafter\get@l@mof\expandafter{\csname#1\endcsname}{#2}% } \def\get@l@mof#1#2{% \expandafter\get@lemof\expandafter{\the#1}{#2}% } \def\get@lemof#1#2{% \ifcase#2 #1\else\fi } \let\fgetelemof\getelemof % token register access \def\concat#1#2{% store the concatenation result in the first sequence #1\expandafter\expandafter\expandafter{\expandafter\the\expandafter#1\the#2}% } \def\concatl#1#2{% store the concatenation result in the second sequence \expandafter\conc@tl\expandafter{\the#2}{#1}{#2}% } \def\conc@tl#1#2#3{% #3\expandafter{\the#2#1}% } \def\appendr#1#2{% \begingroup \edef\next{#1{\the#1#2}}\next \tokreturn{}{}{#1{\the#1}}% } \def\appendl#1#2{% \begingroup \edef\next{#1{#2\the#1}}\next \tokreturn{}{}{#1{\the#1}}% } % appending to token registers without expansion \long\def\appendlnx#1#2{% \expandafter\app@ndlnx\expandafter{\the#1}{#2}{#1}% } \long\def\app@ndlnx#1#2#3{% #3{#2#1}% } % one can use #1\expandafter{\the#1#2} instead of \appendrnx below; % this form (as well as the \appendlnx above) has the advantage of % being useable with \romannumeral0 in case one merely wants to record % the concatenation for future use \long\def\appendrnx#1#2{% \expandafter\app@ndrnx\expandafter{\the#1}{#2}{#1}% } \long\def\app@ndrnx#1#2#3{% #3{#1#2}% } % a macro to append new material to an existing control sequence \def\appendxrt#1#2#3#4{% #1 one of \def, \edef (why?), \gdef, \xdef (why?) % #2 sequence name being appended to % #3 the material appended to the right (expanded once) % #4 the material appended to the right of #3 (not expanded) \expandafter\app@ndxrt\expandafter{\csname #2\endcsname}{#1}{#3}{#4}% } \def\app@ndxrt#1#2#3#4{% #1 is the sequence being appended to % #2 is \?def % #3 is expanded once (appended to the right of #1) % #4 is appended to the right of #3 (not expanded) \expandafter\ap@@ndxrt\expandafter{#3}{#4}{#2}{#1}% } \def\ap@@ndxrt#1#2#3#4{% #1 is expanded once (appended to the right of #4) % #2 is appended to the right of #1 (not expanded) % #3 is \?def % #4 is the sequence being appended to \expandafter#3\expandafter#4\expandafter{#4#1#2}% } % the following macros are an expandable way to determine if a token register is empty; % while a number of different conditionals can be used, including plain \iffalse, % this choice seems to result in a shortest macro and the fewest number of \expandafter's; % an idea from % http://tex.stackexchange.com/questions/2936/test-whether-token-list-is-empty % where it is attributed to Ulrich Diez can be generalized to apply multiple tests inside braces % in a row; the macros from that discussion are quoted below; note, however, that these macros % lead to unbalanced braces inside alignments (see The \TeX book, Appendix~D, p.~385 for the % discussion of the `master counter' and the `balance counter' and their behavior when % \TeX\ evaluates the constants `{ and `}); in addition, the first `1' is superfluous; %\newcommand\@ifempty@toks[1]{% % \ifcase\iffalse{{{\fi\expandafter\@ifempty@@toks\the#1}1}1}0 % \expandafter\@firstoftwo % \else % \expandafter\@secondoftwo % \fi} %\newcommand{\@ifempty@@toks} % {\expandafter\@gobble\expandafter{\expandafter{% % \ifcase`}\expandafter}\expandafter\fi\string} % as a note of explanation, the reason this works relies on the fact % that \string will turn a `{', a `}', or any other token into a % non-brace while the parameter scanning mechanism of \TeX\ will try % to collect the smallest possible balanced input; the `excessive' % braces will disappear in the expansion of the `\if...' construct; % the reason \if or other macros that expand their arguments are so % well suited for this `chain expansion' mechanism is in the fact % that the expansions for \string and \if... are launched from the % same point. \long\def\yytoksempty#1{% \iffalse{{\fi \if{\expandafter\yytoks@mpty\the#1}}}% \yybreak\yyfirstoftwo \else \yybreak\yysecondoftwo \yycontinue } % when the token list is empty, \TeX\ will try to expand \yybreak premaurely; % in this case \yybreak forces a \fi to be expanded while skipping the rest; % note that a simple \expandafter would not work in this case as \TeX would % insert a \relax when trying to expand a premature \else (this can be only % gleaned from `\TeX\ the program') \long\def\yystringempty#1{% \iffalse{{\fi \if{\yytoks@mpty#1}}}% \yybreak\yyfirstoftwo \else \yybreak\yysecondoftwo \yycontinue } \catcode`\>=2 \def\yytoks@mpty{% \expandafter\eatone\expandafter{\expandafter{% \if}\expandafter>\expandafter\fi\string } \catcode`\>=12 \long\def\yystartsinspace#1{% is the first token a \charcode 32, \catcode 10 token? \iffalse{\fi\yystartsinspac@#1 }% } \long\def\yystartsinspac@#1 {% \yystringempty{#1}% {\expandafter\yysecondofthree\expandafter{\string}}% {\expandafter\yythirdofthree\expandafter{\string}}% } % the macro below can be simplified by reducing the number of braces % but then \yytoks@mpty could not be reused \long\def\yystartsinbrace#1{% \iffalse{\fi \if{\yytoks@mpty#1}}% \yybreak\yysecondoftwo \else \yybreak\yyfirstoftwo \yycontinue } % the macros below are based on David Kastrup's magnificent string comparison % macros: % \def\strequal#1{\number\strequalstart{}{}#1\relax} % \def\strequalstart#1#2#3{\if#3\relax\strequalstop\fi % \strequalstart{\if#3#1}{#2\fi}} % \def\strequalstop\fi\strequalstart#1#2#3{\fi#1#3\relax'#213 } % % use: \if\strequal{string}{string}... % % they were adjusted to handle spaces inside the strings and to conform to a different % syntax, namely \yyifsamestring{string1}{string2}{true}{false} % the original macros use the fact that, say \if1\fi will expand to nothing and % that \number'13 expands to 11 whereas \number13 expands to 13; the elegance of % the second test was lost due to a different syntax; \edef\yyifsamestring#1{\noexpand\yyifsamestr@ng{}{}#1 \noexpand\yyifsam@str@ng\space} \def\yyifsamestr@ng#1#2#3 {\ifx\yyifsam@str@ng#3\yyifsam@str@ng\fi \yyifs@m@str@ng{#1}{#2}#3\space} \def\yyifs@m@str@ng#1#2#3{% \if#3\space \expandafter\yyifsamestr@ng \else \expandafter\yyifs@m@str@ng \fi {\if#3#1}{#2\fi}% } \def\yyifsam@str@ng\fi\yyifs@m@str@ng#1#2\yyifsam@str@ng\space#3{\fi \if\noexpand\yyifsam@str@ng#1#3 \noexpand\yyifsam@str@ng\yystrcleanup#2\fi \yysecondoftwo } \def\yystrcleanup#1\yysecondoftwo{#1\yyfirstoftwo} % prefix comparison macros % use: \romannumeral-0\yyprefixmatch{string1}{string2} % this will expand into {common prefix}{rest of string1}{rest of string2} \def\yyprefixmatch#1#2{% \yyprefixmatchbegin{#1\end}{#2\relax}{}% } \def\yyprefixmatchbegin#1#2{% \yypr@fixmatch#1{#2}% } \def\yypr@fixmatch#1#2#{% \yypr@fixm@tch{#1}{#2}% } \def\yypr@fixm@tch#1#2#3{% #2 is the rest of string1, #1 is the first char of string1 \yyprefixrematch#3{#1}{#2}% } \def\yyprefixrematch#1#2#{% \yypr@fixrematch{#1}{#2}% } \def\yypr@fixrematch#1#2#3#4#5{% \ifx#1#3% \yybreak{\yyprefixmatchbegin{#4}{#2}{#5#1}}% \else \yybreak{\yyprefixmatchend{#3#4}{#1#2}{#5}}% \yycontinue } \def\yyprefixmatchend#1#2#3{% \yypr@fixmatchend#1#2{#3}% } \def\yypr@fixmatchend#1\end#2\relax#3{% {#3}{#1}{#2}% } % macros to check if the string matches #1* for some char #1 % use: \yyifrepeatedchar{char}{string}{true case}{false case} \def\yyifrepeatedchar#1#2{% \yyifr@peatedchar#1#2\relax } \def\yyifr@peatedchar#1#2{% \ifx#2\relax \yybreak{\yyfirstoftwo}% string complete, match \else \yybreak{\yyifr@p@atedchar#1#2}% \yycontinue } \def\yyifr@p@atedchar#1#2{% \ifx#1#2% \yybreak{\yyifr@peatedchar#1}% next character \else \yybreak{\yyifrepeatedcharmismatch}% \yycontinue } \def\yyifrepeatedcharmismatch#1\relax{% \yysecondoftwo } % end prefix comparison macros % a test to determine whether the argument is a given control sequence \long\def\yyisthiscs#1#2{% \yystringempty{#1}{\yysecondoftwo}{% \yystartsinspace{#1}{\yysecondoftwo}{% \yystartsinbrace{#1}{\yysecondoftwo}{% \expandafter\yystringempty\expandafter{\eatone#1}{% \expandafter\yyisth@scs\expandafter{\string#1}{#2}% }{\yysecondoftwo}% } } }% } \long\def\yyisth@scs#1#2{% \expandafter\yyifsamestring\expandafter{\string#2}{#1}% } % same as above but the argument is a token register \def\yyisthiscsr#1{% \expandafter\yyisthiscs\expandafter{\the#1}% } % a `self-propagating \expandafter'; allows building lists like \yysx a\yysx b ... % so that a \romannumeral-1 at the beginning of the list would cary the expansion % to the last token but leave the list intact; note that #1 should be a single token \def\yysx#1#2{% \expandafter\space\expandafter\yysx\expandafter#1\romannumeral-1#2% } % linked list macros \newif\iftracinglists \def\initlist#1{% #1 is the list name \iftracinglists \message{init list<#1>}% \fi \expandafter\def\csname list.counter(#1)\endcsname{0}% init the counter \resetlistpointer{#1}% } \def\resetlistpointer#1{% \iftracinglists \message{reset list pointer<#1>}% \fi \expandafter\def\csname list.pointer(#1)\endcsname{0}% init the pointer } % the macro below may fail on some potential elements (the ones that contain #'s); % for extra robustness one may use \appendtolistx after storing the list element in % a token register. % if the list implementation changes, \splitlist@t must change too \def\appendtolistg#1#2#3{% #1 is the list name % #2 is the list element % #3 is the action on the contents % store the contents in the inner element \expandafter#3\csname list.term.1(#1)[\csname list.counter(#1)\endcsname]\endcsname{ #2}% \iftracinglists {\edef\lname{#1}\toksa\expandafter\expandafter\expandafter {\csname list.term.1(#1)[\csname list.counter(#1)\endcsname]\endcsname}% \message{adding to list<#1> at \showlistcounter{\lname}::\the\toksa.}}% \fi {% \edef\listname{#1}% \tempca\csname list.counter(\listname)\endcsname\relax % outer element name \toksa\expandafter{\csname list.term.0(\listname)[\the\tempca]\endcsname}% % inner element name \toksb\expandafter{\csname list.term.1(\listname)[\the\tempca]\endcsname}% \advance\tempca by\@ne % next outer element name \toksc\expandafter{\csname list.term.0(\listname)[\the\tempca]\endcsname}% \edef\next{% % store the new counter \def\expandafter\noexpand\csname list.counter(\listname)\endcsname{\the\tempca}% % wrap the inner element \def\the\toksa{\noexpand\expandafter\the\toksb\noexpand\romannumeral0\the\toksc}% }\expandafter }\next % \next is not affected by this } \def\appendtolist#1#2{\appendtolistg{#1}{#2}{\def}} \def\appendtolistx#1#2{\appendtolistg{#1}{#2}{\edef}} \def\appendtolisti#1#2{\appendtolistg{#1}{#2}{\fdef}} % note that lists with \listiterator entries can be executed and spliced % but some functions (like \replace...) below do not work properly \def\fdef#1#2{% \def#1{\listiterator{#1}{#2}}% so that #1 knows its name ... } \def\listiteratorsimple#1#2{% #2% } \let\listiterator\listiteratorsimple % expand the list without preprocessing % the name of the next macro is misleading: the whole % concatenated list starts at the first term of list #1 % but the only way to append to the resulting list is to append to % list #2; any attempt to append a term to list #1 will % disconnect the lists (although they can be concatenated again) \def\concatlists#1#2{% \expandafter\expandafter\expandafter \let\expandafter\expandafter \csname list.term.0(#1)[\csname list.counter(#1)\endcsname]\endcsname \csname list.term.0(#2)[0]\endcsname } \def\listisempty#1{% \ifnum\csname list.counter(#1)\endcsname=\z@ \yybreak\yyfirstoftwo \else \yybreak\yysecondoftwo \yycontinue } % execute a slice of a list (commonly amended by an iterator) \def\evallistbetween#1#2#3{% #1 is the list name % #2 is the start marker % #3 is the finish marker \ifnum#3<#2\relax \yybreak{}% \else \yybreak{% \expandafter\expandafter\expandafter\@vallistbetween\csname list.term.0(#1)[#3]\endcsname{#1}{#2}{#3}% }% \yycontinue } \def\@vallistbetween#1#2#3#4#5#6#7#8{% #1 \expandafter % #2 the contents of the element at #6 % #3 \romannumeral % #4 0 % #5 the next element in the remaining list % #6 the list name % #7 the start marker % #8 the finish marker \expandafter\edef\csname list.term.0(#6)[#8]\endcsname{% \noexpand#1\noexpand#2\noexpand#3#4\noexpand\space }% terminate the list temporarily \executelistat{#6}{#7}% execute the list slice \expandafter\edef\csname list.term.0(#6)[#8]\endcsname{% \noexpand#1\noexpand#2\noexpand#3#4\noexpand#5% }% restore the list } % the macro below cannot be used with iterator amended lists (unless the iterator % is purely expandable) \def\readlistbetween#1#2#3\to#4{% #1 is the list name % #2 is the start marker % #3 is the finish marker % #4 is name of the token register \ifnum#3<#2\relax %\errmessage{trying to read a negative slice (#2->#3) in list #1}% #4{}% \else \expandafter\expandafter\expandafter\r@adlistbetween\csname list.term.0(#1)[#3]\endcsname{#1}{#2}{#3}{#4}% \fi } \def\r@adlistbetween#1#2#3#4#5#6#7#8#9{% #1 \expandafter % #2 the contents of the element at #6 % #3 \romannumeral % #4 0 % #5 the next element in the remaining list % #6 the list name % #7 the start marker % #8 the finish marker % #9 the token register \expandafter\edef\csname list.term.0(#6)[#8]\endcsname{% \noexpand#1\noexpand#2\noexpand#3#4\noexpand\space }% terminate the list temporarily #9\expandafter{\romannumeral0\executelistat{#6}{#7}}% store the list slice \expandafter\edef\csname list.term.0(#6)[#8]\endcsname{% \noexpand#1\noexpand#2\noexpand#3#4\noexpand#5% }% restore the list } \def\consumelistupto#1#2\to#3{% \readlistbetween{#1}{\showlistpointer{#1}}{#2}\to{#3}% {% \iftracinglists \message{splice<#1> (\csname list.pointer(#1)\endcsname,#2)}% \fi \tempca=#2\relax \advance\tempca\@ne \ifnum\tempca>\showlistpointer{#1}\relax \edef\next{\def\expandafter\noexpand\csname list.pointer(#1)\endcsname{\the\tempca}}% \else \let\next\empty \fi \expandafter }\next } \def\consumefulllist#1\to#2{% #2\expandafter{\romannumeral0\executelistat{#1}{\showlistpointer{#1}}}% } % the macro below is not aware of the list iterators so it should be used carefully with amended lists % (one possible way is to redefine the list iterator before applying this macro). \def\changelistelem#1#2#3#4{% #1 list name % #2 marker % #3 prefix % #4 suffix \expandafter\ch@ngelistelem\csname list.term.1(#1)[#2]\endcsname{#3}{#4}% } \def\ch@ngelistelem#1#2#3{ \expandafter\ch@ng@listelem\expandafter{#1}#1{#2}{#3}% } \def\ch@ng@listelem#1#2#3#4{% remove the space added by the list packaging macros \expandafter\ch@ng@l@stelem\expandafter{\romannumeral0#1}{#2}{#3}{#4}% } \def\ch@ng@l@stelem#1#2#3#4{% assemble everything \def#2{ #3#1#4}% } \def\replacelistelemg#1#2#3#4{% #1 list name % #2 marker % #3 new contents % #4 action (\def, \edef, etc.) \expandafter\expandafter\expandafter\r@placelistelem\csname list.term.0(#1)[#2]\endcsname{#1}{#2}% \expandafter#4\csname list.term.1(#1)[#2]\endcsname{#3}% } \def\r@placelistelem#1#2#3#4#5#6#7{% #1 \expandafter % #2 the contents of the element at #7 % #3 \romannumeral % #4 0 % #5 the next element in the list % #6 the list name % #7 the marker \expandafter\edef\csname list.term.0(#6)[#7]\endcsname{\noexpand\expandafter \expandafter\noexpand\csname list.term.1(#6)[#7]\endcsname \noexpand\romannumeral0\noexpand#5}% } \def\replacelistelem#1#2#3{% \replacelistelemg{#1}{#2}{#3}{\def}% } \def\replacelistelemx#1#2#3{% \replacelistelemg{#1}{#2}{#3}{\edef}% } % the next macro assumes that the list counter is pointing to the last (currently empty) % list element \def\finishlist#1{% #1 is the list name \expandafter\def\csname list.term.0(#1)[\showlistcounter{#1}]\endcsname{ }% } \def\executelistat#1#2{% #1 is the list name % #2 is the element at which to start execution \csname list.term.0(#1)[#2]\endcsname } \def\executelist#1{% #1 is the list name \romannumeral0\executelistat{#1}{0}% } \def\storelist#1\to#2{% #1 is the list name % #2 is the token register to store it in #2\expandafter{\romannumeral0\csname list.term.0(#1)[0]\endcsname}% } \def\storelistx#1\to#2#3{% #1 is the list name % #2 is the token register to store it in % #3 is the suffix #2\expandafter{\romannumeral0\csname list.term.0(#1)[0]\endcsname#3}% } \def\showlistcounter#1{% \number\csname list.counter(#1)\endcsname } \def\showlistpointer#1{% \number\csname list.pointer(#1)\endcsname } \def\showlistcs#1{% {\toksa\expandafter{\csname list.term.0(#1)[\csname list.counter(#1)\endcsname]\endcsname}% \toksb\expandafter\expandafter\expandafter{\the\toksa}% \message{current cs: \the\toksa is \the\toksb}}% } % use example for the macros above: %\initlist{table} %\toksa{#} %\appendtolistx{table}{\the\toksa,} %\appendtolist{table}{a,} %\appendtolist{table}{b,} %\appendtolist{table}{{c},} %\appendtolist{table}{d,} %\appendtolist{table}{e,} %\appendtolist{table}{{f}} %\appendtolist{table}{\space.} %\appendtolistx{table}{\space\space\end} %\finishlist{table} %\storelist{table}\to\toksa %\errmessage{full list: \the\toksa} % use example for the macros above: %\initlist{table} %\toksa{#} %\def\listiteratorxmpl#1#2{% % #2{\format}% %} %\let\listiterator\listiteratorxmpl %\appendtolisti{table}{..} %\appendtolisti{table}{a,} %\appendtolisti{table}{b,} %\appendtolisti{table}{{c},} %\appendtolisti{table}{d,} %\appendtolisti{table}{e,} %\appendtolisti{table}{{f}} %\appendtolisti{table}{.} %\appendtolisti{table}{\end} %\finishlist{table} %\storelist{table}\to\toksa %\errmessage{full list: \the\toksa} % `data structure access' macros: picking the n-th undelimited parameter % in a parameter list inside a token register % it is assumed that none of the arguments is \end, and that there are enough % parameters to pick the desired one \def\getfirst#1\to#2{% #2\expandafter\expandafter\expandafter{\expandafter\g@tfirst\the#1\end}% } \def\g@tfirst#1#2\end{#1} \def\getsecond#1\to#2{% #2\expandafter\expandafter\expandafter{\expandafter\g@tsecond\the#1\end}% } \def\g@tsecond#1#2#3\end{#2} \def\getthird#1\to#2{% #2\expandafter\expandafter\expandafter{\expandafter\g@tthird\the#1\end}% } \def\g@tthird#1#2#3#4\end{#3} \def\getfourth#1\to#2{% #2\expandafter\expandafter\expandafter{\expandafter\g@tfourth\the#1\end}% } \def\g@tfourth#1#2#3#4#5\end{#4} \def\getfifth#1\to#2{% #2\expandafter\expandafter\expandafter{\expandafter\g@tfifth\the#1\end}% } \def\g@tfifth#1#2#3#4#5#6\end{#5} \def\getsixth#1\to#2{% #2\expandafter\expandafter\expandafter{\expandafter\g@tsixth\the#1\end}% } \def\g@tsixth#1#2#3#4#5#6#7\end{#6} \def\getseventh#1\to#2{% #2\expandafter\expandafter\expandafter{\expandafter\g@tseventh\the#1\end}% } \def\g@tseventh#1#2#3#4#5#6#7#8\end{#7} \def\geteightth#1\to#2{% #2\expandafter\expandafter\expandafter{\expandafter\g@teightth\the#1\end}% } \def\g@teightth#1#2#3#4#5#6#7#8#9\end{#8} \def\getninth#1\to#2{% the `.' is necessary since \TeX's scanning mechanism will % strip any potential braces surrounding the last parameter % (assuming there are exactly nine) twice: % o first, expanding \g@tninth, % o second, expanding \g@tfirst #2\expandafter\expandafter\expandafter{\expandafter\g@tninth\the#1.\end}% #2\expandafter\expandafter\expandafter{\the#2}% } \def\g@tninth#1#2#3#4#5#6#7#8#9\end{\g@tfirst#9\end} \def\gettenth#1\to#2{% no need for `.' (or any other placeholder) here, % since the #9-th parameter to \g@ttenth is a list of % at least two parameters itself, thus any existing braces % have survived intact #2\expandafter\expandafter\expandafter{\expandafter\g@ttenth\the#1\end}% #2\expandafter\expandafter\expandafter{\the#2}% } \def\g@ttenth#1#2#3#4#5#6#7#8#9\end{\g@tsecond#9\end} % removing the first element of a token register if it has more than one; \def\sansfirst#1{% \expandafter\s@nsfirst\expandafter{\the#1}{#1}% } \def\s@nsfirst#1#2{% \expandafter\s@nsf@rst\expandafter{\eatone#1}{#2}% } \def\s@nsf@rst#1#2{% \yystringempty{#1}{}{% #2{#1}% }% } % a version of the macro above that expands to the original argument with the first element removed \def\sansfirstx#1{% \expandafter\yystringempty\expandafter{\eatone#1}{#1}{\eatone#1}% } % string replacement: all arguments are registers, nothing is expanded, no \next is defined % note that this is not a greedy replacement: this could be arranged with a more sophisticated macro % also note that the string being replaced cannot have any braces in it \newif\ifyytracereplacements \newif\ifyyreplaced \yytracereplacementstrue \def\yyreplacestring#1\in#2\with#3{% \expandafter\def\expandafter\r@placestring\expandafter##\expandafter1\the#1##2\end{% \def\r@placestring{##2}% is this the string at the very end? \ifx\r@placestring\empty % then it is the one we inserted, % report \yyreplacedfalse \ifyytracereplacements \errmessage{string <\the#1> not present in \the#2}% do not change the register if the string is not there \fi \else % remove the extra copy of #1\end at the end \yyreplacedtrue \expandafter#2\expandafter\expandafter\expandafter {\expandafter\r@plac@string\expandafter{\the#3}{##1}##2\end}% \fi}% end of \r@placestring definition \expandafter\def\expandafter\r@plac@string \expandafter##\expandafter1% \expandafter##\expandafter2% \expandafter##\expandafter3% \the#1\end{##2##1##3}% \expandafter\expandafter\expandafter\r@placestring\expandafter\the\expandafter#2\the#1\end } % returning token register values from a group % in such a way that no other register values are affected \def\tokreturn#1#2#3{% #1 is the code to be prepended (will be expanded) % #2 is a list of token registers % #3 is the code to be appended \t@kreturn{#1}{#3}#2\end } \def\t@kreturn#1#2#3{% first step: see if the list is non-empty and pick the first token register \ifx#3\end % there are no registers to return so \toksa can be used as temporary storage % (on exiting the current \begingroup its value will be restored to what it was % before the group was entered) \edef\next{\toksa{#1#2}}\next % return prepended and appended code \def\t@kreturn{\expandafter\endgroup\the\toksa}% \else \edef\tokreturn{#3{{#2}#1#3{\the#3}}}\tokreturn \let\tokreturn#3% \let\t@kreturn\t@kr@turn \fi \t@kreturn % this sequence will be restored to its original value when the group is exited } \def\t@kr@turn#1{% \ifx#1\end \def\t@kreturn##1##2\end{\tokreturn{##2##1}}% \expandafter\t@kreturn\the\tokreturn\end \def\t@kreturn{\expandafter\endgroup\the\tokreturn}% \else \edef\t@kreturn{\tokreturn{\the\tokreturn#1{\the#1}}}\t@kreturn \let\t@kreturn\t@kr@turn \fi \t@kreturn } % switch macros, also used to implement state machines % a lot of care has been taken to ensure that no control sequence is changed % as well as all the register values are preserved. \newif\iftracedfa \def\taction#1\in#2{% \begingroup \edef\acstring{#1}% in case #1 is, say, \the\toksa, so we no longer have to keep track of it \iftracedfa\ferrmessage{acting on <\meaning\acstring>\space in (\string#2) \getstatename#2 }\fi \toksa\expandafter{#2}\toksb\expandafter{\acstring}% \edef\next{\toksa{\the\toksa\the\toksb{% \iftracedfa\noexpand\ferrmessage{default action: \noexpand\meaning\noexpand\default}\fi \noexpand\default}}% \def\noexpand\next####1\the\toksb####2####{\noexpand\grabaction}}\next \expandafter\next\the\toksa\grabaction \tokreturn{}{}{\the\toksa}% } \def\tactionx#1\in#2{% exclusive version of the macro above (i.e. match the last action before the brace) \begingroup \edef\acstring{#1}% in case #1 is, say, \the\toksa, so we no longer have to keep track of it \iftracedfa\errmessage{acting on <\meaning\acstring>\space in (\string#2) \getstatename#2 }\fi \toksa\expandafter{#2}\toksb\expandafter{\acstring}% \edef\next{\toksa{\the\toksa\the\toksb{% \iftracedfa\noexpand\ferrmessage{default action: \noexpand\meaning\noexpand\default}\fi \noexpand\default}}% \def\noexpand\next####1\the\toksb####{\noexpand\grabaction}}\next \expandafter\next\the\toksa\grabaction \tokreturn{}{}{\the\toksa}% } \def\getstatename#1{\expandafter\g@tstatename#1.\raw} \def\g@tstatename#1#2\raw{\expandafter\eatone\string#1} \def\caction#1\in#2{% \begingroup \uccode`.=#1\relax \uppercase{\toksa{\taction{.}\in}}% \toksb{#2}\concat\toksa\toksb \tokreturn{}{}{\the\toksa}% } \def\checkforcount#1{% a rough implementation of `type checking' for a parameter \expandafter\expandafter\expandafter \ch@ckforcount\expandafter\meaning\expandafter#1\meaning\count\end } \expandafter\def\expandafter\ch@ckforcount\expandafter#\expandafter1\meaning\count#2\end{% \yystringempty{#2}{\toksa{\taction}}{\toksa{\caction}}% } \def\switchonwithtype#1\in#2{% \begingroup \checkforcount#1% \toksb{{#1}\in{#2}}\concat\toksa\toksb \tokreturn{}{}{\the\toksa}% }% \let\switchon\taction \let\default\relax \def\grabaction#1#2\grabaction{\toksa{#1}} % switch manipulation macros: adding and replacing labels and actions % the macros assume that the switch to be manipulated is well formed, otherwise % no assumptions have been made; % if the label is not present in the switch or the new label already exists, an % error is returned % the macros are not expandable but can be made such with some % (rather significant) effort % #1 is the name of the old switch % #2 is the existing label to which the new label will be added % #3 is the new label % #4 is the name of the new switch % #5 is the operation to perform if #2 is present and #3 is not % this operation takes the following parameters: % #1: the expanded original switch % #2: the existing label % #3: the new label % #4: the name of the new switch \def\matchswitch#1#2#3#4#5{% \expandafter\matchswitch@a\expandafter{#1}{#2}{#3}{#4}{#1}{\matchswitch@e}{#5}% } % #1 is the expanded version of the switch % #2 is the label at which to change % #3 is the new label % #4 is the name of the new switch % #5 is the switch % #6 is the test sequence to apply if #2 is present % #7 is the operation to perform if #2 is present and #3 is not \def\matchswitch@a#1#2#3#4#5#6#7{\matchswitch@b{#1}{#1}{#2}{#3}{#4}{#5}{#6}{#7}} % #1 is the expanded version of the switch % #2 is the expanded version of the switch % #3 is the label at which to change % #4 is the new label % #5 is the name of the new switch % #6 is the switch % #7 is the test sequence to apply if #3 is present % #8 is the operation to perform if #3 is present and #4 is not \def\matchswitch@b#1#2#3#4#5#6#7#8{% \def#5##1#3{\matchswitch@c}% \expandafter\expandafter\expandafter#5\expandafter\eatone\string{#1#3}{#2}{#3}{#4}{#5}{#6}{#7}{#8}% } \def\matchswitch@c{% \expandafter\expandafter\expandafter\matchswitch@d \expandafter\expandafter\expandafter{\expandafter\eatone\string}% } % #1 is the match result % #2 is the expanded version of the switch % #3 is the label at which to change % #4 is the new label % #5 is the name of the new switch % #6 is the switch % #7 is the test sequence to apply if #3 is present % #8 is the operation to perform if #3 is present and #4 is not \def\matchswitch@d#1#2#3#4#5#6#7#8{% #7{#1}{#2}{#3}{#4}{#5}{#6}{#8}% } % #1 is the match result % #2 is the expanded version of the switch % #3 is the label at which to change % #4 is the new label % #5 is the name of the new switch % #6 is the switch % #7 is the operation to perform if #3 is present and #4 is not \def\matchswitch@e#1#2#3#4#5#6#7{% \yystringempty{#1}{% label not present \errhelp{Switch #6 contents: #2}% \errmessage{label \nx#3 was not found in switch \nx#6}% }{% \yystringempty{#4}{% no new label, skip the next test #7{#2}{#3}{#4}{#5}% }{% \matchswitch@a{#2}{#4}{#3}{#5}{#6}{\matchswitch@f}{#7}% }% }% } \def\matchswitch@f#1#2#3#4#5#6#7{% \yystringempty{#1}{% (new) label not present #7{#2}{#4}{#3}{#5}% }{% \errhelp{Switch #6 contents: #2}% \errmessage{label \nx#3 already exists in switch \nx#6} }% } % add a new empty action to a switch with a known action (safety feature) \def\amendswitch#1\near#2\by#3\to#4{% \matchswitch{#1}{#2}{#3}{#4}{\@mendswitch}% } \def\@mendswitch#1#2#3#4{% \def#4{#1#3{}}% } % add a label to an existing action \def\extendswitch#1\at#2\by#3\to#4{% \matchswitch{#1}{#2}{#3}{#4}{\@xtendswitch}% } \def\@xtendswitch#1#2#3#4{% \def#4##1#2##2#3{\def#4{##1#2#3##2}}% #4#1#3% } % replace an existing label inside a switch \def\replaceswitch#1\at#2\by#3\to#4{% \matchswitch{#1}{#2}{#3}{#4}{\r@placeswitch}% } \def\r@placeswitch#1#2#3#4{% \def#4##1#2##2#3{\def#4{##1#3##2}}% #4#1#3% } % replace an existing action inside a switch % this can also be used to add new labels, although no check is performed % whether the new label already exists % a word of caution: if one is using this command as intended, the % action code should be surrounded by an additional pair of braces (see % a use example in yy.sty) \def\replaceaction#1\at#2\by#3\to#4{% \matchswitch{#1}{#2}{}{#4}{\r@placeaction{#3}}% } % #1 holds the new action % #2 is the expanded switch % #3 is the label at which to make the replacement % #4 is empty % #5 is the name of the new switch \def\r@placeaction#1#2#3#4#5{% \r@placeaction@a{#2}{#3}{#5}{#1}% } % #1 is the expanded switch % #2 is the label at which to make the replacement % #3 is the name of the new switch % #4 is the new action \def\r@placeaction@a#1#2#3#4{% \def#3##1#2##2##{\expandafter\expandafter\expandafter \r@placeaction@b\expandafter\expandafter\expandafter{\expandafter\eattwo\string}}% \expandafter\expandafter\expandafter#3\expandafter\eatone\string{#1}{#2}{#3}{#1}{#4}% } % #1 is the part of the switch after the action % #2 is the label at which to make the replacement % #3 is the name of the new switch % #4 is the expanded switch % #5 is the new action \def\r@placeaction@b#1#2#3#4#5{% \def#3##1#2##2##{\expandafter\expandafter\expandafter \r@placeaction@c\expandafter\expandafter\expandafter{\expandafter\eatone\string}{##1}{##2}}% \expandafter\expandafter\expandafter#3\expandafter\eattwo\string{#4.}{#2}{#3}{#1}{#5}% } % #1 = {{before the label}{between the label and the action} after the action . } \def\r@placeaction@c#1{% \expandafter\yystringempty\expandafter{\r@placeaction@f#1}{% the remainder of the switch is gone \expandafter\r@placeaction@d\r@placeaction@e#1% }{% \expandafter\r@placeaction@c\expandafter{\r@placeaction@e#1}% } } % #1 before the label % #2 between the label and the action % #3 is the label % #4 is the name of the new switch % #5 part of the switch after the action % #6 is the new action \def\r@placeaction@d#1#2#3#4#5#6{\def#4{#1#3#2#6#5}} \def\r@placeaction@e#1#2#3.{{#1}{#2}} \def\r@placeaction@f#1#2#3.{} % grab the first token unless it is a space or a brace \def\getfirsttoken#1{% \yystartsinbrace{#1}{ }{\yystartsinspace{#1}{ }{% \expandafter\g@tfirsttoken\string{#1} % terminate \romannumeral }}% } \def\g@tfirsttoken#1#2{% \expandafter\noexpand\expandafter#2\romannumeral0\expandafter\eatone\expandafter{\string}% } % macros for `breaking out of' conditionals: % the idea is probably folklore; % \yybreak ... \yycontinue are the most efficient as they read everything exactly once % and expand only what is necessary; the next preferred way is the \xskip ... series % the \yyfinish macro is here `to plug a hole' when it is stylistically preferable % to keep the existing conditional structure and efficiency is not that important \long\def\xskiptofi#1#2\fi{\fi#1} \long\def\xskiptofifi#1#2\fi\fi{\fi\fi#1} \long\def\xskiptofififi#1#2\fi\fi\fi{\fi\fi\fi#1} \long\def\yyfinish#1#2\yycontinue{#2#1}% here just for completeness, use the ones below instead \long\def\yybreak#1#2\yycontinue{\fi#1} \long\def\yybreak@#1#2\yycontinue{\fi\fi#1} \long\def\yybreak@@#1#2\yycontinue{\fi\fi\fi#1} \long\def\yybreak@@@#1#2\yycontinue{\fi\fi\fi\fi#1} \long\def\yybreak@@@@#1#2\yycontinue{\fi\fi\fi\fi\fi#1} % we intentionally leave \yycontinue defined as an \errmessage % since it should not be expanded normally; % every conditional that uses \yybreak?{...} ... \yycontinue construct % must have an \else clause, i.e.\ a conditional such as % \if ab % \yybreak{}% % \yycontinue % is a bad idea as it will result in an incomplete \iffalse %\let\yycontinue\fi \def\yycontinue{\errmessage{\noexpand\yycontinue should never be expanded!}} % this also makes \if...\yycontinue constructs unskippable; this can be remedied by % adding a \fi before \yycontinue, which will not affect a properly constructed % conditional \long\def\yyfirstoftwo#1#2{#1} \long\def\yysecondoftwo#1#2{#2} \long\def\yyfirstofthree#1#2#3{#1} \long\def\yysecondofthree#1#2#3{#2} \long\def\yythirdofthree#1#2#3{#3} \long\def\yypioneofthree#1#2#3{{#1}} \long\def\yypitwoofthree#1#2#3{{#2}} \long\def\yypithreeofthree#1#2#3{{#3}} % macros for taking care of extra tokens \long\def\yyid#1{#1} % this is misnamed since it may change #1 by stripping braces and spaces \long\def\yyswap#1#2{#2#1} \long\def\eatone#1{} \long\def\eattwo#1#2{} \long\def\eatthree#1#2#3{} \long\def\eattoend#1\end{} \long\def\eattospace#1 {}