|
|
using System;
|
|
|
using Implab.Automaton.RegularExpressions;
|
|
|
using Implab.Automaton;
|
|
|
|
|
|
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;
|
|
|
|
|
|
public BufferScanner(DFAStateDescriptor<TTag>[] dfa, int initialState, int chunk, int limit) {
|
|
|
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;
|
|
|
}
|
|
|
|
|
|
/// <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];
|
|
|
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)
|
|
|
)
|
|
|
);
|
|
|
}
|
|
|
m_state = next;
|
|
|
m_position++;
|
|
|
}
|
|
|
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
public void Eof() {
|
|
|
if (!m_dfa[m_state].final)
|
|
|
throw new ParserException(
|
|
|
String.Format(
|
|
|
"Unexpected token '{0}'",
|
|
|
new string(m_buffer, m_offset, m_position - m_offset)
|
|
|
)
|
|
|
);
|
|
|
}
|
|
|
|
|
|
public TTag[] GetTokenTags() {
|
|
|
return m_dfa[m_state].tags;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|