]>
Commit | Line | Data |
---|---|---|
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 | |
26 | template <typename P> | |
27 | void 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 | ||
40 | template <typename P> | |
41 | void 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 | |
57 | template <typename P, typename T> | |
58 | void 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 | ||
71 | template <typename P, typename T> | |
72 | void test_phrase_parser_attr( | |
73 | char const* input, P const& p, T& attr, bool full_match = true) | |
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 | |
88 | struct 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 | ||
104 | void 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 | /////////////////////////////////////////////////////////////////////////////// | |
120 | template <typename T> | |
121 | struct 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 | /////////////////////////////////////////////////////////////////////////////// | |
188 | struct 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 | |
209 | struct 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 | |
222 | std::istream& | |
223 | operator>> (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 | */ | |
239 | BOOST_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 | */ | |
259 | namespace 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 | |
279 | struct int_data | |
280 | { | |
281 | int i; | |
282 | }; | |
283 | ||
284 | ||
285 | // we provide a custom attribute transformation to allow its use as an int | |
286 | namespace 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 | ||
301 | namespace 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 | ||
324 | int | |
325 | main() | |
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 | } |