| 1 | #include <boost/spirit/include/qi.hpp>
|
|---|
| 2 | #include <boost/spirit/include/phoenix_operator.hpp>
|
|---|
| 3 |
|
|---|
| 4 | namespace qi = boost::spirit::qi;
|
|---|
| 5 |
|
|---|
| 6 | template <typename P, typename T>
|
|---|
| 7 | void test_parser_attr(char const* input, P const& p, T& attr, bool full_match = true)
|
|---|
| 8 | {
|
|---|
| 9 | using boost::spirit::qi::parse;
|
|---|
| 10 |
|
|---|
| 11 | char const* f(input);
|
|---|
| 12 | char const* l(f + strlen(f));
|
|---|
| 13 | if (parse(f, l, p, attr) && (!full_match || (f == l)))
|
|---|
| 14 | std::cout << "ok" << std::endl;
|
|---|
| 15 | else
|
|---|
| 16 | std::cout << "fail" << std::endl;
|
|---|
| 17 | }
|
|---|
| 18 |
|
|---|
| 19 | /* This test structure represents a primitive range limited type. */
|
|---|
| 20 | struct body_temp
|
|---|
| 21 | {
|
|---|
| 22 | float t;
|
|---|
| 23 | };
|
|---|
| 24 |
|
|---|
| 25 | bool no_chance(false);
|
|---|
| 26 |
|
|---|
| 27 | namespace boost { namespace spirit { namespace traits
|
|---|
| 28 | {
|
|---|
| 29 | template <>
|
|---|
| 30 | struct transform_attribute<body_temp, float, qi::domain>
|
|---|
| 31 | {
|
|---|
| 32 | typedef float type;
|
|---|
| 33 | static float pre(body_temp t) { return t.t; }
|
|---|
| 34 | /* if parsed attribute is within desired range, than assign it,
|
|---|
| 35 | * otherwise report failure.
|
|---|
| 36 | */
|
|---|
| 37 | static bool post(body_temp& t, float const &attr)
|
|---|
| 38 | {
|
|---|
| 39 | if (attr > 30.0 && attr < 45.0) {
|
|---|
| 40 | t.t = attr;
|
|---|
| 41 | return true;
|
|---|
| 42 | }
|
|---|
| 43 | else
|
|---|
| 44 | return false;
|
|---|
| 45 | }
|
|---|
| 46 | static void fail(body_temp &t) { }
|
|---|
| 47 | };
|
|---|
| 48 | }}}
|
|---|
| 49 |
|
|---|
| 50 | int main(int argc, char **argv)
|
|---|
| 51 | {
|
|---|
| 52 | namespace qi = boost::spirit::qi;
|
|---|
| 53 | using qi::float_;
|
|---|
| 54 | using qi::omit;
|
|---|
| 55 | using qi::rule;
|
|---|
| 56 | using qi::attr_cast;
|
|---|
| 57 | using boost::phoenix::ref;
|
|---|
| 58 |
|
|---|
| 59 | body_temp d1 = { 36.6 }, d2 = { 36.6 };
|
|---|
| 60 |
|
|---|
| 61 | rule<char const *, body_temp()> r;
|
|---|
| 62 |
|
|---|
| 63 | /* Adapt qi::float_ parser to struct body_temp which represents a range
|
|---|
| 64 | * limited numeric type. If range can not be accomodated, per conversion
|
|---|
| 65 | * defined, the first alternative will fail, and second will be invoked,
|
|---|
| 66 | * to set the error flag.
|
|---|
| 67 | */
|
|---|
| 68 | r %= attr_cast<body_temp>(float_) | omit[float_[ref(no_chance) = true]];
|
|---|
| 69 |
|
|---|
| 70 | /* Supplied value is within range and will be parsed as appropriate
|
|---|
| 71 | * range limited float.
|
|---|
| 72 | */
|
|---|
| 73 | test_parser_attr("40.0", r, d1);
|
|---|
| 74 | std::cout << "parsed temp " << d1.t << " error flag " << no_chance
|
|---|
| 75 | << std::endl;
|
|---|
| 76 |
|
|---|
| 77 | no_chance = false;
|
|---|
| 78 | /* Supplied value is not within allowed range, the parser will take the
|
|---|
| 79 | * alternative choice to set the error flag.
|
|---|
| 80 | */
|
|---|
| 81 | test_parser_attr("20.0", r, d2);
|
|---|
| 82 | std::cout << "parsed temp " << d2.t << " error flag " << no_chance
|
|---|
| 83 | << std::endl;
|
|---|
| 84 |
|
|---|
| 85 | return 0;
|
|---|
| 86 | }
|
|---|