#include #include #include "cs_std.hh" namespace cscript { static inline char const *p_skip_white(char const *beg, char const *end) { while ((beg != end) && isspace(*beg)) { ++beg; } return beg; } static inline void p_set_end( char const *nbeg, char const *nend, std::string_view *end ) { if (!end) { return; } *end = std::string_view{nbeg, nend}; } /* this function assumes the input is definitely a hex digit */ static inline cs_int p_hexd_to_int(char c) { if (c >= 97) { /* a-f */ return (c - 'a') + 10; } else if (c >= 65) { /* A-F */ return (c - 'A') + 10; } /* 0-9 */ return c - '0'; } static inline bool p_check_neg(char const *&input) { bool neg = (*input == '-'); if (neg || (*input == '+')) { ++input; } return neg; } cs_int parse_int(std::string_view input, std::string_view *endstr) { char const *beg = input.begin(); char const *end = input.end(); char const *orig = beg; beg = p_skip_white(beg, end); if (beg == end) { p_set_end(orig, end, endstr); return cs_int(0); } bool neg = p_check_neg(beg); cs_int ret = 0; char const *past = beg; if ((end - beg) >= 2) { std::string_view pfx = std::string_view{beg, 2}; if ((pfx == "0x") || (pfx == "0X")) { beg += 2; past = beg; while ((past != end) && std::isxdigit(*past)) { ret = ret * 16 + p_hexd_to_int(*past++); } goto done; } else if ((pfx == "0b") || (pfx == "0B")) { beg += 2; past = beg; while ((past != end) && ((*past == '0') || (*past == '1'))) { ret = ret * 2 + (*past++ - '0'); } goto done; } } while ((past != end) && std::isdigit(*past)) { ret = ret * 10 + (*past++ - '0'); } done: p_set_end((past == beg) ? orig : past, end, endstr); if (neg) { return -ret; } return ret; } template static inline bool p_read_exp(char const *&beg, char const *end, cs_int &fn) { if (beg == end) { return true; } if ((*beg != e1) && (*beg != e2)) { return true; } if (++beg == end) { return false; } bool neg = p_check_neg(beg); if ((beg == end) || !std::isdigit(*beg)) { return false; } cs_int exp = 0; while ((beg != end) && std::isdigit(*beg)) { exp = exp * 10 + (*beg++ - '0'); } if (neg) { exp = -exp; } fn += exp; return true; } template static inline bool parse_gen_float( char const *&beg, char const *end, std::string_view *endstr, cs_float &ret ) { auto read_digits = [&beg, end](double r, cs_int &n) { while ( (beg != end) && (Hex ? std::isxdigit(*beg) : std::isdigit(*beg)) ) { if (Hex) { r = r * 16.0 + double(p_hexd_to_int(*beg)); } else { r = r * 10.0 + double(*beg - '0'); } ++n; ++beg; } return r; }; cs_int wn = 0, fn = 0; double r = read_digits(0.0, wn); if ((beg != end) && (*beg == '.')) { ++beg; r = read_digits(r, fn); } if (!wn && !fn) { return false; } fn = -fn; p_set_end(beg, end, endstr); /* we have a valid number until here */ if (p_read_exp(beg, end, fn)) { p_set_end(beg, end, endstr); } if (Hex) { ret = cs_float(ldexp(r, fn * 4)); } else { ret = cs_float(r * pow(10, fn)); } return true; } cs_float parse_float(std::string_view input, std::string_view *endstr) { char const *beg = input.begin(); char const *end = input.end(); char const *orig = beg; beg = p_skip_white(beg, end); if (beg == end) { p_set_end(orig, end, endstr); return cs_float(0); } bool neg = p_check_neg(beg); cs_float ret = cs_float(0); if ((end - beg) >= 2) { std::string_view pfx = std::string_view{beg, 2}; if ((pfx == "0x") || (pfx == "0X")) { beg += 2; if (!parse_gen_float(beg, end, endstr, ret)) { p_set_end(orig, end, endstr); return ret; } goto done; } } if (!parse_gen_float(beg, end, endstr, ret)) { p_set_end(orig, end, endstr); return ret; } done: if (neg) { return -ret; } return ret; } } /* namespace cscript */