Creating a vector of shared pointers by Spirit Qi

This is the next question from the previous question .

I can parse into vectors of strings from my grammar, but I cannot make out into a vector of common pointers to strings; those. std::vector<std::shared_ptr<std::string> >

and need a little help.

My compilation header:

#define BOOST_SPIRIT_USE_PHOENIX_V3 1


#include <boost/spirit/include/qi_core.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <iostream>
#include <string>


#include <boost/spirit/include/phoenix_stl.hpp>

#include <boost/phoenix/bind/bind_member_function.hpp>
#include <boost/spirit/include/phoenix_fusion.hpp>



// this solution for lazy make shared comes from the SO forum, user sehe.
// https://stackoverflow.com/questions/21516201/how-to-create-boost-phoenix-make-shared
//    post found using google search terms `phoenix construct shared_ptr`
// changed from boost::shared_ptr to std::shared_ptr
namespace {
    template <typename T>
    struct make_shared_f
    {
        template <typename... A> struct result
        { typedef std::shared_ptr<T> type; };

        template <typename... A>
        typename result<A...>::type operator()(A&&... a) const {
            return std::make_shared<T>(std::forward<A>(a)...);
        }
    };

    template <typename T>
    using make_shared_ = boost::phoenix::function<make_shared_f<T> >;
}




namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;


template<typename Iterator, typename Skipper = ascii::space_type>
struct SystemParser : qi::grammar<Iterator, std::vector<std::shared_ptr<std::string> >(), Skipper>
{


    SystemParser() : SystemParser::base_type(variable_group_)
    {
        namespace phx = boost::phoenix;
        using qi::_1;
        using qi::_val;
        using qi::eps;
        using qi::lit;


        var_counter = 0;

        declarative_symbols.add("variable_group",0);

        variable_group_ = "variable_group" > genericvargp_ > ';';
        genericvargp_ = new_variable_ % ','; //
        new_variable_ = unencountered_symbol_ [_val = make_shared_<std::string>() (_1)];
        unencountered_symbol_ = valid_variable_name_ - ( encountered_variables | declarative_symbols );
        valid_variable_name_ = +qi::alpha >> *(qi::alnum | qi::char_("[]_") );



//      debug(variable_group_); debug(unencountered_symbol_); debug(new_variable_); debug(genericvargp_);
//      BOOST_SPIRIT_DEBUG_NODES((variable_group_) (valid_variable_name_) (unencountered_symbol_) (new_variable_) (genericvargp_))
    }


    // rule declarations.  these are member variables for the parser.
    qi::rule<Iterator, std::vector<std::shared_ptr<std::string> >(), Skipper > variable_group_;
    qi::rule<Iterator, std::vector<std::shared_ptr<std::string> >(), Skipper > genericvargp_;
    qi::rule<Iterator, std::shared_ptr<std::string()> >  new_variable_;
    qi::rule<Iterator, std::string()> unencountered_symbol_;
    qi::rule<Iterator, std::string()> valid_variable_name_;


    unsigned var_counter;
    qi::symbols<char,int> encountered_variables;
    qi::symbols<char,int> declarative_symbols;
};

      

with driver code:

int main(int argc, char** argv)
{

    std::vector<std::shared_ptr<std::string> > V;
    std::string str = "variable_group x, y, z; ";


    std::string::const_iterator iter = str.begin();
    std::string::const_iterator end = str.end();


    SystemParser<std::string::const_iterator> S;


    bool s = phrase_parse(iter, end, S, boost::spirit::ascii::space, V);

    if (s)
    {
        std::cout << "Parse succeeded: " << V.size() << " variables\n";
        for (auto& s : V)
            std::cout << " - '" << s << "'\n";
    }
    else
        std::cout << "Parse failed\n";

    if (iter!=end)
        std::cout << "Remaining unparsed: '" << std::string(iter, end) << "'\n";


    return 0;
}

      

The text is parsed correctly, but the resulting vector has length 0, while the length should be 3. Somehow, it is std::shared_ptr<string>

not pressed on the back of the vector obtained from the rule genericvargp_

.

I've tried a lot of things, including reading all the debug information from test parsing and placing signs %=

for rule definitions to be used for rules for which there is a semantic action that doesn't assign _val

if I'm not mistaken. I also played all night and day using phx::bind

manual back push _val

but didn't get anywhere. I also confirmed that the make_shared_

one provided by sehe in another answer is actually lazy for std :: shared_ptr.

As an aside, I also struggled with getting the result unencountered_symbol_

to append to encountered_variables

to ensure that the variable names are unique ...

The problem is to propagate the result of the rule new_variable_

to the desired vector of shared pointers in the rule genericvargp_

.

+3


source to share


1 answer


This ad

qi::rule<Iterator, std::shared_ptr<std::string()> > new_variable_;

      

Doesn't match the desired type:

qi::rule<Iterator, std::shared_ptr<std::string>() > new_variable_;

      

Unfortunately, in the old SpiritV2 this attribute is silently ignored and the propagation of the attributes is not done. This also explains why there were no errors at compile time.



Live On Coliru

#define BOOST_SPIRIT_USE_PHOENIX_V3 1
#define BOOST_SPIRIT_DEBUG 1

#include <boost/spirit/include/qi_core.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <iostream>
#include <string>

#include <boost/spirit/include/phoenix_stl.hpp>

#include <boost/phoenix/bind/bind_member_function.hpp>
#include <boost/spirit/include/phoenix_fusion.hpp>

// this solution for lazy make shared comes from the SO forum, user sehe.
// https://stackoverflow.com/questions/21516201/how-to-create-boost-phoenix-make-shared
//    post found using google search terms `phoenix construct shared_ptr`
// changed from boost::shared_ptr to std::shared_ptr
namespace {
    template <typename T> struct make_shared_f {
        template <typename... A> struct result { typedef std::shared_ptr<T> type; };

        template <typename... A> typename result<A...>::type operator()(A &&... a) const {
            return std::make_shared<T>(std::forward<A>(a)...);
        }
    };

    template <typename T> using make_shared_ = boost::phoenix::function<make_shared_f<T> >;
}

namespace qi    = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;

template <typename Iterator, typename Skipper = ascii::space_type>
struct SystemParser : qi::grammar<Iterator, std::vector<std::shared_ptr<std::string> >(), Skipper> {

    SystemParser() : SystemParser::base_type(variable_group_) {
        namespace phx = boost::phoenix;
        using qi::_1;
        using qi::_val;
        using qi::eps;
        using qi::lit;

        var_counter = 0;

        declarative_symbols.add("variable_group", 0);

        variable_group_       = "variable_group" > genericvargp_ > ';';
        genericvargp_         = new_variable_ % ',';                                                                                      //
        new_variable_         = unencountered_symbol_ [_val = make_shared_<std::string>()(_1)];
        unencountered_symbol_ = valid_variable_name_ - (encountered_variables | declarative_symbols);
        valid_variable_name_  = +qi::alpha >> *(qi::alnum | qi::char_("[]_"));

        BOOST_SPIRIT_DEBUG_NODES((variable_group_) (valid_variable_name_) (unencountered_symbol_) (new_variable_) (genericvargp_))
    }

    // rule declarations.  these are member variables for the parser.
    qi::rule<Iterator, std::vector<std::shared_ptr<std::string> >(), Skipper> variable_group_;
    qi::rule<Iterator, std::vector<std::shared_ptr<std::string> >(), Skipper> genericvargp_;
    qi::rule<Iterator, std::shared_ptr<std::string>() > new_variable_;
    qi::rule<Iterator, std::string()> unencountered_symbol_;
    qi::rule<Iterator, std::string()> valid_variable_name_;

    unsigned var_counter;
    qi::symbols<char, qi::unused_type> encountered_variables;
    qi::symbols<char, qi::unused_type> declarative_symbols;
};

int main()
{
    std::vector<std::shared_ptr<std::string> > V;
    std::string str = "variable_group x, y, z; ";

    std::string::const_iterator iter = str.begin();
    std::string::const_iterator end = str.end();

    SystemParser<std::string::const_iterator> S;

    bool s = phrase_parse(iter, end, S, boost::spirit::ascii::space, V);

    if (s)
    {
        std::cout << "Parse succeeded: " << V.size() << " variables\n";
        for (auto& s : V)
            std::cout << " - '" << *s << "'\n";
    }
    else
        std::cout << "Parse failed\n";

    if (iter!=end)
        std::cout << "Remaining unparsed: '" << std::string(iter, end) << "'\n";
}

      

Printing

Parse succeeded: 3 variables
 - 'x'
 - 'y'
 - 'z'

      

As well as a lot of debugging information

+4


source







All Articles