diff options
-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. | |||
546 | The parser for Lua source code treats numeric literals with the | 546 | The parser for Lua source code treats numeric literals with the |
547 | suffixes <tt>LL</tt> or <tt>ULL</tt> as signed or unsigned 64 bit | 547 | suffixes <tt>LL</tt> or <tt>ULL</tt> as signed or unsigned 64 bit |
548 | integers. Case doesn't matter, but uppercase is recommended for | 548 | integers. Case doesn't matter, but uppercase is recommended for |
549 | readability. It handles both decimal (<tt>42LL</tt>) and hexadecimal | 549 | readability. It handles decimal (<tt>42LL</tt>), hexadecimal |
550 | (<tt>0x2aLL</tt>) literals. | 550 | (<tt>0x2aLL</tt>) and binary (<tt>0b101010LL</tt>) literals. |
551 | </p> | 551 | </p> |
552 | <p> | 552 | <p> |
553 | The imaginary part of complex numbers can be specified by suffixing | 553 | 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>. | |||
183 | <h3 id="tonumber"><tt>tonumber()</tt> etc. use builtin string to number conversion</h3> | 183 | <h3 id="tonumber"><tt>tonumber()</tt> etc. use builtin string to number conversion</h3> |
184 | <p> | 184 | <p> |
185 | All string-to-number conversions consistently convert integer and | 185 | All string-to-number conversions consistently convert integer and |
186 | floating-point inputs in decimal and hexadecimal on all platforms. | 186 | floating-point inputs in decimal, hexadecimal and binary on all platforms. |
187 | <tt>strtod()</tt> is <em>not</em> used anymore, which avoids numerous | 187 | <tt>strtod()</tt> is <em>not</em> used anymore, which avoids numerous |
188 | problems with poor C library implementations. The builtin conversion | 188 | problems with poor C library implementations. The builtin conversion |
189 | function provides full precision according to the IEEE-754 standard, it | 189 | 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, | |||
140 | break; | 140 | break; |
141 | } | 141 | } |
142 | 142 | ||
143 | /* Reduce range then convert to double. */ | 143 | /* Reduce range, then convert to double. */ |
144 | if ((x & U64x(c0000000,0000000))) { x = (x >> 2) | (x & 3); ex2 += 2; } | 144 | if ((x & U64x(c0000000,0000000))) { x = (x >> 2) | (x & 3); ex2 += 2; } |
145 | strscan_double(x, o, ex2, neg); | 145 | strscan_double(x, o, ex2, neg); |
146 | return fmt; | 146 | return fmt; |
@@ -326,6 +326,49 @@ static StrScanFmt strscan_dec(const uint8_t *p, TValue *o, | |||
326 | return fmt; | 326 | return fmt; |
327 | } | 327 | } |
328 | 328 | ||
329 | /* Parse binary number. */ | ||
330 | static StrScanFmt strscan_bin(const uint8_t *p, TValue *o, | ||
331 | StrScanFmt fmt, uint32_t opt, | ||
332 | int32_t ex2, int32_t neg, uint32_t dig) | ||
333 | { | ||
334 | uint64_t x = 0; | ||
335 | uint32_t i; | ||
336 | |||
337 | if (ex2 || dig > 64) return STRSCAN_ERROR; | ||
338 | |||
339 | /* Scan binary digits. */ | ||
340 | for (i = dig; i; i--, p++) { | ||
341 | if ((*p & ~1) != '0') return STRSCAN_ERROR; | ||
342 | x = (x << 1) | (*p & 1); | ||
343 | } | ||
344 | |||
345 | /* Format-specific handling. */ | ||
346 | switch (fmt) { | ||
347 | case STRSCAN_INT: | ||
348 | if (!(opt & STRSCAN_OPT_TONUM) && x < 0x80000000u+neg) { | ||
349 | o->i = neg ? -(int32_t)x : (int32_t)x; | ||
350 | return STRSCAN_INT; /* Fast path for 32 bit integers. */ | ||
351 | } | ||
352 | if (!(opt & STRSCAN_OPT_C)) { fmt = STRSCAN_NUM; break; } | ||
353 | /* fallthrough */ | ||
354 | case STRSCAN_U32: | ||
355 | if (dig > 32) return STRSCAN_ERROR; | ||
356 | o->i = neg ? -(int32_t)x : (int32_t)x; | ||
357 | return STRSCAN_U32; | ||
358 | case STRSCAN_I64: | ||
359 | case STRSCAN_U64: | ||
360 | o->u64 = neg ? (uint64_t)-(int64_t)x : x; | ||
361 | return fmt; | ||
362 | default: | ||
363 | break; | ||
364 | } | ||
365 | |||
366 | /* Reduce range, then convert to double. */ | ||
367 | if ((x & U64x(c0000000,0000000))) { x = (x >> 2) | (x & 3); ex2 += 2; } | ||
368 | strscan_double(x, o, ex2, neg); | ||
369 | return fmt; | ||
370 | } | ||
371 | |||
329 | /* Scan string containing a number. Returns format. Returns value in o. */ | 372 | /* Scan string containing a number. Returns format. Returns value in o. */ |
330 | StrScanFmt lj_strscan_scan(const uint8_t *p, TValue *o, uint32_t opt) | 373 | StrScanFmt lj_strscan_scan(const uint8_t *p, TValue *o, uint32_t opt) |
331 | { | 374 | { |
@@ -364,8 +407,12 @@ StrScanFmt lj_strscan_scan(const uint8_t *p, TValue *o, uint32_t opt) | |||
364 | 407 | ||
365 | /* Determine base and skip leading zeros. */ | 408 | /* Determine base and skip leading zeros. */ |
366 | if (LJ_UNLIKELY(*p <= '0')) { | 409 | if (LJ_UNLIKELY(*p <= '0')) { |
367 | if (*p == '0' && casecmp(p[1], 'x')) | 410 | if (*p == '0') { |
368 | base = 16, cmask = LJ_CHAR_XDIGIT, p += 2; | 411 | if (casecmp(p[1], 'x')) |
412 | base = 16, cmask = LJ_CHAR_XDIGIT, p += 2; | ||
413 | else if (casecmp(p[1], 'b')) | ||
414 | base = 2, cmask = LJ_CHAR_DIGIT, p += 2; | ||
415 | } | ||
369 | for ( ; ; p++) { | 416 | for ( ; ; p++) { |
370 | if (*p == '0') { | 417 | if (*p == '0') { |
371 | hasdig = 1; | 418 | hasdig = 1; |
@@ -403,7 +450,7 @@ StrScanFmt lj_strscan_scan(const uint8_t *p, TValue *o, uint32_t opt) | |||
403 | } | 450 | } |
404 | 451 | ||
405 | /* Parse exponent. */ | 452 | /* Parse exponent. */ |
406 | if (casecmp(*p, (uint32_t)(base == 16 ? 'p' : 'e'))) { | 453 | if (base >= 10 && casecmp(*p, (uint32_t)(base == 16 ? 'p' : 'e'))) { |
407 | uint32_t xx; | 454 | uint32_t xx; |
408 | int negx = 0; | 455 | int negx = 0; |
409 | fmt = STRSCAN_NUM; p++; | 456 | fmt = STRSCAN_NUM; p++; |
@@ -460,6 +507,8 @@ StrScanFmt lj_strscan_scan(const uint8_t *p, TValue *o, uint32_t opt) | |||
460 | return strscan_oct(sp, o, fmt, neg, dig); | 507 | return strscan_oct(sp, o, fmt, neg, dig); |
461 | if (base == 16) | 508 | if (base == 16) |
462 | fmt = strscan_hex(sp, o, fmt, opt, ex, neg, dig); | 509 | fmt = strscan_hex(sp, o, fmt, opt, ex, neg, dig); |
510 | else if (base == 2) | ||
511 | fmt = strscan_bin(sp, o, fmt, opt, ex, neg, dig); | ||
463 | else | 512 | else |
464 | fmt = strscan_dec(sp, o, fmt, opt, ex, neg, dig); | 513 | fmt = strscan_dec(sp, o, fmt, opt, ex, neg, dig); |
465 | 514 | ||