0

I'm trying to set up a program in order to iterate over a list of elements formatted like [number1][content1][number2][content2]. The following code is a minimal not working example: (in real code the variable \@list would be defined inputting a whole file).

\documentclass[a4paper,11pt]{article}

\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage[italian]{babel}

\makeatletter
\newif\ifendlist%
\endlistfalse%
\errorcontextlines 10000
\tracingmacros5

\def\@list{[1][A string][1][Another string][2][Yet another one]}

\def\@grabnextelement[#1][#2]{%
  \gdef\@elementnumber{#1}%
  \gdef\@elementcontent{#2}%
}

\def\@nextelement{%
  \@ifnextchar[\@grabnextelement\endlisttrue%
}

\def\@advancelist{%
  \expandafter\protected@xdef\expandafter\@list{\expandafter\@nextelement\@list}%
}

\def\printlist{%
  \loop\unless\ifendlist%
  \@advancelist%
  \@elementnumber \hskip 1.5em \@elementcontent

  \repeat%
}
\makeatother

\begin{document}
\printlist%
\end{document}

I don't understand why, if I try to execute the above code, I get an error:

! Argument of \reserved@a has an extra }.
<inserted text> 
                \par 
<to be read again> 
                   }
\iterate ->\unless \ifendlist \@advancelist 
                                            \@elementnumber \hskip 1.5em \@e...

\loop ...elax \expandafter \iterate \fi }\iterate 
                                                  \let \iterate \relax 

l.38 \printlist
               %

I'm not a TeX wizard, but I tried to protect all edef and xdef. Can someone point out what is happening here?

More informations about the expansions:

\printlist ->\loop \unless \ifendlist \@advancelist \@elementnumber \hskip 1.5em \@elementcontent \par \repeat 

\loop #1\repeat ->\def \iterate {#1\relax \expandafter \iterate \fi }\iterate \let \iterate \relax 
#1<-\unless \ifendlist \@advancelist \@elementnumber \hskip 1.5em \@elementcontent \par 

\iterate ->\unless \ifendlist \@advancelist \@elementnumber \hskip 1.5em \@elementcontent \par \relax \expandafter \iterate \fi 

\@advancelist ->\expandafter \protected@xdef \expandafter \@list {\expandafter \@nextelement \@list }

\protected@xdef ->\let \@@protect \protect \let \protect \@unexpandable@protect \afterassignment \restore@protect \xdef 

\@list ->[1][A string][1][Another string][2][Yet another one]

\@nextelement ->\@ifnextchar [\@grabnextelement \endlisttrue 

\@ifnextchar #1#2#3->\let \reserved@d =#1\def \reserved@a {#2}\def \reserved@b {#3}\futurelet \@let@token \@ifnch 
#1<-[
#2<-\@grabnextelement 
#3<-\endlisttrue 

\reserved@a #10#2{->\expandafter \def \expandafter \it@ccap  \reserved@b #10{

I do see there is some odd thing going on with \reserved@a, but I don't realize how it could be solved and why it is happening.

6
  • Even by changing the \protected@xdef in a \xdef the error and the expansions remain the same. And yes I do need the definitions because in the real example the list could contain commands that I want to be executed at the point where I put them in the text.
    – trenta3
    Sep 9, 2017 at 22:01
  • yes, that's what I mean you can not use your \@nextelement in edef,xdef,protected@edef etc as it does not work by expansion. Sep 9, 2017 at 22:03
  • I don't understand your comment about needing the definitions, you save each item in \@elementcontent but you can't use that definition to use that item in a different place as you immediately re-define it for the next item. Sep 9, 2017 at 22:05
  • The real application of the code with the list would be redefining an environment end in order to print the elements of the list with number n after the n-th occurrence of the environment (The numbers in the list are sorted in ascending order), so I need to be able to stop printing the list (and that would be done inside the loop)
    – trenta3
    Sep 9, 2017 at 22:13
  • with the loop defined as below you can make definitions and stop at any point (not just at \relax) but you can not make definitions inside an edef, only expansion may occur there. Sep 9, 2017 at 22:27

1 Answer 1

0

You can't use \@ifnextchar in a \protected@xdef as it doesn't work via expansion however do you need the loop and definitions at all, as opposed to simply evaluating the list?

enter image description here

\documentclass{article}

\begin{document}

\makeatletter

\def\@list{[1][A string][1][Another string][2][Yet another one]}

\def\printlist{\expandafter\printitem\@list[\relax][]}

\def\printitem[#1][#2]{%
  \ifx\relax#1%
  \else
  #1\hskip 1.5em #2\par
  \expandafter\printitem
  \fi}

\printlist

\end{document}
3
  • Thank you for pointing out that issue with \protected@xdef. I need the possibility to assign one element of the list at a time, because I'd like to print those with number $n$ after the $n$-th occurrence of an environment. The \printlist was just a fake application example.
    – trenta3
    Sep 9, 2017 at 22:09
  • @trenta3 as far as I understand your comment just adjust the definition of \printitem as above to just print if #1 = n then next time you set n evaluate the list again and print those with the new value of n. Sep 9, 2017 at 22:29
  • Yes of course. I just did not think of it. :)
    – trenta3
    Sep 9, 2017 at 22:53

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.