Mercurial > pub > ImplabNet
view Implab/Formats/JSON/JSONScanner.cs @ 165:e227e78d72e4 ref20160224
DFA refactoring
author | cin |
---|---|
date | Mon, 29 Feb 2016 02:02:17 +0300 |
parents | 419aa51b04fd |
children | 0c3c69fe225b |
line wrap: on
line source
using System; using System.Globalization; using Implab.Automaton; namespace Implab.Formats.JSON { /// <summary> /// Сканнер (лексер), разбивающий поток символов на токены JSON. /// </summary> public class JSONScanner : Scanner<object> { char[] m_stringBuffer; DFAStateDescriptior<>[] m_stringDFA; int[] m_stringAlphabet; /// <summary> /// Создает новый экземпляр сканнера /// </summary> public JSONScanner() : base(JSONGrammar.Instance.JsonDFA.GetTransitionTable(), JSONGrammar.Instance.JsonDFA.Alphabet.GetTranslationMap()) { 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; } } } }