ANTLRで生成したパーサーで構文解析
前回の続きです。
JavaParser.csとJavaLexer.csを使ってみましょう。
まずはVisualStudioでC#のコンソールアプリケーションプロジェクトを作成してください。
JavaParser.csと同じ階層に作成するとパーサを作り直したときeclipseに消されてしまうので気をつけてください。
今回はJavaParser.csのある階層に1つディレクトリを作りその中にプロジェクトを作成しました。
パースするにもANTLRのランタイムが必要なので以下のページのDOT-NET-runtime-3.1.3.zipをダウンロードしてください。
http://www.antlr.org/download/CSharp
zipを解凍しておきます。
次にこれをC#プロジェクトに追加します。
ソリューションエクスプローラの参照設定を右クリックし、参照の追加でzipに含まれていたすべてのdllを選択し追加してください。
Antlr3.Runtime.dll Antlr3.Utility.dll antlr.runtime.dll StringTemplate.dll
JavaParser.cs JavaLexer.csも追加します。
このとき次の手順を踏むとソースをコピーせずプロジェクトに追加できます。
プロジェクトを右クリックし[追加]、[既存の項目]と進み、先の2つの.csを選択し、追加ボタンの右の三角形をクリックし、リンクとして追加を選択します。
ソリューションエクスプローラ上で2つのファイルのアイコンに矢印が付いていればコピーでなく参照として追加されたことがわかります。
ここでパースするコードを書こうと思っていたのですが、いくつかコンパイルエラーになってしまいます。
.gファイルを修正しましょう。
上の方にある@lexer::membersを以下のように修正してください
@lexer::members{ protected bool enumIsKeyword = true; protected bool assertIsKeyword = true; }
これはJavaLexer.csクラスのメンバとしてそのまま出力されます。
ですのでjavaの組み込み型であるbooleanでなくC#の組み込み型であるboolへの直しておきましょう。
続いて、Treeの実装と.gに書かれたTreeを使ったコードがかみ合わずエラーとなるので修正します。
$t1.getLine()や$t2.getLine()などは$t1.Line $t2.Lineとします。
C#ではLineがメソッドでなくプロパティとして提供されています。
同様にgetCharPositionInLine()はCharPositionInLineに直します。
最後にパースするコードを書きましょう。
//ファイルの読み込み string filename = @"test.java"; Antlr.Runtime.ANTLRFileStream fs = new Antlr.Runtime.ANTLRFileStream(filename);
もしくは
Antlr.Runtime.ANTLRStringStream fs = new Antlr.Runtime.ANTLRStringStream(@" class Main{ public static void Main(String[] arg){ int test = 0; System.out.println(test); } } ");
として直接ソースを書きます。
ANTLRFileStreamもANTLRStringStreamもICharStreamのサブクラスですのでどちらでもかまいません。
残りのコードは以下のようになります。
JavaLexer lex = new JavaLexer(fs); Antlr.Runtime.CommonTokenStream tokens = new Antlr.Runtime.CommonTokenStream(lex); JavaParser parse = new JavaParser(tokens); parse.compilationUnit();
ここでcompilationUnit()は構文のルールの中でももっとも最上位の物です。
このメソッドの戻り値から構文木を取得することが出来ます。
ここで意味でなく構文が無効となるソースを書いてどのようになるか試してみましょう。
たとえばclassをclasとすると構文解析に失敗します。
line 2:0 no viable alternative at input 'clas'
とコンソールに出力されると思います。
問題なく構文解析された場合はコンソールへの出力がありません。
今回は構文解析のみですのでここで終わりです。
コンパイラなどの作成には構文木を使用するようです。その辺はおいおい勉強して行こうと思います。