comparison Implab/Formats/JSON/JSONScanner.cs @ 176:0c3c69fe225b ref20160224

rewritten the text scanner
author cin
date Tue, 22 Mar 2016 18:58:40 +0300
parents e227e78d72e4
children a0ff6a0e9c44
comparison
equal deleted inserted replaced
175:96a89dcb4060 176:0c3c69fe225b
1 using System; 1 using System;
2 using System.Globalization; 2 using System.Globalization;
3 using Implab.Automaton; 3 using Implab.Automaton;
4 using System.Text;
5 using Implab.Components;
6 using System.IO;
7 using Implab.Automaton.RegularExpressions;
4 8
5 namespace Implab.Formats.JSON { 9 namespace Implab.Formats.JSON {
6 /// <summary> 10 /// <summary>
7 /// Сканнер (лексер), разбивающий поток символов на токены JSON. 11 /// Сканнер (лексер), разбивающий поток символов на токены JSON.
8 /// </summary> 12 /// </summary>
9 public class JSONScanner : Scanner<object> { 13 public class JSONScanner : Disposable {
10 char[] m_stringBuffer; 14 readonly StringBuilder m_builder = new StringBuilder();
11 DFAStateDescriptior<>[] m_stringDFA; 15
12 int[] m_stringAlphabet; 16 readonly ScannerContext<JSONGrammar.TokenType> m_jsonScanner = JSONGrammar.Instance.JsonDFA;
17 readonly ScannerContext<JSONGrammar.TokenType> m_stringScanner = JSONGrammar.Instance.JsonStringDFA;
18
19
20 readonly TextScanner m_scanner;
13 21
14 /// <summary> 22 /// <summary>
15 /// Создает новый экземпляр сканнера 23 /// Создает новый экземпляр сканнера
16 /// </summary> 24 /// </summary>
17 public JSONScanner() 25 public JSONScanner(string text) {
18 : base(JSONGrammar.Instance.JsonDFA.GetTransitionTable(), JSONGrammar.Instance.JsonDFA.Alphabet.GetTranslationMap()) { 26 Safe.ArgumentNotEmpty(text, "text");
19 m_stringBuffer = new char[1024]; 27
20 var dfa = JSONGrammar.Instance.JsonStringDFA; 28 m_scanner = new StringScanner(text);
21 m_stringAlphabet = dfa.Alphabet.GetTranslationMap(); 29 }
22 m_stringDFA = dfa.States; 30
31 public JSONScanner(TextReader reader, int bufferMax, int chunkSize) {
32 Safe.ArgumentNotNull(reader, "reader");
33
34 m_scanner = new ReaderScanner(reader);
23 } 35 }
24 36
25 /// <summary> 37 /// <summary>
26 /// Читает следующий лексический элемент из входных данных. 38 /// Читает следующий лексический элемент из входных данных.
27 /// </summary> 39 /// </summary>
29 /// <param name="tokenType">Возвращает тип прочитанного токена.</param> 41 /// <param name="tokenType">Возвращает тип прочитанного токена.</param>
30 /// <returns><c>true</c> - чтение произведено успешно. <c>false</c> - достигнут конец входных данных</returns> 42 /// <returns><c>true</c> - чтение произведено успешно. <c>false</c> - достигнут конец входных данных</returns>
31 /// <remarks>В случе если токен не распознается, возникает исключение. Значения токенов обрабатываются, т.е. 43 /// <remarks>В случе если токен не распознается, возникает исключение. Значения токенов обрабатываются, т.е.
32 /// в строках обрабатываются экранированные символы, числа становтся типа double.</remarks> 44 /// в строках обрабатываются экранированные символы, числа становтся типа double.</remarks>
33 public bool ReadToken(out object tokenValue, out JsonTokenType tokenType) { 45 public bool ReadToken(out object tokenValue, out JsonTokenType tokenType) {
34 if (ReadTokenInternal()) { 46 JSONGrammar.TokenType[] tag;
35 switch ((JSONGrammar.TokenType)m_currentState.tag[0]) { 47 if (m_jsonScanner.Execute(m_scanner, out tag)) {
48 switch (tag[0]) {
36 case JSONGrammar.TokenType.StringBound: 49 case JSONGrammar.TokenType.StringBound:
37 tokenValue = ReadString(); 50 tokenValue = ReadString();
38 tokenType = JsonTokenType.String; 51 tokenType = JsonTokenType.String;
39 break; 52 break;
40 case JSONGrammar.TokenType.Number: 53 case JSONGrammar.TokenType.Number:
41 tokenValue = Double.Parse(new String(m_buffer, m_tokenOffset, m_tokenLen), CultureInfo.InvariantCulture); 54 tokenValue = Double.Parse(m_scanner.GetTokenValue(), CultureInfo.InvariantCulture);
42 tokenType = JsonTokenType.Number; 55 tokenType = JsonTokenType.Number;
43 break; 56 break;
44 default: 57 default:
45 tokenType = (JsonTokenType)m_currentState.tag[0]; 58 tokenType = (JsonTokenType)tag[0];
46 tokenValue = new String(m_buffer, m_tokenOffset, m_tokenLen); 59 tokenValue = m_scanner.GetTokenValue();
47 break; 60 break;
48 } 61 }
49 return true; 62 return true;
50 } 63 }
51 tokenValue = null; 64 tokenValue = null;
53 return false; 66 return false;
54 } 67 }
55 68
56 string ReadString() { 69 string ReadString() {
57 int pos = 0; 70 int pos = 0;
58 Switch(m_stringDFA, m_stringAlphabet); 71 char[] buf = new char[6]; // the buffer for unescaping chars
59 while (ReadTokenInternal()) { 72
60 switch ((JSONGrammar.TokenType)m_currentState.tag[0]) { 73 JSONGrammar.TokenType[] tag;
74 m_builder.Clear();
75
76 while (m_stringScanner.Execute(m_scanner, out tag)) {
77 switch (tag[0]) {
61 case JSONGrammar.TokenType.StringBound: 78 case JSONGrammar.TokenType.StringBound:
62 Restore(); 79 return m_builder.ToString();
63 return new String(m_stringBuffer, 0, pos);
64 case JSONGrammar.TokenType.UnescapedChar: 80 case JSONGrammar.TokenType.UnescapedChar:
65 EnsureStringBufferSize(pos + m_tokenLen); 81 m_scanner.CopyTokenTo(m_builder);
66 Array.Copy(m_buffer, m_tokenOffset, m_stringBuffer, pos, m_tokenLen);
67 pos += m_tokenLen;
68 break; 82 break;
69 case JSONGrammar.TokenType.EscapedUnicode: 83 case JSONGrammar.TokenType.EscapedUnicode: // \xXXXX - unicode escape sequence
70 EnsureStringBufferSize(pos + 1); 84 m_scanner.CopyTokenTo(buf, 0);
71 m_stringBuffer[pos] = StringTranslator.TranslateHexUnicode(m_buffer, m_tokenOffset + 2); 85 m_builder.Append(StringTranslator.TranslateHexUnicode(buf, 2));
72 pos++; 86 pos++;
73 break; 87 break;
74 case JSONGrammar.TokenType.EscapedChar: 88 case JSONGrammar.TokenType.EscapedChar: // \t - escape sequence
75 EnsureStringBufferSize(pos + 1); 89 m_scanner.CopyTokenTo(buf, 0);
76 m_stringBuffer[pos] = StringTranslator.TranslateEscapedChar(m_buffer[m_tokenOffset + 1]); 90 m_builder.Append(StringTranslator.TranslateEscapedChar(buf[1]));
77 pos++;
78 break; 91 break;
79 default: 92 default:
80 break; 93 break;
81 } 94 }
82 95
83 } 96 }
84 97
85 throw new ParserException("Unexpected end of data"); 98 throw new ParserException("Unexpected end of data");
86 } 99 }
87
88 void EnsureStringBufferSize(int size) {
89 if (size > m_stringBuffer.Length) {
90 var newBuffer = new char[size];
91 m_stringBuffer.CopyTo(newBuffer, 0);
92 m_stringBuffer = newBuffer;
93 }
94 }
95 } 100 }
96 } 101 }