diff options
author | Mike Pall <mike> | 2015-08-19 02:10:36 +0200 |
---|---|---|
committer | Mike Pall <mike> | 2015-08-19 02:10:36 +0200 |
commit | eb050f9e2abc7432b17059f900c70bf7ce5575c9 (patch) | |
tree | b163cd6368ce0785ce4f65a076d11f8db4fd9409 | |
parent | 0dcd2d129241964925e27831fa61194a8dbe6191 (diff) | |
download | luajit2-eb050f9e2abc7432b17059f900c70bf7ce5575c9.tar.gz |
Parse binary number literals (0bxxx).
-rw-r--r-- | doc/ext_ffi_api.html | 4 | ||||
-rw-r--r-- | doc/extensions.html | 2 | ||||
-rw-r--r-- | src/lj_strscan.c | 57 |
3 files changed, 56 insertions, 7 deletions
diff --git a/doc/ext_ffi_api.html b/doc/ext_ffi_api.html index 8cf48dc3..b095c05f 100644 --- a/doc/ext_ffi_api.html +++ b/doc/ext_ffi_api.html @@ -546,8 +546,8 @@ corresponding ctype. The parser for Lua source code treats numeric literals with the suffixes <tt>LL</tt> or <tt>ULL</tt> as signed or unsigned 64 bit integers. Case doesn't matter, but uppercase is recommended for -readability. It handles both decimal (<tt>42LL</tt>) and hexadecimal -(<tt>0x2aLL</tt>) literals. +readability. It handles decimal (<tt>42LL</tt>), hexadecimal +(<tt>0x2aLL</tt>) and binary (<tt>0b101010LL</tt>) literals. </p> <p> The imaginary part of complex numbers can be specified by suffixing diff --git a/doc/extensions.html b/doc/extensions.html index d2f8d7ba..3122051d 100644 --- a/doc/extensions.html +++ b/doc/extensions.html @@ -183,7 +183,7 @@ in <tt>"-inf"</tt>. <h3 id="tonumber"><tt>tonumber()</tt> etc. use builtin string to number conversion</h3> <p> All string-to-number conversions consistently convert integer and -floating-point inputs in decimal and hexadecimal on all platforms. +floating-point inputs in decimal, hexadecimal and binary on all platforms. <tt>strtod()</tt> is <em>not</em> used anymore, which avoids numerous problems with poor C library implementations. The builtin conversion function provides full precision according to the IEEE-754 standard, it diff --git a/src/lj_strscan.c b/src/lj_strscan.c index 568f647d..d3c5ba91 100644 --- a/src/lj_strscan.c +++ b/src/lj_strscan.c @@ -140,7 +140,7 @@ static StrScanFmt strscan_hex(const uint8_t *p, TValue *o, break; } - /* Reduce range then convert to double. */ + /* Reduce range, then convert to double. */ if ((x & U64x(c0000000,0000000))) { x = (x >> 2) | (x & 3); ex2 += 2; } strscan_double(x, o, ex2, neg); return fmt; @@ -326,6 +326,49 @@ static StrScanFmt strscan_dec(const uint8_t *p, TValue *o, return fmt; } +/* Parse binary number. */ +static StrScanFmt strscan_bin(const uint8_t *p, TValue *o, + StrScanFmt fmt, uint32_t opt, + int32_t ex2, int32_t neg, uint32_t dig) +{ + uint64_t x = 0; + uint32_t i; + + if (ex2 || dig > 64) return STRSCAN_ERROR; + + /* Scan binary digits. */ + for (i = dig; i; i--, p++) { + if ((*p & ~1) != '0') return STRSCAN_ERROR; + x = (x << 1) | (*p & 1); + } + + /* Format-specific handling. */ + switch (fmt) { + case STRSCAN_INT: + if (!(opt & STRSCAN_OPT_TONUM) && x < 0x80000000u+neg) { + o->i = neg ? -(int32_t)x : (int32_t)x; + return STRSCAN_INT; /* Fast path for 32 bit integers. */ + } + if (!(opt & STRSCAN_OPT_C)) { fmt = STRSCAN_NUM; break; } + /* fallthrough */ + case STRSCAN_U32: + if (dig > 32) return STRSCAN_ERROR; + o->i = neg ? -(int32_t)x : (int32_t)x; + return STRSCAN_U32; + case STRSCAN_I64: + case STRSCAN_U64: + o->u64 = neg ? (uint64_t)-(int64_t)x : x; + return fmt; + default: + break; + } + + /* Reduce range, then convert to double. */ + if ((x & U64x(c0000000,0000000))) { x = (x >> 2) | (x & 3); ex2 += 2; } + strscan_double(x, o, ex2, neg); + return fmt; +} + /* Scan string containing a number. Returns format. Returns value in o. */ StrScanFmt lj_strscan_scan(const uint8_t *p, TValue *o, uint32_t opt) { @@ -364,8 +407,12 @@ StrScanFmt lj_strscan_scan(const uint8_t *p, TValue *o, uint32_t opt) /* Determine base and skip leading zeros. */ if (LJ_UNLIKELY(*p <= '0')) { - if (*p == '0' && casecmp(p[1], 'x')) - base = 16, cmask = LJ_CHAR_XDIGIT, p += 2; + if (*p == '0') { + if (casecmp(p[1], 'x')) + base = 16, cmask = LJ_CHAR_XDIGIT, p += 2; + else if (casecmp(p[1], 'b')) + base = 2, cmask = LJ_CHAR_DIGIT, p += 2; + } for ( ; ; p++) { if (*p == '0') { hasdig = 1; @@ -403,7 +450,7 @@ StrScanFmt lj_strscan_scan(const uint8_t *p, TValue *o, uint32_t opt) } /* Parse exponent. */ - if (casecmp(*p, (uint32_t)(base == 16 ? 'p' : 'e'))) { + if (base >= 10 && casecmp(*p, (uint32_t)(base == 16 ? 'p' : 'e'))) { uint32_t xx; int negx = 0; fmt = STRSCAN_NUM; p++; @@ -460,6 +507,8 @@ StrScanFmt lj_strscan_scan(const uint8_t *p, TValue *o, uint32_t opt) return strscan_oct(sp, o, fmt, neg, dig); if (base == 16) fmt = strscan_hex(sp, o, fmt, opt, ex, neg, dig); + else if (base == 2) + fmt = strscan_bin(sp, o, fmt, opt, ex, neg, dig); else fmt = strscan_dec(sp, o, fmt, opt, ex, neg, dig); |