宏的参数行为不符合预期

宏的参数行为不符合预期

我正在尝试用逗号分隔的参数替换宏。

下面的代码可以正常工作:

\documentclass{article}

\usepackage{listings}

\lstset{
    literate={->}{\texttt{->}}{2}
}

\begin{document}
\begin{lstlisting}
    Example
\end{lstlisting}
\end{document}

由于\newcommand只是生成一个将被替换的宏,我希望下面的代码也能正常工作。

\documentclass{article}

\usepackage{listings}

\newcommand{\somemacro}{{->}{\texttt{->}}{2}}

\lstset{
    literate=\somemacro
}

\begin{document}
\begin{lstlisting}
    Example
\end{lstlisting}
\end{document}

但它会导致多个错误。

那么,我的假设到底错在哪里,\newcommand以及如何正确定义可以用作参数的宏?

答案1

这归结为扩展是一个问题。考虑一个稍微简单一点的类似示例:

\documentclass{article}

\newcommand{\someothermacro}[2]{.#1.#2.}
\newcommand{\someargument}{{first}{second}}

\begin{document}
\someothermacro\someargument
\end{document}

有人会认为调用\someothermacro\someargument类似于\someothermacro{first}{second}。直观上看,是的,但 TeX 会盲目地抓取参数(实际上是标记)。由于\someothermacro需要 2 个参数,它会抓取\someargument第一个参数并将\end(从 开始)作为\end{document}第二个参数,然后扩展为.{first}{second}.\end.而不是.first.second.。由于\end没有与其开头(document在本例中)相对应的适当环境名称,因此它会失败,并指出\begin{document}由 结束\end{.}

你可以使用以下方法规避这个问题

\expandafter\someothermacro\someargument

这相当简单。但是,在您的设置中,扩展必须以不同的方式进行。更具体地说,使用\begingroup\edef\x{\endgroup ...}\x是最简单的。

如果希望样式设置可见,可以使用以下扩展形式:

\usepackage{listings}

\newcommand{\somemacro}{{->}{\noexpand\texttt{->}}{2}}

\begingroup\edef\x{\endgroup\noexpand
\lstset{
  literate=\somemacro
}}\x

“扩展代码”围绕着您的\lstset构造,并要求任何敏感内容(不需要扩展的内容)以 为前缀\noexpand

定义一个style使用方法可能会更好\lstdefinestyle{<style>}{<key value list>},这样可以隐藏一些细节,然后直接使用

\lstset{
  style=<style>,
  % other settings
}

在您的主文档中。

相关内容