JSONScanner.cs
96 lines
| 4.6 KiB
| text/x-csharp
|
CSharpLexer
cin
|
r165 | using System; | ||
cin
|
r163 | using System.Globalization; | ||
cin
|
r165 | using Implab.Automaton; | ||
cin
|
r163 | |||
cin
|
r165 | namespace Implab.Formats.JSON { | ||
cin
|
r163 | /// <summary> | ||
/// Сканнер (лексер), разбивающий поток символов на токены JSON. | ||||
/// </summary> | ||||
cin
|
r165 | public class JSONScanner : Scanner<object> { | ||
cin
|
r163 | char[] m_stringBuffer; | ||
cin
|
r165 | DFAStateDescriptior<>[] m_stringDFA; | ||
cin
|
r163 | int[] m_stringAlphabet; | ||
/// <summary> | ||||
/// Создает новый экземпляр сканнера | ||||
/// </summary> | ||||
public JSONScanner() | ||||
cin
|
r165 | : base(JSONGrammar.Instance.JsonDFA.GetTransitionTable(), JSONGrammar.Instance.JsonDFA.Alphabet.GetTranslationMap()) { | ||
cin
|
r163 | m_stringBuffer = new char[1024]; | ||
var dfa = JSONGrammar.Instance.JsonStringDFA; | ||||
m_stringAlphabet = dfa.Alphabet.GetTranslationMap(); | ||||
m_stringDFA = dfa.States; | ||||
} | ||||
/// <summary> | ||||
/// Читает следующий лексический элемент из входных данных. | ||||
/// </summary> | ||||
/// <param name="tokenValue">Возвращает значение прочитанного токена.</param> | ||||
/// <param name="tokenType">Возвращает тип прочитанного токена.</param> | ||||
/// <returns><c>true</c> - чтение произведено успешно. <c>false</c> - достигнут конец входных данных</returns> | ||||
/// <remarks>В случе если токен не распознается, возникает исключение. Значения токенов обрабатываются, т.е. | ||||
/// в строках обрабатываются экранированные символы, числа становтся типа double.</remarks> | ||||
public bool ReadToken(out object tokenValue, out JsonTokenType tokenType) { | ||||
if (ReadTokenInternal()) { | ||||
switch ((JSONGrammar.TokenType)m_currentState.tag[0]) { | ||||
case JSONGrammar.TokenType.StringBound: | ||||
tokenValue = ReadString(); | ||||
tokenType = JsonTokenType.String; | ||||
break; | ||||
case JSONGrammar.TokenType.Number: | ||||
tokenValue = Double.Parse(new String(m_buffer, m_tokenOffset, m_tokenLen), CultureInfo.InvariantCulture); | ||||
tokenType = JsonTokenType.Number; | ||||
break; | ||||
default: | ||||
tokenType = (JsonTokenType)m_currentState.tag[0]; | ||||
tokenValue = new String(m_buffer, m_tokenOffset, m_tokenLen); | ||||
break; | ||||
} | ||||
return true; | ||||
} | ||||
tokenValue = null; | ||||
tokenType = JsonTokenType.None; | ||||
return false; | ||||
} | ||||
string ReadString() { | ||||
int pos = 0; | ||||
Switch(m_stringDFA, m_stringAlphabet); | ||||
while (ReadTokenInternal()) { | ||||
switch ((JSONGrammar.TokenType)m_currentState.tag[0]) { | ||||
case JSONGrammar.TokenType.StringBound: | ||||
Restore(); | ||||
return new String(m_stringBuffer, 0, pos); | ||||
case JSONGrammar.TokenType.UnescapedChar: | ||||
EnsureStringBufferSize(pos + m_tokenLen); | ||||
Array.Copy(m_buffer, m_tokenOffset, m_stringBuffer, pos, m_tokenLen); | ||||
pos += m_tokenLen; | ||||
break; | ||||
case JSONGrammar.TokenType.EscapedUnicode: | ||||
EnsureStringBufferSize(pos + 1); | ||||
m_stringBuffer[pos] = StringTranslator.TranslateHexUnicode(m_buffer, m_tokenOffset + 2); | ||||
pos++; | ||||
break; | ||||
case JSONGrammar.TokenType.EscapedChar: | ||||
EnsureStringBufferSize(pos + 1); | ||||
m_stringBuffer[pos] = StringTranslator.TranslateEscapedChar(m_buffer[m_tokenOffset + 1]); | ||||
pos++; | ||||
break; | ||||
default: | ||||
break; | ||||
} | ||||
} | ||||
throw new ParserException("Unexpected end of data"); | ||||
} | ||||
void EnsureStringBufferSize(int size) { | ||||
if (size > m_stringBuffer.Length) { | ||||
var newBuffer = new char[size]; | ||||
m_stringBuffer.CopyTo(newBuffer, 0); | ||||
m_stringBuffer = newBuffer; | ||||
} | ||||
} | ||||
} | ||||
} | ||||