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>
|
|
11 /// Сканнер, разбивающий поток символов на токены JSON.
|
|
12 /// </summary>
|
|
13 public class JSONScanner : Scanner {
|
|
14 char[] m_stringBuffer;
|
|
15 DFAStateDescriptior[] m_stringDFA;
|
|
16 int[] m_stringAlphabet;
|
|
17
|
|
18 public JSONScanner()
|
|
19 : base(JSONGrammar.Instance.JsonDFA) {
|
|
20 m_stringBuffer = new char[1024];
|
|
21 var dfa = JSONGrammar.Instance.JsonStringDFA;
|
|
22 m_stringAlphabet = dfa.Alphabet.GetTranslationMap();
|
|
23 m_stringDFA = dfa.States;
|
|
24 }
|
|
25
|
|
26 public bool ReadToken(out object tokenValue, out JsonTokenType tokenType) {
|
|
27 if (ReadTokenInternal()) {
|
|
28 switch ((JSONGrammar.TokenType)m_currentState.tag[0]) {
|
|
29 case JSONGrammar.TokenType.StringBound:
|
|
30 tokenValue = ReadString();
|
|
31 tokenType = JsonTokenType.String;
|
|
32 break;
|
|
33 case JSONGrammar.TokenType.Number:
|
|
34 tokenValue = Double.Parse(new String(m_buffer, m_tokenOffset, m_tokenLen), CultureInfo.InvariantCulture);
|
|
35 tokenType = JsonTokenType.Number;
|
|
36 break;
|
|
37 default:
|
|
38 tokenType = (JsonTokenType)m_currentState.tag[0];
|
|
39 tokenValue = new String(m_buffer, m_tokenOffset, m_tokenLen);
|
|
40 break;
|
|
41 }
|
|
42 return true;
|
|
43 }
|
|
44 tokenValue = null;
|
|
45 tokenType = JsonTokenType.None;
|
|
46 return false;
|
|
47 }
|
|
48
|
|
49 string ReadString() {
|
|
50 int pos = 0;
|
|
51 Switch(m_stringDFA, m_stringAlphabet);
|
|
52 while (ReadTokenInternal()) {
|
|
53 switch ((JSONGrammar.TokenType)m_currentState.tag[0]) {
|
|
54 case JSONGrammar.TokenType.StringBound:
|
|
55 Restore();
|
|
56 return new String(m_stringBuffer, 0, pos);
|
|
57 case JSONGrammar.TokenType.UnescapedChar:
|
|
58 EnsureStringBufferSize(pos + m_tokenLen);
|
|
59 Array.Copy(m_buffer, m_tokenOffset, m_stringBuffer, pos, m_tokenLen);
|
|
60 pos += m_tokenLen;
|
|
61 break;
|
|
62 case JSONGrammar.TokenType.EscapedUnicode:
|
|
63 EnsureStringBufferSize(pos + 1);
|
|
64 m_stringBuffer[pos] = StringTranslator.TranslateHexUnicode(m_buffer, m_tokenOffset + 2);
|
|
65 pos++;
|
|
66 break;
|
|
67 case JSONGrammar.TokenType.EscapedChar:
|
|
68 EnsureStringBufferSize(pos + 1);
|
|
69 m_stringBuffer[pos] = StringTranslator.TranslateEscapedChar(m_buffer[m_tokenOffset + 1]);
|
|
70 pos++;
|
|
71 break;
|
|
72 default:
|
|
73 break;
|
|
74 }
|
|
75
|
|
76 }
|
|
77
|
|
78 throw new ParserException("Unexpected end of data");
|
|
79 }
|
|
80
|
|
81 void EnsureStringBufferSize(int size) {
|
|
82 if (size > m_stringBuffer.Length) {
|
|
83 var newBuffer = new char[size];
|
|
84 m_stringBuffer.CopyTo(newBuffer, 0);
|
|
85 m_stringBuffer = newBuffer;
|
|
86 }
|
|
87 }
|
|
88 }
|
|
89 }
|