The following example is largely shorn of its original context as part of the process of simplification.
This LaTeX file, if compiled with pdflatex parameternum.tex
, gives
! Illegal parameter number in definition of \reserved@a.
The structure of this file has been the same for a long time. However,
I only recently added the use of \IfFileExists
and \PackageError
to \foo
, which made it blow up. If one just uses
\NewDocumentCommand{\foo}{m +m}
{
#2
}
there is no error. Similarly, if one leaves out
\renewcommand{\nextnuml}[1]{\refstepcounter{tabenum}\thetabenum.\label{\theletternum:#1}}
from the second argument in the call to \foo
, the error
disappears. These two changes are different, but they both involve a
parameter character.
Alternatively, leaving in that line, but doubling the parameter character from # to ## also makes the error go away. I.e.
\renewcommand{\nextnuml}[1]{\refstepcounter{tabenum}\thetabenum.\label{\theletternum:##1}}
This seems similar to the situation where defining a macro inside the definition of another macro requires doubling the parameter character, and the error is similar. But as far as I can tell, this is the (re)definition of a macro inside a macro invocation, so not the same thing.
Doubling the parameter character takes care of the error, as already said, but of course I'd like to know what is going on here.
Running a trace does not enlighten me, though it does produce
<argument> ...etabenum .\label {\theletternum :##1
}} Text
\reserved@a #1#2->#1
The file follows.
% 12pt default for scrlttr2
\documentclass{scrlttr2}
\newcommand{\nextnuml}[1]{\refstepcounter{tabenum}\thetabenum.\label{#1}}
% \NewDocumentCommand{\foo}{m +m}
% {
% #2
% }
\NewDocumentCommand{\foo}{m +m}
{
\IfFileExists{./#1}{
#2
}{\PackageError{foo}{CONFIG FILE '#1' DOES NOT EXIST - NOT CREATING FORMLETTER}{Check that the config filename (first argument) has been correctly passed to \formletter}}
}
% Parameters for document commands
\newcommand{\addressesconfigfilename}{formletterbug.addresses.yaml}
\begin{filecontents}[overwrite,noheader]{\addressesconfigfilename}
foo
\end{filecontents}
\begin{document}
\newcounter{letternum}
\foo{\addressesconfigfilename}
{
\stepcounter{letternum}
\renewcommand{\nextnuml}[1]{\refstepcounter{tabenum}\thetabenum.\label{\theletternum:#1}}
Text
}
\end{document}
PS. When I was posting this, "Illegal parameter number in definition of \reserved@a" following \IfFileExists came up as a similar question. Since this also involves \IfFileExists
it's probably relevant. Though I don't understand Phelype's answer there.
\IfFileExists doesn't work like “usual” conditionals: it stores the true and false branches in macros, and uses them later.
More details, please. Does this correspond to defining a macro inside another macro? If not, why is the doubling necessary?
\newcommand
and\renewcommand
with appropriate checks around\def
. So\renewcommand
is at its core still\def
, just like\newcommand
.\IfFileExists
internally uses something like\def\next{#2}\next
(well,\expandafter\def\expandafter\reserved@a\expandafter{\reserved@a{#2}{#3}}\reserved@a
, with\reserved@a
being\@firstoftwo
or\@secondoftwo
). So you're doing\def\reserved@a{\renewcommand\nextnuml[1]{...#1}}
and that errs.##1
in the replacement text of\nextnuml
. And also to avoid lots of spurious spaces in your code. But you also want to expand\theletternum
…