source: NonGTP/Boost/boost/wave/grammars/cpp_chlit_grammar.hpp @ 857

Revision 857, 13.3 KB checked in by igarcia, 18 years ago (diff)
Line 
1/*=============================================================================
2    Boost.Wave: A Standard compliant C++ preprocessor library
3
4    http://www.boost.org/
5
6    Copyright (c) 2001-2005 Hartmut Kaiser. Distributed under the Boost
7    Software License, Version 1.0. (See accompanying file
8    LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9=============================================================================*/
10
11#if !defined(CPP_CHLIT_GRAMMAR_HPP_9527D349_6592_449A_A409_42A001E6C64C_INCLUDED)
12#define CPP_CHLIT_GRAMMAR_HPP_9527D349_6592_449A_A409_42A001E6C64C_INCLUDED
13
14#include <limits>     // sid::numeric_limits
15
16#include <boost/static_assert.hpp>
17#include <boost/cstdint.hpp>
18
19#include <boost/spirit/core.hpp>
20#include <boost/spirit/attribute/closure.hpp>
21#include <boost/spirit/dynamic/if.hpp>
22
23#include <boost/spirit/phoenix/operators.hpp>
24#include <boost/spirit/phoenix/primitives.hpp>
25#include <boost/spirit/phoenix/statements.hpp>
26#include <boost/spirit/phoenix/functions.hpp>
27
28#include <boost/wave/wave_config.hpp>   
29#include <boost/wave/cpp_exceptions.hpp>   
30#include <boost/wave/grammars/cpp_literal_grammar_gen.hpp>
31
32///////////////////////////////////////////////////////////////////////////////
33//
34//  Reusable grammar to parse a C++ style character literal
35//
36///////////////////////////////////////////////////////////////////////////////
37namespace boost {
38namespace wave {
39namespace grammars {
40
41namespace closures {
42
43    struct chlit_closure
44    :   boost::spirit::closure<chlit_closure, boost::uint32_t, bool>
45    {
46        member1 value;
47        member2 long_lit;
48    };
49}
50
51namespace impl {
52
53///////////////////////////////////////////////////////////////////////////////
54//
55//  compose a multibyte character literal
56//
57///////////////////////////////////////////////////////////////////////////////
58    struct compose_character_literal {
59
60        template <typename ResultT, typename A1, typename A2, typename A3>
61        struct result {
62       
63            typedef void type;
64        };
65
66        void
67        operator()(boost::uint32_t& value, bool long_lit, bool& overflow,
68            boost::uint32_t character) const
69        {
70            // The following assumes that wchar_t is max. 32 Bit
71            BOOST_STATIC_ASSERT(sizeof(wchar_t) <= 4);
72           
73            static boost::uint32_t masks[] = {
74                0x000000ff, 0x0000ffff, 0x00ffffff, 0xffffffff
75            };
76            static boost::uint32_t overflow_masks[] = {
77                0xff000000, 0xffff0000, 0xffffff00, 0xffffffff
78            };
79           
80            if (long_lit) {
81            // make sure no overflow will occur below
82                if ((value & overflow_masks[sizeof(wchar_t)-1]) != 0) {
83                    overflow |= true;
84                }
85                else {
86                // calculate the new value (avoiding a warning regarding
87                // shifting count >= size of the type)
88                    value <<= 8 * (sizeof(wchar_t)-1);
89                    value <<= 8; 
90                    value |= character & masks[sizeof(wchar_t)-1];
91                }
92            }
93            else {
94            // make sure no overflow will occur below
95                if ((value & overflow_masks[sizeof(char)-1]) != 0) {
96                    overflow |= true;
97                }
98                else {
99                // calculate the new value
100                    value <<= 8 * sizeof(char);
101                    value |= character & masks[sizeof(char)-1];
102                }
103            }
104        }
105    };
106    phoenix::function<compose_character_literal> const compose;
107
108}   // namespace impl
109
110///////////////////////////////////////////////////////////////////////////////
111//  define, whether the rule's should generate some debug output
112#define TRACE_CHLIT_GRAMMAR \
113    bool(BOOST_SPIRIT_DEBUG_FLAGS_CPP & BOOST_SPIRIT_DEBUG_FLAGS_CHLIT_GRAMMAR) \
114    /**/
115
116struct chlit_grammar :
117    public boost::spirit::grammar<chlit_grammar,
118        closures::chlit_closure::context_t>
119{
120    chlit_grammar()
121    :   overflow(false)
122    {
123        BOOST_SPIRIT_DEBUG_TRACE_GRAMMAR_NAME(*this, "chlit_grammar",
124            TRACE_CHLIT_GRAMMAR);
125    }
126   
127    template <typename ScannerT>
128    struct definition
129    {
130        typedef
131            boost::spirit::rule<ScannerT, closures::chlit_closure::context_t>
132            rule_t;
133
134        rule_t ch_lit;
135
136        definition(chlit_grammar const &self)
137        {
138            using namespace boost::spirit;
139            using namespace phoenix;
140           
141            // special parsers for '\x..' and L'\x....'
142            typedef uint_parser<
143                        unsigned int, 16, 1, 2 * sizeof(char)
144                    > hex_char_parser_type;
145            typedef uint_parser<
146                        unsigned int, 16, 1, 2 * sizeof(wchar_t)
147                    > hex_wchar_parser_type;
148
149            // the rule for a character literal
150            ch_lit
151                =   eps_p[self.value = val(0), self.long_lit = val(false)]
152                    >> !ch_p('L')[self.long_lit = val(true)]
153                    >>  ch_p('\'')
154                    >> +(   (
155                            ch_p('\\')
156                            >>  (   ch_p('a')    // BEL
157                                    [
158                                        impl::compose(self.value, self.long_lit,
159                                            var(self.overflow), val(0x07))
160                                    ]
161                                |   ch_p('b')    // BS
162                                    [
163                                        impl::compose(self.value, self.long_lit,
164                                            var(self.overflow), val(0x08))
165                                    ]
166                                |   ch_p('t')    // HT
167                                    [
168                                        impl::compose(self.value, self.long_lit,
169                                            var(self.overflow), val(0x09))
170                                    ]
171                                |   ch_p('n')    // NL
172                                    [
173                                        impl::compose(self.value, self.long_lit,
174                                            var(self.overflow), val(0x0a))
175                                    ]
176                                |   ch_p('v')    // VT
177                                    [
178                                        impl::compose(self.value, self.long_lit,
179                                            var(self.overflow), val(0x0b))
180                                    ]
181                                |   ch_p('f')    // FF
182                                    [
183                                        impl::compose(self.value, self.long_lit,
184                                            var(self.overflow), val(0x0c))
185                                    ]
186                                |   ch_p('r')    // CR
187                                    [
188                                        impl::compose(self.value, self.long_lit,
189                                            var(self.overflow), val(0x0d))
190                                    ]
191                                |   ch_p('?')
192                                    [
193                                        impl::compose(self.value, self.long_lit,
194                                            var(self.overflow), val('?'))
195                                    ]
196                                |   ch_p('\'')
197                                    [
198                                        impl::compose(self.value, self.long_lit,
199                                            var(self.overflow), val('\''))
200                                    ]
201                                |   ch_p('\"')
202                                    [
203                                        impl::compose(self.value, self.long_lit,
204                                            var(self.overflow), val('\"'))
205                                    ]
206                                |   ch_p('\\')
207                                    [
208                                        impl::compose(self.value, self.long_lit,
209                                            var(self.overflow), val('\\'))
210                                    ]
211                                |   ch_p('x')
212                                    >>  if_p(self.long_lit)
213                                        [
214                                            hex_wchar_parser_type()
215                                            [
216                                                impl::compose(self.value, self.long_lit,
217                                                    var(self.overflow), arg1)
218                                            ]
219                                        ]
220                                        .else_p
221                                        [
222                                            hex_char_parser_type()
223                                            [
224                                                impl::compose(self.value, self.long_lit,
225                                                    var(self.overflow), arg1)
226                                            ]
227                                        ]
228                                |   ch_p('u')
229                                    >>  uint_parser<unsigned int, 16, 4, 4>()
230                                        [
231                                            impl::compose(self.value, self.long_lit,
232                                                var(self.overflow), arg1)
233                                        ]
234                                |   ch_p('U')
235                                    >>  uint_parser<unsigned int, 16, 8, 8>()
236                                        [
237                                            impl::compose(self.value, self.long_lit,
238                                                var(self.overflow), arg1)
239                                        ]
240                                |   uint_parser<unsigned int, 8, 1, 3>()
241                                    [
242                                        impl::compose(self.value, self.long_lit,
243                                            var(self.overflow), arg1)
244                                    ]
245                                )
246                            )
247                        |   ~eps_p(ch_p('\'')) >> anychar_p
248                            [
249                                impl::compose(self.value, self.long_lit,
250                                    var(self.overflow), arg1)
251                            ]
252                        )
253                    >>  ch_p('\'')
254                ;
255
256            BOOST_SPIRIT_DEBUG_TRACE_RULE(ch_lit, TRACE_CHLIT_GRAMMAR);
257        }
258
259    // start rule of this grammar
260        rule_t const& start() const
261        { return ch_lit; }
262    };
263
264    // flag signaling integer overflow during value composition
265    mutable bool overflow;
266};
267
268#undef TRACE_CHLIT_GRAMMAR
269
270///////////////////////////////////////////////////////////////////////////////
271// 
272//  The following function is defined here, to allow the separation of
273//  the compilation of the intlit_grammap from the function using it.
274// 
275///////////////////////////////////////////////////////////////////////////////
276
277#if BOOST_WAVE_SEPARATE_GRAMMAR_INSTANTIATION != 0
278#define BOOST_WAVE_CHLITGRAMMAR_GEN_INLINE
279#else
280#define BOOST_WAVE_CHLITGRAMMAR_GEN_INLINE inline
281#endif
282
283template <typename TokenT>
284BOOST_WAVE_CHLITGRAMMAR_GEN_INLINE
285unsigned int
286chlit_grammar_gen<TokenT>::evaluate(TokenT const &token)
287{
288    using namespace boost::spirit;
289   
290chlit_grammar g;
291boost::uint32_t result = 0;
292typename TokenT::string_type const &token_val = token.get_value();
293parse_info<typename TokenT::string_type::const_iterator> hit =
294    parse(token_val.begin(), token_val.end(), g[spirit_assign_actor(result)]);
295
296    if (!hit.hit) {
297        BOOST_WAVE_THROW(preprocess_exception, ill_formed_character_literal,
298            token_val.c_str(), token.get_position());
299    }
300    else {
301    // range check
302        if ('L' == token_val[0]) {
303        // recognised wide character
304            if (g.overflow ||
305                result > (unsigned long)(std::numeric_limits<wchar_t>::max)())
306            {
307            // out of range
308                BOOST_WAVE_THROW(preprocess_exception,
309                    character_literal_out_of_range,
310                    token_val.c_str(), token.get_position());
311            }
312        }
313        else {
314        // recognised narrow ('normal') character
315            if (g.overflow ||
316                result > (unsigned long)(std::numeric_limits<unsigned char>::max)())
317            {
318            // out of range
319                BOOST_WAVE_THROW(preprocess_exception,
320                    character_literal_out_of_range,
321                    token_val.c_str(), token.get_position());
322            }
323        }
324    }
325    return result;
326}
327
328#undef BOOST_WAVE_CHLITGRAMMAR_GEN_INLINE
329
330///////////////////////////////////////////////////////////////////////////////
331}   // namespace grammars
332}   // namespace wave
333}   // namespace boost
334
335#endif // !defined(CPP_CHLIT_GRAMMAR_HPP_9527D349_6592_449A_A409_42A001E6C64C_INCLUDED)
Note: See TracBrowser for help on using the repository browser.