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
  • 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. – David Carlisle Mar 9 '17 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 '17 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 – David Carlisle Mar 9 '17 at 16:03
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

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}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.