首页 > 解决方案 > 将 kleene 运算符解析为一组备选方案,适配器?有精神 x3

问题描述

在过去的几周里,我学到了很多关于这些东西的知识,但还不够。下面的代码编译并运行,但代码TEST_ADAPT不完整,我不知道如何建立连接。

对象是解析成没有变体依赖的平面简容器。我发现我可以得到一个对我的存储的引用的元组,哪个精神足够好。(见TEST_REF)。kleene 操作员正在寻找一个单一的顺序容器,但在一组替代方案上,这看起来是不可能的。所以我想我需要给它一些东西,它是那个容器的代理,但有齿轮工作来定位目标引用的元组。

我认为写这篇文章对我来说将是一个很好的练习,ContainerAdaptor即使这是错误的方法。所以我想知道我是在正确的领域还是在正确的轨道上。

我知道我能完成的最好的事情是使用该TEST_VECT方法并通过向量将数据复制到我的ALL容器中。但这是不对的。

更新: 我已经对Target::All融合进行了调整并ContainerAdaptor部分实现了功能。足以让 kleene 操作员接受它。我应该能够连接到 Target::All 对象,也许......

#include <iostream>
#include <boost/fusion/include/as_vector.hpp>
#include <boost/fusion/adapted.hpp>
#include <boost/fusion/adapted/std_tuple.hpp>
#include <boost/fusion/include/boost_tuple.hpp>
#include <boost/spirit/home/x3.hpp>
#include <boost/spirit/home/x3/support/ast/variant.hpp>

//parse kleene operator to a set of alternatives, adaptor? with spirit x3
#define TEST_VECT
#define TEST_REF
#define TEST_ADAPT
// l.......................................................................
namespace Target {
    struct Int
    {
        int int_val;
    };
    using IntVect = std::vector<Int>;

    struct Word
    {
        std::string word_val;
    };
    using WordVect = std::vector<Word>;

    struct All
    {
        IntVect int_vect;
        WordVect word_vect;
    };
}

BOOST_FUSION_ADAPT_STRUCT(Target::Int, int_val)
BOOST_FUSION_ADAPT_STRUCT(Target::Word, word_val)
BOOST_FUSION_ADAPT_STRUCT(Target::All, int_vect, word_vect)

std::ostream& operator << (std::ostream& o, const Target::Int& in) { o << in.int_val; return o; }
std::ostream& operator << (std::ostream& o, const Target::Word& in) { o << in.word_val; return o; }
std::ostream& operator << (std::ostream& o, const Target::IntVect& in) { for( auto& i : in ) o << i << " "; return o; }
std::ostream& operator << (std::ostream& o, const Target::WordVect& in) { for (auto& i : in) o << i << " "; return o; }

#define DEF_RULE( RuleName, Attr ) static auto const RuleName = rule<struct Attr##_def, Attr>( #RuleName )
namespace Target {

    using namespace boost::spirit::x3;

    auto const bare_word = lexeme[+char_("a-z")];

    DEF_RULE(int_rule, Int) = int_;
    DEF_RULE(word_rule, Word) = bare_word;

    auto const int_vect_rule= "int" >> *int_rule;
    auto const word_vect_rule= "word" >> *(word_rule - "int");

    //another test
    DEF_RULE(f_int_vect_rule, IntVect) = int_vect_rule;
    DEF_RULE(f_word_vect_rule, IntVect) = word_vect_rule;

}//namespace Target

namespace Target {
    struct Printer {

        Printer(std::ostream& out) : out(out) {};
        using result_type = void;

        void operator()(const IntVect& expression) {
            out << "IntVect: ";
            for (auto& t : expression)
                out << t << " ";
            out << std::endl;
        }
        void operator()(const WordVect& expression) {
            out << "Word: ";
            for (auto& t : expression)
                out << t << " ";
            out << std::endl;
        }
    private:
        std::ostream& out;
    };
}//namespace Target

template<class Arg>
class ContainerAdaptor
{
public:
    ContainerAdaptor(Arg& arg) :arg(arg) { }
    typedef boost::spirit::x3::variant<Target::IntVect,Target::WordVect> value_type;
    typedef size_t size_type;
    struct Vis : public boost::static_visitor<>
    {
        void operator()(const Target::IntVect & i) const
        {
            std::cout << i << std::endl;
        }
        void operator()(const Target::WordVect & i) const
        {
            std::cout << i << std::endl;
        }

    };
    void insert(value_type* e, const value_type& v) {
        std::cout << "haha! ";
        boost::apply_visitor(Vis(), v);
    }
    value_type* end() { return nullptr; }
    value_type* begin() { return nullptr; }
    size_t size;

private:
    Arg & arg;
};

