Mercurial > pub > ImplabNet
comparison Implab/Formats/JSON/JSONScanner.cs @ 163:419aa51b04fd ref20160224
JSON moved to Formats namespace
Working in RegularDFA
author | cin |
---|---|
date | Wed, 24 Feb 2016 20:12:52 +0300 |
parents | |
children | e227e78d72e4 |
comparison
equal
deleted
inserted
replaced
162:0526412bbb26 | 163:419aa51b04fd |
---|---|
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 /// <summary> | |
19 /// Создает новый экземпляр сканнера | |
20 /// </summary> | |
21 public JSONScanner() | |
22 : base(JSONGrammar.Instance.JsonDFA.States, JSONGrammar.Instance.JsonDFA.Alphabet.GetTranslationMap()) { | |
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 | |
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> | |
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 } |