各种构造都可能导致 TeX(又名狮子)陷入无限循环。最简单的例子是\def~{~}~
,它定义~
为扩展为自身,然后扩展它。现在,如果我们排除宏扩展,获得循环就更加困难了。对于纯 TeX,我发现的两种最短方法(不使用宏)是
\everypar{\the\everypar}.
\toksdef~0~{\the~}\the~.
\the\toks0
(包括尾随的点);请注意,第二个不是宏扩展,而是隐藏的扩展。使用 eTeX,我
\if\unexpanded\fi
它具有可扩展的额外“特性”。这里,\unexpanded
可以替换为\detokenize
或\scantokens
。
- 为什么这会引发无限循环?
- 是否存在类似的短 TeX 构造,并且不使用宏扩展(最好仅使用原语)?
答案1
我认为已经理解了为什么会触发无限循环。e-TeX 基元\unexpanded
大致如下\lowercase
:它后面应该跟着<general text>
,而后者又是<filler>{<balanced text><right brace>
。重要的是<filler>
,它是命令和空格的任意序列\relax
(TeXbook,第 276 页)。
所以\unexpanded
寻找{
随时扩展的命令并忽略\relax
空格标记。但它是可扩展的!
当 e-TeX 找到 时\if\unexpanded\fi
,原语\if
会触发 的扩展\unexpanded
;但是\fi
紧随其后的 会导致插入一个 (frozen) \relax
,因为未完成的条件会\unexpanded
被吞噬,留下一个未完成的条件,从而导致插入\relax
…
哎呀,无限循环。对于\detokenize
和的\scantokens
情况是一样的。在原始的 TeX 中不<general text>
据我所知,可扩展原语接受一个as 参数。
情况确实完全不同\if\lowercase\fi
,\lowercase
其中不是可扩展,因此 TeX\relax
可以插入并进行比较(并且是正确的)。
答案2
不是特别短,但是我在开发过程中遇到了一个真正的错误xor
\output{\deadcycles=1
\message{.}% just to show that something is happening
\setbox0\box255}
\null
\bye
当然,输出例程没有设置\deadcycles
为 1。实际上,它是连续调用两个 OR,第一个将其设置为零。
刚刚意识到我只回答了问题的第二部分。到目前为止,第一部分已经由@egreg 回答了。
答案3
仅使用经典 tex 且不使用宏扩展的较短循环是
\let\par\relax.\vskip
或者
\let
\noindent
\vskip