关于宏匹配的一个问题

关于宏匹配的一个问题

考虑以下宏定义和后续调用:

\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

#2TeX在看到第一个空格( 之后的空格)后寻找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”,第二个参数是“*”。

相关内容