source: NonGTP/Boost/boost/spirit/utility/impl/escape_char.ipp @ 857

Revision 857, 8.9 KB checked in by igarcia, 18 years ago (diff)
Line 
1/*=============================================================================
2    Copyright (c) 2001-2003 Daniel Nuffer
3    Copyright (c) 2002-2003 Hartmut Kaiser
4    http://spirit.sourceforge.net/
5
6    Use, modification and distribution is subject to the Boost Software
7    License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
8    http://www.boost.org/LICENSE_1_0.txt)
9=============================================================================*/
10#ifndef BOOST_SPIRIT_ESCAPE_CHAR_IPP
11#define BOOST_SPIRIT_ESCAPE_CHAR_IPP
12
13#include <boost/spirit/core/parser.hpp>
14#include <boost/spirit/core/primitives/numerics.hpp>
15#include <boost/spirit/core/composite/difference.hpp>
16#include <boost/spirit/core/composite/sequence.hpp>
17
18///////////////////////////////////////////////////////////////////////////////
19namespace boost { namespace spirit {
20
21///////////////////////////////////////////////////////////////////////////////
22//
23//  escape_char_parser class
24//
25///////////////////////////////////////////////////////////////////////////////
26
27const unsigned long c_escapes = 1;
28const unsigned long lex_escapes = c_escapes << 1;
29
30//////////////////////////////////
31namespace impl {
32
33    //////////////////////////////////
34#if (defined(BOOST_MSVC) && (BOOST_MSVC <= 1310))
35#pragma warning(push)
36#pragma warning(disable:4127)
37#endif
38    template <unsigned long Flags, typename CharT>
39    struct escape_char_action_parse {
40
41        template <typename ParserT, typename ScannerT>
42        static typename parser_result<ParserT, ScannerT>::type
43        parse(ScannerT const& scan, ParserT const &p)
44        {
45            // Actually decode the escape char.
46            typedef CharT char_t;
47            typedef typename ScannerT::iterator_t iterator_t;
48            typedef typename parser_result<ParserT, ScannerT>::type result_t;
49
50            if (scan.first != scan.last) {
51
52                iterator_t save = scan.first;
53                if (result_t hit = p.subject().parse(scan)) {
54
55                    char_t unescaped;
56
57                    scan.first = save;
58                    if (*scan.first == '\\') {
59
60                        ++scan.first;
61                        switch (*scan.first) {
62                        case 'b':   unescaped = '\b';   ++scan.first; break;
63                        case 't':   unescaped = '\t';   ++scan.first; break;
64                        case 'n':   unescaped = '\n';   ++scan.first; break;
65                        case 'f':   unescaped = '\f';   ++scan.first; break;
66                        case 'r':   unescaped = '\r';   ++scan.first; break;
67                        case '"':   unescaped = '"';    ++scan.first; break;
68                        case '\'':  unescaped = '\'';   ++scan.first; break;
69                        case '\\':  unescaped = '\\';   ++scan.first; break;
70
71                        case 'x': case 'X':
72                            {
73                                char_t hex = 0;
74                                char_t const lim =
75                                    (std::numeric_limits<char_t>::max)() >> 4;
76
77                                ++scan.first;
78                                while (scan.first != scan.last)
79                                {
80                                    char_t c = *scan.first;
81                                    if (hex > lim && impl::isxdigit_(c))
82                                    {
83                                        // overflow detected
84                                        scan.first = save;
85                                        return scan.no_match();
86                                    }
87                                    if (impl::isdigit_(c))
88                                    {
89                                        hex <<= 4;
90                                        hex |= c - '0';
91                                        ++scan.first;
92                                    }
93                                    else if (impl::isxdigit_(c))
94                                    {
95                                        hex <<= 4;
96                                        c = impl::toupper_(c);
97                                        hex |= c - 'A' + 0xA;
98                                        ++scan.first;
99                                    }
100                                    else
101                                    {
102                                        break; // reached the end of the number
103                                    }
104                                }
105                                unescaped = hex;
106                            }
107                            break;
108
109                        case '0': case '1': case '2': case '3':
110                        case '4': case '5': case '6': case '7':
111                            {
112                                char_t oct = 0;
113                                char_t const lim =
114                                    (std::numeric_limits<char_t>::max)() >> 3;
115                                while (scan.first != scan.last)
116                                {
117                                    char_t c = *scan.first;
118                                    if (oct > lim && (c >= '0' && c <= '7'))
119                                    {
120                                        // overflow detected
121                                        scan.first = save;
122                                        return scan.no_match();
123                                    }
124
125                                    if (c >= '0' && c <= '7')
126                                    {
127                                        oct <<= 3;
128                                        oct |= c - '0';
129                                        ++scan.first;
130                                    }
131                                    else
132                                    {
133                                        break; // reached end of digits
134                                    }
135                                }
136                                unescaped = oct;
137                            }
138                            break;
139
140                        default:
141                            if (Flags & c_escapes)
142                            {
143                                // illegal C escape sequence
144                                scan.first = save;
145                                return scan.no_match();
146                            }
147                            else
148                            {
149                                unescaped = *scan.first;
150                                ++scan.first;
151                            }
152                            break;
153                        }
154                    }
155                    else {
156                        unescaped = *scan.first;
157                        ++scan.first;
158                    }
159
160                    scan.do_action(p.predicate(), unescaped, save, scan.first);
161                    return hit;
162                }
163            }
164            return scan.no_match(); // overflow detected
165        }
166    };
167#if (defined(BOOST_MSVC) && (BOOST_MSVC <= 1310))
168#pragma warning(pop)
169#endif
170
171    //////////////////////////////////
172    template <typename CharT>
173    struct escape_char_parse {
174
175        template <typename ScannerT, typename ParserT>
176        static typename parser_result<ParserT, ScannerT>::type
177        parse(ScannerT const &scan, ParserT const &/*p*/)
178        {
179            typedef
180                uint_parser<CharT, 8, 1,
181                    std::numeric_limits<CharT>::digits / 3 + 1
182                >
183                oct_parser_t;
184            typedef
185                uint_parser<CharT, 16, 1,
186                    std::numeric_limits<CharT>::digits / 4 + 1
187                >
188                hex_parser_t;
189
190            typedef alternative<difference<anychar_parser, chlit<CharT> >,
191                sequence<chlit<CharT>, alternative<alternative<oct_parser_t,
192                sequence<inhibit_case<chlit<CharT> >, hex_parser_t > >,
193                difference<difference<anychar_parser,
194                inhibit_case<chlit<CharT> > >, oct_parser_t > > > >
195                parser_t;
196
197            static parser_t p =
198                ( (anychar_p - chlit<CharT>(CharT('\\')))
199                | (chlit<CharT>(CharT('\\')) >>
200                    (  oct_parser_t()
201                     | as_lower_d[chlit<CharT>(CharT('x'))] >> hex_parser_t()
202                     | (anychar_p - as_lower_d[chlit<CharT>(CharT('x'))] - oct_parser_t())
203                    )
204                ));
205
206            BOOST_SPIRIT_DEBUG_TRACE_NODE(p,
207                (BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_ESCAPE_CHAR) != 0);
208
209            return p.parse(scan);
210        }
211    };
212
213///////////////////////////////////////////////////////////////////////////////
214} // namespace impl
215
216///////////////////////////////////////////////////////////////////////////////
217}} // namespace boost::spirit
218
219#endif
220
Note: See TracBrowser for help on using the repository browser.