TeX 基元\expandafter
和\aftergroup
都有“经验法则”,指出
\expandafter
应该使用2n+1
次数来提前查看n
标记(这是正确的吗?)。- 类似的“经验法则”也适用于
\aftergroup
作业:n^2-1
。
有人能解释一下这些规则从何而来吗?我理解将标记扩展为其定义的基本思想,但我无法将其推广到任意的前瞻,也就是说,扩展标记标记n
对我来说仍然很困难。
附言:我添加了一个“aftergroup”标签,因为我不确定哪个标签最合适。如果您认为您知道如何正确标记,请随意调整。
答案1
\expandafter
已在其他地方讨论过,因此我将限制于\aftergroup
。
考虑纯文本文件
{{{
xxx
\aftergroup a
xxx
\aftergroup\aftergroup
\aftergroup b
xxx
\aftergroup\aftergroup
\aftergroup\aftergroup
\aftergroup\aftergroup
\aftergroup c
xxx }
yyy }
zzz }
\bye
这产生了
\aftergroup
从输入流中取出以下标记,并在组结束后重新插入。
因此在第一个之后\aftergroup a
插入a
}
\aftergroup
为了更好地理解这三点b
,请按照图示逐行考虑它们。
\aftergroup\aftergroup
第一个\aftergroup
执行并将(未执行的)\aftergroup
令牌放在组的末尾(在这种情况下,它将被插入到a
先前放置在\aftergroup
队列中的令牌之后)。
\aftergroup b
b
位于当前组末尾的地方,它将被插入到\aftergroup
刚刚讨论的之后。
这意味着首先插入}
标记,然后进行排版,然后在遇到下一个标记时再次删除并重新插入。a\aftergroup b
a
\aftergroup
b
}
\aftergroup
前面的七个c
也类似。一开始读行时,你会发现每个其他标记都插入在当前组之后,因此插入
b
标记 之后(正如刚才讨论的那样)会插入该组之后,因此最后插入 c 并进行排版。\aftergroup\aftergroup\aftergroup c
\aftergroup c
}
为了将令牌提升一个额外的组级别,您需要对\aftergroup
前一个级别使用的所有令牌进行分组,再加\aftergroup
上感兴趣的令牌,您会发现通常有 1,3,7,... 2 ^ n-1 个\aftergroup
令牌来将令牌提升通过 n 个组级别。
请注意,并不是说必须有 2^n-1 个\aftergroup
有趣的效果,可以通过其他分组获得:
{{{
xxx
\aftergroup\aftergroup a
yyy}zzz
\aftergroup\aftergroup\aftergroup\aftergroup b
www}qqq}mmm
\bye
生产
这里\aftergroup\aftergroup
位于\aftergroup
第一个 之后}
;a
完全不受影响,因此在 之后按正常方式排版xxx
。然后在 处插入}
标记\aftergroup
并应用于第一个z
,因此只有两个zz
在此时排版,第一个在z
之后的下一个处排版。}
www
\aftergroup
之前的四个b
类似。两个\aftergroup
标记被移除并插入到下一个标记中}
,并且b
完全不受影响,因此在 之后排版zz
。这两个标记\aftergroup
被插入到下一个标记中}
,因此输入是
\aftergroup\aftergroup qqq}mmm
这\aftergroup
在之后插入一个}
,因此相当于
qqq}\aftergroup mmm
因此,一个m
从输入中取出,两个mm
被排版。第一个m
只是默默地消失,因为它会出现在当前组的末尾,但这是顶层,所以它只是丢失了(不是错误)。
答案2
(不可扩展)原语\aftergroup
仅适用于下一个标记;它使 TeX 将标记保存在 FIFO 列表中,该列表将在当前组结束后立即传送。所以
\begingroup\aftergroup x\aftergroup y\endgroup
和输入一样xy
:列表是“先进先出”的。请注意,对于宏,TeX 只保存宏,而不保存其含义。因此
\def\foo{X}
\begingroup\def\foo{Y}\aftergroup\foo\endgroup
将打印,因为一旦执行,X
的重新定义就会消失。\foo
\endgroup
我们属于哪个组并不重要;它可以是十六种不同的组类型中的任何一种。例如,\hbox{A\aftergroup B}
将框住一个并在框外A
打印;第一个例子可能是。B
{\aftergroup x\aftergroup y}
撇开由于为 FIFO 列表保留的大小有限而导致的问题,哪些标记可以跟在后面\aftergroup
?任何标记,甚至{
或}
;LaTeX 环境的定义lrbox
在这方面非常有启发性。
如果您想要链接标记以便在当前组结束后重新出现,只需在每个标记前面加上\aftergroup
:
\begingroup\aftergroup\mbox\aftergroup{\aftergroup X\aftergroup}\endgroup
\mbox{X}
将使 TeX在组结束后立即看到标记(并且所有设置都恢复)。
注意\aftergroup{\mbox{X}}
注意不是相当于上面的代码:\aftergroup
不接受括号中的参数,它只适用于紧随其后的标记。
如果你想推迟代码二团体赛结束,很简单:
\begingroup\begingroup
\aftergroup\aftergroup\aftergroup\foo
\endgroup\endgroup
意思应该很清楚:当前组(嵌套级别 2)结束时,TeX 将交付\aftergroup\foo
,它将保存回\foo
aftergroup 列表中,以便在外层组结束后交付。任何组级别都有此列表的化身。
如果你想爬三级,只要记住每组消耗一个\aftergroup
:所以
\begingroup\begingroup\begingroup
\aftergroup\aftergroup
\aftergroup\aftergroup
\aftergroup\aftergroup
\aftergroup\foo
\endgroup\endgroup\endgroup
就可以了,因为当第 3 级组结束时,列表将包含
\aftergroup\aftergroup\aftergroup\foo
通过归纳法自己证明一下,为了爬上去n级别,你需要 2n -\aftergroup
之前有 1 个标记\foo
。