以下宏在 TikZ 源代码中定义(具体在 中<tex installation directory>/tex/generic/pgf/frontendlayer/tikz/tikz.code.tex
)。
\def\tikz@scan@next@command{%
\ifx\tikz@collected@onpath\pgfutil@empty%
\else%
\tikz@invoke@collected@onpath%
\fi%
\afterassignment\tikz@handle\let\pgf@let@token=%
}
\afterassignment
在这种情况下的目的是什么?
我问的不是\afterassignmet
一般问题,但我当然不介意重述一下这个构造的一般工作原理。但我特别感兴趣的是,考虑到宏应该做什么,它在上述宏中的含义是什么。类似的用法在 TikZ 源代码中出现过很多次。我希望,如果我理解了上面的例子,我就能一劳永逸地理解它。
答案1
它类似于,\futurelet
因为它\let
是命令名称到以下标记(忽略一个可选空格),但与\futurelet
它不同消耗令牌
\documentclass{article}
\def\zza{\afterassignment\zzx\let\tmp=}
\def\zzb{\futurelet\tmp\zzx}
\def\zzc#1{\def\tmp{#1}\zzx}
\def\zzx{[tmp is \texttt{\meaning\tmp}] }
\begin{document}
A \zza xyz
B \zzb xyz
C \zzc xyz
A \zza {xyz
B \zzb {xyz}
C \zzc {xyz}
\end{document}
请注意,构造 A 和 B 都使用,\let
因此“看到”以下内容{
,而使用宏参数的 C 则“看到”整个括号组。虽然 A 从输入中删除了标记,因此x
只出现一次,并且不需要匹配}
,{
但是使用\zzb
with\futurelet
会将标记留在输入流中(因此x
出现两次,您需要匹配,}
因为 确实{
启动了一个组并被分配给\tmp
。
答案2
我只是想通过解释这个构造在原始帖子中列出的宏的上下文中所起的用途来补充大卫的回答。
当一个
\path<body>
在 TikZ 环境中的输入流开头遇到语句时,它被重写为
\tikz@scan@next@command <body>
\tikz@scan@next@command
然后将<body>
的第一个标记分配给\pgf@let@token
,最后一个表达式重写为
\tikz@handle <body tail>
通过删除 的第一个标记<body tail>
来获得其中。<body>
<body>
\tikz@handle
是一个长的 switch 语句,它根据 的值\pgf@let@token
(因此基于<body>
的第一个标记)分派适当的处理程序。
每个处理程序都会从输入流的开头吞噬一个块,对其进行处理,最后重新定位\tikz@scan@next@command
到缩减的输入流的开头:
\tikz@scan@next@command <reduced body>
驯兽师咬掉它头上的一块肉之后,<reduced body>
剩下的肉是哪里呢?<body tail>
因此,\tikz@scan@next@command
它充当由处理程序推进的前向移动光标,并指向输入流中的当前位置。此光标指向的标记决定了下一个将分派哪个处理程序。
在这些方面
\afterassignment\tikz@handle\let\pgf@let@token=
所做的是从输入流中删除光标位置的标记,并将该标记分配给\pgf@let@token
。