diff --git a/Implab/Automaton/Scanner.cs b/Implab/Automaton/Scanner.cs
--- a/Implab/Automaton/Scanner.cs
+++ b/Implab/Automaton/Scanner.cs
@@ -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 {
- ///
- /// Базовый класс для разбора потока входных символов на токены.
- ///
- ///
- /// Сканнер имеет внутри буффер с симолами входного текста, по которому перемещаются два
- /// указателя, начала и конца токена, при перемещении искользуется ДКА для определения
- /// конца токена и допустимости текущего символа.
- ///
- public abstract class Scanner : Disposable {
- protected struct ScannerConfig {
- public readonly DFAStateDescriptor[] states;
- public readonly int[] alphabet;
- public readonly int initialState;
-
- public ScannerConfig(DFAStateDescriptor[] states, int[] alphabet, int initialState) {
- this.initialState = initialState;
- this.alphabet = alphabet;
- this.states = states;
- }
- }
-
- Stack m_defs = new Stack();
-
- ScannerConfig m_config;
-
- protected DFAStateDescriptor 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;
- }
-
- ///
- /// Заполняет входными данными буффер.
- ///
- /// Данные для обработки.
- /// Копирование данных не происходит, переданный массив используется в
- /// качестве входного буффера.
- public void Feed(char[] data) {
- Safe.ArgumentNotNull(data, "data");
-
- Feed(data, data.Length);
- }
-
- ///
- /// Заполняет буффур чтения входными данными.
- ///
- /// Данные для обработки.
- /// Длина данных для обработки.
- /// Копирование данных не происходит, переданный массив используется в
- /// качестве входного буффера.
- 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();
- }
-
- ///
- /// Получает текущий токен в виде строки.
- ///
- ///
- protected string GetTokenValue() {
- return new String(m_buffer, m_tokenOffset, m_tokenLen);
- }
-
- ///
- /// Метки текущего токена, которые были назначены в регулярном выражении.
- ///
- protected TTag[] TokenTags {
- get {
- return m_currentState.tags;
- }
- }
-
- ///
- /// Признак конца данных
- ///
- public bool EOF {
- get {
- return m_pointer >= m_bufferSize;
- }
- }
-
- ///
- /// Читает следующий токен, при этом указывает на начало токена,
- /// на длину токена, - массив символов, в
- /// котором находится токен.
- ///
- /// false - достигнут конец данных, токен не прочитан.
- 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;
- }
-
- ///
- /// Позиция сканнера во входном буфере
- ///
- public int Position {
- get {
- return m_pointer + 1;
- }
- }
-
- ///
- /// Преключает внутренний ДКА на указанный, позволяет реализовать подобие захватывающей
- /// группировки.
- ///
- ///
- 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]];
- }
-
- ///
- /// Восстанавливает предыдущей ДКА сканнера.
- ///
- 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 {
+ ///
+ /// Базовый класс для разбора потока входных символов на токены.
+ ///
+ ///
+ /// Сканнер имеет внутри буффер с симолами входного текста, по которому перемещаются два
+ /// указателя, начала и конца токена, при перемещении искользуется ДКА для определения
+ /// конца токена и допустимости текущего символа.
+ ///
+ public abstract class Scanner : Disposable {
+ protected struct ScannerConfig {
+ public readonly DFAStateDescriptor[] states;
+ public readonly int[] alphabet;
+ public readonly int initialState;
+
+ public ScannerConfig(DFAStateDescriptor[] states, int[] alphabet, int initialState) {
+ this.initialState = initialState;
+ this.alphabet = alphabet;
+ this.states = states;
+ }
+ }
+
+ Stack m_defs = new Stack();
+
+ ScannerConfig m_config;
+
+ protected DFAStateDescriptor 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;
+ }
+
+ ///
+ /// Заполняет входными данными буффер.
+ ///
+ /// Данные для обработки.
+ /// Копирование данных не происходит, переданный массив используется в
+ /// качестве входного буффера.
+ public void Feed(char[] data) {
+ Safe.ArgumentNotNull(data, "data");
+
+ Feed(data, data.Length);
+ }
+
+ ///
+ /// Заполняет буффур чтения входными данными.
+ ///
+ /// Данные для обработки.
+ /// Длина данных для обработки.
+ /// Копирование данных не происходит, переданный массив используется в
+ /// качестве входного буффера.
+ 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();
+ }
+
+ ///
+ /// Получает текущий токен в виде строки.
+ ///
+ ///
+ protected string GetTokenValue() {
+ return new String(m_buffer, m_tokenOffset, m_tokenLen);
+ }
+
+ ///
+ /// Метки текущего токена, которые были назначены в регулярном выражении.
+ ///
+ protected TTag[] TokenTags {
+ get {
+ return m_currentState.tags;
+ }
+ }
+
+ ///
+ /// Признак конца данных
+ ///
+ public bool EOF {
+ get {
+ return m_pointer >= m_bufferSize;
+ }
+ }
+
+ ///
+ /// Читает следующий токен, при этом указывает на начало токена,
+ /// на длину токена, - массив символов, в
+ /// котором находится токен.
+ ///
+ /// false - достигнут конец данных, токен не прочитан.
+ 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;
+ }
+
+ ///
+ /// Позиция сканнера во входном буфере
+ ///
+ public int Position {
+ get {
+ return m_pointer + 1;
+ }
+ }
+
+ ///
+ /// Преключает внутренний ДКА на указанный, позволяет реализовать подобие захватывающей
+ /// группировки.
+ ///
+ ///
+ 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]];
+ }
+
+ ///
+ /// Восстанавливает предыдущей ДКА сканнера.
+ ///
+ 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);
+ }
+ }
+}
diff --git a/Implab/Formats/BufferScanner.cs b/Implab/Formats/BufferScanner.cs
--- a/Implab/Formats/BufferScanner.cs
+++ b/Implab/Formats/BufferScanner.cs
@@ -1,125 +1,45 @@
using System;
using Implab.Automaton.RegularExpressions;
using Implab.Automaton;
+using System.Diagnostics;
namespace Implab.Formats {
public struct BufferScanner {
- char[] m_buffer;
- int m_offset;
- int m_position;
- int m_hi;
-
- readonly int m_chunk;
- readonly int m_limit;
-
readonly DFAStateDescriptor[] m_dfa;
int m_state;
+ int m_pos;
- public BufferScanner(DFAStateDescriptor[] dfa, int initialState, int chunk, int limit) {
+ public BufferScanner(DFAStateDescriptor[] 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; }
}
///
/// Scan this instance.
///
/// true - additional data required
- 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 @@ namespace Implab.Formats {
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"
)
);
}
diff --git a/Implab/Formats/TextScanner.cs b/Implab/Formats/TextScanner.cs
--- a/Implab/Formats/TextScanner.cs
+++ b/Implab/Formats/TextScanner.cs
@@ -4,11 +4,11 @@ using Implab.Components;
namespace Implab.Formats {
public abstract class TextScanner : 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 m_scanner;
@@ -17,29 +17,36 @@ namespace Implab.Formats {
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 @@ namespace Implab.Formats {
}
}
- ///
- /// Feed the specified scanner.
- ///
- /// Scanner.
- ///
- /// protected override void Feed(ref BufferScanner 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);
- /// }
- /// }
- ///
- protected abstract void Feed(ref BufferScanner scanner);
-
public abstract bool EOF { get; }
-
+
}
}