TeX 总是插入宏 \par 吗?

TeX 总是插入宏 \par 吗?

当输入处理器遇到连续两个类别代码为 5 的字符(换句话说,一个空白行)时,它会插入宏\par

\vbox{Abc.}结束时,TeX 会结束当前段落,但不会插入宏\par。TeX 似乎插入的是\par原始内容。我理解 TeX 在这种情况下在做什么是否正确?TeX 插入的其他地方呢\par?什么时候是宏\par,什么时候是原始内容?

\catcode`@=11
\let\@@par\par
\def\par{\typeout{Macro!}\@@par}

Abc.

\vbox{Abc.\tracingall}

答案1

TeX 程序中只有 7 个地方 TeX 内部执行段落构建器,即将水平列表(如果正在构建)转换为段落。这种情况发生不是通过\par在输入流中插入一个标记,而是通过执行过程结束在 TeX 程序的模块§1096 中实现。

如果 TeX 不是水平模式,则此过程不执行任何操作;如果 TeX 处于水平模式但列表为空(TeX 会忽略空段落),则此过程基本不执行任何操作,然后执行该过程越线否则(并且那个人做了所有关于添加 parfillskip 惩罚等的神奇事情)。

这七个地方是

  • 在内部垂直结构的末尾,如右括号“\vbox但”\noalign\vcenter“对齐单元”
  • 当原始par_end被感知(最初在宏观层面上可用作 token 的含义\par
  • 输出例程(OR)结束后立即开始(因此,任何在 OR 中开始的水平列表都不会继续使用样稿中的材料,而是形成自己的段落)

在所有这些情况下,都没有\par插入标记(可能会重新定义);相反,结束程序已执行!

\par只有在水平模式下,遇到与水平模式不兼容的基元(如\vskip\hrule、... 中的完整列表在 TeX 代码中的 §1094)时,才会插入标记。当然,在标记化过程中,TeX 会用 替换两个行尾字符\par(即,使空行等同于\par)。

答案2

根据TeXbook,行尾规则如下

如果 TeX 遇到行尾字符(类别 5),它会丢弃当前行中可能保留的任何其他信息。然后如果 TeX 处于状态(换行符),行尾字符将转换为控制序列标记\par(段落结束);如果 TeX 处于状态(中间行),行尾字符被转换为类别 10(空格)的字符 32( )的标记;并且如果 TeX 处于状态年代(跳过空格),行尾字符被删除。

这里,需要注意的是 TeX 插入的是 token \par,而不是\par原语。这意味着\par在任何情况下都必须定义。Knuth 在讨论强制水平模式的命令时说明了这一点:

出现<垂直命令> 在受限水平模式下是被禁止的,但在常规水平模式下它会导致 TeX 将标记插入\par到输入中;在读取并扩展此 \par标记后,TeX 将看到 <垂直命令\par> 再次标记。(将使用 控制序列的当前含义;\par可能不再代表 TeX 的\par原语。)

现在,似乎没有任何地方提到内部垂直模式结束时会发生什么。显然,上述规则不允许插入标记,\par因为没有行尾标记需要处理。(如果在最后一个材料和框末尾\par之间有一个空白行,则确实会插入一个。)\vbox

读取跟踪输出,没有提到\par框末尾的原语,但 shipout 确实显示

....\penalty 10000
....\glue(\parfillskip) 0.0 plus 1.0fil

当然,显然已经构建了一个段落。所以我的结论是,内部垂直模式的结尾隐式插入了一个\par原语,从而插入了通常的段落结尾材料,然后运行段落构建器。

答案3

\parTeX 将 的“原始含义”放在 的末尾是有原因的\vbox:考虑以下愚蠢的输入

\vbox{\let\par\empty a}

当 TeX 找到 时},它会将其备份,通过插入“原始\par”来终止水平模式,然后重新读取},关闭内部垂直模式。

我们可以模拟如果 TeX在\par重新读取之前插入当前的含义会发生什么}

\vbox{\let\par\empty a\vskip0pt}

因为\vskip插入了一个 (当前)\par并且 TeX 重新读取了\vskip。结果就是无限循环!

(发现于1993 年讨论comp.text.tex

相关内容