diff options
Diffstat (limited to 'support/splint/tex/yycommon.sty')
-rw-r--r-- | support/splint/tex/yycommon.sty | 716 |
1 files changed, 580 insertions, 136 deletions
diff --git a/support/splint/tex/yycommon.sty b/support/splint/tex/yycommon.sty index a8144efaa4..9dd249bd76 100644 --- a/support/splint/tex/yycommon.sty +++ b/support/splint/tex/yycommon.sty @@ -1,4 +1,4 @@ -% Copyright 2012-2020, Alexander Shibakov +% Copyright 2012-2024, Alexander Shibakov % This file is part of SPLinT % % SPLinT is free software: you can redistribute it and/or modify @@ -14,9 +14,22 @@ % You should have received a copy of the GNU General Public License % along with SPLinT. If not, see <http://www.gnu.org/licenses/>. +% 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 -% stacks will be defined as `list' macros, consisting of \sts{...}\sts{...}... type lists +% 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 @@ -111,55 +124,28 @@ \def\stackfinish#1{\def#1{0\message{:stack empty:}}} -\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 -} +% (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\yypeekvstack#1\upto#2{% assume #2 > 0 - \edef\sts{\noexpand\peelstack{\number#2}{\expandafter\xincrement\expandafter{\number\toptoks}}}#1\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}% } -\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 +\def\get@l@mof#1#2{% + \expandafter\get@lemof\expandafter{\the#1}{#2}% } -% 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% +\def\get@lemof#1#2{% + \ifcase#2 #1\else\fi } -\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 -} +\let\fgetelemof\getelemof % token register access @@ -210,6 +196,29 @@ #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; @@ -236,9 +245,10 @@ % 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. +% 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 @@ -283,7 +293,19 @@ {\expandafter\yythirdofthree\expandafter{\string}}% } -% the macros below are a derivation of David Kastrup's magnificent string comparison +% 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 @@ -318,26 +340,75 @@ \def\yystrcleanup#1\yysecondoftwo{#1\yyfirstoftwo} -% 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 +% prefix comparison macros +% use: \romannumeral-0\yyprefixmatch{string1}{string2} +% this will expand into {common prefix}{rest of string1}{rest of string2} -\def\yysx#1#2{% - \expandafter\space\expandafter\yysx\expandafter#1\romannumeral-1#2% +\def\yyprefixmatch#1#2{% + \yyprefixmatchbegin{#1\end}{#2\relax}{}% } -% the macro below can be simplified by reducing the number of braces -% but then \yytoks@mpty could not be reused +\def\yyprefixmatchbegin#1#2{% + \yypr@fixmatch#1{#2}% +} -\long\def\yystartsinbrace#1{% - \iffalse{\fi - \if{\yytoks@mpty#1}}% - \yybreak\yysecondoftwo +\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\yyfirstoftwo + \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{% @@ -362,95 +433,443 @@ \expandafter\yyisthiscs\expandafter{\the#1}% } -\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} +% 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 -\long\def\yypioneofthree#1#2#3{{#1}} -\long\def\yypitwoofthree#1#2#3{{#2}} -\long\def\yypithreeofthree#1#2#3{{#3}} +\def\yysx#1#2{% + \expandafter\space\expandafter\yysx\expandafter#1\romannumeral-1#2% +} -% (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 asignment 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 +% linked list macros -\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}% -} +\newif\iftracinglists -\def\get@l@mof#1#2{% - \expandafter\get@lemof\expandafter{\the#1}{#2}% +\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\get@lemof#1#2{% - \ifcase#2 #1\else\fi +\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 } -\let\fgetelemof\getelemof +\def\appendtolist#1#2{\appendtolistg{#1}{#2}{\def}} +\def\appendtolistx#1#2{\appendtolistg{#1}{#2}{\edef}} +\def\appendtolisti#1#2{\appendtolistg{#1}{#2}{\fdef}} -% a nestable loop +% note that lists with \listiterator entries can be executed and spliced +% but some functions (like \replace...) below do not work properly -\def\bloop#1\repeat{#1\bl@op{#1}\repeat\fi} +\def\fdef#1#2{% + \def#1{\listiterator{#1}{#2}}% so that #1 knows its name ... +} -\def\bl@op#1\repeat\fi{\fi#1\bl@op{#1}\repeat\fi} +\def\listiteratorsimple#1#2{% + #2% +} -% 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 +\let\listiterator\listiteratorsimple % expand the list without preprocessing -\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 +% 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\optimizetext#1{% optimizing text arrays - \setoptopt{#1}% - \tempca\z@ - \@ptimizetext{#1} +\def\listisempty#1{% + \ifnum\csname list.counter(#1)\endcsname=\z@ + \yybreak\yyfirstoftwo + \else + \yybreak\yysecondoftwo + \yycontinue } -\def\@ptimizetext#1{% - \edef\next{\expandafter\ifcase\expandafter\tempca\the\csname#1\endcsname\else\end\fi}% - \ifx\next\endcontainer - \let\next\eatone +% 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 - \expandafter\edef\csname #1\parsernamespace\the\tempca\endcsname{\next}% - \advance\tempca\@ne - \let\next\@ptimizetext + \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 - \next{#1}% } -\def\uoptimize#1{% same as the macro above but produces nonnegative constants as \mathchardef's - \setoptopt{#1}% - \tempca\z@ - \bloop - \tempcb=\expandafter\ifcase\expandafter\tempca\the\csname#1\endcsname\else\@MM\fi\relax - \ifnum\tempcb<\@MM % - \toksa\expandafter{\csname #1\parsernamespace\the\tempca\endcsname}% - \edef\next{\mathchardef\the\toksa=\the\tempcb\relax}\next - \advance\tempca\@ne - \repeat +\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\setoptopt#1{% - \expandafter\let\csname optopt[#1]\parsernamespace\endcsname\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}% } -\countdef\toptoks=15 % register responsible for token allocations +\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 @@ -540,7 +959,7 @@ \yystringempty{#2}{\toksa{\taction}}{\toksa{\caction}}% } -\def\action#1\in#2{% +\def\switchonwithtype#1\in#2{% \begingroup \checkforcount#1% \toksb{{#1}\in{#2}}\concat\toksa\toksb @@ -548,7 +967,6 @@ }% \let\switchon\taction -\let\switchonwithtype\action % phase out \action, since it is a rather common name \let\default\relax \def\grabaction#1#2\grabaction{\toksa{#1}} @@ -561,11 +979,16 @@ % the macros are not expandable but can be made such with some % (rather significant) effort -% #1 is the label at which to change -% #2 is the new label -% #3 is the name of the new switch -% #4 is the switch +% #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}% } @@ -630,7 +1053,7 @@ } \def\matchswitch@f#1#2#3#4#5#6#7{% - \yystringempty{#1}{% label not present + \yystringempty{#1}{% (new) label not present #7{#2}{#4}{#3}{#5}% }{% \errhelp{Switch #6 contents: #2}% @@ -638,6 +1061,16 @@ }% } +% 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{% @@ -661,6 +1094,11 @@ } % 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}}% @@ -761,16 +1199,22 @@ % 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 changes #1 by stripping braces and spaces +\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 {} - -\input xarithm.sty - -\newif\ifbootstrapmode |