Re: comment:
Thanks for your answers. I wanted to do both usual parsing and keeping the maximum encountered string, and it worked with : var_ = *as_string[qi::lexeme[ +digit ]] [if_(phx::ref(m) < _1) [phx::ref(m) = _1], _val = _1];
For even more fun, and in the interest of complete overkill, I've come up with something that I think is close to useful:
Live On Coliru
int main() {
do_test<int>(" 1 99 -1312 4 1014", -9999);
do_test<double>(" 1 NaN -4 7e3 7e4 -31e9");
do_test<std::string>("beauty shall be in ze eye of the beholder", "", qi::as_string[qi::lexeme[+qi::graph]]);
}
The sample prints:
Parse success: 5 elements with maximum of 1014
values: 1 99 -1312 4 1014
Parse success: 6 elements with maximum of 70000
values: 1 nan -4 7000 70000 -3.1e+10
Parse success: 9 elements with maximum of ze
values: beauty shall be in ze eye of the beholder
As you can see, with string
we need to help the Spirit a bit because it doesn't know how you would like to "define" a single "word". The test driver is completely generic:
template <typename T, typename ElementParser = typename boost::spirit::traits::create_parser<T>::type>
void do_test(std::string const& input,
T const& start_value = std::numeric_limits<T>::lowest(),
ElementParser const& element_parser = boost::spirit::traits::create_parser<T>::call())
{
using It = std::string::const_iterator;
vector_and_max<T> data;
It it = input.begin(), end = input.end();
bool ok = qi::phrase_parse(it, end, max_parser<It, T>(start_value, element_parser), qi::space, data);
if (ok) {
std::cout << "Parse success: " << data.first.size() << " elements with maximum of " << data.second << "\n";
std::copy(data.first.begin(), data.first.end(), std::ostream_iterator<T>(std::cout << "\t values: ", " "));
std::cout << "\n";
} else {
std::cout << "Parse failed\n";
}
if (it != end)
std::cout << "Remaining unparsed: '" << std::string(it,end) << "'\n";
}
The start-element and element-parser are passed to the constructor of our grammar:
template <typename T>
using vector_and_max = std::pair<std::vector<T>, T>;
template <typename It, typename T, typename Skipper = qi::space_type>
struct max_parser : qi::grammar<It, vector_and_max<T>(), Skipper> {
template <typename ElementParser>
max_parser(T const& start_value, ElementParser const& element_parser) : max_parser::base_type(start) {
using namespace qi;
using phx::if_;
_a_type running_max;
vector_with_max %=
eps [ running_max = start_value ]
>> *boost::proto::deep_copy(element_parser)
[ if_(_1>running_max) [running_max=_1], _pass = true ]
>> attr(running_max)
;
start = vector_with_max;
}
private:
qi::rule<It, vector_and_max<T>(), Skipper> start;
qi::rule<It, vector_and_max<T>(), Skipper, qi::locals<T> > vector_with_max;
};
Full Listing
For reference
Live On Coliru
#define BOOST_SPIRIT_USE_PHOENIX_V3
#include <boost/fusion/adapted/std_pair.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
namespace qi = boost::spirit::qi;
namespace phx = boost::phoenix;
template <typename T>
using vector_and_max = std::pair<std::vector<T>, T>;
template <typename It, typename T, typename Skipper = qi::space_type>
struct max_parser : qi::grammar<It, vector_and_max<T>(), Skipper> {
template <typename ElementParser>
max_parser(T const& start_value, ElementParser const& element_parser) : max_parser::base_type(start) {
using namespace qi;
using phx::if_;
_a_type running_max;
vector_with_max %=
eps [ running_max = start_value ]
>> *boost::proto::deep_copy(element_parser)
[ if_(_1>running_max) [running_max=_1], _pass = true ]
>> attr(running_max)
;
start = vector_with_max;
}
private:
qi::rule<It, vector_and_max<T>(), Skipper> start;
qi::rule<It, vector_and_max<T>(), Skipper, qi::locals<T> > vector_with_max;
};
template <typename T, typename ElementParser = typename boost::spirit::traits::create_parser<T>::type>
void do_test(std::string const& input,
T const& start_value = std::numeric_limits<T>::lowest(),
ElementParser const& element_parser = boost::spirit::traits::create_parser<T>::call())
{
using It = std::string::const_iterator;
vector_and_max<T> data;
It it = input.begin(), end = input.end();
bool ok = qi::phrase_parse(it, end, max_parser<It, T>(start_value, element_parser), qi::space, data);
if (ok) {
std::cout << "Parse success: " << data.first.size() << " elements with maximum of " << data.second << "\n";
std::copy(data.first.begin(), data.first.end(), std::ostream_iterator<T>(std::cout << "\t values: ", " "));
std::cout << "\n";
} else {
std::cout << "Parse failed\n";
}
if (it != end)
std::cout << "Remaining unparsed: '" << std::string(it,end) << "'\n";
}
int main() {
do_test<int>(" 1 99 -1312 4 1014");
do_test<double>(" 1 NaN -4 7e3 7e4 -31e9");
do_test<std::string>("beauty shall be in ze eye of the beholder", "", qi::as_string[qi::lexeme[+qi::graph]]);
}