From cfcc1904be1dc1c098dda94f10feaa4b498bbc0e Mon Sep 17 00:00:00 2001 From: Karl Berry Date: Wed, 22 Jun 2016 22:28:57 +0000 Subject: olsak-misc (21jun16) git-svn-id: svn://tug.org/texlive/trunk@41526 c570f23f-e606-0410-a88d-b1316a301751 --- .../texmf-dist/doc/generic/olsak-misc/seplist.tex | 131 +++++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 Master/texmf-dist/doc/generic/olsak-misc/seplist.tex (limited to 'Master/texmf-dist/doc/generic/olsak-misc/seplist.tex') diff --git a/Master/texmf-dist/doc/generic/olsak-misc/seplist.tex b/Master/texmf-dist/doc/generic/olsak-misc/seplist.tex new file mode 100644 index 00000000000..0eac4d541a4 --- /dev/null +++ b/Master/texmf-dist/doc/generic/olsak-misc/seplist.tex @@ -0,0 +1,131 @@ +% seplist.tex +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Petr Olsak 2014 + +% This macro enables to declare more than one separator for parameter +% scanning of your macro. Usage: + +% \long\def\yourmacro#1{usage of #1parameter} +% \seplist{list of separators}\yourmacro parameter-text separator +% example: +% \seplist{{sepA}{SepB}{SEPC}}\yourmacro text separated by sepA +% \seplist{{sepA}{SepB}{SEPC}}\yourmacro text separated by SepB +% \seplist{{sepA}{SepB}{SEPC}}\yourmacro text separated by SEPC +% All lines of this example are expanded to "usage of text separated by parameter". + +% The actually used separator is stored globally to the \sepused macro. +% The macro programmer can use this. + +% The input stream is read to the first instance of any of the listed +% separator, no more. The separator list includes separators in braces. +% If there are only one-token separators, braces can be omited. Example + +% \seplist{0123456789}\mymacro text to the first decimal digit 7 + +% The parameter have to be balanced. Thus, the separator hidden in braces +% is ignored. This behavior is similar like in normal separated parameters. + +% The \par or spaces or arbitrary control sequences can be a part of +% separators. The # (of catcode 6) cannot be a part of the separator but +% it can be included in the parameter text. + +% See implementation details at the end of this file + +\long\def\addto#1#2{\expandafter\def\expandafter#1\expandafter{#1#2}} +\newtoks\seplistT + +\long\def\seplistD#1{% + \seplistS##2\seplistE{\def\tmpa{##1}\def\tmpb{##2}\seplistE}% + \def\tmpb{\tmpa #1}\expandafter\tmpb \tmp\seplistD\seplistE +} +\long\def\seplistE#1{% + \ifx\tmpa\empty + \seplistS\seplistD{\def\tmpb{##1}}\expandafter\tmpa\tmpb + \ifx\tmpb\empty \seplistQ{#1}% + \else \expandafter\addto\expandafter\seplistLx + \expandafter {\expandafter\seplistD\expandafter{\tmpb}{#1}}% + \fi\fi +} +\def\seplistS{\long\expandafter\def\expandafter\tmpa\expandafter##\expandafter1\tmp} +\long\def\seplistQ#1#2\seplistA{\fi\fi\gdef\sepused{#1}\seplistZ} + +\long\def\seplist#1#2{\begingroup + \toks0={#2}\let\bgroup=\relax \let\egroup=\relax + \def\seplistL{}\def\seplistLx{}\seplistI#1{}\gdef\sepused{}% + \ifx\seplistL\empty \expandafter\endgroup \the\toks0\else + \seplistT={}\expandafter\seplistA\fi +} +\def\seplistA{\futurelet\tmp\seplistB} +\def\seplistB{\let\next=\seplistP + \expandafter\ifx\space\tmp \let\next=\seplistC \let\nexxt=\seplistM \fi + \ifx##\tmp \let\next=\seplistC \let\nexxt=\seplistH \fi + \ifx{\tmp \let\next=\seplistG \fi + \ifx}\tmp \let\next=\seplistC \let\nexxt=\seplistF \fi + \next +} +\def\seplistC{\afterassignment\nexxt \let\next= } +\long\def\seplistP#1{\seplistX#1\def\tmp{#1}\seplistN} +\def\seplistM{\seplistX{ }\def\tmp{ }\seplistN} +\def\seplistH{\seplistX{##}\def\seplistLx{}\seplistA} +\def\seplistN{\edef\seplistLx{\expandafter}\seplistLx \seplistL \seplistA} +\long\def\seplistG#1{\def\seplistLx{}\seplistX{{#1}}\seplistA} +\def\seplistF{\seplistT\expandafter{\expandafter{\the\seplistT}}\seplistZ} +\long\def\seplistX#1{\seplistT\expandafter{\the\seplistT#1}} +\def\seplistZ{\let\tmp=\sepused + \expandafter\seplistS\expandafter{\the\toks0{##1}}% + \expandafter\expandafter\expandafter\endgroup\expandafter\tmpa\the\seplistT +} +\long\def\seplistI#1{\ifx\seplistI#1\seplistI\else + \addto\seplistL{\seplistD{#1}{#1}}\expandafter\seplistI \fi +} + +\endinput + +\def\m#1{\toks0={#1}\message{param: "\the\toks0", separator: "\sepused"}} +\seplist{ab{c a}{cb}0123456789}\m uv#wcd{6cb7}uffc a + +% You can define \sepdef \macro #1[{sepA}{sepB}{sepC}]{usage of the parameter #1...} + +\def\sepdef #1#2[#3]{\def#1{\seplist{#3}{\csname:\string#1\endcsname}}% + \long\expandafter\def\csname:\string#1\endcsname ##1} + +\sepdef\test #1[uvw]#2{\message{1="#1", 2="#2"}} + +\test ahawx \test bhavy + +\end + +Comments to the implementation. + +We read the parameter token-per-token similarly as in openbrace.tex or +eparam.tex and store these tokens in \seplistT token list. The internal +macro \seplistL includes the list of separators in the form: + +\seplistD{sepA}{sepA}\seplistD{sepB}{sepB}... + +We store the already read token to \tmp and run \seplistL. More exactly: at +the start, the temporary \seplistLx is emty. For each read token, we expand +\seplistLx and \seplistL to the input stream and before executing it we +reset \def\seplistLx{}. Now, the input stream is executed, i.e. the +\seplistD macro is processed for each separator. The task of +\seplistD{sepA}{sepA} is the following: to test if the \tmp is equal to the +first token of its first parameter ("s" in this example). If it is true, +then \seplistD (using \seplistE) adds the text \seplistD{epA}{sepA} (the +first token from the first parameter is removed) to the temporary list +\seplistLx which will be executed for the next token. If \tmp isn't equal to +the first token of the first parameter then \seplistD does nothing. + +For example, the next read token \tmp is "e". Then \seplistD{epA}{sepA} +saves the \seplistD{pA}{sepA} to \seplistLx, because the first letter +\tmp="e". If the next token \tmp is "p", then \seplistD{A}{sepA} is stored +to the \seplistLx. And finally, if the next \tmp is "A", then +\seplistD{A}{sepA} does not store \seplistD{}{sepA}, but it decides that +separator is found because the first parameter is empty. It defines \sepused +to its second parameter "sepA" and it does the end of this game by \seplistQ +plus \seplistZ. If the last token \tmp isn't "A" then the \seplistD{A}{sepA} +does nothing and the chain is broken because the \seplistLx is set to empty +in each step. The new chain can be built because \seplistD{sepA}{sepA} is +still included in \seplistL which isn't changed during calculation. + +Macro-programing in TeX is beautiful but it is different than the classical +technique used by "normal" programming. -- cgit v1.2.3