First version, c++.
#include "jsonsax.hpp"
#include <assert.h>
#define CASE_IS_SPACE \
case ' ': \
case '\n': \
case '\t': \
case '\r'
#define CASE_IS_DIGIT \
case '0': \
case '1': \
case '2': \
case '3': \
case '4': \
case '5': \
case '6': \
case '7': \
case '8': \
case '9'
JSLXParser::JSLXParser(IJSLXBackend* pBackend)
: m_pBackend(pBackend)
{}
bool JSLXParser::Parse()
{
return GetNextChar() && ParseValue();
}
bool JSLXParser::_GetNextChar()
{
if (!m_pBackend->Eof())
{
m_lastChar = m_pBackend->GetChar();
return true;
}
return false;
}
bool JSLXParser::TrimWhiteSpace()
{
do
{
switch(m_lastChar)
{
CASE_IS_SPACE:
break;
default:
return true;
}
}
while(_GetNextChar());
return false;
}
bool JSLXParser::GetNextChar(bool trim /* = true */)
{
if (trim)
{
return _GetNextChar() && TrimWhiteSpace();
}
return _GetNextChar();
}
bool JSLXParser::ParseValue()
{
switch(m_lastChar)
{
case '[':
return ParseArray();
case '{':
return ParseObject();
case '"':
return ParseString();
case '-':
CASE_IS_DIGIT:
return ParseNumber();
case 'n':
return ParseNull();
case 't':
return ParseTrue();
case 'f':
return ParseFalse();
default:
return false;
}
}
bool JSLXParser::ParseObject()
{
assert(m_lastChar == '{');
m_pBackend->OnStartObject();
GetNextChar();
while(ParsePair())
{
switch(m_lastChar)
{
case ',':
GetNextChar();
break;
case '}':
m_pBackend->OnStopObject();
GetNextChar();
return true;
default:
m_pBackend->OnError("ParseObject: invalid char");
return false;
}
}
if (m_lastChar != '}')
{
m_pBackend->OnError("ParseObject: invalid char");
return false;
}
m_pBackend->OnStopObject();
GetNextChar();
return true;
}
bool JSLXParser::ParsePair()
{
if (m_lastChar != '"')
{
m_pBackend->OnError("ParsePair: Invalid Key");
return false;
}
if (!ParseString())
{
m_pBackend->OnError("ParsePair: Invalid Key");
return false;
}
if (m_lastChar != ':')
{
m_pBackend->OnError("ParsePair: Missing pair separator");
return false;
}
if (!GetNextChar())
{
m_pBackend->OnError("ParsePair: Missing value");
return false;
}
return ParseValue();
}
bool JSLXParser::ParseArray()
{
assert(m_lastChar == '[');
if (!GetNextChar()) return false;
while(ParseValue())
{
switch(m_lastChar)
{
case ',':
GetNextChar();
break;
case ']':
m_pBackend->OnStopArray();
GetNextChar();
return true;
default:
m_pBackend->OnError("ParseArray: Missing seperator in array");
return false;
}
}
if (m_lastChar != ']')
{
m_pBackend->OnError("ParseArray: Bad value in array");
return false;
}
m_pBackend->OnStopArray();
GetNextChar();
return true;
}
bool JSLXParser::ParseString()
{
assert(m_lastChar == '"');
m_pBackend->OnStartString();
while(GetNextChar())
{
switch(m_lastChar)
{
case '\\':
GetNextChar();
break;
case '"':
m_pBackend->OnStopString();
GetNextChar();
return true;
}
}
return false;
}
bool JSLXParser::ParseNumber()
{
assert(m_lastChar == '-' ||
m_lastChar == '0' ||
m_lastChar == '1' ||
m_lastChar == '2' ||
m_lastChar == '3' ||
m_lastChar == '4' ||
m_lastChar == '5' ||
m_lastChar == '6' ||
m_lastChar == '7' ||
m_lastChar == '8' ||
m_lastChar == '9');
m_pBackend->OnStartNumber();
while(GetNextChar())
{
switch(m_lastChar)
{
// TODO: lookup for correct number format.
case 'e':
case '-':
case '.':
CASE_IS_DIGIT:
break;
default:
m_pBackend->OnStopNumber();
return true;
}
}
return true;
}
bool JSLXParser::ParseNull()
{
if (ParseConstant("null"))
{
m_pBackend->OnNull();
return true;
}
return false;
}
bool JSLXParser::ParseTrue()
{
if (ParseConstant("true"))
{
m_pBackend->OnTrue();
return true;
}
return false;
}
bool JSLXParser::ParseFalse()
{
if (ParseConstant("false"))
{
m_pBackend->OnFalse();
return true;
}
return false;
}
bool JSLXParser::ParseConstant(const char* constant)
{
assert(m_lastChar == constant[0]);
++constant;
while(GetNextChar())
{
if (*constant == '\0')
return true;
if (*constant != m_lastChar)
return false;
constant++;
}
return *constant == '\0';
}
#undef CASE_IS_DIGIT
#undef CASE_IS_SPACE