TeX 确定注释后 \par 的规则

TeX 确定注释后 \par 的规则

我对 TeX 中的注释、换行符和 s 的交互方式感到困惑\par。请考虑以下内容:

ab

a b

a
b

a%
b

a
%
b

a

b

a%

b

产生输出

ab

a b

a b

ab

a b

a

b

a

b

我一直认为注释会“消耗”下一个换行符,所以我会预料到

a%

b

产生与

a
b

但又有所不同。这是为什么呢?

答案1

当 TeX 读取你的文件时,它会维护一个state可以是以下三者之一的文件:

  • 状态(对于new_line):这是 TeX 从输入中每一行的开头开始的状态。

  • 状态(对于mid_line):这是最常见的状态

  • 状态年代(对于skip_blanks):这与状态 M 类似,只是空白被忽略。

除其他事项外(请参阅更多详细信息TeX 主题 2.5 节以及第 46-47 页TeXbookget_next程序第 343 条及以后在 TeX 程序中),一些相​​关的交互如下:

  1. 在州内时

    1. 空格(catcode 10)将被忽略[§345](因此:每行的前导空格将被忽略),

    2. 行尾字符(catcode 5)产生一个\par标记 [§347→§351]

    3. 注释字符(catcode 14)“结束该行”,即导致该行的其余部分(包括行尾字符)被忽略,因此(除非文件结束)TeX 将从下一行再次以状态 N 开始 [§347→§350]

    4. 大多数其他字符(字母等)将导致进入状态 M [§347]

  2. 在州内时

    1. 空格(类别码 10)产生空格标记并进入状态 S [§347→§349]

    2. 行尾字符(catcode 5)导致空格标记,并且(除非文件结束)TeX 将从下一行再次以状态 N 开始 [§347→§348]

    3. 注释字符(catcode 14)如上所述“结束该行”,即导致该行的其余部分(包括行尾字符)被忽略,因此(除非文件结束)TeX 将从下一行再次以状态 N 开始 [§347→§350]

  3. 在州内时年代

    1. 空格(catcode 10)将被忽略[§345]

    2. 行尾字符(catcode 5)与上述一样“结束该行”,因此(除非文件结束)TeX 将从下一行再次以状态 N 开始 [§347→§350]

    3. 注释字符(catcode 14)与上述一样“结束该行”,因此(除非文件结束)TeX 将从下一行再次以状态 N 开始 [§347→§350]


(稍后添加):如果太长,可能的总结是:

  • 首先想象一下,输入文件中的所有行都已删除所有前导空格,以便每行都是空的或以非空格字符开头。

  • 遇到注释字符会将您“传送”到下一行的开头(这样就不会遇到行尾)。

  • 当 TeX 位于行首并遇到行末时 —— 换句话说,如果该行(删除前导空格后)为空 —— 这将产生一个\par标记。

  • 否则,行尾相当于空格。

  • 连续的空格相当于一个空格。


因此,让我们看一下所有 7 个示例:

ab

— 上面的输出产生了“ab”;没有什么有趣的事情发生。

a b

— 上面的输出产生了“ab”:看到空格后,TeX 进入状态 S,因此a b也会产生相同的输出。

a
b

— 上面的代码在输出中产生了“ab”:当看到行尾时,会发出一个空格(上面列表中的 2.2)。请注意

a
    b

也会产生相同的“ab”。

a%
b

— 上述代码在输出中产生“ab”:当%看到 时,TeX 结束该行并进入状态 N(然后当b看到 时进入状态 M),就像ab在同一行中看到一样。同样,第二行上的前导空格将仍然结果为“ab”。

a
%
b

a— 上述代码在输出中产生了“ab”:当看到行尾(在 之后)时,会生成一个空格并且 TeX 进入状态 N,然后当在第二行时,TeX 会忽略该行的其余部分(包括行尾),并且在第三行看到%时再次处于状态 N。b

a

b

