123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166 |
- #include <sstream>
- #include "parser.h"
- #include "utils.h"
- namespace json {
- std::string bad_near(const std::string &type, const unsigned int &pos) {
- std::ostringstream err;
- err << "bad type of '" << type << "' near position [" << pos << ']';
- return err.str();
- }
- std::string bad_near(const char &c, const unsigned int &pos) {
- std::ostringstream err;
- err << "bad character '" << c << "' near position [" << pos << ']';
- return err.str();
- }
- char Parser::next_real() {
- while (std::isspace(_str[_idx])) _idx++;
- return _str[_idx];
- }
- bool Parser::is_str_end(unsigned const &pos) {
- unsigned front = pos;
- while (_str[front] == '\\') front--;
- return (pos - front) % 2 == 0;
- }
- Value Parser::_parse() {
- char next = next_real();
- switch (next) {
- case 'n':
- return parse_null();
- case 't':
- case 'f':
- return parse_bool();
- case '-':
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- return parse_number();
- case '"':
- return parse_string();
- case '[':
- return parse_list();
- case '{':
- return parse_dict();
- default:
- throw std::logic_error(bad_near(_str[_idx], _idx));
- }
- }
- Value Parser::parse_null() {
- if (_str.compare(_idx, 4, "null") == 0) {
- _idx += 4;
- return {};
- }
- throw std::logic_error(bad_near("null", _idx));
- }
- Value Parser::parse_bool() {
- if (_str.compare(_idx, 4, "true") == 0) {
- _idx += 4;
- return Value(true);
- }
- if (_str.compare(_idx, 5, "false") == 0) {
- _idx += 5;
- return Value(false);
- }
- throw std::logic_error(bad_near("bool", _idx));
- }
- Value Parser::parse_number() {
- unsigned start = _idx;
- if (_str[_idx] == '-') _idx++;
- if (std::isdigit(_str[_idx])) {
- while (std::isdigit(_str[_idx])) _idx++;
- // decimal
- if (_str[_idx] == '.') {
- _idx++;
- if (std::isdigit(_str[_idx])) {
- while (std::isdigit(_str[_idx])) _idx++;
- return Value(std::strtod(_str.c_str() + start, nullptr));
- } else throw std::logic_error(bad_near("number", _idx));
- }
- if (_str[_idx] != '.')
- return Value(std::strtol(_str.c_str() + start, nullptr, 10));
- } else throw std::logic_error(bad_near("number", _idx));
- // 不会到这里
- return {};
- }
- Value Parser::parse_string() {
- unsigned start = ++_idx;
- auto end = _str.find('"', _idx);
- if (end != std::string::npos) {
- // 可能是 \" 而不是真正的字符串结尾
- while (true) {
- if (is_str_end(end - 1)) break;
- end = _str.find('"', end + 1);
- if (end == std::string::npos) throw std::logic_error(bad_near("string", _idx));
- }
- _idx = end + 1;
- return Value(_str.substr(start, end - start));
- }
- throw std::logic_error(bad_near("string", _idx));
- }
- Value Parser::parse_list() {
- std::vector<Value> list;
- _idx++;
- char c;
- while (true) {
- c = next_real();
- if (c == ',') _idx++;
- else if (c == ']') {
- _idx++;
- return Value(list);
- } else list.push_back(_parse());
- }
- }
- Value Parser::parse_dict() {
- std::map<std::string, Value> dict;
- _idx++;
- char c;
- string_type key;
- while (true) {
- c = next_real();
- if (c == '"') {
- key = parse_string().value<string_type>();
- if (next_real() == ':') {
- _idx++;
- dict[key] = _parse();
- } else throw std::logic_error(bad_near("dict", _idx));
- } else if (c == ',') _idx++;
- else if (c == '}') {
- _idx++;
- return Value(dict);
- } else throw std::logic_error(bad_near("dict", _idx));
- }
- }
- Parser::Parser() {
- _str = "";
- _idx = 0;
- }
- Value Parser::parse(const std::string &str) {
- _str = hm::trim(str);
- auto max = _str.size() - 1;
- if (max < 0) throw std::logic_error("blank string");
- if (!((_str[0] == '{' && _str[max] == '}') || (_str[0] == '[' && _str[max] == ']')))
- throw std::logic_error("bad json string");
- _idx = 0;
- return _parse();
- }
- }
|