разбирать оператор клини на набор альтернатив, адаптер? с духом х3 - PullRequest
0 голосов
/ 02 мая 2018

За последние пару недель я многое узнал об этом, но недостаточно. Код ниже компилируется и запускается, но код в TEST_ADAPT неполный, я не уверен, как установить соединение.

Цель состоит в том, чтобы выполнить синтаксический анализ в контейнере плоскости jane, который не имеет зависимости от варианта. Я понял, что могу получить набор ссылок на свое хранилище, которое духу нравится достаточно хорошо. (см. TEST_REF). Оператор клини ищет единый последовательный контейнер, но с набором альтернатив, который не представляется возможным. Поэтому я думаю, что мне нужно передать что-то, что является прокси-сервером для этого контейнера, но имеет механизм для определения местоположения в кортеже целевых ссылок.

Я думаю, для меня будет отличным упражнением написать это ContainerAdaptor, даже если это неправильный подход к этому. Поэтому мне интересно, в правильном ли я поле или на правильном пути.

Лучшее, что я могу сделать, - это использовать метод TEST_VECT и передать вектор, чтобы скопировать данные в мой контейнер ALL. Но это просто неправильно.

Обновление: Я сделал Target::All fusion адаптированным и сделал ContainerAdaptor частично функциональным. Достаточно, чтобы оператор клини принял это. Я должен иметь возможность подключиться к объекту 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 голосов
/ 03 мая 2018

Контейнер Adaptor 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 
...