假设我们有以下简短的文档
\documentclass{article}
\def\foo#1{\if#1XX\else not X\fi}
\edef\bar#1{\if#1XX\else not X\fi}
\begin{document}
foo: X = \foo{X}, Y = \foo{Y}
bar: X = \bar{X}, Y = \bar{Y}
\end{document}
结果是
foo:X = X,Y = 非 X
bar:X = 非 X,Y = 非 X
第一种情况很容易理解,的扩展\foo
发生在调用宏时,#1
被X
或替换Y
,并且\if
用这两个字符中的任一个执行 。
不太清楚的是 的结果\bar
。我理解 的扩展\if
发生在定义宏时,因此 的具体值#1
尚不可用;TeX 在扩展的替换文本中为参数留下了“空洞”,以便在实际调用宏时稍后填充。但要正确扩展\if
,一些#1
需要的值。
参数似乎不能留空,否则\bar
不应该给出not X
,因为\if XX
总是为真。它们似乎也没有被\relax
编辑,因为
\edef\baz#1{\ifx#1\relax yes\else no\fi}
总是给予no
。
那么定义的时候参数采用的是什么值呢?
答案1
当 TeX 执行\edef<macro><parameter text>{
1 <replacement text>}
2<macro>
时,它会将替换文本和{
1放在一边,然后进行完全扩展,<replacement text>
直到找到匹配的}
2。最后它执行
\def<macro><parameter text>{<full expansion of the replacement text>}
的完整展开\if#1XX\else not X\fi
是not X
,因为#
和1
是不同的字符标记(按字符代码)。
因此你的\edef
变得和
\def\bar#1{not X}
再举一个例子,
\edef\rightbracestring{\string}}
是完全合法的,即使它看起来括号不匹配,因为在进行扩展时,遇到的第一个括号}
已经被标记为}
12。这证明 TeX 不会先吸收整个<replacement text>
,而是像在正常情况下一样执行扩展,不同之处在于匹配的}
2会停止该过程并恢复赋值。
答案2
我想说的是,它#
与1
hance 进行比较,总是选择错误的分支。(比较第二个测试,它 #
与正确的分支进行比较#
并选择正确的分支)
\edef\bar#1{\if#1#1 (TRUE)\else #1 (FALSE)\fi}
\show\bar
\edef\bar#1{\if##1 (TRUE)\else (FALSE)\fi}
\show\bar
\bye
给予
> \bar=macro:
#1->#1 (FALSE).
l.3 \show\bar
> \bar=macro:
#1->1 (TRUE).
l.8 \show\bar