TikZ 手册中有关 /tikz/graph/parse 键的一个示例

TikZ 手册中有关 /tikz/graph/parse 键的一个示例

我将列出两份 LaTeX 手稿。第一份是手册中给出的用于演示密钥有用性的示例/tikz/graph/parse,它编译成功,而第二份编译失败。在列出第一份手稿并展示其输出后,我将论证第二份手稿与第一份手稿等同。显然这个论点是错误的,但我不知道为什么。

考虑以下 LaTeX 手稿,它本质上是 TikZ & PGF 手册 3.0.1a 版(第 265 页)第 19 章(“指定图形”)第 19.3 节(“图形路径命令的语法”)第 19.3.2 小节(“组规范的语法”)末尾的示例的副本。

\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{graphs}
\begin{document}
    \def\mychain#1{
        \def \mytext{1}
        \foreach \i in {2,...,#1} {
            \xdef\mytext{\mytext -> \i}
        }
    }
    \tikzgraphsset{my chain/.style={
        /utils/exec=\mychain{#1},
        parse/.expand once=\mytext}
    }
    \tikz \graph { [my chain=4] };
\end{document}

最终渲染的图片为(不按比例)

TikZ 图

我将尽我所理解来解释输出。

  1. \tikzgraphsset命令只是使用路径前缀执行其键/tikz/graphs(该\tikzgraphsset命令在 p. 262 中描述)。因此,键/tikz/graphs/my chain成为扩展为 的缩写/utils/exec=\mychain{#1}, parse/.expand once=\mytext
  2. 接下来\graph ...执行命令。唯一要做的就是处理组选项([my chain=4])。组选项使用路径前缀执行/tikz/graphs(第 264 页中对此进行了描述)。因此/tikz/graphs/mychain=4执行了键分配。这扩展为/utils/exec=\mychain{4},/tikz/graphs/parse/.expand once=\mytext
  3. 现在执行分配/utils/exec=\mychain{4}。此键仅执行分配的值(此键在“密钥管理”一章第 893 页中描述),因此宏\mychain{4}得到扩展。
  4. 最后一步/tikz/graphs/parse/.expand once=\mytext是执行赋值。密钥处理程序.expand once导致\mytext将 的替换文本(即 )1 -> 2 -> 3 -> 4赋值给/tikz/graphs/parse.expand once密钥处理程序在“密钥管理”一章第 890 页中描述)。赋值给 密钥的效果/tikz/graphs/parse是将赋值的值插入到当前组的开头,就像您在那里输入它一样(/tikz/graphs/parse在第 265 页中描述)。

总之,上述手稿应等同于以下内容:

\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{graphs}
\begin{document}
    \def \mychain#1{
        \def \mytext{1}
        \foreach \i in {2,...,#1} {
            \xdef\mytext{\mytext -> \i}
        }
    }
    \tikz \graph { \mychain{4} 1->2->3->4 };
\end{document}

但最后的手稿编译失败,并pdftex报告以下错误消息:

ERROR: Undefined control sequence.

--- TeX said ---
\mychain #1-> \def \mytext 
                           {1} \foreach \i in {2,...,#1} { \xdef \mytext {\m...l.11     \tikz \graph { \mychain{4} 1->2->3->4 }

如果有人能解释第二个例子为什么会失败,而且更重要的是,能解释第一个例子是如何工作的,我将不胜感激。我希望能够预测类似的例子会如何发挥作用。

答案1

以下是 TikZ“引擎”如何处理路径的粗略概述*

\graph { [my chain=4] };

假设调用了图解析器\graph@parser(实际上并没有调用,这只是为了说明)。然后上述语句扩展为

{\graph@parser [my chain=4] };}

换句话说,这两个标记\graph { 被控制序列替换\graph@parser,然后整个语句被 TeX 组包围。

现在 TeX 打开了一个新的范围,并继续处理以下输入流:

\graph@parser [my chain=4] };}

当解析器看到 时[,它会将整个[...]构造替换为 \pgfkeys{/tikz/graphs/.cd,...},并在执行选项后恢复解析。换句话说,最后一个代码片段扩展为

\pgfkeys{/tikz/graphs/.cd,my chain=4}\graph@parser };}

/tikz/graphs/.cd表示具有相对路径(或使用手册术语的“部分路径”)的键将相对于基本路径进行解释/tikz/graphs。因此,最后一个代码片段扩展为

\pgfkeys{/tikz/graphs/my chain=4}\graph@parser };}

由于/tikz/graphs/my chain是一种样式,因此在用指定值 4 替换参数 #1 后,它将被其“替换文本”替换,因此最后一个代码片段扩展为

\pgfkeys{/utils/exec=\mychain{4},/tikz/graphs/parse/.expand once=\mytext}%
    \graph@parser };}

正如原帖所述,这扩展为

\mychain{4}\pgfkeys{/tikz/graphs/parse/.expand once=\mytext}\graph@parser };}

\mychain[4}最终扩展为\gdef\mytext{1->2->3->4}。因此,宏\mytext保存在 TeX 的内部状态中,最后一个代码片段简化为

\pgfkeys{/tikz/graphs/parse/.expand once=\mytext}\graph@parser };}

正如原帖所述,这扩展为

    \pgfkeys{/tikz/graphs/parse=1->2->3->4}\graph@parser };}

键的操作/tikz/graphs/parse是将其参数插入到控制序列之后\graph@parser。因此,最后一个代码片段扩展为

    \graph@parser 1->2->3->4};}

所有这些扩展的总体效果就像原始路径(\graph { [my chain=4] };)被替换为

{%
    \gdef\mytext{1->2->3->4}%
    \graph{1->2->3->4}%
}

这反过来相当于

\def\mytext{1->2->3->4}%
\graph{1->2->3->4}

* 需要明确的是:这意味着我没有讲述完整的故事,并且我只是说了一些善意的谎言,以使呈现更清晰、更干净。

相关内容