文件内容奇怪的编码

文件内容奇怪的编码

当查看filecontents文件中的环境latex.ltx(或中的类似版本filecontents.sty)时,我发现了这段我无法理解的代码:

  \edef\E{\@backslashchar end\string{\@currenvir\string}}%
  \edef\reserved@b{%
    \def\noexpand\reserved@b%
         ####1\E####2\E####3\relax}%
  \reserved@b{%
    \ifx\relax##3\relax%
      \immediate\write\reserved@c{##1}%
    \else%
      \edef^^M{\noexpand\end{\@currenvir}}%
      \ifx\relax##1\relax%
      \else%
          \@latex@warning{Writing text `##1' before %
             \string\end{\@currenvir}\MessageBreak as last line of #1}%
        \immediate\write\reserved@c{##1}%
      \fi%
      \ifx\relax##2\relax%
      \else%
         \@latex@warning{%
           Ignoring text `##2' after \string\end{\@currenvir}}%
      \fi%
    \fi%
    ^^M}%
  \catcode`\^^L\active%
  \let\L\@undefined%
  \def^^L{\expandafter\ifx\csname L\endcsname\relax\fi ^^J^^J}%
  \catcode`\^^I\active%
  \let\I\@undefined%
  \def^^I{\expandafter\ifx\csname I\endcsname\relax\fi\space}%
  \catcode`\^^M\active%
  \edef^^M##1^^M{%
    \noexpand\reserved@b##1\E\E\relax}}%

此环境用于在文件中写入一些文本。将所有 catcode 转换为 12 个字符后,使用命令将文本写入文件中\reserved@b。我对这个编码有很多困扰:

  1. 为什么有一些递归编码?

    \edef\reserved@b{%
        \def\noexpand\reserved@b%
             ####1\E####2\E####3\relax}%
    
  2. 参数分隔符的作用是\E什么 \end{filecontents}

  3. 为什么行尾 ( ^^L) 被转换成 \end{filecontents}

任何有关此代码中使用的精细技巧的帮助都将不胜感激。

答案1

按顺序回答这三个问题:

从历史上看,可用的宏名称数量非常有限。因此,反复使用相同的名称很有用。在 LaTeX 内核中,\reserved@a等仅供团队使用\@tempa(请参阅哪些宏应该用作“临时空间”?@tempdima,reserved@a,@tempcnta,还有什么?了解详细信息)。片段

\edef\reserved@b{%
    \def\noexpand\reserved@b%
         ####1\E####2\E####3\relax}%

用作\reserved@b一次性宏来\reserved@b以不同的方式定义:可以用不同的名称来完成,并且不是递归。这个想法是我们需要\edef“某些东西”来正确设置\reserved@b

\E这很好地引出了第二个问题。在上面,

\edef\E{\@backslashchar end\string{\@currenvir\string}}

因此,当它扩展时,我们会被\E替换\end{<envname>}。这用于创建\reserved@b看起来像

> \reserved@b=macro:
->\def \reserved@b ####1\end{<envname>}####2\end{<envname>}####3\relax .

正如您所看到的,这\edef意味着它\E不再存在:它是另一个一次性的宏名称,可以使用其他东西来完成。

的奇怪定义^^L是允许从扩展上下文中的设置生成警告消息。我们稍后会

\gdef\endfilecontents{|
  \immediate\closeout\reserved@c
  \def\T##1##2##3{|
  \ifx##1\@undefined\else
    \@latex@warning@no@line{##2 has been converted to Blank ##3e}|
  \fi}|
  \T\L{Form Feed}{Lin}|
  \T\I{Tab}{Spac}|
  \immediate\write\@unused{}}

这意味着如果\L定义了,就会出现警告。但如何定义\L?已经完成了

\def^^L{\expandafter\ifx\csname L\endcsname\relax\fi ^^J^^J}%

由于\csname会将未定义的控制序列转换为\relax,这让我们可以设置一个“标志”,表示即使换行发生在 中,也可以看到换行\write。(我们在expl3一般形式中有一个类似的技巧。)

相关内容