考虑以下 MWE:
\documentclass[12pt]{article}
\begin{document}
\def\aaa{something}
\typeout{=1==\aaa==}
\typeout{=1==\meaning\aaa==}
\typeout{}
\def\bbb{else \aaa, else}
\typeout{=2==\bbb==}
\typeout{=2==\meaning\bbb==}
\typeout{}
\def\ccc{third \bbb, level}
\typeout{=3==\ccc==}
\typeout{=3==\meaning\ccc==}
\typeout{}
\end{document}
它向终端输出以下内容:
=1==something==
=1==macro:->something==
=2==else something, else==
=2==macro:->else \aaa , else==
=3==third else something, else, level==
=3==macro:->third \bbb , level==
因此,我会考虑(在这种情况下)\meaning
提供宏的未扩展内容(即“空”扩展级别);而\typeout
进行“无限”扩展(直到没有更多标记需要扩展)。我注意到\typeout
调用\write
:
$ texdef -t latex -c book -p titletoc typeout -f
\typeout is defined by (La)TeX.
\typeout:
macro:#1->\begingroup \set@display@protect \immediate \write \@unused {#1}\endgroup
...因此这种“无限”扩张行为可能是由于\write
。
我最终想要的是一个可扩展的函数,它将接受数字的“扩展级别”,并且可以像这样调用:
# just a fake interface definition for testing
\def\expandlevel#1\nil#2\nil{
---#1---#2--
}
\edef\yyy{\expandlevel0\nil\ccc\nil}
\typeout{\yyy}
...例如:
- 当我调用级别空扩展时 - 我输入时得到的是未扩展的内容(如
\meaning
);伪:* \typeout{==\expandlevel0\nil\ccc\nil==} ==第三 \bbb ,级别==
- 当我调用单次扩展时 - 我得到的是(伪):
* \typeout{==\expandlevel1\nil\ccc\nil==} ==第三否则\aaa,否则,级别==
- 当我要求无限扩展 - 也就是 99 个级别
:)
- 我得到的结果与执行的结果相同\typeout
;伪:* \typeout{==\expandlevel99\nil\ccc\nil==} ==第三其他某事,其他,级别==
不可扩展/受保护的令牌将保留(或显示为\inaccessible
),如\typeout
当前执行的那样。
在缺少像那样的“真正的”可扩展宏的情况下,是否有任何技巧可以诱导其\typeout
以类似的方式运行(如果可能的话)?
答案1
这与 无关,\typeout
除非它的参数由于 而完全展开\write
,如您所指出的。您可以对 提出同样的问题\edef
,答案是使用\expandafter
、\noexpand
和的足够复杂的组合\unexpanded
来强制每个标记展开所需的次数。例如:
*\def\a{\b} \def\b{\c} \def\c{c}
*\edef\x{\noexpand \a}
*\show\x
> \x=macro:
->\a .
<*> \show\x
?
*\edef\x{\expandafter\noexpand \a}
*\show\x
> \x=macro:
->\b .
<*> \show\x
?
*\edef\x{\expandafter\expandafter\expandafter\noexpand \a}
*\show\x
> \x=macro:
->\c .
<*> \show\x
?
*\edef\x{%
\expandafter\expandafter\expandafter\expandafter
\expandafter\expandafter\expandafter\noexpand\x}
*\show\x
> \x=macro:
->c.
<*> \show\x
s的数量\expandafter
呈指数增长。如何编写单身的可扩展命令,扩展所需的次数被寻址这里。请注意,那里给出的答案仍然只是扩展一标记,因此您不能将其应用于整个文本。可以使用\unexpanded
(\noexpand
表示许多标记)和标记列表寄存器(在内部\edef
,扩展到其内容,然后使结果暂时不扩展)来玩弄技巧,以实现类似的效果。
您可能想知道,如果允许对整个文本进行零次扩展和无限次扩展,为什么不允许一次或多次扩展?答案是,事实上,“无限”扩展是逐个标记进行的,没有扩展“整个文本”的概念。要进行零次扩展,TeX 只需转储给定的标记列表;\meaning
显然进行一次扩展的方式是它实际上更改了\catcode
输出的 s,使其不再可扩展:您看到的那些不是真正的宏。如果您将 in\scantokens
与 change 结合使用,您可以自己实现相同的效果\catcode
……除了\catcode
不可扩展,因此您无法在\edef
或中执行此操作。或者更确切地说,如果您这样做,您只会在结果中\write
看到字符串“ ”。\catcode
无论如何,如果您想将“整个文本”扩展一定次数,则可能意味着以下三件事之一:
扩展第一个标记,然后扩展结果的第一个标记,依此类推,多次。
扩展第一个可扩展标记,然后扩展结果的第一个可扩展标记,依此类推,多次。
展开第一个可扩展标记;然后,在展开的文本中,以相同的方式展开所有内容 (n - 1) 次。完成后,移动到第一个“未触及”标记,并以此方式继续到文本末尾。(因此,扩展到整个文本的某个“深度”。)
规则 1 和 2 有不同的结果:
\def\a{a}
a\a
其中,扩展“once”会\a
根据规则给出“a”或“aa”。规则 1 相对容易使用\multiexpandafter
(来自另一个问题)和来实现。如果不将和嵌入到所有宏中\unexpanded
,规则 2 可能就无法实现。规则 3 可能是图灵完备的。\expandafter
\noexpand