]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/libs/spirit/example/qi/reference.cpp
update sources to v12.2.3
[ceph.git] / ceph / src / boost / libs / spirit / example / qi / reference.cpp
CommitLineData
7c673cae
FG
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 <iostream>
21#include <string>
22#include <cstdlib>
23//]
24
25//[reference_test
26template <typename P>
27void test_parser(
28 char const* input, P const& p, bool full_match = true)
29{
30 using boost::spirit::qi::parse;
31
32 char const* f(input);
33 char const* l(f + strlen(f));
34 if (parse(f, l, p) && (!full_match || (f == l)))
35 std::cout << "ok" << std::endl;
36 else
37 std::cout << "fail" << std::endl;
38}
39
40template <typename P>
41void test_phrase_parser(
42 char const* input, P const& p, bool full_match = true)
43{
44 using boost::spirit::qi::phrase_parse;
45 using boost::spirit::qi::ascii::space;
46
47 char const* f(input);
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;
51 else
52 std::cout << "fail" << std::endl;
53}
54//]
55
56//[reference_test_attr
57template <typename P, typename T>
58void test_parser_attr(
59 char const* input, P const& p, T& attr, bool full_match = true)
60{
61 using boost::spirit::qi::parse;
62
63 char const* f(input);
64 char const* l(f + strlen(f));
65 if (parse(f, l, p, attr) && (!full_match || (f == l)))
66 std::cout << "ok" << std::endl;
67 else
68 std::cout << "fail" << std::endl;
69}
70
71template <typename P, typename T>
72void test_phrase_parser_attr(
73 char const* input, P const& p, T& attr, bool full_match = true)
74{
75 using boost::spirit::qi::phrase_parse;
76 using boost::spirit::qi::ascii::space;
77
78 char const* f(input);
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;
82 else
83 std::cout << "fail" << std::endl;
84}
85//]
86
87//[reference_print_info
88struct printer
89{
90 typedef boost::spirit::utf8_string string;
91
92 void element(string const& tag, string const& value, int depth) const
93 {
94 for (int i = 0; i < (depth*4); ++i) // indent to depth
95 std::cout << ' ';
96
97 std::cout << "tag: " << tag;
98 if (value != "")
99 std::cout << ", value: " << value;
100 std::cout << std::endl;
101 }
102};
103
104void print_info(boost::spirit::info const& what)
105{
106 using boost::spirit::basic_info_walker;
107
108 printer pr;
109 basic_info_walker<printer> walker(pr, what.tag, 0);
110 boost::apply_visitor(walker, what.value);
111}
112//]
113
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///////////////////////////////////////////////////////////////////////////////
120template <typename T>
121struct ts_real_policies : boost::spirit::qi::ureal_policies<T>
122{
123 // 2 decimal places Max
124 template <typename Iterator, typename Attribute>
125 static bool
126 parse_frac_n(Iterator& first, Iterator const& last, Attribute& attr)
127 {
128 return boost::spirit::qi::
129 extract_uint<T, 10, 1, 2, true>::call(first, last, attr);
130 }
131
132 // No exponent
133 template <typename Iterator>
134 static bool
135 parse_exp(Iterator&, Iterator const&)
136 {
137 return false;
138 }
139
140 // No exponent
141 template <typename Iterator, typename Attribute>
142 static bool
143 parse_exp_n(Iterator&, Iterator const&, Attribute&)
144 {
145 return false;
146 }
147
148 // Thousands separated numbers
149 template <typename Iterator, typename Attribute>
150 static bool
151 parse_n(Iterator& first, Iterator const& last, Attribute& attr)
152 {
153 using boost::spirit::qi::uint_parser;
154 namespace qi = boost::spirit::qi;
155
156 uint_parser<unsigned, 10, 1, 3> uint3;
157 uint_parser<unsigned, 10, 3, 3> uint3_3;
158
159 T result = 0;
160 if (parse(first, last, uint3, result))
161 {
162 bool hit = false;
163 T n;
164 Iterator save = first;
165
166 while (qi::parse(first, last, ',') && qi::parse(first, last, uint3_3, n))
167 {
168 result = result * 1000 + n;
169 save = first;
170 hit = true;
171 }
172
173 first = save;
174 if (hit)
175 attr = result;
176 return hit;
177 }
178 return false;
179 }
180};
181//]
182
183//[reference_test_bool_policy
184///////////////////////////////////////////////////////////////////////////////
185// These policies can be used to parse "eurt" (i.e. "true" spelled backwards)
186// as `false`
187///////////////////////////////////////////////////////////////////////////////
188struct backwards_bool_policies : boost::spirit::qi::bool_policies<>
189{
190 // we want to interpret a 'true' spelled backwards as 'false'
191 template <typename Iterator, typename Attribute>
192 static bool
193 parse_false(Iterator& first, Iterator const& last, Attribute& attr)
194 {
195 namespace qi = boost::spirit::qi;
196 if (qi::detail::string_parse("eurt", first, last, qi::unused))
197 {
198 namespace traits = boost::spirit::traits;
199 traits::assign_to(false, attr); // result is false
200 return true;
201 }
202 return false;
203 }
204};
205//]
206
207//[reference_qi_complex
208// a simple complex number representation z = a + bi
209struct complex
210{
211 complex (double a = 0.0, double b = 0.0)
212 : a(a), b(b)
213 {}
214
215 double a;
216 double b;
217};
218//]
219
220//[reference_qi_stream_complex
221// define streaming operator for the type complex
222std::istream&
223operator>> (std::istream& is, complex& z)
224{
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);
229 return is;
230}
231//]
232
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_ >> '}'`.
238*/
239BOOST_FUSION_ADAPT_STRUCT(
240 complex,
241 (double, a)
242 (double, b)
243)
244
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.
250 */
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
257 proto expression.
258*/
259namespace boost { namespace spirit { namespace traits
260{
261 template <>
262 struct create_parser<complex>
263 {
264 typedef proto::result_of::deep_copy<
265 BOOST_TYPEOF('{' >> qi::double_ >> ',' >> qi::double_ >> '}')
266 >::type type;
267
268 static type call()
269 {
270 return proto::deep_copy(
271 '{' >> qi::double_ >> ',' >> qi::double_ >> '}');
272 }
273 };
274}}}
275//]
276
277//[reference_qi_auxiliary_attr_cast_data1
278// this is just a test structure we want to use in place of an int
279struct int_data
280{
281 int i;
282};
283
284
285// we provide a custom attribute transformation to allow its use as an int
286namespace boost { namespace spirit { namespace traits
287{
288 // in this case we just expose the embedded 'int' as the attribute instance
289 // to use, allowing to leave the function 'post()' empty
290 template <>
291 struct transform_attribute<int_data, int, qi::domain>
292 {
293 typedef int& type;
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&) {}
297 };
298}}}
299//]
300
301namespace client
302{
303 using boost::spirit::qi::grammar;
304 using boost::spirit::qi::rule;
305 using boost::spirit::ascii::space_type;
306
307//[reference_grammar_definition
308/*`Basic grammar usage:
309 */
310 struct num_list : grammar<char const*, space_type>
311 {
312 num_list() : base_type(start)
313 {
314 using boost::spirit::int_;
315 num = int_;
316 start = num >> *(',' >> num);
317 }
318
319 rule<char const*, space_type> start, num;
320 };
321//]
322}
323
324int
325main()
326{
327 {
328 //[reference_using_declarations_lit_char
329 using boost::spirit::qi::lit;
330 using boost::spirit::ascii::char_;
331 //]
332
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_
337 //]
338
339 //[reference_char_range
340 char ch;
341 test_parser_attr("5", char_('0','9'), ch); // ascii::char_ range
342 std::cout << ch << std::endl; // prints '5'
343 //]
344
345 //[reference_char_set
346 test_parser_attr("5", char_("0-9"), ch); // ascii::char_ set
347 std::cout << ch << std::endl; // prints '5'
348 //]
349
350 //[reference_char_phoenix
351 namespace phx = boost::phoenix;
352 test_parser("x", phx::val('x')); // direct
353 test_parser("5",
354 char_(phx::val('0'),phx::val('9'))); // ascii::char_ range
355 //]
356 }
357
358 {
359 //[reference_using_declarations_lit_string
360 using boost::spirit::qi::lit;
361 using boost::spirit::ascii::string;
362 //]
363
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
368 //]
369 }
370
371 {
372 using boost::spirit::qi::lit;
373 using boost::spirit::ascii::string;
374
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
380 //]
381 }
382
383 {
384 using boost::spirit::qi::lit;
385 using boost::spirit::ascii::string;
386
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
392 //]
393 }
394
395 {
396 //[reference_using_declarations_symbols
397 using boost::spirit::qi::symbols;
398 //]
399
400 //[reference_symbols_with_data
401 symbols<char, int> sym;
402
403 sym.add
404 ("Apple", 1)
405 ("Banana", 2)
406 ("Orange", 3)
407 ;
408
409 int i;
410 test_parser_attr("Banana", sym, i);
411 std::cout << i << std::endl;
412 //]
413 }
414
415 {
416 //[reference_using_declarations_lexeme
417 using boost::spirit::qi::lexeme;
418 using boost::spirit::qi::lit;
419 using boost::spirit::ascii::digit;
420 //]
421
422 //[reference_lexeme
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 ]);
426 //]
427 }
428
429 // as
430 {
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_;
438 //]
439
440 //[reference_as
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.*/
444 utree ut;
445
446 typedef as<utf8_symbol_type> as_symbol_type;
447 as_symbol_type const as_symbol = as_symbol_type();
448
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);
452 ut.clear();
453
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);
457 ut.clear();
458
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);
462 ut.clear();
463
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);
467 //]
468 }
469
470 {
471 //[reference_using_declarations_no_skip
472 using boost::spirit::qi::no_skip;
473 using boost::spirit::qi::char_;
474 //]
475
476 //[reference_no_skip
477 /*`The use of no_skip here will prevent skipping of whitespace in front
478 and in between the characters of the string `' abc '`.*/
479
480 std::string str;
481 test_phrase_parser_attr("' abc '",
482 '\'' >> no_skip[+~char_('\'')] >> '\'', str);
483 std::cout << str << std::endl; // will output: > abc <
484 //]
485 }
486
487 {
488 //[reference_using_declarations_hold
489 using boost::spirit::qi::hold;
490 using boost::spirit::qi::int_;
491 using boost::spirit::qi::attr;
492 //]
493
494 //[reference_hold
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. */
498
499 std::vector<int> v;
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<
503 //]
504 }
505
506 {
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;
512 //]
513
514 //[reference_no_case
515 test_parser("X", no_case[char_('x')]);
516 test_parser("6", no_case[alnum]);
517 //]
518
519 //[reference_symbols_with_no_case
520 symbols<char, int> sym;
521
522 sym.add
523 ("apple", 1) // symbol strings are added in lowercase...
524 ("banana", 2)
525 ("orange", 3)
526 ;
527
528 int i;
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;
534 //]
535 }
536
537 {
538 //[reference_using_declarations_omit
539 using boost::spirit::qi::omit;
540 using boost::spirit::qi::int_;
541 using boost::spirit::ascii::char_;
542 //]
543
544 //[reference_omit
545 /*`This parser ignores the first two characters
546 and extracts the succeeding `int`:*/
547 int i;
548 test_parser_attr("xx345", omit[char_ >> char_] >> int_, i);
549 std::cout << i << std::endl; // should print 345
550 //]
551 }
552
553 {
554 //[reference_using_declarations_matches
555 using boost::spirit::qi::matches;
556 using boost::spirit::qi::int_;
557 //]
558
559 //[reference_matches
560 /*`This parser tries to match an `int` and returns `true` a its
561 attribute as it succeeded matching: */
562 bool result = false;
563 test_parser_attr("345", matches[int_], result);
564 std::cout << std::boolalpha << result << std::endl; // should print: true
565
566 /*`This parser tries to match an `int` as well and returns `false` as
567 its attribute as it fails matching: */
568 result = true;
569 test_parser_attr("abc", matches[int_], result);
570 std::cout << std::boolalpha << result << std::endl; // should print: false
571 //]
572 }
573
574 {
575 //[reference_using_declarations_raw
576 using boost::spirit::qi::raw;
577 using boost::spirit::ascii::alpha;
578 using boost::spirit::ascii::alnum;
579 //]
580
581 //[reference_raw
582 //`This parser matches and extracts C++ identifiers:
583 std::string id;
584 test_parser_attr("James007", raw[(alpha | '_') >> *(alnum | '_')], id);
585 std::cout << id << std::endl; // should print James007
586 //]
587 }
588
589 {
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;
597 //]
598
599 //[reference_repeat
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_./")]);
602
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.)
605 */
606 uint_parser<unsigned, 16, 6, 6> rgb;
607 std::vector<unsigned> colors;
608 test_parser_attr("ffffff0000003f3f3f", repeat(3)[rgb], colors);
609 std::cout
610 << std::hex
611 << colors[0] << ','
612 << colors[1] << ','
613 << colors[2] << std::endl;
614
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.)
617 */
618 test_parser("1011101011110010", repeat(16)[lit('1') | '0']);
619 //]
620
621 std::cout << std::dec; // reset to decimal
622
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:
631 */
632 std::string str;
633 int n;
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"
637 //]
638 }
639
640 {
641 //[reference_using_declarations_skip
642 using boost::spirit::qi::skip;
643 using boost::spirit::qi::int_;
644 using boost::spirit::ascii::space;
645 //]
646
647 //[reference_skip
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_)]);
651 //]
652 }
653
654 // attr()
655 {
656 //[reference_using_declarations_attr
657 namespace phx = boost::phoenix;
658 using boost::spirit::qi::attr;
659 //]
660
661 //[reference_attr
662 std::string str;
663 test_parser_attr("", attr("boost"), str);
664 std::cout << str << std::endl; // will print 'boost'
665
666 double d;
667 test_parser_attr("", attr(1.0), d);
668 std::cout << d << std::endl; // will print '1.0'
669 //]
670
671 //[reference_attr_phoenix
672 d = 0.0;
673 double d1 = 1.2;
674 test_parser_attr("", attr(phx::ref(d1)), d);
675 std::cout << d << std::endl; // will print '1.2'
676 //]
677 }
678
679 // attr_cast
680 {
681 //[reference_qi_using_declarations_attr_cast
682 using boost::spirit::qi::int_;
683 //]
684
685 //[reference_qi_attr_cast1
686 int_data d = { 0 };
687 test_parser_attr("1", boost::spirit::qi::attr_cast(int_), d);
688 std::cout << d.i << std::endl;
689 //]
690 }
691
692 // eol
693 {
694 //[reference_using_declarations_eol
695 using boost::spirit::qi::eol;
696 //]
697
698 //[reference_eol
699 test_parser("\n", eol);
700 //]
701 }
702
703 // eoi
704 {
705 //[reference_using_declarations_eoi
706 using boost::spirit::qi::eoi;
707 //]
708
709 //[reference_eoi
710 test_parser("", eoi);
711 //]
712 }
713
714 // eps
715 {
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;
721 //]
722
723 //[reference_eps
724 //`Basic `eps`:
725 test_parser("", eps); // always matches
726 //]
727
728 //[reference_eps_if
729 /*`This example simulates the "classic" `if_p` parser. Here, `int_` will be
730 tried only if the condition, `c`, is true.
731 */
732 bool c = true; // a flag
733 test_parser("1234", eps(phx::ref(c) == true) >> int_);
734 //]
735
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`.
740 */
741 test_phrase_parser("1 2 3 4",
742 *(eps(phx::ref(c) == true) >> int_[phx::ref(c) = (_1 == 4)]));
743 //]
744 }
745
746 // lazy
747 {
748 //[reference_using_declarations_lazy
749 using boost::spirit::qi::lazy;
750 using boost::spirit::ascii::string;
751 using boost::phoenix::val;
752 //]
753
754 //[reference_lazy
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.
760 */
761 test_parser("Hello", lazy(val(string("Hello"))));
762
763 //` The above is equivalent to:
764 test_parser("Hello", val(string("Hello")));
765 //]
766 }
767
768 // char class
769 {
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;
775 //]
776
777 //[reference_char_class
778 test_parser("1", alnum);
779 test_parser(" ", blank);
780 test_parser("1", digit);
781 test_parser("a", lower);
782 //]
783 }
784
785 // uint
786 {
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;
792 //]
793
794 //[reference_uint
795 // unsigned int
796 test_parser("12345", uint_);
797 test_parser("12345", uint_(12345));
798 test_parser("12345", uint_(val(12345)));
799
800 // literals
801 test_parser("12345", lit(12345));
802 test_parser("12345", lit(val(12345)));
803 //]
804
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));
810 //]
811 }
812
813 // int
814 {
815 //[reference_using_declarations_int
816 using boost::phoenix::val;
817 using boost::spirit::qi::lit;
818 using boost::spirit::qi::int_;
819 //]
820
821 //[reference_int
822 // signed 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)));
829
830 // literals
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)));
835 //]
836 }
837
838 // real
839 {
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;
845 //]
846
847 //[reference_real
848 // double
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)));
855
856 // literals
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)));
861 //]
862
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));
867 //]
868 }
869
870 // bool_
871 {
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;
877 //]
878
879 //[reference_bool
880 // bool
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)));
887
888 // literals
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)));
893 //]
894
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));
901 //]
902 }
903
904 // sequence
905 {
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;
911 //]
912
913 //[reference_sequence
914 //`Simple usage:
915 test_parser("xy", char_ >> char_);
916
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;
921
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;
926
927 //`Extracting the attributes using __qi_semantic_actions__ (using __phoenix__):
928 test_parser("xy", (char_ >> char_)[std::cout << _1 << ',' << _2 << std::endl]);
929 //]
930 }
931
932 // sequential_or
933 {
934 //[reference_using_declarations_sequential_or
935 using boost::spirit::qi::int_;
936 //]
937
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
943
944 /*`A naive but incorrect solution would try to do this using optionals (e.g.):
945
946 int_ >> -('.' >> int_) // will not match ".456"
947 -int_ >> ('.' >> int_) // will not match "123"
948 -int_ >> -('.' >> int_) // will match empty strings! Ooops.
949 */
950 //]
951 }
952
953 // alternative
954 {
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;
960 //]
961
962 //[reference_alternative
963 //`Simple usage:
964 test_parser("Hello", string("Hello") | int_);
965 test_parser("123", string("Hello") | int_);
966
967 //`Extracting the attribute variant (using __boost_variant__):
968 variant<std::string, int> attr;
969 test_parser_attr("Hello", string("Hello") | int_, attr);
970
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
973 for demonstration.
974 */
975 if (boost::get<int>(&attr))
976 std::cout << boost::get<int>(attr) << std::endl;
977 else
978 std::cout << boost::get<std::string>(attr) << std::endl;
979
980 /*`Extracting the attributes using __qi_semantic_actions__ with __phoenix__
981 (this should print `123`):
982 */
983 test_parser("123", (string("Hello") | int_)[std::cout << _1 << std::endl]);
984 //]
985
986 }
987
988 // permutation
989 {
990 //[reference_using_declarations_permutation
991 using boost::spirit::ascii::char_;
992 //]
993
994 //[reference_permutation
995 //`Parse a string containing DNA codes (ACTG)
996 test_parser("ACTGGCTAGACT", *(char_('A') ^ 'C' ^ 'T' ^ 'G'));
997 //]
998 }
999
1000 // expect
1001 {
1002 //[reference_using_declarations_expect
1003 using boost::spirit::ascii::char_;
1004 using boost::spirit::qi::expectation_failure;
1005 //]
1006
1007 //[reference_expect
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.
1013 */
1014 try
1015 {
1016 test_parser("xi", char_('x') > char_('o')); // should throw an exception
1017 }
1018 catch (expectation_failure<char const*> const& x)
1019 {
1020 std::cout << "expected: "; print_info(x.what_);
1021 std::cout << "got: \"" << std::string(x.first, x.last) << '"' << std::endl;
1022 }
1023 /*`The code above will print:[teletype]
1024
1025 expected: tag: literal-char, value: o
1026 got: "i"``[c++]``
1027 */
1028 //]
1029 }
1030
b32b8144
FG
1031 // expectd
1032 {
1033 //[reference_using_declarations_expectd
1034 using boost::spirit::ascii::char_;
1035 using boost::spirit::qi::expect;
1036 using boost::spirit::qi::expectation_failure;
1037 //]
1038
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.
1045 */
1046 try
1047 {
1048 test_parser("xi", expect[char_('o')]); // should throw an exception
1049 }
1050 catch (expectation_failure<char const*> const& x)
1051 {
1052 std::cout << "expected: "; print_info(x.what_);
1053 std::cout << "got: \"" << std::string(x.first, x.last) << '"' << std::endl;
1054 }
1055 /*`The code above will print:[teletype]
1056
1057 expected: tag: literal-char, value: o
1058 got: "x"``[c++]``
1059 */
1060 //]
1061 }
1062
7c673cae
FG
1063 // and-predicate
1064 {
1065 //[reference_and_predicate
1066 //`Some using declarations:
1067 using boost::spirit::lit;
1068
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:
1071 */
1072 test_phrase_parser("Hello ;", lit("Hello") >> &lit(';'), false);
1073 //]
1074 }
1075
1076 // not-predicate
1077 {
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;
1084
1085 /*`Here's an alternative to the `*(r - x) >> x` idiom using the
1086 not-predicate instead. This parses a list of characters terminated
1087 by a ';':
1088 */
1089 test_parser("abcdef;", *(!lit(';') >> char_) >> ';');
1090
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:
1094 */
1095 symbols<char, int> keywords;
1096 keywords = "begin", "end", "for";
1097
1098 // This should fail:
1099 test_parser("beginner", keywords >> !(alpha | '_'));
1100
1101 // This is ok:
1102 test_parser("end ", keywords >> !(alpha | '_'), false);
1103
1104 // This is ok:
1105 test_parser("for()", keywords >> !(alpha | '_'), false);
1106 //]
1107 }
1108
1109 // difference
1110 {
1111 //[reference_difference
1112 //`Some using declarations:
1113 using boost::spirit::ascii::char_;
1114
1115 /*`Parse a C/C++ style comment:
1116 */
1117 test_parser("/*A Comment*/", "/*" >> *(char_ - "*/") >> "*/");
1118 //]
1119 }
1120
1121 // kleene
1122 {
1123 //[reference_kleene
1124 //`Some using declarations:
1125 using boost::spirit::qi::int_;
1126
1127 /*`Parse a comma separated list of numbers and put them in a vector:
1128 */
1129 std::vector<int> attr;
1130 test_phrase_parser_attr(
1131 "111, 222, 333, 444, 555", int_ >> *(',' >> int_), attr);
1132 std::cout
1133 << attr[0] << ',' << attr[1] << ',' << attr[2] << ','
1134 << attr[3] << ',' << attr[4]
1135 << std::endl;
1136 //]
1137 }
1138
1139 // plus
1140 {
1141 //[reference_plus
1142 //`Some using declarations:
1143 using boost::spirit::ascii::alpha;
1144 using boost::spirit::qi::lexeme;
1145
1146 /*`Parse one or more strings containing one or more alphabetic
1147 characters and put them in a vector:
1148 */
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;
1152 //]
1153 }
1154
1155 // optional
1156 {
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;
1165
1166 /*`Parse a person info with name (in quotes) optional age [footnote
1167 James Bond is shy about his age :-)] and optional sex, all
1168 separated by comma.
1169 */
1170 vector<std::string, optional<int>, optional<char> > attr;
1171
1172 test_phrase_parser_attr(
1173 "\"James Bond\", M"
1174 , lexeme['"' >> +(char_ - '"') >> '"'] // name
1175 >> -(',' >> int_) // optional age
1176 >> -(',' >> char_) // optional sex
1177 , attr);
1178
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;
1186 //]
1187 }
1188
1189 // list
1190 {
1191 //[reference_list
1192 //`Some using declarations:
1193 using boost::spirit::qi::int_;
1194
1195 /*`Parse a comma separated list of numbers and put them in a vector:
1196 */
1197 std::vector<int> attr;
1198 test_phrase_parser_attr(
1199 "111, 222, 333, 444, 555", int_ % ',', attr);
1200 std::cout
1201 << attr[0] << ',' << attr[1] << ',' << attr[2] << ','
1202 << attr[3] << ',' << attr[4]
1203 << std::endl;
1204 //]
1205 }
1206
1207 // stream
1208 {
1209 //[reference_qi_stream
1210 //`Using declarations and variables:
1211 using boost::spirit::qi::stream;
1212 using boost::spirit::qi::stream_parser;
1213
1214 /*`Parse a simple string using the operator>>(istream&, std::string&);
1215 */
1216 std::string str;
1217 test_parser_attr("abc", stream, str);
1218 std::cout << str << std::endl; // prints: abc
1219
1220 /*`Parse our complex type using the operator>>(istream&, complex&);
1221 */
1222 complex c;
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
1225 //]
1226 }
1227
1228 ///////////////////////////////////////////////////////////////////////////
1229 // auto module
1230 {
1231 //[reference_qi_using_declarations_auto
1232 using boost::spirit::qi::auto_;
1233 //]
1234
1235 //[reference_qi_auto
1236 /*`Parse a simple integer using the generated parser component `int_`:
1237 */
1238 int i = 0;
1239 test_parser_attr("123", auto_, i);
1240 std::cout << i << std::endl; // prints: 123
1241
1242 /*`Parse an instance of the `complex` data type as defined above using
1243 the parser as generated by the defined customization point:
1244 */
1245 complex c;
1246 test_parser_attr("{1.2,2.4}", auto_, c);
1247 std::cout << c.a << "," << c.b << std::endl; // prints: 1.2,2.4
1248 //]
1249 }
1250
1251 // native binary
1252 {
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;
1259
1260 boost::uint8_t uc;
1261 boost::uint16_t us;
1262 boost::uint32_t ui;
1263//<-
1264#ifdef BOOST_HAS_LONG_LONG
1265//->
1266 boost::uint64_t ul;
1267//<-
1268#endif
1269
1270#ifdef BOOST_LITTLE_ENDIAN
1271//->
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);
1276//<-
1277#ifdef BOOST_HAS_LONG_LONG
1278//->
1279 test_parser_attr("\x01\x02\x03\x04\x05\x06\x07\x08", qword, ul);
1280 assert(ul == 0x0807060504030201LL);
1281
1282//<-
1283#endif
1284//->
1285 test_parser("\x01", byte_(0x01));
1286 test_parser("\x01\x02", word(0x0201));
1287 test_parser("\x01\x02\x03\x04", dword(0x04030201));
1288//<-
1289#ifdef BOOST_HAS_LONG_LONG
1290//->
1291 test_parser("\x01\x02\x03\x04\x05\x06\x07\x08",
1292 qword(0x0807060504030201LL));
1293//<-
1294#endif
1295#else
1296//->
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);
1301//<-
1302#ifdef BOOST_HAS_LONG_LONG
1303//->
1304 test_parser_attr("\x01\x02\x03\x04\x05\x06\x07\x08", qword, ul);
1305 assert(0x0102030405060708LL);
1306
1307//<-
1308#endif
1309//->
1310 test_parser("\x01", byte_(0x01));
1311 test_parser("\x01\x02", word(0x0102));
1312 test_parser("\x01\x02\x03\x04", dword(0x01020304));
1313//<-
1314#ifdef BOOST_HAS_LONG_LONG
1315//->
1316 test_parser("\x01\x02\x03\x04\x05\x06\x07\x08",
1317 qword(0x0102030405060708LL));
1318//<-
1319#endif
1320#endif
1321//->
1322 //]
1323 }
1324
1325 // little binary
1326 {
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;
1332
1333 boost::uint16_t us;
1334 boost::uint32_t ui;
1335//<-
1336#ifdef BOOST_HAS_LONG_LONG
1337//->
1338 boost::uint64_t ul;
1339//<-
1340#endif
1341
1342//->
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);
1346//<-
1347#ifdef BOOST_HAS_LONG_LONG
1348//->
1349 test_parser_attr("\x01\x02\x03\x04\x05\x06\x07\x08", little_qword, ul);
1350 assert(ul == 0x0807060504030201LL);
1351
1352//<-
1353#endif
1354//->
1355 test_parser("\x01\x02", little_word(0x0201));
1356 test_parser("\x01\x02\x03\x04", little_dword(0x04030201));
1357//<-
1358#ifdef BOOST_HAS_LONG_LONG
1359//->
1360 test_parser("\x01\x02\x03\x04\x05\x06\x07\x08",
1361 little_qword(0x0807060504030201LL));
1362//<-
1363#endif
1364//->
1365 //]
1366 }
1367
1368 // big binary
1369 {
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;
1375
1376 boost::uint16_t us;
1377 boost::uint32_t ui;
1378//<-
1379#ifdef BOOST_HAS_LONG_LONG
1380//->
1381 boost::uint64_t ul;
1382//<-
1383#endif
1384
1385//->
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);
1389//<-
1390#ifdef BOOST_HAS_LONG_LONG
1391//->
1392 test_parser_attr("\x01\x02\x03\x04\x05\x06\x07\x08", big_qword, ul);
1393 assert(0x0102030405060708LL);
1394
1395//<-
1396#endif
1397//->
1398 test_parser("\x01\x02", big_word(0x0102));
1399 test_parser("\x01\x02\x03\x04", big_dword(0x01020304));
1400//<-
1401#ifdef BOOST_HAS_LONG_LONG
1402//->
1403 test_parser("\x01\x02\x03\x04\x05\x06\x07\x08",
1404 big_qword(0x0102030405060708LL));
1405//<-
1406#endif
1407//->
1408 //]
1409 }
1410
1411 // rule
1412 {
1413 //[reference_rule
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;
1423
1424 /*`Basic rule:
1425 */
1426 rule<char const*> r;
1427 r = int_;
1428 test_parser("123", r);
1429
1430 /*`Rule with synthesized attribute:
1431 */
1432 rule<char const*, int()> ra;
1433 ra = int_;
1434 int i;
1435 test_parser_attr("123", ra, i);
1436 assert(i == 123);
1437
1438 /*`Rule with skipper and synthesized attribute:
1439 */
1440 rule<char const*, std::vector<int>(), space_type> rs;
1441 rs = *int_;
1442 std::vector<int> v;
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);
1447
1448 /*`Rule with one local variable:
1449 */
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
1454 //]
1455 }
1456
1457 // grammar
1458 {
1459 using client::num_list;
1460
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;
1467 //]
1468
1469 //[reference_grammar
1470 //`How to use the example grammar:
1471 num_list nlist;
1472 test_phrase_parser("123, 456, 789", nlist);
1473 //]
1474 }
1475
1476 return 0;
1477}