\input 会引起哪些状态改变?

\input 会引起哪些状态改变?

TeXbook(第 20 次印刷,Addison-Wesley 1991 年)第 8 章“您输入的字符”描述了 TeX 的标记器,其输入是字符流,输出是标记流。标记器被描述为具有三种状态的状态机:

  • N - 开始新行
  • M——线的中间
  • S——跳过空白

在本章末尾(第 47 页),描述了\input标记器如何处理原语:

如果 TEX 在当前行没有更多内容可读,它将转到下一行并进入状态N。但是,如果\endinput已为文件指定\input,或者\input文件已结束,则 TEX 返回到\input最初发出命令时它正在读取的内容。

我不清楚的是:

  1. 当 TeX 开始读取文件时,会发生什么状态变化(如果有的话)\input

  2. 当 TeX 读取完文件后继续读取主文件时,会发生什么状态变化(如果有的话)\input

  3. 文件的结束是否\input被视为该文件最后一行的结束。


Johannes_B 和 Joseph Wright 对问题 1 和 3 给出了很好的答案,但问题 2 的答案对我来说仍然不清楚。Johannes_B 和 Joseph Wright 都声称,当读取输入文件时,标记器会恢复到以前的状态。但是这个以前的状态是在什么时候建立的?是在\input读取原语之前还是之后?是在读取文件名之前还是之后?是在文件名后面的空格被消耗之前还是之后?

答案1

\input遇到原语时,TeX 开始读取新文件并开始新行作为开头:因此状态从“无论它是什么”变为N。然后它按照正常规则继续进行,直到文件结尾(或\endinput)。然后 TeX 将返回到之前的状态。

在大多数情况下,这都是有点学术性的,因为\input通常在“表现良好”的源文件中单独使用一行。因此,结果与将文件输入的行简单地复制粘贴到主源中相同。如果我们故意安排情况并非如此,我们可以进行测试以表明行为与描述一致。例如,通过文件main.tex读取

\def\world{world}
\def\bar{bar}
Hello \world \input foo \bar
\bye

foo.tex阅读

foo

我们得到输出

你好,世界foo 酒吧

另一方面,如果我们foo.tex改为

foo%

然后我们得到输出

你好,世界foobar

这表明正如所描述的,TeX 已经恢复跳过空格原始字符的结尾\input。在第一种情况下,末尾有一个换行符,该换行符foo.tex会变成空格,因此会显示出来。在第二种情况下,我们没有该空格,后面的空格\input foo会被忽略,因此我们看不到它。请注意,该空格分隔由 : 拾取的文件名\input,如果没有它,我们需要一个 `\relax。)

如果输入文件包含\endinput所有线之后的将被忽略,但同一行中除 之后的任何内容都不会被忽略\endinput。同样,将我们的演示修改foo.tex

foo \endinput baz%
oops

我们得到

你好世界foo bazbar

或者如果我们省略%

你好世界foo baz bar

答案2

以下内容旨在补充约瑟夫·赖特的回答通过对原始帖子中的第 2 个问题提供明确的答案,即当 TeX 在完成读取文件后继续读取主文件时,会发生哪些状态变化(如果有的话)。\input这个答案是推测性的,因为我没有以源代码、TeXbook 或任何其他权威来源为基础,而是基于我自己的想法和观察。它基本上就是 Joseph Wright 在他的回答中所写的内容,只是我并不声称一旦读取了输入文件,TeX 就会“返回到之前的状态”。除此之外,它基本上是对他答案的重述。

我将假设 TeX 手稿的语法正确。我还将假设输入文件名是明确指定的,而不是通过宏指定的,并且以空格或某些不可扩展的控制序列结尾。

当 TeX“胃”\input从标记器接收到标记时,产生该标记的字符已被使用,并且后面的空格也已被使用,因此输入流中的下一个字符标记了文件名的第一个字符。

假设标记\input具有默认值(即假设它没有\let其他值),接下来发生的事情是文件名将被使用,直到输入流上的下一个字符是空格或某些不可扩展的控制序列。

然后,标记器将切换到状态 N(正如 Joseph Wright 的回答中指出的那样),当前输入流将被缓存,然后当前输入流指针将被指向由输入文件产生的输入流。

当后一个输入流被使用后,标记器的状态将变为 S,并且当前输入流指针将重定向到缓存的输入流。因此,现在将使用原始输入文件名后面的任何空格(如 Joseph Wright 的回答中指出的那样)。

相关内容