3

ルールが完全に事前定義されていない、つまり変数部分が含まれているパーサーを定義しようとしていました。これは Spirit Qi では問題ありませんでしたが、X3 の静的な性質のために実装できませんでした。with ディレクティブを試しましたが、残念ながら文書化されていませんが、これまでのところ運がありません。これまでに見つけた唯一の例は、ラムダ式の中にあります。

問題を実証するために簡単な例を作成しました。セパレーターがパラメーターとして指定されている整数の解析です。

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

namespace x3 = boost::spirit::x3;

namespace parsing {
    x3::rule<struct parser> parser {"parser"};

    //struct separator {};
    char separator(',');

    //auto parser_def = x3::int_ % x3::lit(x3::get<separator>(/* context */)); // candidate function template not viable: requires single argument 'context'
    auto parser_def = x3::int_ % x3::lit(separator);

    BOOST_SPIRIT_DEFINE(parser)
}

void parse(const std::string &data, const char separator) {
    using namespace std;

    //auto parser = x3::with<parsing::separator>(ref(separator)) [parsing::parser] >> x3::eoi;
    auto parser = parsing::parser >> x3::eoi;

    if (x3::parse(data.begin(), data.end(), parser))
        cout << "Parse succeeded\n";
    else
        cout << "Parse failed\n";
}

int main() {
    parse("1 2 3", ' ');
    parse("1,2,3", ',');
    parse("1;2;3", ';');
}

with ディレクティブを使用しようとした部分をコメントアウトしました。

これは現在 X3 で可能ですか? 誰もこれを以前にやったことがありますか?

4

2 に答える 2

1

X3 の投稿をさらにいくつか見た後、sehe のこの回答に啓発されました: https://stackoverflow.com/a/38303379/7110782

x3::_pass について知ることで、この解決策にたどり着きました。

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

namespace x3 = boost::spirit::x3;

namespace parsing {
    x3::rule<struct parser> parser {"parser"};

    struct separator {};

    // only the separator which is currently in the context is allowed (passes)
    auto isSeparator = [](auto& ctx){ x3::_pass(ctx) = x3::_attr(ctx) == x3::get<separator>(ctx); };

    // at first match any char and then check whether it is the separator
    auto parser_def = x3::int_ % x3::char_[isSeparator];

    BOOST_SPIRIT_DEFINE(parser)
}

void parse(const std::string &data, const char separator) {
    using namespace std;

    auto parser = x3::with<parsing::separator>(ref(separator)) [parsing::parser] >> x3::eoi;

    if (x3::parse(data.begin(), data.end(), parser))
        cout << "Parse succeeded\n";
    else
        cout << "Parse failed\n";
}

int main() {
    // succeed
    parse("1 2 3", ' ');
    parse("1,2,3", ',');
    parse("1;2;3", ';');

    // fail
    parse("1,2,3", ' ');
    parse("1;2;3", ',');
}

さらなるステップでテストする必要があるのは、複数のパラメーターを設定する可能性です (おそらく x3::with<> のカスケード経由)。

編集:

はい、カスケード x3::with<> を介して複数のパラメーターを設定するとうまくいくようです。例えば:

auto parser = x3::with<parsing::separator>(ref(separator))[x3::with<parsing::separator2>(ref(separator2))[parsing::parser]] >> x3::eoi;
于 2016-11-04T08:22:18.023 に答える