Imported Upstream version 1.72.0
[platform/upstream/boost.git] / boost / spirit / home / classic / utility / impl / escape_char.ipp
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 ///////////////////////////////////////////////////////////////////////////////
19 namespace boost { namespace spirit {
20
21 BOOST_SPIRIT_CLASSIC_NAMESPACE_BEGIN
22
23 ///////////////////////////////////////////////////////////////////////////////
24 //
25 //  escape_char_parser class
26 //
27 ///////////////////////////////////////////////////////////////////////////////
28
29 const unsigned long c_escapes = 1;
30 const unsigned long lex_escapes = c_escapes << 1;
31
32 //////////////////////////////////
33 namespace 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 ///////////////////////////////////////////////////////////////////////////////
219 BOOST_SPIRIT_CLASSIC_NAMESPACE_END
220
221 }} // namespace boost::spirit
222
223 #endif
224