ANTLR4を使ってみた


## 動機

EMF等Eclipseの成果物は、Mavenリポジトリで~~配布されていない~~配布されている[^central]。Gradle等を使う場合、Mavenリポジトリが欲しい。EclipseにもJGit等を配布するリポジトリはあるが、そこにライブラリがないのであれば、とりあえず自前のMavenリポジトリにデプロイしたい。ただデプロイするだけでも骨が折れるが、プラグインには依存関係があるので、それも解決したい。プラグインの依存関係は、`META-INF/MANIFEST.MF`の`Require-Bundle`に記述されている。この情報を解析したいが、ここの形式は次のようになっていた。

[^central]: [Maven Centralにアップロードされている(Thanks @ShintaroHosoai)](https://twitter.com/ShintaroHosoai/status/619799495371440128)。ただちょっと探しにくいかも…。

```org.eclipse.uml2.uml_5.1.0.v20150601-0733/META-INF/MANIFEST.MF(抜粋)
Require-Bundle: org.eclipse.core.runtime;bundle-version="[3.5.0,4.0.0)
 ",org.eclipse.emf.ecore;visibility:="reexport";bundle-version="[2.11.
 0,3.0.0)",org.eclipse.emf.ecore.xmi;visibility:="reexport";bundle-ver
 sion="[2.11.0,3.0.0)",org.eclipse.uml2.common;visibility:="reexport";
 bundle-version="[2.1.0,3.0.0)",org.eclipse.uml2.types;visibility:="re
 export";bundle-version="[2.0.0,3.0.0)",org.eclipse.emf.mapping.ecore2
 xml;visibility:="reexport";bundle-version="[2.9.0,3.0.0)"
```


プラグイン毎を区切った文字が`,`のように見えるが、`,`はバージョンレンジにも使われている。単純に`,`でsplitするだけではダメなのだ。その他、visibility等の情報も入っている。これらを抜きつつ、必要なプラグイン名とバージョンレンジを取り出すにはどうすればいいか？今回は[ANTLR](http://www.antlr.org/)を使ってみることにした。[^antlr][実際に作成した文法ファイルをGitHubにおいている。](https://github.com/kompiro/Eclipse-plugin-to-maven-repo/blob/master/src/main/antlr/org/kompiro/BundleDependency.g4)バージョンのオプション指定は不完全なので、まだ追加する必要がありそう。

[^antlr]: [The Definitive ANTLR4 Reference](https://pragprog.com/book/tpantlr2/the-definitive-antlr-4-reference)という洋書が安かった時に買った。中々いいタイミングがなかったので、今回触ってみた。

## ANTLRとは？

ANTLRを使うと構文を持ったデータを読み込む事ができるらしい。構文を持ったデータとして一番良く使われているものはプログラミング言語だろう。ANTLRの推薦文(Testimonials)をみるとPythonの創始者であるGuido van Rossumだったり、Objective-Cの創始者であるBrad Coxだったりから推薦されている。

ANTLRの開発は1989から始まっている。現在の最新版は4で、Javaで実装されている。Parserの生成先のターゲットは、Javaだけでなく、PythonだったりJavascriptだったりを選択できる。[^c言語]

[^C言語]: ANTLR3の頃はC言語も生成できていた。しかい、3->4になるタイミングでより文法が分かりやすくするためにAdaptive LLという解析技術を採用したせいか、実行環境の実装が後回しになっている模様。

余談だが、ANTLRを使っている製品の中で興味深いものに[Xtext](https://eclipse.org/Xtext/)がある。Xtextの文法ファイルはANTLRのものではない独特の文法定義だ。Xtextの文法ファイルから対応するEMFモデルやらEditorやらOutlineViewやらを生成する。それと一緒にEditorの内容を解析するためのパーサーを生成するためのANTLRの文法ファイルを生成し、構文解析器(Parser)として利用している。[^xtext]

[^xtext]: http://stackoverflow.com/questions/8672144/whats-the-relationshiop-between-xtext-and-antlr より。回答しているSebastian ZarnekowはXtextチームの人

## インストール方法

Homebrewが入っている環境ならbrewコマンドでインストールできる。

```Macの場合
$ brew install antlr
```

これにより、下記の2つのコマンドが実行できるようになる

- antlr4 : 文法ファイルからコードを生成する。コードの生成のみなので、利用には`javac`などコンパイルが必要。AntでもMavenでもGradleでも実行できるので、適切なビルドツールを使うと良い。
- grun : 文法ファイルのテストができる。起動後、テスト用の文字列を入れて`Ctrl+D`するとトークンの分割結果だったり、解析結果を図示する。grunの起動には文法ファイルから生成されたコードだけでは不十分。コンパイルしたクラスファイルが必要。

## 文法ファイルの書き方

文法ファイルの書き方自体は、自分自身不慣れなのでここではまとめない。苦労した点のみまとめておく。

### ダブルクォートに名前をつけられないか？

文法を記述するとき記号にも名前がつけられるので、下記のようにできないか書いたがうまく解析できなかった。

```sample.g4
grammer sample;

any_string : D_QUOTE [a-zA-Z]+ D_QUOTE
  | [a-zA-Z]+
  ;
D_QUOTE : '"'
  ;
```

下記のように記号を文字として埋め込む。

```sample.g4
grammer sample;

any_string : '"' [a-zA-Z]+ '"'
  | [a-zA-Z]+
```

### 生成結果のコードにパッケージを指定できないか？

```
@header {
package org.kompiro;
}
```

というように`@header`で指定可能。

### 文法ファイルの例

文法ファイルの書き方自体は[多くのプログラミング言語に対応したANTLR4の文法ファイルはGitHubに公開されている。](https://github.com/antlr/grammars-v4)文法ファイルの書き方がわからない時に参考にするとよい。

## 構文解析のコード例

```java

import org.antlr.v4.runtime.ANTLRInputStream
import org.antlr.v4.runtime.CommonTokenStream

String input = "org.eclipse.core.runtime;bundle-version=\"[3.5.0,4.0.0)\"";
ANTLRInputStream stream = new ANTLRInputStream(input);
SampleLexer lexer = new SampleLexer(stream);
CommonTokenStream tokens = new CommonTokenStream(lexer);
BundleDependencyParser parser = new SampleParser(tokens);
parser.top(); // 文法の最初に記述したルール名を指定すると、その構文木を取得できる
```