]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/spirit/doc/qi/employee.qbk
bump version to 12.2.2-pve1
[ceph.git] / ceph / src / boost / libs / spirit / doc / qi / employee.qbk
1 [/==============================================================================
2 Copyright (C) 2001-2011 Joel de Guzman
3 Copyright (C) 2001-2011 Hartmut Kaiser
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 Employee - Parsing into structs]
10
11 It's a common question in the __spirit_list__: How do I parse and place
12 the results into a C++ struct? Of course, at this point, you already
13 know various ways to do it, using semantic actions. There are many ways
14 to skin a cat. Spirit2, being fully attributed, makes it even easier.
15 The next example demonstrates some features of Spirit2 that make this
16 easy. In the process, you'll learn about:
17
18 * More about attributes
19 * Auto rules
20 * Some more built-in parsers
21 * Directives
22
23 [import ../../example/qi/employee.cpp]
24
25 First, let's create a struct representing an employee:
26
27 [tutorial_employee_struct]
28
29 Then, we need to tell __fusion__ about our employee struct to make it a first-class
30 fusion citizen that the grammar can utilize. If you don't know fusion yet,
31 it is a __boost__ library for working with heterogeneous collections of data,
32 commonly referred to as tuples. Spirit uses fusion extensively as part of its
33 infrastructure.
34
35 In fusion's view, a struct is just a form of a tuple. You can adapt any struct
36 to be a fully conforming fusion tuple:
37
38 [tutorial_employee_adapt_struct]
39
40 Now we'll write a parser for our employee. Inputs will be of the form:
41
42 employee{ age, "surname", "forename", salary }
43
44 Here goes:
45
46 [tutorial_employee_parser]
47
48 The full cpp file for this example can be found here: [@../../example/qi/employee.cpp]
49
50 Let's walk through this one step at a time (not necessarily from top to bottom).
51
52 template <typename Iterator>
53 struct employee_parser : grammar<Iterator, employee(), space_type>
54
55 `employee_parser` is a grammar. Like before, we make it a template so that we can
56 reuse it for different iterator types. The grammar's signature is:
57
58 employee()
59
60 meaning, the parser generates employee structs. `employee_parser` skips white
61 spaces using `space_type` as its skip parser.
62
63 employee_parser() : employee_parser::base_type(start)
64
65 Initializes the base class.
66
67 rule<Iterator, std::string(), space_type> quoted_string;
68 rule<Iterator, employee(), space_type> start;
69
70 Declares two rules: `quoted_string` and `start`. `start` has the same template
71 parameters as the grammar itself. `quoted_string` has a `std::string` attribute.
72
73 [heading Lexeme]
74
75 lexeme['"' >> +(char_ - '"') >> '"'];
76
77 `lexeme` inhibits space skipping from the open brace to the closing brace.
78 The expression parses quoted strings.
79
80 +(char_ - '"')
81
82 parses one or more chars, except the double quote. It stops when it sees
83 a double quote.
84
85 [heading Difference]
86
87 The expression:
88
89 a - b
90
91 parses `a` but not `b`. Its attribute is just `A`; the attribute of `a`. `b`'s
92 attribute is ignored. Hence, the attribute of:
93
94 char_ - '"'
95
96 is just `char`.
97
98 [heading Plus]
99
100 +a
101
102 is similar to Kleene star. Rather than match everything, `+a` matches one or more.
103 Like it's related function, the Kleene star, its attribute is a `std::vector<A>`
104 where `A` is the attribute of `a`. So, putting all these together, the attribute
105 of
106
107 +(char_ - '"')
108
109 is then:
110
111 std::vector<char>
112
113 [heading Sequence Attribute]
114
115 Now what's the attribute of
116
117 '"' >> +(char_ - '"') >> '"'
118
119 ?
120
121 Well, typically, the attribute of:
122
123 a >> b >> c
124
125 is:
126
127 fusion::vector<A, B, C>
128
129 where `A` is the attribute of `a`, `B` is the attribute of `b` and `C` is the
130 attribute of `c`. What is `fusion::vector`? - a tuple.
131
132 [note If you don't know what I am talking about, see: [@http://tinyurl.com/6xun4j
133 Fusion Vector]. It might be a good idea to have a look into __fusion__ at this
134 point. You'll definitely see more of it in the coming pages.]
135
136 [heading Attribute Collapsing]
137
138 Some parsers, especially those very little literal parsers you see, like `'"'`,
139 do not have attributes.
140
141 Nodes without attributes are disregarded. In a sequence, like above, all nodes
142 with no attributes are filtered out of the `fusion::vector`. So, since `'"'` has
143 no attribute, and `+(char_ - '"')` has a `std::vector<char>` attribute, the
144 whole expression's attribute should have been:
145
146 fusion::vector<std::vector<char> >
147
148 But wait, there's one more collapsing rule: If the attribute is followed by a
149 single element `fusion::vector`, The element is stripped naked from its container.
150 To make a long story short, the attribute of the expression:
151
152 '"' >> +(char_ - '"') >> '"'
153
154 is:
155
156 std::vector<char>
157
158 [heading Auto Rules]
159
160 It is typical to see rules like:
161
162 r = p[_val = _1];
163
164 If you have a rule definition such as the above, where the attribute of the RHS
165 (right hand side) of the rule is compatible with the attribute of the LHS (left
166 hand side), then you can rewrite it as:
167
168 r %= p;
169
170 The attribute of `p` automatically uses the attribute of `r`.
171
172 So, going back to our `quoted_string` rule:
173
174 quoted_string %= lexeme['"' >> +(char_ - '"') >> '"'];
175
176 is a simplified version of:
177
178 quoted_string = lexeme['"' >> +(char_ - '"') >> '"'][_val = _1];
179
180 The attribute of the `quoted_string` rule: `std::string` *is compatible* with
181 the attribute of the RHS: `std::vector<char>`. The RHS extracts the parsed
182 attribute directly into the rule's attribute, in-situ.
183
184 [note `r %= p` and `r = p` are equivalent if there are no semantic actions
185 associated with `p`. ]
186
187
188 [heading Finally]
189
190 We're down to one rule, the start rule:
191
192 start %=
193 lit("employee")
194 >> '{'
195 >> int_ >> ','
196 >> quoted_string >> ','
197 >> quoted_string >> ','
198 >> double_
199 >> '}'
200 ;
201
202 Applying our collapsing rules above, the RHS has an attribute of:
203
204 fusion::vector<int, std::string, std::string, double>
205
206 These nodes do not have an attribute:
207
208 * `lit("employee")`
209 * `'{'`
210 * `','`
211 * `'}'`
212
213 [note In case you are wondering, `lit("employee")` is the same as "employee". We
214 had to wrap it inside `lit` because immediately after it is `>> '{'`. You can't
215 right-shift a `char[]` and a `char` - you know, C++ syntax rules.]
216
217 Recall that the attribute of `start` is the `employee` struct:
218
219 [tutorial_employee_struct]
220
221 Now everything is clear, right? The `struct employee` *IS* compatible with
222 `fusion::vector<int, std::string, std::string, double>`. So, the RHS of `start`
223 uses start's attribute (a `struct employee`) in-situ when it does its work.
224
225 [endsect]