11

I have this code on my hard disk and now I would like to understand it. Firstly I would like to know if this code is correct and logic or if there is another way to do the same thing.

\documentclass{article}
\usepackage{fp}

\newcommand*\macro[2][]{%
  Option : #1\par % print the option in #1
  \let\y #2 % to keep 
\begingroup
  \catcode`\(=1
  \catcode`\)=2
  \macrobis
}
\newcommand*\macrobis[1]{%
\endgroup
\scantokens{\def\temp{#1}}}

\begin{document}

\def\fct{x*x}

\macro[op]{\fct}(exp(1))

\FPeval\x{\temp}%
\FPeval\img{\y}%
x = \x\ donne  y = \img

\end{document}

\begingroup and \endgroup are here, I suppose, because the code changes the catcodes but tha call of macrobis is very strange. Where is the argument ? Can someone explain this code?

Alain Matthes
  • 95,075

2 Answers2

10

Let's see one command at a time:

\newcommand*\macro[2][]{%
  Option : #1\par % print the option in #1
  \let\y #2 % to keep 
\begingroup
  \catcode`\(=1
  \catcode`\)=2
  \macrobis
}

\macro has one optional argument (default empty) and a mandatory one. It assumes that the mandatory argument is one token, as it does \let\y#2 (but will leave a space in the input stream). Then it opens a group where it sets ( and ) as delimiters just like { and }; after this it calls \macrobis.

\newcommand*\macrobis[1]{%
\endgroup
\scantokens{\def\temp{#1}}}

\macrobis gathers its argument considering ( and ) as braces. Then it ends the group, so ( and ) return to their previous status and defines \temp to expand to #1 but inside \scantokens so the possible ( and ) characters in #1 will be rescanned in this setting where they are not delimiters any more.

What appears to be a parenthesized second mandatory argument to \macro is actually the argument to \macrobis, but this is not relevant from a user's point of view.

The point is to hide possible parentheses in that argument: if one defined

\newcommand*\macro[2][]{%
  Option : #1\par % print the option in #1
  \let\y #2 % to keep 
  \macrobis}
\def\macrobis(#1){\def\temp{#1}}

then an input such as \macro[op]{\fct}(exp(1)) would interpret exp(1 as the argument to \macrobis, which would be wrong.

egreg
  • 1,121,712
3

As far as I interpret it, macros (or control sequences) could be considered "replacements" for larger constructs (here "larger constructs" refers to the macro contents). As such, \macro gobbles \macro[op]{\fct} since it requires 2 arguments, does some magic, and replaces it with \macrobis. Still left in the input steam is (exp(1)) with the category codes changed for ( and ) to group beginning and endings, respectively. So, effectively you're left with \macrobis{exp(1)}, which represents valid input for \macrobis, since it requires a single argument.

On a related note, consider the following. \FPeval is a macro that takes two arguments as is evident from \show\FPeval:

> \FPeval=macro:
#1#2->\FP@eval {#1}{#2}.

However, if you define

\newcommand{\myfunc}{\FPeval}

where \myfunc now takes no arguments, and use

\myfunc\x{\temp}%
\myfunc\img{\y}%
x = \x\ donne  y = \img

you'll get the same output, illustrating the idea behind replacement.

Werner
  • 603,163