有一天我会了解 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