1
2
3
4
5
6 #include <sng2html/sng2html/TokenValueParsers.hpp>
7 #include <soulng/util/Unicode.hpp>
8
9 namespace sng2html { namespace sng2html {
10
11 using namespace soulng::unicode;
12
13 void ParseHexChar(const std::string& fileName, char32_t& value, const char32_t*& p, const char32_t* e, const soulng::lexer::Token& token)
14 {
15 if (p != e)
16 {
17 switch (*p)
18 {
19 case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
20 {
21 value = 16 * value + *p - '0';
22 break;
23 }
24 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
25 {
26 value = 16 * value + 10 + *p - 'A';
27 break;
28 }
29 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
30 {
31 value = 16 * value + 10 + *p - 'a';
32 break;
33 }
34 }
35 ++p;
36 }
37 else
38 {
39 throw std::runtime_error("hex character expected at " + fileName + ":" + std::to_string(token.line) + ": " + ToUtf8(token.match.ToString()));
40 }
41 }
42
43 char32_t ParseEscape(const std::string& fileName, const char32_t*& p, const char32_t* e, const soulng::lexer::Token& token)
44 {
45 char32_t value = '\0';
46 if (p != e&&( *p == 'x' || *p == 'X'))
47 {
48 ++p;
49 while (p != e&&( (*p >= '0' && *p <= '9') || (*p >= 'a' && *p <= 'f') || (*p >= 'A' && *p <= 'F')))
50 {
51 ParseHexChar(fileName, value, p, e, token);
52 }
53 }
54 else if (p != e&&( *p == 'd' || *p == 'D'))
55 {
56 ++p;
57 while (p != e && *p >= '0' && *p <= '9')
58 {
59 value = 10 * value + (*p - '0');
60 ++p;
61 }
62 }
63 else if (p != e&&( *p >= '0' && *p <= '7'))
64 {
65 while (p != e && *p >= '0' && *p <= '7')
66 {
67 value = 8 * value + (*p - '0');
68 ++p;
69 }
70 }
71 else if (p != e && *p == 'u')
72 {
73 ++p;
74 ParseHexChar(fileName, value, p, e, token);
75 ParseHexChar(fileName, value, p, e, token);
76 ParseHexChar(fileName, value, p, e, token);
77 ParseHexChar(fileName, value, p, e, token);
78 }
79 else if (p != e && *p == 'U')
80 {
81 ++p;
82 ParseHexChar(fileName, value, p, e, token);
83 ParseHexChar(fileName, value, p, e, token);
84 ParseHexChar(fileName, value, p, e, token);
85 ParseHexChar(fileName, value, p, e, token);
86 ParseHexChar(fileName, value, p, e, token);
87 ParseHexChar(fileName, value, p, e, token);
88 ParseHexChar(fileName, value, p, e, token);
89 ParseHexChar(fileName, value, p, e, token);
90 }
91 else if (p != e)
92 {
93 switch (*p)
94 {
95 case 'a': value = '\a'; break;
96 case 'b': value = '\b'; break;
97 case 'f': value = '\f'; break;
98 case 'n': value = '\n'; break;
99 case 'r': value = '\r'; break;
100 case 't': value = '\t'; break;
101 case 'v': value = '\v'; break;
102 default: value = *p; break;
103 }
104 ++p;
105 }
106 return value;
107 }
108
109 std::u32string MakeStrValue(const std::string& fileName, const soulng::lexer::Token& token)
110 {
111 std::u32string strValue;
112 const char32_t* p = token.match.begin;
113 const char32_t* e = token.match.end;
114 if (p != e && *p == '"')
115 {
116 ++p;
117 }
118 while (p != e && *p != '\r' && *p != '\n' && *p != '"')
119 {
120 if (*p == '\\')
121 {
122 ++p;
123 strValue.append(1, ParseEscape(fileName, p, e, token));
124 }
125 else
126 {
127 strValue.append(1, *p);
128 ++p;
129 }
130 }
131 if (p != e && *p == '"')
132 {
133 ++p;
134 }
135 if (p != e)
136 {
137 throw std::runtime_error("invalid string literal at " + fileName + ":" + std::to_string(token.line) + ": " + ToUtf8(token.match.ToString()));
138 }
139 return strValue;
140 }
141
142 std::u32string MakeExprStringValue(const std::string& fileName, const soulng::lexer::Token& token)
143 {
144 std::u32string strValue;
145 const char32_t* p = token.match.begin;
146 const char32_t* e = token.match.end;
147 if (p != e && *p == '"')
148 {
149 ++p;
150 }
151 while (p != e && *p != '\r' && *p != '\n' && *p != '"')
152 {
153 if (*p == '\\')
154 {
155 ++p;
156 if (p != e && *p == '"')
157 {
158 strValue.append(1, '"');
159 ++p;
160 }
161 else
162 {
163 strValue.append(1, '\\');
164 strValue.append(1, *p);
165 ++p;
166 }
167 }
168 else
169 {
170 strValue.append(1, *p);
171 ++p;
172 }
173 }
174 if (p != e && *p == '"')
175 {
176 ++p;
177 }
178 if (p != e)
179 {
180 throw std::runtime_error("invalid expression string literal at " + fileName + ":" + std::to_string(token.line) + ": " + ToUtf8(token.match.ToString()));
181 }
182 return strValue;
183 }
184
185 std::u32string MakePathValue(const std::string& fileName, const soulng::lexer::Token& token)
186 {
187 std::u32string pathValue;
188 const char32_t* p = token.match.begin;
189 const char32_t* e = token.match.end;
190 if (p != e && *p == '<')
191 {
192 ++p;
193 }
194 while (p != e && *p != '\r' && *p != '\n' && *p != '>')
195 {
196 pathValue.append(1, *p);
197 ++p;
198 }
199 if (p != e && *p == '>')
200 {
201 ++p;
202 }
203 if (p != e)
204 {
205 throw std::runtime_error("invalid path literal at " + fileName + ":" + std::to_string(token.line) + ": " + ToUtf8(token.match.ToString()));
206 }
207 return pathValue;
208 }
209
210 int MakeActionIntValue(const std::string& fileName, const soulng::lexer::Token& token)
211 {
212 int actionIntValue = 0;
213 const char32_t* p = token.match.begin;
214 const char32_t* e = token.match.end;
215 if (p == e)
216 {
217 throw std::runtime_error("invalid action integer value at " + fileName + ":" + std::to_string(token.line) + ": " + ToUtf8(token.match.ToString()));
218 }
219 while (p != e && *p >= '0' && *p <= '9')
220 {
221 actionIntValue = 10 * actionIntValue + (*p - '0');
222 ++p;
223 }
224 if (p != e)
225 {
226 throw std::runtime_error("invalid action integer value at " + fileName + ":" + std::to_string(token.line) + ": " + ToUtf8(token.match.ToString()));
227 }
228 return actionIntValue;
229 }
230
231 std::u32string MakeExprRefId(const std::string& fileName, const std::u32string& match, int line)
232 {
233 std::u32string exprRefId;
234 const char32_t* p = match.c_str();
235 const char32_t* e = match.c_str() + match.length();
236 if (p != e && *p == '{')
237 {
238 ++p;
239 }
240 while (p != e && *p != '\r' && *p != '\n' && *p != '}')
241 {
242 exprRefId.append(1, *p);
243 ++p;
244 }
245 if (p != e && *p == '}')
246 {
247 ++p;
248 }
249 if (p != e)
250 {
251 throw std::runtime_error("invalid expression reference at " + fileName + ":" + std::to_string(line) + ": " + ToUtf8(match));
252 }
253 return exprRefId;
254 }
255
256 char32_t MakeEscapeValue(const std::string& fileName, const soulng::lexer::Token& token)
257 {
258 char32_t escapeValue = '\0';
259 const char32_t* p = token.match.begin;
260 const char32_t* e = token.match.end;
261 if (p != e && *p == '\\')
262 {
263 ++p;
264 }
265 escapeValue = ParseEscape(fileName, p, e, token);
266 if (p != e)
267 {
268 throw std::runtime_error("invalid escape at " + fileName + ":" + std::to_string(token.line) + ": " + ToUtf8(token.match.ToString()));
269 }
270 return escapeValue;
271 }
272
273 std::string MakeFilePath(const std::string& fileName, const soulng::lexer::Token& token)
274 {
275 std::u32string s;
276 const char32_t* p = token.match.begin;
277 const char32_t* e = token.match.end;
278 if (p != e && *p == '<')
279 {
280 ++p;
281 }
282 while (p != e && *p != '>')
283 {
284 s.append(1, *p);
285 ++p;
286 }
287 if (p != e && *p == '>')
288 {
289 ++p;
290 }
291 if (p != e)
292 {
293 throw std::runtime_error("invalid file path at " + fileName + ":" + std::to_string(token.line) + " : '" + ToUtf8(token.match.ToString()) + "'");
294 }
295 return ToUtf8(s);
296 }
297
298 std::u32string ParseStringLiteral(const std::string& fileName, const soulng::lexer::Token& token)
299 {
300 std::u32string stringLiteral;
301 const char32_t* p = token.match.begin;
302 const char32_t* e = token.match.end;
303 if (p != e && *p == '"')
304 {
305 ++p;
306 while (p != e && *p != '\r' && *p != '\n' && *p != '"')
307 {
308 if (*p == '\\')
309 {
310 ++p;
311 stringLiteral.append(1, ParseEscape(fileName, p, e, token));
312 }
313 else
314 {
315 stringLiteral.append(1, *p);
316 ++p;
317 }
318 }
319 if (p != e && *p == '"')
320 {
321 ++p;
322 }
323 if (p != e)
324 {
325 throw std::runtime_error("invalid string literal at " + fileName + ":" + std::to_string(token.line) + ": " + ToUtf8(token.match.ToString()));
326 }
327 }
328 else
329 {
330 throw std::runtime_error("invalid string literal at " + fileName + ":" + std::to_string(token.line) + ": " + ToUtf8(token.match.ToString()));
331 }
332 return stringLiteral;
333 }
334
335 char32_t ParseCharLiteral(const std::string& fileName, const soulng::lexer::Token& token)
336 {
337 char32_t charLit = '\0';
338 const char32_t* p = token.match.begin;
339 const char32_t* e = token.match.end;
340 bool first = true;
341 if (p != e && *p == '\'')
342 {
343 ++p;
344 while (p != e && *p != '\r' && *p != '\n' && *p != '\'')
345 {
346 if (*p == '\\')
347 {
348 ++p;
349 if (first)
350 {
351 charLit = ParseEscape(fileName, p, e, token);
352 first = false;
353 }
354 else
355 {
356 throw std::runtime_error("invalid character literal at " + fileName + ":" + std::to_string(token.line) + ": " + ToUtf8(token.match.ToString()));
357 }
358 }
359 else
360 {
361 if (first)
362 {
363 charLit = *p;
364 first = false;
365 }
366 else
367 {
368 throw std::runtime_error("invalid character literal at " + fileName + ":" + std::to_string(token.line) + ": " + ToUtf8(token.match.ToString()));
369 }
370 ++p;
371 }
372 }
373 if (p != e && *p == '\'')
374 {
375 ++p;
376 }
377 if (p != e)
378 {
379 throw std::runtime_error("invalid character literal at " + fileName + ":" + std::to_string(token.line) + ": " + ToUtf8(token.match.ToString()));
380 }
381 }
382 else
383 {
384 throw std::runtime_error("invalid character literal at " + fileName + ":" + std::to_string(token.line) + ": " + ToUtf8(token.match.ToString()));
385 }
386 return charLit;
387 }
388
389 CharSet ParseCharSet(const std::string& fileName, const soulng::lexer::Token& token, const std::u32string& str)
390 {
391 CharSet set;
392 const char32_t* p = str.c_str();
393 const char32_t* e = str.c_str() + str.length();
394 bool inverse = false;
395 if (p != e && *p == '[')
396 {
397 ++p;
398 if (p != e && *p == '^')
399 {
400 set.SetInverse();
401 ++p;
402 }
403 while (p != e && *p != ']')
404 {
405 char32_t first = *p;
406 char32_t last = first;
407 ++p;
408 if (p != e && *p != ']')
409 {
410 if (*p == '-')
411 {
412 ++p;
413 if (p != e && *p != ']')
414 {
415 last = *p;
416 ++p;
417 }
418 else
419 {
420 soulng::parser::Range range;
421 range.first = first;
422 range.last = first;
423 set.AddRange(range);
424 first = '-';
425 last = '-';
426 }
427 }
428 }
429 soulng::parser::Range range;
430 range.first = first;
431 range.last = last;
432 set.AddRange(range);
433 }
434 if (p != e && *p == ']')
435 {
436 ++p;
437 }
438 if (p != e)
439 {
440 throw std::runtime_error("invalid character set literal at " + fileName + ":" + std::to_string(token.line) + ": " + ToUtf8(token.match.ToString()));
441 }
442 }
443 else
444 {
445 throw std::runtime_error("invalid character set literal at " + fileName + ":" + std::to_string(token.line) + ": " + ToUtf8(token.match.ToString()));
446 }
447 return set;
448 }
449
450
451 } }