3

I wrote the following code

\documentclass{article}
\makeatletter
 \newtoks\a@toks
 \newtoks\b@toks
 \newcounter{a@counter}%
 \newcounter{b@counter}%
 \setcounter{a@counter}{0}%
 \setcounter{b@counter}{0}%
 \newcommand{\aAdd}[1]{%
  \ifnum\thea@counter>0\a@toks=\expandafter{\the\a@toks {#1}}%
  \else\a@toks=\expandafter{\the\a@toks {#1}}%
  \fi
  \stepcounter{a@counter}%
 }
 \newcommand{\reset}{%
  \setcounter{a@counter}{0}%
  \a@toks={}%
 }
 \newcommand{\bexp}{%
  \ifnum\theb@counter>0\b@toks=\expandafter{\the\b@toks, (\the\a@toks)}%
  \else\b@toks=\expandafter{\the\b@toks (\the\a@toks) }%
  \fi
  \stepcounter{b@counter}%
  \setcounter{a@counter}{0}%
  \a@toks=\noexpand{}%
 }
 \newcommand{\print}{%
  \the\b@toks%
 }
\makeatother
\begin{document}
 Hello World!\\[3cm]
 \aAdd{a}
 \aAdd{b}
 \bexp
 \aAdd{c}
 \print
\end{document}

What I'm trying to do is the following: with \aAdd I add some element to a list, specifically in this example after

\aAdd{a}
\aAdd{b}

I expect \a@toks to be equal to ab. Then I flush this into another token, so I expect \b@toks to be equal to ab. The problem is when the command

\a@toks={}

is executed, this resets even \b@toks that continues to follow \a@toks, so that, when I execute

\aAdd{c}

\b@toks has the value c.

I would like, once set \b@toks = \a@toks to set only the value of \b@toks, so that, when I redefine \a@toks, \b@toks continues to have the preceding value (in this case ab).

Can anyone help me?

  • the question is very hard to understand, after the first two \aAdd the register \a@toks is {a}{b} not ab do you not want the braces? and after \bexp the register \b@toks is (\the \a@toks ) but (I think?) you want the content of a@toks not a reference? – David Carlisle May 4 '16 at 19:30
  • The problem is not what is stored in \a@toks, but what is stored in\b@toks. I want that after I reset \a@toks={} in \b@toks continues to be {a}{b}. Have I explained it better? – MaPo May 4 '16 at 19:33
  • beware doing \ifnum\theb@counter>0\b@toks which will try to expand \b@toks to terminate the number before doing the test, it works here as b@toks is not expandable but safer to leave a space after 0 or better use \z@ – David Carlisle May 4 '16 at 19:34
  • \b@toks=\expandafter{\the\a@toks} for the first assignment? – user31729 May 4 '16 at 19:35
  • but your description said a@toks contains ab which it does not, so the whole question is very confusing. b@toks is never set to {a}{b} in the above code. – David Carlisle May 4 '16 at 19:35
9

\expandafter doesn't expand everything after it, just the following token. Also, since it seems like b@counter measures the content added to \b@toks, I don't see the need for

\ifnum...
\else\b@toks=\expandafter{\the\b@toks (\the\a@toks) }
\fi

where you want to add (an empty) \b@toks to itself.

The following produces what you're after, I think (I've cleaned it up a bit):

enter image description here

\documentclass{article}

\makeatletter
\newtoks\a@toks
\newtoks\b@toks
\newcounter{b@counter}%
\newcounter{a@counter}[b@counter]%

\newcommand{\aAdd}[1]{%
  \ifnum\value{a@counter}>0 \a@toks=\expandafter{\the\a@toks {#1}}%
  \else\a@toks=\expandafter{\the\a@toks {#1}}%
  \fi
  \stepcounter{a@counter}%
}
\newcommand{\reset}{%
  \setcounter{a@counter}{0}%
  \a@toks={}%
}
\newcommand{\bexp}{%
  \ifnum\value{b@counter}>0
    \edef\x{\noexpand\b@toks={\the\b@toks, (\the\a@toks)}}%
  \else
    \edef\x{\noexpand\b@toks={(\the\a@toks)}}%
  \fi
  \x
  \stepcounter{b@counter}%
  \a@toks={}%
}
\newcommand{\print}{%
  \the\b@toks%
}
\makeatother

\begin{document}

Hello World!

\bigskip

\aAdd{a}% \a@toks = {a}
\aAdd{b}% \a@toks = {a}{b}
\bexp% \a@toks = {}, \b@toks = {a}{b}
\aAdd{c}% \a@toks = {c}
\print% \b@toks

\end{document}

One could use

\b@toks=\expandafter{\expandafter(\the\a@toks)}

to make sure \a@toks is expanded before inserting it into \b@toks. However, I've instead opted to make sure everything expands before adding it to \b@toks by using an \edef\x{...}\x approach.

If leaving behind an unwanted \x is a problem, you can use the following definition for \bexp:

\newcommand{\bexp}{%
  \begingroup
  \ifnum\value{b@counter}>0
    \edef\x{\endgroup\noexpand\b@toks={\the\b@toks, (\the\a@toks)}}%
  \else
    \edef\x{\endgroup\noexpand\b@toks={(\the\a@toks)}}%
  \fi
  \x
  \stepcounter{b@counter}%
  \a@toks={}%
}
  • \noexpand{ is harmless, but... – David Carlisle May 4 '16 at 19:40
  • @DavidCarlisle... sorry, missed that one. – Werner May 4 '16 at 19:42
  • 1
    Just use e-TeX! – Joseph Wright May 4 '16 at 19:47
  • It is almost I like to do, the last thing is that I was lookin for. I still do not understand why, if between the \aAdd{c} and the \print i write another \bexp I get (ab), () instead of (ab), (c),which I would like to obtain for my purposes... – MaPo May 4 '16 at 19:50
  • Thanks for helping me understand a bit more about token registers and such. I've always been clueless on them. – Steven B. Segletes May 4 '16 at 19:51
5

Werner's analysis is very good. Here's an alternative implementation with xparse and expl3. Note that you can define as optional argument to \print the separator between items (default is “comma-space”).

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn

\NewDocumentCommand{\aAdd}{m}
 {
  \mapo_aadd:n { #1 }
 }
\NewDocumentCommand{\bexp}{}
 {
  \mapo_bexp:
 }
\NewDocumentCommand{\reset}{}
 {
  \mapo_reset:
 }
\NewDocumentCommand{\print}{O{,~}}
 {
  \mapo_print:n { #1 }
 }

\tl_new:N \l_mapo_a_tl
\seq_new:N \l_mapo_b_seq

\cs_new_protected:Nn \mapo_aadd:n
 {
  \tl_put_right:Nn \l_mapo_a_tl { #1 }
 }
\cs_new_protected:Nn \mapo_bexp:
 {
  \seq_put_right:Nx \l_mapo_b_seq { ( \exp_not:V \l_mapo_a_tl ) }
  \mapo_reset:
 }
\cs_new_protected:Nn \mapo_reset:
 {
  \tl_clear:N \l_mapo_a_tl
 }
\cs_new:Nn \mapo_print:n
 {
  \seq_use:Nn \l_mapo_b_seq { #1 }
 }
\ExplSyntaxOff

\begin{document}

\noindent
Hello World!\\
\aAdd{a}\aAdd{b}\bexp\aAdd{c}%
\print\\
\bexp
\print[---]

\end{document}

enter image description here

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.