1 using System;
2 using System.Collections;
3 using System.IO;
4
5
6
7
8
9 namespace soulcm.scmpg
10 {
11 public const int noPrefix = 0;
12 public const int utf16Prefix = 1;
13 public const int utf32Prefix = 2;
14 public void ParseHexChar(const string& fileName, uchar& value, const uchar*& p, const uchar* e, const System.Lex.Token& token)
15 {
16 if (p != e)
17 {
18 switch (cast<uchar>(*p))
19 {
20 case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
21 {
22 value = cast<uchar>(16 * cast<int>(value) + cast<int>(*p) - cast<int>('0'));
23 break;
24 }
25 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
26 {
27 value = cast<uchar>(16 * cast<int>(value) + 10 + cast<int>(*p) - cast<int>('A'));
28 break;
29 }
30 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
31 {
32 value = cast<uchar>(16 * cast<int>(value) + 10 + cast<int>(*p) - cast<int>('a'));
33 break;
34 }
35 }
36 ++p;
37 }
38 else
39 {
40 throw Exception("hex character expected at " + fileName + ":" + ToString(token.line) + ": " + ToUtf8(token.match.ToString()));
41 }
42 }
43 public uchar ParseEscape(const string& fileName, const uchar*& p, const uchar* e, const System.Lex.Token& token)
44 {
45 uchar 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 = cast<uchar>(10 * cast<int>(value) + (cast<int>(*p) - cast<int>('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 = cast<uchar>(8 * cast<int>(value) + (cast<int>(*p) - cast<int>('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 (cast<uchar>(*p))
94 {
95 case 'a': value = '\a';
96 break;
97 case 'b': value = '\b';
98 break;
99 case 'f': value = '\f';
100 break;
101 case 'n': value = '\n';
102 break;
103 case 'r': value = '\r';
104 break;
105 case 't': value = '\t';
106 break;
107 case 'v': value = '\v';
108 break;
109 default: value = *p;
110 break;
111 }
112 ++p;
113 }
114 return value;
115 }
116 public void ParseFloatingLiteral(const string& fileName, const System.Lex.Token& token, double& floatingLit, bool& floatingLitFloat)
117 {
118 floatingLit = 0.000000;
119 floatingLitFloat = false;
120 const uchar* p = token.match.begin;
121 const uchar* e = token.match.end;
122 string str;
123 while (p != e && ((*p >= '0' && *p <= '9') || *p == '.' || *p == 'e' || *p == 'E' || *p == '-' || *p == '+'))
124 {
125 str.Append(cast<char>(*p), 1);
126 ++p;
127 }
128 if (p != e && (*p == 'f' || *p == 'F'))
129 {
130 ++p;
131 floatingLitFloat = true;
132 }
133 if (p != e)
134 {
135 throw Exception("invalid floating literal at " + fileName + ":" + ToString(token.line) + ": " + ToUtf8(ustring(token.match.begin, token.match.end)));
136 }
137 if (floatingLitFloat) floatingLit = ParseFloat(str); else floatingLit = ParseDouble(str);
138 }
139 public void ParseIntegerLiteral(const string& fileName, const System.Lex.Token& token, ulong& intLit, bool& intLitUnsigned)
140 {
141 intLit = 0u;
142 intLitUnsigned = false;
143 const uchar* p = token.match.begin;
144 const uchar* e = token.match.end;
145 if (p != e && *p == '0')
146 {
147 ++p;
148 if (p != e && (*p == 'x' || *p == 'X'))
149 {
150 ++p;
151 while (p != e && ((*p >= '0' && *p <= '9') || (*p >= 'a' && *p <= 'f') || (*p >= 'A' && *p <= 'F')))
152 {
153 switch (cast<uchar>(*p))
154 {
155 case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
156 {
157 intLit = 16u * intLit + cast<ulong>(*p) - cast<ulong>('0');
158 break;
159 }
160 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
161 {
162 intLit = 16u * intLit + 10u + cast<ulong>(*p) - cast<ulong>('A');
163 break;
164 }
165 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
166 {
167 intLit = 16u * intLit + 10u + cast<ulong>(*p) - cast<ulong>('a');
168 break;
169 }
170 }
171 ++p;
172 }
173 }
174 else
175 {
176 while (p != e && *p >= '0' && *p <= '7')
177 {
178 intLit = 8u * intLit + (cast<ulong>(*p) - cast<ulong>('0'));
179 ++p;
180 }
181 }
182 }
183 else if (p != e && *p >= '1' && *p <= '9')
184 {
185 while (p != e && *p >= '0' && *p <= '9')
186 {
187 intLit = 10u * intLit + (cast<ulong>(*p) - cast<ulong>('0'));
188 ++p;
189 }
190 }
191 else
192 {
193 throw Exception("invalid integer literal at " + fileName + ":" + ToString(token.line) + ": " + ToUtf8(ustring(token.match.begin, token.match.end)));
194 }
195 if (p != e && (*p == 'u' || *p == 'U'))
196 {
197 ++p;
198 intLitUnsigned = true;
199 }
200 if (p != e)
201 {
202 throw Exception("invalid integer literal at " + fileName + ":" + ToString(token.line) + ": " + ToUtf8(ustring(token.match.begin, token.match.end)));
203 }
204 }
205 public void ParseCharacterLiteral(const string& fileName, const System.Lex.Token& token, uchar& charLit, int& charLitPrefix)
206 {
207 charLit = '\0';
208 charLitPrefix = noPrefix;
209 const uchar* p = token.match.begin;
210 const uchar* e = token.match.end;
211 if (p != e && *p == 'w')
212 {
213 charLitPrefix = utf16Prefix;
214 ++p;
215 }
216 else if (p != e && *p == 'u')
217 {
218 charLitPrefix = utf32Prefix;
219 ++p;
220 }
221 if (p != e && *p == '\'')
222 {
223 ++p;
224 if (p != e && *p == '\\')
225 {
226 ++p;
227 charLit = ParseEscape(fileName, p, e, token);
228 }
229 else
230 {
231 string s;
232 while (p != e && *p != '\r' && *p != '\n' && *p != '\'')
233 {
234 s.Append(cast<char>(*p), 1);
235 ++p;
236 }
237 ustring u = ToUtf32(s);
238 if (u.Length() != 1)
239 {
240 throw Exception("invalid character literal at " + fileName + ":" + ToString(token.line) + ": " + ToUtf8(ustring(token.match.begin, token.match.end)));
241 }
242 charLit = u[0];
243 }
244 if (p != e && *p == '\'')
245 {
246 ++p;
247 }
248 if (p != e)
249 {
250 throw Exception("invalid character literal at " + fileName + ":" + ToString(token.line) + ": " + ToUtf8(ustring(token.match.begin, token.match.end)));
251 }
252 }
253 else
254 {
255 throw Exception("invalid character literal at " + fileName + ":" + ToString(token.line) + ": " + ToUtf8(ustring(token.match.begin, token.match.end)));
256 }
257 }
258 public void ParseStringLiteral(const string& fileName, const System.Lex.Token& token, ustring& stringLit, int& stringLitPrefix)
259 {
260 stringLit.Clear();
261 stringLitPrefix = noPrefix;
262 const uchar* p = token.match.begin;
263 const uchar* e = token.match.end;
264 if (p != e && *p == 'w')
265 {
266 stringLitPrefix = utf16Prefix;
267 ++p;
268 }
269 else if (p != e && *p == 'u')
270 {
271 stringLitPrefix = utf32Prefix;
272 ++p;
273 }
274 if (p != e && *p == '@')
275 {
276 ++p;
277 if (p != e && *p == '\"')
278 {
279 ++p;
280 while (p != e && *p != '\"')
281 {
282 stringLit.Append(*p, 1);
283 ++p;
284 }
285 if (p != e && *p == '\"')
286 {
287 ++p;
288 }
289 if (p != e)
290 {
291 throw Exception("invalid string literal at " + fileName + ":" + ToString(token.line) + ": " + ToUtf8(ustring(token.match.begin, token.match.end)));
292 }
293 }
294 }
295 else
296 {
297 if (p != e && *p == '\"')
298 {
299 ++p;
300 while (p != e && *p != '\r' && *p != '\n' && *p != '\"')
301 {
302 if (*p == '\\')
303 {
304 ++p;
305 stringLit.Append(ParseEscape(fileName, p, e, token), 1);
306 }
307 else
308 {
309 stringLit.Append(*p, 1);
310 ++p;
311 }
312 }
313 if (p != e && *p == '\"')
314 {
315 ++p;
316 }
317 if (p != e)
318 {
319 throw Exception("invalid string literal at " + fileName + ":" + ToString(token.line) + ": " + ToUtf8(ustring(token.match.begin, token.match.end)));
320 }
321 }
322 else
323 {
324 throw Exception("invalid string literal at " + fileName + ":" + ToString(token.line) + ": " + ToUtf8(ustring(token.match.begin, token.match.end)));
325 }
326 }
327 }
328 public string MakeFilePath(const string& fileName, const System.Lex.Token& token)
329 {
330 ustring s;
331 const uchar* p = token.match.begin;
332 const uchar* e = token.match.end;
333 if (p != e && *p == '<')
334 {
335 ++p;
336 }
337 while (p != e && *p != '>')
338 {
339 s.Append(*p, 1);
340 ++p;
341 }
342 if (p != e && *p == '>')
343 {
344 ++p;
345 }
346 if (p != e)
347 {
348 throw Exception("invalid file path at " + fileName + ":" + ToString(token.line) + " : \'" + ToUtf8(token.match.ToString()) + "\'");
349 }
350 return ToUtf8(s);
351 }
352 public ustring ParseStringLiteral(const string& fileName, const System.Lex.Token& token)
353 {
354 ustring stringLiteral;
355 const uchar* p = token.match.begin;
356 const uchar* e = token.match.end;
357 if (p != e && *p == '\"')
358 {
359 ++p;
360 while (p != e && *p != '\r' && *p != '\n' && *p != '\"')
361 {
362 if (*p == '\\')
363 {
364 ++p;
365 stringLiteral.Append(ParseEscape(fileName, p, e, token), 1);
366 }
367 else
368 {
369 stringLiteral.Append(*p, 1);
370 ++p;
371 }
372 }
373 if (p != e && *p == '\"')
374 {
375 ++p;
376 }
377 if (p != e)
378 {
379 throw Exception("invalid string literal at " + fileName + ":" + ToString(token.line) + ": " + ToUtf8(token.match.ToString()));
380 }
381 }
382 else
383 {
384 throw Exception("invalid string literal at " + fileName + ":" + ToString(token.line) + ": " + ToUtf8(token.match.ToString()));
385 }
386 return stringLiteral;
387 }
388 public uchar ParseCharLiteral(const string& fileName, const System.Lex.Token& token)
389 {
390 uchar charLit = '\0';
391 const uchar* p = token.match.begin;
392 const uchar* e = token.match.end;
393 bool first = true;
394 if (p != e && *p == '\'')
395 {
396 ++p;
397 while (p != e && *p != '\r' && *p != '\n' && *p != '\'')
398 {
399 if (*p == '\\')
400 {
401 ++p;
402 if (first)
403 {
404 charLit = ParseEscape(fileName, p, e, token);
405 first = false;
406 }
407 else
408 {
409 throw Exception("invalid character literal at " + fileName + ":" + ToString(token.line) + ": " + ToUtf8(token.match.ToString()));
410 }
411 }
412 else
413 {
414 if (first)
415 {
416 charLit = *p;
417 first = false;
418 }
419 else
420 {
421 throw Exception("invalid character literal at " + fileName + ":" + ToString(token.line) + ": " + ToUtf8(token.match.ToString()));
422 }
423 ++p;
424 }
425 }
426 if (p != e && *p == '\'')
427 {
428 ++p;
429 }
430 if (p != e)
431 {
432 throw Exception("invalid character literal at " + fileName + ":" + ToString(token.line) + ": " + ToUtf8(token.match.ToString()));
433 }
434 }
435 else
436 {
437 throw Exception("invalid character literal at " + fileName + ":" + ToString(token.line) + ": " + ToUtf8(token.match.ToString()));
438 }
439 return charLit;
440 }
441 public CharSet ParseCharSet(const string& fileName, const System.Lex.Token& token, const ustring& str)
442 {
443 CharSet set;
444 const uchar* p = str.Chars();
445 const uchar* e = str.Chars() + str.Length();
446 bool inverse = false;
447 if (p != e && *p == '[')
448 {
449 ++p;
450 if (p != e && *p == '^')
451 {
452 set.SetInverse();
453 ++p;
454 }
455 while (p != e - 1)
456 {
457 uchar first = *p;
458 ++p;
459 uchar last = first;
460 if (p != e - 1)
461 {
462 if (*p == '-')
463 {
464 ++p;
465 if (p != e - 1)
466 {
467 last = *p;
468 ++p;
469 }
470 else
471 {
472 System.Parsing.Range range;
473 range.first = cast<int>(first);
474 range.last = cast<int>(first);
475 set.AddRange(range);
476 first = '-';
477 last = '-';
478 }
479 }
480 }
481 System.Parsing.Range range;
482 range.first = cast<int>(first);
483 range.last = cast<int>(last);
484 set.AddRange(range);
485 }
486 if (p != e && *p == ']')
487 {
488 ++p;
489 }
490 if (p != e)
491 {
492 throw Exception("invalid character set literal at " + fileName + ":" + ToString(token.line) + ": " + ToUtf8(token.match.ToString()));
493 }
494 }
495 else
496 {
497 throw Exception("invalid character set literal at " + fileName + ":" + ToString(token.line) + ": " + ToUtf8(token.match.ToString()));
498 }
499 return set;
500 }
501 }