![为什么当还有标记需要处理时,`\endinput` 会让 TeX 进入交互模式?](https://linux22.com/image/418039/%E4%B8%BA%E4%BB%80%E4%B9%88%E5%BD%93%E8%BF%98%E6%9C%89%E6%A0%87%E8%AE%B0%E9%9C%80%E8%A6%81%E5%A4%84%E7%90%86%E6%97%B6%EF%BC%8C%60%5Cendinput%60%20%E4%BC%9A%E8%AE%A9%20TeX%20%E8%BF%9B%E5%85%A5%E4%BA%A4%E4%BA%92%E6%A8%A1%E5%BC%8F%EF%BC%9F.png)
最小示例包含两个文件:
fileA.tex
:
\def\foo#1{#1}
\foo{\endinput\input fileB.tex}%
fileB.tex
:
This is file B.
\bye
我假设编译fileA.tex
会产生一个fileA.pdf
包含短语“这是文件 B”的文件。
我明白这一点,但在编译过程中 TeX 进入交互模式。
当我按下回车键时,fileB.tex
就会加载并完成编译。
我的问题是:
TeX 为什么进入交互模式?
我认为\endinput\input fileB.tex
它已经存在于标记流中了。
这\endinput
会导致 TeX 不再读取和标记fileA.tex
任何内容。
由于\input fileB.tex
已经在标记流中,因此接下来会对其进行处理,并导致 TeX 从中读取和标记内容fileB.tex
。
但是为什么 TeX 在加载之前进入交互模式fileB.tex
?
这是控制台输出:
$ pdftex fileA.tex
This is pdfTeX, Version 3.14159265-2.6-1.40.19 (TeX Live 2019/dev/Debian) (preloaded format=pdftex)
restricted \write18 enabled.
entering extended mode
(./fileA.tex)
*
(./fileB.tex [1{/var/lib/texmf/fonts/map/pdftex/updmap/pdftex.map}] )</usr/shar
e/texlive/texmf-dist/fonts/type1/public/amsfonts/cm/cmr10.pfb>
Output written on fileA.pdf (1 page, 11997 bytes).
Transcript written on fileA.log.
答案1
非常好的发现。我想它会被视为一个潜在的错误,但其行为符合\endinput
TeXbook 第 214 页的定义:
- \结束输入。扩展为空。下次 TeX 到达 \input 行的末尾时,它将停止从包含该行的文件读取。
包装\foo{ }
器是一种不必要的转移,没有任何作用,因此在这里被忽略。(它可能本来是为了延迟的效果\endinput
,但却\endinput
被设计延迟了。)
在给定行以 结尾的情况下,%
TeX 仍然尝试读取文件名的字符,当它遇到行尾并触发待处理的 时\endinput
。这将结束来自 filea.tex 的输入,而文件名\input
仍不完整,因此 TeX 会寻找交互式输入。Enter
在交互式提示符 ( *
) 下按下 会给出一个\par
标记(因为行尾字符出现在控制台上输入行的开头)。这\par
会终止/分隔文件名,因此 TeX 可以继续输入 fileb.tex,它确实这样做了。\endinput
已经产生了效果(规则说“下一个时间”),这样整个文件 b.tex 都会得到输入。
请注意,定义中说的是“包含该行的文件”,而不是“包含 \endinput 的文件”,因此(对我来说)可能更有趣的情况是%
行中没有\input
。在这种情况下,文件名在 TeX 到达 EOL 之前终止,因此它会打开 fileb.tex 并从中读取输入。然后在 fileb 中第一行的末尾\endinput
触发待处理的请求,fileb 的其余部分被丢弃,输入返回到 filea.tex 中剩余的内容。
答案2
有两个不同的问题。
如果我删除尾随的%
,我可以通过交互式运行获得以下内容tex
:
This is TeX, Version 3.14159265 (TeX Live 2020) (preloaded format=tex)
(./jewdokijaA.tex (./jewdokijaB.tex))
*\bye
[1]
Output written on jewdokijaA.dvi (1 page, 224 bytes).
Transcript written on jewdokijaA.log.
您可以注意到,第二个文件在发出*
提示之前已加载。为了结束运行,我必须\bye
在提示符下手动提供。按下回车键除了重复消息外什么也不做
(Please type a command or say `\end')
*
并再次发出提示。
如果我\relax
之后添加\input jewdokijaB.tex
,我会得到相同的行为。
为什么你会得到
This is TeX, Version 3.14159265 (TeX Live 2020) (preloaded format=tex)
(./jewdokijaA.tex)
*
(./jewdokijaB.tex [1] )
Output written on jewdokijaA.dvi (1 page, 224 bytes).
Transcript written on jewdokijaA.log.
使用您的代码并按下回车键后运行结束?
在前两种情况下(无%
或有\relax
),文件名的解析已经完成,但\endinput
仍处于潜伏状态,因此第二个文件的第一行被读入并\endinput
执行其工作。
在你的情况下,TeX 除了向你请求输入之外什么也做不了,因为\endinput
仍然潜伏着,所以主文件中的后续行无法使用。你可以检查
\input jew%
dokija.tex
将定期输入文件,但
\endinput\input jew%
dokija.tex
不会。
但是,还有一个问题需要解决。为什么使用你的代码,文件充分回车后读入?
我猜答案在 的模块 361 和 362 中tex.web
。我承认这种行为令人费解。