如何使用 \edef 扩展现有的宏?

如何使用 \edef 扩展现有的宏?

\edef进行扩展,但不执行命令。以下示例中如何使在其调用时而不是在定义时\foo执行 的赋值?为什么会产生而不是?使用 可根据需要工作。此外,调用会产生。为什么?\tmp\foo0F1F\let\bar\bazTeX capacity exceeded

\def\foo{F}
\def\bar{B}
\def\baz{Z}
\newcount\tmp
\newcount\N

\edef\foo{\tmp = \if aa \N \fi \the\tmp \foo}
\N=1
\foo

\let\oldbar = \bar
\def\bar{\tmp = \if aa \N \fi \the\tmp \oldbar}
\N=2
\bar

\expandafter\def\expandafter\baz\expandafter{\tmp = \if aa \N \fi \the\tmp \baz}
\N=3
%\baz

\bye

答案1

\foo如果您希望在替换文本的开头添加一些内容来增强其定义,则方法非常标准:

\def\leftadd#1#2{% #1 is a parameterless macro, #2 a token list
  \toks0=\expandafter{#1}% store the expansion of #1
  \toks2={#2}% store the token list
  \edef#1{\the\toks2 \the\toks0}% redefine #1
}

已经提出了几种其他方法,这可能是最容易理解的。它基于 传递的标记\the<toks register>在 中不再扩展的规则\edef

使用 e-TeX 扩展可以省去令牌寄存器:

\def\leftadd#1#2{\edef#1{\unexpanded{#2}\unexpanded\expandafter{#1}}}

现在

\def\foo{F}
\leftadd\foo{\tmp = \if aa \N \fi \the\tmp}

相当于定义\foo

\def\foo{\tmp = \if aa \N \fi \the\tmp F}

首先。


令牌注册免费版本:

\def\leftadd#1#2{\expandafter\leftaddaux\expandafter{#1}{#2}{#1}}
\def\leftaddaux#1#2#3{\def#3{#2#1}}

答案2

编辑后,这解决了 OP 提出的所有问题,关于\foo\baz。它还解决了 OP 在评论中提出的后续问题。

通过在定义中\foo放置前置\noexpand的来修复。并且,响应 OP 的评论,如果必须前置,则没有问题,如 MWE 中所示。\the\tmp\foo\tmp

修复涉及在新定义中设置结果之前\baz一直扩展到。我放了一堆东西来简化这个过程。还编辑了以作为解决方案的一部分进行演示。\baz\baz\glob\advance\tmp\baz

重新编辑以解决 OP 在评论中提出的其他情况:

\painful类似于\baz,但不使用\glob

\superbaz\tmp同时演示了之前值和之后值的使用。

\documentclass{article}
\begin{document}
\def\foo{F}
\def\bar{B}
\def\painful{W}
\def\baz{Z}
\newcount\tmp
\newcount\N

\edef\foo{\tmp = \if aa \N \fi \advance\tmp by 7 \noexpand\the\tmp \foo}
\N=1
\foo

\let\oldbar = \bar
\def\bar{\tmp = \if aa \N \fi \the\tmp \oldbar}
\N=2
\bar

\def\glob{\tmp = \if aa \N  \fi \advance\tmp by 2\noexpand\the\tmp}
\expandafter\def\expandafter\baz\expandafter{\expandafter\glob\baz}
\N=3
\baz

\expandafter\def\expandafter\painful\expandafter{\expandafter\tmp%
  \expandafter\expandafter\if\expandafter a\expandafter a%
  \expandafter\N\expandafter\fi\expandafter\the\expandafter\tmp\painful}
\N=4
\painful

\verb+\tmp+ is currently \the\tmp
\edef\superbaz{\the\tmp Z}

\def\glob{\tmp = \if aa \N  \fi \advance\tmp by 2\noexpand\the\tmp}
\expandafter\def\expandafter\superbaz\expandafter{\expandafter\glob\superbaz}
\N=5
\superbaz

%\bye
\end{document}

在此处输入图片描述

最后附录:

回答 OP 评论How to leave \the\tmp only in \superbaz and remove from \def\glob? (so that only 7Z will be printed). Also, how to do the same without \def\glob?

鞭打一匹死马……

\documentclass{article}
\begin{document}
\newcount\tmp
\newcount\N

\def\ultimatebaz{\the\tmp Z}
\expandafter\def\expandafter\ultimatebaz\expandafter{%
  \expandafter\tmp\expandafter\expandafter\if\expandafter a\expandafter a%
  \expandafter\N\expandafter\fi\expandafter\advance\expandafter\tmp%
  \expandafter b\expandafter y\expandafter 2\expandafter\noexpand\ultimatebaz}
\N=5
\ultimatebaz\par
\end{document}

在此处输入图片描述

相关内容