1, p219]:
\def\length#1{{\count0=0 \getlength#1\end \number\count0}}
\def\getlength#1{\ifx#1\end \let\next=\relax
\else\advance\count0 by1 \let\next=\getlength\fi \next}
首先从代码的执行过程体会一下整体思路:
*\tracingmacros=1
*\tracingonline=1
*\def\length#1{{\count0=0 \getlength#1\end \number\count0}}
*\def\getlength#1{\ifx#1\end \let\next=\relax \else\advance\count0 by1 \let\next=\getlength\fi \next}
*\length{name}
\length #1->{\count 0=0 \getlength #1\end \number \count 0}
#1<-name
\getlength #1->\ifx #1\end \let \next =\relax \else \advance \count 0 by1 \let
\next =\getlength \fi \next
#1<-n
\next #1->\ifx #1\end \let \next =\relax \else \advance \count 0 by1 \let \next
=\getlength \fi \next
#1<-a
\next #1->\ifx #1\end \let \next =\relax \else \advance \count 0 by1 \let \next
=\getlength \fi \next
#1<-m
\next #1->\ifx #1\end \let \next =\relax \else \advance \count 0 by1 \let \next
=\getlength \fi \next
#1<-e
\next #1->\ifx #1\end \let \next =\relax \else \advance \count 0 by1 \let \next
=\getlength \fi \next
#1<-\end
仔细解读这段代码,我们可以学到很多。首先看一下\length的定义,借用count0来统计字符串的长度,这很容易理解。但是要注意\getlength#1\end的调用,这是本段代码的关键点之一。getlength宏的参数为#1\end,比如字符串为”name”,则getlength的参数为:name\end,即5个token,其中的\end是一个宏,但是由于参数中的宏不会展开,因此这里的\end不需要定义,我们只是拿来表示字符串的结束(getlength参数的结束)而已。\getlength#1\end会首先将#1中的第一个字母作为参数,这里即为将n作为getlength的参数。处理完第一个字母,下一步会处理第二个字母,直到遇到\end为止。
如果\getlength name\end只执行一次,那么会输出\getlength n的结果,nme\end会原样输出(实际上,由于\end没有定义,如果\getlength name\end只执行一次,会报告\end没有定义的错误)。因此,\getlength宏巧妙的实现了一个看起来像是递归的过程:
  • 首先将\getlength的参数和\end比较,如果相同则表示字符串处理完毕,将\next设置为\relax。注意到,整个\getlength宏的可执行部分只有\next宏。
  • 如果\getlength的参数不是\end,则将\count0增加1,并且设置\next宏为\getlength:这样就实现了递归调用,因为\getlength的可执行代码只有\next,而\next是重新执行\getlength宏,即读入token序列的下一个字母作为参数继续处理。
 
注意到,\getlength name\end的执行过程是,TeX首先将这个命令及其参数切分为token序列:\getlength、␣、n、a、m、e、\end,然后从这个token序列中依次读出token进行处理。

点赞(1)

评论列表 共有 0 条评论

暂无评论
立即
投稿

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部