1 //  Copyright (c) 2001-2010 Hartmut Kaiser
2 //
3 //  Distributed under the Boost Software License, Version 1.0. (See accompanying
4 //  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5 
6 // The purpose of this example is to demonstrate how custom, user defined types
7 // can be easily integrated with the lexer as token value types. Moreover, the
8 // custom token values are properly exposed to the parser as well, allowing to
9 // retrieve the custom values using the built in parser attribute propagation
10 // rules.
11 
12 #include <boost/spirit/include/lex_lexertl.hpp>
13 #include <boost/spirit/include/qi.hpp>
14 
15 namespace lex = boost::spirit::lex;
16 namespace qi = boost::spirit::qi;
17 namespace mpl = boost::mpl;
18 
19 ///////////////////////////////////////////////////////////////////////////////
20 // This is just a simple custom rational data structure holding two ints to be
21 // interpreted as a rational number
22 struct rational
23 {
rationalrational24     rational(int n = 0, int d = 0)
25       : nominator_(n), denominator_(d)
26     {}
27 
28     int nominator_;
29     int denominator_;
30 };
31 
32 ///////////////////////////////////////////////////////////////////////////////
33 // A rational is represented as "{n,d}", where 'n' and 'd' are the nominator
34 // and denominator of the number. We use Spirit.Qi to do the low level parsing
35 // of the input sequence as matched by the lexer. Certainly, any other
36 // conversion could be used instead.
37 //
38 // The lexer uses the template assign_to_attribute_from_iterators<> to convert
39 // the matched input sequence (pair of iterators) to the token value type as
40 // specified while defining the lex::token_def<>.
41 //
42 // Our specialization of assign_to_attribute_from_iterators<> for the rational
43 // data type defined above has to be placed into the
44 // namespace boost::spirit::traits, otherwise it won't be found by the library.
45 namespace boost { namespace spirit { namespace traits
46 {
47     template <typename Iterator>
48     struct assign_to_attribute_from_iterators<rational, Iterator>
49     {
50         static void
callboost::spirit::traits::assign_to_attribute_from_iterators51         call(Iterator const& first, Iterator const& last, rational& attr)
52         {
53             int x, y;
54             Iterator b = first;
55             qi::parse(b, last,
56                 '{' >> qi::int_ >> ',' >> qi::int_ >> '}', x, y);
57             attr = rational(x, y);
58         }
59     };
60 }}}
61 
62 ///////////////////////////////////////////////////////////////////////////////
63 // a lexer recognizing a single token type: rational
64 template <typename Lexer>
65 struct lex_rational : lex::lexer<Lexer>
66 {
lex_rationallex_rational67     lex_rational()
68     {
69         this->self.add_pattern("INT", "[1-9][0-9]*");
70 
71         rt = "\\{{INT},{INT}\\}";
72         this->self.add(rt);
73     }
74     lex::token_def<rational> rt;
75 };
76 
77 
main()78 int main()
79 {
80     // the token type needs to know the iterator type of the underlying
81     // input and the set of used token value types
82     typedef lex::lexertl::token<std::string::iterator,
83         mpl::vector<rational> > token_type;
84 
85     // use actor_lexer<> here if your token definitions have semantic
86     // actions
87     typedef lex::lexertl::lexer<token_type> lexer_type;
88 
89     // this is the iterator exposed by the lexer, we use this for parsing
90     typedef lexer_type::iterator_type iterator_type;
91 
92     // create a lexer instance
93     std::string input("{3,4}");
94     std::string::iterator s = input.begin();
95 
96     lex_rational<lexer_type> lex;
97     iterator_type b = lex.begin(s, input.end());
98 
99     // use the embedded token_def as a parser, it exposes its token value type
100     // as its parser attribute type
101     rational r;
102     if (!qi::parse(b, lex.end(), lex.rt, r))
103     {
104         std::cerr << "Parsing failed!" << std::endl;
105         return -1;
106     }
107 
108     std::cout << "Parsing succeeded: {"
109               << r.nominator_ << ", " << r.denominator_ << "}" << std::endl;
110     return 0;
111 }
112 
113