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 {
///
/// Сканнер (лексер), разбивающий поток символов на токены JSON.
///
public class JSONScanner : Scanner {
char[] m_stringBuffer;
DFAStateDescriptior[] m_stringDFA;
int[] m_stringAlphabet;
///
/// Создает новый экземпляр сканнера
///
public JSONScanner()
: base(JSONGrammar.Instance.JsonDFA) {
m_stringBuffer = new char[1024];
var dfa = JSONGrammar.Instance.JsonStringDFA;
m_stringAlphabet = dfa.Alphabet.GetTranslationMap();
m_stringDFA = dfa.States;
}
///
/// Читает следующий лексический элемент из входных данных.
///
/// Возвращает значение прочитанного токена.
/// Возвращает тип прочитанного токена.
/// true - чтение произведено успешно. false - достигнут конец входных данных
/// В случе если токен не распознается, возникает исключение. Значения токенов обрабатываются, т.е.
/// в строках обрабатываются экранированные символы, числа становтся типа double.
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;
}
}
}
}