Skip to content

Instantly share code, notes, and snippets.

@Bloodb0ne
Last active April 8, 2020 19:08
Show Gist options
  • Save Bloodb0ne/d1ea6949ce042ce760020b54023e2f20 to your computer and use it in GitHub Desktop.
Save Bloodb0ne/d1ea6949ce042ce760020b54023e2f20 to your computer and use it in GitHub Desktop.
Parser Combinator JSON Example
//Transformations
constexpr auto to_string = [](auto v) { return std::string(1, v); };
constexpr auto vec_to_string = [](auto v) {
return std::accumulate(v.begin(), v.end(), std::string{});
};
//Grammar
constexpr auto ws = monadic::Many(symbs<'\n', '\t', '\r',' '>() % to_string);
constexpr auto str_wrap = Wrapper('"'_symb, '"'_symb);
constexpr auto obj_wrap = Wrapper('{'_symb, '}'_symb);
constexpr auto array_wrap = Wrapper('['_symb, ']'_symb);
//Handle Scientific notation
constexpr auto json_int = AcceptString('0'_symb % to_string || "1..9"_range % to_string && monadic::Many(AcceptString("0..9"_range)));
constexpr auto json_exp = symbs<'E', 'e'>() % to_string && Optional(symbs<'+', '-'>() % to_string) && json_int;
constexpr auto float_part = AcceptString('.'_symb % to_string && monadic::Many(AcceptString("0..9"_range)));
constexpr auto json_number = Optional('-'_symb % to_string) && json_int && Optional(float_part) && Optional(json_exp);
constexpr auto json_string = str_wrap(monadic::Repeat(AcceptString("a..z"_range || "A..Z"_range)));
constexpr auto json_obj = [&](const auto json_value) {
return obj_wrap(SepBy(json_value, ','_symb) % vec_to_string || ws);
};
constexpr auto json_arr = [&](const auto json_value) {
return array_wrap(SepBy(json_value, ','_symb) % vec_to_string || ws);
};
Rule<ctxStringIter, std::string> json_value =
json_number ||
json_string ||
json_arr(Reference(&json_value)) ||
json_obj(json_string && AcceptString(':'_symb) && AcceptString(Reference(&json_value))) ||
ParseLit("true") ||
ParseLit("false") ||
ParseLit("null");
std::string test_string = "[1,-3.45,[],{},5,6,\"asd\",{\"Test\":\"Arr\"},{\"Tester\":[1,2,34,3,5,6]},{\n}]";
ctxStringIter start = test_string.begin();
ctxStringIter end = test_string.end();
decltype(json_value)::return_type var_test;
bool hasParsed = json_value(start, end, &var_test);
if (hasParsed) {
std::cout << "Parsed Successfully" << std::endl;
std::cout << "Result:= " << var_test << std::endl;
std::cout << "(line: " << start.getCurrentLine() << " col: " << start.getCurrentCol() << std::endl;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment