每次我尝试读取或编写一些宏时,我总是被\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
为了兼容性,我们可能会限制新的语法仅在定义宏和调用宏,以及一些赋值等操作中生效。
我的问题如下:
- 这个新语法有什么缺点吗?
- 如果我想将这个新语法实现为宏,我可以参考哪些现有的宏?
- 如果有人在 TeX 引擎中实现这个新语法,会
pdftex
接受xetex
这个luatex
补丁和新原语吗?
答案1
您需要将 L3 的选择:
和_
语法与功能分开。
下面使用比 xparser 小得多的扩展库(仅 7 行代码)但它实现了n
(无扩展)x
(完全\edef
扩展)和o
(扩展一次\expandafter
)扩展类型。
不需要定义带有:nnx
后缀的变体宏名,只需在使用前明确添加前缀,\use
指定如何扩展参数的命令(这也是 xparse 语法的基础)。
请注意,在调用之前o
,使用\argb
仅扩展一次,但使用 则完全扩展为。bbb {\arga}
\cmd
x
\argb
bbb {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}
正如评论中指出的那样,根本不清楚您是否打算让您的()
语法与之相对应o
,x
但无论哪种方式,在宏层处理确实比改变引擎扩展逻辑更好。
答案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
到已知变体列表中即可。