c++ - Is it possible to attach an action to a boost::spirit::rule parser which assigns the parsed result to a member of a (yet) unknown instance? -


i'm trying reference member of (yet) unknown instance within boost::spirit rule definitions' action, in pseudocode,

instead of double_[ref(rn) = _1] i'm looking x** ppx; double_[ref(&x::rn, ppx) = _1]

a workaround simple "semantic action" parameter knows instance , able write it, like

qi::rule<iterator, skipper> start; my_grammar(datacontext*& datacontext) : my_grammar::base_type(start) , execcontext(execcontext) {     start = qi::double_[ boost::bind(&my_grammar::newvalueforxy, datacontext, ::_1) ]; 

however, i'm wondering if there possibility "bind" directly member variable it's possible bind "local" variable using "phoenix::ref(...) = value".

i tried following syntax:

start = qi::int_[ boost::bind<int&>(&datacontext::newvalueforxy, boost::ref(datacontext))() = ::_1] ]; 

but failed vs2010sp1 , error message

error c2440: '=': 'boost::arg' cannot converted ...

there several ways skin cat:

  1. you thought of deferring execution of bind expression: phx::bind can that
  2. alternatively, use attribute propagation (and without semantic actions altogether)
  3. lastly, use inherited attributes (e.g. when datacontext has no default constructor or copying expensive)

1. deferring bind phoenix

use phoenix bind purpose: result in phoenix actor, "deferred executed" @ time semantic action triggered.

here's reconstruction of missing code sample might have been after:

#include <boost/spirit/include/qi.hpp> #include <boost/spirit/include/phoenix.hpp>  namespace qi = boost::spirit::qi; namespace phx= boost::phoenix;  struct datacontext {     double xy; };  template <typename iterator, typename skipper> struct my_grammar : qi::grammar<iterator, skipper> {     my_grammar(datacontext& datacontext) : my_grammar::base_type(start)     {         start = qi::double_             [ phx::bind(&my_grammar::newvalueforxy,                      phx::ref(datacontext),                      qi::_1) ];     }   private:     static void newvalueforxy(datacontext& dc, double value)     {          dc.xy = value;     }      qi::rule<iterator, skipper> start; };  int main() {     const std::string s = "3.14";      datacontext ctx;      my_grammar<decltype(begin(s)), qi::space_type> p(ctx);     auto f(begin(s)), l(end(s));     if (qi::phrase_parse(f, l, p, qi::space))         std::cout << "success: " << ctx.xy << "\n"; } 

note:

  • phx::ref() wrap reference datacontext
  • qi::_1 instead of boost::_1 placeholder
  • given implementation of newvalueforxy have written

        start = qi::double_         [ phx::bind(&datacontext::xy, phx::ref(datacontext)) = qi::_1 ]; 

2. use attribute grammar, instead of semantic actions

however, i'd write same example using attributes instead of semantic actions (because that's they for):

#include <boost/fusion/adapted/struct.hpp> #include <boost/spirit/include/qi.hpp> #include <boost/spirit/include/phoenix.hpp>  namespace qi = boost::spirit::qi; namespace phx= boost::phoenix;  struct datacontext {     double xy; };  boost_fusion_adapt_struct(datacontext, (double, xy))  template <typename iterator, typename skipper> struct my_grammar : qi::grammar<iterator, datacontext(), skipper> {     my_grammar() : my_grammar::base_type(start) {         start = qi::double_;     }   private:     qi::rule<iterator, datacontext(), skipper> start; };  int main() {     const std::string s = "3.14";     static const my_grammar<decltype(begin(s)), qi::space_type> p;      datacontext ctx;     if (qi::phrase_parse(begin(s), end(s), p, qi::space, ctx))         std::cout << "success: " << ctx.xy << "\n"; } 

3. use inherited attributes pass in context reference

if absolutely insist, can use inherited attributes purpose:

#include <boost/spirit/include/qi.hpp> #include <boost/spirit/include/phoenix.hpp>  namespace qi = boost::spirit::qi; namespace phx= boost::phoenix;  struct datacontext {     double xy; };  template <typename iterator, typename skipper> struct my_grammar : qi::grammar<iterator, void(datacontext&), skipper> {     my_grammar() : my_grammar::base_type(start)      {         start = qi::double_ [ phx::bind(&datacontext::xy, qi::_r1) = qi::_1 ];     }     qi::rule<iterator, void(datacontext&), skipper> start; };  int main() {     const std::string s = "3.14";     const static my_grammar<std::string::const_iterator, qi::space_type> p;     datacontext ctx;     if(qi::phrase_parse(begin(s), end(s), p(phx::ref(ctx)), qi::space)) {         std::cout << "success: " << ctx.xy << "\n";     } } 

this more expressive @ call site:

qi::phrase_parse(begin(s), end(s), p(phx::ref(ctx)), qi::space)); 

and doesn't require context default constructible.


Comments

Popular posts from this blog

blackberry 10 - how to add multiple markers on the google map just by url? -

php - guestbook returning database data to flash -

delphi - Dynamic file type icon -