]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | [/============================================================================== |
2 | Copyright (C) 2001-2011 Hartmut Kaiser | |
3 | Copyright (C) 2001-2011 Joel de Guzman | |
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 | [section:distinct Qi Distinct Parser Directive] | |
10 | ||
11 | [heading Description] | |
12 | ||
13 | The __qi__ `distinct` parser is a directive component allowing to avoid partial | |
14 | matches while parsing using a skipper. A simple example is the common task of | |
15 | matching a C keyword. | |
16 | Consider: | |
17 | ||
18 | "description" >> -lit(":") >> *(char_ - eol) | |
19 | ||
20 | intended to match a line in a configuration file. Let's assume further, that | |
21 | this rule is used with a `space` skipper and that we have the following strings | |
22 | in the input: | |
23 | ||
24 | "description: ident\n" | |
25 | "description ident\n" | |
26 | "descriptionident\n" | |
27 | ||
28 | It might seem unexpected, but the parser above matches all three inputs just | |
29 | fine, even if the third input should not match at all! In order to avoid the | |
30 | unwanted match we are forced to make our rule more complicated: | |
31 | ||
32 | lexeme["description" >> !char_("a-zA-Z_0-9")] >> -lit(":") >> *(char_ - eol) | |
33 | ||
34 | (the rule reads as: match `"description"` as long as it's not /directly/ | |
35 | followed by a valid identifier). | |
36 | ||
37 | The `distinct[]` directive is meant to simplify the rule above: | |
38 | ||
39 | distinct(char_("a-zA-Z_0-9"))["description"] >> -lit(":") >> *(char_ - eol) | |
40 | ||
41 | Using the `distinct[]` component instead of the explicit sequence has the | |
42 | advantage of being able to encapsulate the tail (i.e the `char_("a-zA-Z_0-9")`) | |
43 | as a separate parser construct. The following code snippet illustrates the idea | |
44 | (for the full code of this example please see | |
45 | [@../../test/qi/distinct.cpp distinct.cpp]): | |
46 | ||
47 | [import ../test/qi/distinct.cpp] | |
48 | [qi_distinct_encapsulation] | |
49 | ||
50 | These definitions define a new Qi parser recognizing keywords! This allows to | |
51 | rewrite our declaration parser expression as: | |
52 | ||
53 | keyword["description"] >> -lit(":") >> *(char_ - eol) | |
54 | ||
55 | which is much more readable and concise if compared to the original parser | |
56 | expression. In addition the new `keyword[]` directive has the advantage to be | |
57 | usable for wrapping any parser expression, not only strings as in the example | |
58 | above. | |
59 | ||
60 | [heading Header] | |
61 | ||
62 | // forwards to <boost/spirit/repository/home/qi/directive/distinct.hpp> | |
63 | #include <boost/spirit/repository/include/qi_distinct.hpp> | |
64 | ||
65 | [heading Synopsis] | |
66 | ||
67 | distinct(tail)[subject] | |
68 | ||
69 | [heading Parameters] | |
70 | ||
71 | [table | |
72 | [[Parameter] [Description]] | |
73 | [[`tail`] [The parser construct specifying what whould not | |
74 | follow the subject in order to match the overall | |
75 | expression.]] | |
76 | [[`subject`] [The parser construct to use to match the current | |
77 | input. The distinct directive makes sure that no | |
78 | unexpected partial matches occur.]] | |
79 | ] | |
80 | ||
81 | All two parameters can be arbitrary complex parsers themselves. | |
82 | ||
83 | [heading Attribute] | |
84 | ||
85 | The `distinct` component exposes the attribute type of its subject as its own | |
86 | attribute type. If the `subject` does not expose any attribute (the type is | |
87 | `unused_type`), then the `distinct` does not expose any attribute either. | |
88 | ||
89 | a: A, b: B --> distinct(b)[a]: A | |
90 | ||
91 | [heading Example] | |
92 | ||
93 | The following example shows simple use cases of the `distinct` parser. | |
94 | [@../../example/qi/distinct.cpp distinct.cpp]) | |
95 | ||
96 | [import ../example/qi/distinct.cpp] | |
97 | ||
98 | [heading Prerequisites] | |
99 | ||
100 | In addition to the main header file needed to include the core components | |
101 | implemented in __qi__ we add the header file needed for the new `distinct` | |
102 | generator. | |
103 | ||
104 | [qi_distinct_includes] | |
105 | ||
106 | To make all the code below more readable we introduce the following namespaces. | |
107 | ||
108 | [qi_distinct_namespace] | |
109 | ||
110 | [heading Using The Distinct Directive to Match keywords] | |
111 | ||
112 | We show several examples of how the `distinct[]` directive can be used to force | |
113 | correct behavior while matching keywords. The first two code snippets show | |
114 | the correct matching of the `description` keyword (in this hypothetical example | |
115 | we allow keywords to be directly followed by an optional `"--"`): | |
116 | ||
117 | [qi_distinct_description_ident] | |
118 | [qi_distinct_description__ident] | |
119 | ||
120 | The last example shows that the `distinct[]` parser component correctly refuses | |
121 | to match "description-ident": | |
122 | ||
123 | [qi_distinct_description_ident_error] | |
124 | ||
125 | [endsect] |