]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/spirit/doc/x3/tutorial/employee.qbk
bump version to 12.2.2-pve1
[ceph.git] / ceph / src / boost / libs / spirit / doc / x3 / tutorial / employee.qbk
1 [/==============================================================================
2 Copyright (C) 2001-2015 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. Spirit X3, being fully attributed, makes it even easier.
15 The next example demonstrates some features of Spirit X3 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 First, let's create a struct representing an employee:
24
25 namespace client { namespace ast
26 {
27 struct employee
28 {
29 int age;
30 std::string surname;
31 std::string forename;
32 double salary;
33 };
34 }}
35
36 Then, we need to tell __fusion__ about our employee struct to make it a first-class
37 fusion citizen that the grammar can utilize. If you don't know fusion yet,
38 it is a __boost__ library for working with heterogeneous collections of data,
39 commonly referred to as tuples. Spirit uses fusion extensively as part of its
40 infrastructure.
41
42 In fusion's view, a struct is just a form of a tuple. You can adapt any struct
43 to be a fully conforming fusion tuple:
44
45 BOOST_FUSION_ADAPT_STRUCT(
46 client::ast::employee,
47 age, surname, forename, salary
48 )
49
50 Now we'll write a parser for our employee. Inputs will be of the form:
51
52 employee{ age, "surname", "forename", salary }
53
54 Here goes:
55
56 namespace parser
57 {
58 namespace x3 = boost::spirit::x3;
59 namespace ascii = boost::spirit::x3::ascii;
60
61 using x3::int_;
62 using x3::lit;
63 using x3::double_;
64 using x3::lexeme;
65 using ascii::char_;
66
67 x3::rule<class employee, ast::employee> const employee = "employee";
68
69 auto const quoted_string = lexeme['"' >> +(char_ - '"') >> '"'];
70
71 auto const employee_def =
72 lit("employee")
73 >> '{'
74 >> int_ >> ','
75 >> quoted_string >> ','
76 >> quoted_string >> ','
77 >> double_
78 >> '}'
79 ;
80
81 BOOST_SPIRIT_DEFINE(employee);
82 }
83
84 The full cpp file for this example can be found here: [@../../../example/x3/employee.cpp]
85
86 Let's walk through this one step at a time (not necessarily from top to bottom).
87
88 [heading Rule Declaration]
89
90 x3::rule<class employee, ast::employee> employee("employee");
91
92 [heading Lexeme]
93
94 lexeme['"' >> +(char_ - '"') >> '"'];
95
96 `lexeme` inhibits space skipping from the open brace to the closing brace.
97 The expression parses quoted strings.
98
99 +(char_ - '"')
100
101 parses one or more chars, except the double quote. It stops when it sees
102 a double quote.
103
104 [heading Difference]
105
106 The expression:
107
108 a - b
109
110 parses `a` but not `b`. Its attribute is just `A`; the attribute of `a`. `b`'s
111 attribute is ignored. Hence, the attribute of:
112
113 char_ - '"'
114
115 is just `char`.
116
117 [heading Plus]
118
119 +a
120
121 is similar to Kleene star. Rather than match everything, `+a` matches one or more.
122 Like it's related function, the Kleene star, its attribute is a `std::vector<A>`
123 where `A` is the attribute of `a`. So, putting all these together, the attribute
124 of
125
126 +(char_ - '"')
127
128 is then:
129
130 std::vector<char>
131
132 [heading Sequence Attribute]
133
134 Now what's the attribute of
135
136 '"' >> +(char_ - '"') >> '"'
137
138 ?
139
140 Well, typically, the attribute of:
141
142 a >> b >> c
143
144 is:
145
146 fusion::vector<A, B, C>
147
148 where `A` is the attribute of `a`, `B` is the attribute of `b` and `C` is the
149 attribute of `c`. What is `fusion::vector`? - a tuple.
150
151 [note If you don't know what I am talking about, see: [@http://tinyurl.com/6xun4j
152 Fusion Vector]. It might be a good idea to have a look into __fusion__ at this
153 point. You'll definitely see more of it in the coming pages.]
154
155 [heading Attribute Collapsing]
156
157 Some parsers, especially those very little literal parsers you see, like `'"'`,
158 do not have attributes.
159
160 Nodes without attributes are disregarded. In a sequence, like above, all nodes
161 with no attributes are filtered out of the `fusion::vector`. So, since `'"'` has
162 no attribute, and `+(char_ - '"')` has a `std::vector<char>` attribute, the
163 whole expression's attribute should have been:
164
165 fusion::vector<std::vector<char> >
166
167 But wait, there's one more collapsing rule: If the attribute is followed by a
168 single element `fusion::vector`, The element is stripped naked from its container.
169 To make a long story short, the attribute of the expression:
170
171 '"' >> +(char_ - '"') >> '"'
172
173 is:
174
175 std::vector<char>
176
177 [heading Rule Definition]
178
179 employee =
180 lit("employee")
181 >> '{'
182 >> int_ >> ','
183 >> quoted_string >> ','
184 >> quoted_string >> ','
185 >> double_
186 >> '}'
187 ;
188
189 BOOST_SPIRIT_DEFINE(employee);
190
191
192 Applying our collapsing rules above, the RHS has an attribute of:
193
194 fusion::vector<int, std::string, std::string, double>
195
196 These nodes do not have an attribute:
197
198 * `lit("employee")`
199 * `'{'`
200 * `','`
201 * `'}'`
202
203 [note In case you are wondering, `lit("employee")` is the same as "employee". We
204 had to wrap it inside `lit` because immediately after it is `>> '{'`. You can't
205 right-shift a `char[]` and a `char` - you know, C++ syntax rules.]
206
207 Recall that the attribute of `parser::employee` is the `ast::employee` struct.
208
209 Now everything is clear, right? The `struct employee` *IS* compatible with
210 `fusion::vector<int, std::string, std::string, double>`. So, the RHS of `start`
211 uses start's attribute (a `struct employee`) in-situ when it does its work.
212
213 [endsect]