]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/spirit/example/qi/reference.cpp
import new upstream nautilus stable release 14.2.8
[ceph.git] / ceph / src / boost / libs / spirit / example / qi / reference.cpp
1 /*=============================================================================
2 Copyright (c) 2001-2011 Joel de Guzman
3 http://spirit.sourceforge.net/
4
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 =============================================================================*/
8
9 // this code is not supposed to be executed, so the asserts are for
10 // demonstration purposes only
11 // boostinspect:naassert_macro
12
13 //[reference_includes
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>
21 #include <iostream>
22 #include <string>
23 #include <cstdlib>
24 //]
25
26 //[reference_test
27 template <typename P>
28 void test_parser(
29 char const* input, P const& p, bool full_match = true)
30 {
31 using boost::spirit::qi::parse;
32
33 char const* f(input);
34 char const* l(f + strlen(f));
35 if (parse(f, l, p) && (!full_match || (f == l)))
36 std::cout << "ok" << std::endl;
37 else
38 std::cout << "fail" << std::endl;
39 }
40
41 template <typename P>
42 void test_phrase_parser(
43 char const* input, P const& p, bool full_match = true)
44 {
45 using boost::spirit::qi::phrase_parse;
46 using boost::spirit::qi::ascii::space;
47
48 char const* f(input);
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;
52 else
53 std::cout << "fail" << std::endl;
54 }
55 //]
56
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)
61 {
62 using boost::spirit::qi::parse;
63
64 char const* f(input);
65 char const* l(f + strlen(f));
66 if (parse(f, l, p, attr) && (!full_match || (f == l)))
67 std::cout << "ok" << std::endl;
68 else
69 std::cout << "fail" << std::endl;
70 }
71
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)
75 {
76 using boost::spirit::qi::phrase_parse;
77 using boost::spirit::qi::ascii::space;
78
79 char const* f(input);
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;
83 else
84 std::cout << "fail" << std::endl;
85 }
86 //]
87
88 //[reference_print_info
89 struct printer
90 {
91 typedef boost::spirit::utf8_string string;
92
93 void element(string const& tag, string const& value, int depth) const
94 {
95 for (int i = 0; i < (depth*4); ++i) // indent to depth
96 std::cout << ' ';
97
98 std::cout << "tag: " << tag;
99 if (value != "")
100 std::cout << ", value: " << value;
101 std::cout << std::endl;
102 }
103 };
104
105 void print_info(boost::spirit::info const& what)
106 {
107 using boost::spirit::basic_info_walker;
108
109 printer pr;
110 basic_info_walker<printer> walker(pr, what.tag, 0);
111 boost::apply_visitor(walker, what.value);
112 }
113 //]
114
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>
123 {
124 // 2 decimal places Max
125 template <typename Iterator, typename Attribute>
126 static bool
127 parse_frac_n(Iterator& first, Iterator const& last, Attribute& attr,
128 int& frac_digits)
129 {
130 Iterator savef = first;
131 bool r = boost::spirit::qi::
132 extract_uint<T, 10, 1, 2, true>::call(first, last, attr);
133 if (r) {
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));
138 }
139 return r;
140 }
141
142 // No exponent
143 template <typename Iterator>
144 static bool
145 parse_exp(Iterator&, Iterator const&)
146 {
147 return false;
148 }
149
150 // No exponent
151 template <typename Iterator, typename Attribute>
152 static bool
153 parse_exp_n(Iterator&, Iterator const&, Attribute&)
154 {
155 return false;
156 }
157
158 // Thousands separated numbers
159 template <typename Iterator, typename Accumulator>
160 static bool
161 parse_n(Iterator& first, Iterator const& last, Accumulator& result)
162 {
163 using boost::spirit::qi::uint_parser;
164 namespace qi = boost::spirit::qi;
165
166 uint_parser<unsigned, 10, 1, 3> uint3;
167 uint_parser<unsigned, 10, 3, 3> uint3_3;
168
169 if (parse(first, last, uint3, result))
170 {
171 Accumulator n;
172 Iterator iter = first;
173
174 while (qi::parse(iter, last, ',') && qi::parse(iter, last, uint3_3, n))
175 {
176 result = result * 1000 + n;
177 first = iter;
178 }
179
180 return true;
181 }
182 return false;
183 }
184 };
185 //]
186
187 //[reference_test_bool_policy
188 ///////////////////////////////////////////////////////////////////////////////
189 // These policies can be used to parse "eurt" (i.e. "true" spelled backwards)
190 // as `false`
191 ///////////////////////////////////////////////////////////////////////////////
192 struct backwards_bool_policies : boost::spirit::qi::bool_policies<>
193 {
194 // we want to interpret a 'true' spelled backwards as 'false'
195 template <typename Iterator, typename Attribute>
196 static bool
197 parse_false(Iterator& first, Iterator const& last, Attribute& attr)
198 {
199 namespace qi = boost::spirit::qi;
200 if (qi::detail::string_parse("eurt", first, last, qi::unused))
201 {
202 namespace traits = boost::spirit::traits;
203 traits::assign_to(false, attr); // result is false
204 return true;
205 }
206 return false;
207 }
208 };
209 //]
210
211 //[reference_qi_complex
212 // a simple complex number representation z = a + bi
213 struct complex
214 {
215 complex (double a = 0.0, double b = 0.0)
216 : a(a), b(b)
217 {}
218
219 double a;
220 double b;
221 };
222 //]
223
224 //[reference_qi_stream_complex
225 // define streaming operator for the type complex
226 std::istream&
227 operator>> (std::istream& is, complex& z)
228 {
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);
233 return is;
234 }
235 //]
236
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_ >> '}'`.
242 */
243 BOOST_FUSION_ADAPT_STRUCT(
244 complex,
245 (double, a)
246 (double, b)
247 )
248
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.
254 */
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
261 proto expression.
262 */
263 namespace boost { namespace spirit { namespace traits
264 {
265 template <>
266 struct create_parser<complex>
267 {
268 typedef proto::result_of::deep_copy<
269 BOOST_TYPEOF('{' >> qi::double_ >> ',' >> qi::double_ >> '}')
270 >::type type;
271
272 static type call()
273 {
274 return proto::deep_copy(
275 '{' >> qi::double_ >> ',' >> qi::double_ >> '}');
276 }
277 };
278 }}}
279 //]
280
281 //[reference_qi_auxiliary_attr_cast_data1
282 // this is just a test structure we want to use in place of an int
283 struct int_data
284 {
285 int i;
286 };
287
288
289 // we provide a custom attribute transformation to allow its use as an int
290 namespace boost { namespace spirit { namespace traits
291 {
292 // in this case we just expose the embedded 'int' as the attribute instance
293 // to use, allowing to leave the function 'post()' empty
294 template <>
295 struct transform_attribute<int_data, int, qi::domain>
296 {
297 typedef int& type;
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&) {}
301 };
302 }}}
303 //]
304
305 namespace client
306 {
307 using boost::spirit::qi::grammar;
308 using boost::spirit::qi::rule;
309 using boost::spirit::ascii::space_type;
310
311 //[reference_grammar_definition
312 /*`Basic grammar usage:
313 */
314 struct num_list : grammar<char const*, space_type>
315 {
316 num_list() : base_type(start)
317 {
318 using boost::spirit::int_;
319 num = int_;
320 start = num >> *(',' >> num);
321 }
322
323 rule<char const*, space_type> start, num;
324 };
325 //]
326 }
327
328 int
329 main()
330 {
331 {
332 //[reference_using_declarations_lit_char
333 using boost::spirit::qi::lit;
334 using boost::spirit::ascii::char_;
335 //]
336
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_
341 //]
342
343 //[reference_char_range
344 char ch;
345 test_parser_attr("5", char_('0','9'), ch); // ascii::char_ range
346 std::cout << ch << std::endl; // prints '5'
347 //]
348
349 //[reference_char_set
350 test_parser_attr("5", char_("0-9"), ch); // ascii::char_ set
351 std::cout << ch << std::endl; // prints '5'
352 //]
353
354 //[reference_char_phoenix
355 namespace phx = boost::phoenix;
356 test_parser("x", phx::val('x')); // direct
357 test_parser("5",
358 char_(phx::val('0'),phx::val('9'))); // ascii::char_ range
359 //]
360 }
361
362 {
363 //[reference_using_declarations_lit_string
364 using boost::spirit::qi::lit;
365 using boost::spirit::ascii::string;
366 //]
367
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
372 //]
373 }
374
375 {
376 using boost::spirit::qi::lit;
377 using boost::spirit::ascii::string;
378
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
384 //]
385 }
386
387 {
388 using boost::spirit::qi::lit;
389 using boost::spirit::ascii::string;
390
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
396 //]
397 }
398
399 {
400 //[reference_using_declarations_symbols
401 using boost::spirit::qi::symbols;
402 //]
403
404 //[reference_symbols_with_data
405 symbols<char, int> sym;
406
407 sym.add
408 ("Apple", 1)
409 ("Banana", 2)
410 ("Orange", 3)
411 ;
412
413 int i;
414 test_parser_attr("Banana", sym, i);
415 std::cout << i << std::endl;
416 //]
417 }
418
419 {
420 //[reference_using_declarations_lexeme
421 using boost::spirit::qi::lexeme;
422 using boost::spirit::qi::lit;
423 using boost::spirit::ascii::digit;
424 //]
425
426 //[reference_lexeme
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 ]);
430 //]
431 }
432
433 // as
434 {
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_;
442 //]
443
444 //[reference_as
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.*/
448 utree ut;
449
450 typedef as<utf8_symbol_type> as_symbol_type;
451 as_symbol_type const as_symbol = as_symbol_type();
452
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);
456 ut.clear();
457
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);
461 ut.clear();
462
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);
466 ut.clear();
467
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);
471 //]
472 }
473
474 {
475 //[reference_using_declarations_no_skip
476 using boost::spirit::qi::no_skip;
477 using boost::spirit::qi::char_;
478 //]
479
480 //[reference_no_skip
481 /*`The use of no_skip here will prevent skipping of whitespace in front
482 and in between the characters of the string `' abc '`.*/
483
484 std::string str;
485 test_phrase_parser_attr("' abc '",
486 '\'' >> no_skip[+~char_('\'')] >> '\'', str);
487 std::cout << str << std::endl; // will output: > abc <
488 //]
489 }
490
491 {
492 //[reference_using_declarations_hold
493 using boost::spirit::qi::hold;
494 using boost::spirit::qi::int_;
495 using boost::spirit::qi::attr;
496 //]
497
498 //[reference_hold
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. */
502
503 std::vector<int> v;
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<
507 //]
508 }
509
510 {
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;
516 //]
517
518 //[reference_no_case
519 test_parser("X", no_case[char_('x')]);
520 test_parser("6", no_case[alnum]);
521 //]
522
523 //[reference_symbols_with_no_case
524 symbols<char, int> sym;
525
526 sym.add
527 ("apple", 1) // symbol strings are added in lowercase...
528 ("banana", 2)
529 ("orange", 3)
530 ;
531
532 int i;
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;
538 //]
539 }
540
541 {
542 //[reference_using_declarations_omit
543 using boost::spirit::qi::omit;
544 using boost::spirit::qi::int_;
545 using boost::spirit::ascii::char_;
546 //]
547
548 //[reference_omit
549 /*`This parser ignores the first two characters
550 and extracts the succeeding `int`:*/
551 int i;
552 test_parser_attr("xx345", omit[char_ >> char_] >> int_, i);
553 std::cout << i << std::endl; // should print 345
554 //]
555 }
556
557 {
558 //[reference_using_declarations_matches
559 using boost::spirit::qi::matches;
560 using boost::spirit::qi::int_;
561 //]
562
563 //[reference_matches
564 /*`This parser tries to match an `int` and returns `true` a its
565 attribute as it succeeded matching: */
566 bool result = false;
567 test_parser_attr("345", matches[int_], result);
568 std::cout << std::boolalpha << result << std::endl; // should print: true
569
570 /*`This parser tries to match an `int` as well and returns `false` as
571 its attribute as it fails matching: */
572 result = true;
573 test_parser_attr("abc", matches[int_], result);
574 std::cout << std::boolalpha << result << std::endl; // should print: false
575 //]
576 }
577
578 {
579 //[reference_using_declarations_raw
580 using boost::spirit::qi::raw;
581 using boost::spirit::ascii::alpha;
582 using boost::spirit::ascii::alnum;
583 //]
584
585 //[reference_raw
586 //`This parser matches and extracts C++ identifiers:
587 std::string id;
588 test_parser_attr("James007", raw[(alpha | '_') >> *(alnum | '_')], id);
589 std::cout << id << std::endl; // should print James007
590 //]
591 }
592
593 {
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;
601 //]
602
603 //[reference_repeat
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_./")]);
606
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.)
609 */
610 uint_parser<unsigned, 16, 6, 6> rgb;
611 std::vector<unsigned> colors;
612 test_parser_attr("ffffff0000003f3f3f", repeat(3)[rgb], colors);
613 std::cout
614 << std::hex
615 << colors[0] << ','
616 << colors[1] << ','
617 << colors[2] << std::endl;
618
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.)
621 */
622 test_parser("1011101011110010", repeat(16)[lit('1') | '0']);
623 //]
624
625 std::cout << std::dec; // reset to decimal
626
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:
635 */
636 std::string str;
637 int n;
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"
641 //]
642 }
643
644 {
645 //[reference_using_declarations_skip
646 using boost::spirit::qi::skip;
647 using boost::spirit::qi::int_;
648 using boost::spirit::ascii::space;
649 //]
650
651 //[reference_skip
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_)]);
655 //]
656 }
657
658 // attr()
659 {
660 //[reference_using_declarations_attr
661 namespace phx = boost::phoenix;
662 using boost::spirit::qi::attr;
663 //]
664
665 //[reference_attr
666 std::string str;
667 test_parser_attr("", attr("boost"), str);
668 std::cout << str << std::endl; // will print 'boost'
669
670 double d;
671 test_parser_attr("", attr(1.0), d);
672 std::cout << d << std::endl; // will print '1.0'
673 //]
674
675 //[reference_attr_phoenix
676 d = 0.0;
677 double d1 = 1.2;
678 test_parser_attr("", attr(phx::ref(d1)), d);
679 std::cout << d << std::endl; // will print '1.2'
680 //]
681 }
682
683 // attr_cast
684 {
685 //[reference_qi_using_declarations_attr_cast
686 using boost::spirit::qi::int_;
687 //]
688
689 //[reference_qi_attr_cast1
690 int_data d = { 0 };
691 test_parser_attr("1", boost::spirit::qi::attr_cast(int_), d);
692 std::cout << d.i << std::endl;
693 //]
694 }
695
696 // eol
697 {
698 //[reference_using_declarations_eol
699 using boost::spirit::qi::eol;
700 //]
701
702 //[reference_eol
703 test_parser("\n", eol);
704 //]
705 }
706
707 // eoi
708 {
709 //[reference_using_declarations_eoi
710 using boost::spirit::qi::eoi;
711 //]
712
713 //[reference_eoi
714 test_parser("", eoi);
715 //]
716 }
717
718 // eps
719 {
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;
725 //]
726
727 //[reference_eps
728 //`Basic `eps`:
729 test_parser("", eps); // always matches
730 //]
731
732 //[reference_eps_if
733 /*`This example simulates the "classic" `if_p` parser. Here, `int_` will be
734 tried only if the condition, `c`, is true.
735 */
736 bool c = true; // a flag
737 test_parser("1234", eps(phx::ref(c) == true) >> int_);
738 //]
739
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`.
744 */
745 test_phrase_parser("1 2 3 4",
746 *(eps(phx::ref(c) == true) >> int_[phx::ref(c) = (_1 == 4)]));
747 //]
748 }
749
750 // lazy
751 {
752 //[reference_using_declarations_lazy
753 using boost::spirit::qi::lazy;
754 using boost::spirit::ascii::string;
755 using boost::phoenix::val;
756 //]
757
758 //[reference_lazy
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.
764 */
765 test_parser("Hello", lazy(val(string("Hello"))));
766
767 //` The above is equivalent to:
768 test_parser("Hello", string("Hello"));
769 //]
770 }
771
772 // char class
773 {
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;
779 //]
780
781 //[reference_char_class
782 test_parser("1", alnum);
783 test_parser(" ", blank);
784 test_parser("1", digit);
785 test_parser("a", lower);
786 //]
787 }
788
789 // uint
790 {
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;
796 //]
797
798 //[reference_uint
799 // unsigned int
800 test_parser("12345", uint_);
801 test_parser("12345", uint_(12345));
802 test_parser("12345", uint_(val(12345)));
803
804 // literals
805 test_parser("12345", lit(12345));
806 test_parser("12345", lit(val(12345)));
807 //]
808
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));
814 //]
815 }
816
817 // int
818 {
819 //[reference_using_declarations_int
820 using boost::phoenix::val;
821 using boost::spirit::qi::lit;
822 using boost::spirit::qi::int_;
823 //]
824
825 //[reference_int
826 // signed 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)));
833
834 // literals
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)));
839 //]
840 }
841
842 // real
843 {
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;
849 //]
850
851 //[reference_real
852 // double
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)));
859
860 // literals
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)));
865 //]
866
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));
871 //]
872 }
873
874 // bool_
875 {
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;
881 //]
882
883 //[reference_bool
884 // bool
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)));
891
892 // literals
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)));
897 //]
898
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));
905 //]
906 }
907
908 // sequence
909 {
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;
915 //]
916
917 //[reference_sequence
918 //`Simple usage:
919 test_parser("xy", char_ >> char_);
920
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;
925
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;
930
931 //`Extracting the attributes using __qi_semantic_actions__ (using __phoenix__):
932 test_parser("xy", (char_ >> char_)[std::cout << _1 << ',' << _2 << std::endl]);
933 //]
934 }
935
936 // sequential_or
937 {
938 //[reference_using_declarations_sequential_or
939 using boost::spirit::qi::int_;
940 //]
941
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
947
948 /*`A naive but incorrect solution would try to do this using optionals (e.g.):
949
950 int_ >> -('.' >> int_) // will not match ".456"
951 -int_ >> ('.' >> int_) // will not match "123"
952 -int_ >> -('.' >> int_) // will match empty strings! Ooops.
953 */
954 //]
955 }
956
957 // alternative
958 {
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;
964 //]
965
966 //[reference_alternative
967 //`Simple usage:
968 test_parser("Hello", string("Hello") | int_);
969 test_parser("123", string("Hello") | int_);
970
971 //`Extracting the attribute variant (using __boost_variant__):
972 variant<std::string, int> attr;
973 test_parser_attr("Hello", string("Hello") | int_, attr);
974
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
977 for demonstration.
978 */
979 if (boost::get<int>(&attr))
980 std::cout << boost::get<int>(attr) << std::endl;
981 else
982 std::cout << boost::get<std::string>(attr) << std::endl;
983
984 /*`Extracting the attributes using __qi_semantic_actions__ with __phoenix__
985 (this should print `123`):
986 */
987 test_parser("123", (string("Hello") | int_)[std::cout << _1 << std::endl]);
988 //]
989
990 }
991
992 // permutation
993 {
994 //[reference_using_declarations_permutation
995 using boost::spirit::ascii::char_;
996 //]
997
998 //[reference_permutation
999 //`Parse a string containing DNA codes (ACTG)
1000 test_parser("ACTGGCTAGACT", *(char_('A') ^ 'C' ^ 'T' ^ 'G'));
1001 //]
1002 }
1003
1004 // expect
1005 {
1006 //[reference_using_declarations_expect
1007 using boost::spirit::ascii::char_;
1008 using boost::spirit::qi::expectation_failure;
1009 //]
1010
1011 //[reference_expect
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.
1017 */
1018 try
1019 {
1020 test_parser("xi", char_('x') > char_('o')); // should throw an exception
1021 }
1022 catch (expectation_failure<char const*> const& x)
1023 {
1024 std::cout << "expected: "; print_info(x.what_);
1025 std::cout << "got: \"" << std::string(x.first, x.last) << '"' << std::endl;
1026 }
1027 /*`The code above will print:[teletype]
1028
1029 expected: tag: literal-char, value: o
1030 got: "i"``[c++]``
1031 */
1032 //]
1033 }
1034
1035 // expectd
1036 {
1037 //[reference_using_declarations_expectd
1038 using boost::spirit::ascii::char_;
1039 using boost::spirit::qi::expect;
1040 using boost::spirit::qi::expectation_failure;
1041 //]
1042
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.
1049 */
1050 try
1051 {
1052 test_parser("xi", expect[char_('o')]); // should throw an exception
1053 }
1054 catch (expectation_failure<char const*> const& x)
1055 {
1056 std::cout << "expected: "; print_info(x.what_);
1057 std::cout << "got: \"" << std::string(x.first, x.last) << '"' << std::endl;
1058 }
1059 /*`The code above will print:[teletype]
1060
1061 expected: tag: literal-char, value: o
1062 got: "x"``[c++]``
1063 */
1064 //]
1065 }
1066
1067 // and-predicate
1068 {
1069 //[reference_and_predicate
1070 //`Some using declarations:
1071 using boost::spirit::lit;
1072
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:
1075 */
1076 test_phrase_parser("Hello ;", lit("Hello") >> &lit(';'), false);
1077 //]
1078 }
1079
1080 // not-predicate
1081 {
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;
1088
1089 /*`Here's an alternative to the `*(r - x) >> x` idiom using the
1090 not-predicate instead. This parses a list of characters terminated
1091 by a ';':
1092 */
1093 test_parser("abcdef;", *(!lit(';') >> char_) >> ';');
1094
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:
1098 */
1099 symbols<char, int> keywords;
1100 keywords = "begin", "end", "for";
1101
1102 // This should fail:
1103 test_parser("beginner", keywords >> !(alpha | '_'));
1104
1105 // This is ok:
1106 test_parser("end ", keywords >> !(alpha | '_'), false);
1107
1108 // This is ok:
1109 test_parser("for()", keywords >> !(alpha | '_'), false);
1110 //]
1111 }
1112
1113 // difference
1114 {
1115 //[reference_difference
1116 //`Some using declarations:
1117 using boost::spirit::ascii::char_;
1118
1119 /*`Parse a C/C++ style comment:
1120 */
1121 test_parser("/*A Comment*/", "/*" >> *(char_ - "*/") >> "*/");
1122 //]
1123 }
1124
1125 // kleene
1126 {
1127 //[reference_kleene
1128 //`Some using declarations:
1129 using boost::spirit::qi::int_;
1130
1131 /*`Parse a comma separated list of numbers and put them in a vector:
1132 */
1133 std::vector<int> attr;
1134 test_phrase_parser_attr(
1135 "111, 222, 333, 444, 555", int_ >> *(',' >> int_), attr);
1136 std::cout
1137 << attr[0] << ',' << attr[1] << ',' << attr[2] << ','
1138 << attr[3] << ',' << attr[4]
1139 << std::endl;
1140 //]
1141 }
1142
1143 // plus
1144 {
1145 //[reference_plus
1146 //`Some using declarations:
1147 using boost::spirit::ascii::alpha;
1148 using boost::spirit::qi::lexeme;
1149
1150 /*`Parse one or more strings containing one or more alphabetic
1151 characters and put them in a vector:
1152 */
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;
1156 //]
1157 }
1158
1159 // optional
1160 {
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;
1169
1170 /*`Parse a person info with name (in quotes) optional age [footnote
1171 James Bond is shy about his age :-)] and optional sex, all
1172 separated by comma.
1173 */
1174 vector<std::string, optional<int>, optional<char> > attr;
1175
1176 test_phrase_parser_attr(
1177 "\"James Bond\", M"
1178 , lexeme['"' >> +(char_ - '"') >> '"'] // name
1179 >> -(',' >> int_) // optional age
1180 >> -(',' >> char_) // optional sex
1181 , attr);
1182
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;
1190 //]
1191 }
1192
1193 // list
1194 {
1195 //[reference_list
1196 //`Some using declarations:
1197 using boost::spirit::qi::int_;
1198
1199 /*`Parse a comma separated list of numbers and put them in a vector:
1200 */
1201 std::vector<int> attr;
1202 test_phrase_parser_attr(
1203 "111, 222, 333, 444, 555", int_ % ',', attr);
1204 std::cout
1205 << attr[0] << ',' << attr[1] << ',' << attr[2] << ','
1206 << attr[3] << ',' << attr[4]
1207 << std::endl;
1208 //]
1209 }
1210
1211 // stream
1212 {
1213 //[reference_qi_stream
1214 //`Using declarations and variables:
1215 using boost::spirit::qi::stream;
1216 using boost::spirit::qi::stream_parser;
1217
1218 /*`Parse a simple string using the operator>>(istream&, std::string&);
1219 */
1220 std::string str;
1221 test_parser_attr("abc", stream, str);
1222 std::cout << str << std::endl; // prints: abc
1223
1224 /*`Parse our complex type using the operator>>(istream&, complex&);
1225 */
1226 complex c;
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
1229 //]
1230 }
1231
1232 ///////////////////////////////////////////////////////////////////////////
1233 // auto module
1234 {
1235 //[reference_qi_using_declarations_auto
1236 using boost::spirit::qi::auto_;
1237 //]
1238
1239 //[reference_qi_auto
1240 /*`Parse a simple integer using the generated parser component `int_`:
1241 */
1242 int i = 0;
1243 test_parser_attr("123", auto_, i);
1244 std::cout << i << std::endl; // prints: 123
1245
1246 /*`Parse an instance of the `complex` data type as defined above using
1247 the parser as generated by the defined customization point:
1248 */
1249 complex c;
1250 test_parser_attr("{1.2,2.4}", auto_, c);
1251 std::cout << c.a << "," << c.b << std::endl; // prints: 1.2,2.4
1252 //]
1253 }
1254
1255 // native binary
1256 {
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;
1263
1264 boost::uint8_t uc;
1265 boost::uint16_t us;
1266 boost::uint32_t ui;
1267 //<-
1268 #ifdef BOOST_HAS_LONG_LONG
1269 //->
1270 boost::uint64_t ul;
1271 //<-
1272 #endif
1273
1274 #if BOOST_ENDIAN_LITTLE_BYTE
1275 //->
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);
1280 //<-
1281 #ifdef BOOST_HAS_LONG_LONG
1282 //->
1283 test_parser_attr("\x01\x02\x03\x04\x05\x06\x07\x08", qword, ul);
1284 assert(ul == 0x0807060504030201LL);
1285
1286 //<-
1287 #endif
1288 //->
1289 test_parser("\x01", byte_(0x01));
1290 test_parser("\x01\x02", word(0x0201));
1291 test_parser("\x01\x02\x03\x04", dword(0x04030201));
1292 //<-
1293 #ifdef BOOST_HAS_LONG_LONG
1294 //->
1295 test_parser("\x01\x02\x03\x04\x05\x06\x07\x08",
1296 qword(0x0807060504030201LL));
1297 //<-
1298 #endif
1299 #else
1300 //->
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);
1305 //<-
1306 #ifdef BOOST_HAS_LONG_LONG
1307 //->
1308 test_parser_attr("\x01\x02\x03\x04\x05\x06\x07\x08", qword, ul);
1309 assert(0x0102030405060708LL);
1310
1311 //<-
1312 #endif
1313 //->
1314 test_parser("\x01", byte_(0x01));
1315 test_parser("\x01\x02", word(0x0102));
1316 test_parser("\x01\x02\x03\x04", dword(0x01020304));
1317 //<-
1318 #ifdef BOOST_HAS_LONG_LONG
1319 //->
1320 test_parser("\x01\x02\x03\x04\x05\x06\x07\x08",
1321 qword(0x0102030405060708LL));
1322 //<-
1323 #endif
1324 #endif
1325 //->
1326 //]
1327 }
1328
1329 // little binary
1330 {
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;
1336
1337 boost::uint16_t us;
1338 boost::uint32_t ui;
1339 //<-
1340 #ifdef BOOST_HAS_LONG_LONG
1341 //->
1342 boost::uint64_t ul;
1343 //<-
1344 #endif
1345
1346 //->
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);
1350 //<-
1351 #ifdef BOOST_HAS_LONG_LONG
1352 //->
1353 test_parser_attr("\x01\x02\x03\x04\x05\x06\x07\x08", little_qword, ul);
1354 assert(ul == 0x0807060504030201LL);
1355
1356 //<-
1357 #endif
1358 //->
1359 test_parser("\x01\x02", little_word(0x0201));
1360 test_parser("\x01\x02\x03\x04", little_dword(0x04030201));
1361 //<-
1362 #ifdef BOOST_HAS_LONG_LONG
1363 //->
1364 test_parser("\x01\x02\x03\x04\x05\x06\x07\x08",
1365 little_qword(0x0807060504030201LL));
1366 //<-
1367 #endif
1368 //->
1369 //]
1370 }
1371
1372 // big binary
1373 {
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;
1379
1380 boost::uint16_t us;
1381 boost::uint32_t ui;
1382 //<-
1383 #ifdef BOOST_HAS_LONG_LONG
1384 //->
1385 boost::uint64_t ul;
1386 //<-
1387 #endif
1388
1389 //->
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);
1393 //<-
1394 #ifdef BOOST_HAS_LONG_LONG
1395 //->
1396 test_parser_attr("\x01\x02\x03\x04\x05\x06\x07\x08", big_qword, ul);
1397 assert(0x0102030405060708LL);
1398
1399 //<-
1400 #endif
1401 //->
1402 test_parser("\x01\x02", big_word(0x0102));
1403 test_parser("\x01\x02\x03\x04", big_dword(0x01020304));
1404 //<-
1405 #ifdef BOOST_HAS_LONG_LONG
1406 //->
1407 test_parser("\x01\x02\x03\x04\x05\x06\x07\x08",
1408 big_qword(0x0102030405060708LL));
1409 //<-
1410 #endif
1411 //->
1412 //]
1413 }
1414
1415 // rule
1416 {
1417 //[reference_rule
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;
1427
1428 /*`Basic rule:
1429 */
1430 rule<char const*> r;
1431 r = int_;
1432 test_parser("123", r);
1433
1434 /*`Rule with synthesized attribute:
1435 */
1436 rule<char const*, int()> ra;
1437 ra = int_;
1438 int i;
1439 test_parser_attr("123", ra, i);
1440 assert(i == 123);
1441
1442 /*`Rule with skipper and synthesized attribute:
1443 */
1444 rule<char const*, std::vector<int>(), space_type> rs;
1445 rs = *int_;
1446 std::vector<int> v;
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);
1451
1452 /*`Rule with one local variable:
1453 */
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
1458 //]
1459 }
1460
1461 // grammar
1462 {
1463 using client::num_list;
1464
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;
1471 //]
1472
1473 //[reference_grammar
1474 //`How to use the example grammar:
1475 num_list nlist;
1476 test_phrase_parser("123, 456, 789", nlist);
1477 //]
1478 }
1479
1480 return 0;
1481 }