changeset 174:983df35b3ca1 ref20160224

sync
author cin
date Fri, 18 Mar 2016 18:10:30 +0300
parents ecfece82ca11
children 96a89dcb4060
files Implab/Automaton/Scanner.cs Implab/Formats/BufferScanner.cs Implab/Formats/TextScanner.cs
diffstat 3 files changed, 295 insertions(+), 387 deletions(-) [+]
line wrap: on
line diff
--- a/Implab/Automaton/Scanner.cs	Tue Mar 15 02:11:06 2016 +0300
+++ b/Implab/Automaton/Scanner.cs	Fri Mar 18 18:10:30 2016 +0300
@@ -1,255 +1,255 @@
-using Implab;
-using System;
-using System.Collections.Generic;
-using System.IO;
-using Implab.Components;
-using Implab.Automaton.RegularExpressions;
-
-namespace Implab.Automaton {
-    /// <summary>
-    /// Базовый класс для разбора потока входных символов на токены.
-    /// </summary>
-    /// <remarks>
-    /// Сканнер имеет внутри буффер с симолами входного текста, по которому перемещаются два
-    /// указателя, начала и конца токена, при перемещении искользуется ДКА для определения
-    /// конца токена и допустимости текущего символа.
-    /// </remarks>
-    public abstract class Scanner<TTag> : Disposable {
-        protected struct ScannerConfig {
-            public readonly DFAStateDescriptor<TTag>[] states;
-            public readonly int[] alphabet;
-            public readonly int initialState;
-
-            public ScannerConfig(DFAStateDescriptor<TTag>[] states, int[] alphabet, int initialState) {
-                this.initialState = initialState;
-                this.alphabet = alphabet;
-                this.states = states;
-            }
-        }
-
-        Stack<ScannerConfig> m_defs = new Stack<ScannerConfig>();
-
-        ScannerConfig m_config;
-
-        protected DFAStateDescriptor<TTag> m_currentState;
-        int m_previewCode;
-
-        protected int m_tokenLen;
-        protected int m_tokenOffset;
-
-        protected char[] m_buffer;
-        protected int m_bufferSize;
-        protected int m_pointer;
-
-        TextReader m_reader;
-        bool m_disposeReader;
-        int m_chunkSize = 1024; // 1k
-        int m_limit = 10 * 1024 * 1024; // 10Mb
-
-        protected Scanner(ScannerConfig config) {
-            Safe.ArgumentNotEmpty(config.states, "config.states");
-            Safe.ArgumentNotNull(config.alphabet, "config.alphabet");
-
-            m_config = config;
-        }
-
-        /// <summary>
-        /// Заполняет входными данными буффер.
-        /// </summary>
-        /// <param name="data">Данные для обработки.</param>
-        /// <remarks>Копирование данных не происходит, переданный массив используется в
-        /// качестве входного буффера.</remarks>
-        public void Feed(char[] data) {
-            Safe.ArgumentNotNull(data, "data");
-
-            Feed(data, data.Length);
-        }
-
-        /// <summary>
-        /// Заполняет буффур чтения входными данными.
-        /// </summary>
-        /// <param name="data">Данные для обработки.</param>
-        /// <param name="length">Длина данных для обработки.</param>
-        /// <remarks>Копирование данных не происходит, переданный массив используется в
-        /// качестве входного буффера.</remarks>
-        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;
-            m_bufferSize = length;
-            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>
-        protected string GetTokenValue() {
-            return new String(m_buffer, m_tokenOffset, m_tokenLen);
-        }
-
-        /// <summary>
-        /// Метки текущего токена, которые были назначены в регулярном выражении.
-        /// </summary>
-        protected TTag[] TokenTags {
-            get {
-                return m_currentState.tags;
-            }
-        }
-
-        /// <summary>
-        /// Признак конца данных
-        /// </summary>
-        public bool EOF {
-            get {
-                return m_pointer >= m_bufferSize;
-            }
-        }
-
-        /// <summary>
-        /// Читает следующий токен, при этом <see cref="m_tokenOffset"/> указывает на начало токена,
-        /// <see cref="m_tokenLen"/> на длину токена, <see cref="m_buffer"/> - массив символов, в
-        /// котором находится токен.
-        /// </summary>
-        /// <returns><c>false</c> - достигнут конец данных, токен не прочитан.</returns>
-        protected bool ReadTokenInternal() {
-            if (m_pointer >= m_bufferSize)
-                return false;
-
-            m_currentState = m_config.states[m_config.initialState];
-            m_tokenLen = 0;
-            m_tokenOffset = m_pointer;
-            int nextState;
-            do {
-                nextState = m_currentState.transitions[m_previewCode];
-                if (nextState == DFAConst.UNREACHABLE_STATE) {
-                    if (m_currentState.final)
-                        return true;
-                    
-                    throw new ParserException(
-                        String.Format(
-                            "Unexpected symbol '{0}', at pos {1}",
-                            m_buffer[m_pointer],
-                            Position
-                        )
-                    );
-                }
-                m_currentState = m_config.states[nextState];
-                m_tokenLen++;
-
-            } while (Shift());
-
-            // END OF DATA
-            if (!m_currentState.final)
-                throw new ParserException("Unexpected end of data");
-
-            return true;
-        }
-
-
-        bool Shift() {
-            m_pointer++;
-
-            if (m_pointer >= m_bufferSize) {
-                if (!ReadNextChunk())
-                    return false;
-            }
-
-            m_previewCode = m_config.alphabet[m_buffer[m_pointer]];
-
-            return true;
-        }
-
-        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>
-        /// Позиция сканнера во входном буфере
-        /// </summary>
-        public int Position {
-            get {
-                return m_pointer + 1;
-            }
-        }
-
-        /// <summary>
-        /// Преключает внутренний ДКА на указанный, позволяет реализовать подобие захватывающей
-        /// группировки.
-        /// </summary>
-        /// <param name = "config"></param>
-        protected void Switch(ScannerConfig config) {
-            Safe.ArgumentNotNull(config.states, "config.states");
-
-            m_defs.Push(m_config);
-            m_config = config;
-
-            m_previewCode = m_config.alphabet[m_buffer[m_pointer]];
-        }
-
-        /// <summary>
-        /// Восстанавливает предыдущей ДКА сканнера.
-        /// </summary>
-        protected void Restore() {
-            if (m_defs.Count == 0)
-                throw new InvalidOperationException();
-            m_config = m_defs.Pop();
-
-            m_previewCode = m_config.alphabet[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);
-        }
-    }
-}
+using Implab;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using Implab.Components;
+using Implab.Automaton.RegularExpressions;
+
+namespace Implab.Automaton {
+    /// <summary>
+    /// Базовый класс для разбора потока входных символов на токены.
+    /// </summary>
+    /// <remarks>
+    /// Сканнер имеет внутри буффер с симолами входного текста, по которому перемещаются два
+    /// указателя, начала и конца токена, при перемещении искользуется ДКА для определения
+    /// конца токена и допустимости текущего символа.
+    /// </remarks>
+    public abstract class Scanner<TTag> : Disposable {
+        protected struct ScannerConfig {
+            public readonly DFAStateDescriptor<TTag>[] states;
+            public readonly int[] alphabet;
+            public readonly int initialState;
+
+            public ScannerConfig(DFAStateDescriptor<TTag>[] states, int[] alphabet, int initialState) {
+                this.initialState = initialState;
+                this.alphabet = alphabet;
+                this.states = states;
+            }
+        }
+
+        Stack<ScannerConfig> m_defs = new Stack<ScannerConfig>();
+
+        ScannerConfig m_config;
+
+        protected DFAStateDescriptor<TTag> m_currentState;
+        int m_previewCode;
+
+        protected int m_tokenLen;
+        protected int m_tokenOffset;
+
+        protected char[] m_buffer;
+        protected int m_bufferSize;
+        protected int m_pointer;
+
+        TextReader m_reader;
+        bool m_disposeReader;
+        int m_chunkSize = 1024; // 1k
+        int m_limit = 10 * 1024 * 1024; // 10Mb
+
+        protected Scanner(ScannerConfig config) {
+            Safe.ArgumentNotEmpty(config.states, "config.states");
+            Safe.ArgumentNotNull(config.alphabet, "config.alphabet");
+
+            m_config = config;
+        }
+
+        /// <summary>
+        /// Заполняет входными данными буффер.
+        /// </summary>
+        /// <param name="data">Данные для обработки.</param>
+        /// <remarks>Копирование данных не происходит, переданный массив используется в
+        /// качестве входного буффера.</remarks>
+        public void Feed(char[] data) {
+            Safe.ArgumentNotNull(data, "data");
+
+            Feed(data, data.Length);
+        }
+
+        /// <summary>
+        /// Заполняет буффур чтения входными данными.
+        /// </summary>
+        /// <param name="data">Данные для обработки.</param>
+        /// <param name="length">Длина данных для обработки.</param>
+        /// <remarks>Копирование данных не происходит, переданный массив используется в
+        /// качестве входного буффера.</remarks>
+        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;
+            m_bufferSize = length;
+            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>
+        protected string GetTokenValue() {
+            return new String(m_buffer, m_tokenOffset, m_tokenLen);
+        }
+
+        /// <summary>
+        /// Метки текущего токена, которые были назначены в регулярном выражении.
+        /// </summary>
+        protected TTag[] TokenTags {
+            get {
+                return m_currentState.tags;
+            }
+        }
+
+        /// <summary>
+        /// Признак конца данных
+        /// </summary>
+        public bool EOF {
+            get {
+                return m_pointer >= m_bufferSize;
+            }
+        }
+
+        /// <summary>
+        /// Читает следующий токен, при этом <see cref="m_tokenOffset"/> указывает на начало токена,
+        /// <see cref="m_tokenLen"/> на длину токена, <see cref="m_buffer"/> - массив символов, в
+        /// котором находится токен.
+        /// </summary>
+        /// <returns><c>false</c> - достигнут конец данных, токен не прочитан.</returns>
+        protected bool ReadTokenInternal() {
+            if (m_pointer >= m_bufferSize)
+                return false;
+
+            m_currentState = m_config.states[m_config.initialState];
+            m_tokenLen = 0;
+            m_tokenOffset = m_pointer;
+            int nextState;
+            do {
+                nextState = m_currentState.transitions[m_previewCode];
+                if (nextState == DFAConst.UNREACHABLE_STATE) {
+                    if (m_currentState.final)
+                        return true;
+                    
+                    throw new ParserException(
+                        String.Format(
+                            "Unexpected symbol '{0}', at pos {1}",
+                            m_buffer[m_pointer],
+                            Position
+                        )
+                    );
+                }
+                m_currentState = m_config.states[nextState];
+                m_tokenLen++;
+
+            } while (Shift());
+
+            // END OF DATA
+            if (!m_currentState.final)
+                throw new ParserException("Unexpected end of data");
+
+            return true;
+        }
+
+
+        bool Shift() {
+            m_pointer++;
+
+            if (m_pointer >= m_bufferSize) {
+                if (!ReadNextChunk())
+                    return false;
+            }
+
+            m_previewCode = m_config.alphabet[m_buffer[m_pointer]];
+
+            return true;
+        }
+
+        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>
+        /// Позиция сканнера во входном буфере
+        /// </summary>
+        public int Position {
+            get {
+                return m_pointer + 1;
+            }
+        }
+
+        /// <summary>
+        /// Преключает внутренний ДКА на указанный, позволяет реализовать подобие захватывающей
+        /// группировки.
+        /// </summary>
+        /// <param name = "config"></param>
+        protected void Switch(ScannerConfig config) {
+            Safe.ArgumentNotNull(config.states, "config.states");
+
+            m_defs.Push(m_config);
+            m_config = config;
+
+            m_previewCode = m_config.alphabet[m_buffer[m_pointer]];
+        }
+
+        /// <summary>
+        /// Восстанавливает предыдущей ДКА сканнера.
+        /// </summary>
+        protected void Restore() {
+            if (m_defs.Count == 0)
+                throw new InvalidOperationException();
+            m_config = m_defs.Pop();
+
+            m_previewCode = m_config.alphabet[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);
+        }
+    }
+}
--- a/Implab/Formats/BufferScanner.cs	Tue Mar 15 02:11:06 2016 +0300
+++ b/Implab/Formats/BufferScanner.cs	Fri Mar 18 18:10:30 2016 +0300
@@ -1,125 +1,45 @@
 using System;
 using Implab.Automaton.RegularExpressions;
 using Implab.Automaton;
