jsonsax.cpp
changeset 0 d187e7fc9970
--- /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
+