13

ブースト スピリット X3 ディレクティブリピートを可変の繰り返し係数で使用しようとしています。基本的な考え方は、ヘッダーがペイロードのサイズを指定する、ヘッダー + ペイロードの考え方です。簡単な例「3 1 2 3」は、ヘッダー = 3、データ = {1, 2, 3} (3 つの整数) として解釈されます。

精神気のドキュメントからしか例を見つけることができませんでした。ブースト フェニックス リファレンスを使用して可変因子をラップします

std::string str;
int n;
test_parser_attr("\x0bHello World",
    char_[phx::ref(n) = _1] >> repeat(phx::ref(n))[char_], str);
std::cout << n << ',' << str << std::endl;  // will print "11,Hello World"

運が悪い場合、精神 x3 の次の簡単な例を書きました。

#include <boost/spirit/home/x3.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <string>
#include <iostream>

namespace x3 = boost::spirit::x3;
using x3::uint_;
using x3::int_;
using x3::phrase_parse;
using x3::repeat;
using x3::space;
using std::string;
using std::cout;
using std::endl;

int main( int argc, char **argv )
{
  string data("3 1 2 3");
  string::iterator begin = data.begin();
  string::iterator end = data.end();

  unsigned int n = 0;

  auto f = [&n]( auto &ctx ) { n = x3::_attr(ctx); };
  bool r = phrase_parse( begin, end, uint_[f] >> repeat(boost::phoenix::ref(n))[int_], space );
  if ( r && begin == end  )
    cout << "Parse success!" << endl; 
  else
    cout << "Parse failed, remaining: " << string(begin,end) << endl;

  return 0;
}

上記のコードをブースト 1.59.0 と clang++ (フラグ: -std=c++14) でコンパイルすると、次の結果が得られます。

boost_1_59_0/boost/spirit/home/x3/directive/repeat.hpp:72:47: error: no matching constructor for

      initialization of 'proto_child0' (aka 'boost::reference_wrapper<unsigned int>')

            typename RepeatCountLimit::type i{};

repeat(3)代わりにハードコードするrepeat(boost::phoenix::ref(n))と正しく動作しますが、可変繰り返し係数をサポートする必要があるため、可能な解決策ではありません。

コンパイルはrepeat(n)正常に完了しますが、解析に失敗し、次の出力が表示されます。 “Parse failed, remaining: 1 2 3"

ソースコードを見ると、boost/spirit/home/x3/directive/repeat.hpp:72テンプレート型RepeatCountLimit::type変数の空のコンストラクターが呼び出さiれ、for ループ中に割り当てられ、min と max が繰り返されます。ただし、型は参照であるため、コンストラクターで初期化する必要があるため、コンパイルは失敗します。以前のライブラリ バージョン boost/spirit/home/qi/directive/repeat.hpp:162 からの同等のソース コードを見ると、直接割り当てられています。

        typename LoopIter::type i = iter.start();

ここで何が間違っているのか、または x3 が現在可変繰り返し係数をサポートしていないのかどうかはわかりません。この問題を解決するための助けをいただければ幸いです。ありがとうございました。

4

1 に答える 1

10

ソースとメーリング リストを読んで収集した情報によると、Phoenix は X3 にまったく統合されていません。その理由は、c++14 によってそのほとんどが廃止されたためです。

eps(DEFERRED_CONDITION)これにより、Qilazy(*RULE_PTR)が洗練された解決策を持っていた場所がいくつか残っていることに同意します。

Spirit X3はまだ開発中なので、これが追加されるかもしれません¹

今のところ、Spirit X3 には、ステートフル コンテキスト用の一般化された機能が 1 つあります。これは本質的に、場合によっては継承された引数を置き換えlocals<>、この特定のケースでも同様に要素の数を検証するように/することができます:

  • x3::with²

使用方法は次のとおりです。

with<_n>(std::ref(n)) 
    [ omit[uint_[number] ] >> 
    *(eps [more] >> int_) >> eps [done] ]

ここで、_nは、 で取得するコンテキスト要素を識別するタグ タイプですget<_n>(cxtx)

現在、コンテキスト内の定数要素になるため、左辺値への参照ラッパーを使用する必要があることに注意してください。これも、X# が成熟するにつれて解除される可能性のある QoI であると思いますnwith<_n>(0u)

次に、セマンティック アクションについて:

unsigned n;
struct _n{};

auto number = [](auto &ctx) { get<_n>(ctx).get() = _attr(ctx); };

これにより、解析された符号なし数値がコンテキストに格納されます。(実際、ref(n)前述のように、バインディングのため、実際には今のところコンテキストの一部ではありません)

auto more   = [](auto &ctx) { _pass(ctx) = get<_n>(ctx) >  _val(ctx).size(); };

ここで、実際に「いっぱい」ではないことを確認します。つまり、より多くの整数が許可されます。

auto done   = [](auto &ctx) { _pass(ctx) = get<_n>(ctx) == _val(ctx).size(); };

ここで、「いっぱい」であることを確認します。つまり、これ以上整数は許可されません

すべてを一緒に入れて:

Live On Coliru

#include <string>
#include <iostream>
#include <iomanip>

#include <boost/spirit/home/x3.hpp>

int main() {
    for (std::string const input : { 
            "3 1 2 3", // correct
            "4 1 2 3", // too few
            "2 1 2 3", // too many
            // 
            "   3 1 2 3   ",
        })
    {
        std::cout << "\nParsing " << std::left << std::setw(20) << ("'" + input + "':");

        std::vector<int> v;

        bool ok;
        {
            using namespace boost::spirit::x3;

            unsigned n;
            struct _n{};

            auto number = [](auto &ctx) { get<_n>(ctx).get() = _attr(ctx); };
            auto more   = [](auto &ctx) { _pass(ctx) = get<_n>(ctx) >  _val(ctx).size(); };
            auto done   = [](auto &ctx) { _pass(ctx) = get<_n>(ctx) == _val(ctx).size(); };

            auto r = rule<struct _r, std::vector<int> > {} 
                  %= with<_n>(std::ref(n)) 
                        [ omit[uint_[number] ] >> *(eps [more] >> int_) >> eps [done] ];

            ok = phrase_parse(input.begin(), input.end(), r >> eoi, space, v);
        }

        if (ok) {
            std::copy(v.begin(), v.end(), std::ostream_iterator<int>(std::cout << v.size() << " elements: ", " "));
        } else {
            std::cout << "Parse failed";
        }
    }
}

どちらが印刷されますか:

Parsing '3 1 2 3':          3 elements: 1 2 3 
Parsing '4 1 2 3':          Parse failed
Parsing '2 1 2 3':          Parse failed
Parsing '   3 1 2 3   ':    3 elements: 1 2 3 

¹ [spirit-general] メーリング リストでサポート/声を貸してください :)

² 適切なドキュメント リンクが見つかりませんが、一部のサンプルで使用されています

于 2015-11-10T10:34:17.090 に答える