有没有办法检测下一个赋值是否是\global
、\long
、\outer
或\protected
?也就是说,是否可以编写一个命令\detectmodifiers
,使得代码如下
\def\otherdef{%
\detectmodifiers
preprocessing
\ifglobal\expandafter\global\fi
\iflong\expandafter\long\fi
\ifouter\expandafter\outer\fi
\ifprotected\expandafter\protected\fi
\def
}
做正确的事情(定义一个\otherdef
与 操作相同的命令\def
,但首先进行一些预处理)?
答案1
您可以在宏的开头创建一个虚拟宏,它将受到上述任何修饰符的影响。然后,您可以测试修饰符以构建 -switches 。您可以在包含、和修饰符的虚拟宏\def
上使用,这些修饰符可以提取出来并再次使用 转换为宏。一个挑战是:您需要在组中进行分配,并检查组后它是否仍然相同。\detectmodifiers
if
\meaning
\outer
\long
\protected
\scantokens
\global
您应该使用您已有的 -tree ,if
而是定义一个宏\themodifiers
,然后将其放在前面\def
:
\def\themodifiers{\protected\global}
...。\themodifiers\def...
这里有一些概念验证代码。我记得“修饰符”称为前缀,所以我更改了宏名称。前缀存储在宏中\theprefixes
,可以在前面使用\def
。\global
但是前缀很特殊,不能像这样读取。我尝试\dummy
在组内定义宏并使用,\global\let\gdummy\dummy
以便我可以测试组结束后两者是否仍然相同。问题是:在:-(之前不允许使用\begingroup
或{
\def\dummy
您应该更改一些宏的名称以防止名称冲突。
\documentclass{article}
\makeatletter
\def\macroother{macro}
\@onelevel@sanitize\macroother
\makeatother
\expandafter
\def\expandafter\returnprefixes\expandafter#\expandafter1\macroother#2\relax{%
\scantokens{\def\theprefixes{#1}}%
}
\def\detectprefixes{%
\def\dummy{}%
\expandafter\returnprefixes\meaning\dummy\relax
}
\def\otherdef{%
\detectprefixes
% other code
\theprefixes\def
}
\global\long\outer\protected\otherdef\mymacro{mystuff}
\show\mymacro
\begin{document}
\end{document}
答案2
您可以通过构建一系列条件来检测差异。
\def\Z{This}
\global\def\X{This}
\outer\def\Y{This}
\ifx\Z\Y true \else false \fi
\ifx
仅当两个标记都是宏,并且它们在\long
和方面具有相同的状态\outer
,并且它们都具有相同的参数和“顶级”扩展时, 才会返回 true。根据条件,您可以使用 构建命令csname
。
答案3
想法:不要编写一个命令来做一些有趣的事情来检测\global
之前是否有另一个前缀,而是进行修改\global
等以提前查看并使用协议来通知相应的宏,它将自己视为前缀。
以下不是工作代码,旨在提出一种方法
\let\ea\expandafter
\makeatletter
\let\@global\global
\let\@long\long
% etc
\let\@def\def
\let\@edef\edef
% etc
\let\@let\let
\@def\@prefixables{%
\def%
\edef%
% etc
\let%
}
\@def\newprefixable#1{
\@def\prefixable@def@reset{
\ea\@def\csname prefixable@#1@global\endcsname{0}
\ea\@def\csname prefixable@#1@long\endcsname{0}
% etc
}
\@def\prefixable@def@reset
\@edef\@prefixables{%
\expandonce{\@prefixables}%
\expandonce{\csname#1\endcsname}%
}
}
\def\global{%
% Pseudocode
If the next token is in \@prefixables:
\@def\prefixable@<the token>@global{1}
End if
}
\newprefixable{def}
% Showing only treatment of \global
\@def\def#1#2{%
\if\prefixable@def@global1%
\@global\@def#1#2%
\else%
\@def#1#2%
\fi%
\prefixable@def@reset%
}
\newprefixable\otherdef % The macro in the question
\makeatother
其他注意事项:如果命令前有多个前缀,则需要工作,例如如果\long\global\otherdef
发生类似情况。上面的方法无法处理这种情况