\everypar 中的无限循环

\everypar 中的无限循环

为什么下面的代码会进入无限循环?

\everypar={\hrule}
a
\bye

\tracingcommands=1给出这个:

{vertical mode: \everypar}
{blank space  }
{the letter a}
{horizontal mode: \hrule}
{\par}
{vertical mode: \hrule}
{the letter a}
{horizontal mode: \hrule}
{\par}
{vertical mode: \hrule}
{the letter a}
{horizontal mode: \hrule}
{\par}
{vertical mode: \hrule}
...

答案1

\hrule是一个垂直命令,用于结束段落。接下来,TeX 重新读取导致插入标记的标记\everypar,发现它是一个字符,因此它开始一个段落,插入\hrule,从而结束段落……

TeXbook 第 282 和 283 页中的更多理论

\indent\parskip除非 TeX 处于内部垂直模式且当前列表为空,否则将把粘连附加到当前列表。然后 TeX 进入不受限制的水平模式,以宽度为 的空 hbox 开始水平列表\parindent\everypar标记插入到 TeX 的输入中。页面生成器开始运行。当段落最终完成时,水平模式将结束,如第 25 章所述。

\noindent. 这与 完全相同\indent,只是 TeX 以水平模式启动时使用的是空列表而不是缩进。

• [...]

• 某些命令与垂直模式不兼容,因为它们本质上是水平的。当以下命令出现在垂直模式下时,它们会导致 TeX 开始一个新段落:

⟨horizontal command⟩ −→ ⟨letter⟩ | ⟨otherchar⟩ | \char | ⟨chardef token⟩
| \noboundary | \unhbox | \unhcopy | \valign | \vrule
| \hskip | \hfil | \hfill | \hss | \hfilneg
| \accent | \discretionary | \- | \␣ | $

这里⟨letter⟩⟨otherchar⟩代表类别 11 和 12 的显式或隐式字符标记。如果这些标记中的任何一个在垂直模式或内部垂直模式下作为命令出现,TeX 会自动执行上述命令\indent。这将导致使用输入中的标记进入水平模式\everypar,之后 TeX 将⟨horizontal command⟩再次看到。

关键在于最后一条:触发段落开始的水平命令尚未进入 TeX 胃中,将会被重新读取。

另一个关键点是,⟨vertical command⟩在水平模式下找到的 将发出一个\par用于结束当前段落(或执行已分配给的任何操作\par)的令牌。

因此你的代码可以简化为

\everypar{\par}a

这也会启动一个令人讨厌的无限循环(令人讨厌,因为它会用一个仅包含缩进框的段落的无尽队列填满你的磁盘。

相关内容