When you say:
\newmacro\testmacro[1]{foo --- #1 ---}
You end up with:
\def\testmacro{\macro@write{\testmacro}{[1]{foo --- #1 ---}}}}
So you try to define a macro without any arguments but still use #1
in it. This leads to the Illegal parameter number
error message.
In order to permit #1
, #2
, etc. you would need to define the macro with the right number of arguments. You can define the macro first with nine arguments to avoid any Illegal parameter number
error. Then you expand it with ##1
etc. as arguments, so you basically replace #1
with ##1
, etc., and define this to the same macro but without arguments. Because all this happens inside another macro \newmacro
all #
must be doubled:
\def\newmacro#1[#2]#3{%
\def#1##1##2##3##4##5##6##7##8##9{\macro@write{#1}{[#2]{#3}}}% Define macro in a safe way
\expandafter\def\expandafter#1\expandafter{#1{####1}{####2}{####3}{####4}{####5}{####6}{####7}{####8}{####9}}% Replace `#1` with `##1` etc.
}
Then, however, you have the issues of ##
in your output file. This can be best avoided by again defining the macro with nine arguments and print the \meaning
with the prefix stripped, before defining it to its true definition:
\def\macro@write#1#2{%
\def#1##1##2##3##4##5##6##7##8##9{#2}%
\immediate\write\macro@outfile{\string\renewcommand\string#1\expandafter\strip@prefix\meaning#1}%
\renewcommand#1#2%
#1%
}
The \jobname.macros
files then holds:
\renewcommand\testmacro[1]{foo(#1)}
\renewcommand\testmacro[1]{foo --- #1 ---}
However, this breaks when you now use ##1
inside the macro definition, e.g:
\newmacro\testmacro[1]{foo --- #1 ---\def\A##1{(##1)}}
So instead you would recommend the following approach: Define the macro to a different name and copy that definition to the real name inside \macro@write
. You avoid thereby all issues with escaping of macro arguments.
You can use \csname
with \string#1
to build a second macro name which is unique to the official macro name.
\documentclass{article}
\makeatletter
\newwrite\macro@outfile
\immediate\openout\macro@outfile=\jobname.macros%
\typeout{Writing extra macros to file \jobname.macros}%
\def\newmacro#1[#2]#3{%
\expandafter\newcommand\csname @\string#1\endcsname[#2]{#3}%
\newcommand#1{\macro@write{#1}{#2}}%
}
\def\macro@write#1#2{%
\expandafter\let\expandafter#1\csname @\string#1\endcsname
\expandafter\let\csname @\string#1\endcsname\@undefined
\immediate\write\macro@outfile{\string\newcommand\string#1[#2]{\expandafter\strip@prefix\meaning#1}}%
#1%
}
\makeatother
\begin{document}
\newmacro\testmacroa[1]{foo(#1)}
\testmacroa{1}
\testmacroa{2}
\newmacro\testmacrob[1]{foo --- #1 ---}
\testmacrob{3}
\testmacrob{4}
\newmacro\testmacroc[1]{foo --- #1 ---\def\A##1{(##1)}}
\testmacroc{3}
\testmacroc{4}
\end{document}
I took the liberty to replace \renewcommand
with \newcommand
because its seems to be more logically for a \newmacro
macro. If you really want \renewcommand
, i.e. allow \newmacro
to redefine its macro, then define \newmacro
like:
\def\newmacro#1[#2]#3{%
\expandafter\let\csname @\string#1\endcsname\empty
\expandafter\renewcommand\csname @\string#1\endcsname[#2]{#3}%
\def#1{\macro@write{#1}{#2}}%
}
The first line ensures that the macro exists in any case before \renewcommand
is used.
With \newcommand
and \renewcommand
you have to use \csname...\endcsname
, with some \expandafter
to build the control sequence before \newcommand
or \renewcommand
comes into action:
\newcommand{\mkMac}[1]{%
\expandafter\newcommand\csname the#1\endcsname{%
Call the macro \texttt{\expandafter\string\csname #1\endcsname}!%
}%
\expandafter\newcommand\csname #1\endcsname[1]{%
\expandafter\renewcommand\csname the#1\endcsname{##1}%
}%
}
\mkMac{affiliation}
\show\theaffiliation
\show\affiliation
\affiliation{University}
\show\theaffiliation
\stop
This is the output on the terminal when running the example (\stop
is just to end the run):
This is pdfTeX, Version 3.1415926-2.5-1.40.14 (TeX Live 2013)
restricted \write18 enabled.
entering extended mode
(./mkmak.tex
LaTeX2e <2011/06/27>
Babel <3.9f> and hyphenation patterns for 78 languages loaded.
> \theaffiliation=\long macro:
->Call the macro \texttt {\expandafter \string \csname affiliation\endcsname }!.
l.11 \show\theaffiliation
?
> \affiliation=\long macro:
#1->\expandafter \renewcommand \csname theaffiliation\endcsname {#1}.
l.12 \show\affiliation
?
> \theaffiliation=\long macro:
->University.
l.14 \show\theaffiliation
?
)
No pages of output.
Transcript written on mkmak.log.
So \mkMak{affiliation}
defines a temporary value for \theaffiliation
and the macro \affiliation
; the call \affiliation{University}
redefines \theaffiliation
to University
.
Best Answer
You can't do like that. The definition of
\myParagraphs
doesn't use#2
; sobecomes
and so TeX reads your file, where
#2
is illegal. Here's a way: define a temporary macro to expand to the value of#2
: