在 Verbatim 选项中使用宏时出现 fancyvrb 错误

在 Verbatim 选项中使用宏时出现 fancyvrb 错误

在环境中使用该firstnumber=...选项时,我发现与宏有关的奇怪行为差异。以下内容没有问题:Verbatimfancyvrb

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

但以下给出! Missing number, treated as zero错误

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

commandchars=\\\{\}选项没有区别。)原因是什么?我找到了一种解决方法,\fvset{firstnumber=last}如果我想的话可以使用(或明确替换\foolast,但我想学习。

这是一个最小的工作示例:

\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}

(我没有写,commandchars=\\\{\}因为没什么区别。)错误信息是:

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

答案1

相关代码定义在,fancyvrb.sty其中firstnumberkey定义如下:

\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}

以下是仅包含必要部分的精简版本:

\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定义为参数 to 的值firstnumber( #1),\@tempb定义为last。现在让我们考虑这两种情况:

  1. firstnumber=last:在这种情况下,我们有\def\@tempa{last}与 基本相同的\def\@tempb{last}。当\ifx\@tempa\@tempb展开时,\ifx将比较后面的两个标记。如果它们是控制序列,则如果它们是相同的原始命令,或者具有相同的参数文本、相同的替换文本以及相同的修饰符(如 ),则两者都被视为相等。\long这里的参数对于\@tempa和是相同的\@tempb(它们没有任何参数),它们的替换文本也是相同的(last),并且两者都缺少任何修饰符。在这种情况下, 的测试\ifx被认为是肯定的,并且以下赋值\let\FV@SetLineNo\relax是最终扩展。(在某个时候\FV@SetLineNo调用 来设置新块的行号。然后定义\relax不会做任何更改。)

  2. firstnumber=\foo:现在第一个参数是\foo,而 的定义\@tempa变为\def\@tempa{\foo},而\@tempb仍然是last。由于\ifx在比较两个宏时不进行完全展开,因此要比较的替换文本现在是 和\foolast它们是不是与之前相同。因此,结果为负数,\else部分成为最终扩展。再次\FV@SetLineNo定义,但现在我们\c@FancyVerbLine#1在其中找到赋值,它将(整数)计数器设置\c@FancyVerbLine为第一个参数的值\foo。在某个时候,这个宏被展开,导致赋值不是以数字开头,而是以 from 开头llast这正是您在错误消息中看到的错误。

这也解释了为什么不同的值commandchars在这里没有任何影响,而\def\foo{2}另一方面却可以正常工作。

相关内容