int main()
{
    using namespace Target;
    std::string thestr("word test more int 1 2 3 4 word this and that int 5 4 int 99 22");
    std::string::iterator end = thestr.end();

#if defined(TEST_ADAPT)
    {
        std::cout << "\nTEST_ADAPT\n";
        std::string::iterator begin = thestr.begin();
        All all;
        auto fwd = std::forward_as_tuple(all.word_vect, all.int_vect);

        ContainerAdaptor<All>attr( all );
        phrase_parse(begin, end, *( int_vect_rule | word_vect_rule), space, attr);
        Printer printer(std::cout);
    }
#endif
#if defined(TEST_VECT)
    {
        std::cout << "TEST_VECT\n";
        std::string::iterator begin = thestr.begin();
        using Vars = variant<Target::IntVect, Target::WordVect>;
        std::vector< Vars > a_vect;

        bool r = phrase_parse(begin, end, *( int_vect_rule | word_vect_rule), space, a_vect);

        Printer printer(std::cout);
        for (auto& i : a_vect)
            i.apply_visitor(printer);
    }
#endif
#if defined(TEST_REF)
    {
        std::cout << "\nTEST_REF\n";
        std::string::iterator begin = thestr.begin();
        All all;
        auto fwd = std::forward_as_tuple(all.word_vect,all.int_vect);
        phrase_parse(begin, end, word_vect_rule >> int_vect_rule, space, fwd);
        Printer printer(std::cout);
        std::_For_each_tuple_element(fwd, printer);
    }
#endif
    return 0;
}

标签: c++c++14boost-spiritboost-spirit-x3

解决方案


ContainerAdaptor 黑客

充分简化,它的工作原理:

Live On Coliru

#include <iostream>
#include <boost/fusion/adapted.hpp>
#include <boost/spirit/home/x3.hpp>
#include <boost/spirit/home/x3/support/ast/variant.hpp>

namespace Target {
    struct Int { int int_val; };
    struct Word { std::string word_val; };

    using IntVect = std::vector<Int>;
    using WordVect = std::vector<Word>;

    struct All {
        IntVect int_vect;
        WordVect word_vect;
    };
}

BOOST_FUSION_ADAPT_STRUCT(Target::Int, int_val)
BOOST_FUSION_ADAPT_STRUCT(Target::Word, word_val)

std::ostream& operator << (std::ostream& o, const Target::Int& in) { o << in.int_val; return o; }
std::ostream& operator << (std::ostream& o, const Target::Word& in) { o << in.word_val; return o; }
std::ostream& operator << (std::ostream& o, const Target::IntVect& in) { for( auto& i : in ) o << i << " "; return o; }
std::ostream& operator << (std::ostream& o, const Target::WordVect& in) { for (auto& i : in) o << i << " "; return o; }

namespace Target {
    using namespace boost::spirit::x3;

    static auto const int_rule  = rule<struct Int_def, Int>("int_rule")    = int_;
    static auto const word_rule = rule<struct Word_def, Word>("word_rule") = lexeme[+char_("a-z")];

    static auto const int_vect_rule  = "int" >> *int_rule;
    static auto const word_vect_rule = "word" >> *(word_rule - "int");
}

template<class Arg> struct ContainerAdaptor
{
    typedef boost::spirit::x3::variant<Target::IntVect,Target::WordVect> value_type;

    void insert(value_type* /*e*/, const value_type& v) {
        std::cout << "haha! ";
        struct Vis {
            //using result_type = void;

            void operator()(const Target::IntVect & i) const { std::cout << i << std::endl; }
            void operator()(const Target::WordVect & i) const { std::cout << i << std::endl; }
        };
        boost::apply_visitor(Vis(), v);
    }

    value_type* end()   { return nullptr; }
    value_type* begin() { return nullptr; }

    Arg & arg;
};

int main() {
    using namespace Target;
    std::string const thestr("word test more int 1 2 3 4 word this and that int 5 4 int 99 22");

    All all;
    ContainerAdaptor<All> attr { all };

    if (phrase_parse(begin(thestr), end(thestr), *( int_vect_rule | word_vect_rule), space, attr)) {
        std::cout << "Parsed: \n";
        std::cout << all.int_vect << "\n";
        std::cout << all.word_vect << "\n";
    }
}

印刷:

haha! test more 
haha! 1 2 3 4 
haha! this and that 
haha! 5 4 
haha! 99 22 
Parsed: 

为什么不是语义动作?

Live On Coliru

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

namespace Target {
    struct Int { int int_val; };
    struct Word { std::string word_val; };

    using IntVect = std::vector<Int>;
    using WordVect = std::vector<Word>;

    struct All {
        IntVect int_vect;
        WordVect word_vect;
    };
}