— 以上内容在输出中产生了两个段落:当看到行尾时(在 之后a),TeX 进入状态 N,然后当它在状态 N 中看到另一个行尾时,它会生成一个\par标记并从状态 N 中的第三行开始,然后看到b

a%

b

— 以上内容还会在输出中产生两个段落:当%看到时,TeX 会丢弃该行的其余部分并从状态 N 中的第二行开始。现在它看到一个行尾(处于状态 N),从而生成一个\par标记,之后 TeX 位于第三行并被b看到。

答案2

请注意,空白行上的空格不会干扰解释\par,因此规则并不像使用连续的换行符那么简单。这是因为 TeX 会忽略行首的空格。

实际规则是,TeX\par在遇到行尾时生成标记,同时仍然忽略行上的前导空格。这会导致两个后果:\par即使第一个行尾被埋在注释中,也会生成标记;n连续的换行符(可能混入空格)产生n-1 个\par代币,不是n/2.

答案3

作为对其他技术答案的补充,我将补充我的想法。你似乎认为%“消耗下一个换行符”。

这不是看待这个问题的最佳方式。在 TeX 中终点线字符。是的,字符 10 的 ASCII 名称是“换行符”或“换行符”,字符 13 的 ASCII 名称是“回车符”。

然而 TeX 采用了不同的方法。在编写 TeX 时,操作系统对于文本文件中“记录结束”的定义有着截然不同的看法。

有些使用“换行符”,有些使用“回车符”,有些使用两者以任意顺序组合,有些则什么都没有(它们有固定长度的记录,用字符 0,“null”)填充空白。

最后一种类型是类别代码 9(忽略)的原因:这里是摘录自plain.tex,为清楚起见,标有行号:

24 % We had to define the \catcodes right away, before the message line,
25 % since \message uses the { and } characters.
26 % When INITEX (the TeX initializer) starts up,
27 % it has defined the following \catcode values:
28 % \catcode`\^^@=9 % ascii null is ignored
29 % \catcode`\^^M=5 % ascii return is end-line
30 % \catcode`\\=0 % backslash is TeX escape character
31 % \catcode`\%=14 % percent sign is comment character
32 % \catcode`\ =10 % ascii space is blank space
33 % \catcode`\^^?=15 % ascii delete is invalid
34 % \catcode`\A=11 ... \catcode`\Z=11 % uppercase letters
35 % \catcode`\a=11 ... \catcode`\z=11 % lowercase letters
36 % all others are type 12 (other)

如你所见,第 29 行表示终点线该符号`\^^M表示“字符编号 13,因为MASCII 为 77,且 77 − 64 = 13。

由于操作系统曾经有过(现在仍然有)这些不同的想法,TeX 将向程序宣布记录结束信号的任务留给了特定系统的实现者。1

当 TeX 读取一条记录(换句话说是一行)时,它会丢弃记录结束信号(如果操作系统使用它的话)以及它前面的空格和行上它后面的内容。然后用与当前值\endlinechar(默认值 13)相对应的字符替换它。

请注意,到目前为止,尚未发生转换为标记的过程。这发生在读入整行之后。如果在标记化过程中,TeX 发现类别代码为 14(注释)的字符,它会丢弃该行上剩余的内容并切换到下一个。

状态其他答案中描述的与标记化阶段有关。

只要您改变思维方式即可%:它会占用当前行。\par无论前面是什么,空白行都会生成一个标记。空白行是仅包含类别代码 10(空格或制表符)或 9 的字符的行,直到找到类别代码 5 的字符。

例如,以下代码将只产生段落:

\endlinechar`a
bc

ef
\end%

输出将是包含的单行bcaaefa,因为根据上述定义,没有空行。

顺便说一句,最后一个%是必须的,否则 TeX 不会再说\end未定义。实际上未定义的控制序列是\enda,但 TeX 永远不会显示当前的\endlinechar


脚注。

1 TeX Live 实现根据在输入文件开头找到的内容识别最常见的记录结束信号,无论是换行符(Unix)、回车符(旧版 macOS)还是回车符/换行符的组合(旧版 DOS)。

相关内容