構文解析の記事一覧

目次

jparsec

http://jparsec.codehaus.org/

パーサ生成フレームワーク

YACCとの違いは外部ファイルを必要としない点が違う。

Ruby版も存在しており、rparsecという。言語の先頭1文字をとって区別をつけている。 haskell版もあるがこちらが、元になっているので、こちらの名前はparsecという。

チュートリアル

http://jparsec.codehaus.org/jparsec2+Tutorial

日本語のjparsec使用ブログ

だいたいチュートリアルの和訳相当だと思っていいです。

http://d.hatena.ne.jp/taichitaichi/20071008/1191808121

俺的チュートリアル

実は、jparsecのソースコードをダウンロードすると、計算機のサンプルコードが入っていて、

これがチュートリアルで解説してあるようなコードよりもすっきりさわやかなコードなのだ。

だから、このサンプルから逆に構築する手順を、観察力+妄想力で、作り、俺的チュートリアルをつくるのだ!。それが、漢ってもんだろ。

ゴール

はっきりとしたゴールがあるってことは、それだけでも、しあわせなことなのさ。

/**
* The main calculator parser.
* 
* @author Ben Yu
*/
public final class Calculator {
 
 /** Parsers {@code source} and evaluates to an {@link Integer}. */
 public static int evaluate(String source) {
   return parser().parse(source);
 }
 
 static final Parser<Integer> NUMBER = Scanners.INTEGER.map(new Map<String, Integer>() {
   public Integer map(String text) {
     return Integer.valueOf(text);
   }
 });
 
 static final Binary<Integer> PLUS = new Binary<Integer>() {
   public Integer map(Integer a, Integer b) {
     return a + b;
   }
 };
 
 static final Binary<Integer> MINUS = new Binary<Integer>() {
   public Integer map(Integer a, Integer b) {
     return a - b;
   }
 };
 
 static final Binary<Integer> MUL = new Binary<Integer>() {
   public Integer map(Integer a, Integer b) {
     return a * b;
   }
 };
 
 static final Binary<Integer> DIV = new Binary<Integer>() {
   public Integer map(Integer a, Integer b) {
     return a / b;
   }
 };
 
 static final Binary<Integer> MOD = new Binary<Integer>() {
   public Integer map(Integer a, Integer b) {
     return a % b;
   }
 };
 
 static final Unary<Integer> NEG = new Unary<Integer>() {
   public Integer map(Integer i) {
     return -i;
   }
 };
 
 private static <T> Parser<T> op(char ch, T value) {
   return isChar(ch).retn(value);
 }
 
 static Parser<Integer> parser() {
   Parser.Reference<Integer> ref = Parser.newReference();
   Parser<Integer> term = ref.lazy().between(isChar('('), isChar(')')).or(NUMBER);
   Parser<Integer> parser = new OperatorTable<Integer>()
       .prefix(op('-', NEG), 100)
       .infixl(op('+', PLUS), 10)
       .infixl(op('-', MINUS), 10)
       .infixl(op('*', MUL), 20)
       .infixl(op('/', DIV), 20)
       .infixl(op('%', MOD), 20)
       .build(term);
   ref.set(parser);
   return parser;
 }
}

SQLの解析サンプルについて

jparsecをダウンロードし、解凍すると [jparsec-2.0_src]-[examples]-[src]-[org]-[codehaus]-[jparsec]-[examples]-[sql] がある。

Eclipseに取り込む手順

jparsecからダウンロードしてきたファイルを解凍しておきます。

junitのjarファイルも手元になければ、ダウンロードしてきます。

ダウンロードしてきたjunitはjunit-4.18.jarとかバージョン名がついているので、

junit.jarという名前にかえておきます。

junitはjparsecのlibフォルダに格納しておきます。

では、eclipseがわの準備を行ってみましょう。

Eclipseに新規にJavaプロジェクトを作成します。

ファイルメニューのインポートで先ほど解凍してできたフォルダを選択し、それをプロジェクトのsrcディレクトリを指定してとりこみます。

srcフォルダは、4つあります、本体用、本体test用、example用、exampleテスト用

インポート直後は

まだ、プロジェクトのビルドパスにjarが登録されていませんので、コンパイルエラーになっています。

そこで、ビルドパスの設定でparsecのlibフォルダ内のjarをすべて登録します。

コンパイルエラー表示はほぼ消えます。

が、1カ所だけAllTest?クラスでエラーになっています。

それは、作者がライブラリをあげたくないからだと build.xmlの80行目に明記してありました。

こんな感じ、

AllTests uses jtc, which is an extra dependency that I don't want to upload.

おそらく、Androidのソースを流用したコードだから、著作権の問題であげれないとでも思ったのでしょうか。

それはさておき、

	

build.xmlには、このクラスのみ除外してコンパイルする記述がありました。

要するにいらないんです。この

だからbuild.xmlをいじくりたくなかったので、つぎのようにクラスを書き換えておきました。

package org.codehaus.jparsec;

//import org.openqa.jtc.junit.TestSuiteBuilder;

import junit.framework.TestSuite;

/**
*
* @author benyu
*/
public class AllTests extends TestSuite {
 public static TestSuite suite() {
   //return TestSuiteBuilder.suite(AllTests.class);
   return null;
 }
}

コンパイル方法

build.xmlがあるので、toolは、ソースが公開されていないみたいなので、開発元の方用のantタスクかもしれません。それ以外はコンパイルできました。

exampleにあるSQLパーサの使い方

exampleのテストケースをみると使い方が書いてありました。

どこに書いてあるかというと

パッケージ名:

package org.codehaus.jparsec.examples.sql.parser;

クラス名:

RelationParserTest?

メソッド名:

 public void testSelect() {

内容の抜粋:

SQLの問い合わせ文

select distinct 1, 2 as id from t1, t2

が下記のようにクラスの構造に解析されているのを確認しているテストコードが書かれていました。

   Parser<Relation> parser = RelationParser.select(NUMBER, NUMBER, TABLE);
   assertParser(parser, "select distinct 1, 2 as id from t1, t2",
       new Select(true, 
           Arrays.asList(new Projection(number(1), null), new Projection(number(2), "id")),
           Arrays.asList(table("t1"), table("t2")),
           null, null, null));

persecのよみもの

Parsec, 高速なコンビネータパーサ

文字コードをEUCにしないと文字化けします。

http://www.lab2.kuis.kyoto-u.ac.jp/~hanatani/tmp/Parsec.html

トップ   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS