• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //  Copyright (c) 2001-2011 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 #ifndef BOOST_SPIRIT_LEX_LEXER_SUPPORT_FUNCTIONS_HPP
7 #define BOOST_SPIRIT_LEX_LEXER_SUPPORT_FUNCTIONS_HPP
8 
9 #if defined(_MSC_VER)
10 #pragma once
11 #endif
12 
13 #include <boost/spirit/home/support/detail/scoped_enum_emulation.hpp>
14 #include <boost/spirit/home/lex/lexer/pass_flags.hpp>
15 #include <boost/spirit/home/lex/lexer/support_functions_expression.hpp>
16 #include <boost/phoenix/core/actor.hpp>
17 #include <boost/phoenix/core/as_actor.hpp>
18 #include <boost/phoenix/core/value.hpp> // includes as_actor specialization
19 
20 ///////////////////////////////////////////////////////////////////////////////
21 namespace boost { namespace spirit { namespace lex
22 {
23     ///////////////////////////////////////////////////////////////////////////
24     // The function object less_type is used by the implementation of the
25     // support function lex::less(). Its functionality is equivalent to flex'
26     // function yyless(): it returns an iterator positioned to the nth input
27     // character beyond the current start iterator (i.e. by assigning the
28     // return value to the placeholder '_end' it is possible to return all but
29     // the first n characters of the current token back to the input stream.
30     //
31     //  This Phoenix actor is invoked whenever the function lex::less(n) is
32     //  used inside a lexer semantic action:
33     //
34     //      lex::token_def<> identifier = "[a-zA-Z_][a-zA-Z0-9_]*";
35     //      this->self = identifier [ _end = lex::less(4) ];
36     //
37     //  The example shows how to limit the length of the matched identifier to
38     //  four characters.
39     //
40     //  Note: the function lex::less() has no effect if used on it's own, you
41     //        need to use the returned result in order to make use of its
42     //        functionality.
43     template <typename Actor>
44     struct less_type
45     {
46         typedef mpl::true_ no_nullary;
47 
48         template <typename Env>
49         struct result
50         {
51             typedef typename remove_reference<
52                 typename remove_const<
53                     typename mpl::at_c<typename Env::args_type, 4>::type
54                 >::type
55             >::type context_type;
56             typedef typename context_type::base_iterator_type type;
57         };
58 
59         template <typename Env>
60         typename result<Env>::type
evalboost::spirit::lex::less_type61         eval(Env const& env) const
62         {
63             typename result<Env>::type it;
64             return fusion::at_c<4>(env.args()).less(it, actor_());
65         }
66 
less_typeboost::spirit::lex::less_type67         less_type(Actor const& actor)
68           : actor_(actor) {}
69 
70         Actor actor_;
71     };
72 
73     //  The function lex::less() is used to create a Phoenix actor allowing to
74     //  implement functionality similar to flex' function yyless().
75     template <typename T>
76     inline typename expression::less<
77         typename phoenix::as_actor<T>::type
78     >::type const
less(T const & v)79     less(T const& v)
80     {
81         return expression::less<T>::make(phoenix::as_actor<T>::convert(v));
82     }
83 
84     ///////////////////////////////////////////////////////////////////////////
85     // The function object more_type is used by the implementation of the
86     // support function lex::more(). Its functionality is equivalent to flex'
87     // function yymore(): it tells the lexer that the next time it matches a
88     // rule, the corresponding token should be appended onto the current token
89     // value rather than replacing it.
90     //
91     //  This Phoenix actor is invoked whenever the function lex::more(n) is
92     //  used inside a lexer semantic action:
93     //
94     //      lex::token_def<> identifier = "[a-zA-Z_][a-zA-Z0-9_]*";
95     //      this->self = identifier [ lex::more() ];
96     //
97     //  The example shows how prefix the next matched token with the matched
98     //  identifier.
99     struct more_type
100     {
101         typedef mpl::true_ no_nullary;
102 
103         template <typename Env>
104         struct result
105         {
106             typedef void type;
107         };
108 
109         template <typename Env>
evalboost::spirit::lex::more_type110         void eval(Env const& env) const
111         {
112             fusion::at_c<4>(env.args()).more();
113         }
114     };
115 
116     //  The function lex::more() is used to create a Phoenix actor allowing to
117     //  implement functionality similar to flex' function yymore().
118     //inline expression::more<mpl::void_>::type const
more()119     inline phoenix::actor<more_type> more()
120     {
121         return phoenix::actor<more_type>();
122     }
123 
124     ///////////////////////////////////////////////////////////////////////////
125     // The function object lookahead_type is used by the implementation of the
126     // support function lex::lookahead(). Its functionality is needed to
127     // emulate the flex' lookahead operator a/b. Use lex::lookahead() inside
128     // of lexer semantic actions to test whether the argument to this function
129     // matches the current look ahead input. lex::lookahead() can be used with
130     // either a token id or a token_def instance as its argument. It returns
131     // a bool indicating whether the look ahead has been matched.
132     template <typename IdActor, typename StateActor>
133     struct lookahead_type
134     {
135         typedef mpl::true_ no_nullary;
136 
137         template <typename Env>
138         struct result
139         {
140             typedef bool type;
141         };
142 
143         template <typename Env>
evalboost::spirit::lex::lookahead_type144         bool eval(Env const& env) const
145         {
146             return fusion::at_c<4>(env.args()).
147                 lookahead(id_actor_(), state_actor_());
148         }
149 
lookahead_typeboost::spirit::lex::lookahead_type150         lookahead_type(IdActor const& id_actor, StateActor const& state_actor)
151           : id_actor_(id_actor), state_actor_(state_actor) {}
152 
153         IdActor id_actor_;
154         StateActor state_actor_;
155     };
156 
157     //  The function lex::lookahead() is used to create a Phoenix actor
158     //  allowing to implement functionality similar to flex' lookahead operator
159     //  a/b.
160     template <typename T>
161     inline typename expression::lookahead<
162         typename phoenix::as_actor<T>::type
163       , typename phoenix::as_actor<std::size_t>::type
164     >::type const
lookahead(T const & id)165     lookahead(T const& id)
166     {
167         typedef typename phoenix::as_actor<T>::type id_actor_type;
168         typedef typename phoenix::as_actor<std::size_t>::type state_actor_type;
169 
170         return expression::lookahead<id_actor_type, state_actor_type>::make(
171             phoenix::as_actor<T>::convert(id),
172             phoenix::as_actor<std::size_t>::convert(std::size_t(~0)));
173     }
174 
175     template <typename Attribute, typename Char, typename Idtype>
176     inline typename expression::lookahead<
177         typename phoenix::as_actor<Idtype>::type
178       , typename phoenix::as_actor<std::size_t>::type
179     >::type const
lookahead(token_def<Attribute,Char,Idtype> const & tok)180     lookahead(token_def<Attribute, Char, Idtype> const& tok)
181     {
182         typedef typename phoenix::as_actor<Idtype>::type id_actor_type;
183         typedef typename phoenix::as_actor<std::size_t>::type state_actor_type;
184 
185         std::size_t state = tok.state();
186 
187         // The following assertion fires if you pass a token_def instance to
188         // lex::lookahead without first associating this instance with the
189         // lexer.
190         BOOST_ASSERT(std::size_t(~0) != state &&
191             "token_def instance not associated with lexer yet");
192 
193         return expression::lookahead<id_actor_type, state_actor_type>::make(
194             phoenix::as_actor<Idtype>::convert(tok.id()),
195             phoenix::as_actor<std::size_t>::convert(state));
196     }
197 
198     ///////////////////////////////////////////////////////////////////////////
ignore()199     inline BOOST_SCOPED_ENUM(pass_flags) ignore()
200     {
201         return pass_flags::pass_ignore;
202     }
203 
204 }}}
205 
206 #endif
207