如果它的 catcode 即将改变,TeX 如何知道是否要占用这个空间?

如果它的 catcode 即将改变,TeX 如何知道是否要占用这个空间?

在文档中

\catcode32=13\def {o} \bye

TeX 如何知道将后面的空格标记\def为活动字符?

细节:正确的结果是o。首先,我们将空格(ASCII 32)设置为活动字符(类别 13);然后,我们将它们定义为打印o;然后,我们添加一个空格,打印o,然后完成。

解析器如何识别文字数字的结尾13?文字数字不能包含不可扩展的控制序列,例如\def。但它包含一个可扩展的控制序列,如\if,我们在读完并查找之前无法知道这是哪一个。因此,直到我们解析完 token 后\def,我们才知道 的结尾在哪里13

这里有点棘手。多字符控制序列会占用后面的空间。因此,在\catcode运行赋值之前,\def会占用后面的空间。但要运行赋值\catcode,我们必须标记到标记的末尾\def

那么,TeX 如何知道不要占用该空间?

答案1

确实,如果令牌处理器创建了一个令牌并将其发送到扩展处理器,那么一旦分配的 catcode 就无法更改(有几个例外\string,如\detokenize等,但这超出了我们当前的重点)。

但是你的例子

\catcode32=13\def {o} \bye

不符合该句子的第二部分:后面的空格\def在标记处理器级别等待处理。它不会被发送到扩展处理器。标记处理器\def两次识别后面的空格。首先,当\def构造控制序列时(此时空格具有类别代码 10)。然后标记处理器切换到“跳过空格”状态,它将发送\def给扩展处理器,并保留空格字符以供进一步处理。扩展处理器无法扩展\def,因此它告诉主处理器数字读取已完成,主处理器完成\catcode分配并运行\def。它在此处停用扩展处理器并要求标记处理器移动下一个标记。标记处理器获取等待空间并使用当前类别代码 13 从中创建一个标记。其“跳过空格”状态已完成,因为创建的标记不是类别为 10 的空格。它将标记空间/13 发送到主处理器。

从中得到的主要教训是:令牌处理器直到被发送到下一级处理(扩展处理器、主处理器)时才肯定会创建字符/catcode 对。

答案2

\catcode32=13\def {o} \bye

  1. 在收集形成第二个 TeX-⟨ 的 token 的过程中数字⟩-\catcode分配的数量,即 TeX-⟨数字⟩-数量被发现是⟨整型常数⟩ 由 ⟨ 序列组成数字以 ⟨ 开头的 ⟩-token数字⟩-token和 。112312
  2. 作为⟨数字⟩-token被视为 ⟨ 的一个组成部分312整型常数⟩ 因此不适合终止收集属于 ⟨整型常数⟩,如果可扩展,则将更多的代币进行代币化和扩展,直到找到适合终止收集属于⟨的代币的过程的代币整型常数⟩ 不被视为 ⟨整型常数⟩.
  3. 因此,在形成更多可能属于第二个 TeX-⟨ 的标记的过程中数字⟩-catcode 分配的数量,TeX 收集表示下一个标记的字符。
  4. 因此,TeX 遇到类别代码为 0(转义符)的字符\,并意识到要收集表示控制序列标记的字符。意识到这一点后,TeX 遇到该字符d ,由于该字符d的类别代码为 11(字母),因此意识到要收集表示控制字标记的字符。
  5. 因此,TeX 还会收集具有类别代码 11(字母)的字符e和字符。f
  6. 然后 TeX 遇到空格字符,此时该字符的类别代码为 10(空格)。在标记化时,类别代码不为 11(字母)的字符不被视为控制字标记名称的组成部分。因此,空格字符终止了收集表示控制字标记的字符的过程,TeX 将控制字标记附加\def到标记流中,并将读取装置切换到状态 S(跳过空格)。

该代币\def不被视为 ⟨整型常数⟩,因此收集属于⟨的代币的过程整型常数⟩/收集属于第二个 TeX 的标记的过程-⟨数字⟩-catcode-assignment 的数量终止,并且 catcode-assignment 已执行。

