![前面带有重复井号(例如 ##1 或 ###1)的宏参数如何解析?](https://linux22.com/image/407738/%E5%89%8D%E9%9D%A2%E5%B8%A6%E6%9C%89%E9%87%8D%E5%A4%8D%E4%BA%95%E5%8F%B7%EF%BC%88%E4%BE%8B%E5%A6%82%20%23%231%20%E6%88%96%20%23%23%231%EF%BC%89%E7%9A%84%E5%AE%8F%E5%8F%82%E6%95%B0%E5%A6%82%E4%BD%95%E8%A7%A3%E6%9E%90%EF%BC%9F.png)
假设我们有以下 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 将替换#
我与我第个参数;在第二种情况下,它只会提供一个#
。这正是上面这种情况: 的第一个(也是唯一的)参数\macrohell
是1
,因此扩展会以上面显示的形式提供替换文本。
在第二种情况下,结果在语法上可能正确或错误,具体取决于上下文;如果你这样做
\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 在参数中找到它时,它会在内部将其加倍宏然后减少##
到#
在扩展过程中,它会提供先前吸收的令牌。