宏的标记参数是怎样的?

宏的标记参数是怎样的?

在以下 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)}(并且括号将会被移除),并且#2c

对于您来说,只有平衡的牙套才能让您回家。

答案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}}

相关内容