1 [/==============================================================================
2 Copyright (C) 2001-2015 Joel de Guzman
3 Copyright (C) 2001-2011 Hartmut Kaiser
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 ===============================================================================/]
9 [section Employee - Parsing into structs]
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:
18 * More about attributes
20 * Some more built-in parsers
23 First, let's create a struct representing an employee:
25 namespace client { namespace ast
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
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:
45 BOOST_FUSION_ADAPT_STRUCT(
46 client::ast::employee,
47 age, surname, forename, salary
50 Now we'll write a parser for our employee. Inputs will be of the form:
52 employee{ age, "surname", "forename", salary }
58 namespace x3 = boost::spirit::x3;
59 namespace ascii = boost::spirit::x3::ascii;
67 x3::rule<class employee, ast::employee> const employee = "employee";
69 auto const quoted_string = lexeme['"' >> +(char_ - '"') >> '"'];
71 auto const employee_def =
75 >> quoted_string >> ','
76 >> quoted_string >> ','
81 BOOST_SPIRIT_DEFINE(employee);
84 The full cpp file for this example can be found here: [@../../../example/x3/employee.cpp]
86 Let's walk through this one step at a time (not necessarily from top to bottom).
88 [heading Rule Declaration]
90 x3::rule<class employee, ast::employee> employee("employee");
94 lexeme['"' >> +(char_ - '"') >> '"'];
96 `lexeme` inhibits space skipping from the open brace to the closing brace.
97 The expression parses quoted strings.
101 parses one or more chars, except the double quote. It stops when it sees
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:
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
132 [heading Sequence Attribute]
134 Now what's the attribute of
136 '"' >> +(char_ - '"') >> '"'
140 Well, typically, the attribute of:
146 fusion::vector<A, B, C>
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.
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.]
155 [heading Attribute Collapsing]
157 Some parsers, especially those very little literal parsers you see, like `'"'`,
158 do not have attributes.
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:
165 fusion::vector<std::vector<char> >
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:
171 '"' >> +(char_ - '"') >> '"'
177 [heading Rule Definition]
183 >> quoted_string >> ','
184 >> quoted_string >> ','
189 BOOST_SPIRIT_DEFINE(employee);
192 Applying our collapsing rules above, the RHS has an attribute of:
194 fusion::vector<int, std::string, std::string, double>
196 These nodes do not have an attribute:
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.]
207 Recall that the attribute of `parser::employee` is the `ast::employee` struct.
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.