这段代码为什么不起作用?

这段代码为什么不起作用?

在此邮政,一个答案指出\obeylines定义为

\def\obeylines{\catcode`\^^M\active \let ^^M\par }

然而当我尝试编译以下代码时,TeX 会抱怨

\def\obeylines{\catcode`\^^M\active \let ^^M\par }
\def\disobeylines{\catcode`\^^M=5 }

\obeylines
    We obey, and end up on separate lines.
    We obey.
\disobeylines
We disobey, and end up on the same line.
We disobey.

\bye

当我将第一行改为

\def\obeylines{\catcode`\^^M=13 \let^^M=\par }

这段代码为什么不起作用?

答案1

当 TeX 执行 时\def,它只会将标记与其当前的类别代码一起存储。在你的情况下,你正在存储

\catcode`12\^^M\active\let ^^M5\par

(项目符号分隔标记)。因此,当您的\obeylines宏被调用时,^^M它将变为活动状态,但\let^^M会抛出“缺少控制序列”的错误。

其实,这种分析并不完全正确,因为^^M定义主体中的 with 类别代码 5 将导致该行结束并被\par}忽略。所以你得到的错误是不同的。对其他字符执行类似操作也会遇到上述相同的问题。

如果你往里看,plain.tex你会看到

% In \obeylines, we say `\let^^M=\par' instead of `\def^^M{\par}'
% since this allows, for example, `\let\par=\cr \obeylines \halign{...'
{\catcode`\^^M=\active % these lines must end with %
  \gdef\obeylines{\catcode`\^^M\active \let^^M\par}%
  \global\let^^M\par} % this is in case ^^M appears in a \write

所以实际存储的是

\catcode`12\^^M\active\let ^^M13\par

它可以完成这项工作。\global\let^^M\par可以不带\global,但如果出现分页符,则可能会出现问题。

答案2

您需要^^M在定义时处于活动状态,以便\let^^M\par合法。查看 plain.tex 了解一种方法。

相关内容