1 概念
一直对TeX中“active character”这个概念熟视无睹,也许对于初学者真的没太大意义,但是编写宏的过程中,active character却担当重任。 所谓的active character是指TeX将单个字符作为控制序列来看待,因此这个字符就不再是一个普通的字符,而是“活动的”,即可以执行的控制序列,其catcode为13(\active )。每次TeX遇到这个active character时,都会执行这个active character所对应的命令序列。因此,定义一个active character分为两个步骤:第一,设置这个字符的catcode为\active (13);第二,定义这个active character的命令序列。TeX默认只定义了一个active character即众所周知的`~` ,是一个不可断行的空格,其定义为:\catcode`\~=\active \def~{\penalty10000\ }我们可以将任意字符定义为active character,比如下面的例子[1]:
\catcode`\z=\active \def z{Yawn, I’m tired} xyz%输出:xyYawn, I’m tired注意到,字母z定义为active character后便成为一个命令了,因此下面的定义:
\def z{Yawnz, I’m tired}将成为一个无限循环而导致TeX异常退出。因此,将普通字母定义为active character是有风险的,一般情况下不建议这样做。另外,以上的定义也可以写为:
\catcode`\z=\active \defz{Yawn, I’m tired}z现在是一个active character了,因此TeX将z解释为一个命令,\def 和z连在一起就是可以的。 active character前面不能使用\来表示控制序列,事实上,`\~` 和`~`具有截然不同的含义:`\~` 打印出字符`~` ,而`~` 打印出一个不可断行的空格。
2 实战
比如,下划线`_`在TeX中是解释为数学环境的下标的,那么如何输入一个字符`_`呢?可以将`_`重新定义为active character:\catcode`\_=\active \def_{\_}定义active character需要相当谨慎,比如上例,一般情况下要将此定义限制在一个分组内,以免和常见的`_` (数学下标)定义冲突。 下面分析一下\obeylines 的实现思路[2, p174]。\obeylines 只是简单的将输入的^^M (回车符)转换为\par 即可,因此一个很容易想到的思路是如下定义并使用\obeylines :
\def\obeylines{\catcode`\^^M=\active \def^^M{\par}} \obeylines{ first line second line }可是当执行时,TeX会抱怨:
Runaway definition? ->\catcode `\^^M=\active \def \obeylines { first line second line } ! File ended while scanning definition of \obeylines. <inserted text> }也就是说,TeX发现\obeylines 的定义不对(Runaway definition)。仔细分析一下obeylines的定义会发现,尽管定义的第一句是\catcode`\^^M=\active ,但是实际上这是在obeylines的定义中,只有执行obeylines时才会真正执行(展开),在定义时是不会展开的,即当TeX读到这一句时,并不会设置^^M 的catcode为13!因此当TeX接着往下解析的时候,问题出现了:\def^^M… ,当读到^^M 时,TeX解读为一个回车符,忽略掉^^M 后面的内容直接跳到到下一行,导致了obeylines的定义出错—没有匹配的右大括号。 是否可以在定义obeylines之前将^^M 定义为普通字符呢?像下面这样:
\catcode`\^^M=12 \def\obeylines{\catcode`\^^M=\active \def^^M{\par}} \obeylines{ first line second line }出错信息为:
! Missing control sequence inserted. <inserted text> \inaccessible <to be read again> ^^M \obeylines ->\catcode `\^^M=\active \def ^^M {\par } l.3 \obeylines {也就是说,在解释\def^^M 时报错:此时^^M 为一个catcode为12的普通字符,显然\def^^M 的形式是不允许的,只能将^^M 的catcode设置为13才能这样使用,因此正确的定义为:
{\catcode`\^^M=\active \gdef\obeylines{\catcode`\^^M=\active \def^^M{\par}} } \obeylines{ first line second line }此处,为了将^^M 的catcode更改的影响减小最小,将obeylines的定义放到一个分组中,因此同时需要将obeylines的定义修改为\gdef ,使之成为一个全局的定义。
发表评论 取消回复