TeX 中的无限循环

TeX 中的无限循环

有一天我会了解 TeX 是如何工作的;与此同时我在这里问;-)

代码

\def\x{Hello!\par\x}
\x

陷入无限循环,在几秒钟内生成数千页(正如我所料)。另一方面,代码片段

\def\x{Hello!\x}
\x

导致错误

! TeX capacity exceeded, sorry [main memory size=5000000].
\x ->Hello 
          !\x

我想理解这种行为。如果我只考虑宏扩展,我预计在后一种情况下也会出现无限循环:显然这不是真的,发布新段落会影响事情。

答案1

当 TeX 看到 时\par,它会创建一个段落,构建文本行;当达到足够的行数时,它会弹出一页并将其从内存中删除。因此,它在第一个循环中永远不会耗尽内存。

在第二种情况下,它会继续存储标记直到段落结束。显然,在内存耗尽之前,这种情况不会发生。

需要注意的是,当宏被扩展时,它将被替换文本替换,原始标记将消失。然而,Hello!在两种情况下,标记都会被发送到内部处理器以构建框。

答案2

正如 egreg 所说,您的示例之间的区别在于所构建的段落的大小不同。

仅考虑扩展,还有其他具有不同失败消息的变体。TeX 宏扩展使用尾部递归消除因此,如果递归调用是替换中的最后一项,则弹出输入堆栈递归调用,因此不需要使用堆栈。

如果你有

\def\x{Hello!\par\x\relax}
\x

这是您的第一个示例的非尾递归变体,tex 消亡得更早:

! TeX capacity exceeded, sorry [input stack size=5000].
\x ->H
      ello!\par \x \relax 
\x ->Hello!\par \x 
                   \relax 
\x ->Hello!\par \x 
                   \relax 
\x ->Hello!\par \x 
                   \relax 
\x ->Hello!\par \x 
                   \relax 
\x ->Hello!\par \x 
                   \relax 
...
l.2 \x

第二个版本基本上会得到同样的错误,因为输入堆栈比主内存的限制更多

\def\x{Hello!\x\relax}
\x

相关内容