diff options
Diffstat (limited to 'macros/generic/olsak-misc/eparam.tex')
-rw-r--r-- | macros/generic/olsak-misc/eparam.tex | 177 |
1 files changed, 177 insertions, 0 deletions
diff --git a/macros/generic/olsak-misc/eparam.tex b/macros/generic/olsak-misc/eparam.tex new file mode 100644 index 0000000000..8c7a22664d --- /dev/null +++ b/macros/generic/olsak-misc/eparam.tex @@ -0,0 +1,177 @@ +% eparam.tex +%%%%%%%%%%%%%%%%%%%% +% Petr Olsak 2014 + +% This macro enables full expansion during parameter scanning. +% The usage: +% \def\macro#1{macro with #1} +% \eparam\macro prameter-text +% +% The delimiters for the parameter are {...} or \start...\stop or +% combination {...\stop, \start...}, where \start is declared by \eparamopen +% and \stop is declared by \eparamclose. See more information at the end of +% this file or at +% http://tex.stackexchange.com/questions/196776/arguments-possibly-delimited-by-bgroup-and-egroup + + +\def\tmp{% all expandable primitives (only from classical TeX, you can add others): + \botmark \csname \else \endcsname \endinput \expandafter \fi \firstmark \fontname + \if \ifcase \ifcat \ifdim \ifeof \iffalse \ifhbox \ifhmode \ifinner + \ifmmode \ifnum \ifodd \iftrue \ifvbox \ifvmode \ifvoid \ifx + \input \jobname \meaning \noexpand \number \or \romannumeral + \splitbotmark \splitfirstmark \string \the \topmark +} +\def\skipmm#1->{} \def\showmm#1->{#1} +\edef\textmm{\expandafter\showmm\meaning\empty} +\edef\expandprimitives{\expandafter\skipmm\meaning\tmp} + +\def\isinlist#1#2#3{% from opmac.tex + \def\tmp##1#2##2\end{\def\tmp{##2}% + \ifx\tmp\empty \csname iffalse\expandafter\endcsname \else + \csname iftrue\expandafter\endcsname \fi}% end of \def\tmp + \expandafter\tmp#1\endlistsep#2\end +} +\def\isexpanded#1#2{% \isexpanded X\iftrue the X is expandable primitive or macro\fi + \edef\tmpb{\meaning#1\space}% + \expandafter\isinlist\expandafter\tmpb\expandafter{\textmm}% + \iftrue \csname iftrue\expandafter\endcsname\else + \def\nexxt{\expandafter\isinlist\expandafter\expandprimitives\expandafter{\tmpb}.}% + \expandafter\nexxt\fi +} +\def\eparamopen#1{\def\eparamopenA{\let#1=\eparamopenA}} +\def\eparamclose#1{\def\eparamcloseA{\let#1=\eparamcloseA}} + +\newtoks\eparamT +\def\eparam#1{\begingroup + \toks0={#1}\let\bgroup=\relax \let\egroup=\relax + \let\ifIamInGroup=\iffalse + \ifx\eparamopenA\undefined \def\eparamopenA{^\eparam^}\else \eparamopenA\fi + \ifx\eparamcloseA\undefined \def\eparamcloseA{^\eparam^}\else \eparamcloseA\fi + \eparamT={}\eparamA +} +\def\eparamA{\futurelet\tmpc\eparamB} +\def\eparamB{\let\next=\eparamD + \isexpanded\tmpc\iftrue \def\next{\expandafter\eparamA}\fi + \ifx\tmpc\bgroupOri \let\next=\eparamC \let\nexxt=\eparamD \fi + \ifx\tmpc\eparamopenA \let\next=\eparamC \let\nexxt=\eparamD \fi + \next +} +\def\eparamC{\afterassignment\nexxt \let\next= } +\def\eparamD{\futurelet\tmpc\eparamE} +\def\eparamE{\let\next=\eparamN + \isexpanded\tmpc\iftrue \def\next{\expandafter\eparamD}\fi + \ifx\tmpc\spacetoken \let\next=\eparamC \let\nexxt=\eparamD \eparamX{ }\fi + \ifx\tmpc\eparamcloseA \ifIamInGroup \let\next=\eparamN + \else \let\next=\eparamC \let\nexxt=\eparamF \fi\fi + \ifx\tmpc\egroupOri \let\next=\eparamC \let\nexxt=\eparamF \fi + \ifx\tmpc\bgroupOri \let\next=\eparamC \let\nexxt=\eparamG \fi + \next +} +\def\eparamN#1{\eparamX#1\eparamD} +\def\eparamG{\begingroup \let\ifIamInGroup=\iftrue \eparamT={}\eparamD} +\def\eparamF{\ifIamInGroup \let\next=\eparamY \else \let\next=\eparamZ \fi \next} +\long\def\eparamX#1{\eparamT\expandafter{\the\eparamT#1}} +\def\eparamY{\expandafter\endgroup + \expandafter\eparamT\expandafter\expandafter\expandafter + {\expandafter\the\expandafter\eparamT\expandafter{\the\eparamT}}% + \eparamD +} +\def\eparamZ{\expandafter\endgroup\the\toks0\expandafter{\the\eparamT}} + +\let\bgroupOri=\bgroup +\let\egroupOri=\egroup +\def\tmp/{\let\spacetoken= }\tmp/ % + +\endinput + +tests: + +\def\macro#1{\toks0={#1}\message{the parameter is "\the\toks0"}} + +\eparam\macro {abc} % the parameter is "abc" + +\def\x{ww} +\eparam\macro {ab\x c} % the parameter is "abwwc" +\eparam\macro {a b\the\pageno c} % the parameter is "ab1c" +\eparam\macro {ab\ifx\x\x true\else false\fi c} % the parameter is "abtruec" +\eparam\macro {ab\ifnum\folio=1 true\else false\fi c} % the parameter is "abtruec" +\eparam\macro {ab\ifcase\pageno oo\or one\or two\fi c} % the parameter is "abonec" + +\eparamopen\start \eparamclose\stop + +\eparam\macro {abc\stop % the parameter is "abc" +\eparam\macro \start abc\stop % the parameter is "abc" +\eparam\macro \start abc} % the parameter is "abc" + +\eparam\macro abc} % the parameter is "abc" +\eparam\macro abc\stop % the parameter is "abc" + +\eparam\macro \start abc{uf\stop fu}ee\stop % the parameter is "abc{uf\stop fu}ee" + +\def\y{end\stop} + +\eparam\macro {a\x\y % the parameter is "awwend" + +\eparam {\def\aha#1#2}\start params: #1 and #2\stop + +\eparamopen\bgroup \eparamclose\egroup +\eparam {\def\foo#1#2}\bgroup Something with #1 and #2\egroup + +\message{\meaning\foo} + +\end + +The question gives me a sense if it is read from its end: *give +the possibility of creating a macro which expands its parameter during +parameter scanning*. Then the variants `}` or `\egroup` as a delimiter of the +parameter is serviceable. + +I've created the `\eparam` macro with this syntax: + + \def\mymacro #1{the #1 parameter is declared as undelimited} + ... + \eparam\mymacro parameter-text + +The `parameter-text` is equal to `real-parameter-text` enclosed by braces or +by another control sequences declared by `\eparamopen` and \eparamclose`. +Example: + + \eparamopen\start \eparamclose\stop + \eparam\mymacro {real-parameter-text} + \eparam\mymacro \start real-parameter-text\stop + \eparam\mymacro \start real-parameter-text} + \eparam\mymacro {real-parameter-text\stop + +The main point of the `\eparam` is that this is **Expanded Parameter**. +The `real-parameter-text` is expanded during parameter scanning like +by `\edef`. This means that all expandable primitives and macros are +expanded during the parameter is read. Unexpandable primitives does nothing +in this time (like `\edef`) so you can do reassigmnent of registers/macros +inside this parameter but without any effect for parameter scaninng. +This is main difference between this case and the `\hbox {...}` primitive +syntax. + +There is one difference between `\edef` and parameter scanning: +undefined control sequences do nothing (like unexpandable primitives) +during parameter scanning. The error can be occur only when the parameter is +used (no during parameter scanning). + +The separator declared by `\eparamclose` can be hidden in a macro. Example: + + \def\x{-text\stop} + \eparam\mymacro {real-parameter\x + +The first open brace or delimiter given by `\eparamopen` is optional. I.e. +you can omit it: + + \eparam\mymacro real-parameter-text\stop + +The parameter is always balanced. This means that the delimiter declared by +`\eparamclose` does no effect inside inner braces pair (like normal +parameter scanning): + + \eparam \start text{inside \stop braces}text\stop + % the parameter is: "text{inside \stop braces}text" + +The implementation (or wipet's sorcery :) and little tests follow. +
\ No newline at end of file |