0

When using the firstnumber=... option in the Verbatim environment of fancyvrb, I found strange behavioral difference involved with macros. The following has no problem:

\def\foo{2}
\begin{Verbatim}[firstnumber=\foo]
line 2
\end{Verbatim}

but the following gives ! Missing number, treated as zero error

\def\foo{last}
\begin{Verbatim}[commandchars=\\\{\},firstnumber=\foo]
line 2
\end{Verbatim}

(The commandchars=\\\{\} option makes no difference.) What would be the reason? I found a walk-around of using \fvset{firstnumber=last} if I want (or replacing \foo with last explicitly), but I would like to learn.

Here is a minimal working example:

\documentclass{article}
\usepackage{fancyvrb}
\begin{document}

\fvset{numbers=left}
\begin{Verbatim}
line 1
\end{Verbatim}

\def\foo{2}
\begin{Verbatim}[firstnumber=\foo]
line 2
\end{Verbatim}

%% problem HERE
\def\foo{last}
\begin{Verbatim}[firstnumber=\foo]
line 3
\end{Verbatim}

\end{document}

(I didn't write commandchars=\\\{\} because it makes no difference.) The error message is:

! Missing number, treated as zero.
<to be read again> 
                   l
l.18 line 3

1 Answer 1

1

The relevant code is defined in fancyvrb.sty where the firstnumber key is defined like the following:

\define@key{FV}{firstnumber}[auto]{%
  \def\@tempa{#1}\def\@tempb{auto}%
  \ifx\@tempa\@tempb
    \def\FV@SetLineNo{%
      \c@FancyVerbLine\FV@CodeLineNo
      \advance\c@FancyVerbLine\m@ne}%
  \else
    \def\@tempb{last}%
    \ifx\@tempa\@tempb
      \let\FV@SetLineNo\relax
    \else
      \def\FV@SetLineNo{\c@FancyVerbLine#1}%
    \fi
  \fi}

Here a reduced version with the essential parts only:

\define@key{FV}{firstnumber}[auto]{%
  \def\@tempa{#1}%
  \def\@tempb{last}%
  \ifx\@tempa\@tempb
    \let\FV@SetLineNo\relax
  \else
    \def\FV@SetLineNo{\c@FancyVerbLine#1}%
  \fi}

\@tempa is defined to the value of the parameter to firstnumber (#1), \@tempb is defined to be last. Now let's consider both cases:

  1. firstnumber=last: In this case we have \def\@tempa{last} which is basically the same as \def\@tempb{last}. When \ifx\@tempa\@tempb is expanded, the two tokens following \ifx are compared. If they are control sequences, both are considered equal if they are the same primitive command, or have the same parameter text, the same replacement text as well as the same modifiers like \long. The parameters are the same here for \@tempa and \@tempb (they don't have any), their replacement text is also the same (last), and any modifiers are also missing for both. In this case the test for \ifx is considerd positive and the following assignment \let\FV@SetLineNo\relax is the final expansion. (At some point \FV@SetLineNo is called to set the line number for the new block. The definition \relax doesn't do any changes then.)

  2. firstnumber=\foo: Now the first parameter is \foo and the definition for \@tempa becomes \def\@tempa{\foo} while \@tempb is still last. As \ifx doesn't do a full expansion when comparing both macros, the replacement texts to be compared are now \foo and last which are not the same as before. Accordingly, the result is negative and the \else part becomes the final expansion. Again, \FV@SetLineNo is defined but now we find the assignment \c@FancyVerbLine#1 in it, which sets the (integer) counter \c@FancyVerbLine to the value of the first parameter \foo. At some point this macro is expanded leading to an assignment that doesn't start with a number but with the lfrom last. And this is exactly the error you see reported in the error message.

That's also the explanation why different values for commandchars don't have any effect here, and why \def\foo{2} on the other hand works fine.

1
  • Wow! Thanks for your clear and detailed answer! So the problem will be gone if \expandafter is used somewhere properly.
    – chan1142
    Oct 23, 2016 at 5:59

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .