TeXの改行とスペース

TeXの処理系は他のプログラム言語とはスペースや改行の扱い方が異なるらしいが、それをよく理解しないままTeXのマクロなどを記述していた。そこで改めてTeXが改行やスペースをどのように扱うのかについて、[TeX by Topic](ftp://ftp.kddilabs.jp/CTAN/info/texbytopic/TeXbyTopic.pdf)のChapter1, 2あたりを読むなどして分かったこと書くことにする。
TeX by Topicは和文組版でよく用いられるpTeX系の内部に関しては述べられていない。そこで和文に関しては[LuaTeX-jaのドキュメント](http://git.sourceforge.jp/view?p=luatex-ja/luatexja.git;a=blob_plain;f=doc/luatexja-ja.pdf;hb=HEAD)を参考にした。

# 改行とスペース

そもそもどのようなことを問題としているのかというだが、例えば次のようなものを何かTeXの処理系でコンパイルすることを考える。

```tex
This is a pen.
I like it.
```

![スクリーンショット 2014-01-07 16.43.36.png](https://qiita-image-store.s3.amazonaws.com/0/10815/c7c3914d-de11-9e38-f3bf-8b2560a0012d.png)

よく見ると、一行目の _pen._ と二行目の _I like_ の間にあった改行が、スペースへ化けたと分かる。
また次のように、

```tex
This is         a         pen.
```

などと、大量のスペースを注入したとしても、

![スクリーンショット 2014-01-04 17.43.19.png](https://qiita-image-store.s3.amazonaws.com/0/10815/4658deb5-b7dc-d056-191a-ee7b8528875c.png)

という感じで、一部のスペースは無視される。
このように、TeXは記述したスペースや改行が全て無視されるというわけでもなければ、全て成果物に表われるというわけでもない。

# TeXの入力処理

TeX by TopicではTeXの入力処理は **有限オートマトン** であるとしている。ただしTeX by Topicは和文組版について全く述べられていないので、ここではLuaTeX-jaのドキュメントを参考に、pTeX系のオートマトンを述べることにした。

## アルファベット

TeXは入力される文字を一文字ずつ、カテゴリーコードという文字に割り当てられた数字によって分類する。カテゴリーコードについては[TeX Wiki](http://oku.edu.mie-u.ac.jp/~okumura/texwiki/?TeX%E5%85%A5%E9%96%80%2F%E3%83%9E%E3%82%AF%E3%83%AD%E3%81%AE%E4%BD%9C%E6%88%90)などに詳細（？）がある。

ただ、TeXの状態遷移を表わすのであれば、とりあえず次のように分類すればことが足りると思う。なのでアルファベット（記号）を次のようにする。

- `\`：バックスラッシュ
- `　`：半角スペース
- `\n`：改行記号
- `%`：コメント文字
- `C`：半角英字（a-z, A-Z）
- `G`：グループの開始と終了（`{`, `}`）
- `O`：`\`, `　`, `\n`, `%`以外の半角文字
- `J`：日本語文字（あ、イ、宇……）

## 5つの状態

pTeXは次の5つの状態を持つ。（TeX by Topicでは状態 _CS_ は書かれていないが、こちらの説明がやりやすいと思うので追加した。）

<dl>
  <dt>状態 <em>N</em>：新規行</dt>
  <dd>TeXが始まった時、または何らかの状態から、<code>\n</code>によって新しい行が始まった時の状態</dd>
  <dt>状態 <em>K</em>：和文の行中</dt>
  <dd>何らかの状態から、日本語文字<code>J</code>が出現した時の状態（pTeX系にのみ存在）</dd>
  <dt>状態 <em>M</em>：英文の行中</dt>
  <dd>何らかの状態から文字<code>C</code>, <code>O</code>が出現した時の状態</dd>
  <dt>状態 <em>S</em>：スキップスペース</dt>
  <dd>何らかの状態からスペース<code>　</code>の出現などによって、以降のスペースを読み飛ばす時の状態</dd>
  <dt>状態 <em>CS</em>：コントロールシークエンス</dt>
  <dd>何らかの状態から<code>\</code>の出現によって、コントロールシークエンス（マクロなど）を構成する時の状態</dd>
</dl>

TeXソースコードにおけるスペースや改行は、このオートマトンの状態によって処理が変わる。

## 状態遷移と改行などの扱い

各状態と、その状態によって改行やスペースがどのように扱われるのか述べる。

### 状態 _N_ ：新規行

TeXはこの状態から始まり、新しい行へ入った際にこの状態へ遷移する。この状態では、

- 全てのスペース`　`が無視される
- 改行`\n`を行うと改段落`\par`が挿入される

### 状態 _K_ ：和文の行中

何か和文文字`J`が出現した際にこの状態へ遷移する。この状態では、

- スペース`　`が出現すると、スペースを表示して状態 _S_ へ遷移する
- 改行`\n`があると、何も出力せずに状態 _N_ へ遷移する

つまり、スペースは表示され、改行は状態を遷移させるだけで表示に影響は与えない。例えば次のような文章を与える。

```tex
スペース の        テスト
改行したが、前の行に書いた文字との間に
スペースはない。
```

![スクリーンショット 2014-01-05 17.12.23.png](https://qiita-image-store.s3.amazonaws.com/0/10815/a606f103-8f90-5679-20d1-39d74b69a24f.png)

最初の行はよく見ると「の」の前後にスペースが挿入されているが、たくさんスペースを連続して書いても、状態 _S_ へ遷移してスペースを読み飛ばすので、「の」と「テスト」の間に大量の隙間が出来ることはない。
また、状態 _K_ においてはグループ文字`G`が表われても状態 _M_ へ遷移しない。なので、

```tex
グループを開始させて改行し{
直後にグループを閉じて}
さらに改行した。
```

![スクリーンショット 2014-01-05 20.12.09.png](https://qiita-image-store.s3.amazonaws.com/0/10815/e7426668-4883-e993-ac19-45e32cce4a65.png)

としても、改行の部分にスペースが挿入されない。

### 状態 _M_ ：英文の行中

英字`C`の他に、例えば`{`, `}`といったグループに関する文字や、数字などによって状態 _M_ へ遷移する。
"This is a pen."の例で挙げたように、英文の場合は和文と異なり改行によってスペースが挿入される。

- スペース`　`が出現すると、スペースを表示して状態 _S_ へ遷移する
- 改行`\n`があると、スペースを表示して状態 _N_ へ遷移する

従って、例えば次のような記述では、

```tex
This is a pen,{
I like it}
very much.
```

![スクリーンショット 2014-01-05 20.18.14.png](https://qiita-image-store.s3.amazonaws.com/0/10815/32e91682-4161-7a53-dd7c-451d1aa16801.png)

などと、改行の度にスペースが挿入される。

ただこの時にコメント文字`%`が出現して次のようになった場合を考える。

```tex
This is a pen.%
I like it.
```

![スクリーンショット 2014-01-06 1.09.04.png](https://qiita-image-store.s3.amazonaws.com/0/10815/86040b92-1e08-e4c7-2164-e6a1bdcb0a2c.png)

このように`%`が出現した後改行した場合、その後に改行`\n`があったとしてもコメントアウトされているものとされる。従って改行によるスペースの挿入も行われず、状態 _M_ のまま次の行を処理する。従ってスペースの挿入などが行われない。

### 状態 _S_ ：スキップスペース

次のような時に状態 _S_ へ遷移する。

- スペース`　`の後
- 状態 _CS_ の後（一部例外あり）

この状態の時、スペースと改行は次のようになる。

- スペース`　`を無視する（何も表示せず、状態もそのまま）
- 改行`\n`があると、何もせず状態 _N_ へ遷移する

つまりこの状態においては、連続するスペースが全て無視される。

### 状態 _CS_ ：コントロールシークエンス

文字`\`の後にこの状態へと遷移する。TeX by Topicにはコントロールシークエンス（ _control sequence_ ）として、次の2つを全てまとめたものであると述べている。

<dl>
  <dt>コントロールシンボル（<em>control symbol</em>）</dt>
  <dd><code>\</code>の後に、英字以外の一字<code>,</code>や<code>%</code>などが続くもの</dd>
  <dt>コントロールワード（<em>control word</em>）</dt>
  <dd><code>\</code>の後に、英字<code>C</code>あるいは日本語文字<code>J</code>が一字以上続くもの</dd>
</dl>

つまり、`\small`といったものはコントロールワードであり、`\%`や`\,`がコントロールシンボルとなる。状態 _CS_ はこの二つで動作が異なる。

#### コントロールシンボル

`\`の後に`C`以外のものが続くもの場合は、その一字を読んだ後状態 _M_ へ遷移する。例えば次のようなものを考える。

```tex
コントロールシンボル\%
の直後に改行を入れる。
```

![スクリーンショット 2014-01-05 20.49.34.png](https://qiita-image-store.s3.amazonaws.com/0/10815/7c106629-cf40-a471-0b53-947f0272e863.png)

このように`%`記号の直後に半角スペースが挿入されていることから、状態 _M_ へ遷移したことが分かる。（分かりやすくするためスペースの部分に色を付けた。）

ただし例外があり、`\　`（`\`+半角スペース、コントロールスペースと呼ばれる）の場合は状態 _S_ へ遷移する。

#### コントロールワード

コントロールワードの場合は、`\`に続く英字`C`あるいは日本語文字`J`を全て読んだ後に状態 _S_ へ遷移する。従って、

- コントロールワードの後にあるスペースは無視される
- コントロールワードの直後にある改行は何も表示せず、状態を _N_ へ遷移させる

となる。例えば次のようにコントロールワードの直後にいくつかのスペースを挿入する。

```tex
\def\hoge{ほげ}

コントロールワード\hoge         % 大量のスペース
の直後に大量のスペースを入れる。
```

![スクリーンショット 2014-01-05 21.00.12.png](https://qiita-image-store.s3.amazonaws.com/0/10815/8eeca541-c031-53bc-cb68-621ff6019fd5.png)

このように`\hoge`の後に入れたスペースは表示されない。

## 引数を取るコントロールワード

コントロールワードの中には、次のように引数を取るものがある。

```tex
\def\hoge#1{（#1）が吸い込まれた}

\hoge       の直後にはスペースが入っている。
```

![スクリーンショット 2014-01-05 23.36.02.png](https://qiita-image-store.s3.amazonaws.com/0/10815/5d740c0f-901a-8d05-4c09-855337eb0a35.png)

図の通り、`\hoge`の直後にある大量のスペースは状態 _CS_ で`\hoge`を処理した直後に状態 _S_ へと遷移し、そこでスペースは消滅した。その後に引数の処理を行ったためスペースの直後にある「の」が引数となった。
また、境界なしの場合は引数と引数の間にある全てのスペースや改行が無視される。

ただし、コントロールワードが引数を取る際は、コントロールワードがどのように引数を取るかによって、スペースなどの処理が分かれる。

<dl>
  <dt>境界なし引数（Undelimited parameters）</dt>
  <dd><code>\def\hoge#1#2{...}</code>のように、引数と引数の間に境界を明示しない</dd>
  <dt>境界あり引数（Delimited parameters）</dt>
  <dd><code>\def\hoge#1, #2{...}</code>のように、引数と引数の間に境界となる文字列を明示する</dd>
</dl>

### 境界なし引数

まずは境界なし引数の場合は、コントロールワードの直後にあるスペースと改行が状態 _S_ によって無視され、その後引数の確保になる。

```tex
\def\hoge#1#2{（#1,#2）が吸い込まれた}

\hoge
  A
  B
という感じ。
```

![スクリーンショット 2014-01-07 16.15.50.png](https://qiita-image-store.s3.amazonaws.com/0/10815/8053cd26-0f0e-78d4-fe6d-b9487b53e863.png)

このように、 "A"の後にある改行や状態 _M_ による改行で挿入されるスペースは無視されているが、"B"の後にある改行（状態 _M_ における改行で挿入されるスペース）は残っている。つまり、引数と引数の間に境界がない場合、引数の間にあるスペースや改行は無視される。

### 境界あり引数

ここで、境界となる文字列を明示すると次のようになる。

```tex
\def\hoge#1,#2and#3{（#1,#2,#3）が吸い込まれた}

\hoge A , B and C
という感じ。
```

![スクリーンショット 2014-01-07 16.19.12.png](https://qiita-image-store.s3.amazonaws.com/0/10815/4886d864-f0bc-e164-36ad-2a2e01297eb7.png)

このように境界文字列で挟まれた部分についてはスペースなどが無視されない。（ただ、スペースによって状態が _S_ へ遷移するので連続するスペースは一つ分になるなどする）

# まとめ

結論としては、

- 状態 _M_ の時に改行するとスペースが挿入される可能性がある

ということになる。なので、

- 和文（状態 _K_ ）の改行は無視される
- コントロールワードの直後にあるスペースや改行は無視される
- コントロールワードの引数は、境界を明示しているのかどうかで振る舞いが違うが、場合によっては改行によるスペースなどが入る可能性がある