boost.spirit.qi:ルールの属性を取り、それを囲みますルールのstruct属性のフィールドとして設定しますか?
-
30-09-2019 - |
質問
これらの他の質問の多くと同様に、私は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つは互換性があり、それは確かに静的分析の観点からは当てはまるようですが、データは保持されていません。
私がどこかに欠けている参照(&)指定はありますか?
解決
整数がルールによって公開される属性であると想定されている場合、次のように宣言する必要があります。
qi::rule<Iterator, Integer()> integer;
(括弧に注意してください)。スピリットは、関数宣言の構文を使用して、ルールの「インターフェイス」を記述する必要があります。精神だけでなく、他のいくつかのライブラリによっても使用されます(たとえば、Boost :: functionを参照)。
これの主な理由は、関数インターフェイスを指定するための簡潔な方法であることです。ルールが何であるかを考えると、それが関数のようなものであることにすぐに気付きます。値(解析結果、つまり合成された属性)を返すことができます。さらに、1つ以上の引数(継承された属性)が必要になる場合があります。
第二に、しかし小さな理由は、スピリットがルールのさまざまなテンプレートパラメーターを区別できる必要があることです。テンプレートパラメーターは、任意の順序で(イテレーターを除く)任意の順序で指定できます。そのため、何が何であるかを理解するための何らかの手段が必要です。関数宣言の構文は、コンパイル時に認識できるように、スキッパーまたはエンコード(他の2つの可能なテンプレートパラメーター)とは十分に異なります。
あなたのさまざまな試みを見てみましょう:
上記のようにルール定義を変更すると、これを機能させることができます。
integer = qi::int_[qi::_val = qi::_1];
_val
あなたを指します Integer
, 、間 _1
を指します int
. 。したがって、課題演算子をから定義する必要があります int
これを機能させるには:
struct Integer {
int value;
Integer& operator=(int) {...}
};
この場合、融合シーケンスとしてタイプを適応させる必要はありません。
しかし、あなたはそれをさらに簡単に書くことができます:
integer = qi::int_ >> qi::eps;
これは100%等価です(EPSは、右側をパーサーシーケンスに変換するために使用されるトリックです。これにより、アダプトされた融合シーケンスの要素をシーケンスの要素の属性にマッピングする組み込みの属性伝播を利用できます。 )。
これ:
integer = qi::int_[qi::_r1 = qi::_1];
として機能しません _r1
ルールの最初の継承属性を指します。ただし、ルールには属性が妨げられていません。
これは機能します:
integer = qi::int_[phoenix::bind(&Integer::value, qi::_val) = qi::_1];
ただし、融合シーケンスとしてタイプを適応させる必要はありません。
そしてこれもそうです:
integer = qi::int_[phoenix::at_c<0>(qi::_val) = qi::_1];