From e550c98d69a270a9c6623fe1fd602b5081f4b46c Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Tue, 11 Sep 2012 16:02:41 +0000 Subject: 30647, 30649: allow underscores in numeric constants --- ChangeLog | 8 +++++++- Doc/Zsh/arith.yo | 10 +++++++++- NEWS | 23 +++++++++++++++++++++-- Src/math.c | 39 +++++++++++++++++++++++++++++++++------ Src/utils.c | 28 +++++++++++++++++++--------- Test/C01arith.ztst | 23 +++++++++++++++++++++++ 6 files changed, 112 insertions(+), 19 deletions(-) diff --git a/ChangeLog b/ChangeLog index cf53ffbe6..c9339beb8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2012-09-11 Peter Stephenson + + * 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 * 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 $ ***************************************************** diff --git a/Doc/Zsh/arith.yo b/Doc/Zsh/arith.yo index dd18ee720..2674c7817 100644 --- a/Doc/Zsh/arith.yo +++ b/Doc/Zsh/arith.yo @@ -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) diff --git a/NEWS b/NEWS index 23097b6aa..68d4ad657 100644 --- a/NEWS +++ b/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. diff --git a/Src/math.c b/Src/math.c index c7d384019..abc5f994e 100644 --- a/Src/math.c +++ b/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; diff --git a/Src/utils.c b/Src/utils.c index d35ca1dfd..cadb06f61 100644 --- a/Src/utils.c +++ b/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 diff --git a/Test/C01arith.ztst b/Test/C01arith.ztst index 1f0d2d0f3..e5845d37f 100644 --- a/Test/C01arith.ztst +++ b/Test/C01arith.ztst @@ -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 -- cgit 1.4.1