##// END OF EJS Templates
Added initial JSON support...
Added initial JSON support +JSONParser +JSONWriter

File last commit:

r55:c0bf853aa04f default
r55:c0bf853aa04f default
Show More
Scanner.cs
207 lines | 7.9 KiB | text/x-csharp | CSharpLexer
using Implab;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Implab.Parsing {
/// <summary>
/// Базовый класс для разбора потока входных символов на токены.
/// </summary>
/// <remarks>
/// Сканнер имеет внутри буффер с симолами входного текста, по которому перемещаются два
/// указателя, начала и конца токена, при перемещении искользуется ДКА для определения
/// конца токена и допустимости текущего символа.
/// </remarks>
public class Scanner {
struct ScannerConfig {
public DFAStateDescriptior[] states;
public int[] alphabetMap;
}
Stack<ScannerConfig> m_defs = new Stack<ScannerConfig>();
DFAStateDescriptior[] m_states;
int[] m_alphabetMap;
protected DFAStateDescriptior m_currentState;
int m_previewCode;
protected int m_tokenLen = 0;
protected int m_tokenOffset;
protected char[] m_buffer;
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());
}
public Scanner(CDFADefinition definition) {
Safe.ArgumentNotNull(definition, "definition");
m_states = definition.States;
m_alphabetMap = definition.Alphabet.GetTranslationMap();
Feed(new char[0]);
}
/// <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");
m_pointer = -1;
m_buffer = data;
m_bufferSize = length;
Shift();
}
/// <summary>
/// Получает текущий токен в виде строки.
/// </summary>
/// <returns></returns>
public string GetTokenValue() {
return new String(m_buffer, m_tokenOffset, m_tokenLen);
}
/// <summary>
/// Метки текущего токена, которые были назначены в регулярном выражении.
/// </summary>
public int[] TokenTags {
get {
return m_currentState.tag;
}
}
/// <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_states[CDFADefinition.INITIAL_STATE];
m_tokenLen = 0;
m_tokenOffset = m_pointer;
int nextState = CDFADefinition.UNREACHEBLE_STATE;
do {
nextState = m_currentState.transitions[m_previewCode];
if (nextState == CDFADefinition.UNREACHEBLE_STATE) {
if (m_currentState.final)
return true;
else
throw new ParserException(
String.Format(
"Unexpected symbol '{0}', at pos {1}",
m_buffer[m_pointer],
Position
)
);
} else {
m_currentState = m_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) {
return ReadNextChunk();
}
m_previewCode = m_alphabetMap[m_buffer[m_pointer]];
return true;
}
/// <summary>
/// Вызывается по достижению конца входного буффера для получения
/// новых данных.
/// </summary>
/// <returns><c>true</c> - новые двнные получены, можно продолжать обработку.</returns>
protected virtual bool ReadNextChunk() {
return false;
}
/// <summary>
/// Позиция сканнера во входном буфере
/// </summary>
public int Position {
get {
return m_pointer + 1;
}
}
/// <summary>
/// Преключает внутренний ДКА на указанный, позволяет реализовать подобие захватывающей
/// группировки.
/// </summary>
/// <param name="states">Таблица состояний нового ДКА</param>
/// <param name="alphabet">Таблица входных символов для нового ДКА</param>
protected void Switch(DFAStateDescriptior[] states, int[] alphabet) {
Safe.ArgumentNotNull(states, "dfa");
m_defs.Push(new ScannerConfig {
states = m_states,
alphabetMap = m_alphabetMap
});
m_states = states;
m_alphabetMap = alphabet;
m_previewCode = m_alphabetMap[m_buffer[m_pointer]];
}
/// <summary>
/// Восстанавливает предыдущей ДКА сканнера.
/// </summary>
protected void Restore() {
if (m_defs.Count == 0)
throw new InvalidOperationException();
var prev = m_defs.Pop();
m_states = prev.states;
m_alphabetMap = prev.alphabetMap;
m_previewCode = m_alphabetMap[m_buffer[m_pointer]];
}
}
}