在LaTeX2e内核中,有一个有用的宏\g@addto@macro
:
\long\def\g@addto@macro#1#2{%
\begingroup
\toks@\expandafter{#1#2}%
\xdef#1{\the\toks@}%
\endgroup}
但是我觉得这个定义比较复杂,为什么不这样定义呢?
\def\g@addto@macro#1#2{%
\expandafter\gdef\expandafter#1\expandafter{#1#2}} % or \xdef?
\par
除了前者允许的之外,我看不出这两种实现之间有任何区别。
我们知道etoolbox
包和 LaTeX3 在 eTeX 的帮助下使用了另一种方法:
% etoolbox
\newcommand{\expandonce}[1]{%
\unexpanded\expandafter{#1}}
\newrobustcmd{\appto}[2]{%
\ifundef{#1}
{\edef#1{\unexpanded{#2}}}
{\edef#1{\expandonce#1\unexpanded{#2}}}}
% LaTeX3
\cs_new:Npn \exp_not:o #1 { \etex_unexpanded:D \exp_after:wN {#1} }
\cs_new_protected:Npn \tl_put_right:Nn #1#2
{ \cs_set_nopar:Npx #1 { \exp_not:o #1 \exp_not:n {#2} } }
看起来没什么用:我根本\toks
找不到\tex_toks:D
, say \toks
in的任何用处。那么,我们真的需要寄存器吗?source3
\toks
注意:我不是在问有关 LaTeX (2e/3) 内核的问题,\g@addto@macro
只是举个例子。这更像是 TeX 中的宏寄存器和标记寄存器之间的比较。
答案1
我会将答案分为两部分:不使用 e-TeX 和使用 e-TeX,后者又细分为几个部分。
如果没有 e-TeX,您确实需要令牌寄存器来控制扩展。 里面\edef
是经典的例子,其中
\toks@{\mymacro\myothermacro...}%
\edef\foo{\the\toks@}%
不会扩展我们的宏。当你不知道这里的输入是什么时,这一点尤其必要:如果已知只有一个标记,那么\noexpand
就可以了。这同样适用于其他扩展上下文,例如\write
。
(我在这里假设读者知道这\the\toks@
只会扩展到 内部的 toks 的内容\edef
,而不会进一步扩展。取决于\mymacro
,ETC。,避免穷举扩张可能至关重要。)
关于为什么使用 toks 而不是简单的链的问题\expandafter
,LaTeX2e 源代码泄露了秘密:
% \begin{macro}{\g@addto@macro}
% Globally add to the end of a macro.
% \changes{v0.2a}{1993/11/14}{Made global}
% \changes{v0.2w}{1994/01/31}
% {Use toks register to avoid `hash' problems}
% \changes{v1.0o}{1995/05/17}
% {Make long for latex/1522}
% \changes{v1.0w}{1996/12/17}
% {Use \cs{begingroup} to save making a mathord}
% \changes{v1.0x}{1997/02/05}
% {missing percent /2402}
% \begin{macrocode}
\long\def\g@addto@macro#1#2{%
\begingroup
\toks@\expandafter{#1#2}%
\xdef#1{\the\toks@}%
\endgroup}
% \end{macrocode}
% \end{macro}
尝试使用\g@addto@macro\foo{\def\baz#1{}}
或其他任何包含#
不使用 toks 的内容并观察问题:您需要将所有#
s 加倍。
使用 e-TeX,\unexpanded
原语可用。它的作用类似于 toks,但没有分配,这允许更简单的定义,类似于问题中引用的两个。因此,一般来说,在 e-TeX 可用的情况下,几乎不需要使用 toks:因此,\g@addto@macro
我们从 LaTeX3 中删除了整个模块。l3toks
TeX 提供了一些 token 参数(例如\everypar
),它们的行为与 toks 非常相似,并且必须以类似的方式处理。对于 LaTeX3,计划是为所有这些参数提供一个类似宏的包装器,因此处理这种不寻常的行为将是内核团队独自完成的工作。
即使在 e-TeX 中,toks 也有一个有用的地方,那就是当你想通过寄存器号引用它们时。使用 toks 的通常方式是
\newtoks\my@toks
然后使用控制序列。但是,您也可以按数字使用 toks
\toks0={tokens}
通常,这不是一个好方法。但是,它不会消耗 TeX 哈希表中的 csname。因此,在一个组中(我们可以确保可以自由使用任何寄存器),按数字使用 toks 可能很有用。Bruno Le Floch 在l3regex
LaTeX3 模块中利用了这种方法,因为这避免了无用地大量使用哈希表,并且在这种情况下按数字引用实际上并不是一个坏主意。