mirror of
git://git.code.sf.net/p/zsh/code
synced 2025-10-23 04:30:24 +02:00
30647, 30649: allow underscores in numeric constants
This commit is contained in:
parent
d88365d964
commit
e550c98d69
6 changed files with 112 additions and 19 deletions
39
Src/math.c
39
Src/math.c
|
@ -452,7 +452,7 @@ lexconstant(void)
|
|||
nptr++;
|
||||
if (*nptr == 'x' || *nptr == 'X') {
|
||||
/* Let zstrtol parse number with base */
|
||||
yyval.u.l = zstrtol(ptr, &ptr, 0);
|
||||
yyval.u.l = zstrtol_underscore(ptr, &ptr, 0, 1);
|
||||
/* Should we set lastbase here? */
|
||||
lastbase = 16;
|
||||
return NUM;
|
||||
|
@ -466,13 +466,13 @@ lexconstant(void)
|
|||
* it can't be a base indication (always decimal)
|
||||
* or a floating point number.
|
||||
*/
|
||||
for (ptr2 = nptr; idigit(*ptr2); ptr2++)
|
||||
for (ptr2 = nptr; idigit(*ptr2) || *ptr2 == '_'; ptr2++)
|
||||
;
|
||||
|
||||
if (ptr2 > nptr && *ptr2 != '.' && *ptr2 != 'e' &&
|
||||
*ptr2 != 'E' && *ptr2 != '#')
|
||||
{
|
||||
yyval.u.l = zstrtol(ptr, &ptr, 0);
|
||||
yyval.u.l = zstrtol_underscore(ptr, &ptr, 0, 1);
|
||||
lastbase = 8;
|
||||
return NUM;
|
||||
}
|
||||
|
@ -481,17 +481,43 @@ lexconstant(void)
|
|||
}
|
||||
else
|
||||
{
|
||||
while (idigit(*nptr))
|
||||
while (idigit(*nptr) || *nptr == '_')
|
||||
nptr++;
|
||||
}
|
||||
|
||||
if (*nptr == '.' || *nptr == 'e' || *nptr == 'E') {
|
||||
char *ptr2;
|
||||
/* it's a float */
|
||||
yyval.type = MN_FLOAT;
|
||||
#ifdef USE_LOCALE
|
||||
prev_locale = dupstring(setlocale(LC_NUMERIC, NULL));
|
||||
setlocale(LC_NUMERIC, "POSIX");
|
||||
#endif
|
||||
if (*nptr == '.') {
|
||||
nptr++;
|
||||
while (idigit(*nptr) || *nptr == '_')
|
||||
nptr++;
|
||||
}
|
||||
if (*nptr == 'e' || *nptr == 'E') {
|
||||
nptr++;
|
||||
if (*nptr == '+' || *nptr == '-')
|
||||
nptr++;
|
||||
while (idigit(*nptr) || *nptr == '_')
|
||||
nptr++;
|
||||
}
|
||||
for (ptr2 = ptr; ptr2 < nptr; ptr2++) {
|
||||
if (*ptr2 == '_') {
|
||||
int len = nptr - ptr;
|
||||
ptr = strdup(ptr);
|
||||
for (ptr2 = ptr; len; len--) {
|
||||
if (*ptr2 == '_')
|
||||
chuck(ptr2);
|
||||
else
|
||||
ptr2++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
yyval.u.d = strtod(ptr, &nptr);
|
||||
#ifdef USE_LOCALE
|
||||
if (prev_locale) setlocale(LC_NUMERIC, prev_locale);
|
||||
|
@ -503,11 +529,12 @@ lexconstant(void)
|
|||
ptr = nptr;
|
||||
} else {
|
||||
/* it's an integer */
|
||||
yyval.u.l = zstrtol(ptr, &ptr, 10);
|
||||
yyval.u.l = zstrtol_underscore(ptr, &ptr, 10, 1);
|
||||
|
||||
if (*ptr == '#') {
|
||||
ptr++;
|
||||
yyval.u.l = zstrtol(ptr, &ptr, lastbase = yyval.u.l);
|
||||
lastbase = yyval.u.l;
|
||||
yyval.u.l = zstrtol_underscore(ptr, &ptr, lastbase, 1);
|
||||
}
|
||||
}
|
||||
return NUM;
|
||||
|
|
28
Src/utils.c
28
Src/utils.c
|
@ -2030,13 +2030,20 @@ skipparens(char inpar, char outpar, char **s)
|
|||
return level;
|
||||
}
|
||||
|
||||
/**/
|
||||
mod_export zlong
|
||||
zstrtol(const char *s, char **t, int base)
|
||||
{
|
||||
return zstrtol_underscore(s, t, base, 0);
|
||||
}
|
||||
|
||||
/* Convert string to zlong (see zsh.h). This function (without the z) *
|
||||
* is contained in the ANSI standard C library, but a lot of them seem *
|
||||
* to be broken. */
|
||||
|
||||
/**/
|
||||
mod_export zlong
|
||||
zstrtol(const char *s, char **t, int base)
|
||||
zstrtol_underscore(const char *s, char **t, int base, int underscore)
|
||||
{
|
||||
const char *inp, *trunc = NULL;
|
||||
zulong calc = 0, newcalc = 0;
|
||||
|
@ -2062,22 +2069,24 @@ zstrtol(const char *s, char **t, int base)
|
|||
if (base < 2 || base > 36) {
|
||||
zerr("invalid base (must be 2 to 36 inclusive): %d", base);
|
||||
return (zlong)0;
|
||||
} else if (base <= 10)
|
||||
for (; *s >= '0' && *s < ('0' + base); s++) {
|
||||
if (trunc)
|
||||
} else if (base <= 10) {
|
||||
for (; (*s >= '0' && *s < ('0' + base)) ||
|
||||
(underscore && *s == '_'); s++) {
|
||||
if (trunc || *s == '_')
|
||||
continue;
|
||||
newcalc = calc * base + *s - '0';
|
||||
if (newcalc < calc)
|
||||
{
|
||||
trunc = s;
|
||||
continue;
|
||||
trunc = s;
|
||||
continue;
|
||||
}
|
||||
calc = newcalc;
|
||||
}
|
||||
else
|
||||
} else {
|
||||
for (; idigit(*s) || (*s >= 'a' && *s < ('a' + base - 10))
|
||||
|| (*s >= 'A' && *s < ('A' + base - 10)); s++) {
|
||||
if (trunc)
|
||||
|| (*s >= 'A' && *s < ('A' + base - 10))
|
||||
|| (underscore && *s == '_'); s++) {
|
||||
if (trunc || *s == '_')
|
||||
continue;
|
||||
newcalc = calc*base + (idigit(*s) ? (*s - '0') : (*s & 0x1f) + 9);
|
||||
if (newcalc < calc)
|
||||
|
@ -2087,6 +2096,7 @@ zstrtol(const char *s, char **t, int base)
|
|||
}
|
||||
calc = newcalc;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Special case: check for a number that was just too long for
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue