解析kleene运算符到一组替代品,适配器?精神x3

时间:2018-05-01 23:55:11

标签: c++ c++14 boost-spirit boost-spirit-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;
}

1 个答案:

答案 0 :(得分:1)

ContainerAdaptor Hack

充分简化,它有效:

<强> 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