web-dev-qa-db-ja.com

Parsec vs Yacc / Bison / Antlr:Parsecを使用する理由と時期

HaskellとParsecは初めてです。 第16章実世界のHaskellのParsecの使用 を読んだ後、私の頭の中に疑問が浮かびました。ParsecがYacc/Bison/Antlrのような他のパーサジェネレータよりも優れているのはなぜですか?

私の理解では、Parsecはパーサーを書くための素晴らしいDSLを作成し、Haskellはそれを非常に簡単で表現力豊かにします。しかし、構文解析は、複数のターゲット言語に出力する独自の言語に値する、そのような標準的で人気のあるテクノロジーです。では、たとえばBison/AntlrからHaskellコードを生成する代わりに、いつParsecを使用するのでしょうか。

この質問は、テクノロジーを少し超えて、業界の慣行の領域に入る可能性があります。パーサーを最初から作成する場合、Bison/Antlrなどと比較して、Haskell/Parsecを取得する利点は何ですか?

ところで:私の質問は これ と非常に似ていますが、そこでは十分に答えられませんでした。

42
Ning Wang

リストしたツールの主な違いの1つは、ANTLR、Bison、およびそれらの友人がパーサーgeneratorsであるのに対し、Parsecはパーサーcombinatorライブラリであるということです。

パーサジェネレータは、文法の説明を読み込み、パーサを吐き出します。一般に、既存の文法をcombine新しい文法に結合することはできません。また、生成された2つの既存のパーサーを新しいパーサーに結合することも確かに不可能です。

パーサーコンビネーターOTOHは何もしませんしかし既存のパーサーを新しいパーサーに結合します。通常、パーサーコンビネーターライブラリには、空の文字列または1つの文字を解析できる、いくつかの簡単な組み込みパーサーが付属しています。また、1つ以上のパーサーを受け取り、新しいパーサーを返すコンビネーターのセットが付属しています。 、元のパーサーのシーケンスを解析し(たとえば、dパーサーとoパーサーを組み合わせてdoパーサーを形成できます)、元のパーサーを交互に解析します(たとえば、 0パーサーと1パーサーから0|1パーサー)または元の解析を複数回解析します(繰り返し)。

これが意味するのは、たとえば、Javaの既存のパーサーとHTMLの既存のパーサーを取り、それらを組み合わせてJSPのパーサーにすることができるということです。

ほとんどのパーサジェネレータはこれをサポートしていないか、限られた方法でしかサポートしていません。パーサーコンビネーター OTOH のみこれをサポートし、他には何もサポートしません。

56
Jörg W Mittag

この質問と、質問内のリンクされた質問を確認することをお勧めします。

どのHaskell解析テクノロジーが最も使いやすいのか、そしてその理由は?

Haskellでは、Parsec(および他のパーサーコンビネーター)とパーサージェネレーターHappyの間で競争があります。すでにLR文法を使用している場合は、Happyを選択します。パーサーコンビネーターはLL形式の文法を使用し、LRからLLへの変換にはある程度の労力がかかり、コンビネーターパーサーは通常大幅に遅くなります。 Parsecを使用する文法がない場合は、Happyよりも柔軟性があり(強力)、HappyとAlexでコードを生成するよりも「Haskellで」作業する方が楽しいです。解析にHappyを使用する場合、ほとんどの場合、字句解析にAlexを使用する必要があります。

業界の慣習では、Parsecを取得するためだけにHaskellを使用することを決定するのは奇妙です。構文解析の場合、現在の言語のほとんどには、少なくともパーサジェネレータがあり、おそらくParsecのポートやPEGシステムなどのより柔軟なものがあります。

リンクされた質問に対するIraBaxterの答えは、translatorを作成するために、ヒマラヤの足場にたどり着くパーセクについてのスポットオンでしたが、トランスレータはパーサーの用途の1つにすぎないため、ANTLR、Happy、Parsecなどのかなりミニマリストなシステムで十分なドメインはまだたくさんあります。

9
stephen tetley

スティーブンの答えに続いて、パーサーコンビネーターを使い続けたい場合、パーセクの最も一般的な代替手段の1つはアトパーセクだと思います。主な違いは、アトパーセクは速度に偏って書かれており、それに応じてトレードオフを行うことです。たとえば、Parsecは、解析が失敗した場合に役立つエラーメッセージを返そうとするために簿記を行いますが、attoparsecは同じ程度には行いません。また、attoparsecは1つの入力ストリーム/トークンタイプに特化していると思いますが、Parsecは入力タイプから抽象化するため、String、ByteString、Textなどのタイプのストリームを問題なく解析できます。

6
chrisdb