2

The objective is to generate rows of a TikZ matrix from a string.

In the example below, \drawpodpair{NAME:TYPE}{SCOPE} produces a matrix row. I want to call \foreach over a string of the form N1:T1,N2:T2,... to get the NAME:TYPE pairs. I know you can't \foreach in a matrix, so I use \xappto to assemble the matrix body.

It works if the \xappto calls are explicitly given one at a time, but not if \xappto is used inside \foreach:

\documentclass[tikz,border=10pt,a4paper]{standalone}

\usepackage[english]{babel}
\usepackage{etoolbox}

\usetikzlibrary{arrows,intersections,shapes,backgrounds,scopes,positioning,fit,matrix}

\tikzset{varname/.style={rectangle,thin,inner sep=0.3ex,font=\ttfamily,text height=1.5ex,text depth=0.35ex}}
\tikzset{vartype/.style={rectangle,text=red,thin,inner sep=0.3ex,font=\ttfamily,text height=1.5ex,text depth=0.35ex}}
\tikzset{struct/.style={matrix of nodes,draw,column 1/.style={anchor=base west},column 2/.style={anchor=base west}}}

\newcommand\drawpodpair[2]{\drawpodpairdoit#2:#1\relax}
\def\drawpodpairdoit#1:#2:#3\relax%
{%
    \node[varname] (#1-#2) {#2}; \pgfmatrixnextcell \node[vartype] (#1-#3) {#3}; \\%
}
\begin{document}

\begin{tikzpicture}

\let\mymatrixcontent\empty

\xappto\mymatrixcontent{\expandonce{\drawpodpair{x1:a11}{x}}}
\xappto\mymatrixcontent{\expandonce{\drawpodpair{x2:a12}{x}}}
\xappto\mymatrixcontent{\expandonce{\drawpodpair{x3:a13}{x}}}
\foreach \p in {a:int,b:char *,c:bool}
{
    %\xappto\mymatrixcontent{\expandonce{\drawpodpair{\p}{x}}} <<< ------ UNCOMMENT THIS
}

\matrix (foo) [struct]
{
    \mymatrixcontent  <<< ------ TO CAUSE AN ERROR HERE
};
\end{tikzpicture}

\end{document}

I want the commented-out line to work, but it causes an error when the matrix tries to include \mymatrixcontent

Undefined control sequence.
<argument> x-\p 
                \relax \drawpodpairdoit x
l.33    \mymatrixconten
3
  • this is the same error as your previous question you are adding the token \p but you need to expand that and add its definition. Mar 9, 2017 at 15:37
  • What happens when multiple consecutive tokens both require \expandafter? If I understand correctly (the lightbulb is flickering into life) then this method wouldn't be possible, right?
    – spraff
    Mar 9, 2017 at 15:47
  • You can always use more \expandafter or here you probably just don't want the \p inside \expandonce as that is stopping it expanding, or as egreg showed in a previous question use expl3 constructs that are explicitly designed to take care of expansion for you Mar 9, 2017 at 16:03

3 Answers 3

2

You can avoid every \expandafter:

\documentclass[tikz,border=10pt,a4paper]{standalone}

\usepackage[english]{babel}
\usepackage{xparse}

\usetikzlibrary{arrows,intersections,shapes,backgrounds,scopes,positioning,fit,matrix}

\tikzset{
  varname/.style={
    rectangle,
    thin,
    inner sep=0.3ex,
    font=\ttfamily,
    text height=1.5ex,
    text depth=0.35ex,
  },
  vartype/.style={
    rectangle,
    text=red,
    thin,
    inner sep=0.3ex,
    font=\ttfamily,
    text height=1.5ex,
    text depth=0.35ex,
  },
  struct/.style={
    matrix of nodes,
    draw,
    column 1/.style={anchor=base west},
    column 2/.style={anchor=base west},
  },
}

\newcommand\drawpodpair[2]{\drawpodpairdoit#2:#1\relax}
\def\drawpodpairdoit#1:#2:#3\relax{%
  \node[varname] (#1-#2) {#2}; \pgfmatrixnextcell \node[vartype] (#1-#3) {#3}; \\
}

\ExplSyntaxOn
\NewDocumentCommand{\appendto}{mm}
 {
  \tl_put_right:Nn #1 { #2 }
 }
\NewDocumentCommand{\clear}{m}
 {
  \tl_clear_new:N #1
 }
\NewDocumentCommand{\cycle}{mm}
 {
  \clist_map_inline:nn { #1 } { #2 }
 }
\ExplSyntaxOff

\begin{document}

\begin{tikzpicture}
\clear\mymatrixcontent
\cycle{x1:a11,x2:a12,x3:a13,a:int,b:char *,c:bool}
 {
  \appendto\mymatrixcontent{\drawpodpair{#1}{x}}
 }
\matrix (foo) [struct]
  {
    \mymatrixcontent 
  };
\end{tikzpicture}

\end{document}

enter image description here

1

I just \expandafter to get to the \p

\documentclass[tikz,border=10pt,a4paper]{standalone}

\usepackage[english]{babel}
\usepackage{etoolbox}

\usetikzlibrary{arrows,intersections,shapes,backgrounds,scopes,positioning,fit,matrix}

\tikzset{varname/.style={rectangle,thin,inner sep=0.3ex,font=\ttfamily,text height=1.5ex,text depth=0.35ex}}
\tikzset{vartype/.style={rectangle,text=red,thin,inner sep=0.3ex,font=\ttfamily,text height=1.5ex,text depth=0.35ex}}
\tikzset{struct/.style={matrix of nodes,draw,column 1/.style={anchor=base west},column 2/.style={anchor=base west}}}

\newcommand\drawpodpair[2]{\drawpodpairdoit#2:#1\relax}
\def\drawpodpairdoit#1:#2:#3\relax%
{%
    \node[varname] (#1-#2) {#2}; \pgfmatrixnextcell \node[vartype] (#1-#3) {#3}; \\%
}
\begin{document}

\begin{tikzpicture}

\let\mymatrixcontent\empty

\xappto\mymatrixcontent{\expandonce{\drawpodpair{x1:a11}{x}}}
\xappto\mymatrixcontent{\expandonce{\drawpodpair{x2:a12}{x}}}
\xappto\mymatrixcontent{\expandonce{\drawpodpair{x3:a13}{x}}}
\foreach \p in {a:int,b:char *,c:bool}
{
    \expandafter\xappto\expandafter\mymatrixcontent\expandafter{%
    \expandafter\expandonce\expandafter{\expandafter\drawpodpair%
    \expandafter{\p}{x}}} %<<< ------ UNCOMMENT THIS
}

\matrix (foo) [struct]
{
    \mymatrixcontent%  <<< ------ TO CAUSE AN ERROR HERE
};
\end{tikzpicture}

\end{document}

enter image description here

1
1

One way to expand \p in time would be

\documentclass[tikz,border=10pt,a4paper]{standalone}

\usepackage[english]{babel}
\usepackage{etoolbox}

\usetikzlibrary{arrows,intersections,shapes,backgrounds,scopes,positioning,fit,matrix}

\tikzset{varname/.style={rectangle,thin,inner sep=0.3ex,font=\ttfamily,text height=1.5ex,text depth=0.35ex}}
\tikzset{vartype/.style={rectangle,text=red,thin,inner sep=0.3ex,font=\ttfamily,text height=1.5ex,text depth=0.35ex}}
\tikzset{struct/.style={matrix of nodes,draw,column 1/.style={anchor=base west},column 2/.style={anchor=base west}}}

\newcommand\drawpodpair[2]{\drawpodpairdoit#2:#1\relax}
\def\drawpodpairdoit#1:#2:#3\relax%
{%
    \node[varname] (#1-#2) {#2}; \pgfmatrixnextcell \node[vartype] (#1-#3) {#3}; \\%
}
\begin{document}

\begin{tikzpicture}

\let\mymatrixcontent\empty

\xappto\mymatrixcontent{\expandonce{\drawpodpair{x1:a11}{x}}}
\xappto\mymatrixcontent{\expandonce{\drawpodpair{x2:a12}{x}}}
\xappto\mymatrixcontent{\expandonce{\drawpodpair{x3:a13}{x}}}
\foreach \p in {a:int,b:char *,c:bool}
{
    \xappto\mymatrixcontent{\expandafter\noexpand\drawpodpair{\p}{x}}
}

\matrix (foo) [struct]
{
    \mymatrixcontent % <<< ------ TO CAUSE AN ERROR HERE
};
\end{tikzpicture}

\end{document}

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .