As
@egreg
and
@UlrichDiez
layed out, the usage of \includepatternloop has a potential error: Inside of
\include the .tex ending shouldn't be used (newer versions of LaTeX detect
this, but to be safe just omit it). So better would've been to use
\includepatternloop{1}{45}{}{}{./chapters/} in your case.
Explanation
Ok, lets take a close look at your code.
The first (and simpler macro) to look at is \exchange. Everything it does is
taking two arguments and switching there order. It will remove one set of braces
if the argument is braced. So both
\exchange{a}{b}
\exchange ab
will result in ba after one step of expansion.
The other macro is your \includepatternloop. It'll take 5 arguments, and in
order to keep better track of them I'll name them here:
<current>
<stop>
<base>
<post>
<dir>
The two arguments <base> and <dir> are a bit redundant and only two distinct
arguments for semantic reasons. You could drop one of the two and simply put
there contents together into one argument (but we'll look at a simplified
version later).
So what does your macro do?
First it puts together a file name from the different arguments and includes
them
\include{#5#3#1#4}%
is in our named argument version the same as
\include{<dir><base><current><post>} so on the first iteration of the call
\includepatternloop{1}{45}{}{.tex}{./chapters/} this will use
\include{./chapters/1.tex} (<base> is empty).
Next line:
\ifnum#1<\expandafter\exchange\expandafter{\number#2}{} %
This line checks whether we're done. \ifnum is a test comparing two numbers.
#1 is the <current> iteration, and this checks whether it is smaller than
#2 (in an overly complicated way). There is a pitfall in TeX's number parsing
that is it expands things until it finds something that can't be part of a
number. To stop this expansion one usually puts a space after it (that space
will be gobbled) or (to be on the really safe side) a \relax token.
To understand that line we need to know that \expandafter basically expands
the token after the next token then removes itself and the next token does its
thing (and \expandafter does so in one step). So
\expandafter\exchange\expandafter will first expand the second \expandafter,
that one will expand the \number behind the brace, and \number reads in
anything TeX could consider a number and leaves the number in arabic digits. So
\number#2 is a normalisation. TeX's number parsing is stopped by the closing
brace (that can't be a number, right?). So when the \expandafters are done our
input looks like \exchange{<stop (normalised)>}{} followed by a space. Now
\exchange swaps the two arguments, the second is empty, so this becomes <stop (normalised)> followed by a space. That space terminates TeX's number parsing
for the second \ifnum number.
All the \exchange did was allow that the normalisation with \number would be
ended by the closing brace and the space at the end of the line is used to
terminate \ifnum's number parsing instead of \number's.
Now \ifnum compares <current> with <stop (normalised)>. If the condition
(smaller than) is not met, everything up to the \fi two rows down is gobbled
and the macro is done. Else the next iteration is called with the line
\exchange{\expandafter\includepatternloop\expandafter{\number\numexpr#1+1\relax}{#2}{#3}{#4}{#5}}%
The \exchange will swap the rest of this line with the \fi, so now the \fi
ends the \ifnum block and afterwards
\expandafter\includepatternloop\expandafter{\number\numexpr#1+1\relax}{#2}{#3}{#4}{#5}
is evaluated.
We have a few \expandafter again. Those will first expand the \number before
\includepatternloop is run. That \number will expand until TeX has a
complete number. To do so it expands \numexpr. Now \numexpr is a number
parsing macro as well, this one allows to do basic calculations, and will be
terminated by either something that can't be part of a number (but semi-ignoring
spaces, no need to further dig here) and is no valid operator (it supports +,
-, *, / and parenthesis). It will be terminated by \relax (which it will
gobble!). So after \number\numexpr<current>+1\relax is expanded once the new
contents of the first braced group will be <next> which is the result of
<current>+1.
The \expandafters are done and our new input line looks like this:
\includepatternloop{<next>}{<stop>}{<base>}{<post>}{<dir>}
resulting in the next iteration.
Alternative implementation
That macro could be a bit simplified. Two of the arguments can be combined into
one <pre> argument. And the number parsing in the \ifnum row is a bit over
the top. Instead I'd use a two step approach, one front end macro doing the
normalisations, and one macro actually doing the loop. \the is similar to
\number, but doesn't work on literal numeric input (so \number5 is fine and
would result in 5, \the5 throws an error), but is a tad faster (and for
\numexpr it doesn't make a difference). Input normalisations are done with
\numexpr instead of \number (this allows to calculate <start> and <stop>
on the spot, so \includepatternloop{1+6}{100-50}{./chapters/}{.tex} would be
fine). The ;s will stop the \numexpr and serve as argument delimiters
because the inner loop is defined with plain syntax \def.
\makeatletter
\newcommand\includepatternloop[2]% <start> and <stop> are grabbed, rest curried
{%
\expandafter\@includepatternloop\the\numexpr#1\expandafter;\the\numexpr#2;
}
\protected\def\@includepatternloop#1;#2;#3#4% <- will grab 2 arguments right delimited by `;` and 2 normal ones
{%
\include{#3#1#4}%
\ifnum#1<#2 % <- space after #2 terminates number parsing
\exchange{\expandafter\@includepatternloop\the\numexpr#1+1;#2;{#3}{#4}}%
\fi
}
\makeatother
The new frontend syntax is \includepatternloop{<start>}{<stop>}{<pre>}{<post>}
and to include every file in ./chapters/ that is named A<number>B from 1
to 45 you'd use
\includepatternloop{1}{45}{./chapters/A}{B}
Remember to not include the file extension .tex for \include.
\include– egreg Apr 02 '22 at 08:37\includeuntil LaTeX 2021/06/01. This will be added automatically during processing. As of LaTeX 2021/06/01, the extension is only added if it has not already been specified by the user. – Ulrich Diez Apr 02 '22 at 09:17\include- the code stems from an answer of mine to the question "How to use for loop to input files". – Ulrich Diez Apr 02 '22 at 14:33