4

I'm trying to combine a stack data structure with a \newcounter{} definition so that I can automatically pair together a collection of points scattered throughout my text.

Each point is either marked as an \openbracket or a \closebracket, and automatically paired to an oppositely defined point in order to form \openbracket-\closebracket pairs. Closed pairs may be nested within other closed bracket pairs, and each pair of open/closed points are marked with the tikz nodes \node(openX) {}; and \node(closeX) {}; respectively [where X is an integer defined by an external counter].

For example:

\openbraket First tier
    \openbraket Second tier A
        \openbraket Third tier
        \closebracket 
    \closebracket 
    \openbracket Second tier B
    \closebracket 
\closebracket 

should automatically pair the above \openbracket \closebracket points into 4 closed bracket pairs; one First tier bracket, containing two Second tier brackets, the first (A) of which contains a single Third tier bracket. My MWE should also pop data from the stack structure so that the tikz nodes in the above example are defined as:

(open0) First tier (open1) Second tier A (open2) Third tier 
(close2) (close1) (open3)  Second tier B (close3) (close0)

Using the help of Push/Pop or save a length/dimension?, Save current value of counter in a command, and Passing stack data to tikz node names, I have managed to defined a working stack data structure and have figured out a method with which to correctly pass stack data to my \tikzmark macro.

However, the MWE below does not explicitly push the current value of the bracketpairingcounter onto the bracketpairingstack, and pushes the verbatim command string instead of the required integer number. Thus when each \node(closeX) {}; tikz mark is popped from the data stack, each node number is evaluated at the last value of bracketpairingcounter, instead of the different integers sequentially pushed onto the stack.

I'm hoping that the numbering problem can be fixed by somehow forcing my LaTeX code to immediately evaluate the value of \openbracketname below, but I can't for the life of me get \expandafter or \edef{} to work in this case...

MWE

\documentclass[openany]{article}
\usepackage{tikz}

%Define stack data structure commands (\push, \pop, \splitstack)
\newtoks\braketpairingstack
\braketpairingstack={\empty}

    \def\push#1#2{%
        \def\tmp{{#1}}% 
        \expandafter\expandafter\expandafter%
        #2\expandafter\expandafter\expandafter{\expandafter\tmp\the#2}%
    \ignorespaces}

    \def\pop#1#2{%
        \expandafter\splitstack\the#1\stop{#1}{#2}%
    }

    \def\splitstack#1#2\stop#3#4{% 
        \def\tmp{#1}
        \ifx\tmp\empty 
        \else
            \def#4{#1}\global#3={#2}%
        \fi
    } 

%Define \tikzmark command
\def\tikzmark#1{%
    \tikz[remember picture, overlay]\node[red](#1) {#1};%
}

%Define bracket pair counting commands (\openbracket, \closebracket)
\newcounter{bracketpairingcounter}

    \newcommand{\openbraket}{%
        \expandafter\edef\csname openbracketname\endcsname{\thebracketpairingcounter}%
        \push{\openbracketname}{\braketpairingstack}%
        \tikzmark{open\openbracketname}%
        \stepcounter{bracketpairingcounter}%
    }

    \newcommand{\closebraket}{%
        \pop{\braketpairingstack}{\closebracketname}%
        \tikzmark{close\closebracketname}%
    }

%Begin MWE document
\begin{document}
    \openbraket Open first bracket.\\ %Correctly marked as open0
    \openbraket Open second bracket.\\ %Correctly marked as open1

    Close second bracket. \closebraket\\ %Correctly marked as close1 
    Close first bracket. \closebraket\\ %Incorrectly marked as close1
\end{document}
1
  • You want to do \edef\temp{{#1}}, to begin with.
    – egreg
    Sep 29, 2014 at 14:18

1 Answer 1

4

You want to do \edef\temp{{#1}}, but you can simplify the definition of \push and other parts of the code as well.

\documentclass[openany]{article}
\usepackage{tikz}

%Define stack data structure commands (\push, \pop, \splitstack)
\newtoks\braketpairingstack
\braketpairingstack={\empty}

\def\push#1#2{%
  \edef\tmp{{#1}\the#2}%
  #2=\expandafter{\tmp}%
}

\def\pop#1#2{%
  \expandafter\splitstack\the#1\stop{#1}{#2}%
}

\def\splitstack#1#2\stop#3#4{% 
  \def\tmp{#1}%
  \ifx\tmp\empty
  \else
    \def#4{#1}\global#3={#2}%
  \fi
} 

%Define \tikzmark command
\def\tikzmark#1{%
  \tikz[remember picture, overlay]\node[red](#1) {#1};%
}

%Define bracket pair counting commands (\openbracket, \closebracket)
\newcounter{bracketpairingcounter}

\newcommand{\openbraket}{%
   \edef\openbracketname{\thebracketpairingcounter}%
   \push{\openbracketname}{\braketpairingstack}%
   \tikzmark{open\openbracketname}%
   \stepcounter{bracketpairingcounter}%
}

\newcommand{\closebraket}{%
  \pop{\braketpairingstack}{\closebracketname}%
  \tikzmark{close\closebracketname}%
}

%Begin MWE document
\begin{document}

\openbraket Open first bracket. %Correctly marked as open0

\openbraket Open second bracket. %Correctly marked as open1

Close second bracket. \closebraket %Correctly marked as close1 

Close first bracket. \closebraket %Correctly marked as close0
\end{document}

enter image description here

With \edef\tmp{{#1}\the#2} we completely expand #1 and add the unexpanded contents of the token register #2, since \the\tokenregister doesn't go on expanding after \the has acted to deliver the register's contents. Then we set #2 to contain the expansion (one level only) of \tmp.

Note that \ignorespaces is unnecessary, as the call of \push will find \tikzmark; actually it could cause untimely expansions (not in this case).

4
  • Brilliant, thanks so much! Genius knowledge as per usual... Sep 29, 2014 at 14:35
  • @DominicKerr As Edison allegedly said, “Genius is one percent inspiration, ninety nine percent perspiration”. ;-) Just experience: \def\tmp{{#1}} immediately looked like the culprit.
    – egreg
    Sep 29, 2014 at 14:37
  • There is a bug when more \pop than previous \push is used. To correct this, you need to set initial value \braketpairingstack={{}.} and to add the \def#4{}% after \ifx\tmp\empty in \splitstack macro.
    – wipet
    Sep 29, 2014 at 15:13
  • @wipet I suspected that.
    – egreg
    Sep 29, 2014 at 15:15

You must log in to answer this question.

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