用于替代可怕的 \expandafter 的新原语和语法

用于替代可怕的 \expandafter 的新原语和语法

每次我尝试读取或编写一些宏时,我总是被\expandafter其中的大量 s 所困扰。为什么我们不在 TeX 引擎中添加一些新的原语和语法,使宏的编写和读取更加容易呢?

我的想法是使用()作为新的组开始和结束字符在某些情况下.()的作用类似于{},但当 TeX 在某些上下文中遇到它们时,它首先会像 一样完全扩展它们内部的标记\edef。例如

\expandfirston
\def\cmd(replacement)  % same as \edef\cmd{replacement}
\expandfistoff

另一个例子:

\expandfirston
\def\cmd#1#2{replacement}
\cmd{\arga}{\argb}  % firstly expands \cmd, then \arga and \argb
\cmd(\arga){\argb}  % firstly expands \arga, then \cmd, lastly \argb
\cmd{\arga}(\argb)  % firstly expands \argb, then \cmd, lastly \arga
\cmd(\arga)(\argb)  % firstly expands \arga, then \argb, lastly \cmd
\expandfirstoff

第三个例子:

\expandfirston
\def\cmda#1{replacementa}
\def\cmdb#1{replacementb}
\cmdb(\cmda(\arg))% firstly expands \arg, then \cmda, lastly \cmdb
\expandfirstoff

为了兼容性,我们可能会限制新的语法仅在定义宏和调用宏,以及一些赋值等操作中生效。

我的问题如下:

  1. 这个新语法有什么缺点吗?
  2. 如果我想将这个新语法实现为宏,我可以参考哪些现有的宏?
  3. 如果有人在 TeX 引擎中实现这个新语法,会pdftex接受xetex这个luatex补丁和新原语吗?

答案1

您需要将 L3 的选择:_语法与功能分开。

下面使用比 xparser 小得多的扩展库(仅 7 行代码)但它实现了n(无扩展)x(完全\edef扩展)和o(扩展一次\expandafter)扩展类型。

不需要定义带有:nnx后缀的变体宏名,只需在使用前明确添加前缀,\use指定如何扩展参数的命令(这也是 xparse 语法的基础)。

请注意,在调用之前o,使用\argb仅扩展一次,但使用 则完全扩展为。bbb {\arga}\cmdx\argbbbb {aa}

在此处输入图片描述

\documentclass{article}
\usepackage[T1]{fontenc}

\def\use#1{\xuse#1z}
\def\xuse#1{\csname use#1\endcsname}
\def\usez#1{#1}
\long\def\usen#1z#2#3{\xuse#1z{#2{#3}}}
\long\def\useo#1z#2#3{\expandafter\useohelp\expandafter{#3}{#1}{#2}}
\long\def\useohelp#1#2#3{\xuse#2z{#3{#1}}}
\protected\long\def\usex#1z#2#3{\edef\usetmp{#3}\expandafter\useohelp\expandafter{\usetmp}{#1}{#2}}

\begin{document}



\def\cmd#1#2{{\ttfamily\par\def\a{#1}\#1:\meaning\a \quad\#2:\def\a{#2}\meaning\a\par}}
\def\arga{aa}
\def\argb{bbb {\arga}}



        \cmd{\arga}{\argb}  % normal
\use{nn}\cmd{\arga}{\argb}  % normal
\use{on}\cmd{\arga}{\argb}  % expand #1 once 
\use{no}\cmd{\arga}{\argb}  % expand #2 once
\use{oo}\cmd{\arga}{\argb}  % expand #1 and #2 once
\use{xx}\cmd{\arga}{\argb}  % fully (\edef) expand #1 and #2

\end{document}

正如评论中指出的那样,根本不清楚您是否打算让您的()语法与之相对应ox但无论哪种方式,在宏层处理确实比改变引擎扩展逻辑更好。

答案2

很简单,使用expl3

\input expl3-generic

\def\arga{what}
\def\argb{how}

\ExplSyntaxOn
\cs_new:Npx \zh_cmda: { \arga\argb }

\cs_new:Npn \zh_cmdb:nn #1 #2
 {
  \str_if_eq:nnTF { #1 } { what }
   { \msg_term:n{\#1~is~`what'} }
   { \msg_term:n{\#1~isn't~`what'} }
  \str_if_eq:nnTF { #2 } { how }
   { \msg_term:n{\#2~is~`how'} }
   { \msg_term:n{\#2~isn't~`how'} }
 }
\cs_generate_variant:Nn \zh_cmdb:nn { no }
\cs_generate_variant:Nn \zh_cmdb:nn { on }
\cs_generate_variant:Nn \zh_cmdb:nn { oo }

\msg_term:n
 {
  The ~ replacement ~ text ~ of ~ \exp_not:N \zh_cmda: ~ is ~
  `\token_get_replacement_spec:N \zh_cmda:'
 }
\zh_cmdb:nn { \arga } { \argb }
\zh_cmdb:no { \arga } { \argb }
\zh_cmdb:on { \arga } { \argb }
\zh_cmdb:oo { \arga } { \argb }

\bye

终端会话将显示

*************************************************
* The replacement text of \zh_cmda: is `whathow'
*************************************************
*************************************************
* #1 isn't `what'
*************************************************
*************************************************
* #2 isn't `how'
*************************************************
*************************************************
* #1 isn't `what'
*************************************************
*************************************************
* #2 is `how'
*************************************************
*************************************************
* #1 is `what'
*************************************************
*************************************************
* #2 isn't `how'
*************************************************
*************************************************
* #1 is `what'
*************************************************
*************************************************
* #2 is `how'
*************************************************

请注意,结果符合预期:o使用时参数扩展一次,从而使\str_if_eq:nnTF测试成功。

expl3您需要在代码中使用语法吗?完全不需要!只需定义一个合适的包装器即可。\exp_args_generate:n您可以定义所需的所有变体。

\input expl3-generic

\ExplSyntaxOn

\cs_new:Npn \use #1 { \cs_if_exist_use:cF { exp_args:N#1 } { \ERROR } }
\exp_args_generate:n { nn, on, ee }

\ExplSyntaxOff

\def\cmd#1#2{{\tt\par\def\a{#1}\#1:\meaning\a \quad\#2:\def\a{#2}\meaning\a\par}}
\def\arga{aa}
\def\argb{bbb {\arga}}



        \cmd{\arga}{\argb}  % normal
\use{nn}\cmd{\arga}{\argb}  % normal
\use{on}\cmd{\arga}{\argb}  % expand #1 once 
\use{no}\cmd{\arga}{\argb}  % expand #2 once
\use{oo}\cmd{\arga}{\argb}  % expand #1 and #2 once
\use{xx}\cmd{\arga}{\argb}  % fully (\edef) expand #1 and #2
\use{ee}\cmd{\arga}{\argb}  % fully (\edef) expand #1 and #2

\bye

最后是新的e-type 扩展,它与 -expansion 类似x,但本身完全可扩展。如果未定义变体,则会收到错误消息。当然,这\use{nn}和什么都没有是一样的。

在此处输入图片描述

优点是您可以根据需要为任意数量的参数定义变体。因此,如果\macro有三个参数,您可以使用

\use{noe}\macro{<first>}{<second>}{<third>}

\macro并在实际调用之前完成所需的扩展,只要将其添加noe到已知变体列表中即可。

相关内容