13
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

RustのCombineパーサコンビネータの使い方例

Last updated at Posted at 2018-05-23

Combineって?

Rustのパーサコンビネータライブラリ。
Haskellのparsecを参考に作ったらしい。
LL構文解析。

インストール

Cargo.tomlに

[dependencies]
combine = "ほしいバージョン"

みたいにして書く
ほしいバージョンは以下から確認して選んだらいい
https://github.com/Marwes/combine/releases

一応現時点の最新バージョンである3.3.0で説明していく。

早速使う

ドキュメントも載せておく。

extern crate combine;
use combine::char::char;
use combine::{Parser, many1};
fn main() {
    let r = many1::<String, _>(char('a').or(char('b'))).parse("aabbaaaaaabababa");
    match r {
        Ok((value, _remaining_input)) => println!("{:?}", value),
        Err(err) => println!("{}", err),
    }
}

これは、任意個のaまたはbにマッチするパーサだ。
char('a')とかにするとaにマッチするパーサが作れる。
orで「または」を表現できる。
many1で複数回続くことを表現できる。
many1の<String,_>の部分の役割は、マッチした要素(今回だとchar型)の集合をどうやって表現するかを指定することだ。
String以外にもVec<char>とかも指定できる。
FromIterator<char>を実装している型であれば指定できるらしい。
作ったパーサはparse(パーサ対象)でパースし結果を得れる。
パーサ対象の型は&strだ。それ以外でもいけるがやり方よくわからん。
結果はResult型で、Okの場合、Ok(マッチしたもの,余ったもの)が返ってくる。

再帰したパーサを作る

パーサを再起するには、関数に包む必要がある。
それ用の便利なマクロがあるのでそれを使おう。

# [macro_use]
extern crate combine;
use combine::Parser;
use combine::char::char;
use combine::parser::choice::optional;
use combine::parser::item::value;
use combine::stream::Stream;
use std::option;
parser!{
    fn paren[I]()(I) ->i32
    where [I: Stream<Item=char>]
    {
        char('(').with(optional(paren())).skip(char(')')).then(
            |op|
            {
                match op {
                    Option::Some(x)=> value(x+1),
                    Option::None=>value(1)
                }
            }
        )
    }
}

fn main() {
    let r = paren().parse("((()))");
    match r {
        Ok((value, _remaining_input)) => println!("{:?}", value),
        Err(err) => println!("{}", err),
    }
}

これはネストしたカッコのネスト数を出力するパーサだ。
実行結果は3になった。

parser!がパーサを関数化するマクロだ。

    fn paren[I]()(I) ->i32
    where [I: Stream<Item=char>]

この部分について軽く説明。
Iは入力される値の型を示している。今回だと&strだ。
i32はパース結果の型だ。
それ以外はよくわからん。
parenの内部でparenを呼び出しているので無限再帰しそうだが、一旦関数ポインタに入れて工夫しているのだろう。無限ループしたりはしない。
マクロマジックだ。withやskipやvalue,optionalについては各自で調べてほしい。
参考URLだけ載せておく
https://docs.rs/combine/3.3.0/combine/parser/item/fn.value.html
https://docs.rs/combine/3.3.0/combine/parser/trait.Parser.html
https://docs.rs/combine/3.3.0/combine/parser/choice/fn.optional.html

13
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?