Mercurial > pub > ImplabNet
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 } |