我刚刚开始学习 expl3 编程,并尝试创建一个用于绘制 TikZ/PGF 图类型的解析器。基本上我想要
\begin{pck}
plot node1 .3 .3;
plot node2 .7 .7;
\end{pck}
扩展到
\begin{tikzpicture}
\begin{axis}[xmin=0, xmax=1,
ymin=0, ymax=1]
\node (node1) at (axis cs:.3, .3) [circle, draw] {};
\node (node1) at (axis cs:.7, .7) [circle, draw] {};
\end{axis}
\end{tikzpicture}
文本在环境中必须先完全解析,然后将其扩展为 TikZ 代码,因为我想对一些参数进行一些处理。
到目前为止我有以下代码。
\documentclass{article}
\usepackage[check-declarations]{expl3}
\usepackage{environ}
\usepackage{pgfplots}
\pgfplotsset{compat=1.15}
\ExplSyntaxOn
\tl_new:N \pck_objects_tl
\seq_new:N \pck_labels
\seq_new:N \pck_xs
\seq_new:N \pck_ys
\seq_new:N \pck_edgs_left
\seq_new:N \pck_edgs_right
\tl_new:N \pck_label
\tl_new:N \pck_x
\tl_new:N \pck_y
\tl_new:N \pck_edg_left
\tl_new:N \pck_edg_right
\cs_new:Npn \pck_draw {
\bool_do_until:nn {\seq_if_empty_p:N \pck_labels} {
\seq_pop_left:NN \pck_labels \pck_label
\seq_pop_left:NN \pck_xs \pck_x
\seq_pop_left:NN \pck_ys \pck_y
\node~(\pck_label)~at~(axis~cs\c_colon_str~\pck_x,~\pck_y)~[circle, draw]~\bgroup \egroup ; \par
}
}
\NewEnviron{pck}[1][] {
\pck_parse:V \BODY
\begin{tikzpicture}
\begin{axis}[xmin=0, xmax=1,
ymin=0, ymax=1]
\pck_draw
\end{axis}
\end{tikzpicture}\par
}
\cs_new_protected:Npn \pck_parse:n #1{
\tl_set:Nn \pck_objects_tl{#1}
\tl_remove_all:Nn \pck_objects_tl{\par}
\tl_replace_all:Nnn \pck_objects_tl{plot~}{\pck_parse_plot:w}
\tl_use:N \pck_objects_tl
}
\cs_generate_variant:Nn \pck_parse:n {V}
\cs_new_protected:Npn \pck_parse_plot:w #1 ~ #2 ~ #3 ; {
\seq_put_right:Nn \pck_labels {#1}
\seq_put_right:Nn \pck_xs {#2}
\seq_put_right:Nn \pck_ys {#3}
}
\ExplSyntaxOff
\begin{document}
\begin{pck}
plot node1 .3 .3;
plot node2 .7 .7;
\end{pck}
\end{document}
但是,此代码将所有节点都绘制在彼此之上。我相信这是因为当序列(例如\pck_labels
)弹出到标记列表时\pck_label
,标记列表不会立即扩展为node1
或node2
,但扩展发生在最后,因此全部扩展为node2
等。我真的无法弄清楚如何以正确的方式扩展标记,我尝试使用和规格生成变体f
并x
使用\exp_after
和\use
。有什么建议吗?
此外,由于我对 expl3 完全陌生,我很高兴收到有关代码的任何反馈!
答案1
此代码将解决您的问题。我不会使用多个序列。通过进行一些 x 类型扩展,它将绘制您的点。请注意,您应该在 l3 名称中添加包含数据类型的后缀。
\documentclass{article}
\usepackage[check-declarations]{expl3}
\usepackage{environ}
\usepackage{pgfplots}
\pgfplotsset{compat=1.15}
\ExplSyntaxOn
\tl_new:N \pck_objects_tl
\seq_new:N \pck_plot_seq
\cs_new:Npn \pck_node:nnn #1#2#3 {
\node~(#1)~at~(axis~cs\c_colon_str#2,#3)~[circle, draw] { };
}
\cs_generate_variant:Nn \pck_node:nnn {xxx}
\cs_new:Npn \pck_draw {
\seq_map_inline:Nn \pck_plot_seq
{
\clist_set:Nn \l_tmpa_clist { ##1 }
\pck_node:xxx { \clist_item:Nn \l_tmpa_clist { 1 } }
{ \clist_item:Nn \l_tmpa_clist { 2 } }
{ \clist_item:Nn \l_tmpa_clist { 3 } }
}
}
\NewEnviron{pck}[1][] {
\pck_parse:V \BODY
\begin{tikzpicture}
\begin{axis}[xmin=0, xmax=1,
ymin=0, ymax=1]
\pck_draw
\end{axis}
\end{tikzpicture}\par
}
\cs_new_protected:Npn \pck_parse:n #1{
\tl_set:Nn \pck_objects_tl{#1}
\tl_remove_all:Nn \pck_objects_tl{\par}
\tl_replace_all:Nnn \pck_objects_tl{plot~}{\pck_parse_plot:w}
\tl_use:N \pck_objects_tl
}
\cs_generate_variant:Nn \pck_parse:n { V }
\cs_new_protected:Npn \pck_parse_plot:w #1 ~ #2 ~ #3 ; {
\seq_put_right:Nn \pck_plot_seq {#1,#2,#3}
}
\ExplSyntaxOff
\begin{document}
\begin{pck}
plot node1 .3 .3;
plot node2 .7 .7;
plot node3 .5 .5;
\end{pck}
\end{document}