两者之间有什么区别吗?
\newcount\acounter
\def\dosomething{\afterassignment\dosomesecret\acounter=}
\def\dosomesecret{I do something with \the\acounter}
和
\newcount\acounter
\def\dosomething#1{\acounter=#1%
I do something with \the\acounter}
是什么加?为什么\afterassignment
我应该选择其中一个解决方案而不是另一个?
答案1
主要区别在于使用\afterassignment
可以保留赋值语法。因此,在您的反例中,后面的任意数量的标记都\dosomething
将被扩展,直到扫描到构成 a 的一系列不可扩展标记为止<number>
。第二个版本强制使用宏参数语法,其中数字必须作为单个标记或括号组给出。哪种更好取决于您要做什么。
来自乳胶来源的另一个例子
\def\protected@edef{%
\let\@@protect\protect
\let\protect\@unexpandable@protect
\afterassignment\restore@protect
\edef
}
\protected@edef
采用带有分隔参数等的语法,并在之后\edef
恢复的含义。因此您可以这样做\protect
\edef
\protectected@edef\foo#1#2\@nil{.....#1...#2}
如果不使用的话,这样做会不太方便\afterassignment
。
另一个可能更好的例子,同样基于 latex 库中的用法,以下是纯 TeX 文件
\def\removetonil#1\xx{}
\def\myset#1{\afterassignment\removetonil
\dimen0=#1pt\relax\xx
\immediate\write20{[\the\dimen0]}}
\myset{3}
\myset{3em}
\myset{3cm}
\myset{\vsize}
\bye
生产
[3.0pt]
[30.00005pt]
[85.35826pt]
[643.20255pt]
这是设置\dimen0
为用户指定的长度,其中参数可以省略单位(默认为pt
)或给出明确的单位,或者是 TeX 维度寄存器或原语,例如\vsize
。通过使用\afterassignment
原语赋值可能会或可能不会使用后面的标记,#1
pt\relax
如果参数是,则将被使用<number>
,但如果它已经是维度,则不会。因为\removetonil
在赋值之后立即插入,它可以清除任何未使用的标记。
答案2
该\afterassignment
宏向用户公开了 TeX 的词法分析例程。正如 David 在他的回答中指出的那样,这可以简化宏参数的处理。您还可以在此基础上构建纯 TeX 中的词法分析器或解析器。
我为普通的 TeX 编写了 geoptk 包,它允许定义以 TeX 基元为参数的宏\hbox
,\hfill
等等。使用此包,您可以定义一个\begindisplay
可以调用的宏,例如
\begindisplay file {chapter1} literal offset 20pt
此输入文本被替换为
\display@M{%
\getoptk@behaviour@display@file{chapter1}%
\getoptk@behaviour@display@literal
\getoptk@behaviour@display@dimen{20pt}%
}
这样它\display@M
就能完成其工作并在适当的时间触发行为。
所涉及的词法分析程序严重依赖于\afterassignment
。包代码足够短,因此您可以在几个小时内“获得它”,我也在 TUGBoat 上写了一篇关于此的文章。