JSONScanner.cs
89 lines
| 3.5 KiB
| text/x-csharp
|
CSharpLexer
cin
|
r55 | using Implab.Parsing; | ||
using System; | ||||
using System.Collections.Generic; | ||||
using System.Globalization; | ||||
using System.Linq; | ||||
using System.Text; | ||||
using System.Threading.Tasks; | ||||
namespace Implab.JSON { | ||||
/// <summary> | ||||
/// Сканнер, разбивающий поток символов на токены JSON. | ||||
/// </summary> | ||||
public class JSONScanner : Scanner { | ||||
char[] m_stringBuffer; | ||||
DFAStateDescriptior[] m_stringDFA; | ||||
int[] m_stringAlphabet; | ||||
public JSONScanner() | ||||
: base(JSONGrammar.Instance.JsonDFA) { | ||||
m_stringBuffer = new char[1024]; | ||||
var dfa = JSONGrammar.Instance.JsonStringDFA; | ||||
m_stringAlphabet = dfa.Alphabet.GetTranslationMap(); | ||||
m_stringDFA = dfa.States; | ||||
} | ||||
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; | ||||
} | ||||
} | ||||
} | ||||
} | ||||