diff --git a/src/lex.c b/src/lex.c index 9e5dbca755bfaff8455da6567b8d772c3f39f0e9..67e2f04b3c403526bdd69ed6fe9af729070aaa80 100644 --- a/src/lex.c +++ b/src/lex.c @@ -13,6 +13,21 @@ #include <ctype.h> +static FLOAT_TYPE mymy_strtod(const char *nptr, char **endptr) +{ +#if SIZEOF_FLOAT_TYPE > SIZEOF_DOUBLE + FLOAT_TYPE tmp=strtold(nptr,endptr); +#else + double tmp=strtod(nptr,endptr); +#endif + if(*endptr>nptr) + { + if(endptr[0][-1]=='.') + endptr[0]--; + } + return tmp; +} + #define LEXDEBUG 0 /* Make lexers for shifts 0, 1 and 2. */ diff --git a/src/lexer.h b/src/lexer.h index 7bb5f8bb0f3e6fcf4742147aaa0d7ef34ad4262b..9d819e34330bbfe34ec7bbafcc36b930343b120c 100644 --- a/src/lexer.h +++ b/src/lexer.h @@ -54,7 +54,7 @@ #define low_yylex low_yylex0 #define lex_atoi atoi #define lex_strtol strtol -#define lex_strtod my_strtod +#define lex_strtod mymy_strtod #define lex_isidchar isidchar #else /* SHIFT != 0 */ @@ -144,11 +144,16 @@ static long lex_strtol(char *buf, char **end, int base) return ret; } -static double lex_strtod(char *buf, char **end) +static FLOAT_TYPE lex_strtod(char *buf, char **end) { PCHARP foo; +#if SIZEOF_FLOAT_TYPE > SIZEOF_DOUBLE + FLOAT_TYPE ret; + ret=STRTOLD_PCHARP(MKPCHARP(buf,SHIFT),&foo); +#else double ret; ret=STRTOD_PCHARP(MKPCHARP(buf,SHIFT),&foo); +#endif if(end) end[0]=(char *)foo.ptr; return ret; } @@ -972,7 +977,7 @@ unknown_directive: case '5': case '6': case '7': case '8': case '9': { char *p1, *p2; - double f; + FLOAT_TYPE f; long l; struct svalue sval; @@ -1026,10 +1031,10 @@ unknown_directive: } } free_svalue(&sval); - yylval->fnum=(FLOAT_TYPE)f; + yylval->fnum=f; #if 0 - fprintf(stderr, "LEX: \"%.8s\" => %f, %f\n", - (char *)lex->pos, f, yylval->fnum); + fprintf(stderr, "LEX: \"%.8s\" => %"PRINTPIKEFLOAT"f\n", + (char *)lex->pos, f); #endif /* 0 */ lex->pos=p1; if (lex_isidchar (LOOK())) { diff --git a/src/stralloc.c b/src/stralloc.c index 98331edf85941a00fa91da70e1e9739b23dbafba..2229bd74fbd617c2107cfbdab08835a3c018b9cf 100644 --- a/src/stralloc.c +++ b/src/stralloc.c @@ -3673,6 +3673,164 @@ PMOD_EXPORT double STRTOD_PCHARP(PCHARP nptr, PCHARP *endptr) return 0.0; } +#if SIZEOF_FLOAT_TYPE > SIZEOF_DOUBLE +/* Convert PCHARP to a long double. If ENDPTR is not NULL, a pointer to the + character after the last one used in the number is put in *ENDPTR. */ +PMOD_EXPORT long double STRTOLD_PCHARP(PCHARP nptr, PCHARP *endptr) +{ + /* Note: Code duplication in strtod. */ + + register PCHARP s; + short int sign; + + /* The number so far. */ + long double num; + + int got_dot; /* Found a decimal point. */ + int got_digit; /* Seen any digits. */ + + /* The exponent of the number. */ + long int exponent; + + if (nptr.ptr == NULL) + { + errno = EINVAL; + goto noconv; + } + + s = nptr; + + /* Eat whitespace. */ + while (EXTRACT_PCHARP(s) <256 && WIDE_ISSPACE(EXTRACT_PCHARP(s))) INC_PCHARP(s,1); + + /* Get the sign. */ + sign = EXTRACT_PCHARP(s) == '-' ? -1 : 1; + if (EXTRACT_PCHARP(s) == '-' || EXTRACT_PCHARP(s) == '+') + INC_PCHARP(s,1); + + num = 0.0; + got_dot = 0; + got_digit = 0; + exponent = 0; + for (;; INC_PCHARP(s,1)) + { + if (EXTRACT_PCHARP(s)<256 && WIDE_ISDIGIT (EXTRACT_PCHARP(s))) + { + got_digit = 1; + + /* Make sure that multiplication by 10 will not overflow. */ + if (num > LDBL_MAX * 0.1) + /* The value of the digit doesn't matter, since we have already + gotten as many digits as can be represented in a `long double'. + This doesn't necessarily mean the result will overflow. + The exponent may reduce it to within range. + + We just need to record that there was another + digit so that we can multiply by 10 later. */ + ++exponent; + else + num = (num * 10.0) + (EXTRACT_PCHARP(s) - '0'); + + /* Keep track of the number of digits after the decimal point. + If we just divided by 10 here, we would lose precision. */ + if (got_dot) + --exponent; + } + else if (!got_dot && (char) EXTRACT_PCHARP(s) == '.') + /* Record that we have found the decimal point. */ + got_dot = 1; + else + /* Any other character terminates the number. */ + break; + } + + if (!got_digit) + goto noconv; + + if (EXTRACT_PCHARP(s) <256 && tolower(EXTRACT_PCHARP(s)) == 'e') + { + /* Get the exponent specified after the `e' or `E'. */ + int save = errno; + PCHARP end; + long int exp; + + errno = 0; + INC_PCHARP(s,1); + exp = STRTOL_PCHARP(s, &end, 10); + if (errno == ERANGE) + { + /* The exponent overflowed a `long int'. It is probably a safe + assumption that an exponent that cannot be represented by + a `long int' exceeds the limits of a `long double'. */ + /* NOTE: Don't trust the value returned from strtol. + * We need to find the sign of the exponent by hand. + */ + p_wchar2 c; + while(WIDE_ISSPACE(c = EXTRACT_PCHARP(s))) { + INC_PCHARP(s, 1); + } + if (endptr != NULL) + *endptr = end; + if (c == '-') + goto underflow; + else + goto overflow; + } + else if (COMPARE_PCHARP(end,==,s)) + /* There was no exponent. Reset END to point to + the 'e' or 'E', so *ENDPTR will be set there. */ + end = ADD_PCHARP(s,-1); + errno = save; + s = end; + exponent += exp; + } + + if(got_dot && INDEX_PCHARP(s,-1)=='.') INC_PCHARP(s,-1); + if (endptr != NULL) + *endptr = s; + + if (num == 0.0) + return 0.0; + + /* Multiply NUM by 10 to the EXPONENT power, + checking for overflow and underflow. */ + + if (exponent < 0) + { + if (num < LDBL_MIN * pow(10.0, (double) -exponent)) + goto underflow; + } + else if (exponent > 0) + { + if (num > LDBL_MAX * pow(10.0, (double) -exponent)) + goto overflow; + } + + if(exponent < 0 && exponent >-100) /* make sure we don't underflow */ + num /= powl(10.0, (long double) -exponent); + else + num *= powl(10.0, (long double) exponent); + + return num * sign; + + overflow: + /* Return an overflow error. */ + errno = ERANGE; + return HUGE_VALL * sign; + + underflow: + /* Return an underflow error. */ + errno = ERANGE; + return 0.0; + + noconv: + /* There was no number. */ + if (endptr != NULL) + *endptr = nptr; + return 0.0; +} +#endif + PMOD_EXPORT p_wchar0 *require_wstring0(struct pike_string *s, char **to_free) diff --git a/src/stralloc.h b/src/stralloc.h index 34cddba72b4152215cd861bf2c9e3d0554dc88e5..9e654f46b934779d3778a929569f20df40d3d7b2 100644 --- a/src/stralloc.h +++ b/src/stralloc.h @@ -459,6 +459,9 @@ PMOD_EXPORT int pcharp_to_svalue_inumber(struct svalue *r, ptrdiff_t maxlength); PMOD_EXPORT int convert_stack_top_string_to_inumber(int base); PMOD_EXPORT double STRTOD_PCHARP(PCHARP nptr, PCHARP *endptr); +#if SIZEOF_FLOAT_TYPE > SIZEOF_DOUBLE +PMOD_EXPORT long double STRTOLD_PCHARP(PCHARP nptr, PCHARP *endptr); +#endif PMOD_EXPORT p_wchar0 *require_wstring0(struct pike_string *s, char **to_free); PMOD_EXPORT p_wchar1 *require_wstring1(struct pike_string *s,