JavaCCを使用した構文解析プログラムの開発環境を整える

よくログ等のテキストファイルを解析するプログラムを作成するのですが、
毎回Tokenを切り出すロジックを書くのが面倒です。

何か良い方法はないか探していると、JavaCCというライブラリを見つけました。

http://javacc.java.net/

Jythonみたいな言語の開発を行う用途にも使用されているようですが、
ログファイルの解析にも使えるはず。

まずは、Eclipseで開発できる環境を作ってみます。




javaccの取得



http://javacc.java.net/
ここの「Download JavaCC 5.0」のリンクからjavacc-5.0.tar.gzをダウンロードします。

ファイルを解凍すると、bin/libにjavacc.jarがありますので、これをコピーしておきます。





Eclipseの設定



テスト用にjavaccというJavaプロジェクトを作成しました。

113_01.png


src/main/javaに
・sample javaccで生成したパーサーを使用するプログラム作成用。
・sample.parser javaccで生成されるソースの置き場所。
という2つのパッケージを作成しました。


libフォルダを作成し、そこに取得しておいたjavacc.jarをコピーします。
これは、定義ファイルからソースファイルを出力するために必要なだけで、
プロジェクト内に存在する必要はありません。

ビルドパスにも含める必要はありません。
わかりやすさのためだけに、ここに配置しました。


src/main/resourceにSample.jjtファイルを作成しています。
これがjavaccの定義ファイルになります。


Sample.jjtからソースファイルを作成するため、antタスクを実行します。
そのため、build.xmlを作成し、Sample.jjtからjavaファイルを出力する
タスクを仕込みます。


ざっくりですが、構成の説明はこんな感じになります。








build.xml



javaccを起動し、javaのソースファイルを出力するbuild.xmlはこうなりました。


  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project name="javacc_test" default="javacc" basedir=".">
  3.     
  4.     <!-- javaソースの出力先 -->
  5.     <property name="src" location="src/main/java/sample/parser"/>
  6.     
  7.     <!-- javacc.jarを置いているディレクトリ -->
  8.     <property name="javacc.home" location="lib"/>
  9.     
  10.     <!-- jjtファイルの配置場所 -->
  11.     <property name="jjt.file" location="src/main/resource/Sample.jjt"/>
  12.     <!-- jjファイルの配置場所 -->
  13.     <property name="jj.file" location="${src}/Sample.jj"/>
  14.     
  15.     <target name="javacc">
  16.         <delete dir="${src}" includes="*.*"/>
  17.         
  18.         <!-- jjtreeタスクを実行して、jjtからjjファイルとjavaファイルを作成 -->
  19.         <jjtree target="${jjt.file}"
  20.             javacchome="${javacc.home}"
  21.             outputdirectory="${src}"/>
  22.         
  23.         <!-- jjファイルからjavaファイルを作成 -->
  24.         <javacc target="${jj.file}"
  25.             javacchome="${javacc.home}"
  26.             outputdirectory="${src}" />
  27.     </target>
  28.     
  29. </project>




まだ十分に理解できていないのですが、
jjtreeで、jjtファイルからいくつかのjavaファイルと、jjファイルを出力。
javaccで、上記で得たjjファイルからさらにjavaファイルを出力。

という流れになるようです。






Sample.jjt



まだ右も左もわからない状態なので、今回作成するパーサーは

・テキストファイル「Token.txt」を読み込む。
・「print python」と記載されていたら、「印字:パイソン」と出力する。
・「print perl」と記載されていたら、「印字:パール」と出力する。

ということをやってみたいと思います。



試行錯誤しながら作成したjjtファイルは以下のとおり。


  1. /* 生成オプション */
  2. options {
  3. STATIC = false;
  4. MULTI=true;
  5. VISITOR=true;
  6. }
  7. /*
  8.     出力するソースファイルのひな形定義開始
  9.     SampleParser」がクラス名になる
  10. */
  11. PARSER_BEGIN(SampleParser)
  12. /** Simple brace matcher. */
  13. package sample.parser;
  14. public class SampleParser {
  15. }
  16. PARSER_END(SampleParser)
  17. /* 無視する文字を定義 */
  18. SKIP:
  19. {
  20.     " " | "\r" | "\t" | "\n"
  21. }
  22. /* 出現するトークンを定義 */
  23. TOKEN:
  24. {
  25.         <PRINT: "print">
  26.     | <PYTHON: "python">
  27.     | <PERL: "perl">
  28. }
  29. /* print [言語]の定義 */
  30. ASTSample Sample():
  31. {}
  32. {
  33.     <PRINT> Lang() { return jjtThis;}
  34. }
  35. /* [言語]は、Python()かPerl()を取る */
  36. void Lang() #void :
  37. {}
  38. {
  39.         Python()
  40.     | Perl()
  41. }
  42. /* Python()は、pythonという文字列 */
  43. void Python():
  44. {}
  45. {
  46.     <PYTHON>
  47. }
  48. /* Python()は、perlという文字列 */
  49. void Perl():
  50. {}
  51. {
  52.     <PERL>
  53. }