BOOST_FUSION_ADAPT_STRUCT(Target::Int, int_val)
BOOST_FUSION_ADAPT_STRUCT(Target::Word, word_val)

std::ostream& operator << (std::ostream& o, const Target::Int& in) { o << in.int_val; return o; }
std::ostream& operator << (std::ostream& o, const Target::Word& in) { o << in.word_val; return o; }
std::ostream& operator << (std::ostream& o, const Target::IntVect& in) { for( auto& i : in ) o << i << " "; return o; }
std::ostream& operator << (std::ostream& o, const Target::WordVect& in) { for (auto& i : in) o << i << " "; return o; }

namespace x3 = boost::spirit::x3;
namespace Target {
    using namespace x3;

    static auto const int_rule  = rule<struct Int_def, Int>("int_rule")    = int_;
    static auto const word_rule = rule<struct Word_def, Word>("word_rule") = lexeme[+char_("a-z")];

    static auto const int_vect_rule  = "int" >> *int_rule;
    static auto const word_vect_rule = "word" >> *(word_rule - "int");
}

int main() {
    std::string const thestr("word test more int 1 2 3 4 word this and that int 5 4 int 99 22");

    Target::All all;

    struct {
        Target::All& _r;
        void operator()(Target::IntVect const&v) const { _r.int_vect.insert(_r.int_vect.end(), v.begin(), v.end()); }
        void operator()(Target::WordVect const&v) const { _r.word_vect.insert(_r.word_vect.end(), v.begin(), v.end()); }
    } push_back { all };

    auto unary = [](auto f) { return [f](auto& ctx) { return f(x3::_attr(ctx)); }; };
    auto action = unary(push_back);

    if (phrase_parse(begin(thestr), end(thestr), *(Target::int_vect_rule[action] | Target::word_vect_rule[action]), x3::space)) {
        std::cout << "Parsed: \n";
        std::cout << all.int_vect << "\n";
        std::cout << all.word_vect << "\n";
    }
}

印刷

Parsed: 
1 2 3 4 5 4 99 22 
test more this and that 

使用特征

重新引入变体“value_type”:

Live On Coliru

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

namespace Target {
    struct Int { int int_val; };
    struct Word { std::string word_val; };

    using IntVect = std::vector<Int>;
    using WordVect = std::vector<Word>;

    struct All {
        IntVect int_vect;
        WordVect word_vect;
    };
}

BOOST_FUSION_ADAPT_STRUCT(Target::Int, int_val)
BOOST_FUSION_ADAPT_STRUCT(Target::Word, word_val)

std::ostream& operator << (std::ostream& o, const Target::Int& in) { o << in.int_val; return o; }
std::ostream& operator << (std::ostream& o, const Target::Word& in) { o << in.word_val; return o; }
std::ostream& operator << (std::ostream& o, const Target::IntVect& in) { for( auto& i : in ) o << i << " "; return o; }
std::ostream& operator << (std::ostream& o, const Target::WordVect& in) { for (auto& i : in) o << i << " "; return o; }

namespace boost { namespace spirit { namespace x3 { namespace traits {

    template<>
    struct container_value<Target::All> {
        using type = boost::variant<Target::IntVect, Target::WordVect>;
    };

    template<>
    struct push_back_container<Target::All> {
        template <typename V>
            static bool call(Target::All& c, V&& v) {
                struct {
                    Target::All& _r;
                    void operator()(Target::IntVect const&v) const { _r.int_vect.insert(_r.int_vect.end(), v.begin(), v.end()); }
                    void operator()(Target::WordVect const&v) const { _r.word_vect.insert(_r.word_vect.end(), v.begin(), v.end()); }
                } vis {c};
                boost::apply_visitor(vis, v);
                return true;
            }
    };

} } } }

namespace x3 = boost::spirit::x3;
namespace Target {
    using namespace x3;

    static auto const int_rule  = rule<struct Int_def, Int>("int_rule")    = int_;
    static auto const word_rule = rule<struct Word_def, Word>("word_rule") = lexeme[+char_("a-z")];

    static auto const int_vect_rule  = "int" >> *int_rule;
    static auto const word_vect_rule = "word" >> *(word_rule - "int");
}

int main() {
    std::string const thestr("word test more int 1 2 3 4 word this and that int 5 4 int 99 22");

    Target::All all;

    if (phrase_parse(begin(thestr), end(thestr), *(Target::int_vect_rule | Target::word_vect_rule), x3::space, all)) {
        std::cout << "Parsed: \n";
        std::cout << all.int_vect << "\n";
        std::cout << all.word_vect << "\n";
    }
}

印刷

Parsed: 
1 2 3 4 5 4 99 22 
test more this and that 

推荐阅读