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