summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/jsonParse.h43
-rw-r--r--lib/jsonParse.impl.cpp39
-rw-r--r--lib/jsonParse.ll156
3 files changed, 238 insertions, 0 deletions
diff --git a/lib/jsonParse.h b/lib/jsonParse.h
new file mode 100644
index 0000000..6b1249f
--- /dev/null
+++ b/lib/jsonParse.h
@@ -0,0 +1,43 @@
+#ifndef JSONFLEXLEXER_H
+#define JSONFLEXLEXER_H
+
+#ifndef FLEX_SCANNER
+# define yyFlexLexer jsonBaseFlexLexer
+# include <FlexLexer.h>
+#endif
+#include <cassert>
+#include <filesystem>
+#include <fstream>
+#include <memory>
+#include <stdexcept>
+#include <string>
+
+namespace json {
+ class jsonParser : public yyFlexLexer {
+ public:
+ using yyFlexLexer::yyFlexLexer;
+ int yylex() override;
+
+ static void appendEscape(const char *, std::string &);
+ static void appendEscape(unsigned long, std::string &);
+
+ protected:
+ virtual void BeginObject() = 0;
+ virtual void BeginArray() = 0;
+
+ virtual void PushBoolean(bool) = 0;
+ virtual void PushNumber(float) = 0;
+ virtual void PushNull() = 0;
+ virtual void PushText(std::string &&) = 0;
+ virtual void PushKey(std::string &&) = 0;
+
+ virtual void EndArray() = 0;
+ virtual void EndObject() = 0;
+
+ void LexerError(const char * msg) override;
+
+ std::string buf;
+ };
+}
+
+#endif
diff --git a/lib/jsonParse.impl.cpp b/lib/jsonParse.impl.cpp
new file mode 100644
index 0000000..27e73b4
--- /dev/null
+++ b/lib/jsonParse.impl.cpp
@@ -0,0 +1,39 @@
+#include "jsonParse.h"
+
+void
+json::jsonParser::LexerError(const char * msg)
+{
+ throw std::runtime_error(msg);
+}
+
+void
+json::jsonParser::appendEscape(const char * cphs, std::string & str)
+{
+ appendEscape(std::strtoul(cphs, nullptr, 16), str);
+}
+
+void
+json::jsonParser::appendEscape(unsigned long cp, std::string & str)
+{
+ if (cp <= 0x7F) {
+ str += cp;
+ }
+ else if (cp <= 0x7FF) {
+ str += (cp >> 6) + 192;
+ str += (cp & 63) + 128;
+ }
+ else if (0xd800 <= cp && cp <= 0xdfff) {
+ throw std::range_error("Invalid UTF-8 sequence");
+ }
+ else if (cp <= 0xFFFF) {
+ str += (cp >> 12) + 224;
+ str += ((cp >> 6) & 63) + 128;
+ str += (cp & 63) + 128;
+ }
+ else if (cp <= 0x10FFFF) {
+ str += (cp >> 18) + 240;
+ str += ((cp >> 12) & 63) + 128;
+ str += ((cp >> 6) & 63) + 128;
+ str += (cp & 63) + 128;
+ }
+}
diff --git a/lib/jsonParse.ll b/lib/jsonParse.ll
new file mode 100644
index 0000000..0fc27e9
--- /dev/null
+++ b/lib/jsonParse.ll
@@ -0,0 +1,156 @@
+%option batch
+%option c++
+%option noyywrap
+%option 8bit
+%option stack
+%option yylineno
+%option yyclass="json::jsonParser"
+%option prefix="jsonBase"
+
+%{
+#include <string>
+#include "jsonParse.h"
+#pragma GCC diagnostic ignored "-Wsign-compare"
+#pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
+#ifdef __clang__
+#pragma clang diagnostic ignored "-Wnull-conversion"
+#endif
+%}
+
+beginobj "{"
+endobj "}"
+beginarray "["
+endarray "]"
+beginstr "\""
+endstr "\""
+true "true"
+false "false"
+null "null"
+number [-+]?[0-9]+(\.[0-9]+)?
+colon ":"
+separator ","
+escape "\\"
+text [^\\\"]*
+
+%x OBJECT_ITEM
+%x OBJECT_ITEM_OR_END
+%x OBJECT_NEXT
+%x ARRAY_ITEM
+%x ARRAY_NEXT
+%x COLON
+%x TEXT
+%x STRING
+%x ESCAPE
+
+%%
+
+<ARRAY_ITEM,INITIAL>{true} {
+ PushBoolean(true);
+ yy_pop_state();
+}
+
+<ARRAY_ITEM,INITIAL>{false} {
+ PushBoolean(false);
+ yy_pop_state();
+}
+
+<ARRAY_ITEM,INITIAL>{number} {
+ PushNumber(std::strtof(YYText(), NULL));
+ yy_pop_state();
+}
+
+<ARRAY_ITEM,INITIAL>{null} {
+ PushNull();
+ yy_pop_state();
+}
+
+<ARRAY_ITEM,INITIAL,OBJECT_ITEM,OBJECT_ITEM_OR_END>{beginstr} {
+ yy_push_state(STRING);
+}
+
+<ARRAY_ITEM,INITIAL>{beginobj} {
+ BeginObject();
+ BEGIN(OBJECT_ITEM_OR_END);
+}
+
+<ARRAY_ITEM,INITIAL>{beginarray} {
+ BeginArray();
+ BEGIN(ARRAY_NEXT);
+ yy_push_state(ARRAY_ITEM);
+}
+
+<STRING>{endstr} {
+ yy_pop_state();
+ switch (YY_START) {
+ case ARRAY_ITEM:
+ case INITIAL:
+ PushText(std::move(buf));
+ yy_pop_state();
+ break;
+ case OBJECT_ITEM:
+ case OBJECT_ITEM_OR_END:
+ PushKey(std::move(buf));
+ BEGIN(COLON);
+ break;
+ }
+ buf.clear();
+}
+
+<OBJECT_NEXT,OBJECT_ITEM_OR_END>{endobj} {
+ EndObject();
+ yy_pop_state();
+}
+
+<ARRAY_ITEM>{endarray} {
+ EndArray();
+ yy_pop_state();
+ yy_pop_state();
+}
+
+<ARRAY_NEXT>{endarray} {
+ EndArray();
+ yy_pop_state();
+}
+
+<COLON>{colon} {
+ BEGIN(OBJECT_NEXT);
+ yy_push_state(INITIAL);
+}
+
+<OBJECT_NEXT>{separator} {
+ BEGIN(OBJECT_ITEM);
+}
+
+<ARRAY_NEXT>{separator} {
+ yy_push_state(INITIAL);
+}
+
+<STRING>{escape} {
+ yy_push_state(ESCAPE);
+}
+
+<ESCAPE>"\"" { buf += "\""; yy_pop_state(); }
+<ESCAPE>"\\" { buf += "\\"; yy_pop_state(); }
+<ESCAPE>"/" { buf += "/"; yy_pop_state(); }
+<ESCAPE>"b" { buf += "\b"; yy_pop_state(); }
+<ESCAPE>"f" { buf += "\f"; yy_pop_state(); }
+<ESCAPE>"n" { buf += "\n"; yy_pop_state(); }
+<ESCAPE>"r" { buf += "\r"; yy_pop_state(); }
+<ESCAPE>"t" { buf += "\t"; yy_pop_state(); }
+
+<ESCAPE>"u"[0-9a-fA-Z]{4} {
+ appendEscape(YYText(), buf);
+ yy_pop_state();
+}
+
+<STRING>{text} {
+ buf += YYText();
+}
+
+<*>[ \t\r\n\f] {
+}
+
+%%
+
+// Make iwyu think unistd.h is required
+[[maybe_unused]]static auto x=getpid;