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