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 ,使之成为一个全局的定义。
引用
1“Defining characters as macros“, UKTUG, 190.
2Levy, S. and Foata, D. and Seroul, R.,
A Beginner's Book of TEX (Springer New York, 2012).
选自:
http://softlab.sdut.edu.cn/blog/subaochen/2017/08/active-character%E9%87%8A%E7%96%91/
发表评论 取消回复