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