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(BOOST_SPIRIT_LEX_CHAR_TOKEN_DEF_MAR_28_2007_0626PM)
7 #define BOOST_SPIRIT_LEX_CHAR_TOKEN_DEF_MAR_28_2007_0626PM
8 
9 #if defined(_MSC_VER)
10 #pragma once
11 #endif
12 
13 #include <boost/spirit/home/support/common_terminals.hpp>
14 #include <boost/spirit/home/support/string_traits.hpp>
15 #include <boost/spirit/home/lex/domain.hpp>
16 #include <boost/spirit/home/lex/lexer_type.hpp>
17 #include <boost/spirit/home/lex/meta_compiler.hpp>
18 
19 namespace boost { namespace spirit
20 {
21     ///////////////////////////////////////////////////////////////////////////
22     // Enablers
23     ///////////////////////////////////////////////////////////////////////////
24 
25     // enables 'x'
26     template <>
27     struct use_terminal<lex::domain, char>
28       : mpl::true_ {};
29 
30     // enables "x"
31     template <>
32     struct use_terminal<lex::domain, char[2]>
33       : mpl::true_ {};
34 
35     // enables wchar_t
36     template <>
37     struct use_terminal<lex::domain, wchar_t>
38       : mpl::true_ {};
39 
40     // enables L"x"
41     template <>
42     struct use_terminal<lex::domain, wchar_t[2]>
43       : mpl::true_ {};
44 
45     // enables char_('x'), char_("x")
46     template <typename CharEncoding, typename A0>
47     struct use_terminal<lex::domain
48       , terminal_ex<
49             tag::char_code<tag::char_, CharEncoding>
50           , fusion::vector1<A0> > >
51       : mpl::true_ {};
52 
53     // enables char_('x', ID), char_("x", ID)
54     template <typename CharEncoding, typename A0, typename A1>
55     struct use_terminal<lex::domain
56       , terminal_ex<
57             tag::char_code<tag::char_, CharEncoding>
58           , fusion::vector2<A0, A1> > >
59       : mpl::true_ {};
60 }}
61 
62 namespace boost { namespace spirit { namespace lex
63 {
64     // use char_ from standard character set by default
65 #ifndef BOOST_SPIRIT_NO_PREDEFINED_TERMINALS
66     using spirit::standard::char_;
67 #endif
68     using spirit::standard::char_type;
69 
70     ///////////////////////////////////////////////////////////////////////////
71     //
72     //  char_token_def
73     //      represents a single character token definition
74     //
75     ///////////////////////////////////////////////////////////////////////////
76     template <typename CharEncoding = char_encoding::standard
77       , typename IdType = std::size_t>
78     struct char_token_def
79       : primitive_lexer<char_token_def<CharEncoding, IdType> >
80     {
81         typedef typename CharEncoding::char_type char_type;
82 
char_token_defboost::spirit::lex::char_token_def83         char_token_def(char_type ch, IdType const& id)
84           : ch(ch), id_(id), unique_id_(std::size_t(~0))
85           , token_state_(std::size_t(~0))
86         {}
87 
88         template <typename LexerDef, typename String>
collectboost::spirit::lex::char_token_def89         void collect(LexerDef& lexdef, String const& state
90           , String const& targetstate) const
91         {
92             std::size_t state_id = lexdef.add_state(state.c_str());
93 
94             // If the following assertion fires you are probably trying to use
95             // a single char_token_def instance in more than one lexer state.
96             // This is not possible. Please create a separate token_def instance
97             // from the same regular expression for each lexer state it needs
98             // to be associated with.
99             BOOST_ASSERT(
100                 (std::size_t(~0) == token_state_ || state_id == token_state_) &&
101                 "Can't use single char_token_def with more than one lexer state");
102 
103             char_type const* target = targetstate.empty() ? 0 : targetstate.c_str();
104             if (target)
105                 lexdef.add_state(target);
106 
107             token_state_ = state_id;
108             unique_id_ = lexdef.add_token (state.c_str(), ch, id_, target);
109         }
110 
111         template <typename LexerDef>
add_actionsboost::spirit::lex::char_token_def112         void add_actions(LexerDef&) const {}
113 
idboost::spirit::lex::char_token_def114         IdType id() const { return id_; }
unique_idboost::spirit::lex::char_token_def115         std::size_t unique_id() const { return unique_id_; }
stateboost::spirit::lex::char_token_def116         std::size_t state() const { return token_state_; }
117 
118         char_type ch;
119         mutable IdType id_;
120         mutable std::size_t unique_id_;
121         mutable std::size_t token_state_;
122     };
123 
124     ///////////////////////////////////////////////////////////////////////////
125     // Lexer generators: make_xxx function (objects)
126     ///////////////////////////////////////////////////////////////////////////
127     namespace detail
128     {
129         template <typename CharEncoding>
130         struct basic_literal
131         {
132             typedef char_token_def<CharEncoding> result_type;
133 
134             template <typename Char>
operator ()boost::spirit::lex::detail::basic_literal135             result_type operator()(Char ch, unused_type) const
136             {
137                 return result_type(ch, ch);
138             }
139 
140             template <typename Char>
operator ()boost::spirit::lex::detail::basic_literal141             result_type operator()(Char const* str, unused_type) const
142             {
143                 return result_type(str[0], str[0]);
144             }
145         };
146     }
147 
148     // literals: 'x', "x"
149     template <typename Modifiers>
150     struct make_primitive<char, Modifiers>
151       : detail::basic_literal<char_encoding::standard> {};
152 
153     template <typename Modifiers>
154     struct make_primitive<char const(&)[2], Modifiers>
155       : detail::basic_literal<char_encoding::standard> {};
156 
157     // literals: L'x', L"x"
158     template <typename Modifiers>
159     struct make_primitive<wchar_t, Modifiers>
160       : detail::basic_literal<char_encoding::standard_wide> {};
161 
162     template <typename Modifiers>
163     struct make_primitive<wchar_t const(&)[2], Modifiers>
164       : detail::basic_literal<char_encoding::standard_wide> {};
165 
166     // handle char_('x')
167     template <typename CharEncoding, typename Modifiers, typename A0>
168     struct make_primitive<
169         terminal_ex<
170             tag::char_code<tag::char_, CharEncoding>
171           , fusion::vector1<A0>
172         >
173       , Modifiers>
174     {
175         typedef char_token_def<CharEncoding> result_type;
176 
177         template <typename Terminal>
operator ()boost::spirit::lex::make_primitive178         result_type operator()(Terminal const& term, unused_type) const
179         {
180             return result_type(fusion::at_c<0>(term.args), fusion::at_c<0>(term.args));
181         }
182     };
183 
184     // handle char_("x")
185     template <typename CharEncoding, typename Modifiers, typename Char>
186     struct make_primitive<
187         terminal_ex<
188             tag::char_code<tag::char_, CharEncoding>
189           , fusion::vector1<Char(&)[2]>   // single char strings
190         >
191       , Modifiers>
192     {
193         typedef char_token_def<CharEncoding> result_type;
194 
195         template <typename Terminal>
operator ()boost::spirit::lex::make_primitive196         result_type operator()(Terminal const& term, unused_type) const
197         {
198             Char ch = fusion::at_c<0>(term.args)[0];
199             return result_type(ch, ch);
200         }
201     };
202 
203     // handle char_('x', ID)
204     template <typename CharEncoding, typename Modifiers, typename A0, typename A1>
205     struct make_primitive<
206         terminal_ex<
207             tag::char_code<tag::char_, CharEncoding>
208           , fusion::vector2<A0, A1>
209         >
210       , Modifiers>
211     {
212         typedef char_token_def<CharEncoding> result_type;
213 
214         template <typename Terminal>
operator ()boost::spirit::lex::make_primitive215         result_type operator()(Terminal const& term, unused_type) const
216         {
217             return result_type(
218                 fusion::at_c<0>(term.args), fusion::at_c<1>(term.args));
219         }
220     };
221 
222     // handle char_("x", ID)
223     template <typename CharEncoding, typename Modifiers, typename Char, typename A1>
224     struct make_primitive<
225         terminal_ex<
226             tag::char_code<tag::char_, CharEncoding>
227           , fusion::vector2<Char(&)[2], A1>   // single char strings
228         >
229       , Modifiers>
230     {
231         typedef char_token_def<CharEncoding> result_type;
232 
233         template <typename Terminal>
operator ()boost::spirit::lex::make_primitive234         result_type operator()(Terminal const& term, unused_type) const
235         {
236             return result_type(
237                 fusion::at_c<0>(term.args)[0], fusion::at_c<1>(term.args));
238         }
239     };
240 }}}  // namespace boost::spirit::lex
241 
242 #endif
243