TeXの処理系は他のプログラム言語とはスペースや改行の扱い方が異なるらしいが、それをよく理解しないままTeXのマクロなどを記述していた。そこで改めてTeXが改行やスペースをどのように扱うのかについて、TeX by TopicのChapter1, 2あたりを読むなどして分かったこと書くことにする。
TeX by Topicは和文組版でよく用いられるpTeX系の内部に関しては述べられていない。そこで和文に関してはLuaTeX-jaのドキュメントを参考にした。
改行とスペース
そもそもどのようなことを問題としているのかというだが、例えば次のようなものを何かTeXの処理系でコンパイルすることを考える。
This is a pen.
I like it.
よく見ると、一行目の pen. と二行目の I like の間にあった改行が、スペースへ化けたと分かる。
また次のように、
This is a pen.
などと、大量のスペースを注入したとしても、
という感じで、一部のスペースは無視される。
このように、TeXは記述したスペースや改行が全て無視されるというわけでもなければ、全て成果物に表われるというわけでもない。
TeXの入力処理
TeX by TopicではTeXの入力処理は 有限オートマトン であるとしている。ただしTeX by Topicは和文組版について全く述べられていないので、ここではLuaTeX-jaのドキュメントを参考に、pTeX系のオートマトンを述べることにした。
アルファベット
TeXは入力される文字を一文字ずつ、カテゴリーコードという文字に割り当てられた数字によって分類する。カテゴリーコードについてはTeX Wikiなどに詳細(?)がある。
ただ、TeXの状態遷移を表わすのであれば、とりあえず次のように分類すればことが足りると思う。なのでアルファベット(記号)を次のようにする。
-
\
:バックスラッシュ -
-
\n
:改行記号 -
%
:コメント文字 -
C
:半角英字(a-z, A-Z) -
G
:グループの開始と終了({
,}
) -
O
:\
,\n
,%
以外の半角文字 -
J
:日本語文字(あ、イ、宇……)
5つの状態
pTeXは次の5つの状態を持つ。(TeX by Topicでは状態 CS は書かれていないが、こちらの説明がやりやすいと思うので追加した。)
- 状態 N:新規行
- TeXが始まった時、または何らかの状態から、
\n
によって新しい行が始まった時の状態 - 状態 K:和文の行中
- 何らかの状態から、日本語文字
J
が出現した時の状態(pTeX系にのみ存在) - 状態 M:英文の行中
- 何らかの状態から文字
C
,O
が出現した時の状態 - 状態 S:スキップスペース
- 何らかの状態からスペース
- 状態 CS:コントロールシークエンス
- 何らかの状態から
\
の出現によって、コントロールシークエンス(マクロなど)を構成する時の状態
TeXソースコードにおけるスペースや改行は、このオートマトンの状態によって処理が変わる。
状態遷移と改行などの扱い
各状態と、その状態によって改行やスペースがどのように扱われるのか述べる。
状態 N :新規行
TeXはこの状態から始まり、新しい行へ入った際にこの状態へ遷移する。この状態では、
- 全てのスペース
- 改行
\n
を行うと改段落\par
が挿入される
状態 K :和文の行中
何か和文文字J
が出現した際にこの状態へ遷移する。この状態では、
- スペース
- 改行
\n
があると、何も出力せずに状態 N へ遷移する
つまり、スペースは表示され、改行は状態を遷移させるだけで表示に影響は与えない。例えば次のような文章を与える。
スペース の テスト
改行したが、前の行に書いた文字との間に
スペースはない。
最初の行はよく見ると「の」の前後にスペースが挿入されているが、たくさんスペースを連続して書いても、状態 S へ遷移してスペースを読み飛ばすので、「の」と「テスト」の間に大量の隙間が出来ることはない。
また、状態 K においてはグループ文字G
が表われても状態 M へ遷移しない。なので、
グループを開始させて改行し{
直後にグループを閉じて}
さらに改行した。
としても、改行の部分にスペースが挿入されない。
状態 M :英文の行中
英字C
の他に、例えば{
, }
といったグループに関する文字や、数字などによって状態 M へ遷移する。
"This is a pen."の例で挙げたように、英文の場合は和文と異なり改行によってスペースが挿入される。
- スペース
- 改行
\n
があると、スペースを表示して状態 N へ遷移する
従って、例えば次のような記述では、
This is a pen,{
I like it}
very much.
などと、改行の度にスペースが挿入される。
ただこの時にコメント文字%
が出現して次のようになった場合を考える。
This is a pen.%
I like it.
このように%
が出現した後改行した場合、その後に改行\n
があったとしてもコメントアウトされているものとされる。従って改行によるスペースの挿入も行われず、状態 M のまま次の行を処理する。従ってスペースの挿入などが行われない。
状態 S :スキップスペース
次のような時に状態 S へ遷移する。
- スペース
- 状態 CS の後(一部例外あり)
この状態の時、スペースと改行は次のようになる。
- スペース
- 改行
\n
があると、何もせず状態 N へ遷移する
つまりこの状態においては、連続するスペースが全て無視される。
状態 CS :コントロールシークエンス
文字\
の後にこの状態へと遷移する。TeX by Topicにはコントロールシークエンス( control sequence )として、次の2つを全てまとめたものであると述べている。
- コントロールシンボル(control symbol)
-
\
の後に、英字以外の一字,
や%
などが続くもの - コントロールワード(control word)
-
\
の後に、英字C
あるいは日本語文字J
が一字以上続くもの
つまり、\small
といったものはコントロールワードであり、\%
や\,
がコントロールシンボルとなる。状態 CS はこの二つで動作が異なる。
コントロールシンボル
\
の後にC
以外のものが続くもの場合は、その一字を読んだ後状態 M へ遷移する。例えば次のようなものを考える。
コントロールシンボル\%
の直後に改行を入れる。
このように%
記号の直後に半角スペースが挿入されていることから、状態 M へ遷移したことが分かる。(分かりやすくするためスペースの部分に色を付けた。)
ただし例外があり、\
(\
+半角スペース、コントロールスペースと呼ばれる)の場合は状態 S へ遷移する。
コントロールワード
コントロールワードの場合は、\
に続く英字C
あるいは日本語文字J
を全て読んだ後に状態 S へ遷移する。従って、
- コントロールワードの後にあるスペースは無視される
- コントロールワードの直後にある改行は何も表示せず、状態を N へ遷移させる
となる。例えば次のようにコントロールワードの直後にいくつかのスペースを挿入する。
\def\hoge{ほげ}
コントロールワード\hoge % 大量のスペース
の直後に大量のスペースを入れる。
このように\hoge
の後に入れたスペースは表示されない。
引数を取るコントロールワード
コントロールワードの中には、次のように引数を取るものがある。
\def\hoge#1{(#1)が吸い込まれた}
\hoge の直後にはスペースが入っている。
図の通り、\hoge
の直後にある大量のスペースは状態 CS で\hoge
を処理した直後に状態 S へと遷移し、そこでスペースは消滅した。その後に引数の処理を行ったためスペースの直後にある「の」が引数となった。
また、境界なしの場合は引数と引数の間にある全てのスペースや改行が無視される。
ただし、コントロールワードが引数を取る際は、コントロールワードがどのように引数を取るかによって、スペースなどの処理が分かれる。
- 境界なし引数(Undelimited parameters)
-
\def\hoge#1#2{...}
のように、引数と引数の間に境界を明示しない - 境界あり引数(Delimited parameters)
-
\def\hoge#1, #2{...}
のように、引数と引数の間に境界となる文字列を明示する
境界なし引数
まずは境界なし引数の場合は、コントロールワードの直後にあるスペースと改行が状態 S によって無視され、その後引数の確保になる。
\def\hoge#1#2{(#1,#2)が吸い込まれた}
\hoge
A
B
という感じ。
このように、 "A"の後にある改行や状態 M による改行で挿入されるスペースは無視されているが、"B"の後にある改行(状態 M における改行で挿入されるスペース)は残っている。つまり、引数と引数の間に境界がない場合、引数の間にあるスペースや改行は無視される。
境界あり引数
ここで、境界となる文字列を明示すると次のようになる。
\def\hoge#1,#2and#3{(#1,#2,#3)が吸い込まれた}
\hoge A , B and C
という感じ。
このように境界文字列で挟まれた部分についてはスペースなどが無視されない。(ただ、スペースによって状態が S へ遷移するので連続するスペースは一つ分になるなどする)
まとめ
結論としては、
- 状態 M の時に改行するとスペースが挿入される可能性がある
ということになる。なので、
- 和文(状態 K )の改行は無視される
- コントロールワードの直後にあるスペースや改行は無視される
- コントロールワードの引数は、境界を明示しているのかどうかで振る舞いが違うが、場合によっては改行によるスペースなどが入る可能性がある