ctpgはコンパイル時コンパイラコンパイラ？

D言語erの方もそうでない方も、こんちには！

[D言語 Advent Calendar 2012](http://qiita.com/advent-calendar/2012/d)の２日目の記事です。

この記事では、[ctpg](https://github.com/youkei/ctpg)と言うライブラリを、とても軽く紹介します。

## ctpg is 何
[@repeatedly](http://qiita.com/users/repeatedly)さんの[最初の記事](http://qiita.com/items/0960bc29b49722dc1d1f)にもありましたが、パーサジェネレータです。ScalaのParserCombinatorの影響を強く受けています。

## ctpgの特徴
さすがに「パーサジェネレータです！」だけではアレなので、特徴をつらつらと挙げていきます。

### コンパイル時にパーサが生成される
パーサジェネレータといえば、YaccやANTLRなどが有名だと思います。

これらのソフトウェアは、予め構文規則が書かれているファイルから、パーサが書かれたソースコードを生成する必要があります。

さくっと小さなパーサが書きたい時、この作業は少し面倒くさいですね。

一方、ctpgではその作業の必要がありません。なぜなら、パーサがコンパイル時に生成されるからです。[文字列mixin](http://www.kmonos.net/alang/d/mixin.html)と[CTFE](http://kmonos.net/alang/d/function.html#interpretation)の合わせ技により、実現しています。

構文規則を別のファイルに書く必要もありません。Dのソースコード内に書くことができます。

パーサジェネレータはよくコンパイラコンパイラと呼ばれます。なのでこのctpgは、コンパイル時にパーサを生成するという点で、**コンパイル時コンパイラコンパイラ**と呼べるかもしれません。

### 生成したパーサもコンパイル時に動作する
ctpgが生成したパーサは、基本的にCTFE可能な関数になるので、コンパイル時に動作させることができます。

なので、ctpgを使うことによって、以下のことが簡単に実現できます。

* JSONをコンパイル時にパースする。
* GUIが定義されたXMLをコンパイル時にパースし、そのGUIを作るDのソースコードに変換して、mixinする。

### 入力は、割と何でもいい
文字列はもちろん、任意の型を要素型とするForwardRangeを入力とすることができます。  
なので、やろうと思えば、バイナリのパースもできます。

やはり、D言語でライブラリを書いている以上、Range対応は避けて通れませんね。

## 導入方法

1. https://github.com/youkei/ctpg から、ZIPで落としたり、git cloneしたりします。
2. src/ctpg.dを自分のプロジェクトの適当なディレクトリに置きます。
3. ctpgを使うソースファイルでctpgをimportします。
4. ctpg.dをおいたディレクトリをインクルードパスに追加しつつ、ctpg.dと一緒にコンパイルします。

#### 例：ctpg.dをincludeディレクトリにおいた場合
```d:src/hoge.d
import ctpg;
import std.stdio;

void main(){
    "Hello world!".writeln();
}
```
```bash:shell
$ dmd -Iinclude include/ctpg.d src/hoge.d
```

## どう使うの？
### 基本的には
以下のように使います。

```d:hello.d
import ctpg;

mixin(generateParsers(q{
    string hello = "Hello";
});

void main(){
    auto parsed = "Hello world!".parse!hello();
    assert(parsed.match);
    assert(parsed.value == "Hello");
}
```

`generateParsers`関数が、Dのソースコードを返すので、それをmixinします。そして、`parse`テンプレート関数のテンプレート引数に規則を渡して、使います。  

`generateParsers`と言う関数名が、どうにもダサいですね・・・

それはさておき、`generateParsers`に渡す文字列の中身ですが、上に書いてある通り、

```
規則名 = 規則 ;
```

と言う感じに構文規則を書いていきます。

### 規則は型を持っている
気づいた方は気づいたと思いますが、規則の前に型が書かれています。上の例では、`string`と書かれていますね。

規則の型は、パースした時の結果の`value`の型になります。

上の例で言うと、規則`hoge`の型が`string`なので、`parsed.value`の型が`string`になります。

### 演算子とか
演算子などは、基本的に[PEG](http://ja.wikipedia.org/wiki/PEG_%28%E6%96%87%E6%B3%95%29)（ポリエチレングリコールじゃないですよ！）に従っています。

なので、普通に並べればつなげることが出来たり、`/`、`*`、`+`、`?`などを使うことができます。

```d:hello2.d
import ctpg, std.string;

mixin(generateParsers(q{
    string Hel = "Hel";
    string o = "o";
    Tuple!(string, string[], string) hello = Hel "l"+ o;
});

void main(){
    auto parsed = "Hello world!".parse!hello();
    assert(parsed.match);
    assert(parsed.value[1].join() == "l");

    parsed = "Hellllllo world!".parse!hello();
    assert(parsed.match);
    assert(parsed.value[1].join() == "lllll");
}
```

### 変換する
`>>`で、結果の値を関数に渡して、変換することができます。
ScalaのParserCombinatorで言うところの`^^`のことですね^^

```d:parse_num.d
import ctpg, std.conv;

mixin(generateParsers(q{
    int num = "3141592" >> to!int;
});

void main(){
    auto parsed = "31415926535".parse!num();
    assert(parsed.match);
    assert(parsed.value == 3141592);
```

### その他
その他の使い方について知りたい方は、[ドキュメント](https://github.com/youkei/ctpg/wiki)を見てみるといいかもしれません。

と、言いたいところなんですが、ドキュメントは全然書けてません。
本当に申し訳 of the world

## まとめ
今回の記事は、軽く紹介という事で、このような感じになりました。次回の記事では、例を挙げながら、複雑な使い方を紹介したいと思います。
ドキュメントは早急に書きます・・・

３日目は、Phobosコミッターでもある[@mono_shoo](http://qiita.com/users/mono_shoo)さんです！