gl5_progのメモ

自分のためのメモとかまとめとか

ANTLR3 C Target導入記

ANTLR C Targetがとりあえず動くようになるまでが大変だったのでここにその記録を残しておきます。ただ苦労したことをだらだら書いただけなので実用性はないです。

言葉の定義

言葉 定義
C Target ANTLRからC言語ソースを吐き出すためのモジュールを指す。ANTLRとは作者が別。
C Runtime パーサーの基本的なプログラムのモジュール。生成されたソースコードはこのC Runtimeを必要とする。

とりあえず3系の最新バージョンで

ANTLRC言語ソースを生成させたい場合、ANTLR4はまだ対応してないのでANTLR3を使うしかありません。3系の最新バージョンであるantlr-3.5-complete.jarを使うことにします。このantlr-3.5-complete.jarにはC Targetも含まれているようです。

C Runtimeを用意する

antlr-3.5-complete.jarは.jarファイルなのでC Runtimeは含まれていません。そこでこっちantlr-3.5.tar.gzから持ってきます。そしてビルドしてみます。libファイルとか好きじゃないので、自分でIDE(QtCreator)のプロジェクトファイルに追加してビルドしてみます。するとビルドエラーが。どうやらantlr3Config.hが無いのが原因のようです。あー、./configureとかで生成される感じなのかと理解し、先ほどのantlr-3.5.tar.gz解凍後の/runtime/C/で./configureを試してみます。…ができない。configureファイルが無い。あるのはconfigure.acってファイルだけ。なにそれ知らん。調べてみるとAutotoolsとかAutomakeがどうたらこうたらいうものらしいです。訳がわかりません。おかしい。ここでは./configureって書いてあるのに。そこで、antlr-3.5.tar.gzではなく、C Runtime単体であるC runtime distributionsの中で最新であるlibantlr3c-3.4.tar.gzを見てみました。すると、ありました、configure。さっそく./configureしてantlr3Config.hをゲット。ビルドも通りました(未使用変数の警告がいっぱい出たけど)。これでC Runtimeは用意できました。

C言語ソースを生成、実行してみる

ANTLRworksで適当に.gファイルを作成し、適当に入力し、C言語ソースを生成してみます。そして、ビルドしてみます。ところが、その組み合わせで生成されたC言語ソースをビルドするとビルドエラーに…。色々調べてみると、どうやら、ルールが1つの終端記号だけで構成されてる場合に生成されるコードでビルドエラーが発生していたようです。そこでルールを少し複雑に(意味もなく統語的述語を使うように)したところ先ほどのビルドエラーはすべてなくなりました。ところが別のエラーが出てしまいました。なんかDFAがなんちゃらみたいな場所でエラーが出ています。決定性有限オートマトンですか?訳が分かりません。お手上げです。グーグルで調べてみるとどうやらこのエラーはバージョン3.4、3.5では発生し、3.3では発生しないようです…。 antlr3 - numerous template errors generating OracleSQL grammar using Antlr-3.5-complete.jar - Stack Overflow

…しょうがありません。3.3を使うことにします。

ANTLR3.3を探す

ANTLR3.3が必要なことがわかったのですが、実はANTLRworksってANTLRを含んでしまっているので、ANTLR3.3を含んだANTLRworksを探す必要があります。ANTLR3のダウンロードページには最新のANTLRworksしかないので、URLいじってファイル一覧ページを見つけ出し、そこから望みのANTLRworksをダウンロードします。しかし、どのバージョンがANTLR3.3を含んでいるのかが分からない。そこで、ANTLR3.3のリリース時期から推察してantlrworks-1.4.2.zipを選んでみました。そしてビンゴ。ANTLR3.3が含まれています。

C Runtimeを用意する( 2回目 )

