根据 TeXbook,文件中的字符首先转换为带有 catcodes 的标记(“mouth”),然后执行任何不可扩展的命令(“stomach”)。\catcode
是一个不可扩展的命令,因此应该执行后角色标记被分配了一个 catcode。但根据这本书,
一旦类别代码被附加到字符标记上,附件是永久的. 例如,如果字符 '{' 突然被声明为属于类别 12 而不是类别 1,则已经在 TEX 标记列表中的字符 '{ 1 ' 仍然属于类别 1;只有新创建的列表才会包含 '{ 12 ' 标记。
那么,如果\catcode
在“嘴巴”中遇到命令,TeX 是否会自动执行该命令,以便它会影响其后的任何标记?或者它仍然在胃中执行,因为跟在它后面的标记可能已经被分配了错误的 catcode?TeX 在哪个“器官”/阶段执行\catcode
?
答案1
TeX 每次吸收一条记录(通常是一行),但不会立即将其标记化。相反,它会将其标准化,如果操作系统使用 EOL 字符(它们),则将其更改为与 的当前值相对应的字符\endlinechar
。
然后它继续读取对输入进行标记的行如所须来确定接下来会发生什么。
例如,如果它发现\foo {xyz}
和\foo
是单参数宏,它将忽略空格并标记开括号和它找到的任何内容,直到找到匹配的闭括号(并标记)。继续这个例子,如果的扩展\foo
包含类似的东西\catcode\endlinechar=12
,下一个尚未标记的行尾字符将被解释为具有类别代码 12。因此,类别代码更改是在胃中完成的,但它们可以并且将影响尚未进入口中的输入,即尚未标记的输入。
但是,请记住,TeX 在吸收宏的替换文本时不会解释任何指令,也不会扩展任何宏。这主要是 Knuth 所指的标记列表中已有的字符。
一个有趣的例子:
x\obeyspaces x\bye
你可能知道这\obeyspaces
很简单
\catcode`\ =\active
并且 Plain TeX 将活动空格字符设置为扩展为 catcode 10 空格。您可以检查输出是否为
等等!TeX 不会忽略控制字后的空格吗?是也不是。在对输入进行标记时,TeX 确定其后的下一个字符s
不是字母(即,catcodes 的内部表没有为其分配代码 11),因此它停止搜索控制序列名称,输入扫描器进入“跳过空格”状态,但空格尚未被标记。该标记是\obeyspaces
一个无参数宏,因此它被扩展并执行类别代码更改。现在 TeX 需要更多标记,因此它对下一个字符进行标记,该字符恰好是一个空格,并根据(刚刚更改的)catcode 表的指示为其分配类别代码 13:由于下一个字符没有 catcode 10,状态从“跳过空格”更改为“行中”。然后 TeX 扩展活动字符 it,输出中出现一个空格。
答案2
根据 TeXbook,文件中的字符首先转换为带有 catcodes(“mouth”)的标记,然后执行任何不可扩展的命令(“stomach”)。
这里你必须小心“然后”的含义。
字符确实由“嘴”转换成标记,这些标记被传递到“胃”。但如果你把它解释为文件中的所有字符都首先被标记,然后(在所有内容都被标记之后)“胃”才开始发挥作用——那就错了。相反,这两个系统相互作用:“嘴”可能会将命令传递给“胃”,后者会采取一些行动,然后问“嘴巴”会获取更多 token,依此类推。“胃”中采取的行动可以影响“嘴巴”未来的运作。
考虑一下“嘴”和“胃”的其他名称可能会有所帮助:它们被称为“输入处理器”[+“扩展处理器”]和“执行处理器”TeX 按主题分类以及 Knuth 在TeX 程序:
大致来说,你可以把 TeX 的主控制循环想象成一个饥饿的胃,它只是接连执行一个又一个的命令,并在完成上一个命令后反复向嘴巴索要 token,或者在执行时特定命令。例如,假设您有以下输入文件:
hi\hskip 10 pt\end
然后胃就会
- 标记
h₁₁
(它本质上“执行”为排版该字符的命令 - 将该字符放入适当的列表中)。 - 令牌
i₁₁
(它“执行”,与上面相同)。 - 令牌
\hskip
——此时,胃执行hskip
命令,作为其中的一部分调用句法例程(mouth)并请求标记,以扫描胶水规范10 pt
。 - 令牌
\end
(作为命令执行)。
那么当TeXbook给出(第38页)您提到的被转换成标记{\hskip 36 pt}
序列的示例{₁
,,,,,,,,,,,这有点误导:虽然字符确实在某个时候转换为这些标记,但这种标记化(例如和)在“胃”看到命令之前并没有完全发生;大部分发生在之后。hskip
3₁₂
6₁₂
p₁₁
t₁₁
}₂
p
t
\hskip
\catcode
是不可展开的命令,因此应该执行后字符标记已分配了 catcode。[…] 那么,如果\catcode
在“嘴巴”中遇到命令,TeX 是否会自动执行该命令,以便它会影响其后的任何标记?或者它仍然在胃中执行,在它后面的标记可能已被分配了错误的 catcode 之后?
这里有很多(可以理解的)困惑,但答案是:\catcode
在胃中执行,之后以前的字符已被分配了 catcode 并变成了标记。
如果
\catcode
在嘴里遇到当胃正在寻找要执行的命令时,然后它会被传递到胃部,在那里执行,并影响未来的令牌。如果
\catcode
在胃只是收集标记(例如在宏定义或标记列表分配中)时在口中遇到,则它只是被收集为另一个标记(未执行),并且未来的标记(在被收集的列表中)将根据收集开始时的 catcode 进行扫描。
为了说明起见,考虑\catcode`S=3
将字母的类别代码更改S
为 3(即数学转变,如$
)。
第一种情况的示例:
hello \catcode`S=3 SxS
\bye
第二种情况的例子:
\def\change{hello \catcode`S=3 SxS}
\change
now SyS
\bye
(这里,首先将 的定义\change
收集为一个标记列表,其中有一个明确的“字母”标记 S,因此当我们使用\change
它时,它会扩展为一个包含该字母 S 标记的列表,这就是被排版的内容。但是 的扩展\change
还包含一个\catcode
命令,该命令这次执行并影响了未来的标记。)
TeX 在哪个“器官”/阶段
\catcode
执行?
简单的回答:在胃里。