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/

点赞(1)

评论列表 共有 0 条评论

暂无评论
立即
投稿

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部