文脈自由文法の書き方と構文解析の方法を学ぶために、ツールを選びたいと思います。Haskellには、2つの大きなオプションがあります。文法の説明からパーサーを生成するHappyと、Haskellでパーサーを直接コーディングできる*Parsecです。
どちらのアプローチの(不)利点は何ですか?
文脈自由文法の書き方と構文解析の方法を学ぶために、ツールを選びたいと思います。Haskellには、2つの大きなオプションがあります。文法の説明からパーサーを生成するHappyと、Haskellでパーサーを直接コーディングできる*Parsecです。
どちらのアプローチの(不)利点は何ですか?
外部 DSL と内部 DSL
Happy のパーサー仕様フォーマットは外部 DSL ですが、Parsec を使用すると、パーサーを定義するときに Haskell のフルパワーを利用できます。これは、たとえば、関数を記述してパーサーを生成したり、Template Haskell を使用したりできることを意味します。
優先ルール
Happy では優先順位を使用して文法を単純化できますが、Parsec では文法規則を自分で正しくネストする必要があります。したがって、Parsec では、演算子の優先順位を変更するのは非常に面倒です。
静的チェック
Happy は、コンパイル時に文法のあいまいさについて警告します。(ただし、それらがどこにあるかを伝えるのは得意ではありません。) Parsec を使用すると、実行時にパーサーが失敗するまで警告が表示されません。
これは従来の決定です。lex/yacc(ハッピー)を使用するのか、それとも独自の(ほとんど再帰下降)パーサーを作成するのか、パーセクライブラリはそれを正しく行うためのDSLのようなものです。
yacc / lexアプローチの経験がある場合、happyを使用すると学習曲線が短くなります。
私の意見では、Parsec は厄介な文法の詳細のほとんどを隠し、パーサーをより直感的に記述できるようにします。そもそもこのようなことを学びたい場合は、Happy のようなパーサー ジェネレーターを使用してください (または、自分で実装してみてください)。
私はユトレヒト大学のパーサーコンビネーターライブラリuu-parsinglibに慣れています。エラー訂正と順列を無料で、そしてパーセクが持っているものを手に入れることができます。また、実装した文法がEBNF文法のように見え、単調なものがあまりなく、読みやすいので、私も気に入っています。
単純なパーサー コンビネータでは、文法規則で左再帰が許可されません。許可するライブラリは見つかりませんでした。
Happy は、言語仕様で完全な BNF を許可し、優先ルールのようないくつかの便利なスタッフを許可します。そのため、複雑なケースでは、ハッピー ジェネレーターとパーサー ジェネレーターが一般的にはるかに優れています。ただし、LL(k) 構文解析可能な文法を使用する単純でばかげた言語の場合は、パーサー コンビネーター ライブラリをより保守しやすいものとして使用します。