|
|
@@ -6,6 +6,7 @@
|
|
|
//
|
|
|
|
|
|
#include "json_common.hpp"
|
|
|
+#include <map>
|
|
|
|
|
|
namespace json {
|
|
|
namespace helper {
|
|
|
@@ -19,35 +20,81 @@ namespace json {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ namespace {
|
|
|
+ std::map<numeric_token_info::parse_state, uint_jt> bases{
|
|
|
+ { numeric_token_info::decimal, 10 },
|
|
|
+ { numeric_token_info::octal, 8 },
|
|
|
+ { numeric_token_info::hexadecimal, 16 }
|
|
|
+ };
|
|
|
+ std::map<numeric_token_info::parse_state, std::string> allowed{
|
|
|
+ { numeric_token_info::decimal, "0123456789" },
|
|
|
+ { numeric_token_info::octal, "01234567" },
|
|
|
+ { numeric_token_info::hexadecimal, "0123456789aAbBcCdDeEfF" }
|
|
|
+ };
|
|
|
+ std::map<char, int_jt> values{
|
|
|
+ { '0', 0 }, { '1', 1 }, { '2', 2 }, { '3', 3 },
|
|
|
+ { '4', 4 }, { '5', 5 }, { '6', 6 }, { '7', 7 },
|
|
|
+ { '8', 8 }, { '9', 9 }, { 'a', 10 }, { 'A', 10 },
|
|
|
+ { 'b', 11 }, { 'B', 11 }, { 'c', 12 }, { 'C', 12 },
|
|
|
+ { 'd', 13 }, { 'D', 13 }, { 'e', 14 }, { 'E', 14 },
|
|
|
+ { 'f', 15 }, { 'F', 15 }
|
|
|
+ };
|
|
|
+ std::map<numeric_token_info::parse_state, uint_jt> thresholds{
|
|
|
+ { numeric_token_info::decimal, UINT_JT_MAX / 10 },
|
|
|
+ { numeric_token_info::octal, UINT_JT_MAX / 8 },
|
|
|
+ { numeric_token_info::hexadecimal, UINT_JT_MAX / 16 }
|
|
|
+ };
|
|
|
+ std::map<numeric_token_info::parse_state, int_jt> last_digits{
|
|
|
+ { numeric_token_info::decimal, INT_JT_MAX % 10 },
|
|
|
+ { numeric_token_info::octal, INT_JT_MAX % 8 },
|
|
|
+ { numeric_token_info::hexadecimal, INT_JT_MAX % 16 }
|
|
|
+ };
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ // TODO - parse hex and octal
|
|
|
numeric_token_info::numeric_token_info(char const * start)
|
|
|
: val(0)
|
|
|
+ , base(decimal)
|
|
|
, it(start)
|
|
|
, end(start)
|
|
|
, is_double(false)
|
|
|
, is_negative(*start == '-') {
|
|
|
if ( is_negative ) { ++it; ++end; }
|
|
|
+ if ( *end == '0' ) {
|
|
|
+ base = octal;
|
|
|
+ ++end;
|
|
|
+ if (strchr("xX", *end)) {
|
|
|
+ base = hexadecimal;
|
|
|
+ ++end;
|
|
|
+ }
|
|
|
+ }
|
|
|
for (char c = *end;
|
|
|
- strchr(",]}", c) == NULL && !isspace(c);
|
|
|
+ !strchr(",]}", c) && !isspace(c);
|
|
|
c = *++end) {
|
|
|
- is_double |= !isdigit(*end);
|
|
|
+ is_double |= !strchr(allowed[base].c_str(), c);
|
|
|
}
|
|
|
|
|
|
+ if ( is_negative && base != decimal ) {
|
|
|
+ throw json_numeric_exception{"Only decimal numbers can be recorded as negative"};
|
|
|
+ }
|
|
|
if (end == it) {
|
|
|
throw unterminated_json_exception("Expected any token, got nothing");
|
|
|
}
|
|
|
}
|
|
|
|
|
|
numeric_state numeric_token_info::parse_numeric() {
|
|
|
- static uint_jt const threshold = (UINT_JT_MAX / 10);
|
|
|
+ uint_jt const threshold = thresholds[base];
|
|
|
+ uint_jt const last_digit = last_digits[base];
|
|
|
val = 0;
|
|
|
for (char c = *it; it != end; c = *++it) {
|
|
|
- int_jt digit = static_cast<int_jt>(c - '0');
|
|
|
+ int_jt digit = values[c];
|
|
|
if (val > threshold ||
|
|
|
( val == threshold && ((it + 1) < end ||
|
|
|
- digit > INT_JT_MAX_LAST_DIGIT))) {
|
|
|
+ digit > last_digit))) {
|
|
|
return DOUBLE;
|
|
|
}
|
|
|
- val = (10 * val) + digit;
|
|
|
+ val = (bases[base] * val) + digit;
|
|
|
}
|
|
|
return INTEGER;
|
|
|
}
|