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