diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/jsonParse.h | 43 | ||||
-rw-r--r-- | lib/jsonParse.impl.cpp | 39 | ||||
-rw-r--r-- | lib/jsonParse.ll | 156 |
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; |