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 }