前面带有重复井号(例如 ##1 或 ###1)的宏参数如何解析?

前面带有重复井号(例如 ##1 或 ###1)的宏参数如何解析?

假设我们有以下 LaTeX

\newcommand{\macrohell}[1]{\newcommand{\nested}[#1]{##1}}

\macrohell{1}接着是\nested{2}输出2,我认为这是由于以下原因:首先,\macrohell在所有参数中替换输入#1,因此\macrohell{1}变成\newcommand{\nested}[(1)]{#(1)},然后对其newcommand进行评估,就像您\newcommand{\nested}[1]{#1}直接编写一样,定义命令nested

然后,\nested{2}进行评估,仅呈现其输入2

但是,如果我将命令编辑成如下形式

\newcommand{\macrohell}[1]{\newcommand{\nested}[#1]{##1 ##2 ##3}}

根据之前的逻辑,我预计会出现错误,因为对于允许的输入数量来说参数太多了(在本例中为 1)。

但它并没有给我一个错误,而是

\nested{2}{3}{4}

呈现为2 3 4

所以这让我想到,也许##n意味着我们根据“第 n 级”来解决这个参数,并且不是我们首先#n在顶层进行解析,然后#(#n)在“第二层”进行解析。这个推理正确吗?

答案1

代码

\newcommand{\macrohell}[1]{\newcommand{\nested}[#1]{##1}}
\macrohell{1}

\newcommand{\nested}[1]{#1}

这很简单。在定义主体中,#要求后面跟着一个数字(从 1 到 9)或另一个#。在第一种情况下,TeX 将替换#第个参数;在第二种情况下,它只会提供一个#。这正是上面这种情况: 的第一个(也是唯一的)参数\macrohell1,因此扩展会以上面显示的形式提供替换文本。

在第二种情况下,结果在语法上可能正确或错误,具体取决于上下文;如果你这样做

\newcommand{\foo}{##1}

扩展时会出错\foo,因为通常#1是不合法的,除非在宏定义期间在替换文本中找到。

因此,这###1通常是错误的,但在某些情况下可能会出现这种情况:

\def\funny#1#2{\vbox{\halign{\hfil###1\hfil\cr#2\crcr}}}

是合法代码。以下纯 TeX 文件证实了这一点:

\def\funny#1#2{\vtop{\halign{\hfil###1\hfil\cr#2\crcr}}}

1) \funny{:}{abc\cr defghi}
\qquad
2) \funny{\hfill}{abc\cr defghi}

\bye

但我有点作弊:第一次调用将导致以下扩展

\vtop{\halign{\hfil#:\hfil\cr abc\cr defghi\crcr}}

这确实是合法的,但###1由两个单独的“对象”组成:第一个##,它将#在扩展时交付,而#1它将交付第一个参数。欺骗是因为\halign 想要单个#表示比对模板中的可变部分,其前面和后面是(可选的)固定部分。


也许这会增加混乱,但你可以尝试

\newcommand{\hellofamacro}[2]{\def#1##1{#2}}

\hellofamacro{\foo}{--#1--}

\foo{x}

这将产生 –x–。

会发生什么?定义根据上述规则存储;调用\hellofamacro将导致

\def\foo#1{--#1--}

诀窍在于,#当 TeX 在参数中找到它时,它会在内部将其加倍然后减少###在扩展过程中,它会提供先前吸收的令牌。

相关内容