]>
git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/spirit/example/qi/reference.cpp
1 /*=============================================================================
2 Copyright (c) 2001-2011 Joel de Guzman
3 http://spirit.sourceforge.net/
5 Distributed under the Boost Software License, Version 1.0. (See accompanying
6 file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 =============================================================================*/
9 // this code is not supposed to be executed, so the asserts are for
10 // demonstration purposes only
11 // boostinspect:naassert_macro
14 #include <boost/spirit/include/support_utree.hpp>
15 #include <boost/spirit/include/qi.hpp>
16 #include <boost/spirit/include/phoenix_core.hpp>
17 #include <boost/spirit/include/phoenix_operator.hpp>
18 #include <boost/fusion/include/adapt_struct.hpp>
19 #include <boost/assert.hpp>
20 #include <boost/predef/other/endian.h>
29 char const* input
, P
const& p
, bool full_match
= true)
31 using boost::spirit::qi::parse
;
34 char const* l(f
+ strlen(f
));
35 if (parse(f
, l
, p
) && (!full_match
|| (f
== l
)))
36 std::cout
<< "ok" << std::endl
;
38 std::cout
<< "fail" << std::endl
;
42 void test_phrase_parser(
43 char const* input
, P
const& p
, bool full_match
= true)
45 using boost::spirit::qi::phrase_parse
;
46 using boost::spirit::qi::ascii::space
;
49 char const* l(f
+ strlen(f
));
50 if (phrase_parse(f
, l
, p
, space
) && (!full_match
|| (f
== l
)))
51 std::cout
<< "ok" << std::endl
;
53 std::cout
<< "fail" << std::endl
;
57 //[reference_test_attr
58 template <typename P
, typename T
>
59 void test_parser_attr(
60 char const* input
, P
const& p
, T
& attr
, bool full_match
= true)
62 using boost::spirit::qi::parse
;
65 char const* l(f
+ strlen(f
));
66 if (parse(f
, l
, p
, attr
) && (!full_match
|| (f
== l
)))
67 std::cout
<< "ok" << std::endl
;
69 std::cout
<< "fail" << std::endl
;
72 template <typename P
, typename T
>
73 void test_phrase_parser_attr(
74 char const* input
, P
const& p
, T
& attr
, bool full_match
= true)
76 using boost::spirit::qi::phrase_parse
;
77 using boost::spirit::qi::ascii::space
;
80 char const* l(f
+ strlen(f
));
81 if (phrase_parse(f
, l
, p
, space
, attr
) && (!full_match
|| (f
== l
)))
82 std::cout
<< "ok" << std::endl
;
84 std::cout
<< "fail" << std::endl
;
88 //[reference_print_info
91 typedef boost::spirit::utf8_string string
;
93 void element(string
const& tag
, string
const& value
, int depth
) const
95 for (int i
= 0; i
< (depth
*4); ++i
) // indent to depth
98 std::cout
<< "tag: " << tag
;
100 std::cout
<< ", value: " << value
;
101 std::cout
<< std::endl
;
105 void print_info(boost::spirit::info
const& what
)
107 using boost::spirit::basic_info_walker
;
110 basic_info_walker
<printer
> walker(pr
, what
.tag
, 0);
111 boost::apply_visitor(walker
, what
.value
);
115 //[reference_test_real_policy
116 ///////////////////////////////////////////////////////////////////////////////
117 // These policies can be used to parse thousand separated
118 // numbers with at most 2 decimal digits after the decimal
119 // point. e.g. 123,456,789.01
120 ///////////////////////////////////////////////////////////////////////////////
121 template <typename T
>
122 struct ts_real_policies
: boost::spirit::qi::ureal_policies
<T
>
124 // 2 decimal places Max
125 template <typename Iterator
, typename Attribute
>
127 parse_frac_n(Iterator
& first
, Iterator
const& last
, Attribute
& attr
,
130 Iterator savef
= first
;
131 bool r
= boost::spirit::qi::
132 extract_uint
<T
, 10, 1, 2, true>::call(first
, last
, attr
);
134 // Optimization note: don't compute frac_digits if T is
135 // an unused_type. This should be optimized away by the compiler.
136 if (!boost::is_same
<T
, boost::spirit::unused_type
>::value
)
137 frac_digits
= static_cast<int>(std::distance(savef
, first
));
143 template <typename Iterator
>
145 parse_exp(Iterator
&, Iterator
const&)
151 template <typename Iterator
, typename Attribute
>
153 parse_exp_n(Iterator
&, Iterator
const&, Attribute
&)
158 // Thousands separated numbers
159 template <typename Iterator
, typename Accumulator
>
161 parse_n(Iterator
& first
, Iterator
const& last
, Accumulator
& result
)
163 using boost::spirit::qi::uint_parser
;
164 namespace qi
= boost::spirit::qi
;
166 uint_parser
<unsigned, 10, 1, 3> uint3
;
167 uint_parser
<unsigned, 10, 3, 3> uint3_3
;
169 if (parse(first
, last
, uint3
, result
))
172 Iterator iter
= first
;
174 while (qi::parse(iter
, last
, ',') && qi::parse(iter
, last
, uint3_3
, n
))
176 result
= result
* 1000 + n
;
187 //[reference_test_bool_policy
188 ///////////////////////////////////////////////////////////////////////////////
189 // These policies can be used to parse "eurt" (i.e. "true" spelled backwards)
191 ///////////////////////////////////////////////////////////////////////////////
192 struct backwards_bool_policies
: boost::spirit::qi::bool_policies
<>
194 // we want to interpret a 'true' spelled backwards as 'false'
195 template <typename Iterator
, typename Attribute
>
197 parse_false(Iterator
& first
, Iterator
const& last
, Attribute
& attr
)
199 namespace qi
= boost::spirit::qi
;
200 if (qi::detail::string_parse("eurt", first
, last
, qi::unused
))
202 namespace traits
= boost::spirit::traits
;
203 traits::assign_to(false, attr
); // result is false
211 //[reference_qi_complex
212 // a simple complex number representation z = a + bi
215 complex (double a
= 0.0, double b
= 0.0)
224 //[reference_qi_stream_complex
225 // define streaming operator for the type complex
227 operator>> (std::istream
& is
, complex& z
)
229 char lbrace
= '\0', comma
= '\0', rbrace
= '\0';
230 is
>> lbrace
>> z
.a
>> comma
>> z
.b
>> rbrace
;
231 if (lbrace
!= '{' || comma
!= ',' || rbrace
!= '}')
232 is
.setstate(std::ios_base::failbit
);
237 //[reference_qi_auto_complex
238 /*`The following construct is required to allow the `complex` data structure
239 to be utilized as a __fusion__ sequence. This is required as we will
240 emit output for this data structure with a __qi__ sequence:
241 `'{' >> qi::double_ >> ',' >> qi::double_ >> '}'`.
243 BOOST_FUSION_ADAPT_STRUCT(
249 /*`We add a specialization for the create_parser customization point
250 defining a custom output format for the complex type. Generally, any
251 specialization for create_parser is expected to return the proto
252 expression to be used to match input for the type the customization
253 point has been specialized for.
255 /*`We need to utilize `proto::deep_copy` as the expression contains literals
256 (the `'{'`, `','`, and `'}'`) which normally get embedded in the proto
257 expression by reference only. The deep copy converts the proto tree to
258 hold this by value. The deep copy operation can be left out for simpler
259 proto expressions (not containing references to temporaries). Alternatively
260 you could use the `proto::make_expr` facility to build the required
263 namespace boost
{ namespace spirit
{ namespace traits
266 struct create_parser
<complex>
268 typedef proto::result_of::deep_copy
<
269 BOOST_TYPEOF('{' >> qi::double_
>> ',' >> qi::double_
>> '}')
274 return proto::deep_copy(
275 '{' >> qi::double_
>> ',' >> qi::double_
>> '}');
281 //[reference_qi_auxiliary_attr_cast_data1
282 // this is just a test structure we want to use in place of an int
289 // we provide a custom attribute transformation to allow its use as an int
290 namespace boost
{ namespace spirit
{ namespace traits
292 // in this case we just expose the embedded 'int' as the attribute instance
293 // to use, allowing to leave the function 'post()' empty
295 struct transform_attribute
<int_data
, int, qi::domain
>
298 static int& pre(int_data
& d
) { return d
.i
; }
299 static void post(int_data
& val
, int const& attr
) {}
300 static void fail(int_data
&) {}
307 using boost::spirit::qi::grammar
;
308 using boost::spirit::qi::rule
;
309 using boost::spirit::ascii::space_type
;
311 //[reference_grammar_definition
312 /*`Basic grammar usage:
314 struct num_list
: grammar
<char const*, space_type
>
316 num_list() : base_type(start
)
318 using boost::spirit::int_
;
320 start
= num
>> *(',' >> num
);
323 rule
<char const*, space_type
> start
, num
;
332 //[reference_using_declarations_lit_char
333 using boost::spirit::qi::lit
;
334 using boost::spirit::ascii::char_
;
337 //[reference_char_literals
338 test_parser("x", 'x'); // plain literal
339 test_parser("x", lit('x')); // explicit literal
340 test_parser("x", char_('x')); // ascii::char_
343 //[reference_char_range
345 test_parser_attr("5", char_('0','9'), ch
); // ascii::char_ range
346 std::cout
<< ch
<< std::endl
; // prints '5'
349 //[reference_char_set
350 test_parser_attr("5", char_("0-9"), ch
); // ascii::char_ set
351 std::cout
<< ch
<< std::endl
; // prints '5'
354 //[reference_char_phoenix
355 namespace phx
= boost::phoenix
;
356 test_parser("x", phx::val('x')); // direct
358 char_(phx::val('0'),phx::val('9'))); // ascii::char_ range
363 //[reference_using_declarations_lit_string
364 using boost::spirit::qi::lit
;
365 using boost::spirit::ascii::string
;
368 //[reference_string_literals
369 test_parser("boost", "boost"); // plain literal
370 test_parser("boost", lit("boost")); // explicit literal
371 test_parser("boost", string("boost")); // ascii::string
376 using boost::spirit::qi::lit
;
377 using boost::spirit::ascii::string
;
379 //[reference_string_std_string
380 std::string
s("boost");
381 test_parser("boost", s
); // direct
382 test_parser("boost", lit(s
)); // explicit
383 test_parser("boost", string(s
)); // ascii::string
388 using boost::spirit::qi::lit
;
389 using boost::spirit::ascii::string
;
391 //[reference_string_phoenix
392 namespace phx
= boost::phoenix
;
393 test_parser("boost", phx::val("boost")); // direct
394 test_parser("boost", lit(phx::val("boost"))); // explicit
395 test_parser("boost", string(phx::val("boost"))); // ascii::string
400 //[reference_using_declarations_symbols
401 using boost::spirit::qi::symbols
;
404 //[reference_symbols_with_data
405 symbols
<char, int> sym
;
414 test_parser_attr("Banana", sym
, i
);
415 std::cout
<< i
<< std::endl
;
420 //[reference_using_declarations_lexeme
421 using boost::spirit::qi::lexeme
;
422 using boost::spirit::qi::lit
;
423 using boost::spirit::ascii::digit
;
427 /*`The use of lexeme here will prevent skipping in between the
428 digits and the sign making inputs such as `"1 2 345"` erroneous.*/
429 test_phrase_parser("12345", lexeme
[ -(lit('+') | '-') >> +digit
]);
435 //[reference_using_declarations_as
436 using boost::spirit::utree
;
437 using boost::spirit::utree_type
;
438 using boost::spirit::utf8_symbol_type
;
439 using boost::spirit::qi::as
;
440 using boost::spirit::qi::as_string
;
441 using boost::spirit::qi::char_
;
445 /*`To properly handle string concatenation with __utree__, we
446 make use of `as_string[]`. We also use `as<T>` to explicitly create
447 a __utree__ symbol node.*/
450 typedef as
<utf8_symbol_type
> as_symbol_type
;
451 as_symbol_type
const as_symbol
= as_symbol_type();
453 test_parser_attr("foo", as_string
[*char_
], ut
);
454 std::cout
<< ut
<< std::endl
; // will output >"foo"<
455 BOOST_ASSERT(ut
.which() == utree_type::string_type
);
458 test_parser_attr("foo", as
<std::string
>()[*char_
], ut
);
459 std::cout
<< ut
<< std::endl
; // will output >"foo"<
460 BOOST_ASSERT(ut
.which() == utree_type::string_type
);
463 test_parser_attr("foo", as_symbol
[*char_
], ut
);
464 std::cout
<< ut
<< std::endl
; // will output >foo<
465 BOOST_ASSERT(ut
.which() == utree_type::symbol_type
);
468 test_parser_attr("foo", as
<utf8_symbol_type
>()[*char_
], ut
);
469 std::cout
<< ut
<< std::endl
; // will output >foo<
470 BOOST_ASSERT(ut
.which() == utree_type::symbol_type
);
475 //[reference_using_declarations_no_skip
476 using boost::spirit::qi::no_skip
;
477 using boost::spirit::qi::char_
;
481 /*`The use of no_skip here will prevent skipping of whitespace in front
482 and in between the characters of the string `' abc '`.*/
485 test_phrase_parser_attr("' abc '",
486 '\'' >> no_skip
[+~char_('\'')] >> '\'', str
);
487 std::cout
<< str
<< std::endl
; // will output: > abc <
492 //[reference_using_declarations_hold
493 using boost::spirit::qi::hold
;
494 using boost::spirit::qi::int_
;
495 using boost::spirit::qi::attr
;
499 /*`The use of `hold[]` here will make sure the changes to the attribute
500 caused by the (failing) first alternative will not be visible after
501 the whole parsing succeeded. */
504 test_phrase_parser_attr("123",
505 hold
[int_
>> ':' >> int_
] | int_
>> attr(0), v
);
506 std::cout
<< v
[0] << "," << v
[1] << std::endl
; // will output: >123,0<
511 //[reference_using_declarations_no_case
512 using boost::spirit::ascii::no_case
;
513 using boost::spirit::ascii::char_
;
514 using boost::spirit::ascii::alnum
;
515 using boost::spirit::qi::symbols
;
519 test_parser("X", no_case
[char_('x')]);
520 test_parser("6", no_case
[alnum
]);
523 //[reference_symbols_with_no_case
524 symbols
<char, int> sym
;
527 ("apple", 1) // symbol strings are added in lowercase...
533 // ...because sym is used for case-insensitive parsing
534 test_parser_attr("Apple", no_case
[ sym
], i
);
535 std::cout
<< i
<< std::endl
;
536 test_parser_attr("ORANGE", no_case
[ sym
], i
);
537 std::cout
<< i
<< std::endl
;
542 //[reference_using_declarations_omit
543 using boost::spirit::qi::omit
;
544 using boost::spirit::qi::int_
;
545 using boost::spirit::ascii::char_
;
549 /*`This parser ignores the first two characters
550 and extracts the succeeding `int`:*/
552 test_parser_attr("xx345", omit
[char_
>> char_
] >> int_
, i
);
553 std::cout
<< i
<< std::endl
; // should print 345
558 //[reference_using_declarations_matches
559 using boost::spirit::qi::matches
;
560 using boost::spirit::qi::int_
;
564 /*`This parser tries to match an `int` and returns `true` a its
565 attribute as it succeeded matching: */
567 test_parser_attr("345", matches
[int_
], result
);
568 std::cout
<< std::boolalpha
<< result
<< std::endl
; // should print: true
570 /*`This parser tries to match an `int` as well and returns `false` as
571 its attribute as it fails matching: */
573 test_parser_attr("abc", matches
[int_
], result
);
574 std::cout
<< std::boolalpha
<< result
<< std::endl
; // should print: false
579 //[reference_using_declarations_raw
580 using boost::spirit::qi::raw
;
581 using boost::spirit::ascii::alpha
;
582 using boost::spirit::ascii::alnum
;
586 //`This parser matches and extracts C++ identifiers:
588 test_parser_attr("James007", raw
[(alpha
| '_') >> *(alnum
| '_')], id
);
589 std::cout
<< id
<< std::endl
; // should print James007
594 //[reference_using_declarations_repeat
595 using boost::spirit::qi::repeat
;
596 using boost::spirit::qi::lit
;
597 using boost::spirit::qi::uint_parser
;
598 using boost::spirit::qi::_1
;
599 using boost::spirit::ascii::char_
;
600 namespace phx
= boost::phoenix
;
604 //`A parser for a file name with a maximum of 255 characters:
605 test_parser("batman.jpeg", repeat(1, 255)[char_("a-zA-Z_./")]);
607 /*`A parser for a specific bitmap file format which has exactly 4096 RGB color information.
608 (for the purpose of this example, we will be testing only 3 RGB color information.)
610 uint_parser
<unsigned, 16, 6, 6> rgb
;
611 std::vector
<unsigned> colors
;
612 test_parser_attr("ffffff0000003f3f3f", repeat(3)[rgb
], colors
);
617 << colors
[2] << std::endl
;
619 /*`A 256 bit binary string (1..256 1s or 0s). (For the purpose of this example,
620 we will be testing only 16 bits.)
622 test_parser("1011101011110010", repeat(16)[lit('1') | '0']);
625 std::cout
<< std::dec
; // reset to decimal
627 //[reference_repeat_pascal
628 /*`This trivial example cannot be practically defined in traditional EBNF.
629 Although some EBNF variants allow more powerful repetition constructs other
630 than the Kleene Star, we are still limited to parsing fixed strings.
631 The nature of EBNF forces the repetition factor to be a constant.
632 On the other hand, Spirit allows the repetition factor to be variable at
633 run time. We could write a grammar that accepts the input string above.
634 Example using phoenix:
638 test_parser_attr("\x0bHello World",
639 char_
[phx::ref(n
) = _1
] >> repeat(phx::ref(n
))[char_
], str
);
640 std::cout
<< n
<< ',' << str
<< std::endl
; // will print "11,Hello World"
645 //[reference_using_declarations_skip
646 using boost::spirit::qi::skip
;
647 using boost::spirit::qi::int_
;
648 using boost::spirit::ascii::space
;
652 /*`Explicitly specify a skip parser. This parser parses comma
653 delimited numbers, ignoring spaces.*/
654 test_parser("1, 2, 3, 4, 5", skip(space
)[int_
>> *(',' >> int_
)]);
660 //[reference_using_declarations_attr
661 namespace phx
= boost::phoenix
;
662 using boost::spirit::qi::attr
;
667 test_parser_attr("", attr("boost"), str
);
668 std::cout
<< str
<< std::endl
; // will print 'boost'
671 test_parser_attr("", attr(1.0), d
);
672 std::cout
<< d
<< std::endl
; // will print '1.0'
675 //[reference_attr_phoenix
678 test_parser_attr("", attr(phx::ref(d1
)), d
);
679 std::cout
<< d
<< std::endl
; // will print '1.2'
685 //[reference_qi_using_declarations_attr_cast
686 using boost::spirit::qi::int_
;
689 //[reference_qi_attr_cast1
691 test_parser_attr("1", boost::spirit::qi::attr_cast(int_
), d
);
692 std::cout
<< d
.i
<< std::endl
;
698 //[reference_using_declarations_eol
699 using boost::spirit::qi::eol
;
703 test_parser("\n", eol
);
709 //[reference_using_declarations_eoi
710 using boost::spirit::qi::eoi
;
714 test_parser("", eoi
);
720 //[reference_using_declarations_eps
721 using boost::spirit::qi::eps
;
722 using boost::spirit::qi::int_
;
723 using boost::spirit::qi::_1
;
724 namespace phx
= boost::phoenix
;
729 test_parser("", eps
); // always matches
733 /*`This example simulates the "classic" `if_p` parser. Here, `int_` will be
734 tried only if the condition, `c`, is true.
736 bool c
= true; // a flag
737 test_parser("1234", eps(phx::ref(c
) == true) >> int_
);
740 //[reference_eps_while
741 /*`This example simulates the "classic" `while_p` parser. Here, the kleene loop
742 will exit once the condition, `c`, becomes true. Notice that the condition, `c`,
743 is turned to `false` when we get to parse `4`.
745 test_phrase_parser("1 2 3 4",
746 *(eps(phx::ref(c
) == true) >> int_
[phx::ref(c
) = (_1
== 4)]));
752 //[reference_using_declarations_lazy
753 using boost::spirit::qi::lazy
;
754 using boost::spirit::ascii::string
;
755 using boost::phoenix::val
;
759 /*` Here, the phoenix::val expression creates a function
760 that returns its argument when invoked. The lazy expression
761 defers the invocation of this function at parse time. Then,
762 this parser (string parser) is called into action. All this
763 takes place at parse time.
765 test_parser("Hello", lazy(val(string("Hello"))));
767 //` The above is equivalent to:
768 test_parser("Hello", string("Hello"));
774 //[reference_using_declarations_char_class
775 using boost::spirit::ascii::alnum
;
776 using boost::spirit::ascii::blank
;
777 using boost::spirit::ascii::digit
;
778 using boost::spirit::ascii::lower
;
781 //[reference_char_class
782 test_parser("1", alnum
);
783 test_parser(" ", blank
);
784 test_parser("1", digit
);
785 test_parser("a", lower
);
791 //[reference_using_declarations_uint
792 using boost::phoenix::val
;
793 using boost::spirit::qi::lit
;
794 using boost::spirit::qi::uint_
;
795 using boost::spirit::qi::uint_parser
;
800 test_parser("12345", uint_
);
801 test_parser("12345", uint_(12345));
802 test_parser("12345", uint_(val(12345)));
805 test_parser("12345", lit(12345));
806 test_parser("12345", lit(val(12345)));
809 //[reference_thousand_separated
810 //`Thousand separated number parser:
811 uint_parser
<unsigned, 10, 1, 3> uint3_p
; // 1..3 digits
812 uint_parser
<unsigned, 10, 3, 3> uint3_3_p
; // exactly 3 digits
813 test_parser("12,345,678", uint3_p
>> *(',' >> uint3_3_p
));
819 //[reference_using_declarations_int
820 using boost::phoenix::val
;
821 using boost::spirit::qi::lit
;
822 using boost::spirit::qi::int_
;
827 test_parser("+12345", int_
);
828 test_parser("-12345", int_
);
829 test_parser("+12345", int_(12345));
830 test_parser("-12345", int_(-12345));
831 test_parser("+12345", int_(val(12345)));
832 test_parser("-12345", int_(val(-12345)));
835 test_parser("+12345", lit(12345));
836 test_parser("-12345", lit(-12345));
837 test_parser("+12345", lit(val(12345)));
838 test_parser("-12345", lit(val(-12345)));
844 //[reference_using_declarations_real
845 using boost::phoenix::val
;
846 using boost::spirit::qi::double_
;
847 using boost::spirit::qi::real_parser
;
848 using boost::spirit::qi::lit
;
853 test_parser("+12345e6", double_
);
854 test_parser("-12345e6", double_
);
855 test_parser("+12345e6", double_(12345e6
));
856 test_parser("-12345e6", double_(-123456e6
));
857 test_parser("+12345e6", double_(val(12345e6
)));
858 test_parser("-12345e6", double_(val(-123456e6
)));
861 test_parser("+12345e6", lit(12345e6
));
862 test_parser("-12345e6", lit(-123456e6
));
863 test_parser("+12345e6", lit(val(12345e6
)));
864 test_parser("-12345e6", lit(val(-123456e6
)));
867 //[reference_custom_real
868 real_parser
<double, ts_real_policies
<double> > ts_real
;
869 test_parser("123,456,789.01", ts_real
);
870 test_parser("123,456,789.01", ts_real(123456789.01));
876 //[reference_using_declarations_bool
877 using boost::phoenix::val
;
878 using boost::spirit::qi::bool_
;
879 using boost::spirit::qi::bool_parser
;
880 using boost::spirit::qi::lit
;
885 test_parser("true", bool_
);
886 test_parser("false", bool_
);
887 test_parser("true", bool_(true));
888 test_parser("false", bool_(false));
889 test_parser("true", bool_(val(true)));
890 test_parser("false", bool_(val(false)));
893 test_parser("true", lit(true));
894 test_parser("false", lit(false));
895 test_parser("true", lit(val(true)));
896 test_parser("false", lit(val(false)));
899 //[reference_custom_bool
900 bool_parser
<bool, backwards_bool_policies
> backwards_bool
;
901 test_parser("true", backwards_bool
);
902 test_parser("eurt", backwards_bool
);
903 test_parser("true", backwards_bool(true));
904 test_parser("eurt", backwards_bool(false));
910 //[reference_using_declarations_sequence
911 using boost::spirit::ascii::char_
;
912 using boost::spirit::qi::_1
;
913 using boost::spirit::qi::_2
;
914 namespace bf
= boost::fusion
;
917 //[reference_sequence
919 test_parser("xy", char_
>> char_
);
921 //`Extracting the attribute tuple (using __fusion__):
922 bf::vector
<char, char> attr
;
923 test_parser_attr("xy", char_
>> char_
, attr
);
924 std::cout
<< bf::at_c
<0>(attr
) << ',' << bf::at_c
<1>(attr
) << std::endl
;
926 //`Extracting the attribute vector (using __stl__):
927 std::vector
<char> vec
;
928 test_parser_attr("xy", char_
>> char_
, vec
);
929 std::cout
<< vec
[0] << ',' << vec
[1] << std::endl
;
931 //`Extracting the attributes using __qi_semantic_actions__ (using __phoenix__):
932 test_parser("xy", (char_
>> char_
)[std::cout
<< _1
<< ',' << _2
<< std::endl
]);
938 //[reference_using_declarations_sequential_or
939 using boost::spirit::qi::int_
;
942 //[reference_sequential_or
943 //`Correctly parsing a number with optional fractional digits:
944 test_parser("123.456", int_
|| ('.' >> int_
)); // full
945 test_parser("123", int_
|| ('.' >> int_
)); // just the whole number
946 test_parser(".456", int_
|| ('.' >> int_
)); // just the fraction
948 /*`A naive but incorrect solution would try to do this using optionals (e.g.):
950 int_ >> -('.' >> int_) // will not match ".456"
951 -int_ >> ('.' >> int_) // will not match "123"
952 -int_ >> -('.' >> int_) // will match empty strings! Ooops.
959 //[reference_using_declarations_alternative
960 using boost::spirit::ascii::string
;
961 using boost::spirit::qi::int_
;
962 using boost::spirit::qi::_1
;
963 using boost::variant
;
966 //[reference_alternative
968 test_parser("Hello", string("Hello") | int_
);
969 test_parser("123", string("Hello") | int_
);
971 //`Extracting the attribute variant (using __boost_variant__):
972 variant
<std::string
, int> attr
;
973 test_parser_attr("Hello", string("Hello") | int_
, attr
);
975 /*`This should print `"Hello"`. Note: There are better ways to extract the value
976 from the variant. See __boost_variant__ visitation. This code is solely
979 if (boost::get
<int>(&attr
))
980 std::cout
<< boost::get
<int>(attr
) << std::endl
;
982 std::cout
<< boost::get
<std::string
>(attr
) << std::endl
;
984 /*`Extracting the attributes using __qi_semantic_actions__ with __phoenix__
985 (this should print `123`):
987 test_parser("123", (string("Hello") | int_
)[std::cout
<< _1
<< std::endl
]);
994 //[reference_using_declarations_permutation
995 using boost::spirit::ascii::char_
;
998 //[reference_permutation
999 //`Parse a string containing DNA codes (ACTG)
1000 test_parser("ACTGGCTAGACT", *(char_('A') ^ 'C' ^ 'T' ^ 'G'));
1006 //[reference_using_declarations_expect
1007 using boost::spirit::ascii::char_
;
1008 using boost::spirit::qi::expectation_failure
;
1012 /*`The code below uses an expectation operator to throw an __qi_expectation_failure__
1013 with a deliberate parsing error when `"o"` is expected and `"i"` is what is
1014 found in the input. The `catch` block prints the information related to the
1015 error. Note: This is low level code that demonstrates the /bare-metal/. Typically,
1016 you use an __qi_error_handler__ to deal with the error.
1020 test_parser("xi", char_('x') > char_('o')); // should throw an exception
1022 catch (expectation_failure
<char const*> const& x
)
1024 std::cout
<< "expected: "; print_info(x
.what_
);
1025 std::cout
<< "got: \"" << std::string(x
.first
, x
.last
) << '"' << std::endl
;
1027 /*`The code above will print:[teletype]
1029 expected: tag: literal-char, value: o
1037 //[reference_using_declarations_expectd
1038 using boost::spirit::ascii::char_
;
1039 using boost::spirit::qi::expect
;
1040 using boost::spirit::qi::expectation_failure
;
1043 //[reference_expectd
1044 /*`The code below uses an expectation operator to throw an __qi_expectation_failure__
1045 with a deliberate parsing error when `"o"` is expected and `"x"` is what is
1046 found in the input. The `catch` block prints the information related to the
1047 error. Note: This is low level code that demonstrates the /bare-metal/. Typically,
1048 you use an __qi_error_handler__ to deal with the error.
1052 test_parser("xi", expect
[char_('o')]); // should throw an exception
1054 catch (expectation_failure
<char const*> const& x
)
1056 std::cout
<< "expected: "; print_info(x
.what_
);
1057 std::cout
<< "got: \"" << std::string(x
.first
, x
.last
) << '"' << std::endl
;
1059 /*`The code above will print:[teletype]
1061 expected: tag: literal-char, value: o
1069 //[reference_and_predicate
1070 //`Some using declarations:
1071 using boost::spirit::lit
;
1073 /*`Basic look-ahead example: make sure that the last character is a
1074 semicolon, but don't consume it, just peek at the next character:
1076 test_phrase_parser("Hello ;", lit("Hello") >> &lit(';'), false);
1082 //[reference_not_predicate
1083 //`Some using declarations:
1084 using boost::spirit::ascii::char_
;
1085 using boost::spirit::ascii::alpha
;
1086 using boost::spirit::qi::lit
;
1087 using boost::spirit::qi::symbols
;
1089 /*`Here's an alternative to the `*(r - x) >> x` idiom using the
1090 not-predicate instead. This parses a list of characters terminated
1093 test_parser("abcdef;", *(!lit(';') >> char_
) >> ';');
1095 /*`The following parser ensures that we match distinct keywords
1096 (stored in a symbol table). To do this, we make sure that the
1097 keyword does not follow an alpha or an underscore:
1099 symbols
<char, int> keywords
;
1100 keywords
= "begin", "end", "for";
1102 // This should fail:
1103 test_parser("beginner", keywords
>> !(alpha
| '_'));
1106 test_parser("end ", keywords
>> !(alpha
| '_'), false);
1109 test_parser("for()", keywords
>> !(alpha
| '_'), false);
1115 //[reference_difference
1116 //`Some using declarations:
1117 using boost::spirit::ascii::char_
;
1119 /*`Parse a C/C++ style comment:
1121 test_parser("/*A Comment*/", "/*" >> *(char_
- "*/") >> "*/");
1128 //`Some using declarations:
1129 using boost::spirit::qi::int_
;
1131 /*`Parse a comma separated list of numbers and put them in a vector:
1133 std::vector
<int> attr
;
1134 test_phrase_parser_attr(
1135 "111, 222, 333, 444, 555", int_
>> *(',' >> int_
), attr
);
1137 << attr
[0] << ',' << attr
[1] << ',' << attr
[2] << ','
1138 << attr
[3] << ',' << attr
[4]
1146 //`Some using declarations:
1147 using boost::spirit::ascii::alpha
;
1148 using boost::spirit::qi::lexeme
;
1150 /*`Parse one or more strings containing one or more alphabetic
1151 characters and put them in a vector:
1153 std::vector
<std::string
> attr
;
1154 test_phrase_parser_attr("yaba daba doo", +lexeme
[+alpha
], attr
);
1155 std::cout
<< attr
[0] << ',' << attr
[1] << ',' << attr
[2] << std::endl
;
1161 //[reference_optional
1162 //`Some using declarations:
1163 using boost::spirit::ascii::char_
;
1164 using boost::spirit::qi::lexeme
;
1165 using boost::spirit::qi::int_
;
1166 using boost::fusion::vector
;
1167 using boost::fusion::at_c
;
1168 using boost::optional
;
1170 /*`Parse a person info with name (in quotes) optional age [footnote
1171 James Bond is shy about his age :-)] and optional sex, all
1174 vector
<std::string
, optional
<int>, optional
<char> > attr
;
1176 test_phrase_parser_attr(
1178 , lexeme
['"' >> +(char_
- '"') >> '"'] // name
1179 >> -(',' >> int_
) // optional age
1180 >> -(',' >> char_
) // optional sex
1183 // Should print: James Bond,M
1184 std::cout
<< at_c
<0>(attr
); // print name
1185 if (at_c
<1>(attr
)) // print optional age
1186 std::cout
<< ',' << *at_c
<1>(attr
);
1187 if (at_c
<2>(attr
)) // print optional sex
1188 std::cout
<< ',' << *at_c
<2>(attr
);
1189 std::cout
<< std::endl
;
1196 //`Some using declarations:
1197 using boost::spirit::qi::int_
;
1199 /*`Parse a comma separated list of numbers and put them in a vector:
1201 std::vector
<int> attr
;
1202 test_phrase_parser_attr(
1203 "111, 222, 333, 444, 555", int_
% ',', attr
);
1205 << attr
[0] << ',' << attr
[1] << ',' << attr
[2] << ','
1206 << attr
[3] << ',' << attr
[4]
1213 //[reference_qi_stream
1214 //`Using declarations and variables:
1215 using boost::spirit::qi::stream
;
1216 using boost::spirit::qi::stream_parser
;
1218 /*`Parse a simple string using the operator>>(istream&, std::string&);
1221 test_parser_attr("abc", stream
, str
);
1222 std::cout
<< str
<< std::endl
; // prints: abc
1224 /*`Parse our complex type using the operator>>(istream&, complex&);
1227 test_parser_attr("{1.0,2.5}", stream_parser
<char, complex>(), c
);
1228 std::cout
<< c
.a
<< "," << c
.b
<< std::endl
; // prints: 1.0,2.5
1232 ///////////////////////////////////////////////////////////////////////////
1235 //[reference_qi_using_declarations_auto
1236 using boost::spirit::qi::auto_
;
1239 //[reference_qi_auto
1240 /*`Parse a simple integer using the generated parser component `int_`:
1243 test_parser_attr("123", auto_
, i
);
1244 std::cout
<< i
<< std::endl
; // prints: 123
1246 /*`Parse an instance of the `complex` data type as defined above using
1247 the parser as generated by the defined customization point:
1250 test_parser_attr("{1.2,2.4}", auto_
, c
);
1251 std::cout
<< c
.a
<< "," << c
.b
<< std::endl
; // prints: 1.2,2.4
1257 //[reference_qi_native_binary
1258 //`Using declarations and variables:
1259 using boost::spirit::qi::byte_
;
1260 using boost::spirit::qi::word
;
1261 using boost::spirit::qi::dword
;
1262 using boost::spirit::qi::qword
;
1268 #ifdef BOOST_HAS_LONG_LONG
1274 #if BOOST_ENDIAN_LITTLE_BYTE
1276 //`Basic usage of the native binary parsers for little endian platforms:
1277 test_parser_attr("\x01", byte_
, uc
); assert(uc
== 0x01);
1278 test_parser_attr("\x01\x02", word
, us
); assert(us
== 0x0201);
1279 test_parser_attr("\x01\x02\x03\x04", dword
, ui
); assert(ui
== 0x04030201);
1281 #ifdef BOOST_HAS_LONG_LONG
1283 test_parser_attr("\x01\x02\x03\x04\x05\x06\x07\x08", qword
, ul
);
1284 assert(ul
== 0x0807060504030201LL
);
1289 test_parser("\x01", byte_(0x01));
1290 test_parser("\x01\x02", word(0x0201));
1291 test_parser("\x01\x02\x03\x04", dword(0x04030201));
1293 #ifdef BOOST_HAS_LONG_LONG
1295 test_parser("\x01\x02\x03\x04\x05\x06\x07\x08",
1296 qword(0x0807060504030201LL
));
1301 //`Basic usage of the native binary parsers for big endian platforms:
1302 test_parser_attr("\x01", byte_
, uc
); assert(uc
== 0x01);
1303 test_parser_attr("\x01\x02", word
, us
); assert(us
== 0x0102);
1304 test_parser_attr("\x01\x02\x03\x04", dword
, ui
); assert(ui
== 0x01020304);
1306 #ifdef BOOST_HAS_LONG_LONG
1308 test_parser_attr("\x01\x02\x03\x04\x05\x06\x07\x08", qword
, ul
);
1309 assert(0x0102030405060708LL
);
1314 test_parser("\x01", byte_(0x01));
1315 test_parser("\x01\x02", word(0x0102));
1316 test_parser("\x01\x02\x03\x04", dword(0x01020304));
1318 #ifdef BOOST_HAS_LONG_LONG
1320 test_parser("\x01\x02\x03\x04\x05\x06\x07\x08",
1321 qword(0x0102030405060708LL
));
1331 //[reference_qi_little_binary
1332 //`Using declarations and variables:
1333 using boost::spirit::qi::little_word
;
1334 using boost::spirit::qi::little_dword
;
1335 using boost::spirit::qi::little_qword
;
1340 #ifdef BOOST_HAS_LONG_LONG
1347 //`Basic usage of the little endian binary parsers:
1348 test_parser_attr("\x01\x02", little_word
, us
); assert(us
== 0x0201);
1349 test_parser_attr("\x01\x02\x03\x04", little_dword
, ui
); assert(ui
== 0x04030201);
1351 #ifdef BOOST_HAS_LONG_LONG
1353 test_parser_attr("\x01\x02\x03\x04\x05\x06\x07\x08", little_qword
, ul
);
1354 assert(ul
== 0x0807060504030201LL
);
1359 test_parser("\x01\x02", little_word(0x0201));
1360 test_parser("\x01\x02\x03\x04", little_dword(0x04030201));
1362 #ifdef BOOST_HAS_LONG_LONG
1364 test_parser("\x01\x02\x03\x04\x05\x06\x07\x08",
1365 little_qword(0x0807060504030201LL
));
1374 //[reference_qi_big_binary
1375 //`Using declarations and variables:
1376 using boost::spirit::qi::big_word
;
1377 using boost::spirit::qi::big_dword
;
1378 using boost::spirit::qi::big_qword
;
1383 #ifdef BOOST_HAS_LONG_LONG
1390 //`Basic usage of the big endian binary parsers:
1391 test_parser_attr("\x01\x02", big_word
, us
); assert(us
== 0x0102);
1392 test_parser_attr("\x01\x02\x03\x04", big_dword
, ui
); assert(ui
== 0x01020304);
1394 #ifdef BOOST_HAS_LONG_LONG
1396 test_parser_attr("\x01\x02\x03\x04\x05\x06\x07\x08", big_qword
, ul
);
1397 assert(0x0102030405060708LL
);
1402 test_parser("\x01\x02", big_word(0x0102));
1403 test_parser("\x01\x02\x03\x04", big_dword(0x01020304));
1405 #ifdef BOOST_HAS_LONG_LONG
1407 test_parser("\x01\x02\x03\x04\x05\x06\x07\x08",
1408 big_qword(0x0102030405060708LL
));
1418 //`Some using declarations:
1419 using boost::spirit::qi::rule
;
1420 using boost::spirit::qi::int_
;
1421 using boost::spirit::qi::locals
;
1422 using boost::spirit::qi::_1
;
1423 using boost::spirit::qi::_a
;
1424 using boost::spirit::ascii::alpha
;
1425 using boost::spirit::ascii::char_
;
1426 using boost::spirit::ascii::space_type
;
1430 rule
<char const*> r
;
1432 test_parser("123", r
);
1434 /*`Rule with synthesized attribute:
1436 rule
<char const*, int()> ra
;
1439 test_parser_attr("123", ra
, i
);
1442 /*`Rule with skipper and synthesized attribute:
1444 rule
<char const*, std::vector
<int>(), space_type
> rs
;
1447 test_phrase_parser_attr("123 456 789", rs
, v
);
1448 assert(v
[0] == 123);
1449 assert(v
[1] == 456);
1450 assert(v
[2] == 789);
1452 /*`Rule with one local variable:
1454 rule
<char const*, locals
<char> > rl
;
1455 rl
= alpha
[_a
= _1
] >> char_(_a
); // get two identical characters
1456 test_parser("aa", rl
); // pass
1457 test_parser("ax", rl
); // fail
1463 using client::num_list
;
1465 //[reference_grammar_using
1466 //`Some using declarations:
1467 using boost::spirit::ascii::space_type
;
1468 using boost::spirit::int_
;
1469 using boost::spirit::qi::grammar
;
1470 using boost::spirit::qi::rule
;
1473 //[reference_grammar
1474 //`How to use the example grammar:
1476 test_phrase_parser("123, 456, 789", nlist
);