マクロツイーター

はてダから移行した記事の表示が崩れてますが、そのうちに直せればいいのに(えっ)

暗黙的な波括弧は波括弧か波括弧でないか (2)

前回の続き)

前回は、「暗黙的な波括弧」である \bgroup\eggroup が「明示的な波括弧」である {} の代替となるかならないかという話をした。しかし、この話が意味を持つためには、そもそも「暗黙的な波括弧で代替する」ことのメリットが存在することが前提になる。ここではそういう実例を考えてみる。

LaTeX の命令 \fbox{<テキスト>} は引数のテキストを実線の枠で囲ったものを出力する。

\fbox{Happy {\TeX}ing!}

ところが、この引数は「TeX マクロの引数」に相当するので、\verb 等の「カテゴリコードの変更を利用する」命令を含めることができない。

\fbox{Happy \verb|(T_T)| {\TeX}ing!} %==>エラー

LaTeX\fbox 命令をそのまま使って \verb を含むテキストを枠で囲むような TeX コードは割と容易に作れる。次のようにボックスレジスタに一旦中身を入れてそれを \fbox に渡せばよい。((\fbox の引数の \verb がダメで \hbox ならよい理由は、「\hbox{ } はマクロの引数ではない」からである。))

\setbox0=\hbox{Happy \verb|(T_T)| {\TeX}ing!}
\fbox{\box0}

それでは、この構成を利用して、「\verb が可能な \fbox」の機能を LaTeX に提供するにはどうすればよいか。

\newcommand\myfbox[1]{%
  \begingroup % レジスタ代入の局所化のため
    \setbox0=\hbox{#1}%
    \fbox{\box0}%
  \endgroup
}
\myfbox{Happy \verb|(T_T)| {\TeX}ing!} %==>エラー

もちろん、これでは \verb が結局マクロ(\myfbox)の引数になっているのでダメである。こういう場合は、命令ではなく環境の形で定義するのが常道である。*1環境として実装した場合の使用形式を考えよう。

\begin{myfbox}%
  Happy \verb|(T_T)| {\TeX}ing!%
\end{myfbox}

これと先述の「構成」を見比べると、次のような定義を行えばよいことが判る。(局所化の処理は \begin\end のところで自動的に行われる。)

\myfbox    → \setbox0=\hbox{
\endmyfbox → }\fbox{\box0}

ところが、ここで問題になるのは、これをそのまま \def\myfbox{\setbox0=\hbox{}

のようにはできないことである。これだと最後の } が直前の { と対応することになり、定義文が終結しない。要するに、マクロ定義の本体には { } の対応が崩れたトークン列を入れることはできないのである。

しかしここで \hbox の波括弧は暗黙でもよかったことを思い出すと解決できる。すなわち、次のように、暗黙の波括弧を用いて定義すればよい。

\def\myfbox{\setbox0=\hbox\bgroup}
\def\endmyfbox{\egroup\fbox{\box0}}

実用的にするにはこれに「先頭・末尾の空白の除去」「color パッケージへの対応」等の対策を入れる必要がある。最終的には以下のようなコードになる。

\documentclass{article}
\usepackage{color}
\pagestyle{empty}
\makeatletter %!!!!!!!!!!!!!!!!!
\newenvironment{myfbox}{%
  \setbox0=\hbox\bgroup
    \color@setgroup
    \ignorespaces
}{%
    \unskip
    \color@endgroup
  \egroup
  \fbox{\box0}%
}
\makeatother  %!!!!!!!!!!!!!!!!!
\begin{document}
$\rightarrow$
\begin{myfbox}
\color{red}Happy \verb|(T_T)| {\TeX}ing!
\end{myfbox}
$\leftarrow$
\end{document}

特に苦労することなく完成したが、これは「\hbox の波括弧は両側とも暗黙のトークン(\bgroup\egroup)で代替できる」という性質があったからである。代替できない用法について同様の構成をしようとすると面倒なことになる。

(まだ続くはず)

*1:ただし、この場合は、トリックを使えば命令の形で定義することも可能である。