##// END OF EJS Templates
Added Skip method to JSON parser to skip contents of the current node
Added Skip method to JSON parser to skip contents of the current node

File last commit:

r60:10c7337d29e7 default
r62:62b440d46313 default
Show More
JSONScanner.cs
100 lines | 4.6 KiB | text/x-csharp | CSharpLexer
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>
/// Сканнер (лексер), разбивающий поток символов на токены JSON.
/// </summary>
public class JSONScanner : Scanner {
char[] m_stringBuffer;
DFAStateDescriptior[] m_stringDFA;
int[] m_stringAlphabet;
/// <summary>
/// Создает новый экземпляр сканнера
/// </summary>
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;
}
/// <summary>
/// Читает следующий лексический элемент из входных данных.
/// </summary>
/// <param name="tokenValue">Возвращает значение прочитанного токена.</param>
/// <param name="tokenType">Возвращает тип прочитанного токена.</param>
/// <returns><c>true</c> - чтение произведено успешно. <c>false</c> - достигнут конец входных данных</returns>
/// <remarks>В случе если токен не распознается, возникает исключение. Значения токенов обрабатываются, т.е.
/// в строках обрабатываются экранированные символы, числа становтся типа double.</remarks>
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;
}
}
}
}