浏览代码

official support for floating hexa numerals

Roberto Ierusalimschy 14 年之前
父节点
当前提交
af119c8b55
共有 3 个文件被更改,包括 99 次插入13 次删除
  1. 77 10
      lobject.c
  2. 4 1
      lstrlib.c
  3. 18 2
      luaconf.h

+ 77 - 10
lobject.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lobject.c,v 2.43 2010/10/29 15:54:55 roberto Exp roberto $
+** $Id: lobject.c,v 2.44 2010/12/06 21:08:36 roberto Exp roberto $
 ** Some generic functions over Lua objects
 ** See Copyright Notice in lua.h
 */
@@ -106,20 +106,87 @@ lua_Number luaO_arith (int op, lua_Number v1, lua_Number v2) {
 }
 
 
-static int checkend (const char *s, const char *e, const char *endptr) {
-  if (endptr == s) return 0;  /* no characters converted */
-  while (lisspace(cast(unsigned char, *endptr))) endptr++;
-  return (endptr == e);  /* OK if no trailing characters */
+int luaO_hexavalue (int c) {
+  if (lisdigit(c)) return c - '0';
+  else if (lisupper(c)) return c - 'A' + 10;
+  else return c - 'a' + 10;
 }
 
 
+#if !defined(lua_strx2number)
+
+#include <math.h>
+
+
+static int isneg (const char **s) {
+  if (**s == '-') { (*s)++; return 1; }
+  else if (**s == '+') (*s)++;
+  return 0;
+}
+
+
+static lua_Number readhexa (const char **s, lua_Number r, int *count) {
+  while (lisxdigit(cast_uchar(**s))) {  /* read integer part */
+    r = (r * 16.0) + (double)luaO_hexavalue(*(*s)++);
+    (*count)++;
+  }
+  return r;
+}
+
+
+/*
+** convert an hexadecimal numeric string to a number, following
+** C99 specification for 'strtod'
+*/
+static lua_Number lua_strx2number (const char *s, char **endptr) {
+  lua_Number r = 0.0;
+  int e = 0, i = 0;
+  int neg = 0;  /* 1 if number is negative */
+  *endptr = cast(char *, s);  /* nothing is valid yet */
+  while (lisspace(cast_uchar(*s))) s++;  /* skip initial spaces */
+  neg = isneg(&s);  /* check signal */
+  if (!(*s == '0' && (*(s + 1) == 'x' || *(s + 1) == 'X')))  /* check '0x' */
+    return 0.0;  /* invalid format (no '0x') */
+  s += 2;  /* skip '0x' */
+  r = readhexa(&s, r, &i);  /* read integer part */
+  if (*s == '.') {
+    s++;  /* skip dot */
+    r = readhexa(&s, r, &e);  /* read fractional part */
+  }
+  if (i == 0 && e == 0)
+    return 0.0;  /* invalid format (no digit) */
+  e *= -4;  /* each fractional digit divides value by 2^-4 */
+  *endptr = cast(char *, s);  /* valid up to here */
+  if (*s == 'p' || *s == 'P') {  /* exponent part? */
+    int exp1 = 0;
+    int neg1;
+    s++;  /* skip 'p' */
+    neg1 = isneg(&s);  /* signal */
+    if (!lisdigit(cast_uchar(*s)))
+      goto ret;  /* must have at least one digit */
+    while (lisdigit(cast_uchar(*s)))  /* read exponent */
+      exp1 = exp1 * 10 + *(s++) - '0';
+    if (neg1) exp1 = -exp1;
+    e += exp1;
+  }
+  *endptr = cast(char *, s);  /* valid up to here */
+ ret:
+  if (neg) r = -r;
+  return ldexp(r, e);
+}
+
+#endif
+
+
 int luaO_str2d (const char *s, size_t len, lua_Number *result) {
   char *endptr;
-  const char *e = s + len;  /* string 's' ends here */
-  *result = lua_str2number(s, &endptr);
-  if (checkend(s, e, endptr)) return 1;  /* conversion OK? */
-  *result = cast_num(strtoul(s, &endptr, 0)); /* try hexadecimal */
-  return checkend(s, e, endptr);
+  if (strpbrk(s, "xX"))  /* hexa? */
+    *result = lua_strx2number(s, &endptr);
+  else
+    *result = lua_str2number(s, &endptr);
+  if (endptr == s) return 0;  /* nothing recognized */
+  while (lisspace(cast_uchar(*endptr))) endptr++;
+  return (endptr == s + len);  /* OK if no trailing characters */
 }
 
 

+ 4 - 1
lstrlib.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lstrlib.c,v 1.158 2010/11/16 20:39:41 roberto Exp roberto $
+** $Id: lstrlib.c,v 1.159 2010/11/19 16:25:51 roberto Exp roberto $
 ** Standard library for string operations and pattern-matching
 ** See Copyright Notice in lua.h
 */
@@ -861,6 +861,9 @@ static int str_format (lua_State *L) {
           break;
         }
         case 'e':  case 'E': case 'f':
+#if defined(LUA_USE_AFORMAT)
+        case 'a': case 'A':
+#endif
         case 'g': case 'G': {
           addlenmod(form, LUA_FLTFRMLEN);
           nb = sprintf(buff, form, (LUA_FLTFRM_T)luaL_checknumber(L, arg));

+ 18 - 2
luaconf.h

@@ -1,5 +1,5 @@
 /*
-** $Id: luaconf.h,v 1.151 2010/11/12 15:48:30 roberto Exp roberto $
+** $Id: luaconf.h,v 1.152 2010/12/08 12:58:04 roberto Exp roberto $
 ** Configuration file for Lua
 ** See Copyright Notice in lua.h
 */
@@ -35,6 +35,7 @@
 
 #if defined(LUA_WIN)
 #define LUA_DL_DLL
+#define LUA_USE_AFORMAT		/* assume 'printf' handles 'aA' specifiers */
 #endif
 
 
@@ -43,6 +44,8 @@
 #define LUA_USE_POSIX
 #define LUA_USE_DLOPEN		/* needs an extra library: -ldl */
 #define LUA_USE_READLINE	/* needs some extra libraries */
+#define LUA_USE_HEXAFLOAT	/* assume 'strtod' handles hexa formats */
+#define LUA_USE_AFORMAT		/* assume 'printf' handles 'aA' specifiers */
 #endif
 
 #if defined(LUA_USE_MACOSX)
@@ -377,14 +380,27 @@
 @@ LUA_NUMBER_FMT is the format for writing numbers.
 @@ lua_number2str converts a number to a string.
 @@ LUAI_MAXNUMBER2STR is maximum size of previous conversion.
-@@ lua_str2number converts a string to a number.
 */
 #define LUA_NUMBER_SCAN		"%lf"
 #define LUA_NUMBER_FMT		"%.14g"
 #define lua_number2str(s,n)	sprintf((s), LUA_NUMBER_FMT, (n))
 #define LUAI_MAXNUMBER2STR	32 /* 16 digits, sign, point, and \0 */
+
+
+/*
+@@ lua_str2number converts a decimal numeric string to a number.
+@@ lua_strx2number converts an hexadecimal numeric string to a number.
+** In C99, 'strtod' do both conversions. C89, however, has no function
+** to convert floating hexadecimal strings to numbers. For these
+** systems, you can leave 'lua_strx2number' undefined and Lua will
+** provide its own implementation.
+*/
 #define lua_str2number(s,p)	strtod((s), (p))
 
+#if defined(LUA_USE_HEXAFLOAT)
+#define lua_strx2number(s,p)	strtod((s), (p))
+#endif
+
 
 /*
 @@ The luai_num* macros define the primitive operations over numbers.