ところで、ANTLRのバージョンが変わるということは、C Targetのバージョンも変わるということです。そうなるとそのバージョンに対応した、C Runtimeが必要ということです。またプロジェクトファイルに追加したり、./configureしてantlr3Config.hをゲットしなければなりません。とりあえず、バージョン3.5のときと同じようにantlr-3.3.tar.gzからC Runtimeを持ってこようとしてみます。が、やっぱりconfigureがありません。なので、ANTLR3.3に対応するC Target単体のソースコードを入手しなけらばなりません。ANTLR3.3内の/runtime/C/ChangeLogを見たところ、ANTLR3.3のバージョンは3.1.2のようです。ちなみに/runtime/C/READMEには"ANTLR v3.0.1 C Runtime"としか書かれておらず、中身もANTLRのREADMEにC Targetの作者であるJim Idleさんの署名がちょこっと追加されただけのもののようで、しかも内容が古いので当てにするのは止めました。読む価値なしです。必要なC Targetのバージョンが3.1.2だと判明したので、そのファイルlibantlr3c-3.1.2.tar.gzを入手し、前回と同じように、./configureし、ファイル数が違っている可能性もあるので、IDEのプロジェクトファイルに追加しなおしなどをし、ビルドしてみます。すると…ビルドエラー。今回はC Runtimeではなく、C Runtimeを実際に利用しているところでビルドエラーになっていました。どうやらバージョンが変わって関数名などが変わってしまったようです。というかよくみてみると、使っていた関数がなくなってます。どうすれば同じ処理をできるのかちょっとわかりません。と、ここで思いつきました。ANTLR3.3を使った解説記事を書いてるサイトがあったじゃないかと。このサイトです。そのサイトを参考にコードを修正してみま…あれ、それでも関数名がおかしいです。どういうことだ…。そのサイトはANTLR3.3を使っているからC Targetのバージョンは3.1.2相当のはず…。でも、そのサイトが使っているRuntimeのバージョンはもっと新しいっぽい…。正しいC Targetバージョンの捜索がはじまりました。思い出したのはantlr3Config.hにはバージョンが定義されていたことです。しかし、antlr-3.3.tar.gzの中にはantlr3Config.hはありません。というか、antlr3Config.hがあったら正しいバージョン番号調べて、C Runtime単体ファイルを落としてくる必要もありません。ところでantlr3Config.hは./configureによって生成されるファイルです。ということはantlr3Config.hに書き込まれるバージョン番号もどこかにあるはずです。探したところconfigure.acの頭にありました。"3.3-SNAPSHOT"となっていました。なるほど、ANTLR3.3のC Targetはちゃんと同じバージョンになってるのね。よしC Runtime 3.3単体ファイルを入手するぞとダウンロードファイル一覧ページを見てみると、libantlr3c-3.2.tar.gz、libantlr3c-3.4.tar.gzはあるのに3.3がありません。はぁ…と思って調べてみると、C Target3.3は欠番だから3.4使えという書き込みを発見。はぁ…そうですか。ん?3.4って最初に使ってたやつじゃないか!最初に用意したC RuntimeをまたIDEプロジェクトに追加してビルド。ビルド成功。やった。

C言語ソースを生成、実行してみる( 2回目 )

前回と同じようにANTLRworksで適当に.gファイルを作成し、適当に入力し、C言語ソースを生成してみます。そして、ビルドしてみます。ビルド成功。そして実行…即落ちました。C Runtime内をステップ実行で追っていくとピンとくる箇所が。ポインタをuint32でキャストしてます。実行環境は64bitなのでこれはまずいです。もうちょっと調べてみると、ANTLR3_USE_64BITというマクロで64bit対応しているもよう。そしてANTLR3_USE_64BITはantlr3Config.h内で定義したりしなかったりするようだ。./configureで生成したんだからそこらへん正しく設定されるはずじゃとか思いながら手でantlr3Config.hを書き換えて、再実行。動いた。パースもちゃんとされてるようだ。が、しかしたまに上手くいかない。6文字以上の文字列を与えるとエラーを出力する…。でも、この原因は自分のミスでした。詳しくはQStringをconst char*に変換するときの罠を。 そのミスの修正でやっとまともにパーサーが動作するように。

ANTLRとの本当の戦いはこれからだ。

まとめ

C Targetは疑ってかかろう。

  • ANTLR3.5に含まれるC Targetにはバグがあるようです。
  • READMEにはほぼANTLR本体のことしか書いてありません。
  • ChangeLogは内容が古いです。
  • ANTLR3 C Runtime APIも内容が古いです。