Browse Source

Parse binary number literals (0bxxx).

Mike Pall 10 years ago
parent
commit
eb050f9e2a
3 changed files with 56 additions and 7 deletions
  1. 2 2
      doc/ext_ffi_api.html
  2. 1 1
      doc/extensions.html
  3. 53 4
      src/lj_strscan.c

+ 2 - 2
doc/ext_ffi_api.html

@@ -546,8 +546,8 @@ corresponding ctype.
 The parser for Lua source code treats numeric literals with the
 The parser for Lua source code treats numeric literals with the
 suffixes <tt>LL</tt> or <tt>ULL</tt> as signed or unsigned 64&nbsp;bit
 suffixes <tt>LL</tt> or <tt>ULL</tt> as signed or unsigned 64&nbsp;bit
 integers. Case doesn't matter, but uppercase is recommended for
 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>
 <p>
 <p>
 The imaginary part of complex numbers can be specified by suffixing
 The imaginary part of complex numbers can be specified by suffixing

+ 1 - 1
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>
 <h3 id="tonumber"><tt>tonumber()</tt> etc. use builtin string to number conversion</h3>
 <p>
 <p>
 All string-to-number conversions consistently convert integer and
 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
 <tt>strtod()</tt> is <em>not</em> used anymore, which avoids numerous
 problems with poor C library implementations. The builtin conversion
 problems with poor C library implementations. The builtin conversion
 function provides full precision according to the IEEE-754 standard, it
 function provides full precision according to the IEEE-754 standard, it

+ 53 - 4
src/lj_strscan.c

@@ -140,7 +140,7 @@ static StrScanFmt strscan_hex(const uint8_t *p, TValue *o,
     break;
     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; }
   if ((x & U64x(c0000000,0000000))) { x = (x >> 2) | (x & 3); ex2 += 2; }
   strscan_double(x, o, ex2, neg);
   strscan_double(x, o, ex2, neg);
   return fmt;
   return fmt;
@@ -326,6 +326,49 @@ static StrScanFmt strscan_dec(const uint8_t *p, TValue *o,
   return fmt;
   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. */
 /* Scan string containing a number. Returns format. Returns value in o. */
 StrScanFmt lj_strscan_scan(const uint8_t *p, TValue *o, uint32_t opt)
 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. */
     /* Determine base and skip leading zeros. */
     if (LJ_UNLIKELY(*p <= '0')) {
     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++) {
       for ( ; ; p++) {
 	if (*p == '0') {
 	if (*p == '0') {
 	  hasdig = 1;
 	  hasdig = 1;
@@ -403,7 +450,7 @@ StrScanFmt lj_strscan_scan(const uint8_t *p, TValue *o, uint32_t opt)
     }
     }
 
 
     /* Parse exponent. */
     /* 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;
       uint32_t xx;
       int negx = 0;
       int negx = 0;
       fmt = STRSCAN_NUM; p++;
       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);
       return strscan_oct(sp, o, fmt, neg, dig);
     if (base == 16)
     if (base == 16)
       fmt = strscan_hex(sp, o, fmt, opt, ex, neg, dig);
       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
     else
       fmt = strscan_dec(sp, o, fmt, opt, ex, neg, dig);
       fmt = strscan_dec(sp, o, fmt, opt, ex, neg, dig);