有人能告诉我,我对 TeX 引擎(如tex
或pdftex
)如何处理以下 TeX 手稿的理解是否正确吗?如果不正确,请纠正我?
\iftrue\expandafter a\else b\fi c\bye
困难在于理解如何\else
扩展,以及在使用\fi
该子句时是否保留在输入流中。\else
我对这种形式感兴趣是因为我在 TikZ 源代码中(在文件中<pgf installation dir>/frontendlayer/tikz/tikz.code.tex
)遇到了类似的形式:
\def\tikz@endscope{%
\iftikz@auto@end@path%
\expandafter\tikz@finish\expandafter\egroup%
\else\expandafter\tikz@@endscope%
\fi%
}
TeX 引擎处理 TeX 手稿的方式如下
\iftrue\expandafter a\else b\fi c\bye
控制序列
\iftrue
从输入流中删除,并将内部标志推送到堆栈上,我将其称为堆栈if
,表示我们处于true
条件表达式的子句内。\expandafter
展开如下:控制序列
\expandafter
已从输入流中删除。输入流开头的标记,即
a
,将从输入流中移除,并推送到我将调用的内部堆栈上堆栈expand after
。输入流开头的标记,即
\else
,被扩展。那么, 是如何\else
扩展的呢?根据 TeX Book(第 20 次印刷,1991 年,第 213 页):当
\else
、\or
或\fi
扩展时,TEX 会读至任何应跳过的文本的末尾。因此 TeX 会跳过(即从输入流中删除)
\else
(包括\else
)和第一个\fi
(不包括 )之间的所有内容\fi
。这样输入流将保留以下内容:\fi c\bye
弹出堆栈
expand after
并将其元素添加到输入流的开头。因此,在此步骤结束时,输入流由以下内容组成:a\fi c\bye
恢复正常 TeX 处理。
该信件
a
被写入 dvi 文件。弹出
\fi
堆栈if
(回想一下步骤 1)。if
堆栈现在为空,因此 TeX 知道我们不再处于条件语句中。该信件
c
被写入 dvi 文件。引擎停止了。
最后,dvi 文件包含文本
交流电
答案1
您有一系列可扩展的命令。在这里,我将主要关注从“TeX 宏的观点”来看事情是如何发生的:TeX 程序中当然有细节,但我的理解是这不是重点。
首先,TeX 会进行扩展\iftrue
,使条件计数器增加一,但不会执行任何其他操作。然后,TeX 会找到\expandafter
跳过a
(就像您所说的放入堆栈一样)并扩展\else
。结果是 TeX 会寻找匹配的\fi
,因此会检查但不扩展标记,直到找到一个为止,并丢弃沿途收集的材料。一旦找到\fi
(或\let
原始标记),条件计数器就会减少,并且\fi
也会丢弃。在此阶段,a
会重新插入,我们(实际上)有
ac\bye
这是按通常方式排版的。
条件扩展移除这很重要。这意味着与\expandafter
条件相结合可以关闭前“有效载荷”已展开。您可以在以下结构中看到
\iftrue\expandafter\show\else b\fi c\bye
你会得到
> the letter c.
l.1 \iftrue\expandafter \show\else b\fi c
\bye
如果您希望插入任何带有参数的内容,这一点至关重要:否则您将不得不在各处应对杂散的条件结尾。