我是编程新手。
我正在阅读宏的代码\tikz@scan@one@point
,
但是遇到了很多麻烦:
问题 1:
如何区分宏的参数?例如
的定义\tikz@scan@one@point
有一个参数
(\def\tikz@scan@one@point#1{...
),
如果我输入\tikz@scan@one@point\pgfutil@firstofone(A)
(“(A)”是 TikZ 中的一个节点),那么定义中
的“ ”是代码的哪一部分? 是吗?还是只有宏?#1
\pgfutil@firstofone(A)
\pgfutil@firstofone
问题 2:
宏\tikz@scanexpand
只有一个参数(\def\tikz@scanexpand#1{...
),
但是在的定义中\tikz@scan@absolute
,
宏\tikz@scanexpand
后面没有任何参数:
\def\tikz@scan@absolute#1{%
\pgfutil@ifnextchar({\tikz@scan@@absolute#1}%)
{%
\advance\tikz@expandcount by -1%
\ifnum\tikz@expandcount<0\relax%
\let\pgfutil@next=\tikz@@scangiveup%
\else%
\let\pgfutil@next=\tikz@@scanexpand%
\fi%
\pgfutil@next{#1}%
}%
}%
这种现象经常发生在 TikZ 和 LaTeX 源代码中。
有人能解释一下为什么吗 ^_^?
如果你已经阅读过 tikz 的源代码,
你能解释一下宏的工作原理\tikz@scan@one@point
吗?
这对我很有帮助。
另外,您有阅读 TeX 源代码的任何技巧吗?
答案1
你需要记住 TeX 是使用 token 来工作的。当抓取一个未限定的参数时,这意味着我们抓取
- 一个代币或
- 一平衡文本:括号内的内容*
- 更正式地说,TeX 吸收类别代码 1 标记之后的所有内容,直到匹配的类别代码 2 标记,从而适当平衡任何嵌套的类别代码 1/2 对。
因此,当你使用时\tikz@scan@one@point\pgfutil@firstofone(A)
,\tikz@scan@one@point
只需要\pgfutil@firstofone
:#1
我们没有支撑参数平衡文本。
在 中\tikz@scan@absolute
,会发生的情况是\pgfutil@next
将 设置为等于 ( \let
) 要采取的操作:这可以是\tikz@@scanexpand
但也可以设置为\tikz@@scangiveup
。然后使用标记\pgfutil@next
,然后是{#1}
,因此\tikz@scan@absolute
是传递\tikz@@scanexpand
给平衡文本。
一般来说,你必须考虑标记,并记住 TeX 通过宏扩展工作。这\tracingall
是你的朋友,但从小处着手 - TikZ 很复杂,你可能有数百万行跟踪!