diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2012-03-22 13:51:15 -0700 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2012-03-22 13:51:15 -0700 |
commit | cffd912f512dc46b5a732068a0380c059db0f07d (patch) | |
tree | 724d494ff91f293f0044cdc120f9346cbdcb0b9d | |
parent | 1ccc6d458fbda380233019a1d80d5aff576d9d03 (diff) | |
download | txr-cffd912f512dc46b5a732068a0380c059db0f07d.tar.gz txr-cffd912f512dc46b5a732068a0380c059db0f07d.tar.bz2 txr-cffd912f512dc46b5a732068a0380c059db0f07d.zip |
* parser.l: Bugfix: was not allowing e-notation floats
with no decimal point like 1E1.
* stream.c: (vformat): Keep track of whether or not precision was
given in precision_p local variable.
When printing #<bad-float> pass a precision of 0
to vformat_str, not precision, since precision does not apply.
In ~f and ~e, if the precision was not given, default
it to 3.
Restructured float printing in ~a and ~s. It now just uses sprintf's %g
with a precision. If user does not specify precision, it defaults
to DBL_DIG to print the number with reasonable accuracy.
A .0 is added if it sprintf produces an integer, and the conversion
is ~s rather than ~a.
-rw-r--r-- | ChangeLog | 17 | ||||
-rw-r--r-- | parser.l | 2 | ||||
-rw-r--r-- | stream.c | 43 |
3 files changed, 41 insertions, 21 deletions
@@ -1,5 +1,22 @@ 2012-03-22 Kaz Kylheku <kaz@kylheku.com> + * parser.l: Bugfix: was not allowing e-notation floats + with no decimal point like 1E1. + + * stream.c: (vformat): Keep track of whether or not precision was + given in precision_p local variable. + When printing #<bad-float> pass a precision of 0 + to vformat_str, not precision, since precision does not apply. + In ~f and ~e, if the precision was not given, default + it to 3. + Restructured float printing in ~a and ~s. It now just uses sprintf's %g + with a precision. If user does not specify precision, it defaults + to DBL_DIG to print the number with reasonable accuracy. + A .0 is added if it sprintf produces an integer, and the conversion + is ~s rather than ~a. + +2012-03-22 Kaz Kylheku <kaz@kylheku.com> + Fix sqrt confusion. There must be a separate isqrt for the integer square root. @@ -153,7 +153,7 @@ SGN [+\-] EXP [eE][+\-]?[0-9]+ DIG [0-9] NUM {SGN}?{DIG}+ -FLO {SGN}?{DIG}*[.]({DIG}+{EXP}?|{EXP}) +FLO {SGN}?({DIG}*[.]{DIG}+{EXP}?|{DIG}+[.]?{EXP}) FLODOT {SGN}?{DIG}+[.] BSCHR [a-zA-Z0-9!$%&*+\-<=>?\\^_~] BSYM {BSCHR}({BSCHR}|#)* @@ -35,6 +35,7 @@ #include <ctype.h> #include <wchar.h> #include <unistd.h> +#include <float.h> #include "config.h" #if HAVE_SYS_WAIT #include <sys/wait.h> @@ -960,7 +961,7 @@ val vformat(val stream, val fmtstr, va_list vl) enum { vf_init, vf_width, vf_digits, vf_precision, vf_spec } state = vf_init, saved_state = vf_init; - int width = 0, precision = 0, digits = 0; + int width = 0, precision = 0, precision_p = 0, digits = 0; int left = 0, sign = 0, zeropad = 0; cnum value; void *ptr; @@ -981,6 +982,7 @@ val vformat(val stream, val fmtstr, va_list vl) left = 0; zeropad = 0; precision = 0; + precision_p = 0; digits = 0; continue; default: @@ -1035,6 +1037,7 @@ val vformat(val stream, val fmtstr, va_list vl) obj = va_arg(vl, val); width = c_num(obj); precision = vf_precision; + precision_p = 1; continue; default: state = vf_spec; @@ -1067,6 +1070,7 @@ val vformat(val stream, val fmtstr, va_list vl) continue; case vf_precision: precision = digits; + precision_p = 1; state = vf_spec; --fmt; continue; @@ -1139,6 +1143,9 @@ val vformat(val stream, val fmtstr, va_list vl) chr(ch), obj, nao); } + if (!precision_p) + precision = 3; + /* guard against num_buf overflow */ if (precision > 128) uw_throwf(error_s, lit("excessive precision in format: ~s\n"), @@ -1150,7 +1157,7 @@ val vformat(val stream, val fmtstr, va_list vl) sprintf(num_buf, "%.*f", precision, n); if (!isdigit(num_buf[0])) { if (!vformat_str(stream, lit("#<bad-float>"), - width, left, precision)) + width, left, 0)) return nil; continue; } @@ -1175,30 +1182,26 @@ val vformat(val stream, val fmtstr, va_list vl) } goto output_num; case FLNUM: - sprintf(num_buf, "%g", obj->fl.n); + if (!precision_p) + precision = DBL_DIG; - if (!isdigit(num_buf[0])) { + if (precision > 500) + uw_throwf(error_s, lit("excessive precision in format: ~s\n"), + num(precision), nao); + + sprintf(num_buf, "%.*g", precision, obj->fl.n); + + if (ch == 's' && !precision_p && !strpbrk(num_buf, "e.")) + strcat(num_buf, ".0"); + + if (!isdigit(num_buf[0]) && !isdigit(num_buf[1])) { if (!vformat_str(stream, lit("#<bad-float>"), - width, left, precision)) + width, left, 0)) return nil; continue; } - if (!precision) { - if (!strpbrk(num_buf, "e.")) - strcat(num_buf, ".0"); - } else { - /* guard against num_buf overflow */ - if (precision > 128) - uw_throwf(error_s, lit("excessive precision in format: ~s\n"), - num(precision), nao); - - if (strchr(num_buf, 'e')) - sprintf(num_buf, "%.*e", precision, obj->fl.n); - else - sprintf(num_buf, "%.*f", precision, obj->fl.n); - precision = 0; - } + precision = 0; goto output_num; default: if (width != 0) { |