1
0
Fork 0
mirror of git://git.code.sf.net/p/zsh/code synced 2024-05-13 11:06:17 +02:00

30647, 30649: allow underscores in numeric constants

This commit is contained in:
Peter Stephenson 2012-09-11 16:02:41 +00:00
parent d88365d964
commit e550c98d69
6 changed files with 112 additions and 19 deletions

View File

@ -1,3 +1,9 @@
2012-09-11 Peter Stephenson <pws@csr.com>
* 30647, 30649: Doc/Zsh/arith.yo, Src/math.c, Src/utils.c,
Test/C01arith.ztst: allow underscores in numeric constants
within math evaluation.
2012-09-09 Peter Stephenson <p.w.stephenson@ntlworld.com>
* Jun T.: 30664: configure.ac: fix some Yodl version issues.
@ -151,5 +157,5 @@
*****************************************************
* This is used by the shell to define $ZSH_PATCHLEVEL
* $Revision: 1.5718 $
* $Revision: 1.5719 $
*****************************************************

View File

@ -48,6 +48,12 @@ The var(base)tt(#) may also be omitted, in which case
base 10 is used. For backwards compatibility the form
`tt([)var(base)tt(])var(n)' is also accepted.
An integer expression or a base given in the form
`var(base)tt(#)var(n)' may contain underscores (`tt(_)') after the
leading digit for visual guidance; these are ignored in computation.
Examples are tt(1_000_000) or tt(0xffff_ffff) which are equivalent to
tt(1000000) and tt(0xffffffff) respectively.
It is also possible to specify a base to be used for output in the form
`tt([#)var(base)tt(])', for example `tt([#16])'. This is used when
outputting arithmetical substitutions or when assigning to scalar
@ -87,7 +93,9 @@ output is valid syntax for input. If the tt(#) is doubled, for example
Floating point constants are recognized by the presence of a decimal point
or an exponent. The decimal point may be the first character of the
constant, but the exponent character tt(e) or tt(E) may not, as it will be
taken for a parameter name.
taken for a parameter name. All numeric parts (before and after the
decimal point and in the exponent) may contain underscores after the
leading digit for visual guidance; these are ignored in computation.
cindex(arithmetic operators)
cindex(operators, arithmetic)

23
NEWS
View File

@ -4,8 +4,27 @@ CHANGES FROM PREVIOUS VERSIONS OF ZSH
Note also the list of incompatibilities in the README file.
Changes between 4.2 and 5.0
---------------------------
Changes since 5.0.0
-------------------
"functions -T" turns on tracing for the specified function(s) only,
similar to "functions -t" except that tracing is turned off for any
functions called from the specified one(s) that don't also have the -t
or -T flag.
In file completion, the recursive-files style can be set to an array of
patterns to matche against "$PWD/". In any matched location, it is
possibly to complete files in arbitrarily deep subdirectories without
needing to type the directory prefix. See example in the zshcompsys
manual.
The _user_expand completer now allows expansion functions in the
user-expand files to return a string in REPLY that will be used to name
the set of expansions returned.
Changes between 4.2 and 5.0.0
-----------------------------
The following changes first appeared in the 4.3 series of releases;
see also the file Etc/NEWS-4.3.

View File

@ -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;

View File

@ -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

View File

@ -210,3 +210,26 @@
print $x
0:double increment for repeated expression
>2
# Floating point. Default precision should take care of rounding errors.
print $(( 1_0.000_000e0_1 ))
# Integer.
print $(( 0x_ff_ff_ ))
# _ are parts of variable names that don't start with a digit
__myvar__=42
print $(( __myvar__ + $__myvar__ ))
# _ is not part of variable name that does start with a digit
# (which are substituted before math eval)
set -- 6
print $(( $1_000_000 ))
# Underscores in expressions with no whitespace
print $(( 3_000_+4_000_/2 ))
# Underscores may appear in the base descriptor, for what it's worth...
print $(( 1_6_#f_f_ ))
0:underscores in math constants
>100.
>65535
>84
>6000000
>5000
>255