summaryrefslogtreecommitdiff
path: root/support/splint/tex/yycommon.sty
diff options
context:
space:
mode:
Diffstat (limited to 'support/splint/tex/yycommon.sty')
-rw-r--r--support/splint/tex/yycommon.sty716
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