因此,当处理空格字符(终止收集\def-token 的字符)时,空格字符的类别代码为 13(活动)。由于状态 S(跳过空格)仅影响类别代码 10(空格)的字符,因此空格字符被标记为活动字符标记。

如果你想熟悉 TeX 中标记化/处理 .tex 输入行的单个字符的阶段如何与其他处理阶段(扩展阶段/执行分配阶段)交织在一起,请尝试弄清楚为什么

\catcode`\.=0\def.macro{replacement}\macro\bye

锻炼的同时

\catcode`\.=0.def.macro{replacement}\macro\bye

.macro产生关于/\macro未定义的错误消息。

答案3

事实上,这很简单。

  1. \catcode标记本身就告诉 TeX 要执行类别代码分配;

  2. 在这种情况下,TeX 会寻找一个 8 位 ⟨number⟩(对于 XeTeX 或 LuaTeX 来说,则是 21 位);

  3. 找到之后,TeX 会寻找 ⟨可选等号⟩ (=如果同时存在 ,则吞噬 后的空格);

  4. TeX 寻找一个 4 位数字。

如何指定 ⟨number⟩ 太长了,无法描述。 在您的例子中,两个必需的 ⟨number⟩ 都是显式常量,并且第 10 类空间将在数字序列后被吞噬。

还需要记住的是,读取了整行输入,并且\endlinechar在删除尾随空格后将记录末尾替换为,但字符尚未被标记:TeX 仅在需要时才对输入进行标记。

因此以下代码行是完全等效的:

\catcode32=13\def {o} \bye
\catcode32 =13\def {o} \bye
\catcode32= 13\def {o} \bye
\catcode32=13 \def {o} \bye
\catcode32 = 13\def {o} \bye
\catcode32 =13 \def {o} \bye
\catcode32 = 13 \def {o} \bye

事实上,输入

{\catcode32=13\def {o} }\par
{\catcode32 =13\def {o} }\par
{\catcode32= 13\def {o} }\par
{\catcode32=13 \def {o} }\par
{\catcode32 = 13\def {o} }\par
{\catcode32 =13 \def {o} }\par
{\catcode32 = 13 \def {o} }\par
\bye

产生七个 o。您的情况是第一个,\def不能解释为数字:在分配完成后,将标记放在一边重新读取。

让我们检查一下

\catcode32=13 \def {o} \bye

您可能想知道的就是这些(另外两个在 13 后面有一个空格的字符类似)。当 TeX 扫描完 后=,它会继续寻找一个 4 位 ⟨number⟩。它找到了1,所以它知道后面跟着一个显式常量。接下来是3一个空格。尚未完成类别代码分配,因此此空格被赋予类别代码 10 并终止数字查找。现在 TeX 知道要分配什么类别代码,它会执行分配并丢弃后面的类别 10 字符。

也许你可以问会发生什么

\catcode32=13  \def {o} \bye

完全一样,因为 TeX 在扫描完一个分类码为 10 的字符后,就进入了“跳过空格”的状态,所以后面的分类码为 10 的字符就被忽略了。这个跳过空格的动作发生在分类码赋值之前,因为 TeX 想要“规范化”输入流。

练习:预测输出

\catcode32=13\def {o} \  \bye

(反斜杠后有两个空格)。

答案4

通过尝试诸如

\catcode`Z=13Z

\def\defZ{W}\catcode`Z=13\defZ{XY}

我觉得在尝试终止 catcode 分配时,TeX 会使用当前预先存在的 catcode 方案进行扫描。因此,它将决定\def<space>终止\def分配,然后恢复其扫描和 catcode 分配(与\futurelet冻结 catcode 的情况不同),因此空间现在处于活动状态。

这不是一个权威的答案,因为不是基于实际的 TeX 源......


下面的例子

  {\catcode`Z=13 \gdefZ{WWW}}\catcode`Z=13ZZ

打印出 ZWWW 表明至少在这里 catcode 11 Z(13 之后的第一个)没有被重新解释为 catcode13。

这必须添加到我之前的胡言乱语中(额外的胡言乱语是一些 catcode 可能会被冻结;在 OP 中,虽然它距离较远,但让我们等待正确的答案)。

相关内容