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