\section は引数をとらない?

この記事は、TeX & LaTeX Advent Calendar 2014 の第 9 日目のために書いたものです。

12/8 のご担当は Acetaminophen さんで、12/10 のご担当は tattsan さんです。

【追記】
[2014-01-02] 以降の jsclasses では、目次関係のマクロ部分に tattsan さんによるパッチが取り込まれています。話が複雑になるのを避けるため、今回の記事ではその件については触れませんでしたが、目次の体裁について真面目に考える場合には、当時の TeX Forum の議論 も是非ご参照ください。 [Added: Dec 10, 2014.]

【追記】
Advent Calendar の一記事としてこのページにいらしたのではなくて、検索などでこのページを見つけられた方がもしいらっしゃいましたら、第 15 日目の北川さんの記事 も併せてお読みになられることをお勧めいたします。北川さんの記事では、私が説明を逃げた \futurelet の使用例ですとか、おしまいでチラっと口走ったいわゆる “anatomy of TeX” についても、きちんとご説明がなされています。 [Added: Dec 16, 2014.]

少し長めの言い訳とお詫び

私が LaTeX に手を出したのは、「ドイツ語の文章の行末で自動的にハイフネーションをしたかったから」 という変な理由なので、もともと数学も出来ませんし、プログラミングもまったく知らないので、毎年一人だけあさっての方向を向いた記事を書かせていただいております。

そのうえ、使い始めて数年目の時点で知識が止まってしまっていて、結局その頃の初級レベルから一歩も出ることなく、今日に至ってしまいました。なので、\expandafter で展開の順番を変えるなんていう難しいことは分かりませんし、パッケージについての情報も、最近はさっぱりフォローできていません (すいません)

そんなお粗末な有り様も省みず今年は何の記事を書かせていただいたかと言いますと、「展開の順番を愚直に追ってみた」 話です (前に一度書いたことがあるものの焼き直しです…)。既に標題で内容がばれてしまっていますので、中級以上の方にとっては、「\section 自体は引数をとらない」 などというのは 「そんな当然のことを何で今更」 と思われるでしょうし、逆に、“最近 LaTeX 始めました” というような方であれば、「\section は必須引数を一つとオプション引数を一つとるコマンドのはずだが?」 と訝しがられるかも知れません。

本記事には、“ネタ” 的要素はまったく含まれてなくて、中級以上のみなさんにとっては 「当たり前」 のことしか書いてないのですけれど、こんなものでも、もしも私と同じ文系ユーザーの方が、これから各種 dtx ファイルや source2e.pdf などを読もうとされる場合には、何かしら参考になることもあるかも知れません。

それにつけても、毎度のこととはいえ、私の番になると途端に話のレベルがガクンと下がってしまって、申し訳ない限りです。

I. 話の準備
   (1) 基本的な仕組み
      (a) 実は引数をとらない \cmdA
      (b) \cmdA が引数をとるけれど
   (2) もうちょっとだけ用意
      (a) 引数は捨ててもいい
      (b) \@dblarg\@ifnextchar
      (c) \@ifstar
II. 具体例
   (1) \section の場合
   (2) \l@section の場合

Since: December 8, 2014.


I. 話の準備

II. が本論なのですが、その前にまず、基本的なパターンと、いくつかのコマンドの動きについて、予め押さえておきたいと思います。

(1) 基本的な仕組み

(a) 実は引数をとらない \cmdA

原稿中に、

\cmdA{argA}

というのが出てきた場合、素朴に考えますと、この “\cmdA” は、引数を一つとるマクロとして:

