diff Implab/Parsing/Scanner.cs @ 59:21611344d366

code cleanup
author cin
date Wed, 18 Jun 2014 03:54:02 +0400
parents 7759c80cad95
children 10c7337d29e7
line wrap: on
line diff
--- a/Implab/Parsing/Scanner.cs	Tue Jun 17 19:40:43 2014 +0400
+++ b/Implab/Parsing/Scanner.cs	Wed Jun 18 03:54:02 2014 +0400
@@ -1,6 +1,7 @@
 using Implab;
 using System;
 using System.Collections.Generic;
+using System.IO;
 using System.Linq;
 using System.Text;
 using System.Threading.Tasks;
@@ -14,7 +15,7 @@
     /// указателя, начала и конца токена, при перемещении искользуется ДКА для определения
     /// конца токена и допустимости текущего символа.
     /// </remarks>
-    public class Scanner {
+    public abstract class Scanner : Disposable {
         struct ScannerConfig {
             public DFAStateDescriptior[] states;
             public int[] alphabetMap;
@@ -35,15 +36,10 @@
         protected int m_bufferSize;
         protected int m_pointer;
 
-        public Scanner(CDFADefinition definition, string text) {
-            Safe.ArgumentNotNull(definition, "definition");
-            Safe.ArgumentNotEmpty(text, "text");
-
-            m_states = definition.States;
-            m_alphabetMap = definition.Alphabet.GetTranslationMap();
-
-            Feed(text.ToCharArray());
-        }
+        TextReader m_reader;
+        bool m_disposeReader;
+        int m_chunkSize = 1024; // 1k
+        int m_limit = 10 * 1024 * 1024; // 10Mb
 
         public Scanner(CDFADefinition definition) {
             Safe.ArgumentNotNull(definition, "definition");
@@ -76,6 +72,7 @@
         public void Feed(char[] data, int length) {
             Safe.ArgumentNotNull(data, "data");
             Safe.ArgumentInRange(length, 0, data.Length, "length");
+            AssertNotDisposed();
 
             m_pointer = -1;
             m_buffer = data;
@@ -83,18 +80,33 @@
             Shift();
         }
 
+        public void Feed(TextReader reader, bool dispose) {
+            Safe.ArgumentNotNull(reader, "reader");
+            AssertNotDisposed();
+
+            if (m_reader != null && m_disposeReader)
+                m_reader.Dispose();
+
+            m_reader = reader;
+            m_disposeReader = dispose;
+            m_pointer = -1;
+            m_buffer = new char[m_chunkSize];
+            m_bufferSize = 0;
+            Shift();
+        }
+
         /// <summary>
         /// Получает текущий токен в виде строки.
         /// </summary>
         /// <returns></returns>
-        public string GetTokenValue() {
+        protected string GetTokenValue() {
             return new String(m_buffer, m_tokenOffset, m_tokenLen);
         }
 
         /// <summary>
         /// Метки текущего токена, которые были назначены в регулярном выражении.
         /// </summary>
-        public int[] TokenTags {
+        protected int[] TokenTags {
             get {
                 return m_currentState.tag;
             }
@@ -163,13 +175,31 @@
             return true;
         }
 
-        /// <summary>
-        /// Вызывается по достижению конца входного буффера для получения
-        /// новых данных.
-        /// </summary>
-        /// <returns><c>true</c> - новые двнные получены, можно продолжать обработку.</returns>
-        protected virtual bool ReadNextChunk() {
-            return false;
+        bool ReadNextChunk() {
+            if (m_reader == null)
+                return false;
+
+            //  extend buffer if nesessary
+            if (m_pointer + m_chunkSize > m_buffer.Length) {
+                // trim unused buffer head
+                var size = m_tokenLen + m_chunkSize;
+                if (size >= m_limit)
+                    throw new ParserException(String.Format("Input buffer {0} bytes limit exceeded", m_limit));
+                var temp = new char[size];
+                Array.Copy(m_buffer, m_tokenOffset, temp, 0, m_tokenLen);
+                m_pointer -= m_tokenOffset;
+                m_bufferSize -= m_tokenOffset;
+                m_tokenOffset = 0;
+                m_buffer = temp;
+            }
+            
+            var read = m_reader.Read(m_buffer, m_tokenLen, m_chunkSize);
+            if (read == 0)
+                return false;
+
+            m_bufferSize += read;
+
+            return true;
         }
 
         /// <summary>
@@ -212,5 +242,18 @@
             m_alphabetMap = prev.alphabetMap;
             m_previewCode = m_alphabetMap[m_buffer[m_pointer]];
         }
+
+        protected override void Dispose(bool disposing) {
+            if (disposing) {
+                if (m_reader != null && m_disposeReader)
+                    m_reader.Dispose();
+                m_buffer = null;
+                m_bufferSize = 0;
+                m_pointer = 0;
+                m_tokenLen = 0;
+                m_tokenOffset = 0;
+            }
+            base.Dispose(disposing);
+        }
     }
 }