動機
EMF等Eclipseの成果物は、Mavenリポジトリで配布されていない配布されている1。Gradle等を使う場合、Mavenリポジトリが欲しい。EclipseにもJGit等を配布するリポジトリはあるが、そこにライブラリがないのであれば、とりあえず自前のMavenリポジトリにデプロイしたい。ただデプロイするだけでも骨が折れるが、プラグインには依存関係があるので、それも解決したい。プラグインの依存関係は、META-INF/MANIFEST.MF
のRequire-Bundle
に記述されている。この情報を解析したいが、ここの形式は次のようになっていた。
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を使ってみることにした。2実際に作成した文法ファイルをGitHubにおいている。バージョンのオプション指定は不完全なので、まだ追加する必要がありそう。
ANTLRとは?
ANTLRを使うと構文を持ったデータを読み込む事ができるらしい。構文を持ったデータとして一番良く使われているものはプログラミング言語だろう。ANTLRの推薦文(Testimonials)をみるとPythonの創始者であるGuido van Rossumだったり、Objective-Cの創始者であるBrad Coxだったりから推薦されている。
ANTLRの開発は1989から始まっている。現在の最新版は4で、Javaで実装されている。Parserの生成先のターゲットは、Javaだけでなく、PythonだったりJavascriptだったりを選択できる。3
余談だが、ANTLRを使っている製品の中で興味深いものにXtextがある。Xtextの文法ファイルはANTLRのものではない独特の文法定義だ。Xtextの文法ファイルから対応するEMFモデルやらEditorやらOutlineViewやらを生成する。それと一緒にEditorの内容を解析するためのパーサーを生成するためのANTLRの文法ファイルを生成し、構文解析器(Parser)として利用している。4
インストール方法
Homebrewが入っている環境ならbrewコマンドでインストールできる。
$ brew install antlr
これにより、下記の2つのコマンドが実行できるようになる
- antlr4 : 文法ファイルからコードを生成する。コードの生成のみなので、利用には
javac
などコンパイルが必要。AntでもMavenでもGradleでも実行できるので、適切なビルドツールを使うと良い。 - grun : 文法ファイルのテストができる。起動後、テスト用の文字列を入れて
Ctrl+D
するとトークンの分割結果だったり、解析結果を図示する。grunの起動には文法ファイルから生成されたコードだけでは不十分。コンパイルしたクラスファイルが必要。
文法ファイルの書き方
文法ファイルの書き方自体は、自分自身不慣れなのでここではまとめない。苦労した点のみまとめておく。
ダブルクォートに名前をつけられないか?
文法を記述するとき記号にも名前がつけられるので、下記のようにできないか書いたがうまく解析できなかった。
grammer sample;
any_string : D_QUOTE [a-zA-Z]+ D_QUOTE
| [a-zA-Z]+
;
D_QUOTE : '"'
;
下記のように記号を文字として埋め込む。
grammer sample;
any_string : '"' [a-zA-Z]+ '"'
| [a-zA-Z]+
生成結果のコードにパッケージを指定できないか?
@header {
package org.kompiro;
}
というように@header
で指定可能。
文法ファイルの例
文法ファイルの書き方自体は多くのプログラミング言語に対応したANTLR4の文法ファイルはGitHubに公開されている。文法ファイルの書き方がわからない時に参考にするとよい。
構文解析のコード例
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(); // 文法の最初に記述したルール名を指定すると、その構文木を取得できる
-
Maven Centralにアップロードされている(Thanks @ShintaroHosoai)。ただちょっと探しにくいかも…。 ↩
-
The Definitive ANTLR4 Referenceという洋書が安かった時に買った。中々いいタイミングがなかったので、今回触ってみた。 ↩
-
ANTLR3の頃はC言語も生成できていた。しかい、3->4になるタイミングでより文法が分かりやすくするためにAdaptive LLという解析技術を採用したせいか、実行環境の実装が後回しになっている模様。 ↩
-
http://stackoverflow.com/questions/8672144/whats-the-relationshiop-between-xtext-and-antlr より。回答しているSebastian ZarnekowはXtextチームの人 ↩