build.xmlを右クリックして、antタスクを実行します。

113_02.png



sample.parserパッケージにSample.jjとクラスが作成されました。


ちなみに・・・

jjtreeで作成されるもの。

ASTPerl.java
ASTPython.java
ASTSample.java
JJTSampleParserState.java
Node.java
SampleParserTreeConstants.java
SampleParserVisitor.java
SimpleNode.java
Sample.jj





javaccで作成されるもの。

ParseException.java
SampleParser.java
SampleParserConstants.java
SampleParserTokenManager.java
SimpleCharStream.java
Token.java
TokenMgrError.java








サンプルプログラム



sampleパッケージにParserTestを作成しました。
内容はこんなかんじです。


  1. package sample;
  2. import java.io.File;
  3. import java.io.FileInputStream;
  4. import sample.parser.ASTPerl;
  5. import sample.parser.ASTPython;
  6. import sample.parser.ASTSample;
  7. import sample.parser.Node;
  8. import sample.parser.SampleParser;
  9. import sample.parser.SampleParserVisitor;
  10. import sample.parser.SimpleNode;
  11. public class ParserTest implements SampleParserVisitor {
  12.     public static void main(String[] args) throws Exception {
  13.         
  14.         FileInputStream is = new FileInputStream(new File("Token.txt"));
  15.         
  16.         SampleParser parser = new SampleParser(is, "UTF-8");
  17.         Node node = parser.Sample();
  18.         
  19.         ParserTest visitor = new ParserTest();
  20.         node.jjtAccept(visitor, null);
  21.         
  22.     }
  23.     @Override
  24.     public Object visit(SimpleNode node, Object data) {
  25.         return null;
  26.     }
  27.     @Override
  28.     public Object visit(ASTSample node, Object data) {
  29.         String word = node.jjtGetChild(0).jjtAccept(this, null)
  30.                 .toString();
  31.         
  32.         System.out.println("印字: " + word);
  33.         return null;
  34.     }
  35.     @Override
  36.     public Object visit(ASTPython node, Object data) {
  37.         return "パイソン";
  38.     }
  39.     @Override
  40.     public Object visit(ASTPerl node, Object data) {
  41.         return "パール";
  42.     }
  43.     
  44. }





Token.txtに

print python


と記載して実行してみると、

印字: パイソン


という結果が得られます。


また、Token.txtの内容を

print perl


と変更すると、

印字: パール


という出力が得られました。

とりあえず、想定通りに動いてくれたようです。



また、Token.txtの内容を

print etc


とすると、エラーになります。

Exception in thread "main" sample.parser.TokenMgrError:
Lexical error at line 1, column 7. Encountered: "e" (101), after : ""
    at sample.parser.SampleParserTokenManager.getNextToken(SampleParserTokenManager.java:289)
    at sample.parser.SampleParser.jj_ntk(SampleParser.java:211)
    at sample.parser.SampleParser.Lang(SampleParser.java:44)
    at sample.parser.SampleParser.Sample(SampleParser.java:16)
    at sample.ParserTest.main(ParserTest.java:21)





とりあえず、開発できる環境ができたので、ここまでメモしておきます。






【参考URL】
javacc
http://javacc.java.net/

Eclipse JavaCC
http://hondou.homedns.org/pukiwiki/index.php?Eclipse%20JavaCC

JavaCCによる構文記述
http://www.chimaira.org/docs/GrammersInJavaCC.htm

ant JavaCC
http://www.jajakarta.org/ant/ant-1.5/docs/ant-1.5/j/docs/manual/OptionalTasks/javacc.html


関連記事

コメント

非公開コメント

プロフィール

Author:symfo
blog形式だと探しにくいので、まとめサイト作成中です。
Symfoware まとめ

PR




検索フォーム

月別アーカイブ