]>
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>
28 char const* input
, P
const& p
, bool full_match
= true)
30 using boost::spirit::qi::parse
;
33 char const* l(f
+ strlen(f
));
34 if (parse(f
, l
, p
) && (!full_match
|| (f
== l
)))
35 std::cout
<< "ok" << std::endl
;
37 std::cout
<< "fail" << std::endl
;
41 void test_phrase_parser(
42 char const* input
, P
const& p
, bool full_match
= true)
44 using boost::spirit::qi::phrase_parse
;
45 using boost::spirit::qi::ascii::space
;
48 char const* l(f
+ strlen(f
));
49 if (phrase_parse(f
, l
, p
, space
) && (!full_match
|| (f
== l
)))
50 std::cout
<< "ok" << std::endl
;
52 std::cout
<< "fail" << std::endl
;
56 //[reference_test_attr
57 template <typename P
, typename T
>
58 void test_parser_attr(
59 char const* input
, P
const& p
, T
& attr
, bool full_match
= true)
61 using boost::spirit::qi::parse
;
64 char const* l(f
+ strlen(f
));
65 if (parse(f
, l
, p
, attr
) && (!full_match
|| (f
== l
)))
66 std::cout
<< "ok" << std::endl
;
68 std::cout
<< "fail" << std::endl
;
71 template <typename P
, typename T
>
72 void test_phrase_parser_attr(
73 char const* input
, P
const& p
, T
& attr
, bool full_match
= true)
75 using boost::spirit::qi::phrase_parse
;
76 using boost::spirit::qi::ascii::space
;
79 char const* l(f
+ strlen(f
));
80 if (phrase_parse(f
, l
, p
, space
, attr
) && (!full_match
|| (f
== l
)))
81 std::cout
<< "ok" << std::endl
;
83 std::cout
<< "fail" << std::endl
;
87 //[reference_print_info
90 typedef boost::spirit::utf8_string string
;
92 void element(string
const& tag
, string
const& value
, int depth
) const
94 for (int i
= 0; i
< (depth
*4); ++i
) // indent to depth
97 std::cout
<< "tag: " << tag
;
99 std::cout
<< ", value: " << value
;
100 std::cout
<< std::endl
;
104 void print_info(boost::spirit::info
const& what
)
106 using boost::spirit::basic_info_walker
;
109 basic_info_walker
<printer
> walker(pr
, what
.tag
, 0);
110 boost::apply_visitor(walker
, what
.value
);
114 //[reference_test_real_policy
115 ///////////////////////////////////////////////////////////////////////////////
116 // These policies can be used to parse thousand separated
117 // numbers with at most 2 decimal digits after the decimal
118 // point. e.g. 123,456,789.01
119 ///////////////////////////////////////////////////////////////////////////////
120 template <typename T
>
121 struct ts_real_policies
: boost::spirit::qi::ureal_policies
<T
>
123 // 2 decimal places Max
124 template <typename Iterator
, typename Attribute
>
126 parse_frac_n(Iterator
& first
, Iterator
const& last
, Attribute
& attr
)
128 return boost::spirit::qi::
129 extract_uint
<T
, 10, 1, 2, true>::call(first
, last
, attr
);
133 template <typename Iterator
>
135 parse_exp(Iterator
&, Iterator
const&)
141 template <typename Iterator
, typename Attribute
>
143 parse_exp_n(Iterator
&, Iterator
const&, Attribute
&)
148 // Thousands separated numbers
149 template <typename Iterator
, typename Attribute
>
151 parse_n(Iterator
& first
, Iterator
const& last
, Attribute
& attr
)
153 using boost::spirit::qi::uint_parser
;
154 namespace qi
= boost::spirit::qi
;
156 uint_parser
<unsigned, 10, 1, 3> uint3
;
157 uint_parser
<unsigned, 10, 3, 3> uint3_3
;
160 if (parse(first
, last
, uint3
, result
))
164 Iterator save
= first
;
166 while (qi::parse(first
, last
, ',') && qi::parse(first
, last
, uint3_3
, n
))
168 result
= result
* 1000 + n
;
183 //[reference_test_bool_policy
184 ///////////////////////////////////////////////////////////////////////////////
185 // These policies can be used to parse "eurt" (i.e. "true" spelled backwards)
187 ///////////////////////////////////////////////////////////////////////////////
188 struct backwards_bool_policies
: boost::spirit::qi::bool_policies
<>
190 // we want to interpret a 'true' spelled backwards as 'false'
191 template <typename Iterator
, typename Attribute
>
193 parse_false(Iterator
& first
, Iterator
const& last
, Attribute
& attr
)
195 namespace qi
= boost::spirit::qi
;
196 if (qi::detail::string_parse("eurt", first
, last
, qi::unused
))
198 namespace traits
= boost::spirit::traits
;
199 traits::assign_to(false, attr
); // result is false
207 //[reference_qi_complex
208 // a simple complex number representation z = a + bi
211 complex (double a
= 0.0, double b
= 0.0)
220 //[reference_qi_stream_complex
221 // define streaming operator for the type complex
223 operator>> (std::istream
& is
, complex& z
)
225 char lbrace
= '\0', comma
= '\0', rbrace
= '\0';
226 is
>> lbrace
>> z
.a
>> comma
>> z
.b
>> rbrace
;
227 if (lbrace
!= '{' || comma
!= ',' || rbrace
!= '}')
228 is
.setstate(std::ios_base::failbit
);
233 //[reference_qi_auto_complex
234 /*`The following construct is required to allow the `complex` data structure
235 to be utilized as a __fusion__ sequence. This is required as we will
236 emit output for this data structure with a __qi__ sequence:
237 `'{' >> qi::double_ >> ',' >> qi::double_ >> '}'`.
239 BOOST_FUSION_ADAPT_STRUCT(
245 /*`We add a specialization for the create_parser customization point
246 defining a custom output format for the complex type. Generally, any
247 specialization for create_parser is expected to return the proto
248 expression to be used to match input for the type the customization
249 point has been specialized for.
251 /*`We need to utilize `proto::deep_copy` as the expression contains literals
252 (the `'{'`, `','`, and `'}'`) which normally get embedded in the proto
253 expression by reference only. The deep copy converts the proto tree to
254 hold this by value. The deep copy operation can be left out for simpler
255 proto expressions (not containing references to temporaries). Alternatively
256 you could use the `proto::make_expr` facility to build the required
259 namespace boost
{ namespace spirit
{ namespace traits
262 struct create_parser
<complex>
264 typedef proto::result_of::deep_copy
<
265 BOOST_TYPEOF('{' >> qi::double_
>> ',' >> qi::double_
>> '}')
270 return proto::deep_copy(
271 '{' >> qi::double_
>> ',' >> qi::double_
>> '}');
277 //[reference_qi_auxiliary_attr_cast_data1
278 // this is just a test structure we want to use in place of an int
285 // we provide a custom attribute transformation to allow its use as an int
286 namespace boost
{ namespace spirit
{ namespace traits
288 // in this case we just expose the embedded 'int' as the attribute instance
289 // to use, allowing to leave the function 'post()' empty
291 struct transform_attribute
<int_data
, int, qi::domain
>
294 static int& pre(int_data
& d
) { return d
.i
; }
295 static void post(int_data
& val
, int const& attr
) {}
296 static void fail(int_data
&) {}
303 using boost::spirit::qi::grammar
;
304 using boost::spirit::qi::rule
;
305 using boost::spirit::ascii::space_type
;
307 //[reference_grammar_definition
308 /*`Basic grammar usage:
310 struct num_list
: grammar
<char const*, space_type
>
312 num_list() : base_type(start
)
314 using boost::spirit::int_
;
316 start
= num
>> *(',' >> num
);
319 rule
<char const*, space_type
> start
, num
;
328 //[reference_using_declarations_lit_char
329 using boost::spirit::qi::lit
;
330 using boost::spirit::ascii::char_
;
333 //[reference_char_literals
334 test_parser("x", 'x'); // plain literal
335 test_parser("x", lit('x')); // explicit literal
336 test_parser("x", char_('x')); // ascii::char_
339 //[reference_char_range
341 test_parser_attr("5", char_('0','9'), ch
); // ascii::char_ range
342 std::cout
<< ch
<< std::endl
; // prints '5'
345 //[reference_char_set
346 test_parser_attr("5", char_("0-9"), ch
); // ascii::char_ set
347 std::cout
<< ch
<< std::endl
; // prints '5'
350 //[reference_char_phoenix
351 namespace phx
= boost::phoenix
;
352 test_parser("x", phx::val('x')); // direct
354 char_(phx::val('0'),phx::val('9'))); // ascii::char_ range
359 //[reference_using_declarations_lit_string
360 using boost::spirit::qi::lit
;
361 using boost::spirit::ascii::string
;
364 //[reference_string_literals
365 test_parser("boost", "boost"); // plain literal
366 test_parser("boost", lit("boost")); // explicit literal
367 test_parser("boost", string("boost")); // ascii::string
372 using boost::spirit::qi::lit
;
373 using boost::spirit::ascii::string
;
375 //[reference_string_std_string
376 std::string
s("boost");
377 test_parser("boost", s
); // direct
378 test_parser("boost", lit(s
)); // explicit
379 test_parser("boost", string(s
)); // ascii::string
384 using boost::spirit::qi::lit
;
385 using boost::spirit::ascii::string
;
387 //[reference_string_phoenix
388 namespace phx
= boost::phoenix
;
389 test_parser("boost", phx::val("boost")); // direct
390 test_parser("boost", lit(phx::val("boost"))); // explicit
391 test_parser("boost", string(phx::val("boost"))); // ascii::string
396 //[reference_using_declarations_symbols
397 using boost::spirit::qi::symbols
;
400 //[reference_symbols_with_data
401 symbols
<char, int> sym
;
410 test_parser_attr("Banana", sym
, i
);
411 std::cout
<< i
<< std::endl
;
416 //[reference_using_declarations_lexeme
417 using boost::spirit::qi::lexeme
;
418 using boost::spirit::qi::lit
;
419 using boost::spirit::ascii::digit
;
423 /*`The use of lexeme here will prevent skipping in between the
424 digits and the sign making inputs such as `"1 2 345"` erroneous.*/
425 test_phrase_parser("12345", lexeme
[ -(lit('+') | '-') >> +digit
]);
431 //[reference_using_declarations_as
432 using boost::spirit::utree
;
433 using boost::spirit::utree_type
;
434 using boost::spirit::utf8_symbol_type
;
435 using boost::spirit::qi::as
;
436 using boost::spirit::qi::as_string
;
437 using boost::spirit::qi::char_
;
441 /*`To properly handle string concatenation with __utree__, we
442 make use of `as_string[]`. We also use `as<T>` to explicitly create
443 a __utree__ symbol node.*/
446 typedef as
<utf8_symbol_type
> as_symbol_type
;
447 as_symbol_type
const as_symbol
= as_symbol_type();
449 test_parser_attr("foo", as_string
[*char_
], ut
);
450 std::cout
<< ut
<< std::endl
; // will output >"foo"<
451 BOOST_ASSERT(ut
.which() == utree_type::string_type
);
454 test_parser_attr("foo", as
<std::string
>()[*char_
], ut
);
455 std::cout
<< ut
<< std::endl
; // will output >"foo"<
456 BOOST_ASSERT(ut
.which() == utree_type::string_type
);
459 test_parser_attr("foo", as_symbol
[*char_
], ut
);
460 std::cout
<< ut
<< std::endl
; // will output >foo<
461 BOOST_ASSERT(ut
.which() == utree_type::symbol_type
);
464 test_parser_attr("foo", as
<utf8_symbol_type
>()[*char_
], ut
);
465 std::cout
<< ut
<< std::endl
; // will output >foo<
466 BOOST_ASSERT(ut
.which() == utree_type::symbol_type
);
471 //[reference_using_declarations_no_skip
472 using boost::spirit::qi::no_skip
;
473 using boost::spirit::qi::char_
;
477 /*`The use of no_skip here will prevent skipping of whitespace in front
478 and in between the characters of the string `' abc '`.*/
481 test_phrase_parser_attr("' abc '",
482 '\'' >> no_skip
[+~char_('\'')] >> '\'', str
);
483 std::cout
<< str
<< std::endl
; // will output: > abc <
488 //[reference_using_declarations_hold
489 using boost::spirit::qi::hold
;
490 using boost::spirit::qi::int_
;
491 using boost::spirit::qi::attr
;
495 /*`The use of `hold[]` here will make sure the changes to the attribute
496 caused by the (failing) first alternative will not be visible after
497 the whole parsing succeeded. */
500 test_phrase_parser_attr("123",
501 hold
[int_
>> ':' >> int_
] | int_
>> attr(0), v
);
502 std::cout
<< v
[0] << "," << v
[1] << std::endl
; // will output: >123,0<
507 //[reference_using_declarations_no_case
508 using boost::spirit::ascii::no_case
;
509 using boost::spirit::ascii::char_
;
510 using boost::spirit::ascii::alnum
;
511 using boost::spirit::qi::symbols
;
515 test_parser("X", no_case
[char_('x')]);
516 test_parser("6", no_case
[alnum
]);
519 //[reference_symbols_with_no_case
520 symbols
<char, int> sym
;
523 ("apple", 1) // symbol strings are added in lowercase...
529 // ...because sym is used for case-insensitive parsing
530 test_parser_attr("Apple", no_case
[ sym
], i
);
531 std::cout
<< i
<< std::endl
;
532 test_parser_attr("ORANGE", no_case
[ sym
], i
);
533 std::cout
<< i
<< std::endl
;
538 //[reference_using_declarations_omit
539 using boost::spirit::qi::omit
;
540 using boost::spirit::qi::int_
;
541 using boost::spirit::ascii::char_
;
545 /*`This parser ignores the first two characters
546 and extracts the succeeding `int`:*/
548 test_parser_attr("xx345", omit
[char_
>> char_
] >> int_
, i
);
549 std::cout
<< i
<< std::endl
; // should print 345
554 //[reference_using_declarations_matches
555 using boost::spirit::qi::matches
;
556 using boost::spirit::qi::int_
;
560 /*`This parser tries to match an `int` and returns `true` a its
561 attribute as it succeeded matching: */
563 test_parser_attr("345", matches
[int_
], result
);
564 std::cout
<< std::boolalpha
<< result
<< std::endl
; // should print: true
566 /*`This parser tries to match an `int` as well and returns `false` as
567 its attribute as it fails matching: */
569 test_parser_attr("abc", matches
[int_
], result
);
570 std::cout
<< std::boolalpha
<< result
<< std::endl
; // should print: false
575 //[reference_using_declarations_raw
576 using boost::spirit::qi::raw
;
577 using boost::spirit::ascii::alpha
;
578 using boost::spirit::ascii::alnum
;
582 //`This parser matches and extracts C++ identifiers:
584 test_parser_attr("James007", raw
[(alpha
| '_') >> *(alnum
| '_')], id
);
585 std::cout
<< id
<< std::endl
; // should print James007
590 //[reference_using_declarations_repeat
591 using boost::spirit::qi::repeat
;
592 using boost::spirit::qi::lit
;
593 using boost::spirit::qi::uint_parser
;
594 using boost::spirit::qi::_1
;
595 using boost::spirit::ascii::char_
;
596 namespace phx
= boost::phoenix
;
600 //`A parser for a file name with a maximum of 255 characters:
601 test_parser("batman.jpeg", repeat(1, 255)[char_("a-zA-Z_./")]);
603 /*`A parser for a specific bitmap file format which has exactly 4096 RGB color information.
604 (for the purpose of this example, we will be testing only 3 RGB color information.)
606 uint_parser
<unsigned, 16, 6, 6> rgb
;
607 std::vector
<unsigned> colors
;
608 test_parser_attr("ffffff0000003f3f3f", repeat(3)[rgb
], colors
);
613 << colors
[2] << std::endl
;
615 /*`A 256 bit binary string (1..256 1s or 0s). (For the purpose of this example,
616 we will be testing only 16 bits.)
618 test_parser("1011101011110010", repeat(16)[lit('1') | '0']);
621 std::cout
<< std::dec
; // reset to decimal
623 //[reference_repeat_pascal
624 /*`This trivial example cannot be practically defined in traditional EBNF.
625 Although some EBNF variants allow more powerful repetition constructs other
626 than the Kleene Star, we are still limited to parsing fixed strings.
627 The nature of EBNF forces the repetition factor to be a constant.
628 On the other hand, Spirit allows the repetition factor to be variable at
629 run time. We could write a grammar that accepts the input string above.
630 Example using phoenix:
634 test_parser_attr("\x0bHello World",
635 char_
[phx::ref(n
) = _1
] >> repeat(phx::ref(n
))[char_
], str
);
636 std::cout
<< n
<< ',' << str
<< std::endl
; // will print "11,Hello World"
641 //[reference_using_declarations_skip
642 using boost::spirit::qi::skip
;
643 using boost::spirit::qi::int_
;
644 using boost::spirit::ascii::space
;
648 /*`Explicitly specify a skip parser. This parser parses comma
649 delimited numbers, ignoring spaces.*/
650 test_parser("1, 2, 3, 4, 5", skip(space
)[int_
>> *(',' >> int_
)]);
656 //[reference_using_declarations_attr
657 namespace phx
= boost::phoenix
;
658 using boost::spirit::qi::attr
;
663 test_parser_attr("", attr("boost"), str
);
664 std::cout
<< str
<< std::endl
; // will print 'boost'
667 test_parser_attr("", attr(1.0), d
);
668 std::cout
<< d
<< std::endl
; // will print '1.0'
671 //[reference_attr_phoenix
674 test_parser_attr("", attr(phx::ref(d1
)), d
);
675 std::cout
<< d
<< std::endl
; // will print '1.2'
681 //[reference_qi_using_declarations_attr_cast
682 using boost::spirit::qi::int_
;
685 //[reference_qi_attr_cast1
687 test_parser_attr("1", boost::spirit::qi::attr_cast(int_
), d
);
688 std::cout
<< d
.i
<< std::endl
;
694 //[reference_using_declarations_eol
695 using boost::spirit::qi::eol
;
699 test_parser("\n", eol
);
705 //[reference_using_declarations_eoi
706 using boost::spirit::qi::eoi
;
710 test_parser("", eoi
);
716 //[reference_using_declarations_eps
717 using boost::spirit::qi::eps
;
718 using boost::spirit::qi::int_
;
719 using boost::spirit::qi::_1
;
720 namespace phx
= boost::phoenix
;
725 test_parser("", eps
); // always matches
729 /*`This example simulates the "classic" `if_p` parser. Here, `int_` will be
730 tried only if the condition, `c`, is true.
732 bool c
= true; // a flag
733 test_parser("1234", eps(phx::ref(c
) == true) >> int_
);
736 //[reference_eps_while
737 /*`This example simulates the "classic" `while_p` parser. Here, the kleene loop
738 will exit once the condition, `c`, becomes true. Notice that the condition, `c`,
739 is turned to `false` when we get to parse `4`.
741 test_phrase_parser("1 2 3 4",
742 *(eps(phx::ref(c
) == true) >> int_
[phx::ref(c
) = (_1
== 4)]));
748 //[reference_using_declarations_lazy
749 using boost::spirit::qi::lazy
;
750 using boost::spirit::ascii::string
;
751 using boost::phoenix::val
;
755 /*` Here, the phoenix::val expression creates a function
756 that returns its argument when invoked. The lazy expression
757 defers the invocation of this function at parse time. Then,
758 this parser (string parser) is called into action. All this
759 takes place at parse time.
761 test_parser("Hello", lazy(val(string("Hello"))));
763 //` The above is equivalent to:
764 test_parser("Hello", val(string("Hello")));
770 //[reference_using_declarations_char_class
771 using boost::spirit::ascii::alnum
;
772 using boost::spirit::ascii::blank
;
773 using boost::spirit::ascii::digit
;
774 using boost::spirit::ascii::lower
;
777 //[reference_char_class
778 test_parser("1", alnum
);
779 test_parser(" ", blank
);
780 test_parser("1", digit
);
781 test_parser("a", lower
);
787 //[reference_using_declarations_uint
788 using boost::phoenix::val
;
789 using boost::spirit::qi::lit
;
790 using boost::spirit::qi::uint_
;
791 using boost::spirit::qi::uint_parser
;
796 test_parser("12345", uint_
);
797 test_parser("12345", uint_(12345));
798 test_parser("12345", uint_(val(12345)));
801 test_parser("12345", lit(12345));
802 test_parser("12345", lit(val(12345)));
805 //[reference_thousand_separated
806 //`Thousand separated number parser:
807 uint_parser
<unsigned, 10, 1, 3> uint3_p
; // 1..3 digits
808 uint_parser
<unsigned, 10, 3, 3> uint3_3_p
; // exactly 3 digits
809 test_parser("12,345,678", uint3_p
>> *(',' >> uint3_3_p
));
815 //[reference_using_declarations_int
816 using boost::phoenix::val
;
817 using boost::spirit::qi::lit
;
818 using boost::spirit::qi::int_
;
823 test_parser("+12345", int_
);
824 test_parser("-12345", int_
);
825 test_parser("+12345", int_(12345));
826 test_parser("-12345", int_(-12345));
827 test_parser("+12345", int_(val(12345)));
828 test_parser("-12345", int_(val(-12345)));
831 test_parser("+12345", lit(12345));
832 test_parser("-12345", lit(-12345));
833 test_parser("+12345", lit(val(12345)));
834 test_parser("-12345", lit(val(-12345)));
840 //[reference_using_declarations_real
841 using boost::phoenix::val
;
842 using boost::spirit::qi::double_
;
843 using boost::spirit::qi::real_parser
;
844 using boost::spirit::qi::lit
;
849 test_parser("+12345e6", double_
);
850 test_parser("-12345e6", double_
);
851 test_parser("+12345e6", double_(12345e6
));
852 test_parser("-12345e6", double_(-123456e6
));
853 test_parser("+12345e6", double_(val(12345e6
)));
854 test_parser("-12345e6", double_(val(-123456e6
)));
857 test_parser("+12345e6", lit(12345e6
));
858 test_parser("-12345e6", lit(-123456e6
));
859 test_parser("+12345e6", lit(val(12345e6
)));
860 test_parser("-12345e6", lit(val(-123456e6
)));
863 //[reference_custom_real
864 real_parser
<double, ts_real_policies
<double> > ts_real
;
865 test_parser("123,456,789.01", ts_real
);
866 test_parser("123,456,789.01", ts_real(123456789.01));
872 //[reference_using_declarations_bool
873 using boost::phoenix::val
;
874 using boost::spirit::qi::bool_
;
875 using boost::spirit::qi::bool_parser
;
876 using boost::spirit::qi::lit
;
881 test_parser("true", bool_
);
882 test_parser("false", bool_
);
883 test_parser("true", bool_(true));
884 test_parser("false", bool_(false));
885 test_parser("true", bool_(val(true)));
886 test_parser("false", bool_(val(false)));
889 test_parser("true", lit(true));
890 test_parser("false", lit(false));
891 test_parser("true", lit(val(true)));
892 test_parser("false", lit(val(false)));
895 //[reference_custom_bool
896 bool_parser
<bool, backwards_bool_policies
> backwards_bool
;
897 test_parser("true", backwards_bool
);
898 test_parser("eurt", backwards_bool
);
899 test_parser("true", backwards_bool(true));
900 test_parser("eurt", backwards_bool(false));
906 //[reference_using_declarations_sequence
907 using boost::spirit::ascii::char_
;
908 using boost::spirit::qi::_1
;
909 using boost::spirit::qi::_2
;
910 namespace bf
= boost::fusion
;
913 //[reference_sequence
915 test_parser("xy", char_
>> char_
);
917 //`Extracting the attribute tuple (using __fusion__):
918 bf::vector
<char, char> attr
;
919 test_parser_attr("xy", char_
>> char_
, attr
);
920 std::cout
<< bf::at_c
<0>(attr
) << ',' << bf::at_c
<1>(attr
) << std::endl
;
922 //`Extracting the attribute vector (using __stl__):
923 std::vector
<char> vec
;
924 test_parser_attr("xy", char_
>> char_
, vec
);
925 std::cout
<< vec
[0] << ',' << vec
[1] << std::endl
;
927 //`Extracting the attributes using __qi_semantic_actions__ (using __phoenix__):
928 test_parser("xy", (char_
>> char_
)[std::cout
<< _1
<< ',' << _2
<< std::endl
]);
934 //[reference_using_declarations_sequential_or
935 using boost::spirit::qi::int_
;
938 //[reference_sequential_or
939 //`Correctly parsing a number with optional fractional digits:
940 test_parser("123.456", int_
|| ('.' >> int_
)); // full
941 test_parser("123", int_
|| ('.' >> int_
)); // just the whole number
942 test_parser(".456", int_
|| ('.' >> int_
)); // just the fraction
944 /*`A naive but incorrect solution would try to do this using optionals (e.g.):
946 int_ >> -('.' >> int_) // will not match ".456"
947 -int_ >> ('.' >> int_) // will not match "123"
948 -int_ >> -('.' >> int_) // will match empty strings! Ooops.
955 //[reference_using_declarations_alternative
956 using boost::spirit::ascii::string
;
957 using boost::spirit::qi::int_
;
958 using boost::spirit::qi::_1
;
959 using boost::variant
;
962 //[reference_alternative
964 test_parser("Hello", string("Hello") | int_
);
965 test_parser("123", string("Hello") | int_
);
967 //`Extracting the attribute variant (using __boost_variant__):
968 variant
<std::string
, int> attr
;
969 test_parser_attr("Hello", string("Hello") | int_
, attr
);
971 /*`This should print `"Hello"`. Note: There are better ways to extract the value
972 from the variant. See __boost_variant__ visitation. This code is solely
975 if (boost::get
<int>(&attr
))
976 std::cout
<< boost::get
<int>(attr
) << std::endl
;
978 std::cout
<< boost::get
<std::string
>(attr
) << std::endl
;
980 /*`Extracting the attributes using __qi_semantic_actions__ with __phoenix__
981 (this should print `123`):
983 test_parser("123", (string("Hello") | int_
)[std::cout
<< _1
<< std::endl
]);
990 //[reference_using_declarations_permutation
991 using boost::spirit::ascii::char_
;
994 //[reference_permutation
995 //`Parse a string containing DNA codes (ACTG)
996 test_parser("ACTGGCTAGACT", *(char_('A') ^ 'C' ^ 'T' ^ 'G'));
1002 //[reference_using_declarations_expect
1003 using boost::spirit::ascii::char_
;
1004 using boost::spirit::qi::expectation_failure
;
1008 /*`The code below uses an expectation operator to throw an __qi_expectation_failure__
1009 with a deliberate parsing error when `"o"` is expected and `"i"` is what is
1010 found in the input. The `catch` block prints the information related to the
1011 error. Note: This is low level code that demonstrates the /bare-metal/. Typically,
1012 you use an __qi_error_handler__ to deal with the error.
1016 test_parser("xi", char_('x') > char_('o')); // should throw an exception
1018 catch (expectation_failure
<char const*> const& x
)
1020 std::cout
<< "expected: "; print_info(x
.what_
);
1021 std::cout
<< "got: \"" << std::string(x
.first
, x
.last
) << '"' << std::endl
;
1023 /*`The code above will print:[teletype]
1025 expected: tag: literal-char, value: o
1033 //[reference_using_declarations_expectd
1034 using boost::spirit::ascii::char_
;
1035 using boost::spirit::qi::expect
;
1036 using boost::spirit::qi::expectation_failure
;
1039 //[reference_expectd
1040 /*`The code below uses an expectation operator to throw an __qi_expectation_failure__
1041 with a deliberate parsing error when `"o"` is expected and `"x"` is what is
1042 found in the input. The `catch` block prints the information related to the
1043 error. Note: This is low level code that demonstrates the /bare-metal/. Typically,
1044 you use an __qi_error_handler__ to deal with the error.
1048 test_parser("xi", expect
[char_('o')]); // should throw an exception
1050 catch (expectation_failure
<char const*> const& x
)
1052 std::cout
<< "expected: "; print_info(x
.what_
);
1053 std::cout
<< "got: \"" << std::string(x
.first
, x
.last
) << '"' << std::endl
;
1055 /*`The code above will print:[teletype]
1057 expected: tag: literal-char, value: o
1065 //[reference_and_predicate
1066 //`Some using declarations:
1067 using boost::spirit::lit
;
1069 /*`Basic look-ahead example: make sure that the last character is a
1070 semicolon, but don't consume it, just peek at the next character:
1072 test_phrase_parser("Hello ;", lit("Hello") >> &lit(';'), false);
1078 //[reference_not_predicate
1079 //`Some using declarations:
1080 using boost::spirit::ascii::char_
;
1081 using boost::spirit::ascii::alpha
;
1082 using boost::spirit::qi::lit
;
1083 using boost::spirit::qi::symbols
;
1085 /*`Here's an alternative to the `*(r - x) >> x` idiom using the
1086 not-predicate instead. This parses a list of characters terminated
1089 test_parser("abcdef;", *(!lit(';') >> char_
) >> ';');
1091 /*`The following parser ensures that we match distinct keywords
1092 (stored in a symbol table). To do this, we make sure that the
1093 keyword does not follow an alpha or an underscore:
1095 symbols
<char, int> keywords
;
1096 keywords
= "begin", "end", "for";
1098 // This should fail:
1099 test_parser("beginner", keywords
>> !(alpha
| '_'));
1102 test_parser("end ", keywords
>> !(alpha
| '_'), false);
1105 test_parser("for()", keywords
>> !(alpha
| '_'), false);
1111 //[reference_difference
1112 //`Some using declarations:
1113 using boost::spirit::ascii::char_
;
1115 /*`Parse a C/C++ style comment:
1117 test_parser("/*A Comment*/", "/*" >> *(char_
- "*/") >> "*/");
1124 //`Some using declarations:
1125 using boost::spirit::qi::int_
;
1127 /*`Parse a comma separated list of numbers and put them in a vector:
1129 std::vector
<int> attr
;
1130 test_phrase_parser_attr(
1131 "111, 222, 333, 444, 555", int_
>> *(',' >> int_
), attr
);
1133 << attr
[0] << ',' << attr
[1] << ',' << attr
[2] << ','
1134 << attr
[3] << ',' << attr
[4]
1142 //`Some using declarations:
1143 using boost::spirit::ascii::alpha
;
1144 using boost::spirit::qi::lexeme
;
1146 /*`Parse one or more strings containing one or more alphabetic
1147 characters and put them in a vector:
1149 std::vector
<std::string
> attr
;
1150 test_phrase_parser_attr("yaba daba doo", +lexeme
[+alpha
], attr
);
1151 std::cout
<< attr
[0] << ',' << attr
[1] << ',' << attr
[2] << std::endl
;
1157 //[reference_optional
1158 //`Some using declarations:
1159 using boost::spirit::ascii::char_
;
1160 using boost::spirit::qi::lexeme
;
1161 using boost::spirit::qi::int_
;
1162 using boost::fusion::vector
;
1163 using boost::fusion::at_c
;
1164 using boost::optional
;
1166 /*`Parse a person info with name (in quotes) optional age [footnote
1167 James Bond is shy about his age :-)] and optional sex, all
1170 vector
<std::string
, optional
<int>, optional
<char> > attr
;
1172 test_phrase_parser_attr(
1174 , lexeme
['"' >> +(char_
- '"') >> '"'] // name
1175 >> -(',' >> int_
) // optional age
1176 >> -(',' >> char_
) // optional sex
1179 // Should print: James Bond,M
1180 std::cout
<< at_c
<0>(attr
); // print name
1181 if (at_c
<1>(attr
)) // print optional age
1182 std::cout
<< ',' << *at_c
<1>(attr
);
1183 if (at_c
<2>(attr
)) // print optional sex
1184 std::cout
<< ',' << *at_c
<2>(attr
);
1185 std::cout
<< std::endl
;
1192 //`Some using declarations:
1193 using boost::spirit::qi::int_
;
1195 /*`Parse a comma separated list of numbers and put them in a vector:
1197 std::vector
<int> attr
;
1198 test_phrase_parser_attr(
1199 "111, 222, 333, 444, 555", int_
% ',', attr
);
1201 << attr
[0] << ',' << attr
[1] << ',' << attr
[2] << ','
1202 << attr
[3] << ',' << attr
[4]
1209 //[reference_qi_stream
1210 //`Using declarations and variables:
1211 using boost::spirit::qi::stream
;
1212 using boost::spirit::qi::stream_parser
;
1214 /*`Parse a simple string using the operator>>(istream&, std::string&);
1217 test_parser_attr("abc", stream
, str
);
1218 std::cout
<< str
<< std::endl
; // prints: abc
1220 /*`Parse our complex type using the operator>>(istream&, complex&);
1223 test_parser_attr("{1.0,2.5}", stream_parser
<char, complex>(), c
);
1224 std::cout
<< c
.a
<< "," << c
.b
<< std::endl
; // prints: 1.0,2.5
1228 ///////////////////////////////////////////////////////////////////////////
1231 //[reference_qi_using_declarations_auto
1232 using boost::spirit::qi::auto_
;
1235 //[reference_qi_auto
1236 /*`Parse a simple integer using the generated parser component `int_`:
1239 test_parser_attr("123", auto_
, i
);
1240 std::cout
<< i
<< std::endl
; // prints: 123
1242 /*`Parse an instance of the `complex` data type as defined above using
1243 the parser as generated by the defined customization point:
1246 test_parser_attr("{1.2,2.4}", auto_
, c
);
1247 std::cout
<< c
.a
<< "," << c
.b
<< std::endl
; // prints: 1.2,2.4
1253 //[reference_qi_native_binary
1254 //`Using declarations and variables:
1255 using boost::spirit::qi::byte_
;
1256 using boost::spirit::qi::word
;
1257 using boost::spirit::qi::dword
;
1258 using boost::spirit::qi::qword
;
1264 #ifdef BOOST_HAS_LONG_LONG
1270 #ifdef BOOST_LITTLE_ENDIAN
1272 //`Basic usage of the native binary parsers for little endian platforms:
1273 test_parser_attr("\x01", byte_
, uc
); assert(uc
== 0x01);
1274 test_parser_attr("\x01\x02", word
, us
); assert(us
== 0x0201);
1275 test_parser_attr("\x01\x02\x03\x04", dword
, ui
); assert(ui
== 0x04030201);
1277 #ifdef BOOST_HAS_LONG_LONG
1279 test_parser_attr("\x01\x02\x03\x04\x05\x06\x07\x08", qword
, ul
);
1280 assert(ul
== 0x0807060504030201LL
);
1285 test_parser("\x01", byte_(0x01));
1286 test_parser("\x01\x02", word(0x0201));
1287 test_parser("\x01\x02\x03\x04", dword(0x04030201));
1289 #ifdef BOOST_HAS_LONG_LONG
1291 test_parser("\x01\x02\x03\x04\x05\x06\x07\x08",
1292 qword(0x0807060504030201LL
));
1297 //`Basic usage of the native binary parsers for big endian platforms:
1298 test_parser_attr("\x01", byte_
, uc
); assert(uc
== 0x01);
1299 test_parser_attr("\x01\x02", word
, us
); assert(us
== 0x0102);
1300 test_parser_attr("\x01\x02\x03\x04", dword
, ui
); assert(ui
== 0x01020304);
1302 #ifdef BOOST_HAS_LONG_LONG
1304 test_parser_attr("\x01\x02\x03\x04\x05\x06\x07\x08", qword
, ul
);
1305 assert(0x0102030405060708LL
);
1310 test_parser("\x01", byte_(0x01));
1311 test_parser("\x01\x02", word(0x0102));
1312 test_parser("\x01\x02\x03\x04", dword(0x01020304));
1314 #ifdef BOOST_HAS_LONG_LONG
1316 test_parser("\x01\x02\x03\x04\x05\x06\x07\x08",
1317 qword(0x0102030405060708LL
));
1327 //[reference_qi_little_binary
1328 //`Using declarations and variables:
1329 using boost::spirit::qi::little_word
;
1330 using boost::spirit::qi::little_dword
;
1331 using boost::spirit::qi::little_qword
;
1336 #ifdef BOOST_HAS_LONG_LONG
1343 //`Basic usage of the little endian binary parsers:
1344 test_parser_attr("\x01\x02", little_word
, us
); assert(us
== 0x0201);
1345 test_parser_attr("\x01\x02\x03\x04", little_dword
, ui
); assert(ui
== 0x04030201);
1347 #ifdef BOOST_HAS_LONG_LONG
1349 test_parser_attr("\x01\x02\x03\x04\x05\x06\x07\x08", little_qword
, ul
);
1350 assert(ul
== 0x0807060504030201LL
);
1355 test_parser("\x01\x02", little_word(0x0201));
1356 test_parser("\x01\x02\x03\x04", little_dword(0x04030201));
1358 #ifdef BOOST_HAS_LONG_LONG
1360 test_parser("\x01\x02\x03\x04\x05\x06\x07\x08",
1361 little_qword(0x0807060504030201LL
));
1370 //[reference_qi_big_binary
1371 //`Using declarations and variables:
1372 using boost::spirit::qi::big_word
;
1373 using boost::spirit::qi::big_dword
;
1374 using boost::spirit::qi::big_qword
;
1379 #ifdef BOOST_HAS_LONG_LONG
1386 //`Basic usage of the big endian binary parsers:
1387 test_parser_attr("\x01\x02", big_word
, us
); assert(us
== 0x0102);
1388 test_parser_attr("\x01\x02\x03\x04", big_dword
, ui
); assert(ui
== 0x01020304);
1390 #ifdef BOOST_HAS_LONG_LONG
1392 test_parser_attr("\x01\x02\x03\x04\x05\x06\x07\x08", big_qword
, ul
);
1393 assert(0x0102030405060708LL
);
1398 test_parser("\x01\x02", big_word(0x0102));
1399 test_parser("\x01\x02\x03\x04", big_dword(0x01020304));
1401 #ifdef BOOST_HAS_LONG_LONG
1403 test_parser("\x01\x02\x03\x04\x05\x06\x07\x08",
1404 big_qword(0x0102030405060708LL
));
1414 //`Some using declarations:
1415 using boost::spirit::qi::rule
;
1416 using boost::spirit::qi::int_
;
1417 using boost::spirit::qi::locals
;
1418 using boost::spirit::qi::_1
;
1419 using boost::spirit::qi::_a
;
1420 using boost::spirit::ascii::alpha
;
1421 using boost::spirit::ascii::char_
;
1422 using boost::spirit::ascii::space_type
;
1426 rule
<char const*> r
;
1428 test_parser("123", r
);
1430 /*`Rule with synthesized attribute:
1432 rule
<char const*, int()> ra
;
1435 test_parser_attr("123", ra
, i
);
1438 /*`Rule with skipper and synthesized attribute:
1440 rule
<char const*, std::vector
<int>(), space_type
> rs
;
1443 test_phrase_parser_attr("123 456 789", rs
, v
);
1444 assert(v
[0] == 123);
1445 assert(v
[1] == 456);
1446 assert(v
[2] == 789);
1448 /*`Rule with one local variable:
1450 rule
<char const*, locals
<char> > rl
;
1451 rl
= alpha
[_a
= _1
] >> char_(_a
); // get two identical characters
1452 test_parser("aa", rl
); // pass
1453 test_parser("ax", rl
); // fail
1459 using client::num_list
;
1461 //[reference_grammar_using
1462 //`Some using declarations:
1463 using boost::spirit::ascii::space_type
;
1464 using boost::spirit::int_
;
1465 using boost::spirit::qi::grammar
;
1466 using boost::spirit::qi::rule
;
1469 //[reference_grammar
1470 //`How to use the example grammar:
1472 test_phrase_parser("123, 456, 789", nlist
);