c++ - Boost Spirit Qi: Omit element in Kleene Star parser -
i want parse special constructs , throw rest away. don't want use skipper.
i want vector of these constructs, use kleene star parser main rule. but, everytime gets thrown away, default constructed element inserted vector.
here made example. looks string test
, throws rest away, @ least plan. every time rule garbage
succeeds adds default constructed item vector in rule all
, giving output of 7 insteat of 1. how can tell spirit add vector if rule item
succeeds?
#define boost_spirit_use_phoenix_v3 #include <boost/config/warning_disable.hpp> #include <boost/spirit/include/qi.hpp> #include <boost/fusion/adapted/struct.hpp> #include <boost/spirit/include/phoenix.hpp> #include <iostream> #include <string> #include <vector> namespace qi = boost::spirit::qi; struct container { std::string name; bool dummy; }; boost_fusion_adapt_struct(::container, (std::string, name) (bool, dummy)) int main() { typedef std::string::const_iterator iterator; qi::rule<iterator, std::vector<container>()> all; qi::rule<iterator, container()> item; qi::rule<iterator, std::string()> string_rule; qi::rule<iterator> garbage; = *(garbage | item); garbage = qi::char_ - qi::lit("test"); string_rule = qi::string("test"); item = string_rule >> qi::attr(true); std::vector<container> ast; std::string input = "blatestbla"; iterator first = input.begin(); iterator last = input.end(); bool result = qi::parse(first, last, all, ast); if (result) { result = first == last; } if (result) { std::cout << "parsed " << ast.size() << " element(s)" << std::endl; } else { std::cout << "failure" << std::endl; } }
since sehe's answer more or less educational purposes, have several solutions:
*garbage >> -(item % *garbage) >> *garbage *garbage >> *(item >> *garbage) = *(garbage | item[phx::push_back(qi::_val,qi::_1)]);
and solution cv_and_he:
#define boost_spirit_use_phoenix_v3 #include <boost/config/warning_disable.hpp> #include <boost/spirit/include/qi.hpp> #include <boost/fusion/adapted/struct.hpp> #include <boost/spirit/include/phoenix.hpp> #include <iostream> #include <string> #include <vector> namespace qi = boost::spirit::qi; struct container { std::string name; bool dummy; }; boost_fusion_adapt_struct(::container, (std::string, name) (bool, dummy)) struct container_vector { //added std::vector<container> data; }; namespace boost{ namespace spirit{ namespace traits //added { template <> struct is_container<container_vector> : boost::mpl::true_ {}; template <> struct container_value<container_vector> { typedef optional<container> type; }; template <> struct push_back_container<container_vector,optional<container> > { static bool call(container_vector& cont, const optional<container>& val) { if(val) cont.data.push_back(*val); return true; } }; }}} int main() { typedef std::string::const_iterator iterator; qi::rule<iterator, container_vector()> all; //changed qi::rule<iterator, container()> item; qi::rule<iterator, std::string()> string_rule; qi::rule<iterator> garbage; = *(garbage | item); garbage = qi::char_ - qi::lit("test"); string_rule = qi::string("test"); item = string_rule >> qi::attr(true); container_vector ast; //changed std::string input = "blatestbla"; iterator first = input.begin(); iterator last = input.end(); bool result = qi::parse(first, last, all, ast); if (result) { result = first == last; } if (result) { std::cout << "parsed " << ast.data.size() << " element(s)" << std::endl; //changed } else { std::cout << "failure" << std::endl; } }
although didn't want use skipper ended with:
start = qi::skip(garbage.alias())[*item];
this last solution fastest (by 1-2%) in unscientific tests using c-files of linux kernel production rules.
Comments
Post a Comment