+using System.Diagnostics;
 
 namespace Implab.Formats {
     public struct BufferScanner<TTag> {
-        char[] m_buffer;
-        int m_offset;
-        int m_position;
-        int m_hi;
-
-        readonly int m_chunk;
-        readonly int m_limit;
-
         readonly DFAStateDescriptor<TTag>[] m_dfa;
         int m_state;
+        int m_pos;
 
-        public BufferScanner(DFAStateDescriptor<TTag>[] dfa, int initialState, int chunk, int limit) {
+        public BufferScanner(DFAStateDescriptor<TTag>[] dfa, int initialState) {
             m_dfa = dfa;
             m_state = initialState;
-            m_chunk = chunk;
-            m_limit = limit;
-            m_buffer = null;
-            m_offset = 0;
-            m_position = 0;
-            m_hi = 0;
-        }
-
-        public char[] Buffer {
-            get {
-                return m_buffer;
-            }
-        }
-
-        public int HiMark {
-            get {
-                return m_hi;
-            }
         }
 
         public int Position {
-            get {
-                return m_position;
-            }
-        }
-
-        public int Length {
-            get {
-                return m_hi - m_position;
-            }
-        }
-
-        public int TokenOffset {
-            get {
-                return m_offset;
-            }
-        }
-
-        public int TokenLength {
-            get {
-                return m_position - m_offset;
-            }
-        }
-
-        public void Init(char[] buffer, int position, int length) {
-            m_buffer = buffer;
-            m_position = position;
-            m_offset = position;
-            m_hi = position + length;
-        }
-
-        public int Extend() {
-            // free space
-            var free = m_buffer.Length - m_hi;
-
-            // if the buffer have enough free space
-            if (free > 0)
-                return free;
-
-            // effective size of the buffer
-            var size = m_buffer.Length - m_offset;
-                
-            // calculate the new size
-            int grow = Math.Min(m_limit - size, m_chunk);
-            if (grow <= 0)
-                throw new ParserException(String.Format("Input buffer {0} bytes limit exceeded", m_limit));
-
-            var temp = new char[size + grow];
-            Array.Copy(m_buffer, m_offset, temp, 0, m_hi - m_offset);
-            m_position -= m_offset;
-            m_hi -= m_offset;
-            m_offset = 0;
-            m_buffer = temp;
-
-            return free + grow;
-        }
-
-        public void RaiseMark(int size) {
-            m_hi += size;
+            get { return m_pos; }
         }
 
         /// <summary>
         /// Scan this instance.
         /// </summary>
         /// <returns><c>true</c> - additional data required</returns>
-        public bool Scan() {
-            while (m_position < m_hi) {
-                var ch = m_buffer[m_position];
-                var next = m_dfa[m_state].transitions[(int)ch];
+        public bool Scan(int[] buffer, int position, int length) {
+            var hi = position + length;
+            m_pos = position;
+
+            while (position < hi) {
+                var next = m_dfa[m_state].transitions[buffer[position]];
                 if (next == DFAConst.UNREACHABLE_STATE) {
                     if (m_dfa[m_state].final)
                         return false;
 
                     throw new ParserException(
                         String.Format(
-                            "Unexpected token '{0}'",
-                            new string(m_buffer, m_offset, m_position - m_offset)
+                            "Unexpected symbol"
                         )
                     );
                 }
+                m_pos++;
                 m_state = next;
-                m_position++;
             }
 
             return true;
@@ -129,8 +49,7 @@
             if (!m_dfa[m_state].final)
                 throw new ParserException(
                     String.Format(
-                        "Unexpected token '{0}'",
-                        new string(m_buffer, m_offset, m_position - m_offset)
+                        "Unexpected EOF"
                     )
                 );
         }
--- a/Implab/Formats/TextScanner.cs	Tue Mar 15 02:11:06 2016 +0300
+++ b/Implab/Formats/TextScanner.cs	Fri Mar 18 18:10:30 2016 +0300
@@ -4,11 +4,11 @@
 namespace Implab.Formats {
     public abstract class TextScanner<TTag> : Disposable {
 
-        char[] m_buffer;
-        int m_offset;
-        int m_length;
-        int m_tokenOffset;
+        readonly int[] m_buffer;
+        int m_bufferOffset;
+        int m_dataLength;
         int m_tokenLength;
+
         TTag[] m_tags;
 
         BufferScanner<TTag> m_scanner;
@@ -17,29 +17,36 @@
             if (EOF)
                 return false;
             
-            // create a new scanner from template (scanners are structs)
+            // create a new scanner from template (scanners are value types)
             var inst = m_scanner;
 
-            // initialize the scanner
-            inst.Init(m_buffer, m_offset, m_length);
+            m_tokenLength = 0;
+
+            while (inst.Scan(m_buffer, m_bufferOffset, m_dataLength)) {
+                m_tokenLength += m_dataLength;
+
+                var actual = Read(m_buffer, 0, m_buffer.Length);
+                    
+                m_bufferOffset = 0;
+                m_dataLength = actual;
 
-            // do work
-            while (inst.Scan())
-                Feed(ref inst);
+                if (actual == 0) {
+                    inst.Eof();
+                    break;
+                }
+            }
+
+            var len = inst.Position - m_bufferOffset;
+            m_tokenLength += len;
+            m_dataLength -= len;
+            m_bufferOffset = inst.Position;
 
             // save result;
-            m_buffer = inst.Buffer;
-            m_length = inst.Length;
-            m_offset = inst.Position;
-            m_tokenOffset = inst.TokenOffset;
-            m_tokenLength = inst.TokenLength;
-
+        
             m_tags = inst.GetTokenTags();
         }
 
-        protected string GetToken() {
-            return new String(m_buffer, m_tokenOffset, m_tokenLength);
-        }
+        protected abstract int Read(int[] buffer, int offset, int size);
 
         protected TTag[] Tags {
             get {
@@ -47,26 +54,8 @@
             }
         }
 
-        /// <summary>
-        /// Feed the specified scanner.
-        /// </summary>
-        /// <param name="scanner">Scanner.</param>
-        /// <example>
-        /// protected override void Feed(ref BufferScanner<TTag> scanner) {
-        ///     var size = scanner.Extend();
-        ///     var actual = m_reader.Read(scanner.Buffer, scanner.HiMark, size);
-        ///     if (actual == 0) {
-        ///         m_eof = true;
-        ///         scanner.Eof();
-        ///     } else {
-        ///         scanner.RaiseHiMark(actual);
-        ///     }
-        /// }
-        /// </example>
-        protected abstract void Feed(ref BufferScanner<TTag> scanner);
-
         public abstract bool EOF { get; }
-
+ 
     }
 }