Pass attribute to child rule in the spirit of forcing

I have two rules with the same attribute.

Can I pass the matrix_ rule attribute to the matrixBlock_ child rule? I want to keep the repeat directive from creating the attribute of the form vector <>. Instead, it should just write in the matrix_ (numBlocks times) attribute. I tried passing the attribute as an inherited attribute to the child rule, and it compiles (see below). But I get a few "ghostly" entries in my vector that do not come from the phoenix :: push_back. And this, it seems, is not the best way for me. Is it possible for us to automatically distribute attributes in matrixBlock_ instead of semantic actions?

typedef vector<columnT> Matrix; matrix_ = repeat(numBlocks)[ matrixBlock_(_val) ]; matrixBlock_ = *column[phoenix::push_back(_r1, _1)]; qi::rule<Iterator, Matrix(), ascii::space_type> matrix_; qi::rule<Iterator, void(Matrix&), ascii::space_type> matrixBlock_; 

Update

to clarify the question:

if I write a rule without semantic actions, the synthesized matrix_ attribute will be

 vector< vector< columnT > > 

-

 typedef vector<columnT> Matrix; matrix_ = repeat(numBlocks)[ matrixBlock_ ]; matrixBlock_ = *column; qi::rule<Iterator, Matrix(), ascii::space_type> matrix_; qi::rule<Iterator, Matrix(), ascii::space_type> matrixBlock_; 

I want it to have the same attribute type as matrixBlock_, a 1-dimensional array.


My actual solution is to use only one rule. (looks easy :-))

 typedef vector<columnT> Matrix; matrix_ = repeat(numBlocks)[ *column_[ phoenix::push_back(_val, _1) ] ]; //matrixBlock_ = *column; qi::rule<Iterator, Matrix(), ascii::space_type> matrix_; //qi::rule<Iterator, Matrix(), ascii::space_type> matrixBlock_; 

Update

I was able to play phantom records with this code in vs2010 and raise 1.46.1

http://liveworkspace.org/code/505091dc4631a379763567168a728e0c

: 42, 45, -9, 3, 2, 1, 12, 34, 56, 0, 0, 0

My mistake was to use the old version of Boost. No backgrounds since 1.5.

Now I have two working versions of my grammar. Is it possible to rework the grammar without using the semantic push_back action?

+2
source share
1 answer

Update

Answering your edited question: yes, you can do it without semantic actions, simply:

 template<typename It> struct Parser : qi::grammar<It, Matrix(), qi::space_type> { Parser() : Parser::base_type(matrix_) { matrixBlock_ = qi::lit(";") >> *qi::int_; matrix_ = qi::repeat(3)[ matrixBlock_ ]; } qi::rule<It, Matrix(), qi::space_type> matrixBlock_, matrix_; }; 

Please note that you can check the number of rows / columns. See my extended sample that uses an extra semantic action to check this out (note the subtle change from *int_ to +int_ to avoid blank lines):

 #include <boost/spirit/include/qi.hpp> #include <boost/spirit/include/karma.hpp> #include <boost/spirit/include/phoenix.hpp> namespace qi = boost::spirit::qi; namespace karma = boost::spirit::karma; namespace phx = boost::phoenix; typedef std::vector<int> Matrix; template<typename It> struct Parser : qi::grammar<It, Matrix(), qi::space_type> { Parser() : Parser::base_type(matrix_) { using namespace qi; matrixBlock_ = lit(";") >> +int_ >> eps( 0 == (phx::size(_val) % 3)); matrix_ = repeat(3)[ matrixBlock_ ]; } qi::rule<It, Matrix(), qi::space_type> matrixBlock_, matrix_; }; int main() { std::string test = ";42 45 -9; 3 2 1; 12 34 56"; std::string::const_iterator f(test.begin()), l(test.end()); Parser<std::string::const_iterator> parser; Matrix m; if (qi::phrase_parse(f,l,parser,qi::space, m)) std::cout << "Wokay\n"; else std::cerr << "Uhoh\n"; std::cout << karma::format(karma::auto_ % ", ", m) << "\n"; } 

Old answer:

Yes, you can use Spirit customization points to treat your custom type as a container. A record of the documentation that I propose for this is given below:

Here is a simple example showing how to use it, live:

Side note regarding “phantom entries”, in general:

Note that there are few FAQs related to backtrace grammars and container attributes. The fact is that for performance reasons, parsers will not cancel ("rollback") to their base containers during backtracking. You can force this behavior to use qi::hold , but it may be worth the effort to rework the grammar into

  • avoid return or
  • pass attribute at a later stage (using semantic actions)

Full sample code:

 #include <boost/spirit/include/qi.hpp> #include <boost/spirit/include/karma.hpp> namespace qi = boost::spirit::qi; namespace karma = boost::spirit::karma; struct Matrix { std::vector<int> data; }; namespace boost { namespace spirit { namespace traits { template <> struct is_container<Matrix> { }; template <typename Attrib> struct push_back_container<Matrix, Attrib> { static bool call(Matrix& c, Attrib const& val) { c.data.push_back(val); return true; } }; template <> struct container_value<Matrix> { typedef int type; }; } } } template<typename It> struct Parser : qi::grammar<It, Matrix(), qi::space_type> { Parser() : Parser::base_type(start) { start = *qi::int_; } qi::rule<It, Matrix(), qi::space_type> start; }; int main() { std::string test = "42 45 -9"; std::string::const_iterator f(test.begin()), l(test.end()); Parser<std::string::const_iterator> parser; Matrix m; if (qi::phrase_parse(f,l,parser,qi::space, m)) std::cout << "Wokay\n"; else std::cerr << "Uhoh\n"; std::cout << karma::format(karma::auto_ % ", ", m.data) << "\n"; } 

Output:

 Wokay 42, 45, -9 

Update

A bit more background:

Of course, for such a trivial example, which simply wraps the standard supported by the type of container, it would be quite easy to use the mail merge adaptation instead: ( http://liveworkspace.org/code/56aea8619867451a21cd49fddb1e93bd )

 #include <boost/spirit/include/qi.hpp> #include <boost/spirit/include/karma.hpp> #include <boost/fusion/adapted/struct.hpp> namespace qi = boost::spirit::qi; namespace karma = boost::spirit::karma; struct Matrix { std::vector<int> data; }; BOOST_FUSION_ADAPT_STRUCT(Matrix, (std::vector<int>, data)); int main() { std::string test = "42 45 -9"; std::string::const_iterator f(test.begin()), l(test.end()); Matrix m; if (qi::phrase_parse(f,l, qi::eps >> *qi::int_, qi::space, m)) std::cout << karma::format(karma::auto_ % ", ", m.data) << "\n"; } 

Note that qi::eps needed due to an error (AFAICT) with structures that contain only one data item. See discussion here (and some other references)

+4
source

Source: https://habr.com/ru/post/951439/


All Articles