xparse 如何处理嵌套的分隔参数?

xparse 如何处理嵌套的分隔参数?

这个答案egreg 提到包r中的参数类型xparse处理嵌套的分隔参数,如这个小例子所示:

\documentclass{article}
\usepackage{xparse}

\NewDocumentCommand\foo{r()}{(#1)}

\begin{document}
\[ \foo(x\cdot\foo(y+\foo(z))\cdot w) \]
\end{document}

不过,软件包文档并未解释如何实现这一点。我尝试查看代码,但它太长了,对于不熟悉 LaTeX3 的人来说几乎无法阅读。

正如上面链接的问题中讨论的那样,TeX 的默认分隔参数不能用于此。我能想到的唯一方法是通过 解析整个以下文本\futurelet,从而以某种方式确保宏正确扩展,直到找到最终的结束分隔符。有人能解释一下如何xparse实际实现这一点吗?

答案1

在 LaTeX2e 使用的基本方法中,人们寻找一个可选的[使用\futurelet(包含在\@ifnextcharLaTeX 中),如果找到则使用分隔宏

\def\foo@aux[#1]{% Do stuff

对于 LaTex2e 来说,就是这样,但对于xparse我们则检查#1它是否包含[。如果包含,那么]我们抓取的就不是与(现已删除的)匹配的正确匹配[。相反,我们必须继续#1寻找正确的匹配。例如,使用

\DeclareDocumentCommand\foo{o}{...}
\foo[[AAA]]]

初始抓取将匹配[[AA],其中包含一个[,因此我们必须再找到一个]。需要注意的一点是

\foo[[a][b]]

需要多次循环才能找到所有内容。

中的代码xparse使用一些以主命令命名的宏来实现这一点。这样做的目的是,如果缺少],则产生的 TeX 错误会将用户指向文档命令,而不是一些奇怪的内部命令。结果是代码中的设置略微复杂一些。(还有一些 Bruno 性能技巧和保留括号的代码。)


对于可扩展抓取,我们不能使用\futurelet,但对于所有前瞻来说都是如此:相反,我们抓取一个参数并查看它是否是与所需前瞻相匹配的单个标记。一切都必须提前设置(不能动态定义),因此还有更多工作……但基本思想保持不变。

相关内容