1
2
3
4
5
6 #include <sngcpp/parser/TokenValueParsers.hpp>
7 #include <soulng/util/Unicode.hpp>
8 #include <sstream>
9
10 namespace sngcpp { namespace cppparser {
11
12 using namespace soulng::unicode;
13
14 void ParseFloatingLiteral(const std::string& fileName, const soulng::lexer::Token& token, double& value, sngcpp::ast::Suffix& suffix)
15 {
16 value = 0.0;
17 suffix = sngcpp::ast::Suffix::none;
18 const char32_t* p = token.match.begin;
19 const char32_t* e = token.match.end;
20 while (p != e && *p >= '0' && *p <= '9')
21 {
22 ++p;
23 }
24 if (p != e && *p == '.')
25 {
26 ++p;
27 }
28 while (p != e && *p >= '0' && *p <= '9')
29 {
30 ++p;
31 }
32 if (p != e&&( *p == 'e' || *p == 'E'))
33 {
34 ++p;
35 }
36 if (p != e&&( *p == '+' || *p == '-'))
37 {
38 ++p;
39 }
40 while (p != e && *p >= '0' && *p <= '9')
41 {
42 ++p;
43 }
44 if (p != e)
45 {
46 std::string s = ToUtf8(std::u32string(token.match.begin, p));
47 std::stringstream sstream;
48 sstream.str(s);
49 sstream >> value;
50 if (!sstream)
51 {
52 throw std::runtime_error("invalid floating point literal in '" + fileName + "' at line " + std::to_string(token.line) + ": " + ToUtf8(token.match.ToString()));
53 }
54 if (p != e&&( *p == 'f' || *p == 'F'))
55 {
56 suffix = sngcpp::ast::Suffix::f;
57 ++p;
58 }
59 else if (p != e&&( *p == 'l' || *p == 'L'))
60 {
61 suffix = sngcpp::ast::Suffix::l;
62 ++p;
63 }
64 }
65 if (p != e)
66 {
67 throw std::runtime_error("invalid floating point literal in '" + fileName + "' at line " + std::to_string(token.line) + ": " + ToUtf8(token.match.ToString()));
68 }
69 }
70
71 void ParseIntegerLiteral(const std::string& fileName, const soulng::lexer::Token& token, uint64_t& value, sngcpp::ast::Base& base, sngcpp::ast::Suffix& suffix)
72 {
73 value = 0;
74 base = sngcpp::ast::Base::decimal;
75 suffix = sngcpp::ast::Suffix::none;
76 const char32_t* p = token.match.begin;
77 const char32_t* e = token.match.end;
78 if (p != e && *p == '0')
79 {
80 base = sngcpp::ast::Base::octal;
81 ++p;
82 if (p != e&&( *p == 'x' || *p == 'X'))
83 {
84 base = sngcpp::ast::Base::hex;
85 ++p;
86 while (p != e&&( (*p >= '0' && *p <= '9') || (*p >= 'a' && *p <= 'f') || (*p >= 'A' && *p <= 'F')))
87 {
88 switch (*p)
89 {
90 case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
91 {
92 value = 16 * value + *p - '0';
93 break;
94 }
95 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
96 {
97 value = 16 * value + 10 + *p - 'A';
98 break;
99 }
100 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
101 {
102 value = 16 * value + 10 + *p - 'a';
103 break;
104 }
105 }
106 ++p;
107 }
108 }
109 else
110 {
111 while (p != e && *p >= '0' && *p <= '7')
112 {
113 value = 8 * value + *p - '0';
114 ++p;
115 }
116 }
117 }
118 else
119 {
120 base = sngcpp::ast::Base::decimal;
121 while (p != e && *p >= '0' && *p <= '9')
122 {
123 value = 10 * value + *p - '0';
124 ++p;
125 }
126 }
127 if (p != e&&( *p == 'u' || *p == 'U'))
128 {
129 suffix = sngcpp::ast::Suffix::u;
130 ++p;
131 }
132 if (p != e&&( *p == 'l' || *p == 'L'))
133 {
134 ++p;
135 if (p != e&&( *p == 'l' || *p == 'L'))
136 {
137 suffix = suffix | sngcpp::ast::Suffix::ll;
138 ++p;
139 }
140 else
141 {
142 suffix = suffix | sngcpp::ast::Suffix::l;
143 }
144 if (p != e&&( *p == 'u' || *p == 'U'))
145 {
146 suffix = suffix | sngcpp::ast::Suffix::u;
147 ++p;
148 }
149 }
150 if (p != e)
151 {
152 throw std::runtime_error("invalid integer literal in '" + fileName + "' at line " + std::to_string(token.line) + ": " + ToUtf8(token.match.ToString()));
153 }
154 }
155
156 void ParseHexChar(const std::string& fileName, const soulng::lexer::Token& token, const char32_t*& p, const char32_t* e, char32_t& value)
157 {
158 if (p != e&&( (*p >= '0' && *p <= '9') || (*p >= 'a' && *p <= 'f') || (*p >= 'A' && *p <= 'F')))
159 {
160 switch (*p)
161 {
162 case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
163 {
164 value = 16 * value + *p - '0';
165 break;
166 }
167 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
168 {
169 value = 16 * value + 10 + *p - 'A';
170 break;
171 }
172 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
173 {
174 value = 16 * value + 10 + *p - 'a';
175 break;
176 }
177 }
178 ++p;
179 }
180 else
181 {
182 throw std::runtime_error("hexadecimal character expected in '" + fileName + "' at line " + std::to_string(token.line) + ": " + ToUtf8(token.match.ToString()));
183 }
184 }
185
186 void ParseEscape(const std::string& fileName, const soulng::lexer::Token& token, const char32_t*& p, const char32_t* e, char32_t& value)
187 {
188 if (p != e && *p == '\\')
189 {
190 ++p;
191 if (p != e && *p == 'x')
192 {
193 ++p;
194 ParseHexChar(fileName, token, p, e, value);
195 ParseHexChar(fileName, token, p, e, value);
196 }
197 else if (p != e && *p == 'u')
198 {
199 ++p;
200 ParseHexChar(fileName, token, p, e, value);
201 ParseHexChar(fileName, token, p, e, value);
202 ParseHexChar(fileName, token, p, e, value);
203 ParseHexChar(fileName, token, p, e, value);
204 }
205 else if (p != e && *p == 'U')
206 {
207 ++p;
208 ParseHexChar(fileName, token, p, e, value);
209 ParseHexChar(fileName, token, p, e, value);
210 ParseHexChar(fileName, token, p, e, value);
211 ParseHexChar(fileName, token, p, e, value);
212 ParseHexChar(fileName, token, p, e, value);
213 ParseHexChar(fileName, token, p, e, value);
214 ParseHexChar(fileName, token, p, e, value);
215 ParseHexChar(fileName, token, p, e, value);
216 }
217 else if (p != e && *p >= '0' && *p <= '7')
218 {
219 value = *p - '0';
220 ++p;
221 if (p != e && *p >= '0' && *p <= '7')
222 {
223 value = 8 * value + *p - '0';
224 ++p;
225 if (p != e && *p >= '0' && *p <= '7')
226 {
227 value = 8 * value + *p - '0';
228 ++p;
229 }
230 }
231 }
232 else if (p != e)
233 {
234 switch (*p)
235 {
236 case 'a': value = '\a'; ++p; break;
237 case 'b': value = '\b'; ++p; break;
238 case 'f': value = '\f'; ++p; break;
239 case 'n': value = '\n'; ++p; break;
240 case 'r': value = '\r'; ++p; break;
241 case 't': value = '\t'; ++p; break;
242 case 'v': value = '\v'; ++p; break;
243 case '\\': value = '\\'; ++p; break;
244 case '?': value = '?'; ++p; break;
245 default: value = *p; ++p; break;
246 }
247 }
248 }
249 else
250 {
251 throw std::runtime_error("invalid escape in '" + fileName + "' at line " + std::to_string(token.line) + ": " + ToUtf8(token.match.ToString()));
252 }
253 }
254
255 void ParseCharacterLiteral(const std::string& fileName, const soulng::lexer::Token& token, char32_t& value, char32_t& prefix)
256 {
257 value = '\0';
258 prefix = '\0';
259 const char32_t* p = token.match.begin;
260 const char32_t* e = token.match.end;
261 if (p != e && *p == 'u')
262 {
263 prefix = *p;
264 ++p;
265 }
266 else if (p != e && *p == 'U')
267 {
268 prefix = *p;
269 ++p;
270 }
271 else if (p != e && *p == 'L')
272 {
273 prefix = *p;
274 ++p;
275 }
276 if (p != e && *p == '\'')
277 {
278 ++p;
279 if (p != e && *p == '\\')
280 {
281 ParseEscape(fileName, token, p, e, value);
282 }
283 else if (p != e)
284 {
285 value = *p;
286 ++p;
287 }
288 if (p != e && *p == '\'')
289 {
290 ++p;
291 }
292 if (p != e)
293 {
294 throw std::runtime_error("invalid character literal in '" + fileName + "' at line " + std::to_string(token.line) + ": " + ToUtf8(token.match.ToString()));
295 }
296 }
297 else
298 {
299 throw std::runtime_error("invalid character literal in '" + fileName + "' at line " + std::to_string(token.line) + ": " + ToUtf8(token.match.ToString()));
300 }
301 }
302
303 void ParseStringLiteral(const std::string& fileName, const soulng::lexer::Token& token, std::u32string& encodingPrefix, std::u32string& value)
304 {
305 encodingPrefix.clear();
306 value.clear();
307 const char32_t* p = token.match.begin;
308 const char32_t* e = token.match.end;
309 if (p != e && *p == 'u')
310 {
311 ++p;
312 if (p != e && *p == '8')
313 {
314 ++p;
315 encodingPrefix = U"u8";
316 }
317 else
318 {
319 encodingPrefix = U"u";
320 }
321 }
322 else if (p != e && *p == 'U')
323 {
324 ++p;
325 encodingPrefix = U"U";
326 }
327 else if (p != e && *p == 'L')
328 {
329 ++p;
330 encodingPrefix = U"L";
331 }
332 if (p != e && *p == 'R')
333 {
334 ++p;
335 if (p != e && *p == '"')
336 {
337 ++p;
338 while (p != e && *p != '"')
339 {
340 value.append(1, *p);
341 ++p;
342 }
343 if (p != e && *p == '"')
344 {
345 ++p;
346 }
347 if (p != e)
348 {
349 throw std::runtime_error("invalid string literal in '" + fileName + "' at line " + std::to_string(token.line) + ": " + ToUtf8(token.match.ToString()));
350 }
351 }
352 else
353 {
354 throw std::runtime_error("invalid string literal in '" + fileName + "' at line " + std::to_string(token.line) + ": " + ToUtf8(token.match.ToString()));
355 }
356 }
357 else if (p != e && *p == '"')
358 {
359 ++p;
360 while (p != e && *p != '"')
361 {
362 if (*p == '\\')
363 {
364 char32_t c = '\0';
365 ParseEscape(fileName, token, p, e, c);
366 value.append(1, c);
367 }
368 else
369 {
370 value.append(1, *p);
371 ++p;
372 }
373 }
374 if (p != e && *p == '"')
375 {
376 ++p;
377 }
378 if (p != e)
379 {
380 throw std::runtime_error("invalid string literal in '" + fileName + "' at line " + std::to_string(token.line) + ": " + ToUtf8(token.match.ToString()));
381 }
382 }
383 else
384 {
385 throw std::runtime_error("invalid string literal in '" + fileName + "' at line " + std::to_string(token.line) + ": " + ToUtf8(token.match.ToString()));
386 }
387 }
388
389 } }