55
|
1 using Implab.Parsing;
|
|
2 using System;
|
|
3 using System.Collections.Generic;
|
|
4 using System.Globalization;
|
|
5 using System.Linq;
|
|
6 using System.Text;
|
|
7 using System.Threading.Tasks;
|
|
8
|
|
9 namespace Implab.JSON {
|
|
10 /// <summary>
|
60
|
11 /// Сканнер (лексер), разбивающий поток символов на токены JSON.
|
55
|
12 /// </summary>
|
|
13 public class JSONScanner : Scanner {
|
|
14 char[] m_stringBuffer;
|
|
15 DFAStateDescriptior[] m_stringDFA;
|
|
16 int[] m_stringAlphabet;
|
|
17
|
60
|
18 /// <summary>
|
|
19 /// Создает новый экземпляр сканнера
|
|
20 /// </summary>
|
55
|
21 public JSONScanner()
|
|
22 : base(JSONGrammar.Instance.JsonDFA) {
|
|
23 m_stringBuffer = new char[1024];
|
|
24 var dfa = JSONGrammar.Instance.JsonStringDFA;
|
|
25 m_stringAlphabet = dfa.Alphabet.GetTranslationMap();
|
|
26 m_stringDFA = dfa.States;
|
|
27 }
|
|
28
|
60
|
29 /// <summary>
|
|
30 /// Читает следующий лексический элемент из входных данных.
|
|
31 /// </summary>
|
|
32 /// <param name="tokenValue">Возвращает значение прочитанного токена.</param>
|
|
33 /// <param name="tokenType">Возвращает тип прочитанного токена.</param>
|
|
34 /// <returns><c>true</c> - чтение произведено успешно. <c>false</c> - достигнут конец входных данных</returns>
|
|
35 /// <remarks>В случе если токен не распознается, возникает исключение. Значения токенов обрабатываются, т.е.
|
|
36 /// в строках обрабатываются экранированные символы, числа становтся типа double.</remarks>
|
55
|
37 public bool ReadToken(out object tokenValue, out JsonTokenType tokenType) {
|
|
38 if (ReadTokenInternal()) {
|
|
39 switch ((JSONGrammar.TokenType)m_currentState.tag[0]) {
|
|
40 case JSONGrammar.TokenType.StringBound:
|
|
41 tokenValue = ReadString();
|
|
42 tokenType = JsonTokenType.String;
|
|
43 break;
|
|
44 case JSONGrammar.TokenType.Number:
|
|
45 tokenValue = Double.Parse(new String(m_buffer, m_tokenOffset, m_tokenLen), CultureInfo.InvariantCulture);
|
|
46 tokenType = JsonTokenType.Number;
|
|
47 break;
|
|
48 default:
|
|
49 tokenType = (JsonTokenType)m_currentState.tag[0];
|
|
50 tokenValue = new String(m_buffer, m_tokenOffset, m_tokenLen);
|
|
51 break;
|
|
52 }
|
|
53 return true;
|
|
54 }
|
|
55 tokenValue = null;
|
|
56 tokenType = JsonTokenType.None;
|
|
57 return false;
|
|
58 }
|
|
59
|
|
60 string ReadString() {
|
|
61 int pos = 0;
|
|
62 Switch(m_stringDFA, m_stringAlphabet);
|
|
63 while (ReadTokenInternal()) {
|
|
64 switch ((JSONGrammar.TokenType)m_currentState.tag[0]) {
|
|
65 case JSONGrammar.TokenType.StringBound:
|
|
66 Restore();
|
|
67 return new String(m_stringBuffer, 0, pos);
|
|
68 case JSONGrammar.TokenType.UnescapedChar:
|
|
69 EnsureStringBufferSize(pos + m_tokenLen);
|
|
70 Array.Copy(m_buffer, m_tokenOffset, m_stringBuffer, pos, m_tokenLen);
|
|
71 pos += m_tokenLen;
|
|
72 break;
|
|
73 case JSONGrammar.TokenType.EscapedUnicode:
|
|
74 EnsureStringBufferSize(pos + 1);
|
|
75 m_stringBuffer[pos] = StringTranslator.TranslateHexUnicode(m_buffer, m_tokenOffset + 2);
|
|
76 pos++;
|
|
77 break;
|
|
78 case JSONGrammar.TokenType.EscapedChar:
|
|
79 EnsureStringBufferSize(pos + 1);
|
|
80 m_stringBuffer[pos] = StringTranslator.TranslateEscapedChar(m_buffer[m_tokenOffset + 1]);
|
|
81 pos++;
|
|
82 break;
|
|
83 default:
|
|
84 break;
|
|
85 }
|
|
86
|
|
87 }
|
|
88
|
|
89 throw new ParserException("Unexpected end of data");
|
|
90 }
|
|
91
|
|
92 void EnsureStringBufferSize(int size) {
|
|
93 if (size > m_stringBuffer.Length) {
|
|
94 var newBuffer = new char[size];
|
|
95 m_stringBuffer.CopyTo(newBuffer, 0);
|
|
96 m_stringBuffer = newBuffer;
|
|
97 }
|
|
98 }
|
|
99 }
|
|
100 }
|