在以下 pdftex 示例中,我们在“...”内创建了 verbatim 环境,即,所有特殊字符均获得 catcode 12。问题在于{
:
\def\setverb{\def\do##1{\catcode`##1=12}\dospecials}
\catcode`\"=\active
\def"#1"{%
\leavevmode\hbox{%
\setverb
\tt
\endlinechar=-1 \scantokens{#1}%
}%
}
hello "{" world
\bye
为什么会出现这个错误?
(./test.tex
Runaway argument?
{" world
! Forbidden control sequence found while scanning use of ".
<inserted text>
\par
<to be read again>
\bye
l.13 \bye
?
在遇到第二个参数之前它不应该对参数进行标记吗"
?
如何\def"#1"{...}
在所有情况下完成工作?
答案1
当 TeX"
找到"
在同一组级别,它没有找到,因为{
仍然有其通常的类别代码 1。由于"
不是\long
,第一个\par
标记会触发错误。
您必须将处理分为两部分:首先设置类别代码,然后吸收参数。
宏的参数文本可以定义分隔或未分隔的参数,但是,在任何情况下,TeX 都会跟踪<left brace>
和<right brace>
(分别表示类别代码 1 和 2 的显式字符标记)。
例如,
\def\foo (#1,#2){#1-#2}
定义一个宏必须后面跟着(
12,第一个参数以,
12分隔,第二个参数也以)
12分隔。
然而,
\foo({(a,b)},c)
将会被吸收#1
为{(a,b)}
(并且括号将会被移除),并且#2
为c
。
对于您来说,只有平衡的牙套才能让您回家。
答案2
我不会使用\scantokens
,甚至"
根本不会扫描参数,而是在一个组中设置适当的 catcodes 并让它"
(\endgroup
也适用于 Knuth TeX)。
\def\setverb{\def\do##1{\catcode`##1=12}\dospecials}
\catcode`\"=\active
\def"{\begingroup\setverb\tt\let"=\endgroup}
hello "{}%~&^_$#\" world
\bye
如果您想将其放入盒子中,请使用某种两阶段方法。
\def\setverb{\def\do##1{\catcode`##1=12}\dospecials}
\catcode`\"=\active
\def"{\begingroup\setverb\tt\doverb}
\def\doverb#1"{\hbox{#1}\endgroup}
hello "{}%~&^_$#\" world
\bye
Knuth 在 中使用了类似的东西manmac.tex
。
\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}
\catcode`\|=\active
{\obeylines \gdef|{\ttverbatim \spaceskip\ttglue \let^^M=\ \let|=\endgroup}}