4

次のように、セマンティックアクションでローカル変数の値を変更したい:

#define BOOST_SPIRIT_USE_PHOENIX_V3
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <string>

namespace qi = boost::spirit::qi;
namespace spirit = boost::spirit;
namespace ascii = boost::spirit::ascii;
using boost::phoenix::ref;
using boost::phoenix::bind;

void dummy(const std::vector<char>& v, int& var)
{
    var = 7;
}

template <typename Iterator>
struct x_grammar : public qi::grammar<Iterator, std::string(), ascii::space_type>
{
public:
    x_grammar() : x_grammar::base_type(start_rule, "x_grammar")
    {
        using namespace qi;
        int local_var = 0;
        start_rule = (+(char_ - ";"))[bind(dummy, _1, ref(local_var))];
        //repeat(ref(local_var))[some_rule];
    }
private:
    qi::rule<Iterator, std::string(), ascii::space_type> start_rule;
};

int main()
{
    typedef std::string::const_iterator iter;
    std::string storage("string;aaa");
    iter it_begin(storage.begin());
    iter it_end(storage.end());
    std::string read_data;
    using boost::spirit::ascii::space;
    x_grammar<iter> g;
    try {
        bool r = qi::phrase_parse(it_begin, it_end, g, space, read_data);
        std::cout << "Pass!\n";
    } catch (const qi::expectation_failure<iter>& x) {
        std::cout << "Error!\n";
    }
}

GCC 4.6.1 とブースト 1.55 を使用すると、厄介なコンパイル エラーが発生します。

4

2 に答える 2

7

コンパイル エラーが気になる場合は、おそらく有効なコードを記述する必要があることに注意せずにはいられません:/


有益なハットオン...

もちろん、それは軽薄な発言ですが、やや啓発的でもあります。

文法でコンストラクタローカル変数を使用するという考え全体が根本的に壊れていることを2 回言いました。

あなたが欲しいのは

  • 継承された属性
  • 気::ローカル
  • maayyyyybe、maaaayyybe 文法メンバー変数。ルールを再入不可にするという警告があります。

ここで本当に頭の中に入るために重要なことは、

Boost Spirit は、式テンプレートからパーサーを生成します。式テンプレートは 90% が静的な情報 (型のみ) であり、「コンパイル」 ( .compile()) されて「呼び出し可能」 ( .parse()) 形式になります。

最も重要なことは、セマンティック アクションで制御フローを記述できますが、定義サイトで実際に実行されるものはありません。後で呼び出すことができる遅延アクターに「コンパイル」されます。

生成された解析は、対応する解析式が一致する場合、条件付きでレイジー アクターを呼び出します。


建設的な帽子をかぶった...

関数を使用して属性を変換したいだけのようです。

できることは次のとおりです。

  1. セマンティック アクションの一部として変換し、結果を通常の属性に配置します (パーサー構成の「機能的」セマンティクスを維持します)。

    qi::rule<Iterator, exposed(), Skipper> myrule;
    myrule = int_ [ _val = phx::bind(custom_xform, _1) ];
    

    custom_xform古い学校の calleable (ポリモーフィックなものを含む) はどこにありますか?

    exposed custom_xform(int i) { return make_new_exposed(i); } 
    // or
    struct custom_xfrom_t {
    
      template <typename> struct result { typedef exposed type; };
    
      template <typename Int>
        exposed operator()(Int i) const {
            return make_new_exposed(i);
        }
    };
    static const custom_xform_t custom_xform;
    
  2. 構文糖衣を追加できます[1]

    qi::rule<Iterator, exposed(), Skipper> myrule;
    myrule = int_ [ _val = custom_xform(_1) ];
    

    これはcustom_xform、怠惰なアクターとして定義されている必要があります。

    phx::function<custom_xform_t> custom_xform; // `custom_xform_t` again the (polymorphic) functor
    

    これは通常の関数では機能しないことに気付くかもしれません。呼び出し可能なオブジェクトでラップするか、BOOST_PHOENIX_ADAPT_FUNCTIONマクロを使用してそれを行うことができます

  3. より頻繁に適用したい複雑な変換がある場合は、スピリット カスタマイズ ポイントの使用を検討してください。

    これらは、属性に特定のタイプを選択すると最もスムーズに機能します (たとえばAst::Multiplicity、 またはAst::VelocityRankingの代わりにintまたは ) 。double


[1] BOOST_SPIRIT_USE_PHOENIX_V3 を使用

于 2014-05-21T18:49:43.167 に答える