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/phoenix/core.hpp>
17#include <boost/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 <boost/proto/deep_copy.hpp>
22#include <iostream>
23#include <string>
24#include <cstdlib>
25//]
26
27//[reference_test
28template <typename P>
29void test_parser(
30 char const* input, P const& p, bool full_match = true)
31{
32 using boost::spirit::qi::parse;
33
34 char const* f(input);
35 char const* l(f + strlen(s: f));
36 if (parse(f, l, p) && (!full_match || (f == l)))
37 std::cout << "ok" << std::endl;
38 else
39 std::cout << "fail" << std::endl;
40}
41
42template <typename P>
43void test_phrase_parser(
44 char const* input, P const& p, bool full_match = true)
45{
46 using boost::spirit::qi::phrase_parse;
47 using boost::spirit::qi::ascii::space;
48
49 char const* f(input);
50 char const* l(f + strlen(s: f));
51 if (phrase_parse(f, l, p, space) && (!full_match || (f == l)))
52 std::cout << "ok" << std::endl;
53 else
54 std::cout << "fail" << std::endl;
55}
56//]
57
58//[reference_test_attr
59template <typename P, typename T>
60void test_parser_attr(
61 char const* input, P const& p, T& attr, bool full_match = true)
62{
63 using boost::spirit::qi::parse;
64
65 char const* f(input);
66 char const* l(f + strlen(s: f));
67 if (parse(f, l, p, attr) && (!full_match || (f == l)))
68 std::cout << "ok" << std::endl;
69 else
70 std::cout << "fail" << std::endl;
71}
72
73template <typename P, typename T>
74void test_phrase_parser_attr(
75 char const* input, P const& p, T& attr, bool full_match = true)
76{
77 using boost::spirit::qi::phrase_parse;
78 using boost::spirit::qi::ascii::space;
79
80 char const* f(input);
81 char const* l(f + strlen(s: f));
82 if (phrase_parse(f, l, p, space, attr) && (!full_match || (f == l)))
83 std::cout << "ok" << std::endl;
84 else
85 std::cout << "fail" << std::endl;
86}
87//]
88
89//[reference_print_info
90struct printer
91{
92 typedef boost::spirit::utf8_string string;
93
94 void element(string const& tag, string const& value, int depth) const
95 {
96 for (int i = 0; i < (depth*4); ++i) // indent to depth
97 std::cout << ' ';
98
99 std::cout << "tag: " << tag;
100 if (value != "")
101 std::cout << ", value: " << value;
102 std::cout << std::endl;
103 }
104};
105
106void print_info(boost::spirit::info const& what)
107{
108 using boost::spirit::basic_info_walker;
109
110 printer pr;
111 basic_info_walker<printer> walker(pr, what.tag, 0);
112 boost::apply_visitor(visitor&: walker, visitable: what.value);
113}
114//]
115
116//[reference_test_real_policy
117///////////////////////////////////////////////////////////////////////////////
118// These policies can be used to parse thousand separated
119// numbers with at most 2 decimal digits after the decimal
120// point. e.g. 123,456,789.01
121///////////////////////////////////////////////////////////////////////////////
122template <typename T>
123struct ts_real_policies : boost::spirit::qi::ureal_policies<T>
124{
125 // 2 decimal places Max
126 template <typename Iterator, typename Attribute>
127 static bool
128 parse_frac_n(Iterator& first, Iterator const& last, Attribute& attr,
129 int& frac_digits)
130 {
131 Iterator savef = first;
132 bool r = boost::spirit::qi::
133 extract_uint<T, 10, 1, 2, true>::call(first, last, attr);
134 if (r) {
135 // Optimization note: don't compute frac_digits if T is
136 // an unused_type. This should be optimized away by the compiler.
137 if (!boost::is_same<T, boost::spirit::unused_type>::value)
138 frac_digits = static_cast<int>(std::distance(savef, first));
139 }
140 return r;
141 }
142
143 // No exponent
144 template <typename Iterator>
145 static bool
146 parse_exp(Iterator&, Iterator const&)
147 {
148 return false;
149 }
150
151 // No exponent
152 template <typename Iterator, typename Attribute>
153 static bool
154 parse_exp_n(Iterator&, Iterator const&, Attribute&)
155 {
156 return false;
157 }
158
159 // Thousands separated numbers
160 template <typename Iterator, typename Accumulator>
161 static bool
162 parse_n(Iterator& first, Iterator const& last, Accumulator& result)
163 {
164 using boost::spirit::qi::uint_parser;
165 namespace qi = boost::spirit::qi;
166
167 uint_parser<unsigned, 10, 1, 3> uint3;
168 uint_parser<unsigned, 10, 3, 3> uint3_3;
169
170 if (parse(first, last, uint3, result))
171 {
172 Accumulator n;
173 Iterator iter = first;
174
175 while (qi::parse(iter, last, ',') && qi::parse(iter, last, uint3_3, n))
176 {
177 result = result * 1000 + n;
178 first = iter;
179 }
180
181 return true;
182 }
183 return false;
184 }
185};
186//]
187
188//[reference_test_bool_policy
189///////////////////////////////////////////////////////////////////////////////
190// These policies can be used to parse "eurt" (i.e. "true" spelled backwards)
191// as `false`
192///////////////////////////////////////////////////////////////////////////////
193struct backwards_bool_policies : boost::spirit::qi::bool_policies<>
194{
195 // we want to interpret a 'true' spelled backwards as 'false'
196 template <typename Iterator, typename Attribute>
197 static bool
198 parse_false(Iterator& first, Iterator const& last, Attribute& attr)
199 {
200 namespace qi = boost::spirit::qi;
201 if (qi::detail::string_parse("eurt", first, last, qi::unused))
202 {
203 namespace traits = boost::spirit::traits;
204 traits::assign_to(false, attr); // result is false
205 return true;
206 }
207 return false;
208 }
209};
210//]
211
212//[reference_qi_complex
213// a simple complex number representation z = a + bi
214struct complex
215{
216 complex (double a = 0.0, double b = 0.0)
217 : a(a), b(b)
218 {}
219
220 double a;
221 double b;
222};
223//]
224
225//[reference_qi_stream_complex
226// define streaming operator for the type complex
227std::istream&
228operator>> (std::istream& is, complex& z)
229{
230 char lbrace = '\0', comma = '\0', rbrace = '\0';
231 is >> lbrace >> z.a >> comma >> z.b >> rbrace;
232 if (lbrace != '{' || comma != ',' || rbrace != '}')
233 is.setstate(std::ios_base::failbit);
234 return is;
235}
236//]
237
238//[reference_qi_auto_complex
239/*`The following construct is required to allow the `complex` data structure
240 to be utilized as a __fusion__ sequence. This is required as we will
241 emit output for this data structure with a __qi__ sequence:
242 `'{' >> qi::double_ >> ',' >> qi::double_ >> '}'`.
243*/
244BOOST_FUSION_ADAPT_STRUCT(
245 complex,
246 (double, a)
247 (double, b)
248)
249
250/*`We add a specialization for the create_parser customization point
251 defining a custom output format for the complex type. Generally, any
252 specialization for create_parser is expected to return the proto
253 expression to be used to match input for the type the customization
254 point has been specialized for.
255 */
256/*`We need to utilize `proto::deep_copy` as the expression contains literals
257 (the `'{'`, `','`, and `'}'`) which normally get embedded in the proto
258 expression by reference only. The deep copy converts the proto tree to
259 hold this by value. The deep copy operation can be left out for simpler
260 proto expressions (not containing references to temporaries). Alternatively
261 you could use the `proto::make_expr` facility to build the required
262 proto expression.
263*/
264namespace boost { namespace spirit { namespace traits
265{
266 template <>
267 struct create_parser<complex>
268 {
269 typedef proto::result_of::deep_copy<
270 BOOST_TYPEOF('{' >> qi::double_ >> ',' >> qi::double_ >> '}')
271 >::type type;
272
273 static type call()
274 {
275 return proto::deep_copy(
276 e: '{' >> qi::double_ >> ',' >> qi::double_ >> '}');
277 }
278 };
279}}}
280//]
281
282//[reference_qi_auxiliary_attr_cast_data1
283// this is just a test structure we want to use in place of an int
284struct int_data
285{
286 int i;
287};
288
289
290// we provide a custom attribute transformation to allow its use as an int
291namespace boost { namespace spirit { namespace traits
292{
293 // in this case we just expose the embedded 'int' as the attribute instance
294 // to use, allowing to leave the function 'post()' empty
295 template <>
296 struct transform_attribute<int_data, int, qi::domain>
297 {
298 typedef int& type;
299 static int& pre(int_data& d) { return d.i; }
300 static void post(int_data& val, int const& attr) {}
301 static void fail(int_data&) {}
302 };
303}}}
304//]
305
306namespace client
307{
308 using boost::spirit::qi::grammar;
309 using boost::spirit::qi::rule;
310 using boost::spirit::ascii::space_type;
311
312//[reference_grammar_definition
313/*`Basic grammar usage:
314 */
315 struct num_list : grammar<char const*, space_type>
316 {
317 num_list() : base_type(start)
318 {
319 using boost::spirit::int_;
320 num = int_;
321 start = num >> *(',' >> num);
322 }
323
324 rule<char const*, space_type> start, num;
325 };
326//]
327}
328
329int
330main()
331{
332 {
333 //[reference_using_declarations_lit_char
334 using boost::spirit::qi::lit;
335 using boost::spirit::ascii::char_;
336 //]
337
338 //[reference_char_literals
339 test_parser(input: "x", p: 'x'); // plain literal
340 test_parser(input: "x", p: lit('x')); // explicit literal
341 test_parser(input: "x", p: char_('x')); // ascii::char_
342 //]
343
344 //[reference_char_range
345 char ch;
346 test_parser_attr(input: "5", p: char_('0','9'), attr&: ch); // ascii::char_ range
347 std::cout << ch << std::endl; // prints '5'
348 //]
349
350 //[reference_char_set
351 test_parser_attr(input: "5", p: char_("0-9"), attr&: ch); // ascii::char_ set
352 std::cout << ch << std::endl; // prints '5'
353 //]
354
355 //[reference_char_phoenix
356 namespace phx = boost::phoenix;
357 test_parser(input: "x", p: phx::val(t: 'x')); // direct
358 test_parser(input: "5",
359 p: char_(phx::val(t: '0'),phx::val(t: '9'))); // ascii::char_ range
360 //]
361 }
362
363 {
364 //[reference_using_declarations_lit_string
365 using boost::spirit::qi::lit;
366 using boost::spirit::ascii::string;
367 //]
368
369 //[reference_string_literals
370 test_parser(input: "boost", p: "boost"); // plain literal
371 test_parser(input: "boost", p: lit("boost")); // explicit literal
372 test_parser(input: "boost", p: string("boost")); // ascii::string
373 //]
374 }
375
376 {
377 using boost::spirit::qi::lit;
378 using boost::spirit::ascii::string;
379
380 //[reference_string_std_string
381 std::string s("boost");
382 test_parser(input: "boost", p: s); // direct
383 test_parser(input: "boost", p: lit(s)); // explicit
384 test_parser(input: "boost", p: string(s)); // ascii::string
385 //]
386 }
387
388 {
389 using boost::spirit::qi::lit;
390 using boost::spirit::ascii::string;
391
392 //[reference_string_phoenix
393 namespace phx = boost::phoenix;
394 test_parser(input: "boost", p: phx::val(t: "boost")); // direct
395 test_parser(input: "boost", p: lit(phx::val(t: "boost"))); // explicit
396 test_parser(input: "boost", p: string(phx::val(t: "boost"))); // ascii::string
397 //]
398 }
399
400 {
401 //[reference_using_declarations_symbols
402 using boost::spirit::qi::symbols;
403 //]
404
405 //[reference_symbols_with_data
406 symbols<char, int> sym;
407
408 sym.add
409 ("Apple", 1)
410 ("Banana", 2)
411 ("Orange", 3)
412 ;
413
414 int i;
415 test_parser_attr(input: "Banana", p: sym, attr&: i);
416 std::cout << i << std::endl;
417 //]
418 }
419
420 {
421 //[reference_using_declarations_lexeme
422 using boost::spirit::qi::lexeme;
423 using boost::spirit::qi::lit;
424 using boost::spirit::ascii::digit;
425 //]
426
427 //[reference_lexeme
428 /*`The use of lexeme here will prevent skipping in between the
429 digits and the sign making inputs such as `"1 2 345"` erroneous.*/
430 test_phrase_parser(input: "12345", p: lexeme[ -(lit('+') | '-') >> +digit ]);
431 //]
432 }
433
434 // as
435 {
436 //[reference_using_declarations_as
437 using boost::spirit::utree;
438 using boost::spirit::utree_type;
439 using boost::spirit::utf8_symbol_type;
440 using boost::spirit::qi::as;
441 using boost::spirit::qi::as_string;
442 using boost::spirit::qi::char_;
443 //]
444
445 //[reference_as
446 /*`To properly handle string concatenation with __utree__, we
447 make use of `as_string[]`. We also use `as<T>` to explicitly create
448 a __utree__ symbol node.*/
449 utree ut;
450
451 typedef as<utf8_symbol_type> as_symbol_type;
452 as_symbol_type const as_symbol = as_symbol_type();
453
454 test_parser_attr(input: "foo", p: as_string[*char_], attr&: 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(input: "foo", p: as<std::string>()[*char_], attr&: ut);
460 std::cout << ut << std::endl; // will output >"foo"<
461 BOOST_ASSERT(ut.which() == utree_type::string_type);
462 ut.clear();
463
464 test_parser_attr(input: "foo", p: as_symbol[*char_], attr&: ut);
465 std::cout << ut << std::endl; // will output >foo<
466 BOOST_ASSERT(ut.which() == utree_type::symbol_type);
467 ut.clear();
468
469 test_parser_attr(input: "foo", p: as<utf8_symbol_type>()[*char_], attr&: ut);
470 std::cout << ut << std::endl; // will output >foo<
471 BOOST_ASSERT(ut.which() == utree_type::symbol_type);
472 //]
473 }
474
475 {
476 //[reference_using_declarations_no_skip
477 using boost::spirit::qi::no_skip;
478 using boost::spirit::qi::char_;
479 //]
480
481 //[reference_no_skip
482 /*`The use of no_skip here will prevent skipping of whitespace in front
483 and in between the characters of the string `' abc '`.*/
484
485 std::string str;
486 test_phrase_parser_attr(input: "' abc '",
487 p: '\'' >> no_skip[+~char_('\'')] >> '\'', attr&: str);
488 std::cout << str << std::endl; // will output: > abc <
489 //]
490 }
491
492 {
493 //[reference_using_declarations_hold
494 using boost::spirit::qi::hold;
495 using boost::spirit::qi::int_;
496 using boost::spirit::qi::attr;
497 //]
498
499 //[reference_hold
500 /*`The use of `hold[]` here will make sure the changes to the attribute
501 caused by the (failing) first alternative will not be visible after
502 the whole parsing succeeded. */
503
504 std::vector<int> v;
505 test_phrase_parser_attr(input: "123",
506 p: hold[int_ >> ':' >> int_] | int_ >> attr(0), attr&: v);
507 std::cout << v[0] << "," << v[1] << std::endl; // will output: >123,0<
508 //]
509 }
510
511 {
512 //[reference_using_declarations_no_case
513 using boost::spirit::ascii::no_case;
514 using boost::spirit::ascii::char_;
515 using boost::spirit::ascii::alnum;
516 using boost::spirit::qi::symbols;
517 //]
518
519 //[reference_no_case
520 test_parser(input: "X", p: no_case[char_('x')]);
521 test_parser(input: "6", p: no_case[alnum]);
522 //]
523
524 //[reference_symbols_with_no_case
525 symbols<char, int> sym;
526
527 sym.add
528 ("apple", 1) // symbol strings are added in lowercase...
529 ("banana", 2)
530 ("orange", 3)
531 ;
532
533 int i;
534 // ...because sym is used for case-insensitive parsing
535 test_parser_attr(input: "Apple", p: no_case[ sym ], attr&: i);
536 std::cout << i << std::endl;
537 test_parser_attr(input: "ORANGE", p: no_case[ sym ], attr&: i);
538 std::cout << i << std::endl;
539 //]
540 }
541
542 {
543 //[reference_using_declarations_omit
544 using boost::spirit::qi::omit;
545 using boost::spirit::qi::int_;
546 using boost::spirit::ascii::char_;
547 //]
548
549 //[reference_omit
550 /*`This parser ignores the first two characters
551 and extracts the succeeding `int`:*/
552 int i;
553 test_parser_attr(input: "xx345", p: omit[char_ >> char_] >> int_, attr&: i);
554 std::cout << i << std::endl; // should print 345
555 //]
556 }
557
558 {
559 //[reference_using_declarations_matches
560 using boost::spirit::qi::matches;
561 using boost::spirit::qi::int_;
562 //]
563
564 //[reference_matches
565 /*`This parser tries to match an `int` and returns `true` a its
566 attribute as it succeeded matching: */
567 bool result = false;
568 test_parser_attr(input: "345", p: matches[int_], attr&: result);
569 std::cout << std::boolalpha << result << std::endl; // should print: true
570
571 /*`This parser tries to match an `int` as well and returns `false` as
572 its attribute as it fails matching: */
573 result = true;
574 test_parser_attr(input: "abc", p: matches[int_], attr&: result);
575 std::cout << std::boolalpha << result << std::endl; // should print: false
576 //]
577 }
578
579 {
580 //[reference_using_declarations_raw
581 using boost::spirit::qi::raw;
582 using boost::spirit::ascii::alpha;
583 using boost::spirit::ascii::alnum;
584 //]
585
586 //[reference_raw
587 //`This parser matches and extracts C++ identifiers:
588 std::string id;
589 test_parser_attr(input: "James007", p: raw[(alpha | '_') >> *(alnum | '_')], attr&: id);
590 std::cout << id << std::endl; // should print James007
591 //]
592 }
593
594 {
595 //[reference_using_declarations_repeat
596 using boost::spirit::qi::repeat;
597 using boost::spirit::qi::lit;
598 using boost::spirit::qi::uint_parser;
599 using boost::spirit::qi::_1;
600 using boost::spirit::ascii::char_;
601 namespace phx = boost::phoenix;
602 //]
603
604 //[reference_repeat
605 //`A parser for a file name with a maximum of 255 characters:
606 test_parser(input: "batman.jpeg", p: repeat(1, 255)[char_("a-zA-Z_./")]);
607
608 /*`A parser for a specific bitmap file format which has exactly 4096 RGB color information.
609 (for the purpose of this example, we will be testing only 3 RGB color information.)
610 */
611 uint_parser<unsigned, 16, 6, 6> rgb;
612 std::vector<unsigned> colors;
613 test_parser_attr(input: "ffffff0000003f3f3f", p: repeat(3)[rgb], attr&: colors);
614 std::cout
615 << std::hex
616 << colors[0] << ','
617 << colors[1] << ','
618 << colors[2] << std::endl;
619
620 /*`A 256 bit binary string (1..256 1s or 0s). (For the purpose of this example,
621 we will be testing only 16 bits.)
622 */
623 test_parser(input: "1011101011110010", p: repeat(16)[lit('1') | '0']);
624 //]
625
626 std::cout << std::dec; // reset to decimal
627
628 //[reference_repeat_pascal
629 /*`This trivial example cannot be practically defined in traditional EBNF.
630 Although some EBNF variants allow more powerful repetition constructs other
631 than the Kleene Star, we are still limited to parsing fixed strings.
632 The nature of EBNF forces the repetition factor to be a constant.
633 On the other hand, Spirit allows the repetition factor to be variable at
634 run time. We could write a grammar that accepts the input string above.
635 Example using phoenix:
636 */
637 std::string str;
638 int n;
639 test_parser_attr(input: "\x0bHello World",
640 p: char_[phx::ref(t&: n) = _1] >> repeat(phx::ref(t&: n))[char_], attr&: str);
641 std::cout << n << ',' << str << std::endl; // will print "11,Hello World"
642 //]
643 }
644
645 {
646 //[reference_using_declarations_skip
647 using boost::spirit::qi::skip;
648 using boost::spirit::qi::int_;
649 using boost::spirit::ascii::space;
650 //]
651
652 //[reference_skip
653 /*`Explicitly specify a skip parser. This parser parses comma
654 delimited numbers, ignoring spaces.*/
655 test_parser(input: "1, 2, 3, 4, 5", p: skip(space)[int_ >> *(',' >> int_)]);
656 //]
657 }
658
659 // attr()
660 {
661 //[reference_using_declarations_attr
662 namespace phx = boost::phoenix;
663 using boost::spirit::qi::attr;
664 //]
665
666 //[reference_attr
667 std::string str;
668 test_parser_attr(input: "", p: attr("boost"), attr&: str);
669 std::cout << str << std::endl; // will print 'boost'
670
671 double d;
672 test_parser_attr(input: "", p: attr(1.0), attr&: d);
673 std::cout << d << std::endl; // will print '1.0'
674 //]
675
676 //[reference_attr_phoenix
677 d = 0.0;
678 double d1 = 1.2;
679 test_parser_attr(input: "", p: attr(phx::ref(t&: d1)), attr&: d);
680 std::cout << d << std::endl; // will print '1.2'
681 //]
682 }
683
684 // attr_cast
685 {
686 //[reference_qi_using_declarations_attr_cast
687 using boost::spirit::qi::int_;
688 //]
689
690 //[reference_qi_attr_cast1
691 int_data d = { .i: 0 };
692 test_parser_attr(input: "1", p: boost::spirit::qi::attr_cast(expr: int_), attr&: d);
693 std::cout << d.i << std::endl;
694 //]
695 }
696
697 // eol
698 {
699 //[reference_using_declarations_eol
700 using boost::spirit::qi::eol;
701 //]
702
703 //[reference_eol
704 test_parser(input: "\n", p: eol);
705 //]
706 }
707
708 // eoi
709 {
710 //[reference_using_declarations_eoi
711 using boost::spirit::qi::eoi;
712 //]
713
714 //[reference_eoi
715 test_parser(input: "", p: eoi);
716 //]
717 }
718
719 // eps
720 {
721 //[reference_using_declarations_eps
722 using boost::spirit::qi::eps;
723 using boost::spirit::qi::int_;
724 using boost::spirit::qi::_1;
725 namespace phx = boost::phoenix;
726 //]
727
728 //[reference_eps
729 //`Basic `eps`:
730 test_parser(input: "", p: eps); // always matches
731 //]
732
733 //[reference_eps_if
734 /*`This example simulates the "classic" `if_p` parser. Here, `int_` will be
735 tried only if the condition, `c`, is true.
736 */
737 bool c = true; // a flag
738 test_parser(input: "1234", p: eps(phx::ref(t&: c) == true) >> int_);
739 //]
740
741 //[reference_eps_while
742 /*`This example simulates the "classic" `while_p` parser. Here, the kleene loop
743 will exit once the condition, `c`, becomes true. Notice that the condition, `c`,
744 is turned to `false` when we get to parse `4`.
745 */
746 test_phrase_parser(input: "1 2 3 4",
747 p: *(eps(phx::ref(t&: c) == true) >> int_[phx::ref(t&: c) = (_1 == 4)]));
748 //]
749 }
750
751 // lazy
752 {
753 //[reference_using_declarations_lazy
754 using boost::spirit::qi::lazy;
755 using boost::spirit::ascii::string;
756 using boost::phoenix::val;
757 //]
758
759 //[reference_lazy
760 /*` Here, the phoenix::val expression creates a function
761 that returns its argument when invoked. The lazy expression
762 defers the invocation of this function at parse time. Then,
763 this parser (string parser) is called into action. All this
764 takes place at parse time.
765 */
766 test_parser(input: "Hello", p: lazy(f: val(t: string("Hello"))));
767
768 //` The above is equivalent to:
769 test_parser(input: "Hello", p: string("Hello"));
770 //]
771 }
772
773 // char class
774 {
775 //[reference_using_declarations_char_class
776 using boost::spirit::ascii::alnum;
777 using boost::spirit::ascii::blank;
778 using boost::spirit::ascii::digit;
779 using boost::spirit::ascii::lower;
780 //]
781
782 //[reference_char_class
783 test_parser(input: "1", p: alnum);
784 test_parser(input: " ", p: blank);
785 test_parser(input: "1", p: digit);
786 test_parser(input: "a", p: lower);
787 //]
788 }
789
790 // uint
791 {
792 //[reference_using_declarations_uint
793 using boost::phoenix::val;
794 using boost::spirit::qi::lit;
795 using boost::spirit::qi::uint_;
796 using boost::spirit::qi::uint_parser;
797 //]
798
799 //[reference_uint
800 // unsigned int
801 test_parser(input: "12345", p: uint_);
802 test_parser(input: "12345", p: uint_(12345));
803 test_parser(input: "12345", p: uint_(val(t: 12345)));
804
805 // literals
806 test_parser(input: "12345", p: lit(12345));
807 test_parser(input: "12345", p: lit(val(t: 12345)));
808 //]
809
810 //[reference_thousand_separated
811 //`Thousand separated number parser:
812 uint_parser<unsigned, 10, 1, 3> uint3_p; // 1..3 digits
813 uint_parser<unsigned, 10, 3, 3> uint3_3_p; // exactly 3 digits
814 test_parser(input: "12,345,678", p: uint3_p >> *(',' >> uint3_3_p));
815 //]
816 }
817
818 // int
819 {
820 //[reference_using_declarations_int
821 using boost::phoenix::val;
822 using boost::spirit::qi::lit;
823 using boost::spirit::qi::int_;
824 //]
825
826 //[reference_int
827 // signed int
828 test_parser(input: "+12345", p: int_);
829 test_parser(input: "-12345", p: int_);
830 test_parser(input: "+12345", p: int_(12345));
831 test_parser(input: "-12345", p: int_(-12345));
832 test_parser(input: "+12345", p: int_(val(t: 12345)));
833 test_parser(input: "-12345", p: int_(val(t: -12345)));
834
835 // literals
836 test_parser(input: "+12345", p: lit(12345));
837 test_parser(input: "-12345", p: lit(-12345));
838 test_parser(input: "+12345", p: lit(val(t: 12345)));
839 test_parser(input: "-12345", p: lit(val(t: -12345)));
840 //]
841 }
842
843 // real
844 {
845 //[reference_using_declarations_real
846 using boost::phoenix::val;
847 using boost::spirit::qi::double_;
848 using boost::spirit::qi::real_parser;
849 using boost::spirit::qi::lit;
850 //]
851
852 //[reference_real
853 // double
854 test_parser(input: "+12345e6", p: double_);
855 test_parser(input: "-12345e6", p: double_);
856 test_parser(input: "+12345e6", p: double_(12345e6));
857 test_parser(input: "-12345e6", p: double_(-123456e6));
858 test_parser(input: "+12345e6", p: double_(val(t: 12345e6)));
859 test_parser(input: "-12345e6", p: double_(val(t: -123456e6)));
860
861 // literals
862 test_parser(input: "+12345e6", p: lit(12345e6));
863 test_parser(input: "-12345e6", p: lit(-123456e6));
864 test_parser(input: "+12345e6", p: lit(val(t: 12345e6)));
865 test_parser(input: "-12345e6", p: lit(val(t: -123456e6)));
866 //]
867
868 //[reference_custom_real
869 real_parser<double, ts_real_policies<double> > ts_real;
870 test_parser(input: "123,456,789.01", p: ts_real);
871 test_parser(input: "123,456,789.01", p: ts_real(123456789.01));
872 //]
873 }
874
875 // bool_
876 {
877 //[reference_using_declarations_bool
878 using boost::phoenix::val;
879 using boost::spirit::qi::bool_;
880 using boost::spirit::qi::bool_parser;
881 using boost::spirit::qi::lit;
882 //]
883
884 //[reference_bool
885 // bool
886 test_parser(input: "true", p: bool_);
887 test_parser(input: "false", p: bool_);
888 test_parser(input: "true", p: bool_(true));
889 test_parser(input: "false", p: bool_(false));
890 test_parser(input: "true", p: bool_(val(t: true)));
891 test_parser(input: "false", p: bool_(val(t: false)));
892
893 // literals
894 test_parser(input: "true", p: lit(true));
895 test_parser(input: "false", p: lit(false));
896 test_parser(input: "true", p: lit(val(t: true)));
897 test_parser(input: "false", p: lit(val(t: false)));
898 //]
899
900 //[reference_custom_bool
901 bool_parser<bool, backwards_bool_policies> backwards_bool;
902 test_parser(input: "true", p: backwards_bool);
903 test_parser(input: "eurt", p: backwards_bool);
904 test_parser(input: "true", p: backwards_bool(true));
905 test_parser(input: "eurt", p: backwards_bool(false));
906 //]
907 }
908
909 // sequence
910 {
911 //[reference_using_declarations_sequence
912 using boost::spirit::ascii::char_;
913 using boost::spirit::qi::_1;
914 using boost::spirit::qi::_2;
915 namespace bf = boost::fusion;
916 //]
917
918 //[reference_sequence
919 //`Simple usage:
920 test_parser(input: "xy", p: char_ >> char_);
921
922 //`Extracting the attribute tuple (using __fusion__):
923 bf::vector<char, char> attr;
924 test_parser_attr(input: "xy", p: char_ >> char_, attr);
925 std::cout << bf::at_c<0>(seq&: attr) << ',' << bf::at_c<1>(seq&: attr) << std::endl;
926
927 //`Extracting the attribute vector (using __stl__):
928 std::vector<char> vec;
929 test_parser_attr(input: "xy", p: char_ >> char_, attr&: vec);
930 std::cout << vec[0] << ',' << vec[1] << std::endl;
931
932 //`Extracting the attributes using __qi_semantic_actions__ (using __phoenix__):
933 test_parser(input: "xy", p: (char_ >> char_)[std::cout << _1 << ',' << _2 << std::endl]);
934 //]
935 }
936
937 // sequential_or
938 {
939 //[reference_using_declarations_sequential_or
940 using boost::spirit::qi::int_;
941 //]
942
943 //[reference_sequential_or
944 //`Correctly parsing a number with optional fractional digits:
945 test_parser(input: "123.456", p: int_ || ('.' >> int_)); // full
946 test_parser(input: "123", p: int_ || ('.' >> int_)); // just the whole number
947 test_parser(input: ".456", p: int_ || ('.' >> int_)); // just the fraction
948
949 /*`A naive but incorrect solution would try to do this using optionals (e.g.):
950
951 int_ >> -('.' >> int_) // will not match ".456"
952 -int_ >> ('.' >> int_) // will not match "123"
953 -int_ >> -('.' >> int_) // will match empty strings! Ooops.
954 */
955 //]
956 }
957
958 // alternative
959 {
960 //[reference_using_declarations_alternative
961 using boost::spirit::ascii::string;
962 using boost::spirit::qi::int_;
963 using boost::spirit::qi::_1;
964 using boost::variant;
965 //]
966
967 //[reference_alternative
968 //`Simple usage:
969 test_parser(input: "Hello", p: string("Hello") | int_);
970 test_parser(input: "123", p: string("Hello") | int_);
971
972 //`Extracting the attribute variant (using __boost_variant__):
973 variant<std::string, int> attr;
974 test_parser_attr(input: "Hello", p: string("Hello") | int_, attr);
975
976 /*`This should print `"Hello"`. Note: There are better ways to extract the value
977 from the variant. See __boost_variant__ visitation. This code is solely
978 for demonstration.
979 */
980 if (boost::get<int>(operand: &attr))
981 std::cout << boost::get<int>(operand&: attr) << std::endl;
982 else
983 std::cout << boost::get<std::string>(operand&: attr) << std::endl;
984
985 /*`Extracting the attributes using __qi_semantic_actions__ with __phoenix__
986 (this should print `123`):
987 */
988 test_parser(input: "123", p: (string("Hello") | int_)[std::cout << _1 << std::endl]);
989 //]
990
991 }
992
993 // permutation
994 {
995 //[reference_using_declarations_permutation
996 using boost::spirit::ascii::char_;
997 //]
998
999 //[reference_permutation
1000 //`Parse a string containing DNA codes (ACTG)
1001 test_parser(input: "ACTGGCTAGACT", p: *(char_('A') ^ 'C' ^ 'T' ^ 'G'));
1002 //]
1003 }
1004
1005 // expect
1006 {
1007 //[reference_using_declarations_expect
1008 using boost::spirit::ascii::char_;
1009 using boost::spirit::qi::expectation_failure;
1010 //]
1011
1012 //[reference_expect
1013 /*`The code below uses an expectation operator to throw an __qi_expectation_failure__
1014 with a deliberate parsing error when `"o"` is expected and `"i"` is what is
1015 found in the input. The `catch` block prints the information related to the
1016 error. Note: This is low level code that demonstrates the /bare-metal/. Typically,
1017 you use an __qi_error_handler__ to deal with the error.
1018 */
1019 try
1020 {
1021 test_parser(input: "xi", p: char_('x') > char_('o')); // should throw an exception
1022 }
1023 catch (expectation_failure<char const*> const& x)
1024 {
1025 std::cout << "expected: "; print_info(what: x.what_);
1026 std::cout << "got: \"" << std::string(x.first, x.last) << '"' << std::endl;
1027 }
1028 /*`The code above will print:[teletype]
1029
1030 expected: tag: literal-char, value: o
1031 got: "i"``[c++]``
1032 */
1033 //]
1034 }
1035
1036 // expectd
1037 {
1038 //[reference_using_declarations_expectd
1039 using boost::spirit::ascii::char_;
1040 using boost::spirit::qi::expect;
1041 using boost::spirit::qi::expectation_failure;
1042 //]
1043
1044 //[reference_expectd
1045 /*`The code below uses an expectation operator to throw an __qi_expectation_failure__
1046 with a deliberate parsing error when `"o"` is expected and `"x"` is what is
1047 found in the input. The `catch` block prints the information related to the
1048 error. Note: This is low level code that demonstrates the /bare-metal/. Typically,
1049 you use an __qi_error_handler__ to deal with the error.
1050 */
1051 try
1052 {
1053 test_parser(input: "xi", p: expect[char_('o')]); // should throw an exception
1054 }
1055 catch (expectation_failure<char const*> const& x)
1056 {
1057 std::cout << "expected: "; print_info(what: x.what_);
1058 std::cout << "got: \"" << std::string(x.first, x.last) << '"' << std::endl;
1059 }
1060 /*`The code above will print:[teletype]
1061
1062 expected: tag: literal-char, value: o
1063 got: "x"``[c++]``
1064 */
1065 //]
1066 }
1067
1068 // and-predicate
1069 {
1070 //[reference_and_predicate
1071 //`Some using declarations:
1072 using boost::spirit::lit;
1073
1074 /*`Basic look-ahead example: make sure that the last character is a
1075 semicolon, but don't consume it, just peek at the next character:
1076 */
1077 test_phrase_parser(input: "Hello ;", p: lit("Hello") >> &lit(';'), full_match: false);
1078 //]
1079 }
1080
1081 // not-predicate
1082 {
1083 //[reference_not_predicate
1084 //`Some using declarations:
1085 using boost::spirit::ascii::char_;
1086 using boost::spirit::ascii::alpha;
1087 using boost::spirit::qi::lit;
1088 using boost::spirit::qi::symbols;
1089
1090 /*`Here's an alternative to the `*(r - x) >> x` idiom using the
1091 not-predicate instead. This parses a list of characters terminated
1092 by a ';':
1093 */
1094 test_parser(input: "abcdef;", p: *(!lit(';') >> char_) >> ';');
1095
1096 /*`The following parser ensures that we match distinct keywords
1097 (stored in a symbol table). To do this, we make sure that the
1098 keyword does not follow an alpha or an underscore:
1099 */
1100 symbols<char, int> keywords;
1101 keywords = "begin", "end", "for";
1102
1103 // This should fail:
1104 test_parser(input: "beginner", p: keywords >> !(alpha | '_'));
1105
1106 // This is ok:
1107 test_parser(input: "end ", p: keywords >> !(alpha | '_'), full_match: false);
1108
1109 // This is ok:
1110 test_parser(input: "for()", p: keywords >> !(alpha | '_'), full_match: false);
1111 //]
1112 }
1113
1114 // difference
1115 {
1116 //[reference_difference
1117 //`Some using declarations:
1118 using boost::spirit::ascii::char_;
1119
1120 /*`Parse a C/C++ style comment:
1121 */
1122 test_parser(input: "/*A Comment*/", p: "/*" >> *(char_ - "*/") >> "*/");
1123 //]
1124 }
1125
1126 // kleene
1127 {
1128 //[reference_kleene
1129 //`Some using declarations:
1130 using boost::spirit::qi::int_;
1131
1132 /*`Parse a comma separated list of numbers and put them in a vector:
1133 */
1134 std::vector<int> attr;
1135 test_phrase_parser_attr(
1136 input: "111, 222, 333, 444, 555", p: int_ >> *(',' >> int_), attr);
1137 std::cout
1138 << attr[0] << ',' << attr[1] << ',' << attr[2] << ','
1139 << attr[3] << ',' << attr[4]
1140 << std::endl;
1141 //]
1142 }
1143
1144 // plus
1145 {
1146 //[reference_plus
1147 //`Some using declarations:
1148 using boost::spirit::ascii::alpha;
1149 using boost::spirit::qi::lexeme;
1150
1151 /*`Parse one or more strings containing one or more alphabetic
1152 characters and put them in a vector:
1153 */
1154 std::vector<std::string> attr;
1155 test_phrase_parser_attr(input: "yaba daba doo", p: +lexeme[+alpha], attr);
1156 std::cout << attr[0] << ',' << attr[1] << ',' << attr[2] << std::endl;
1157 //]
1158 }
1159
1160 // optional
1161 {
1162 //[reference_optional
1163 //`Some using declarations:
1164 using boost::spirit::ascii::char_;
1165 using boost::spirit::qi::lexeme;
1166 using boost::spirit::qi::int_;
1167 using boost::fusion::vector;
1168 using boost::fusion::at_c;
1169 using boost::optional;
1170
1171 /*`Parse a person info with name (in quotes) optional age [footnote
1172 James Bond is shy about his age :-)] and optional sex, all
1173 separated by comma.
1174 */
1175 vector<std::string, optional<int>, optional<char> > attr;
1176
1177 test_phrase_parser_attr(
1178 input: "\"James Bond\", M"
1179 , p: lexeme['"' >> +(char_ - '"') >> '"'] // name
1180 >> -(',' >> int_) // optional age
1181 >> -(',' >> char_) // optional sex
1182 , attr);
1183
1184 // Should print: James Bond,M
1185 std::cout << at_c<0>(seq&: attr); // print name
1186 if (at_c<1>(seq&: attr)) // print optional age
1187 std::cout << ',' << *at_c<1>(seq&: attr);
1188 if (at_c<2>(seq&: attr)) // print optional sex
1189 std::cout << ',' << *at_c<2>(seq&: attr);
1190 std::cout << std::endl;
1191 //]
1192 }
1193
1194 // list
1195 {
1196 //[reference_list
1197 //`Some using declarations:
1198 using boost::spirit::qi::int_;
1199
1200 /*`Parse a comma separated list of numbers and put them in a vector:
1201 */
1202 std::vector<int> attr;
1203 test_phrase_parser_attr(
1204 input: "111, 222, 333, 444, 555", p: int_ % ',', attr);
1205 std::cout
1206 << attr[0] << ',' << attr[1] << ',' << attr[2] << ','
1207 << attr[3] << ',' << attr[4]
1208 << std::endl;
1209 //]
1210 }
1211
1212 // stream
1213 {
1214 //[reference_qi_stream
1215 //`Using declarations and variables:
1216 using boost::spirit::qi::stream;
1217 using boost::spirit::qi::stream_parser;
1218
1219 /*`Parse a simple string using the operator>>(istream&, std::string&);
1220 */
1221 std::string str;
1222 test_parser_attr(input: "abc", p: stream, attr&: str);
1223 std::cout << str << std::endl; // prints: abc
1224
1225 /*`Parse our complex type using the operator>>(istream&, complex&);
1226 */
1227 complex c;
1228 test_parser_attr(input: "{1.0,2.5}", p: stream_parser<char, complex>(), attr&: c);
1229 std::cout << c.a << "," << c.b << std::endl; // prints: 1.0,2.5
1230 //]
1231 }
1232
1233 ///////////////////////////////////////////////////////////////////////////
1234 // auto module
1235 {
1236 //[reference_qi_using_declarations_auto
1237 using boost::spirit::qi::auto_;
1238 //]
1239
1240 //[reference_qi_auto
1241 /*`Parse a simple integer using the generated parser component `int_`:
1242 */
1243 int i = 0;
1244 test_parser_attr(input: "123", p: auto_, attr&: i);
1245 std::cout << i << std::endl; // prints: 123
1246
1247 /*`Parse an instance of the `complex` data type as defined above using
1248 the parser as generated by the defined customization point:
1249 */
1250 complex c;
1251 test_parser_attr(input: "{1.2,2.4}", p: auto_, attr&: c);
1252 std::cout << c.a << "," << c.b << std::endl; // prints: 1.2,2.4
1253 //]
1254 }
1255
1256 // native binary
1257 {
1258 //[reference_qi_native_binary
1259 //`Using declarations and variables:
1260 using boost::spirit::qi::byte_;
1261 using boost::spirit::qi::word;
1262 using boost::spirit::qi::dword;
1263 using boost::spirit::qi::qword;
1264
1265 boost::uint8_t uc;
1266 boost::uint16_t us;
1267 boost::uint32_t ui;
1268//<-
1269#ifdef BOOST_HAS_LONG_LONG
1270//->
1271 boost::uint64_t ul;
1272//<-
1273#endif
1274
1275#if BOOST_ENDIAN_LITTLE_BYTE
1276//->
1277 //`Basic usage of the native binary parsers for little endian platforms:
1278 test_parser_attr(input: "\x01", p: byte_, attr&: uc); assert(uc == 0x01);
1279 test_parser_attr(input: "\x01\x02", p: word, attr&: us); assert(us == 0x0201);
1280 test_parser_attr(input: "\x01\x02\x03\x04", p: dword, attr&: ui); assert(ui == 0x04030201);
1281//<-
1282#ifdef BOOST_HAS_LONG_LONG
1283//->
1284 test_parser_attr(input: "\x01\x02\x03\x04\x05\x06\x07\x08", p: qword, attr&: ul);
1285 assert(ul == 0x0807060504030201LL);
1286
1287//<-
1288#endif
1289//->
1290 test_parser(input: "\x01", p: byte_(0x01));
1291 test_parser(input: "\x01\x02", p: word(0x0201));
1292 test_parser(input: "\x01\x02\x03\x04", p: dword(0x04030201));
1293//<-
1294#ifdef BOOST_HAS_LONG_LONG
1295//->
1296 test_parser(input: "\x01\x02\x03\x04\x05\x06\x07\x08",
1297 p: qword(0x0807060504030201LL));
1298//<-
1299#endif
1300#else
1301//->
1302 //`Basic usage of the native binary parsers for big endian platforms:
1303 test_parser_attr("\x01", byte_, uc); assert(uc == 0x01);
1304 test_parser_attr("\x01\x02", word, us); assert(us == 0x0102);
1305 test_parser_attr("\x01\x02\x03\x04", dword, ui); assert(ui == 0x01020304);
1306//<-
1307#ifdef BOOST_HAS_LONG_LONG
1308//->
1309 test_parser_attr("\x01\x02\x03\x04\x05\x06\x07\x08", qword, ul);
1310 assert(0x0102030405060708LL);
1311
1312//<-
1313#endif
1314//->
1315 test_parser("\x01", byte_(0x01));
1316 test_parser("\x01\x02", word(0x0102));
1317 test_parser("\x01\x02\x03\x04", dword(0x01020304));
1318//<-
1319#ifdef BOOST_HAS_LONG_LONG
1320//->
1321 test_parser("\x01\x02\x03\x04\x05\x06\x07\x08",
1322 qword(0x0102030405060708LL));
1323//<-
1324#endif
1325#endif
1326//->
1327 //]
1328 }
1329
1330 // little binary
1331 {
1332 //[reference_qi_little_binary
1333 //`Using declarations and variables:
1334 using boost::spirit::qi::little_word;
1335 using boost::spirit::qi::little_dword;
1336 using boost::spirit::qi::little_qword;
1337
1338 boost::uint16_t us;
1339 boost::uint32_t ui;
1340//<-
1341#ifdef BOOST_HAS_LONG_LONG
1342//->
1343 boost::uint64_t ul;
1344//<-
1345#endif
1346
1347//->
1348 //`Basic usage of the little endian binary parsers:
1349 test_parser_attr(input: "\x01\x02", p: little_word, attr&: us); assert(us == 0x0201);
1350 test_parser_attr(input: "\x01\x02\x03\x04", p: little_dword, attr&: ui); assert(ui == 0x04030201);
1351//<-
1352#ifdef BOOST_HAS_LONG_LONG
1353//->
1354 test_parser_attr(input: "\x01\x02\x03\x04\x05\x06\x07\x08", p: little_qword, attr&: ul);
1355 assert(ul == 0x0807060504030201LL);
1356
1357//<-
1358#endif
1359//->
1360 test_parser(input: "\x01\x02", p: little_word(0x0201));
1361 test_parser(input: "\x01\x02\x03\x04", p: little_dword(0x04030201));
1362//<-
1363#ifdef BOOST_HAS_LONG_LONG
1364//->
1365 test_parser(input: "\x01\x02\x03\x04\x05\x06\x07\x08",
1366 p: little_qword(0x0807060504030201LL));
1367//<-
1368#endif
1369//->
1370 //]
1371 }
1372
1373 // big binary
1374 {
1375 //[reference_qi_big_binary
1376 //`Using declarations and variables:
1377 using boost::spirit::qi::big_word;
1378 using boost::spirit::qi::big_dword;
1379 using boost::spirit::qi::big_qword;
1380
1381 boost::uint16_t us;
1382 boost::uint32_t ui;
1383//<-
1384#ifdef BOOST_HAS_LONG_LONG
1385//->
1386 boost::uint64_t ul;
1387//<-
1388#endif
1389
1390//->
1391 //`Basic usage of the big endian binary parsers:
1392 test_parser_attr(input: "\x01\x02", p: big_word, attr&: us); assert(us == 0x0102);
1393 test_parser_attr(input: "\x01\x02\x03\x04", p: big_dword, attr&: ui); assert(ui == 0x01020304);
1394//<-
1395#ifdef BOOST_HAS_LONG_LONG
1396//->
1397 test_parser_attr(input: "\x01\x02\x03\x04\x05\x06\x07\x08", p: big_qword, attr&: ul);
1398 assert(0x0102030405060708LL);
1399
1400//<-
1401#endif
1402//->
1403 test_parser(input: "\x01\x02", p: big_word(0x0102));
1404 test_parser(input: "\x01\x02\x03\x04", p: big_dword(0x01020304));
1405//<-
1406#ifdef BOOST_HAS_LONG_LONG
1407//->
1408 test_parser(input: "\x01\x02\x03\x04\x05\x06\x07\x08",
1409 p: big_qword(0x0102030405060708LL));
1410//<-
1411#endif
1412//->
1413 //]
1414 }
1415
1416 // rule
1417 {
1418 //[reference_rule
1419 //`Some using declarations:
1420 using boost::spirit::qi::rule;
1421 using boost::spirit::qi::int_;
1422 using boost::spirit::qi::locals;
1423 using boost::spirit::qi::_1;
1424 using boost::spirit::qi::_a;
1425 using boost::spirit::ascii::alpha;
1426 using boost::spirit::ascii::char_;
1427 using boost::spirit::ascii::space_type;
1428
1429 /*`Basic rule:
1430 */
1431 rule<char const*> r;
1432 r = int_;
1433 test_parser(input: "123", p: r);
1434
1435 /*`Rule with synthesized attribute:
1436 */
1437 rule<char const*, int()> ra;
1438 ra = int_;
1439 int i;
1440 test_parser_attr(input: "123", p: ra, attr&: i);
1441 assert(i == 123);
1442
1443 /*`Rule with skipper and synthesized attribute:
1444 */
1445 rule<char const*, std::vector<int>(), space_type> rs;
1446 rs = *int_;
1447 std::vector<int> v;
1448 test_phrase_parser_attr(input: "123 456 789", p: rs, attr&: v);
1449 assert(v[0] == 123);
1450 assert(v[1] == 456);
1451 assert(v[2] == 789);
1452
1453 /*`Rule with one local variable:
1454 */
1455 rule<char const*, locals<char> > rl;
1456 rl = alpha[_a = _1] >> char_(_a); // get two identical characters
1457 test_parser(input: "aa", p: rl); // pass
1458 test_parser(input: "ax", p: rl); // fail
1459 //]
1460 }
1461
1462 // grammar
1463 {
1464 using client::num_list;
1465
1466 //[reference_grammar_using
1467 //`Some using declarations:
1468 using boost::spirit::ascii::space_type;
1469 using boost::spirit::int_;
1470 using boost::spirit::qi::grammar;
1471 using boost::spirit::qi::rule;
1472 //]
1473
1474 //[reference_grammar
1475 //`How to use the example grammar:
1476 num_list nlist;
1477 test_phrase_parser(input: "123, 456, 789", p: nlist);
1478 //]
1479 }
1480
1481 return 0;
1482}
1483

source code of boost/libs/spirit/example/qi/reference.cpp