diff options
-rw-r--r-- | Makefile.am | 2 | ||||
-rw-r--r-- | Makefile.in | 14 | ||||
-rw-r--r-- | aclocal.m4 | 1 | ||||
-rw-r--r-- | array.c | 71 | ||||
-rw-r--r-- | awk.h | 9 | ||||
-rw-r--r-- | awkgram.c | 20 | ||||
-rw-r--r-- | awkgram.y | 20 | ||||
-rw-r--r-- | awklib/Makefile.in | 12 | ||||
-rw-r--r-- | builtin.c | 4 | ||||
-rw-r--r-- | configh.in | 3 | ||||
-rwxr-xr-x | configure | 78 | ||||
-rw-r--r-- | configure.ac | 3 | ||||
-rw-r--r-- | doc/Makefile.in | 12 | ||||
-rw-r--r-- | eval.c | 69 | ||||
-rw-r--r-- | field.c | 23 | ||||
-rw-r--r-- | interpret.h | 28 | ||||
-rw-r--r-- | io.c | 1 | ||||
-rw-r--r-- | m4/mpfr.m4 | 62 | ||||
-rw-r--r-- | mpfr.c | 254 | ||||
-rw-r--r-- | node.c | 2 | ||||
-rw-r--r-- | profile.c | 15 | ||||
-rw-r--r-- | test/Makefile.am | 7 | ||||
-rw-r--r-- | test/Makefile.in | 20 |
23 files changed, 516 insertions, 214 deletions
diff --git a/Makefile.am b/Makefile.am index 4e483e4e..8f6ee12e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -129,7 +129,7 @@ base_sources = \ gawk_SOURCES = $(base_sources) # Get extra libs as needed, Automake will supply LIBINTL and SOCKET_LIBS. -LDADD = $(LIBSIGSEGV) $(LIBINTL) $(SOCKET_LIBS) @LIBREADLINE@ -lmpfr -lgmp +LDADD = $(LIBSIGSEGV) $(LIBINTL) $(SOCKET_LIBS) @LIBREADLINE@ @LIBMPFR@ # Directory for gawk's data files. Automake supplies datadir. pkgdatadir = $(datadir)/awk diff --git a/Makefile.in b/Makefile.in index 4643feb6..3775dc4a 100644 --- a/Makefile.in +++ b/Makefile.in @@ -72,11 +72,12 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/arch.m4 \ $(top_srcdir)/m4/isc-posix.m4 $(top_srcdir)/m4/lcmessage.m4 \ $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libsigsegv.m4 \ - $(top_srcdir)/m4/longlong.m4 $(top_srcdir)/m4/nls.m4 \ - $(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \ - $(top_srcdir)/m4/readline.m4 $(top_srcdir)/m4/socket.m4 \ - $(top_srcdir)/m4/stdint_h.m4 $(top_srcdir)/m4/uintmax_t.m4 \ - $(top_srcdir)/m4/ulonglong.m4 $(top_srcdir)/configure.ac + $(top_srcdir)/m4/longlong.m4 $(top_srcdir)/m4/mpfr.m4 \ + $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ + $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/m4/readline.m4 \ + $(top_srcdir)/m4/socket.m4 $(top_srcdir)/m4/stdint_h.m4 \ + $(top_srcdir)/m4/uintmax_t.m4 $(top_srcdir)/m4/ulonglong.m4 \ + $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ @@ -201,6 +202,7 @@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ LDFLAGS = @LDFLAGS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ +LIBMPFR = @LIBMPFR@ LIBOBJS = @LIBOBJS@ LIBREADLINE = @LIBREADLINE@ LIBS = @LIBS@ @@ -394,7 +396,7 @@ base_sources = \ gawk_SOURCES = $(base_sources) # Get extra libs as needed, Automake will supply LIBINTL and SOCKET_LIBS. -LDADD = $(LIBSIGSEGV) $(LIBINTL) $(SOCKET_LIBS) @LIBREADLINE@ -lmpfr -lgmp +LDADD = $(LIBSIGSEGV) $(LIBINTL) $(SOCKET_LIBS) @LIBREADLINE@ @LIBMPFR@ # stuff for compiling gawk/pgawk DEFPATH = '".$(PATH_SEPARATOR)$(pkgdatadir)"' @@ -963,6 +963,7 @@ m4_include([m4/lib-link.m4]) m4_include([m4/lib-prefix.m4]) m4_include([m4/libsigsegv.m4]) m4_include([m4/longlong.m4]) +m4_include([m4/mpfr.m4]) m4_include([m4/nls.m4]) m4_include([m4/po.m4]) m4_include([m4/progtest.m4]) @@ -885,21 +885,19 @@ asort_actual(int nargs, SORT_CTXT ctxt) result->parent_array = array->parent_array; } - subs = make_number((AWKNUM) 0.0); - if (ctxt == ASORTI) { /* We want the indices of the source array. */ for (i = 1, ptr = list; i <= num_elems; i++, ptr += 2) { - subs->numbr = (AWKNUM) i; - r = *ptr; - *assoc_lookup(result, subs) = r; + subs = make_number(i); + *assoc_lookup(result, subs) = *ptr; + unref(subs); } } else { /* We want the values of the source array. */ for (i = 1, ptr = list; i <= num_elems; i++) { - subs->numbr = (AWKNUM) i; + subs = make_number(i); /* free index node */ r = *ptr++; @@ -922,10 +920,10 @@ asort_actual(int nargs, SORT_CTXT ctxt) arr->parent_array = array; /* actual parent, not the temporary one. */ *assoc_lookup(result, subs) = assoc_copy(r, arr); } + unref(subs); } } - unref(subs); efree(list); if (result != dest) { @@ -1054,15 +1052,29 @@ sort_up_index_number(const void *p1, const void *p2) t1 = *((const NODE *const *) p1); t2 = *((const NODE *const *) p2); +#ifdef HAVE_MPFR + if (t1->flags & MPFN) { + assert((t2->flags & MPFN) != 0); + + ret = mpfr_cmp(t1->mpfr_numbr, t2->mpfr_numbr); + if (ret == 0) + goto break_tie; + return ret; + } +#endif + if (t1->numbr < t2->numbr) ret = -1; else ret = (t1->numbr > t2->numbr); + if (ret != 0) + return ret; +break_tie: /* break a tie with the index string itself */ - if (ret == 0) - return cmp_string(t1, t2); - return ret; + t1 = force_string((NODE *) t1); + t2 = force_string((NODE *) t2); + return cmp_string(t1, t2); } /* sort_down_index_number --- qsort comparison function; descending index numbers */ @@ -1123,23 +1135,33 @@ sort_up_value_number(const void *p1, const void *p2) if (t2->type == Node_var_array) return -1; /* t1 (scalar) < t2 (sub-array) */ +#ifdef HAVE_MPFR + if (t1->flags & MPFN) { + assert((t2->flags & MPFN) != 0); + + ret = mpfr_cmp(t1->mpfr_numbr, t2->mpfr_numbr); + if (ret == 0) + goto break_tie; + return ret; + } +#endif + /* t1 and t2 both Node_val, and force_number'ed */ if (t1->numbr < t2->numbr) ret = -1; else ret = (t1->numbr > t2->numbr); - if (ret == 0) { - /* - * Use string value to guarantee same sort order on all - * versions of qsort(). - */ - t1 = force_string(t1); - t2 = force_string(t2); - ret = cmp_string(t1, t2); - } - - return ret; + if (ret != 0) + return ret; +break_tie: + /* + * Use string value to guarantee same sort order on all + * versions of qsort(). + */ + t1 = force_string(t1); + t2 = force_string(t2); + return cmp_string(t1, t2); } @@ -1186,6 +1208,13 @@ sort_up_value_type(const void *p1, const void *p2) (void) force_string(n2); if ((n1->flags & NUMBER) != 0 && (n2->flags & NUMBER) != 0) { +#ifdef HAVE_MPFR + if (n1->flags & MPFN) { + assert((n2->flags & MPFN) != 0); + return mpfr_cmp(n1->mpfr_numbr, n2->mpfr_numbr); + } +#endif + if (n1->numbr < n2->numbr) return -1; else if (n1->numbr > n2->numbr) @@ -25,8 +25,6 @@ /* ------------------------------ Includes ------------------------------ */ -#define HAVE_MPFR 1 - /* * config.h absolutely, positively, *M*U*S*T* be included before * any system headers. Otherwise, extreme death, destruction @@ -1427,9 +1425,6 @@ extern INSTRUCTION *POP_CODE(void); extern void init_interpret(void); extern int r_interpret(INSTRUCTION *); extern int debug_interpret(INSTRUCTION *); -#ifdef HAVE_MPFR -extern int mpfr_interpret(INSTRUCTION *); -#endif extern int cmp_nodes(NODE *p1, NODE *p2); extern void set_IGNORECASE(void); extern void set_OFS(void); @@ -1551,7 +1546,7 @@ extern NODE *do_mpfr_strtonum(int); extern NODE *do_mpfr_xor(int); extern void init_mpfr(const char *); extern NODE *mpfr_node(); -extern void op_assign_mpfr(OPCODE op); +extern void op_mpfr_assign(OPCODE op); const char *mpfr_fmt(const char *mesg, ...); #endif /* msg.c */ @@ -1572,7 +1567,7 @@ extern void init_profiling(int *flag, const char *def_file); extern void init_profiling_signals(void); extern void set_prof_file(const char *filename); extern void dump_prog(INSTRUCTION *code); -extern char *pp_number(AWKNUM d); +extern char *pp_number(NODE *n); extern char *pp_string(const char *in_str, size_t len, int delim); extern char *pp_node(NODE *n); extern int pp_func(INSTRUCTION *pc, void *); @@ -6578,21 +6578,29 @@ parms_shadow(INSTRUCTION *pc, int *shadow) void valinfo(NODE *n, Func_print print_func, FILE *fp) { - /* FIXME -- MPFR */ - if (n == Nnull_string) print_func(fp, "uninitialized scalar\n"); else if (n->flags & STRING) { pp_string_fp(print_func, fp, n->stptr, n->stlen, '"', FALSE); print_func(fp, "\n"); - } else if (n->flags & NUMBER) + } else if (n->flags & NUMBER) { +#ifdef HAVE_MPFR + if (n->flags & MPFN) + print_func(fp, "%s\n", mpfr_fmt("%.17R*g", RND_MODE, n->mpfr_numbr)); + else +#endif print_func(fp, "%.17g\n", n->numbr); - else if (n->flags & STRCUR) { + } else if (n->flags & STRCUR) { pp_string_fp(print_func, fp, n->stptr, n->stlen, '"', FALSE); print_func(fp, "\n"); - } else if (n->flags & NUMCUR) + } else if (n->flags & NUMCUR) { +#ifdef HAVE_MPFR + if (n->flags & MPFN) + print_func(fp, "%s\n", mpfr_fmt("%.17R*g", RND_MODE, n->mpfr_numbr)); + else +#endif print_func(fp, "%.17g\n", n->numbr); - else + } else print_func(fp, "?? flags %s\n", flags2str(n->flags)); } @@ -3881,21 +3881,29 @@ parms_shadow(INSTRUCTION *pc, int *shadow) void valinfo(NODE *n, Func_print print_func, FILE *fp) { - /* FIXME -- MPFR */ - if (n == Nnull_string) print_func(fp, "uninitialized scalar\n"); else if (n->flags & STRING) { pp_string_fp(print_func, fp, n->stptr, n->stlen, '"', FALSE); print_func(fp, "\n"); - } else if (n->flags & NUMBER) + } else if (n->flags & NUMBER) { +#ifdef HAVE_MPFR + if (n->flags & MPFN) + print_func(fp, "%s\n", mpfr_fmt("%.17R*g", RND_MODE, n->mpfr_numbr)); + else +#endif print_func(fp, "%.17g\n", n->numbr); - else if (n->flags & STRCUR) { + } else if (n->flags & STRCUR) { pp_string_fp(print_func, fp, n->stptr, n->stlen, '"', FALSE); print_func(fp, "\n"); - } else if (n->flags & NUMCUR) + } else if (n->flags & NUMCUR) { +#ifdef HAVE_MPFR + if (n->flags & MPFN) + print_func(fp, "%s\n", mpfr_fmt("%.17R*g", RND_MODE, n->mpfr_numbr)); + else +#endif print_func(fp, "%.17g\n", n->numbr); - else + } else print_func(fp, "?? flags %s\n", flags2str(n->flags)); } diff --git a/awklib/Makefile.in b/awklib/Makefile.in index 01511c36..1b1a274e 100644 --- a/awklib/Makefile.in +++ b/awklib/Makefile.in @@ -67,11 +67,12 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/arch.m4 \ $(top_srcdir)/m4/isc-posix.m4 $(top_srcdir)/m4/lcmessage.m4 \ $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libsigsegv.m4 \ - $(top_srcdir)/m4/longlong.m4 $(top_srcdir)/m4/nls.m4 \ - $(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \ - $(top_srcdir)/m4/readline.m4 $(top_srcdir)/m4/socket.m4 \ - $(top_srcdir)/m4/stdint_h.m4 $(top_srcdir)/m4/uintmax_t.m4 \ - $(top_srcdir)/m4/ulonglong.m4 $(top_srcdir)/configure.ac + $(top_srcdir)/m4/longlong.m4 $(top_srcdir)/m4/mpfr.m4 \ + $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ + $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/m4/readline.m4 \ + $(top_srcdir)/m4/socket.m4 $(top_srcdir)/m4/stdint_h.m4 \ + $(top_srcdir)/m4/uintmax_t.m4 $(top_srcdir)/m4/ulonglong.m4 \ + $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs @@ -157,6 +158,7 @@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ LDFLAGS = @LDFLAGS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ +LIBMPFR = @LIBMPFR@ LIBOBJS = @LIBOBJS@ LIBREADLINE = @LIBREADLINE@ LIBS = @LIBS@ @@ -1061,7 +1061,6 @@ out2: need_format = FALSE; parse_next_arg(); (void) force_number(arg); - #ifdef HAVE_MPFR if (arg->flags & MPFN) goto mpfr_int; @@ -1180,7 +1179,6 @@ out2: need_format = FALSE; parse_next_arg(); (void) force_number(arg); - #ifdef HAVE_MPFR if (arg->flags & MPFN) { mpfr_ptr mt; @@ -3061,8 +3059,6 @@ do_compl(int nargs) DEREF(tmp); if (do_lint) { - if ((tmp->flags & (NUMCUR|NUMBER)) == 0) - lintwarn(_("compl: received non-numeric argument")); if (d < 0) lintwarn(_("compl(%lf): negative value will give strange results"), d); if (double_to_int(d) != d) @@ -157,6 +157,9 @@ /* we have the mktime function */ #undef HAVE_MKTIME +/* Define to 1 if you have a fully functional mpfr and gmp library. */ +#undef HAVE_MPFR + /* Define to 1 if you have the <netdb.h> header file. */ #undef HAVE_NETDB_H @@ -607,6 +607,7 @@ ac_func_list= ac_subst_vars='am__EXEEXT_FALSE am__EXEEXT_TRUE LTLIBOBJS +LIBMPFR LIBREADLINE SOCKET_LIBS LIBSIGSEGV_PREFIX @@ -736,6 +737,7 @@ with_libiconv_prefix with_libintl_prefix with_libsigsegv_prefix with_readline +with_mpfr ' ac_precious_vars='build_alias host_alias @@ -1387,6 +1389,7 @@ Optional Packages: --with-libsigsegv-prefix[=DIR] search for libsigsegv in DIR/include and DIR/lib --without-libsigsegv-prefix don't search for libsigsegv in includedir and libdir --with-readline=DIR look for the readline library in DIR + --with-mpfr=DIR look for the mpfr and gmp libraries in DIR Some influential environment variables: CC C compiler command @@ -10297,6 +10300,81 @@ $as_echo "#define HAVE_LIBREADLINE 1" >>confdefs.h fi + + +# Check whether --with-mpfr was given. +if test "${with_mpfr+set}" = set; then : + withval=$with_mpfr; _do_mpfr=$withval +else + _do_mpfr=yes +fi + + + if test "$_do_mpfr" != "no" ; then + if test -d "$withval" ; then + CPPFLAGS="${CPPFLAGS} -I$withval/include" + LDFLAGS="${LDFLAGS} -L$withval/lib" + fi + + _mpfr_save_libs=$LIBS + _combo="-lmpfr -lgmp" + LIBS="$LIBS $_combo" + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether mpfr via \"$_combo\" is present and usable" >&5 +$as_echo_n "checking whether mpfr via \"$_combo\" is present and usable... " >&6; } + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#include <stdio.h> +#include <mpfr.h> +#include <gmp.h> + +int +main () +{ + +mpfr_t p; +mpz_t z; +mpfr_init(p); +mpz_init(z); +mpfr_printf("%Rf%Zd", p, z); +mpfr_clear(p); +mpz_clear(z); + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + _found_mpfr=yes +else + _found_mpfr=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $_found_mpfr" >&5 +$as_echo "$_found_mpfr" >&6; } + + LIBS=$_mpfr_save_libs + + if test $_found_mpfr = yes ; then + +$as_echo "#define HAVE_MPFR 1" >>confdefs.h + + LIBMPFR=$_combo + + break + fi + + unset _mpfr_save_libs + unset _combo + unset _found_mpfr + fi + + ac_fn_c_check_member "$LINENO" "struct stat" "st_blksize" "ac_cv_member_struct_stat_st_blksize" "$ac_includes_default" if test "x$ac_cv_member_struct_stat_st_blksize" = xyes; then : diff --git a/configure.ac b/configure.ac index 3b0ba330..7e07a791 100644 --- a/configure.ac +++ b/configure.ac @@ -339,6 +339,9 @@ GAWK_AC_LIB_SOCKETS dnl check for readline support GNUPG_CHECK_READLINE +dnl check for mpfr support +GNUPG_CHECK_MPFR + dnl checks for structure members AC_STRUCT_ST_BLKSIZE AC_HEADER_TIME diff --git a/doc/Makefile.in b/doc/Makefile.in index 2d3dbae2..f0571c49 100644 --- a/doc/Makefile.in +++ b/doc/Makefile.in @@ -68,11 +68,12 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/arch.m4 \ $(top_srcdir)/m4/isc-posix.m4 $(top_srcdir)/m4/lcmessage.m4 \ $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libsigsegv.m4 \ - $(top_srcdir)/m4/longlong.m4 $(top_srcdir)/m4/nls.m4 \ - $(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \ - $(top_srcdir)/m4/readline.m4 $(top_srcdir)/m4/socket.m4 \ - $(top_srcdir)/m4/stdint_h.m4 $(top_srcdir)/m4/uintmax_t.m4 \ - $(top_srcdir)/m4/ulonglong.m4 $(top_srcdir)/configure.ac + $(top_srcdir)/m4/longlong.m4 $(top_srcdir)/m4/mpfr.m4 \ + $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ + $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/m4/readline.m4 \ + $(top_srcdir)/m4/socket.m4 $(top_srcdir)/m4/stdint_h.m4 \ + $(top_srcdir)/m4/uintmax_t.m4 $(top_srcdir)/m4/ulonglong.m4 \ + $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs @@ -153,6 +154,7 @@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ LDFLAGS = @LDFLAGS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ +LIBMPFR = @LIBMPFR@ LIBOBJS = @LIBOBJS@ LIBREADLINE = @LIBREADLINE@ LIBS = @LIBS@ @@ -590,10 +590,15 @@ cmp_nodes(NODE *t1, NODE *t2) if (t1->flags & MPFN) { assert((t2->flags & MPFN) != 0); - /* Note: returns zero if either t1 or t2 is NaN */ + /* + * N.B.: Gawk returns 1 if either t1 or t2 is NaN. + * The results of == and < comparisons below are false with NaN(s). + */ + + if (mpfr_nan_p(t1->mpfr_numbr) || mpfr_nan_p(t2->mpfr_numbr)) + return 1; return mpfr_cmp(t1->mpfr_numbr, t2->mpfr_numbr); } - assert((t2->flags & MPFN) == 0); #endif if (t1->numbr == t2->numbr) @@ -1490,14 +1495,6 @@ unwind_stack(long n) #define pop_stack() (void) unwind_stack(0) -/* - * This generated compiler warnings from GCC 4.4. Who knows why. - * -#define eval_condition(t) (((t)->flags & MAYBE_NUM) && force_number(t), \ - ((t)->flags & NUMBER) ? ((t)->numbr != 0.0) : ((t)->stlen != 0)) -*/ - - static inline int eval_condition(NODE *t) { @@ -1536,7 +1533,6 @@ cmp_scalar() return di; } - /* op_assign --- assignment operators excluding = */ static void @@ -1696,6 +1692,29 @@ pop_exec_state(int *rule, char **src, long *sz) return cp; } + +/* interpreter routine when not debugging */ +#include "interpret.h" + +/* interpreter routine when deubugging with gawk --debug */ +#define r_interpret debug_interpret +#define DEBUGGING 1 +#include "interpret.h" +#undef DEBUGGING +#undef r_interpret + +/* interpreter routine for gawk --mpfr */ +#ifdef HAVE_MPFR +#define r_interpret mpfr_interpret +#define EXE_MPFR 1 +#include "interpret.h" +#undef EXE_MPFR +#undef r_interpret +#endif + +/* FIXME interpreter routine for gawk --mpfr --debug */ + + void init_interpret() { @@ -1725,31 +1744,15 @@ init_interpret() } /* select the interpreter routine */ - if (do_debug) - interpret = debug_interpret; #ifdef HAVE_MPFR + if (do_mpfr && do_debug) + interpret = mpfr_interpret; /* FIXME mpfr_debug_interpret; */ else if (do_mpfr) interpret = mpfr_interpret; -#endif + else +#endif + if (do_debug) + interpret = debug_interpret; else interpret = r_interpret; } - - -/* interpreter routine when not debugging */ -#include "interpret.h" - -/* interpreter routine when deubugging with gawk --debug */ -#define r_interpret debug_interpret -#define DEBUGGING 1 -#include "interpret.h" -#undef DEBUGGING -#undef r_interpret - -#ifdef HAVE_MPFR -#define r_interpret mpfr_interpret -#define EXE_MPFR 1 -#include "interpret.h" -#undef EXE_MPFR -#undef r_interpret -#endif @@ -194,24 +194,31 @@ rebuild_record() * so that unrefing a field doesn't try to unref into the old $0. */ for (cops = ops, i = 1; i <= NF; i++) { - if (fields_arr[i]->stlen > 0) { + NODE *r = fields_arr[i]; + if (r->stlen > 0) { NODE *n; getnode(n); - if ((fields_arr[i]->flags & FIELD) == 0) { + if ((r->flags & FIELD) == 0) { *n = *Null_field; - n->stlen = fields_arr[i]->stlen; - if ((fields_arr[i]->flags & (NUMCUR|NUMBER)) != 0) { - n->flags |= (fields_arr[i]->flags & (NUMCUR|NUMBER)); - n->numbr = fields_arr[i]->numbr; + n->stlen = r->stlen; + if ((r->flags & (NUMCUR|NUMBER)) != 0) { + n->flags |= (r->flags & (NUMCUR|NUMBER)); +#ifdef HAVE_MPFR + if (r->flags & MPFN) { + mpfr_init(n->mpfr_numbr); + mpfr_set(n->mpfr_numbr, r->mpfr_numbr, RND_MODE); + } else +#endif + n->numbr = r->numbr; } } else { - *n = *(fields_arr[i]); + *n = *r; n->flags &= ~(MALLOC|STRING); } n->stptr = cops; - unref(fields_arr[i]); + unref(r); fields_arr[i] = n; assert((n->flags & WSTRCUR) == 0); } diff --git a/interpret.h b/interpret.h index 83e78056..fc521ddd 100644 --- a/interpret.h +++ b/interpret.h @@ -1,11 +1,33 @@ /* - * interpret --- code is a list of instructions to run. + * interpret.h --- run a list of instructions. */ +/* + * Copyright (C) 1986, 1988, 1989, 1991-2012 the Free Software Foundation, Inc. + * + * This file is part of GAWK, the GNU implementation of the + * AWK Programming Language. + * + * GAWK is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * GAWK is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + + #ifdef EXE_MPFR -#define NV(r) r->mpfr_numbr +#define NV(r) (r)->mpfr_numbr #else -#define NV(r) r->numbr +#define NV(r) (r)->numbr #endif @@ -233,6 +233,7 @@ extern NODE *ARGIND_node; extern NODE *ERRNO_node; extern NODE **fields_arr; +/* init_io --- set up timeout related variables */ void init_io() diff --git a/m4/mpfr.m4 b/m4/mpfr.m4 new file mode 100644 index 00000000..11cfe106 --- /dev/null +++ b/m4/mpfr.m4 @@ -0,0 +1,62 @@ +dnl Check for MPFR and dependencies +dnl Copyright (C) 2004, 2005 Free Software Foundation, Inc. +dnl +dnl This file is free software, distributed under the terms of the GNU +dnl General Public License. As a special exception to the GNU General +dnl Public License, this file may be distributed as part of a program +dnl that contains a configuration script generated by Autoconf, under +dnl the same distribution terms as the rest of that program. +dnl +dnl Defines HAVE_MPFR to 1 if a working MPFR/GMP setup is +dnl found, and sets @LIBMPFR@ to the necessary libraries. + +AC_DEFUN([GNUPG_CHECK_MPFR], +[ + AC_ARG_WITH([mpfr], + AC_HELP_STRING([--with-mpfr=DIR], + [look for the mpfr and gmp libraries in DIR]), + [_do_mpfr=$withval],[_do_mpfr=yes]) + + if test "$_do_mpfr" != "no" ; then + if test -d "$withval" ; then + CPPFLAGS="${CPPFLAGS} -I$withval/include" + LDFLAGS="${LDFLAGS} -L$withval/lib" + fi + + _mpfr_save_libs=$LIBS + _combo="-lmpfr -lgmp" + LIBS="$LIBS $_combo" + + AC_MSG_CHECKING([whether mpfr via \"$_combo\" is present and usable]) + + AC_LINK_IFELSE([ + AC_LANG_PROGRAM([ +#include <stdio.h> +#include <mpfr.h> +#include <gmp.h> +],[ +mpfr_t p; +mpz_t z; +mpfr_init(p); +mpz_init(z); +mpfr_printf("%Rf%Zd", p, z); +mpfr_clear(p); +mpz_clear(z); +])],_found_mpfr=yes,_found_mpfr=no) + + AC_MSG_RESULT([$_found_mpfr]) + + LIBS=$_mpfr_save_libs + + if test $_found_mpfr = yes ; then + AC_DEFINE(HAVE_MPFR,1, + [Define to 1 if you have a fully functional mpfr and gmp library.]) + AC_SUBST(LIBMPFR,$_combo) + break + fi + + unset _mpfr_save_libs + unset _combo + unset _found_mpfr + fi +])dnl @@ -47,14 +47,6 @@ set_RNDMODE() extern NODE **fmt_list; /* declared in eval.c */ -#define POP_TWO_SCALARS(s1, s2) \ -s2 = POP_SCALAR(); \ -s1 = POP(); \ -do { if (s1->type == Node_var_array) { \ -DEREF(s2); \ -fatal(_("attempt to use array `%s' in a scalar context"), array_vname(s1)); \ -}} while (FALSE) - mpz_t mpzval; /* GMP integer type; used as temporary in many places */ mpfr_t MNR; mpfr_t MFNR; @@ -92,7 +84,10 @@ mpfr_node() NODE *r; getnode(r); r->type = Node_val; + + /* Initialize, set precision to the default precision, and value to NaN */ mpfr_init(r->mpfr_numbr); + r->valref = 1; r->flags = MALLOC|MPFN|NUMBER|NUMCUR; r->stptr = NULL; @@ -170,6 +165,7 @@ mpfr_force_number(NODE *n) return n; } + /* mpfr_format_val --- format a numeric value based on format */ static NODE * @@ -267,6 +263,7 @@ mpfr_set_var(NODE *n) mpfr_get_z(mpzval, p, MPFR_RNDZ); if (mpfr_signbit(p)) { + /* It is a negative number ! */ neg = TRUE; mpz_neg(mpzval, mpzval); } @@ -456,25 +453,63 @@ do_mpfr_atan2(int nargs) NODE * do_mpfr_compl(int nargs) { - NODE *tmp; + NODE *tmp, *r; + mpfr_ptr p; tmp = POP_SCALAR(); + if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0) + lintwarn(_("compl: received non-numeric argument")); + p = force_number(tmp)->mpfr_numbr; + if (! mpfr_number_p(p)) { + /* [+-]inf or NaN */ + return tmp; + } + + if (do_lint) { + if (mpfr_signbit(p)) + lintwarn("%s", + mpfr_fmt(_("compl(%Rg): negative value will give strange results"), p) + ); + if (! mpfr_integer_p(p)) + lintwarn("%s", + mpfr_fmt(_("comp(%Rg): fractional value will be truncated"), p) + ); + } + mpfr_get_z(mpzval, p, MPFR_RNDZ); + mpz_com(mpzval, mpzval); + r = mpfr_node(); + mpfr_set_z(r->mpfr_numbr, mpzval, RND_MODE); DEREF(tmp); - return dupnode(Nnull_string); + return r; } -/* do_cos --- do the cos function */ +#define SPEC_MATH(X) \ +NODE *tmp, *res; \ +tmp = POP_SCALAR(); \ +if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0) \ + lintwarn(_("%s: received non-numeric argument"), #X); \ +force_number(tmp); \ +res = mpfr_node(); \ +mpfr_##X(res->mpfr_numbr, tmp->mpfr_numbr, RND_MODE); \ +DEREF(tmp); \ +return res + + +/* do_sin --- do the sin function */ NODE * -do_mpfr_cos(int nargs) +do_mpfr_sin(int nargs) { - NODE *tmp; + SPEC_MATH(sin); +} - tmp = POP_SCALAR(); +/* do_cos --- do the cos function */ - DEREF(tmp); - return dupnode(Nnull_string); +NODE * +do_mpfr_cos(int nargs) +{ + SPEC_MATH(cos); } /* do_exp --- exponential function */ @@ -482,38 +517,46 @@ do_mpfr_cos(int nargs) NODE * do_mpfr_exp(int nargs) { - NODE *tmp; - - tmp = POP_SCALAR(); - - DEREF(tmp); - return dupnode(Nnull_string); + SPEC_MATH(exp); } -/* do_int --- convert double to int for awk */ +/* do_log --- the log function */ NODE * -do_mpfr_int(int nargs) +do_mpfr_log(int nargs) { - NODE *tmp; + SPEC_MATH(log); +} - tmp = POP_SCALAR(); +/* do_sqrt --- do the sqrt function */ - DEREF(tmp); - return dupnode(Nnull_string); +NODE * +do_mpfr_sqrt(int nargs) +{ + SPEC_MATH(sqrt); } -/* do_log --- the log function */ + +/* do_int --- convert double to int for awk */ NODE * -do_mpfr_log(int nargs) +do_mpfr_int(int nargs) { - NODE *tmp; + NODE *tmp, *r; tmp = POP_SCALAR(); - + if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0) + lintwarn(_("int: received non-numeric argument")); + force_number(tmp); + if (! mpfr_number_p(tmp->mpfr_numbr)) { + /* [+-]inf or NaN */ + return tmp; + } + mpfr_get_z(mpzval, tmp->mpfr_numbr, MPFR_RNDZ); + r = mpfr_node(); + mpfr_set_z(r->mpfr_numbr, mpzval, RND_MODE); DEREF(tmp); - return dupnode(Nnull_string); + return r; } @@ -554,21 +597,24 @@ do_mpfr_lshift(int nargs) NODE * do_mpfr_or(int nargs) { - NODE *s1, *s2; + NODE *t1, *t2, *res; + mpz_t z; - POP_TWO_SCALARS(s1, s2); + if ((res = get_bit_ops(& t1, & t2, "or")) != NULL) + return res; - DEREF(s1); - DEREF(s2); - return dupnode(Nnull_string); -} + mpz_init(z); + mpfr_get_z(mpzval, t1->mpfr_numbr, MPFR_RNDZ); + mpfr_get_z(z, t2->mpfr_numbr, MPFR_RNDZ); + mpz_ior(z, mpzval, z); -/* do_rand --- do the rand function */ + res = mpfr_node(); + mpfr_set_z(res->mpfr_numbr, z, RND_MODE); + mpz_clear(z); -NODE * -do_mpfr_rand(int nargs ATTRIBUTE_UNUSED) -{ - return dupnode(Nnull_string); + DEREF(t1); + DEREF(t2); + return res; } @@ -613,82 +659,120 @@ do_mpfr_rhift(int nargs) res = mpfr_node(); mpfr_set_z(res->mpfr_numbr, mpzval, RND_MODE); /* integer to float conversion */ - DEREF(t1); DEREF(t2); return res; } -/* do_sin --- do the sin function */ +/* do_strtonum --- the strtonum function */ NODE * -do_mpfr_sin(int nargs) +do_mpfr_strtonum(int nargs) { - NODE *tmp; + NODE *tmp, *r; + int base; tmp = POP_SCALAR(); + r = mpfr_node(); + if ((tmp->flags & (NUMBER|NUMCUR)) != 0) + mpfr_set(r->mpfr_numbr, tmp->mpfr_numbr, RND_MODE); + else if ((base = get_numbase(tmp->stptr, use_lc_numeric)) != 10) { + mpfr_strtofr(r->mpfr_numbr, tmp->stptr, NULL, base, RND_MODE); + errno = 0; + } else { + (void) force_number(tmp); + mpfr_set(r->mpfr_numbr, tmp->mpfr_numbr, RND_MODE); + } DEREF(tmp); - return dupnode(Nnull_string); + return r; } -/* do_sqrt --- do the sqrt function */ + +/* do_xor --- perform an ^ operation */ NODE * -do_mpfr_sqrt(int nargs) +do_mpfr_xor(int nargs) { - NODE *tmp; - - tmp = POP_SCALAR(); - - DEREF(tmp); - return dupnode(Nnull_string); -} + NODE *t1, *t2, *res; + mpz_t z; -/* do_srand --- seed the random number generator */ + if ((res = get_bit_ops(& t1, & t2, "xor")) != NULL) + return res; -NODE * -do_mpfr_srand(int nargs) -{ - NODE *tmp; + mpz_init(z); + mpfr_get_z(mpzval, t1->mpfr_numbr, MPFR_RNDZ); + mpfr_get_z(z, t2->mpfr_numbr, MPFR_RNDZ); + mpz_xor(z, mpzval, z); - if (nargs == 0) - ; - else { - tmp = POP_SCALAR(); - DEREF(tmp); - } + res = mpfr_node(); + mpfr_set_z(res->mpfr_numbr, z, RND_MODE); + mpz_clear(z); - return dupnode(Nnull_string); + DEREF(t1); + DEREF(t2); + return res; } -/* do_strtonum --- the strtonum function */ +static int firstrand = TRUE; +static gmp_randstate_t state; +static mpz_t seed; /* current seed */ + +/* do_rand --- do the rand function */ NODE * -do_mpfr_strtonum(int nargs) +do_mpfr_rand(int nargs ATTRIBUTE_UNUSED) { - NODE *tmp; - - tmp = POP_SCALAR(); - DEREF(tmp); - - return dupnode(Nnull_string); + NODE *res; + + if (firstrand) { + /* Choose the default algorithm */ + gmp_randinit_default(state); + mpz_init(seed); + mpz_set_ui(seed, 1L); + /* seed state */ + gmp_randseed(state, seed); + firstrand = FALSE; + } + res = mpfr_node(); + mpfr_urandomb(res->mpfr_numbr, state); + return res; } -/* do_xor --- perform an ^ operation */ +/* do_srand --- seed the random number generator */ NODE * -do_mpfr_xor(int nargs) +do_mpfr_srand(int nargs) { - NODE *s1, *s2; + NODE *tmp, *res; + + if (firstrand) { + /* Choose the default algorithm */ + gmp_randinit_default(state); + mpz_init(seed); + mpz_set_ui(seed, 1L); + /* No need to seed state, will change it below */ + firstrand = FALSE; + } - POP_TWO_SCALARS(s1, s2); + res = mpfr_node(); + mpfr_set_z(res->mpfr_numbr, seed, RND_MODE); /* previous seed */ + + if (nargs == 0) + mpz_set_ui(seed, (unsigned long) time((time_t *) 0)); + else { + tmp = POP_SCALAR(); + if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0) + lintwarn(_("srand: received non-numeric argument")); + force_number(tmp); + mpfr_get_z(seed, tmp->mpfr_numbr, MPFR_RNDZ); + DEREF(tmp); + } - DEREF(s1); - DEREF(s2); - return dupnode(Nnull_string); + gmp_randseed(state, seed); + return res; } @@ -205,7 +205,7 @@ r_format_val(const char *format, int index, NODE *s) */ NODE *dummy[2], *r; - unsigned short oflags; + unsigned int oflags; /* create dummy node for a sole use of format_tree */ dummy[1] = s; @@ -228,7 +228,7 @@ pprint(INSTRUCTION *startp, INSTRUCTION *endp, int in_for_header) if (m == Nnull_string) /* optional return or exit value; don't print 0 or "" */ pp_push(pc->opcode, m->stptr, DONT_FREE); else if ((m->flags & NUMBER) != 0) - pp_push(pc->opcode, pp_number(m->numbr), CAN_FREE); + pp_push(pc->opcode, pp_number(m), CAN_FREE); else { str = pp_string(m->stptr, m->stlen, '"'); if ((m->flags & INTLSTR) != 0) { @@ -341,7 +341,7 @@ cleanup: && is_binary(t1->type)) /* (a - b) * 1 */ pp_parenthesize(t1); if ((m->flags & NUMBER) != 0) - tmp = pp_number(m->numbr); + tmp = pp_number(m); else tmp = pp_string(m->stptr, m->stlen, '"'); str = pp_concat(t1->pp_str, op2str(pc->opcode), tmp); @@ -1202,13 +1202,18 @@ pp_string(const char *in_str, size_t len, int delim) /* pp_number --- pretty format a number */ char * -pp_number(AWKNUM d) +pp_number(NODE *n) { #define PP_PRECISION 6 char *str; emalloc(str, char *, PP_PRECISION + 10, "pp_number"); - sprintf(str, "%0.*g", PP_PRECISION, d); +#ifdef HAVE_MPFR + if (n->flags & MPFN) + mpfr_sprintf(str, "%0.*R*g", PP_PRECISION, RND_MODE, n->mpfr_numbr); + else +#endif + sprintf(str, "%0.*g", PP_PRECISION, n->numbr); return str; #undef PP_PRECISION } @@ -1219,7 +1224,7 @@ char * pp_node(NODE *n) { if ((n->flags & NUMBER) != 0) - return pp_number(n->numbr); + return pp_number(n); return pp_string(n->stptr, n->stlen, '"'); } diff --git a/test/Makefile.am b/test/Makefile.am index 2bbc5539..e3bf71c5 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -863,19 +863,14 @@ GENTESTS_UNUSED = Makefile.in gtlnbufv.awk printfloat.awk CMP = cmp AWKPROG = ../gawk$(EXEEXT) -PGAWKPROG = ../pgawk$(EXEEXT) # This business forces the locale to be C for running the tests, # unless we override it to something else for testing. # # This can also be done in individual tests where we wish to # check things specifically not in the C locale. -AWK = LC_ALL=$${GAWKLOCALE:-C} LANG=$${GAWKLOCALE:-C} $(AWKPROG) -PGAWK = LC_ALL=$${GAWKLOCALE:-C} LANG=$${GAWKLOCALE:-C} $(PGAWKPROG) +AWK = LC_ALL=$${GAWKLOCALE:-C} LANG=$${GAWKLOCALE:-C} $(AWKPROG) $(AWKFLAGS) -check-mpfr: AWK+=-M - -check-mpfr: check # Message stuff is to make it a little easier to follow. # Make the pass-fail last and dependent on others to avoid diff --git a/test/Makefile.in b/test/Makefile.in index f56ee6ca..12974265 100644 --- a/test/Makefile.in +++ b/test/Makefile.in @@ -67,11 +67,12 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/arch.m4 \ $(top_srcdir)/m4/isc-posix.m4 $(top_srcdir)/m4/lcmessage.m4 \ $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libsigsegv.m4 \ - $(top_srcdir)/m4/longlong.m4 $(top_srcdir)/m4/nls.m4 \ - $(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \ - $(top_srcdir)/m4/readline.m4 $(top_srcdir)/m4/socket.m4 \ - $(top_srcdir)/m4/stdint_h.m4 $(top_srcdir)/m4/uintmax_t.m4 \ - $(top_srcdir)/m4/ulonglong.m4 $(top_srcdir)/configure.ac + $(top_srcdir)/m4/longlong.m4 $(top_srcdir)/m4/mpfr.m4 \ + $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ + $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/m4/readline.m4 \ + $(top_srcdir)/m4/socket.m4 $(top_srcdir)/m4/stdint_h.m4 \ + $(top_srcdir)/m4/uintmax_t.m4 $(top_srcdir)/m4/ulonglong.m4 \ + $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs @@ -92,7 +93,7 @@ AUTOMAKE = @AUTOMAKE@ # # This can also be done in individual tests where we wish to # check things specifically not in the C locale. -AWK = LC_ALL=$${GAWKLOCALE:-C} LANG=$${GAWKLOCALE:-C} $(AWKPROG) +AWK = LC_ALL=$${GAWKLOCALE:-C} LANG=$${GAWKLOCALE:-C} $(AWKPROG) $(AWKFLAGS) CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ @@ -121,6 +122,7 @@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ LDFLAGS = @LDFLAGS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ +LIBMPFR = @LIBMPFR@ LIBOBJS = @LIBOBJS@ LIBREADLINE = @LIBREADLINE@ LIBS = @LIBS@ @@ -1046,8 +1048,6 @@ FAIL_CODE1 = \ GENTESTS_UNUSED = Makefile.in gtlnbufv.awk printfloat.awk CMP = cmp AWKPROG = ../gawk$(EXEEXT) -PGAWKPROG = ../pgawk$(EXEEXT) -PGAWK = LC_ALL=$${GAWKLOCALE:-C} LANG=$${GAWKLOCALE:-C} $(PGAWKPROG) all: all-am .SUFFIXES: @@ -1225,10 +1225,6 @@ uninstall-am: mostlyclean-generic pdf pdf-am ps ps-am uninstall uninstall-am -check-mpfr: AWK+=-M - -check-mpfr: check - # Message stuff is to make it a little easier to follow. # Make the pass-fail last and dependent on others to avoid # spurious errors if `make -j' in effect. |