--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jsonsax.cpp Sat Oct 06 21:08:55 2012 -0400
@@ -0,0 +1,276 @@
+#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
+