理解定义的问题

理解定义的问题

我定义了一个堆栈结构(我在 LaTeXcurrfile包中找到了一个例子,并根据我的需要进行了调整):

\def\MB@modulestack{}
\def\MB@modulestack@push#1{\xdef\MB@modulestack{{#1}\MB@modulestack}}
\def\MB@modulestack@top{\expandafter\MB@modulestack@top@eat\MB@modulestack\relax\relax}
\def\MB@modulestack@top@eat#1#2\relax{#1}
\def\MB@modulestack@pop{\expandafter\MB@modulestack@pop@eat\MB@modulestack\relax\relax}
\def\MB@modulestack@pop@eat#1#2\relax{\gdef\MB@modulestack{#2}}

我理解它的工作原理,尤其是那些\relax。我在那里保存了一个 4 元组参数:

\def\MB@modulestack@push{{a}{b}{c}{d}}
\def\MB@modulestack@push{{1}{2}{3}{4}}

现在,为了从堆栈顶部解析这样的 4 元组,我想要使用以下代码:

\def\MB@modulestack@topitemparse@eat#1#2#3#4{... here I use #1, #2, #3, #4 ...}
\def\MB@modulestack@topitemparse{
  \expandafter\MB@modulestack@topitemparse@eat\MB@modulestack@top
}

...但是没用。在试验过程中我发现必须用另一种方法来实现:

\def\MB@modulestack@topitemparse@eat#1#2#3#4#5\relax{... here I use  #1, #2, #3, #4 ...}
\def\MB@modulestack@topitemparse{
  \edef\MB@modulestack@topitem{\MB@modulestack@top}
  \expandafter\MB@modulestack@topitemparse@eat\MB@modulestack@topitem\relax\relax
}

为什么第一个不起作用而第二个起作用?为什么我需要在宏中获取#5和?为什么我需要将堆栈顶部读入变量,而不是直接将其传递给宏?\relax@eat@eat

答案1

这是宏扩展语言和基于函数的系统之间的典型区别。当你这样做时

\def\MB@modulestack@topitemparse{
  \expandafter\MB@modulestack@topitemparse@eat\MB@modulestack@top
}

\MB@modulestack@top只需要扩展一次,这样 TeX 就可以读取

\MB@modulestack@topitemparse@eat\expandafter\MB@modulestack@top@eat
  \MB@modulestack\relax\relax

这并没有达到你想要的效果。你可以计算出实现这个功能所需的确切扩展次数;在本例中,你需要:

\def\MB@modulestack@topitemparse{
  \expandafter\expandafter\expandafter
    \expandafter\expandafter\expandafter
    \expandafter\MB@modulestack@topitemparse@eat\MB@modulestack@top
}

它将根据需要扩展所有内容。然而,这显然很尴尬,这就是它的作用\edef所在,因为它总是完全扩展内容。唯一的危险是

\edef\MB@modulestack@topitem{\MB@modulestack@top}

如果堆栈项本身可扩展,则可能不是您所期望的。

答案2

\expandafterJoseph 已经解释了为什么以及它是如何工作的。这里有一个不用太多东西的替代方法:

除了将@top宏用作参数的一部分之外,您还可以将其定义为使用堆栈顶部“调用”解析宏:

\def\MB@modulestack@top{\expandafter\MB@modulestack@top@call\MB@modulestack\relax}
\def\MB@modulestack@top@call#1#2\relax#3{#3#1}% here #1 are the four {.}{.}{.}{.} pushed on the stack

解析宏 simple 接收四个参数:

\def\MB@modulestack@topitemparse#1#2#3#4{%
  % do what you want with the four arguments
}

用法:

\MB@modulestack@top\MB@modulestack@topitempars

也可以\MB@modulestack@topitempars被硬编码到\MB@modulestack@top@call

相关内容