manmac.tex
当我读到这段代码片段时,我读了一些宏
% (now Appendix E resumes again)
% macros for verbatim scanning
\chardef\other=12
\def\ttverbatim{\begingroup
\catcode`\\=\other
\catcode`\{=\other
\catcode`\}=\other
\catcode`\$=\other
\catcode`\&=\other
\catcode`\#=\other
\catcode`\%=\other
\catcode`\~=\other
\catcode`\_=\other
\catcode`\^=\other
\obeyspaces \obeylines \tt}
\outer\def\begintt{$$\let\par=\endgraf \ttverbatim \parskip=\z@
\catcode`\|=0 \rightskip-5pc \ttfinish}
{\catcode`\|=0 |catcode`|\=\other % | is temporary escape character
|obeylines % end of line is active
|gdef|ttfinish#1^^M#2\endtt{#1|vbox{#2}|endgroup$$}}
在 的定义中\begintt
, 的 catcode\
被 改为 12 \ttverbatim
,然后是一系列宏\parskip=\z@ \catcode`\|=0 \rightskip-5pc \ttfinish
。为了清楚地描述我的问题,我在下面的代码片段中提取了作者的想法:
\def\x{x}
\def\myverbatim{\begingroup\catcode`\\=12 \tt \x }
{\catcode`\^^@=0 ^^@myverbatim ^^@endgroup}
这个输出是x
。让我感到疑惑的是,既然 的 catcode\
从 0 变成了 12,为什么后面的输入文本\tt \x
还能被解析成控制序列 token 呢?我期望的输出是\tt \x
。
答案1
因为当你定义 时\def\myverbatim{\begingroup\catcode`\\=12 \tt \x }
, 的 catcode\
是 0,所以 TeX 已经将 和 标记\tt
为\x
控制序列标记,并且 TeX 永远不会在标记被标记之后更改标记。也许这个例子可以帮助你更清楚地看到区别:
\def\x{x}
\def\myverbatim{\begingroup\catcode`\\=12 (1: \tt \x)}
\def\endmyverbatim{\endgroup}
\catcode`|=0
\myverbatim % (1: \tt \x)
(2:\tt \x)
|endmyverbatim
\bye
对于1
,TeX 已经将其扫描\tt \x
为控制序列标记,当您展开 时\myverbatim
,它们仍然是控制序列标记并进行相应的处理。
完全处理 后\myverbatim
, 的 catcode\
会发生变化,然后 TeX 会继续扫描(2:...
。此时,TeX 将 视为\
普通字符,因此\tt \x
只是一个没有特殊含义的 6 字符字符串。因此,您现在必须键入内容|endmyverbatim
才能使环境正确结束(\endmyverbatim
只会被排版)。
这个过程就是 Knuth 所说的 TeX 的眼睛和 TeX 的嘴巴。眼睛看着人物并根据当前的 catcode 设置为每个字符分配一个含义。这个含义固定到看到的每个字符上,字符 + 含义构成一个标记。代币然后到达嘴里,根据其含义进行处理。
这个标记不会改变,这就是\makeatletter
...\makeatother
在定义中不起作用的原因,也是导致逐字环境在另一个宏的参数中使用时不起作用的原因。
答案2
当 TeX 吸收要定义的宏的替换文本时,\def
或者\gdef
它不无论对输入作何解释,它都只会根据\def
找到时有效的类别代码对其进行标记。使用\edef
或\xdef
仅执行宏扩展。
在这两种情况下,都不会执行任何分配,因此尝试是没有用的\edef\myverbatim
。
按照你的定义,替换文本\myverbatim
是
|begingroup| |catcode| `12 |\| =12 112 212 |tt| |x|
其中|...|
表示一个符号标记(空格只是为了清楚起见)。
这样做\edef
只会产生一个奇怪的错误,因为唯一可扩展的标记是\\
,在纯 TeX 中是
\\:
macro:#1pt->#1
(由于历史原因)。
仅有的后您调用的\myverbatim
替换文本被插入到输入流中,标记被扩展,分配被执行,因此的类别代码\
将变成 12。
为什么会这样?一个典型的任务是\advance\mycount by 1
,您希望 TeX 在调用时执行此操作,而不是在定义最终执行此操作的宏时执行此操作。同样,如果您在替换文本中有一个宏,您希望在调用时使用它的含义,而不是在定义时使用它的含义。
同样,您希望定义时有效的类别代码与调用时有效的类别代码相同,否则会产生非常奇怪的效果。例如,定义\begintt
has $$
,您希望这些是总是 $3
,而不是在通话时可能发生的任何情况。