考虑以下宏定义和后续调用:
\def\foo #1 #2 \bar{stuff with #1 and #2 goes here}
\foo arg1 arg2 \bar
\bar 只是充当 \foo 的终止符。这一切都按预期工作,#1 得到“arg1”,#2 得到“arg2”。但现在考虑一下:
\def\foo #1 #2\bar{stuff with #1 and #2 goes here}
\foo arg1 arg2 \bar
这里我删除了宏定义中 \bar 之前的空格,但在宏调用中保留了它。由于 TeX 通常非常严格,我预计宏调用不会再触发。 的调用\foo<SPACE>arg1<SPACE>arg2\bar
自然在技术上与模板不匹配\foo<SPACE>#1<SPACE>#2<SPACE>\bar
,但 TeX 似乎并不在意。
这里究竟应用了什么规则?如果我在 \bar 前放置两个空格,第一个定义会放入arg2<SPACE>
#2 中吗?第二个定义会失败吗?我现在就要去尝试一下,显然可以通过实验推断出这条规则的工作原理,但如果有的话,看到 TeX 如何将宏调用与调用相匹配的详细解释会很好。
只是想寻求想法和潜在的指导。
答案1
你想区分“TeX 对参数文本很严格”和“TeX 关心参数文本中的空格”。后者是正确的,但具有误导性:TeX 关心一切在参数文本中,空格就是一个隐蔽的例子(控制序列之后除外)。如果你在宏参数中放入空格,那么每次展开宏时都会寻找该空格。另一方面,如果你这样做不是在参数中放入一个空格,并且在扩展时仍然发现一个空格,如果它符合整个参数规范,它就会被解释为参数之一。
因此在你的例子中,
\def\foo #1 #2\bar{...}
\foo arg1 arg2 \bar
#2
TeX在看到第一个空格( 之后的空格)后寻找arg1
,并将其视为直到 的所有内容\bar
,包括您认为它关心的空间。它并不关心,因为该空间从未出现在 的定义中,\foo
因此它只是为此目的而设置的一些标记。
答案2
使用你的第一个定义
\def\foo⍽#1⍽#2⍽\bar{stuff⍽with⍽#1⍽and⍽#2⍽goes⍽here}
是<parameter text>
(用 • 分隔标记,<space>
表示空格标记)
#1
•<space>
•#2
•<space>
•\bar
和电话
\foo⍽arg1⍽arg2⍽\bar
结果是#1<-arg1
和#2<-arg2
。由于 TeX 宏扩展的工作方式,这两个<space>
标记被一起删除\bar
。 的开头没有空格标记,<parameter text>
因为控制序列后的空格会被忽略。 扩展后的最终标记列表\foo
将是
stuff<space>with<space>arg1<space>and<space>arg2<space>goes<space>here
呼吁
\foo⍽arg1⍽arg2⍽⍽\bar
会产生完全相同的结果,因为在标记化过程中,连续的空格被规范化为单个空格标记。
第二个定义是
\def⍽#1⍽#2\bar{stuff⍽with⍽#1⍽and⍽#2⍽goes here}
是<parameter text>
(同样用 • 来分隔标记)
#1
•<space>
•#2
•\bar
和电话
\foo⍽arg1⍽arg2⍽\bar
将导致#1<-arg1
和#2<-arg2<space>
(第二个参数后面有一个空格),并且结果标记列表将是
stuff<space>with<space>arg1<space>and<space>arg2<space><space>goes<space>here
请注意,在这种情况下将会有两个空格标记,因为标记化已经发生。
答案3
定义
\def\foo #1 #2\bar{stuff with ``#1'' and ``#2'' goes here}
仍然匹配
\foo arg1 arg2 \bar
#2
简单地被替换为(请注意下面输出中和arg2␣
之间的水平空格)。arg2
”
的替换#1
是直到下一个空格为止的所有内容,但#2
只是直到下一个\bar
可能的内容为止的所有内容。
对于第一个定义\foo
\def\foo #1 #2 \bar{stuff with ``#1'' and ``#2'' goes here}
并使用
\foo arg1 arg2 arg3? \bar
类似情况适用:#1
是到下一个空格为止的所有内容(但不包括它);#2
将是到下一个标记序列为止的所有内容␣\bar
,并且不是“一切都将取决于下一个空间,然后希望\bar
将会随之而来”。
代码
\def\foo #1 #2 \bar{stuff with ``#1'' and ``#2'' goes here}
\foo arg1 arg2 \bar \par \foo arg1 arg2 arg3? \bar \par\bigskip
\def\foo #1 #2\bar{stuff with ``#1'' and ``#2'' goes here}
\foo arg1 arg2 \bar \par \foo arg1 arg2 arg3? \bar
\bye
输出
答案4
我假设你已经定义了 \foo
\def \foo #1 #2 \bar{stuff with #1 and #2 goes here}.
空格是 TeX 中的一个难题。一个规则是控制字(即所有字母的控制序列)后面的空格会被忽略。另一个规则是两个或多个连续的空格(大多数情况下)被视为一个空格。为了清楚起见,让我们重新定义 \foo 为
\def \foo #1*#2**\bar{stuff with #1 and #2 goes here}
要使用 \foo,它后面必须跟一个字符串,其中“*”表示第一个参数的结束,而“*\bar”表示第二个参数的结束。因此,当 TeX 读取
\foo arg1*arg2**\bar
\foo 的第一个参数将是“arg1”(不带引号),第二个参数是“arg2*”。如果我们定义
\def \goo #1*#2\bar{stuff with #1 and #2 goes here}
第二个参数以 \bar 结尾。因此,当 TeX 读取
\goo arg1*arg2**\bar
\goo 的第一个参数将是“arg1”,第二个参数将是“arg2**”。请注意,当参数以“{”开头并以“}”结尾时,这些括号将被删除。因此,当 TeX 读取
\goo {arg1}*{arg}2**\bar
\goo 的第一个参数是“arg1”,第二个参数是“{arg}2**”。另一个例子:当 TeX 读取
\goo {arg1*}{arg}2**\bar
\goo 的第一个参数是“{arg1*}{arg}2”,第二个参数是“*”。