JSONScanner.cs
100 lines
| 4.7 KiB
| text/x-csharp
|
CSharpLexer
cin
|
r55 | using Implab.Parsing; | ||
using System; | ||||
using System.Collections.Generic; | ||||
using System.Globalization; | ||||
using System.Linq; | ||||
using System.Text; | ||||
using System.Threading.Tasks; | ||||
namespace Implab.JSON { | ||||
/// <summary> | ||||
cin
|
r60 | /// Сканнер (лексер), разбивающий поток символов на токены JSON. | ||
cin
|
r55 | /// </summary> | ||
public class JSONScanner : Scanner { | ||||
char[] m_stringBuffer; | ||||
DFAStateDescriptior[] m_stringDFA; | ||||
int[] m_stringAlphabet; | ||||
cin
|
r60 | /// <summary> | ||
/// Создает новый экземпляр сканнера | ||||
/// </summary> | ||||
cin
|
r55 | public JSONScanner() | ||
cin
|
r158 | : base(JSONGrammar.Instance.JsonDFA.States, JSONGrammar.Instance.JsonDFA.Alphabet.GetTranslationMap()) { | ||
cin
|
r55 | m_stringBuffer = new char[1024]; | ||
var dfa = JSONGrammar.Instance.JsonStringDFA; | ||||
m_stringAlphabet = dfa.Alphabet.GetTranslationMap(); | ||||
m_stringDFA = dfa.States; | ||||
} | ||||
cin
|
r60 | /// <summary> | ||
/// Читает следующий лексический элемент из входных данных. | ||||
/// </summary> | ||||
/// <param name="tokenValue">Возвращает значение прочитанного токена.</param> | ||||
/// <param name="tokenType">Возвращает тип прочитанного токена.</param> | ||||
/// <returns><c>true</c> - чтение произведено успешно. <c>false</c> - достигнут конец входных данных</returns> | ||||
/// <remarks>В случе если токен не распознается, возникает исключение. Значения токенов обрабатываются, т.е. | ||||
/// в строках обрабатываются экранированные символы, числа становтся типа double.</remarks> | ||||
cin
|
r55 | public bool ReadToken(out object tokenValue, out JsonTokenType tokenType) { | ||
if (ReadTokenInternal()) { | ||||
switch ((JSONGrammar.TokenType)m_currentState.tag[0]) { | ||||
case JSONGrammar.TokenType.StringBound: | ||||
tokenValue = ReadString(); | ||||
tokenType = JsonTokenType.String; | ||||
break; | ||||
case JSONGrammar.TokenType.Number: | ||||
tokenValue = Double.Parse(new String(m_buffer, m_tokenOffset, m_tokenLen), CultureInfo.InvariantCulture); | ||||
tokenType = JsonTokenType.Number; | ||||
break; | ||||
default: | ||||
tokenType = (JsonTokenType)m_currentState.tag[0]; | ||||
tokenValue = new String(m_buffer, m_tokenOffset, m_tokenLen); | ||||
break; | ||||
} | ||||
return true; | ||||
} | ||||
tokenValue = null; | ||||
tokenType = JsonTokenType.None; | ||||
return false; | ||||
} | ||||
string ReadString() { | ||||
int pos = 0; | ||||
Switch(m_stringDFA, m_stringAlphabet); | ||||
while (ReadTokenInternal()) { | ||||
switch ((JSONGrammar.TokenType)m_currentState.tag[0]) { | ||||
case JSONGrammar.TokenType.StringBound: | ||||
Restore(); | ||||
return new String(m_stringBuffer, 0, pos); | ||||
case JSONGrammar.TokenType.UnescapedChar: | ||||
EnsureStringBufferSize(pos + m_tokenLen); | ||||
Array.Copy(m_buffer, m_tokenOffset, m_stringBuffer, pos, m_tokenLen); | ||||
pos += m_tokenLen; | ||||
break; | ||||
case JSONGrammar.TokenType.EscapedUnicode: | ||||
EnsureStringBufferSize(pos + 1); | ||||
m_stringBuffer[pos] = StringTranslator.TranslateHexUnicode(m_buffer, m_tokenOffset + 2); | ||||
pos++; | ||||
break; | ||||
case JSONGrammar.TokenType.EscapedChar: | ||||
EnsureStringBufferSize(pos + 1); | ||||
m_stringBuffer[pos] = StringTranslator.TranslateEscapedChar(m_buffer[m_tokenOffset + 1]); | ||||
pos++; | ||||
break; | ||||
default: | ||||
break; | ||||
} | ||||
} | ||||
throw new ParserException("Unexpected end of data"); | ||||
} | ||||
void EnsureStringBufferSize(int size) { | ||||
if (size > m_stringBuffer.Length) { | ||||
var newBuffer = new char[size]; | ||||
m_stringBuffer.CopyTo(newBuffer, 0); | ||||
m_stringBuffer = newBuffer; | ||||
} | ||||
} | ||||
} | ||||
} | ||||