1 // Copyright (c) 2001-2011 Hartmut Kaiser
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)
6 #include <boost/spirit/include/lex_lexertl.hpp>
7 #include <boost/spirit/include/lex_lexertl_position_token.hpp>
9 #include <boost/core/lightweight_test.hpp>
10 #include <boost/phoenix/object.hpp>
11 #include <boost/phoenix/operator.hpp>
12 #include <boost/phoenix/stl/container.hpp>
13 #include <boost/spirit/include/qi_numeric.hpp>
15 namespace spirit
= boost::spirit
;
16 namespace lex
= boost::spirit::lex
;
17 namespace phoenix
= boost::phoenix
;
18 namespace mpl
= boost::mpl
;
20 ///////////////////////////////////////////////////////////////////////////////
27 template <typename Lexer
>
28 struct token_definitions
: lex::lexer
<Lexer
>
32 this->self
.add_pattern("HEXDIGIT", "[0-9a-fA-F]");
33 this->self
.add_pattern("OCTALDIGIT", "[0-7]");
34 this->self
.add_pattern("DIGIT", "[0-9]");
36 this->self
.add_pattern("OPTSIGN", "[-+]?");
37 this->self
.add_pattern("EXPSTART", "[eE][-+]");
38 this->self
.add_pattern("EXPONENT", "[eE]{OPTSIGN}{DIGIT}+");
40 // define tokens and associate them with the lexer
41 int_
= "{OPTSIGN}[1-9]{DIGIT}*";
44 double_
= "{OPTSIGN}({DIGIT}*\\.{DIGIT}+|{DIGIT}+\\.){EXPONENT}?|{DIGIT}+{EXPONENT}";
45 double_
.id(ID_DOUBLE
);
47 whitespace
= "[ \t\n]+";
52 | whitespace
[ lex::_pass
= lex::pass_flags::pass_ignore
]
56 lex::token_def
<double> int_
;
57 lex::token_def
<double> double_
;
58 lex::token_def
<lex::omit
> whitespace
;
61 template <typename Lexer
>
62 struct token_definitions_with_state
: lex::lexer
<Lexer
>
64 token_definitions_with_state()
66 this->self
.add_pattern("HEXDIGIT", "[0-9a-fA-F]");
67 this->self
.add_pattern("OCTALDIGIT", "[0-7]");
68 this->self
.add_pattern("DIGIT", "[0-9]");
70 this->self
.add_pattern("OPTSIGN", "[-+]?");
71 this->self
.add_pattern("EXPSTART", "[eE][-+]");
72 this->self
.add_pattern("EXPONENT", "[eE]{OPTSIGN}{DIGIT}+");
74 this->self
.add_state();
75 this->self
.add_state("INT");
76 this->self
.add_state("DOUBLE");
78 // define tokens and associate them with the lexer
79 int_
= "{OPTSIGN}[1-9]{DIGIT}*";
82 double_
= "{OPTSIGN}({DIGIT}*\\.{DIGIT}+|{DIGIT}+\\.){EXPONENT}?|{DIGIT}+{EXPONENT}";
83 double_
.id(ID_DOUBLE
);
85 whitespace
= "[ \t\n]+";
88 double_
[ lex::_state
= "DOUBLE"]
89 | int_
[ lex::_state
= "INT" ]
90 | whitespace
[ lex::_pass
= lex::pass_flags::pass_ignore
]
94 lex::token_def
<double> int_
;
95 lex::token_def
<double> double_
;
96 lex::token_def
<lex::omit
> whitespace
;
99 ///////////////////////////////////////////////////////////////////////////////
100 template <typename Token
>
102 test_token_ids(int const* ids
, std::vector
<Token
> const& tokens
)
104 for (std::size_t i
= 0, len
= tokens
.size(); i
< len
; ++i
)
107 return false; // reached end of expected data
109 if (tokens
[i
].id() != static_cast<std::size_t>(*ids
)) // token id must match
115 return (*ids
== -1) ? true : false;
118 ///////////////////////////////////////////////////////////////////////////////
119 template <typename Token
>
121 test_token_states(std::size_t const* states
, std::vector
<Token
> const& tokens
)
123 for (std::size_t i
= 0, len
= tokens
.size(); i
< len
; ++i
)
125 if (*states
== std::size_t(-1))
126 return false; // reached end of expected data
128 if (tokens
[i
].state() != *states
) // token state must match
134 return (*states
== std::size_t(-1)) ? true : false;
137 ///////////////////////////////////////////////////////////////////////////////
140 std::size_t begin
, end
;
143 template <typename Iterator
, typename Token
>
145 test_token_positions(Iterator begin
, position_type
const* positions
,
146 std::vector
<Token
> const& tokens
)
148 for (std::size_t i
= 0, len
= tokens
.size(); i
< len
; ++i
)
150 if (positions
->begin
== std::size_t(-1) &&
151 positions
->end
== std::size_t(-1))
153 return false; // reached end of expected data
156 boost::iterator_range
<Iterator
> matched
= tokens
[i
].matched();
157 std::size_t start
= std::distance(begin
, matched
.begin());
158 std::size_t end
= std::distance(begin
, matched
.end());
160 // position must match
161 if (start
!= positions
->begin
|| end
!= positions
->end
)
167 return (positions
->begin
== std::size_t(-1) &&
168 positions
->end
== std::size_t(-1)) ? true : false;
171 ///////////////////////////////////////////////////////////////////////////////
172 template <typename Token
>
174 test_token_values(double const* values
, std::vector
<Token
> const& tokens
)
176 for (std::size_t i
= 0, len
= tokens
.size(); i
< len
; ++i
)
179 return false; // reached end of expected data
182 spirit::traits::assign_to(tokens
[i
], val
);
183 if (val
!= *values
) // token value must match
189 return (*values
== 0.0) ? true : false;
192 ///////////////////////////////////////////////////////////////////////////////
195 typedef std::string::iterator base_iterator_type
;
196 std::string
input(" 1 1.2 -2 3 2.3e6 -3.4");
197 int ids
[] = { ID_INT
, ID_DOUBLE
, ID_INT
, ID_INT
, ID_DOUBLE
, ID_DOUBLE
, -1 };
198 std::size_t states
[] = { 0, 1, 2, 1, 1, 2, std::size_t(-1) };
199 position_type positions
[] =
201 { 2, 3 }, { 4, 7 }, { 8, 10 }, { 13, 14 }, { 15, 20 }, { 21, 25 },
202 { std::size_t(-1), std::size_t(-1) }
204 double values
[] = { 1.0, 1.2, -2.0, 3.0, 2.3e6
, -3.4, 0.0 };
206 // token type: token id, iterator_pair as token value, no state
208 typedef lex::lexertl::token
<
209 base_iterator_type
, mpl::vector
<double>, mpl::false_
> token_type
;
210 typedef lex::lexertl::actor_lexer
<token_type
> lexer_type
;
212 token_definitions
<lexer_type
> lexer
;
213 std::vector
<token_type
> tokens
;
214 base_iterator_type first
= input
.begin();
216 using phoenix::arg_names::_1
;
217 BOOST_TEST(lex::tokenize(first
, input
.end(), lexer
218 , phoenix::push_back(phoenix::ref(tokens
), _1
)));
220 BOOST_TEST(test_token_ids(ids
, tokens
));
221 BOOST_TEST(test_token_values(values
, tokens
));
225 typedef lex::lexertl::position_token
<
226 base_iterator_type
, mpl::vector
<double>, mpl::false_
> token_type
;
227 typedef lex::lexertl::actor_lexer
<token_type
> lexer_type
;
229 token_definitions
<lexer_type
> lexer
;
230 std::vector
<token_type
> tokens
;
231 base_iterator_type first
= input
.begin();
233 using phoenix::arg_names::_1
;
234 BOOST_TEST(lex::tokenize(first
, input
.end(), lexer
235 , phoenix::push_back(phoenix::ref(tokens
), _1
)));
237 BOOST_TEST(test_token_ids(ids
, tokens
));
238 BOOST_TEST(test_token_positions(input
.begin(), positions
, tokens
));
239 BOOST_TEST(test_token_values(values
, tokens
));
242 // token type: holds token id, state, iterator_pair as token value
244 typedef lex::lexertl::token
<
245 base_iterator_type
, mpl::vector
<double>, mpl::true_
> token_type
;
246 typedef lex::lexertl::actor_lexer
<token_type
> lexer_type
;
248 token_definitions_with_state
<lexer_type
> lexer
;
249 std::vector
<token_type
> tokens
;
250 base_iterator_type first
= input
.begin();
252 using phoenix::arg_names::_1
;
253 BOOST_TEST(lex::tokenize(first
, input
.end(), lexer
254 , phoenix::push_back(phoenix::ref(tokens
), _1
)));
256 BOOST_TEST(test_token_ids(ids
, tokens
));
257 BOOST_TEST(test_token_states(states
, tokens
));
258 BOOST_TEST(test_token_values(values
, tokens
));
262 typedef lex::lexertl::position_token
<
263 base_iterator_type
, mpl::vector
<double>, mpl::true_
> token_type
;
264 typedef lex::lexertl::actor_lexer
<token_type
> lexer_type
;
266 token_definitions_with_state
<lexer_type
> lexer
;
267 std::vector
<token_type
> tokens
;
268 base_iterator_type first
= input
.begin();
270 using phoenix::arg_names::_1
;
271 BOOST_TEST(lex::tokenize(first
, input
.end(), lexer
272 , phoenix::push_back(phoenix::ref(tokens
), _1
)));
274 BOOST_TEST(test_token_ids(ids
, tokens
));
275 BOOST_TEST(test_token_states(states
, tokens
));
276 BOOST_TEST(test_token_positions(input
.begin(), positions
, tokens
));
277 BOOST_TEST(test_token_values(values
, tokens
));
280 return boost::report_errors();