boost.orgのSpiritパーサー/ジェネレーターフレームワークの欠点は何ですか?
-
08-07-2019 - |
質問
いくつかの質問で、の推奨事項を見ました。 Spirit boost.org のparser-generatorフレームワークですが、コメントには人々から不満があります幸せでないスピリットを使用しています。それらの人々は、スピリットを使用することの欠点や欠点を他の人たちに喜んで説明してくれますか?
解決
これは非常にクールなアイデアであり、私はそれが気に入りました。 C ++テンプレートの使用方法を実際に学ぶことが特に役立ちました。
しかし、彼らのドキュメントは、小規模から中規模のパーサーにスピリットを使用することを推奨しています。完全な言語のパーサーは、コンパイルに時間がかかります。 3つの理由をリストします。
-
スキャナーなしの解析。それは非常に簡単ですが、バックトラッキングが必要な場合、パーサーの速度が低下する可能性があります。ただし、オプションです。レクサーが統合されている可能性があります。Spiritで構築されたCプリプロセッサーを参照してください。 〜300行の文法(.hファイルと.cppファイルの両方を含む)は、GCCで6Mのファイルにコンパイル(最適化なし)されます。インライン化と最大の最適化により、最大1,7Mになります。
-
遅い解析-文法の静的なチェックはなく、過剰な先読みが必要であることを示唆したり、たとえば左再帰の使用などの基本的なエラーを確認したりしません(再帰下降で無限再帰につながります)パーサーLL文法)。ただし、左再帰は追跡するのが本当に難しいバグではありませんが、先読みが多すぎると、解析時間が指数関数的になる可能性があります。
-
テンプレートの使用が多い-これには一定の利点がありますが、コンパイル時間とコードサイズに影響します。さらに、文法定義は通常、他のすべてのユーザーに表示される必要があり、さらに多くのコンパイル時間に影響します。 適切なパラメーターを使用して明示的なテンプレートのインスタンス化を追加することで、文法を.cppファイルに移動できましたが、簡単ではありませんでした。
更新:私の回答は、Spirit V2ではなく、Spirit classicでの経験に限定されます。私はまだSpiritがテンプレートベースに大きく依存することを期待していますが、今は推測しているだけです。
他のヒント
ブースト1.41では、Spiritの新しいバージョンがリリースされ、それはspirit :: classic:
からズボンを打ち負かしますベータ版での長い時間の後(2つ以上 Spirit 2.0での年数)、Spirit 2.1 ついにリリースされます 今後のBoost 1.41リリース。コード 今非常に安定しており、準備ができています 生産コード。私たちは一生懸命働いています 時間内にドキュメントを完成させる Boost 1.41の場合。あなたはで覗くことができます ドキュメントの現在の状態 ここに。現在、あなたはコードを見つけることができます Boost SVNのドキュメント トランク。新しいプロジェクトがある場合 スピリットを含む、私たちは強くお勧めします Spirit 2.1から始めます。許して OvermindDLの投稿を引用する Spiritメーリングリスト:
ボットのように聞こえ始めるかもしれません どれくらいの頻度でこれを言いますが、 Spirit.Classicは古代です。 Spirit2.1に切り替えて、それができる あなたが素晴らしい取引の上にしたすべて 簡単、はるかに少ないコード、そしてそれ より速く実行します。例えば、 Spirit2.1はAST全体を構築できます インライン、奇妙なオーバーライド、不要 後で物事を構築するなど すべてが素晴らしく、速いステップとして。君は 本当に更新する必要があります。他を見る へのリンクの過去日の投稿 Spirit2.1のドキュメントなど。スピリット2.1 現在ブーストトランクにありますが、 Boost 1.41で正式にリリースされる それ以外は完全です。
私にとって最大の問題は、Spiritの式がコンパイラーまたはデバッガーで見るとかなり長いことです(Spirit Classicの1つの式の一部の下にコピーしました)。これらの表現は私を怖がらせます。 Spiritを使用するプログラムで作業するとき、valgrindを使用したり、gdbでバックトレースを出力したりするのが怖いです。
boost::spirit::classic::parser_result<boost::spirit::classic::action<boost::spirit::classic::sequence<boost::spirit::classic::action<boost::spirit::classic::action<optional_suffix_parser<char const*>, boost::spirit::classic::ref_actor<std::vector<std::string, std::allocator<std::string> >, boost::spirit::classic::clear_action> >, boost::spirit::classic::ref_actor<std::vector<int, std::allocator<int> >, boost::spirit::classic::clear_action> >, boost::spirit::classic::sequence<boost::spirit::classic::alternative<boost::spirit::classic::alternative<boost::spirit::classic::action<boost::spirit::classic::contiguous<boost::spirit::classic::sequence<boost::spirit::classic::alternative<boost::spirit::classic::chlit<char>, boost::spirit::classic::chlit<char> >, boost::spirit::classic::positive<boost::spirit::classic::alternative<boost::spirit::classic::alternative<boost::spirit::classic::alnum_parser, boost::spirit::classic::chlit<char> >, boost::spirit::classic::chlit<char> > > > >, boost::spirit::classic::ref_value_actor<std::vector<std::string, std::allocator<std::string> >, boost::spirit::classic::push_back_action> >, boost::spirit::classic::action<boost::spirit::classic::rule<boost::spirit::classic::scanner<char const*, boost::spirit::classic::scanner_policies<boost::spirit::classic::skipper_iteration_policy<boost::spirit::classic::iteration_policy>, boost::spirit::classic::match_policy, boost::spirit::classic::action_policy> >, boost::spirit::classic::nil_t, boost::spirit::classic::nil_t>, boost::spirit::classic::ref_const_ref_actor<std::vector<std::string, std::allocator<std::string> >, std::string, boost::spirit::classic::push_back_action> > >, boost::spirit::classic::contiguous<boost::spirit::classic::sequence<boost::spirit::classic::chlit<char>, boost::spirit::classic::action<boost::spirit::classic::uint_parser<unsigned int, 10, 1u, -1>, boost::spirit::classic::ref_value_actor<std::vector<int, std::allocator<int> >, boost::spirit::classic::push_back_action> > > > >, boost::spirit::classic::kleene_star<boost::spirit::classic::sequence<boost::spirit::classic::chlit<char>, boost::spirit::classic::alternative<boost::spirit::classic::alternative<boost::spirit::classic::action<boost::spirit::classic::contiguous<boost::spirit::classic::sequence<boost::spirit::classic::alternative<boost::spirit::classic::chlit<char>, boost::spirit::classic::chlit<char> >, boost::spirit::classic::positive<boost::spirit::classic::alternative<boost::spirit::classic::alternative<boost::spirit::classic::alnum_parser, boost::spirit::classic::chlit<char> >, boost::spirit::classic::chlit<char> > > > >, boost::spirit::classic::ref_value_actor<std::vector<std::string, std::allocator<std::string> >, boost::spirit::classic::push_back_action> >, boost::spirit::classic::action<boost::spirit::classic::rule<boost::spirit::classic::scanner<char const*, boost::spirit::classic::scanner_policies<boost::spirit::classic::skipper_iteration_policy<boost::spirit::classic::iteration_policy>, boost::spirit::classic::match_policy, boost::spirit::classic::action_policy> >, boost::spirit::classic::nil_t, boost::spirit::classic::nil_t>, boost::spirit::classic::ref_const_ref_actor<std::vector<std::string, std::allocator<std::string> >, std::string, boost::spirit::classic::push_back_action> > >, boost::spirit::classic::contiguous<boost::spirit::classic::sequence<boost::spirit::classic::chlit<char>, boost::spirit::classic::action<boost::spirit::classic::uint_parser<unsigned int, 10, 1u, -1>, boost::spirit::classic::ref_value_actor<std::vector<int, std::allocator<int> >, boost::spirit::classic::push_back_action> > > > > > > > >, void ()(char const, char const*)>, boost::spirit::classic::scanner<char const*, boost::spirit::classic::scanner_policies<boost::spirit::classic::skipper_iteration_policy<boost::spirit::classic::iteration_policy>, boost::spirit::classic::match_policy, boost::spirit::classic::action_policy> > >::type boost::spirit::classic::action<boost::spirit::classic::sequence<boost::spirit::classic::action<boost::spirit::classic::action<
ここに私が嫌いなものがあります:
-
ドキュメントは限られています。 <!> quot; everything <!> quot;という1つの大きなWebページがあります。説明されていますが、現在の説明には詳細がありません。
-
ASTの生成が不十分です。 ASTの説明が不十分であり、AST修飾子がどのように機能するかを理解するために頭を壁に当てた後でも、ASTを簡単に操作することは困難です(つまり、問題の領域にうまく対応するもの)
-
<!> quot; medium <!> quot;サイズの文法でも、コンパイル時間が大幅に増加します
-
構文が重すぎます。 C / C ++では、コードを複製する必要があります(つまり、宣言と定義の間)。ただし、boost :: spiritでは、文法を宣言するときに<!> lt; <!> gt;、3回繰り返す必要があります:D(ASTが必要なとき、これが欲しい:D)
これ以外は、C ++の制限を考えると、パーサーでかなり良い仕事をしたと思います。しかし、もっと改善すべきだと思います。履歴ページには、<!> quot; dynamic <!> quot;があったことが記載されています。現在の<!> quot; static <!> quotの前のスピリット;精神;私はそれがどれくらい速くてどれくらい優れた構文を持っていたのだろうと思っています。
最大の問題は、文法の問題に対する診断やその他の助けがないことだと思います。文法があいまいな場合、パーサーは期待する内容を解析しない可能性があり、それに気付く良い方法はありません。