Upload
cct-inc
View
262
Download
3
Embed Size (px)
Citation preview
Parser Combinator ってなんなのさ
開発解析事業部 東
2014/08/21
文字列を解釈する処理
基本的に作るのが面倒
→ Parser Combinator を使って楽しよう
既存手法 補足
頑張って手書き 書くのが面倒、デバックが面倒
Parser Generator 使い方覚えるのが面倒
Parser Combinator
• Parser– 入力: 文字列
– 出力: 解析結果 (数値など),読み残し文字列
• Parser Combinator– 入力: 1つ以上の Parser
– 出力: 新しいParser
→ 単純な Parser から複雑な Parserを構築
例: 計算機を作ろう
0〜9の数字,+,* のみを含む文字列から
なる計算式を解釈,計算結果を返す
計算機1 0 + 2 * 3 16
計算機* 3_人人人人人_> エラー < ̄Y^Y^Y^Y ̄
文字列、数値、Parserの表記
文字列
1 0 + 2 * 3
空
数値
16
Parser
int1 0 + 2 * 3 10
+ 2 * 3
読み残し
解析結果
in out
関数、Parser Combinatorの表記関数
Parser Combinator
sum2
1
4
7
Chain
mul
2 * 3 6
空
in out
in out
どうやって解釈しよう?
1 0 + 2 3 4 * 5 + 6 * 7*
+ 区切りで分割してみる
1 0 + 2 3 4 * 5 + 6 * 7*
「整数が * 区切りで並んでいる文字列」が+ 区切りで並んでいる
3 つの Parser が必要?
1 0 + 2 3 4 * 5 + 6 * 7*
「整数が * 区切りで並んでいる文字列」が+ 区切りで並んでいる
Integer Parser Multiple Parser
Plus Parser
1 つの Parser Combinator が必要?
1 0 + 2 3 4 * 5 + 6 * 7*
「整数が * 区切りで並んでいる文字列」が+ 区切りで並んでいる
1 つの Parser Combinator が必要?
1 0 + 2 3 4 * 5 + 6 * 7*
「整数が * 区切りで並んでいる文字列」が+ 区切りで並んでいる
Integer parser
int1 0 + 2 * 3 10
+ 2 * 3
int1 0 0 100
空
int+ 2 * 3_人人人人人人_> 解析失敗 < ̄Y^Y^Y^Y^Y ̄
Character parser
char+ 2 * 3 0
2 * 3
char+ 0
空
char* 3
+
+
+
0
0
0
_人人人人人人_> 解析失敗 < ̄Y^Y^Y^Y^Y ̄
Chain Combinator
Chain
char int
* 1
mul
2 * 30 *1
• 入力を右、左、右 と交互にParserへ与える• 左のParserで解析できなかったら解析成功
Chain Combinator
Chain
char int
* 1
mul
2 * 30 *1
読み始める位置
入力を右側のparserで解釈する
Chain Combinator
Chain
char int
* 1
mul
2 * 30 *1
入力を右側のparserで解析する
10
Chain Combinator
Chain
char int
* 1
mul
2 * 30 *1
残りを左側のparserで解析する
10
Chain Combinator
Chain
char int
* 1
mul
2 * 30 *1
残りを左側のparserで解析する
10 1
Chain Combinator
Chain
char int
* 1
mul
2 * 30 *1
残りを右側のparserで解析する
10 1 2
Chain Combinator
Chain
char int
* 1
mul
2 * 30 *1
残りを左側のparserで解析する
10 1 2 1
Chain Combinator
Chain
char int
* 1
mul
2 * 30 *1
残りを右側のparserで解析する
10 1 2 1 3
Chain Combinator
Chain
char int
* 1
mul
2 * 30 *1
残りを左側のparserで解析する → 失敗→ (全体としては) 解析成功
10 1 2 1 3
Chain Combinator
Chain
char int
* 1
mul
2 * 30 *1
途中で得られた解析結果を関数で評価して全体の解析結果として返す
10 1 2 1 3
60
空
Chain
_人人人人人_> 計算機 <
 ̄Y^Y^Y^Y ̄
Chain
char int
* 1
mul
sum
char
+ 0
Parser Combinator 何が嬉しいの?
単純な Parser から
複雑な Parser を構築できる
– Parser 個別のテストがしやすい
– Parser の再利用性が高い
– Parser Combinator の再利用性が高い
Parser Combinator Library
Language Library
Haskell Parsec, Attoparsec
F# FParsec
Scala scala.util.parsing.combinator.Parsers
C# Sparche, csharp-monad
Python PyParsing
Sparche を用いた計算機の実装
var Int = Parse.Regex("[0-9]+").Select(int.Parse);
var Mul = Parse.String("*").Select(_ => 1);
var Plus = Parse.String("+").Select(_ => 0);
var MulExpr =
Parse.ChainOperator(Mul, Int,
(op, acc, elem) => acc * elem);
var PlusExpr =
Parse.ChainOperator(Plus, MulExpr,
(op, acc, elem) => acc + elem);
var result = PlusExpr.Parse("10+2*3");
典型的な Parser Combinator
• Combine(P1, P2)P1 で解析成功したらその読み残しをP2で解析、それも解析成功したら、解析成功
• Or(P1, P2)1. P1で解析成功したら解析成功2. P2で解析成功したら解析成功3. 両方失敗したらその解析失敗
• ZeroOrMore(P)P で0回以上解析できたら成功
まとめ
• Parser Combinator をざっくり説明した
• 利用例として簡単な計算機を定義した
• Parser Combinator Library を紹介した