summaryrefslogtreecommitdiffstats
blob: 8467560f676df1c55c414abf09f83e6b37a1721b (plain)
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
197
198
199
200
201
202
203
204
205
//  Copyright (c) 2001-2011 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)

#if !defined(SPIRIT_LEX_SUPPORT_FUNCTIONS_JUN_08_2009_0211PM)
#define SPIRIT_LEX_SUPPORT_FUNCTIONS_JUN_08_2009_0211PM

#if defined(_MSC_VER)
#pragma once
#endif

#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/home/support/detail/scoped_enum_emulation.hpp>
#include <boost/spirit/home/lex/lexer/pass_flags.hpp>

#include <boost/spirit/home/lex/lexer/support_functions_expression.hpp>

///////////////////////////////////////////////////////////////////////////////
namespace boost { namespace spirit { namespace lex
{
    ///////////////////////////////////////////////////////////////////////////
    // The function object less_type is used by the implementation of the 
    // support function lex::less(). Its functionality is equivalent to flex' 
    // function yyless(): it returns an iterator positioned to the nth input 
    // character beyond the current start iterator (i.e. by assigning the 
    // return value to the placeholder '_end' it is possible to return all but
    // the first n characters of the current token back to the input stream. 
    //
    //  This Phoenix actor is invoked whenever the function lex::less(n) is 
    //  used inside a lexer semantic action:
    //
    //      lex::token_def<> identifier = "[a-zA-Z_][a-zA-Z0-9_]*";
    //      this->self = identifier [ _end = lex::less(4) ];
    //
    //  The example shows how to limit the length of the matched identifier to 
    //  four characters.
    //
    //  Note: the function lex::less() has no effect if used on it's own, you 
    //        need to use the returned result in order to make use of its 
    //        functionality.
    template <typename Actor>
    struct less_type
    {
        typedef mpl::true_ no_nullary;

        template <typename Env>
        struct result
        {
            typedef typename remove_reference< 
                typename remove_const<
                    typename mpl::at_c<typename Env::args_type, 4>::type
                >::type
            >::type context_type;
            typedef typename context_type::base_iterator_type type;
        };

        template <typename Env>
        typename result<Env>::type 
        eval(Env const& env) const
        {
            typename result<Env>::type it;
            return fusion::at_c<4>(env.args()).less(it, actor_());
        }

        less_type(Actor const& actor)
          : actor_(actor) {}

        Actor actor_;
    };

    //  The function lex::less() is used to create a Phoenix actor allowing to
    //  implement functionality similar to flex' function yyless().
    template <typename T>
    inline typename expression::less<
        typename phoenix::as_actor<T>::type
    >::type const
    less(T const& v)
    {
        return expression::less<T>::make(phoenix::as_actor<T>::convert(v));
    }

    ///////////////////////////////////////////////////////////////////////////
    // The function object more_type is used by the implementation of the  
    // support function lex::more(). Its functionality is equivalent to flex' 
    // function yymore(): it tells the lexer that the next time it matches a 
    // rule, the corresponding token should be appended onto the current token 
    // value rather than replacing it.
    //
    //  This Phoenix actor is invoked whenever the function lex::more(n) is 
    //  used inside a lexer semantic action:
    //
    //      lex::token_def<> identifier = "[a-zA-Z_][a-zA-Z0-9_]*";
    //      this->self = identifier [ lex::more() ];
    //
    //  The example shows how prefix the next matched token with the matched
    //  identifier.
    struct more_type
    {
        typedef mpl::true_ no_nullary;

        template <typename Env>
        struct result
        {
            typedef void type;
        };

        template <typename Env>
        void eval(Env const& env) const
        {
            fusion::at_c<4>(env.args()).more();
        }
    };

    //  The function lex::more() is used to create a Phoenix actor allowing to
    //  implement functionality similar to flex' function yymore(). 
    //inline expression::more<mpl::void_>::type const
    inline phoenix::actor<more_type> more()
    {
        return phoenix::actor<more_type>();
    }

    ///////////////////////////////////////////////////////////////////////////
    // The function object lookahead_type is used by the implementation of the  
    // support function lex::lookahead(). Its functionality is needed to 
    // emulate the flex' lookahead operator a/b. Use lex::lookahead() inside
    // of lexer semantic actions to test whether the argument to this function
    // matches the current look ahead input. lex::lookahead() can be used with
    // either a token id or a token_def instance as its argument. It returns
    // a bool indicating whether the look ahead has been matched.
    template <typename IdActor, typename StateActor>
    struct lookahead_type
    {
        typedef mpl::true_ no_nullary;

        template <typename Env>
        struct result
        {
            typedef bool type;
        };

        template <typename Env>
        bool eval(Env const& env) const
        {
            return fusion::at_c<4>(env.args()).
                lookahead(id_actor_(), state_actor_());
        }

        lookahead_type(IdActor const& id_actor, StateActor const& state_actor)
          : id_actor_(id_actor), state_actor_(state_actor) {}

        IdActor id_actor_;
        StateActor state_actor_;
    };

    //  The function lex::lookahead() is used to create a Phoenix actor 
    //  allowing to implement functionality similar to flex' lookahead operator
    //  a/b.
    template <typename T>
    inline typename expression::lookahead<
        typename phoenix::as_actor<T>::type
      , typename phoenix::as_actor<std::size_t>::type
    >::type const
    lookahead(T const& id)
    {
        typedef typename phoenix::as_actor<T>::type id_actor_type;
        typedef typename phoenix::as_actor<std::size_t>::type state_actor_type;

        return expression::lookahead<id_actor_type, state_actor_type>::make(
            phoenix::as_actor<T>::convert(id),
            phoenix::as_actor<std::size_t>::convert(std::size_t(~0)));
    }

    template <typename Attribute, typename Char, typename Idtype>
    inline typename expression::lookahead<
        typename phoenix::as_actor<Idtype>::type
      , typename phoenix::as_actor<std::size_t>::type
    >::type const
    lookahead(token_def<Attribute, Char, Idtype> const& tok)
    {
        typedef typename phoenix::as_actor<Idtype>::type id_actor_type;
        typedef typename phoenix::as_actor<std::size_t>::type state_actor_type;

        std::size_t state = tok.state();

        // The following assertion fires if you pass a token_def instance to 
        // lex::lookahead without first associating this instance with the 
        // lexer.
        BOOST_ASSERT(std::size_t(~0) != state && 
            "token_def instance not associated with lexer yet");

        return expression::lookahead<id_actor_type, state_actor_type>::make(
            phoenix::as_actor<Idtype>::convert(tok.id()),
            phoenix::as_actor<std::size_t>::convert(state));
    }

    ///////////////////////////////////////////////////////////////////////////
    inline BOOST_SCOPED_ENUM(pass_flags) ignore()
    {
        return pass_flags::pass_ignore;
    }

}}}

#endif