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:
parent
d88365d964
commit
e550c98d69
|
@ -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 $
|
||||
*****************************************************
|
||||
|
|
|
@ -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
23
NEWS
|
@ -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.
|
||||
|
|
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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue