8

これらの他の質問の多くと同様に、Boost.Spirit.Qiを使用して、単純な文法を構造体のツリーに解析しようとしています。

私がやろうとしていることを可能な限り単純なケースに蒸留しようと思います。私は持っています:

struct Integer {
  int value;
};
BOOST_FUSION_ADAPT_STRUCT(Integer, (int, value))

後で、文法構造体の中に、次のメンバー変数があります。

qi::rule<Iterator, Integer> integer;

私が定義している

integer = qi::int_;

しかし、実際に整数を解析しようとすると、

qi::phrase_parse(iter, end, g, space, myInteger);

myInteger.value解析が成功すると、常に初期化されません。同様に、私は次の定義を試しました(明らかにコンパイルされないものは間違っています):

integer = qi::int_[qi::_val = qi::_1]; //compiles, uninitialized value
integer = qi::int_[qi::_r1 = qi::_1]; //doesn't compile
integer = qi::int_[phoenix::bind(&Integer::value, qi::_val) = qi::_1]; //doesn't
integer = qi::int_[phoenix::at_c<0>(qi::_val) = qi::_1]; //doesn't

明らかに、私はスピリット、フェニックス、または他の何かについて何かを誤解しています。私の理解では、これがここでqi::_1の最初の属性でありqi::int_、角括弧内の部分が関数オブジェクトとして実行されるときに、解析された整数を表す必要があります。integer次に、関数オブジェクトが囲んでいる属性を受け取りqi::_val、解析された整数をそれに割り当てようとすると仮定しています。私の推測では、私のBOOST_FUSION_ADAPT_STRUCT呼び出しのおかげで、この2つは互換性があり、静的分析の観点からは確かにそうであるように見えますが、データは保存されていません。

どこかに欠けている参照(&)指定はありますか?

4

1 に答える 1

15

Integer がルールによって公開される属性であると想定される場合は、次のように宣言する必要があります。

qi::rule<Iterator, Integer()> integer; 

(括弧に注意してください)。Spirit は、関数宣言構文を使用してルールの「インターフェース」を記述する必要があります。これは、Spirit だけでなく、他のいくつかのライブラリでも使用されています (たとえば、boost::function を参照してください)。

これの主な理由は、関数インターフェイスを指定するための簡潔な方法だからです。ルールとは何かを考えると、それが関数のようなものであることがすぐにわかります。値 (解析された結果、つまり合成された属性) を返す場合があります。さらに、1 つ以上の引数 (継承された属性) を取る場合があります。

2 つ目の小さな理由は、Spirit がルールのさまざまなテンプレート パラメータを区別できる必要があるためです。テンプレート パラメーターは (反復子を除いて) 任意の順序で指定できるため、何が何であるかを把握する手段が必要です。関数宣言の構文は、コンパイル時に認識できるように、スキッパーまたはエンコーディング (他の 2 つの可能なテンプレート パラメーター) とは十分に異なります。

あなたのさまざまな試みを見てみましょう:

上記のようにルール定義を変更すると、これを機能させることができます。

integer = qi::int_[qi::_val = qi::_1]; 

_valはあなたのを指しInteger、 は_1を指しますintintしたがって、これを機能させるには、代入演算子を定義する必要があります。

struct Integer {
    int value;
    Integer& operator=(int) {...}
};                    

この場合、型を Fusion シーケンスとして適応させる必要はありません。

しかし、もっと簡単に書くことができます:

integer = qi::int_ >> qi::eps;

これは 100% 同等です (eps は右側をパーサー シーケンスに変換するために使用されるトリックです。これにより、組み込みの属性伝播を利用して、適応した Fusion シーケンスの要素をシーケンスの要素の属性にマッピングできます。 )。

これ:

integer = qi::int_[qi::_r1 = qi::_1]; 

_r1ルールの最初に継承された属性を参照するようには機能しません。ただし、ルールには継承された属性はありません。

これはうまくいきます:

integer = qi::int_[phoenix::bind(&Integer::value, qi::_val) = qi::_1];

タイプを Fusion シーケンスとして適応させる必要はありません。

これも機能します:

integer = qi::int_[phoenix::at_c<0>(qi::_val) = qi::_1]; 
于 2011-01-06T22:15:57.780 に答える