diff Implab/Formats/JSON/JSONScanner.cs @ 163:419aa51b04fd ref20160224

JSON moved to Formats namespace Working in RegularDFA
author cin
date Wed, 24 Feb 2016 20:12:52 +0300
parents
children e227e78d72e4
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Implab/Formats/JSON/JSONScanner.cs	Wed Feb 24 20:12:52 2016 +0300
@@ -0,0 +1,100 @@
+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.States, 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;
+            }
+        }
+    }
+}