\newcommand{\cmdA}[1]{#1}

とか

\def\cmdA#1{#1}

みたいに定義されていることが予想されます。

ところが、ここで、\cmdA が:

\newcommand{\cmdA}{\cmdB{argB}}
\newcommand{\cmdB}[2]{#2, #1}

とか

\def\cmdA{\cmdB{argB}}
\def\cmdB#1#2{#2, #1}

のように定義されていることがあります。

この場合、\cmdA は、“\newcommand{\cmdA}{\cmdB{argB}}” という定義を見れば分かりますように、引数はとらずに、単純に “\cmdB{argB}” に置き換わることになります。その後、“{argA}” は、\cmdB の二つ目の引数として、受け取られます:

\cmdA{argA} some text...
 ↓
 ↓ \cmdA は引数をとらないので \cmdA のみが取り去られる({argA} はそのママ)
 ↓
\cmdA{argA} some text...
 ↓
 ↓ \cmdA の定義にしたがい \cmdA の代わりに \cmdB{argB} が入る
 ↓
\cmdB{argB}{argA} some text...
 ↓
 ↓ \cmdB は引数を二つとるので \cmdB{argB}{argA} が取り去られる
 ↓
\cmdB{argB}{argA} some text...
 ↓
 ↓ \cmdB の定義に引数それぞれを当てはめたものが入る
 ↓
argA, argB some text...

なんでこんな面倒なことをするのかと思われるかも知れませんけれど、これは多分、\cmdA の見掛け上の引数 (ここでは “argA”) はユーザーに入力してもらって、他方 \cmdA の実体である) \cmdB に必要なパラメータ (ここでは “argB ”) については、マクロの作成者なりクラスファイル作成者なりが値を指定できるように、両者を分離しているのではないかと思います。

全然面白くない例ですけど、たとえば:

\newcommand{\cmdFoo}{\cmdFrame{3cm}{l}}
\newcommand{\cmdBar}{\cmdFrame{5cm}{c}}
\newcommand{\cmdBaz}{\cmdFrame{7cm}{r}}
\newcommand{\cmdFrame}[3]{\framebox[#1][#2]{#3}}

\cmdFoo{arg1}\par
\cmdBar{arg2}\par
\cmdBaz{arg3}\par

とすると、それぞれ引数を一つとるようにみえている \cmdFoo\cmdBar\cmdBaz は実際は引数をとらず、\cmdFrame にとって必要な三つの引数のうち二つを引き連れた \cmdFrame と置き換わることになり、そこで予めパラメータに値を与えておくことができるようになるわけです。

(b) \cmdA が引数をとるけれど

今みた (a) では、\cmdA がまったく引数をとらない場合を考えましたが、そうではなくて、\cmdA が引数をとるのだけれど、見掛け上のその引数の個数と、\cmdA の定義上の引数の個数とが異なる、という場合もよくあります。どういうことかと言いますと、例えば、原稿中に、

\cmdA{arg1}{arg2}

というのが出てきたとしたら、見掛けの上では、\cmdA は引数を二つとるマクロとして定義されていそうに思えます。しかし、ここで:

\newcommand{\cmdA}[1]{\cmdB{#1}}
\newcommand{\cmdB}[2]{#1, #2}

と定義されているとしたら、どうでしょう。

この場合、\cmdA は引数を一つとって、それを下請けの \cmdB に、\cmdB の一つ目の引数として渡すので、\cmdA{arg1} が、\cmdB{arg1} に置き換わり、それから、{arg2} は、\cmdB の二つ目の引数として受け取られます:

\cmdA{arg1}{arg2} some text...
 ↓
 ↓ \cmdA は引数を一つとるので \cmdA{arg1} が取り去られる
 ↓
\cmdA{arg1}{arg2} some text...
 ↓
 ↓ \cmdA の定義にしたがい \cmdA{arg1} の代わりに \cmdB{arg1} が入る
 ↓
\cmdB{arg1}{arg2} some text...
 ↓
 ↓ \cmdB は引数を二つとるので \cmdB{arg1}{arg2} が取り去られる
 ↓
\cmdB{arg1}{arg2} some text...
 ↓
 ↓ \cmdB の定義に引数それぞれを当てはめたものが入る
 ↓
arg1, arg2 some text...

これまた、なんでこんな面倒なことを、と思われるかと思いますが、次の (2) で取り上げる \@dblarg\@ifstar の内部では、この仕組みが使われています。

(2) もうちょっとだけ用意

II. での話を理解しやすくするために、いくつかのコマンドについても、ここで先に取り上げておきます。

(a) 引数は捨ててもいい

例えば:

\newcommand{\cmd}[5]{<definition>}

と定義されているとき、この \cmd は引数を五つとるわけですから、使うときには:

\cmd{arg1}{arg2}{arg3}{arg4}{arg5}

という風な形になります (当たり前ですよね)。ここで、上の <definition> の部分で、#1#5 が使われていればこそ、arg1arg5 は何らかの役割を果たせるわけですが、もしも <definition> の部分で使われていない番号の引数があったとしたら、その引数はただ捨てられてしまう (飲み込まれてしまう) ことになります。

【補足】
実際、LaTeX には、引数一つをただ飲み込んでしまう \@gobble とか、二つ飲み込んでしまう \@gobbletwo、また、二つの引数のうちの二つ目を捨てて一つ目だけを戻す \@firstoftwo とか、逆に一つ目の引数を捨てて二つ目だけを戻す \@secondoftwo なんていうコマンドが予め用意されています。例えば、\@firstoftwo の定義は、こんな感じです:

\long\def\@firstoftwo#1#2{#1}
(b) \@dblarg\@ifnextchar

\@dblarg は、その名のとおり、引数をダブルにするコマンドです。

\@dblarg はその内部で \@ifnextchar を使っているのですが、\@ifnextchar の仕組みを理解するには \futurelet とか、スペースを読み飛ばすための再帰的処理とかについての知識が必要になって、あまり初級向きではないので、ここではひとまず \@ifnextchar のはたらきについてだけ触れて、それから \@dblarg のはたらきについてみることにします。

\@ifnextchar は引数を三つとって、三つ目の引数の “次の (空白ではない) 文字” が、一つ目の引数と一致する場合には、二つ目の引数を戻して、一致しない場合には、三つ目の引数を戻す、というものです。例えば:

\newcommand{\bangornot}{\@ifnextchar!{yes}{no}}

と定義した場合、この \@ifnextchar の一つ目の引数は “!” で、二つ目の引数は “yes”、三つ目の引数は “no” です。

ここで \bangornot の次が “!” のときは:

\bangornot!
 ↓
 ↓ \bangornot がその定義と置き換わる
 ↓
\@ifnextchar!{yes}{no}!
 ↓
 ↓ \@ifnextchar は引数を三つとるので \@ifnextchar!{yes}{no} が取り去られる
 ↓
\@ifnextchar!{yes}{no}!
 ↓
 ↓ \@ifnextchar の一つ目の引数(!)と、後続の ! が一致するので、二つ目の引数(yes)が戻される
 ↓
yes!

という風になり、もしも \bangornot の次が “!” でないときは:

\bangornot?
 ↓
 ↓ \bangornot がその定義と置き換わる
 ↓
\@ifnextchar!{yes}{no}?
 ↓
 ↓ \@ifnextchar は引数を三つとるので \@ifnextchar!{yes}{no} が取り去られる
 ↓
\@ifnextchar!{yes}{no}?
 ↓
 ↓ \@ifnextchar の一つ目の引数(!)と、後続の ? が一致しないので、三つ目の引数(no)が戻される
 ↓
no?

となります。

以上のようなはたらきをする \@ifnextchar を内部で使っている \@dblarg は、引数を一つとって、その後ろが “[” である場合には、引数をそのまま戻して、“[” でない場合には、\@dblarg の引数を戻した次に、後続の引数をコピーして “[ ]” に入れたものを置きます。どういうことかと言いますと、

[” があるときには:

\@dblarg{\cmd}[argB]{argA}
 ↓
 ↓ \@dblarg は引数を一つとるので、まず、\@dblarg{\cmd} が取り去られる
 ↓
\@dblarg{\cmd}[argB]{argA}
 ↓
 ↓ 次が“[”なので、\@dblarg の引数(\cmd)が戻される
 ↓
\cmd[argB]{argA}

となり、他方、“[” がないときには:

\@dblarg{\cmd}{argA}
 ↓
 ↓ \@dblarg は引数を一つとるので、まず、\@dblarg{\cmd} が取り去られる
 ↓
\@dblarg{\cmd}{argA}
 ↓
 ↓ 次が“[”でないので、後続の argA をコピーして [] に入れたものを、\@dblarg の引数(\cmd)を戻した次に入れる
 ↓
\cmd[argA]{argA}

という風になります。

【補足】
この説明はさすがに乱暴過ぎで、実際は、“[” でないときには、上で述べた I. (1) (b) の場合のように、引数を二つとる下請けのマクロに処理を渡すことで、後続の引数を取得してコピーしています:

\long\def\@dblarg#1{\kernel@ifnextchar[{#1}{\@xdblarg{#1}}}
\long\def\@xdblarg#1#2{#1[{#2}]{#2}}

※ ここに出てくる “\kernel@ifnextchar” は、\@ifnextchar と同じものです。

(c) \@ifstar

\@ifstar は、これまたその名のとおり、“*” の有無によって処理を分岐するコマンドです \@ifstar もその内部では \@ifnextchar を使っています)

\@ifstar は、(見掛け上) 引数を二つとって、その後ろに “*” がある場合には、“*” を取り除いた上で一つ目の引数を戻して、“*” がない場合には、二つ目の引数を戻します。

つまり、“*” があるときには:

\@ifstar{\cmdA}{\cmdB}*{arg}
 ↓
 ↓
 ↓
\cmdA{arg}

となり、“*” がないときには:

\@ifstar{\cmdA}{\cmdB}{arg}
 ↓
 ↓
 ↓
\cmdB{arg}

となるわけです。

【補足】
LaTeX2.09 のときの \@ifstar は:

\def\@ifstar#1#2{\@ifnextchar *{\def\@tempa*{#1}\@tempa}{#2}}

と定義されていましたので、\@ifstar は、かつては見掛け上ではなく実際に引数を二つとるマクロで、“*” は、ご覧のように、\def のパターンマッチで取り除いていました。ただ、こうすると、“\def\@tempa*{#1}” の部分が、“\def の中の \def” になってしまって、引数をとる場合に “#” の扱いが面倒になります。そこで、LaTeX2e では、\@ifstar は以下のように定義され直されています:

\def\@ifstar#1{\@ifnextchar *{\@firstoftwo{#1}}}

LaTeX2.09 のころの定義だと、直感的にも理解しやすかったと思いますが、この LaTeX2e での \@ifstar の定義は、上で述べた I. (1) (b) のパターンのようになっています。

つまり、現在の \@ifstar は、引数を一つとって、それを内部の \@ifnextchar の二つ目の引数 (の中の \@firstoftwo の一つ目の引数) として渡して、\@ifstar の見掛け上二つ目の引数は、実際は、内部の \@ifnextchar の三つ目の引数となっています。

展開を順に追ってみますと、“*” があるときには:

\@ifstar{\cmdA}{\cmdB}*{arg}
 ↓
 ↓ \@ifstar は引数を一つとるので \@ifstar{\cmdA} が取り去られる
 ↓
\@ifstar{\cmdA}{\cmdB}*{arg}
 ↓
 ↓ \@ifstar の定義にしたがって \@ifstar{\cmdA} の代わりに \@ifnextchar *{\@firstoftwo{\cmdA}} が入る
 ↓
\@ifnextchar *{\@firstoftwo{\cmdA}}{\cmdB}*{arg}
 ↓
 ↓ \@ifnextchar は引数を三つとるので \@ifnextchar *{\@firstoftwo{\cmdA}}{\cmdB} が取り去られる
 ↓
\@ifnextchar *{\@firstoftwo{\cmdA}}{\cmdB}*{arg}
 ↓
 ↓ * が一致するので、\@ifnextchar の二つ目の引数(\@firstoftwo{\cmdA})が戻される
 ↓
\@firstoftwo{\cmdA}*{arg}
 ↓
 ↓ \@firstoftwo は引数を二つとるので \@firstoftwo{\cmdA}* が取り去られる
 ↓
\@firstoftwo{\cmdA}*{arg}
 ↓
 ↓ \@firstoftwo は一つ目の引数(\cmdA)のみを戻す
 ↓
\cmdA{arg}

という風になり、他方、“*” がないときには:

\@ifstar{\cmdA}{\cmdB}{arg}
 ↓
 ↓ \@ifstar は引数を一つとるので \@ifstar{\cmdA} が取り去られる
 ↓
\@ifstar{\cmdA}{\cmdB}{arg}
 ↓
 ↓ \@ifstar の定義にしたがって \@ifstar{\cmdA} の代わりに \@ifnextchar *{\@firstoftwo{\cmdA}} が入る
 ↓
\@ifnextchar *{\@firstoftwo{\cmdA}}{\cmdB}{arg}
 ↓
 ↓ \@ifnextchar は引数を三つとるので \@ifnextchar *{\@firstoftwo{\cmdA}}{\cmdB} が取り去られる
 ↓
\@ifnextchar *{\@firstoftwo{\cmdA}}{\cmdB}{arg}
 ↓
 ↓ * が一致しないので、\@ifnextchar の三つ目の引数(\cmdB)が戻される
 ↓
\cmdB{arg}

となることになります。

II. 具体例

長々とした準備を終えましたので、ようやく本題に入れます。見掛け上の引数が、実は下請けのマクロの引数であったり、その下請けのマクロが必要とする個数の引数の一定数を引き連れて置き換わる話の例として、\section と、\l@section とを取り上げます。

(1) \section の場合

LaTeX を使うようになってしばらく経ちますと、誰もが一度は “\section” の定義を調べてみるんじゃないかと思います。でも、\section の巧妙な仕組み全体を解析するようなことは私の手に余りますので、ここでは、飽くまで 「\section の引数のとり方」 について、順を追って眺めてみたいと思います。

\section は、次のいずれかの形で使いますよね:

それで、素朴に考えると、\section は、引数を一つなり二つなりとるマクロとして定義されてるのかな、と思ったら実はそうじゃなかった、というのが、この記事の標題の意味です。

【補足】
ちなみに、 “\section*” というコマンドは実はなくて、この場合は、“\section” の後ろに “*” が続いている、という状態になります。“*” は 「英文字 (letter)」 ではなくて 「その他の文字 (other)」 なので、そのままではマクロ名の文字列に含めることができないからです。尤も、“\csname” と “\endcsname” のペアを使えば 「その他の文字」 もコントロールシーケンスの文字列に含めることができて、実際、環境名だと “figure*” とか “table*” が存在しますよね。

で、実際はどうなっているのかといいますと、例えば、article.cls をみてみますと、\section は次のように定義されています:

\newcommand\section{\@startsection {section}{1}{\z@}%
                                   {-3.5ex \@plus -1ex \@minus -.2ex}%
                                   {2.3ex \@plus.2ex}%
                                   {\normalfont\Large\bfseries}}

驚くべきことに、\section 自身は引数をまったくとらずに、六個の引数を引き連れた \@startsection とただ置き換わるだけです。

ここで、上述 I. (1) (a) の話を思い出して、「あ〜、それなら、\@startsection は引数を七個とるマクロであって、\section の見掛け上の引数は \@startsection の七個目の引数になるわけね!」 と考えられたとすると、それはちょっと早合点です。

なぜなら、\@startsection の定義は:

\def\@startsection#1#2#3#4#5#6{%
  \if@noskipsec \leavevmode \fi
  \par
  \@tempskipa #4\relax
  \@afterindenttrue
  \ifdim \@tempskipa <\z@
    \@tempskipa -\@tempskipa \@afterindentfalse
  \fi
  \if@nobreak
    \everypar{}%
  \else
    \addpenalty\@secpenalty\addvspace\@tempskipa
  \fi
  \@ifstar
    {\@ssect{#3}{#4}{#5}{#6}}%
    {\@dblarg{\@sect{#1}{#2}{#3}{#4}{#5}{#6}}}}

となっていて、\@startsection に必要な引数は六個なので、\section と置き換わった部分には、引数の不足はないからです。

\@startsection の定義にはいろいろな処理が含まれていますが、本記事では引数のとり方にのみ注目していますので、ここでは最後の三行についてだけ着目することにします。すなわち:

\@ifstar
  {\@ssect{#3}{#4}{#5}{#6}}%
  {\@dblarg{\@sect{#1}{#2}{#3}{#4}{#5}{#6}}}

となっていることから、I. (2) (c) でみましたように、\section の次に “*” がある場合には、“*” を取り除いた上でこの \@ifstar の一つ目の引数が戻され、“*” がない場合には、二つ目の引数が戻されることになります。

まず、“*” がある場合は \@startsection の具体的な引数である “section”、“1”、“\z@” 等々を、arg1arg2arg3 のように略記しますと)

\section*{<heading>}
 ↓
 ↓ \section は引数をとらないので \section のみが取り去られる
 ↓
\section*{<heading>}
 ↓
 ↓ \section の定義にしたがい \@startsection{arg1}{arg2}{arg3}{arg4}{arg5}{arg6} が入る
 ↓
\@startsection{arg1}{arg2}{arg3}{arg4}{arg5}{arg6}*{<heading>}
 ↓
 ↓ \@startsection は引数を六個とるので \@startsection{arg1}{arg2}{arg3}{arg4}{arg5}{arg6} が取り去られる
 ↓
\@startsection{arg1}{arg2}{arg3}{arg4}{arg5}{arg6}*{<heading>}
 ↓
 ↓ \@startsection の定義に引数それぞれを当てはめたものが入る
 ↓
\if@noskipsec \leavevmode \fi
.....
\fi
\@ifstar
  {\@ssect{arg3}{arg4}{arg5}{arg6}}%
  {\@dblarg{\@sect{arg1}{arg2}{arg3}{arg4}{arg5}{arg6}}}*{<heading>}
 ↓
 ↓ * を取り除いた上で \@ifstar の一つ目の引数が戻される(★)
 ↓
\@ssect{arg3}{arg4}{arg5}{arg6}{<heading>}

となります。

したがって、一見 \section* の引数のようにみえた {<heading>} は、実際には \@ssect の五つ目の引数として受け取られるということが分かります (なお、“*” がある場合には、\@startsection の最初の二つの引数は捨てられてしまっていることも分かります)

次に、“*” がない場合には、上の展開の過程の(★)の部分で \@ifstar の二つ目の引数が戻されて、“\section{<heading>}” のときは:

\@dblarg{\@sect{arg1}{arg2}{arg3}{arg4}{arg5}{arg6}}{<heading>}

となり、“\section[<toc_entry>]{<heading>}” のときは:

\@dblarg{\@sect{arg1}{arg2}{arg3}{arg4}{arg5}{arg6}}[<toc_entry>]{<heading>}

になりますが、これらは、I. (2) (b) でみた \@dblarg のはたらきにより、いずれも:

\@sect{arg1}{arg2}{arg3}{arg4}{arg5}{arg6}[<heading>/<toc_entry>]{<heading>}

という形に帰着されることになります。

つまり、“*” がない場合には、\section の引数のようにみえた引数は、実際は \@sect の七個目と八個目の引数として受け取られる、ということです。

以上をまとめますと、\section は、その後ろに “*” が来るか、“{” が来るか、“[” が来るかにしたがって、以下のように展開することになります \@startsection の六個の引数を仮に abcdef とします)

\@ssect は引数が五個必要ですが、\@startsection を経ることで、そのうちの四個を引き連れて \section と置き換わり、\@sect もまた \@startsection を経由することで、八個必要な引数のうち、六個を引き連れて \section と置き換わっている、ということになるわけです。

(2) \l@section の場合

LaTeX で目次をつくりたいときには、“\tableofcontents” と書けばよくて、そうすると、その場所に “.toc” ファイルが読み込まれますよね。

この “.toc” ファイルの中を覗いてみますと、例えば、jbook.cls の場合には、こんな感じになっています:

\contentsline {part}{第I部\hspace {1em}事物概念と関係概念}{1}
\contentsline {chapter}{\numberline {第1章}概念形成の理論によせて}{3}
\contentsline {chapter}{\numberline {第2章}数の概念}{32}
\contentsline {section}{\numberline {2.1}感覚論的導出の欠陥}{32}
\contentsline {section}{\numberline {2.2}純粋数概念の論理学的基礎づけ}{42}
\contentsline {section}{\numberline {2.3}数概念とクラス概念}{51}
\contentsline {section}{\numberline {2.4}数概念の拡大}{62}

【註】
どうでもいい話なのですけれど、この例に使った本では、実際には、section レベルには見出しはついていなくて、ただ大文字のローマ数字が振られているだけです。「感覚論的導出の欠陥」 等々は、いうなれば subsection のレベルに相当するものになりますが、しかし、当該見出しは巻頭の 「内容目次」 にのみ現われ、本文には subsection レベルの見出しはついていません (昔の本だとこういうやり方が結構みられます)。

ここで、“\contentsline” は一見引数を三つとるようにみえますが、実は:

\def\contentsline#1{\csname l@#1\endcsname}

と定義されているマクロなので、読み込まれた部分は、まず、次のようになります:

\l@part{第I部\hspace {1em}事物概念と関係概念}{1}
\l@chapter{\numberline {第1章}概念形成の理論によせて}{3}
\l@chapter{\numberline {第2章}数の概念}{32}
\l@section{\numberline {2.1}感覚論的導出の欠陥}{32}
\l@section{\numberline {2.2}純粋数概念の論理学的基礎づけ}{42}
\l@section{\numberline {2.3}数概念とクラス概念}{51}
\l@section{\numberline {2.4}数概念の拡大}{62}

【補足】
この説明は多分ちょっとウソです。\contentsline だけが先に一斉に展開されるわけはなくて、TeX は上から順番に処理していくはずです。

【補足】
\numberline” は jarticle.clsjbook.cls では)\def\numberline#1{\hbox to\@lnumwidth{#1\hfil}}” と定義されているマクロで、見出しの番号部分を \@lnumwidth 幅の箱に左寄せで入れるものです。

目次の各行を成形するこれら \l@<sectioning-unit> マクロは、見掛け上は引数を二つとるような形をしていますが、実際にどのような引数のとり方をするマクロとして定義するかについては、二通りの方法が考えられます。

ひとつには、素直に引数を二つとるマクロとして \l@<sectioning-unit> を定義するやり方があり、もうひとつは、上述の I. (1) (a) のように考えて、三つ以上の引数をとる別のマクロと \l@<sectioning-unit> とを置換するように定義する、というものです。

見出しを成形する \part\chapter\section 等々のコマンドの定義の方針にもこれと似たところがあって、\part\chapter はそれぞれ独自に定義されているのに対して、\section 以下のコマンドについては、汎用的な \@startsection にパラメータの値のセットを渡して見出しを成形していますよね。

同様に、この \l@<sectioning-unit> の場合も、\l@part\l@chapter はそれぞれ引数を二つとる独自のマクロとして定義されているのに対して、 \l@section 以下の \l@<sectioning-unit> は、引数を五つとる汎用的な \@dottedtocline が引数を三つ引き連れたものと置換するように定義されています。\l@section 以下の実際の定義をみてみますと:

\newcommand*{\l@section}{\@dottedtocline{1}{1.5em}{2.3em}}
\newcommand*{\l@subsection}   {\@dottedtocline{2}{3.8em}{3.2em}}
\newcommand*{\l@subsubsection}{\@dottedtocline{3}{7.0em}{4.1em}}
\newcommand*{\l@paragraph}    {\@dottedtocline{4}{10em}{5em}}
\newcommand*{\l@subparagraph} {\@dottedtocline{5}{12em}{6em}}

という風になっています。

【補足】
これは jbook.cls の場合です。jarticle.cls ですと、\l@part\l@section が引数を二つとるマクロとして定義されていて、引数を引き連れた \@dottedtocline と置換するように定義されているのは \l@subsection 以下の目次項目です。

以上から、“.toc” ファイルが読み込まれた後の、目次の section の行について、展開を追ってみますと:

\contentsline {section}{\numberline {2.1}感覚論的導出の欠陥}{32}
 ↓
 ↓ \contentsline は引数をひとつとるので \contentsline {section} が取り去られる
 ↓
\contentsline {section}{\numberline {2.1}感覚論的導出の欠陥}{32}
 ↓
 ↓ \contentsline の定義にしたがい \l@section が入る
 ↓
\l@section{\numberline {2.1}感覚論的導出の欠陥}{32}
 ↓
 ↓ \l@section は引数をとらないので \l@section のみが取り去られる
 ↓
\l@section{\numberline {2.1}感覚論的導出の欠陥}{32}
 ↓
 ↓ \l@section の定義にしたがい \@dottedtocline{1}{1.5em}{2.3em} が入る
 ↓
\@dottedtocline{1}{1.5em}{2.3em}{\numberline {2.1}感覚論的導出の欠陥}{32}

のようになります。

つまり、\@dottedtocline は引数を五つ必要としますが、途中に挟まる \l@section が、必要な引数のうちの三つを引き連れた \@dottedtocline と、置き換わっているわけです。

締めのごあいさつ

上級者の方々であれば、この手の話について扱うのなら、いわゆる TeX の 「口 (mouth)」 のこととか、展開可能なコマンドと展開可能でないコマンドの処理のタイミングのことなんかについても触れられたりするのかも知れませんけれど、そんな難しい話は私には無理なので、只管直線的に展開の順番を追ってみました。

最近たまたま plain TeX の “\line” コマンドを目にする機会があって、そういえば、以前こういうパターンについて言及したことがあったなぁ、と思い出して、昔書いたものを引っ張り出してきて再構成したのが、今回の記事となります。こんな、長いばっかりで何らの新規性もない記事を最後までお読みくださって、本当にありがとうございます m(_ _)m

それでは、Merry TeXmas & Happy TeXing!

をはり

Last modified: January 4, 2015.


home