-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathqi_token.hpp
197 lines (162 loc) · 6 KB
/
qi_token.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
// Support for Spirit V2 (Qi) parsing with Wave tokens
// Copyright (c) 2021 Jeffrey Trull
// Copyright (c) 2001-2012 Hartmut Kaiser
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/spirit/include/lex_plain_token.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/wave/cpplexer/cpp_lex_iterator.hpp>
#include <boost/wave/token_ids.hpp>
#include <boost/wave/util/file_position.hpp>
#include <utility>
// we need to wrap cpplexer's tokens so they can be used as Spirit V2 Lex
// tokens compatible with qi::token
template<typename PositionT = boost::wave::util::file_position_type>
class qi_token : private boost::wave::cpplexer::lex_token<PositionT>
{
// pretend to be a lexertl token with flexible attributes
// model: lex::lexertl::token<base_string_iter_t,
// mpl::vector<base_string_t, PositionT>,
// mpl::false_>
typedef typename boost::wave::cpplexer::lex_token<PositionT> base_type;
public:
typedef typename base_type::string_type base_string_t;
typedef typename base_type::string_type string_type;
typedef typename string_type::const_iterator base_string_iter_t;
typedef PositionT position_type;
// requirements from Spirit V2
typedef boost::wave::token_id id_type;
typedef base_string_iter_t iterator_type;
typedef boost::mpl::false_ has_state;
typedef std::pair<string_type, position_type> token_value_type;
qi_token() {}
qi_token(int dummy) : base_type(dummy) {}
qi_token(id_type id, string_type const & value, PositionT pos)
: base_type(id, value, pos) {}
id_type id() const {
// apply user-defined conversion to id_type
return static_cast<base_type const&>(*this);
}
operator id_type() const { return id(); }
bool eoi() const {
return static_cast<base_type const &>(*this).is_eoi();
}
// returns the Qi token value (get_value() supplies the Wave value)
token_value_type value() const {
return std::pair<string_type const &, position_type const &>(
get_value(), static_cast<base_type const *>(this)->get_position());
}
// Wave requirements delegated to base class
bool operator==(qi_token const & other) const {
return static_cast<base_type const &>(*this) == static_cast<base_type const &>(other);
}
string_type const & get_value() const {
return static_cast<base_type const &>(*this).get_value();
}
bool is_valid() const {
return static_cast<base_type const &>(*this).is_valid();
}
// Spirit V2 debugging
#if defined(BOOST_SPIRIT_DEBUG)
friend std::ostream&
operator<< (std::ostream &os, qi_token<PositionT> const & tok) {
using namespace boost::wave;
auto id = token_id(tok);
os << get_token_name(id) << "(";
if (id == T_NEWLINE) {
os << "\\n";
} else {
os << tok.get_value();
}
os << ")" ;
return os;
}
#endif
};
//
// Spirit V2 helper function requirements for token (see lex/lexer/lexertl/token.hpp)
//
template <typename Position>
inline bool
token_is_valid(qi_token<Position> const & t)
{
return t.is_valid();
}
//
// Spirit.Qi customization points
//
namespace boost { namespace spirit { namespace traits
{
//
// Teach Spirit how to get data from our token into attributes
//
// generally following Spirit.Lex's lexertl/token.hpp here
// string or range requests the underlying char data
template<typename PositionT, typename StringT>
struct assign_to_attribute_from_value<StringT, qi_token<PositionT> >
{
static void
call(qi_token<PositionT> const & tok, StringT & attr)
{
// use the Wave accessor to get the string data
attr = StringT(boost::begin(tok.value().first),
boost::end(tok.value().first));
}
};
template<typename PositionT, typename StringT>
struct assign_to_container_from_value<StringT, qi_token<PositionT> >
: assign_to_attribute_from_value<StringT, qi_token<PositionT> >
{};
// if the user wants position data instead
template<typename PositionT>
struct assign_to_attribute_from_value<PositionT, qi_token<PositionT> >
{
static void
call(qi_token<PositionT> const & tok, PositionT & attr)
{
attr = tok.value().second;
}
};
// we don't support assigning positions to "containers"
// if the user wants both position and string value
template<typename PositionT, typename StringT>
struct assign_to_attribute_from_value<
std::pair<StringT, PositionT>, qi_token<PositionT> >
{
static void
call(qi_token<PositionT> const & tok, std::pair<StringT, PositionT> & attr)
{
// delegate to existing handlers
assign_to_attribute_from_value<StringT, qi_token<PositionT> >::call(tok, attr.first);
assign_to_attribute_from_value<PositionT, qi_token<PositionT> >::call(tok, attr.second);
}
};
// Support debug output
template <typename PositionT>
struct token_printer_debug<qi_token<PositionT> >
{
typedef qi_token<PositionT> token_type;
template <typename Out>
static void print(Out& out, token_type const & val)
{
out << '[' << val << ']';
}
};
}}}
// Adapt underlying token iterator from cpplexer (Wave) to one compatible with Spirit V2
// requires adding a special typedef and returning Spirit-compatible tokens
template<typename TokenT>
struct qi_lex_iterator : boost::wave::cpplexer::lex_iterator<TokenT>
{
using base_type = boost::wave::cpplexer::lex_iterator<TokenT>;
using position_type = typename TokenT::position_type;
// add the typedef that qi::token requires
using base_iterator_type = typename TokenT::string_type::const_iterator;
// forward constructors
qi_lex_iterator() {}
template<typename IteratorT>
qi_lex_iterator(IteratorT beg, IteratorT end, position_type pos,
boost::wave::language_support lang)
: base_type(beg, end, pos, lang) {}
};