summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog69
-rw-r--r--Makefile.am3
-rw-r--r--Makefile.in16
-rw-r--r--TODO.NUMH40
-rw-r--r--TODO.decimal7
-rw-r--r--array.c56
-rw-r--r--awk.h277
-rw-r--r--awkgram.c1140
-rw-r--r--awkgram.y422
-rw-r--r--awklib/ChangeLog4
-rw-r--r--builtin.c1784
-rw-r--r--command.c34
-rw-r--r--command.y34
-rw-r--r--debug.c33
-rw-r--r--double.c1641
-rw-r--r--eval.c250
-rw-r--r--field.c24
-rw-r--r--format.c791
-rw-r--r--format.h189
-rw-r--r--gawkapi.c7
-rw-r--r--int_array.c2
-rw-r--r--interpret.h172
-rw-r--r--io.c65
-rw-r--r--main.c118
-rw-r--r--misc/ap_math.awk331
-rw-r--r--mpfr.c1802
-rw-r--r--msg.c54
-rw-r--r--node.c339
-rw-r--r--profile.c52
29 files changed, 5294 insertions, 4462 deletions
diff --git a/ChangeLog b/ChangeLog
index 69d9a565..ee54f79c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2014-09-16 Arnold D. Robbins <arnold@skeeve.com>
+
+ * mpfr.c (cleanup_mpfr): Removed.
+ (do_mpfp_div): Merged in. Other changes to make things work.
+ * awkgram.y (tokentab): Need a new flag for "div" instead of
+ checking the builtin function.
+
2014-09-15 Arnold D. Robbins <arnold@skeeve.com>
Finish removing use of isalpha and isalnum.
@@ -639,6 +646,11 @@
include stdlib.h. Needed for Illumos. Thanks to
Richard Palo <richard.palo@free.fr> for the report.
+2013-12-23 Arnold D. Robbins <arnold@skeeve.com>
+
+ * eval.c, interpret.h, mpfr.c: Remove unused variables, fix
+ "variable may be used but not initialized" warnings.
+
2013-12-21 Mike Frysinger <vapier@gentoo.org>
* configure.ac: Add --disable-extensions flag to control
@@ -1348,6 +1360,25 @@
* dfa.h: Include regex.h and stddef.h directly.
* dfa.c: Adjust includes.
+2013-01-12 John Haque <j.eh@mchsi.com>
+
+ * format.c: New file.
+ * Makefile.am: Add format.c to the list of files.
+ * builtin.c (format_tree, format_nondecimal, fmt_parse,
+ get_fmt_buf, mbc_byte_count, mbc_char_count): Move to format.c.
+
+2013-01-11 John Haque <j.eh@mchsi.com>
+
+ Finish format_tree() refactoring.
+
+ * awk.h (struct fmt_list_item): New definition.
+ * builtin.c (fmt_parse): New routine to parse a single format code.
+ (format_tree): Adjusted.
+ * eval.c (fmt_index): (Pre-)compile and store format codes.
+ * double.c (format_awknum_val): Reworked to use compiled
+ format codes.
+ * mpfr.c (mpfp_format_val): Ditto.
+
2013-01-11 John Haque <j.eh@mchsi.com>
* awk.h (do_mpfr_rshift): Renamed from do_mpfr_rhift.
@@ -1377,6 +1408,28 @@
* regex_internal.h (struct re_dfa_t): Restore ifdefs around
__libc_lock_define, they really were needed. Bleah.
+2013-01-03 John Haque <j.eh@mchsi.com>
+
+ Refactor format_tree() to seperate number formatting code.
+
+ * format.h: New file.
+ (format_spec, print_fmt_buf): Definitions.
+ (chksize, bchunk, bchunk_one, buf_adjust, buf2node,
+ tmpbuf_prepend, pr_fill, pr_num_tail, free_print_fmt_buf):
+ Inline routines.
+ * awk.h (num_handler_t): New fields gawk_format_printf,
+ gawk_isnan, gawk_isinf. Removed field gawk_format_nodes.
+ * builtin.c (chksize__internal, cpbuf_chksize__internal,
+ get_fmt_buf, format_nondecimal): New routines.
+ (format_tree): Restore function format_tree(). Adjusted to call
+ the current number formatting routine.
+ * double.c (awknum_isnan, awknum_isinf, format_awknum_printf):
+ New routines.
+ (format_nodes_awknum): Removed.
+ * mpfr.c (mpfp_isnan, mpfp_isinf, mpfp_format_printf):
+ New routines.
+ (mpfp_format_nodes): Removed.
+
2013-01-01 Arnold D. Robbins <arnold@skeeve.com>
Sync with GLIBC regex files.
@@ -1387,11 +1440,27 @@
* regexec.c (check_node_accept_bytes): Restore decl with use from
GLIBC code since this is LIBC case.
+2012-12-28 John Haque <j.eh@mchsi.com>
+
+ * double.c: Use make_awknum everywhere instead of make_number
+ in case a routine is called using not the current handler
+ or before initialization.
+
2012-12-27 Arnold D. Robbins <arnold@skeeve.com>
* builtin.c (do_print, do_printf): Use output_fp as default
output for print/printf only if running under the debugger.
Otherwise use stdout as Brian, Peter, and Al intended.
+
+2012-12-27 John Haque <j.eh@mchsi.com>
+
+ Number handling interface.
+
+ * awk.h (numbr_handler_t, bltin_t): New definitions.
+ * double.c: New file for C double numbers.
+ * mpfr.c: Reworked.
+
+ Lots of other changes.
2012-12-25 Arnold D. Robbins <arnold@skeeve.com>
diff --git a/Makefile.am b/Makefile.am
index 3d1c8837..52ef5a47 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -88,11 +88,14 @@ base_sources = \
debug.c \
dfa.c \
dfa.h \
+ double.c \
eval.c \
ext.c \
field.c \
floatcomp.c \
floatmagic.h \
+ format.c \
+ format.h \
gawkapi.c \
gawkapi.h \
gawkmisc.c \
diff --git a/Makefile.in b/Makefile.in
index 5c2a7f11..4b5fa69f 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -133,11 +133,12 @@ am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(includedir)"
PROGRAMS = $(bin_PROGRAMS)
am__objects_1 = array.$(OBJEXT) awkgram.$(OBJEXT) builtin.$(OBJEXT) \
cint_array.$(OBJEXT) command.$(OBJEXT) debug.$(OBJEXT) \
- dfa.$(OBJEXT) eval.$(OBJEXT) ext.$(OBJEXT) field.$(OBJEXT) \
- floatcomp.$(OBJEXT) gawkapi.$(OBJEXT) gawkmisc.$(OBJEXT) \
- getopt.$(OBJEXT) getopt1.$(OBJEXT) int_array.$(OBJEXT) \
- io.$(OBJEXT) main.$(OBJEXT) mpfr.$(OBJEXT) msg.$(OBJEXT) \
- node.$(OBJEXT) profile.$(OBJEXT) random.$(OBJEXT) re.$(OBJEXT) \
+ dfa.$(OBJEXT) double.$(OBJEXT) eval.$(OBJEXT) ext.$(OBJEXT) \
+ field.$(OBJEXT) floatcomp.$(OBJEXT) format.$(OBJEXT) \
+ gawkapi.$(OBJEXT) gawkmisc.$(OBJEXT) getopt.$(OBJEXT) \
+ getopt1.$(OBJEXT) int_array.$(OBJEXT) io.$(OBJEXT) \
+ main.$(OBJEXT) mpfr.$(OBJEXT) msg.$(OBJEXT) node.$(OBJEXT) \
+ profile.$(OBJEXT) random.$(OBJEXT) re.$(OBJEXT) \
regex.$(OBJEXT) replace.$(OBJEXT) str_array.$(OBJEXT) \
symbol.$(OBJEXT) version.$(OBJEXT)
am_gawk_OBJECTS = $(am__objects_1)
@@ -492,11 +493,14 @@ base_sources = \
debug.c \
dfa.c \
dfa.h \
+ double.c \
eval.c \
ext.c \
field.c \
floatcomp.c \
floatmagic.h \
+ format.c \
+ format.h \
gawkapi.c \
gawkapi.h \
gawkmisc.c \
@@ -661,10 +665,12 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/command.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/debug.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dfa.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/double.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eval.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/field.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/floatcomp.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/format.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gawkapi.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gawkmisc.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getopt.Po@am__quote@
diff --git a/TODO.NUMH b/TODO.NUMH
new file mode 100644
index 00000000..d95ed559
--- /dev/null
+++ b/TODO.NUMH
@@ -0,0 +1,40 @@
+* (Further) refactoring (s)printf formatting code:
+
+ [1] Remove direct calls to format_tree() in number to string (force_string)
+routines. Fix CONVFMT = "%s"/"%c" crash; present in all known gawk versions.
+Cache parsed format code in fmt_idx() ... DONE
+
+ [2] Try to format NaN/inf in main gawk code, and not in the individual handlers.
+
+* In non-number related routines (substr, index, ..), fetch an integer directly
+using get_number_si/get_number_ui to get the correct size at the int boundaries.
+Use isinteger() to test for a floating-point value instead of get_number_d() and ...
+May require additional tests e.g. SIZE_MAX <= UINT_MAX. In a nutshell, don't do this:
+
+ number => double => integer
+
+* Restore constant-folding code for numbers.
+
+* Consider special handling of integer-indexed arrays with non-double
+number handlers.
+ - Choose a reasonable range for integer indices.
+ #if SIZEOF_LONG <= 8
+ typedef gawk_int_t long
+ #define GAWK_INT_MAX LONG_MAX
+ #define GAWK_INT_MIN LONG_MIN
+ #define GAWK_INT_BIT SIZEOF_LONG * 8 ### may not need this
+ #else
+ typedef gawk_int_t int
+ #define GAWK_INT_MAX INT_MAX
+ #define GAWK_INT_MIN INT_MIN
+ #define GAWK_INT_BIT SIZEOF_INT * 8
+ #endif
+ Install gaurd code in array handlers (or adjust the defs) for size
+ anything but 4 or 8 (overthinking?). Use gawk_int_t instead
+ of int32_t or int64_t.
+
+ - Use additional struct field number_fits_gawk_int()
+ (MPFR has similarly named routines, e.g. mpfr_fits_slong()),
+ and avoid checking after conversion. Note that the type is
+ gawk_int_t and NOT necessarily long.
+
diff --git a/TODO.decimal b/TODO.decimal
new file mode 100644
index 00000000..e40cddbd
--- /dev/null
+++ b/TODO.decimal
@@ -0,0 +1,7 @@
+Fri Mar 15 14:07:55 IST 2013
+============================
+
+This branch needs to be merged with master.
+
+The eventual goal is to support decimal arithmetic with the mpdecimal library
+at http://www.bytereef.org/mpdecimal/index.html
diff --git a/array.c b/array.c
index 682b8ddb..cb2e654f 100644
--- a/array.c
+++ b/array.c
@@ -26,7 +26,6 @@
#include "awk.h"
extern FILE *output_fp;
-extern NODE **fmt_list; /* declared in eval.c */
static size_t SUBSEPlen;
static char *SUBSEP;
@@ -72,14 +71,13 @@ register_array_func(afunc_t *afunc)
return false;
}
-
/* array_init --- register all builtin array types */
void
array_init()
{
(void) register_array_func(str_array_func); /* the default */
- if (! do_mpfr) {
+ if (numbr_hndlr == & awknum_hndlr) {
(void) register_array_func(int_array_func);
(void) register_array_func(cint_array_func);
}
@@ -655,10 +653,6 @@ do_delete_loop(NODE *symbol, NODE **lhs)
static void
value_info(NODE *n)
{
-
-#define PREC_NUM -1
-#define PREC_STR -1
-
if (n == Nnull_string || n == Null_field) {
fprintf(output_fp, "<(null)>");
return;
@@ -666,30 +660,12 @@ value_info(NODE *n)
if ((n->flags & (STRING|STRCUR)) != 0) {
fprintf(output_fp, "<");
- fprintf(output_fp, "\"%.*s\"", PREC_STR, n->stptr);
- if ((n->flags & (NUMBER|NUMCUR)) != 0) {
-#ifdef HAVE_MPFR
- if (is_mpg_float(n))
- fprintf(output_fp, ":%s",
- mpg_fmt("%.*R*g", PREC_NUM, ROUND_MODE, n->mpg_numbr));
- else if (is_mpg_integer(n))
- fprintf(output_fp, ":%s", mpg_fmt("%Zd", n->mpg_i));
- else
-#endif
- fprintf(output_fp, ":%.*g", PREC_NUM, n->numbr);
- }
+ fprintf(output_fp, "\"%.*s\"", -1, n->stptr);
+ if ((n->flags & (NUMBER|NUMCUR)) != 0)
+ fprintf(output_fp, ":%s", fmt_number("%.17g", n));
fprintf(output_fp, ">");
- } else {
-#ifdef HAVE_MPFR
- if (is_mpg_float(n))
- fprintf(output_fp, "<%s>",
- mpg_fmt("%.*R*g", PREC_NUM, ROUND_MODE, n->mpg_numbr));
- else if (is_mpg_integer(n))
- fprintf(output_fp, "<%s>", mpg_fmt("%Zd", n->mpg_i));
- else
-#endif
- fprintf(output_fp, "<%.*g>", PREC_NUM, n->numbr);
- }
+ } else
+ fprintf(output_fp, "<%s>", fmt_number("%.17g", n));
fprintf(output_fp, ":%s", flags2str(n->flags));
@@ -702,11 +678,8 @@ value_info(NODE *n)
fprintf(output_fp, "][");
fprintf(output_fp, "stfmt=%d, ", n->stfmt);
fprintf(output_fp, "CONVFMT=\"%s\"", n->stfmt <= -1 ? "%ld"
- : fmt_list[n->stfmt]->stptr);
+ : fmt_list[n->stfmt].fmt->stptr);
}
-
-#undef PREC_NUM
-#undef PREC_STR
}
@@ -1220,22 +1193,11 @@ sort_user_func(const void *p1, const void *p2)
PUSH(val2);
/* execute the comparison function */
- (void) (*interpret)(code);
+ interpret(code);
/* return value of the comparison function */
r = POP_NUMBER();
-#ifdef HAVE_MPFR
- /*
- * mpfr_sgn(mpz_sgn): Returns a positive value if op > 0,
- * zero if op = 0, and a negative value if op < 0.
- */
- if (is_mpg_float(r))
- ret = mpfr_sgn(r->mpg_numbr);
- else if (is_mpg_integer(r))
- ret = mpz_sgn(r->mpg_i);
- else
-#endif
- ret = (r->numbr < 0.0) ? -1 : (r->numbr > 0.0);
+ ret = sgn_number(r);
DEREF(r);
return ret;
}
diff --git a/awk.h b/awk.h
index cd055962..e1ec7b91 100644
--- a/awk.h
+++ b/awk.h
@@ -203,18 +203,6 @@ extern void *memset_ulong(void *dest, int val, unsigned long l);
/* same thing for warning */
#define warning (*(set_loc(__FILE__, __LINE__),r_warning))
-#ifdef HAVE_MPFR
-#include <gmp.h>
-#include <mpfr.h>
-#ifndef MPFR_RNDN
-/* for compatibility with MPFR 2.X */
-#define MPFR_RNDN GMP_RNDN
-#define MPFR_RNDZ GMP_RNDZ
-#define MPFR_RNDU GMP_RNDU
-#define MPFR_RNDD GMP_RNDD
-#endif
-#endif
-
#include "regex.h"
#include "dfa.h"
typedef struct Regexp {
@@ -237,6 +225,13 @@ typedef struct Regexp {
#define RE_NEED_START 1 /* need to know start/end of match */
#define RE_NO_BOL 2 /* not allowed to match ^ in regexp */
+
+#ifndef CHAR_BIT
+# define CHAR_BIT 8
+#endif
+
+#define DEFAULT_G_PRECISION 6
+
#include "gawkapi.h"
/* Stuff for losing systems. */
@@ -380,17 +375,6 @@ typedef struct exp_node {
} nodep;
struct {
-#ifdef HAVE_MPFR
- union {
- AWKNUM fltnum;
- mpfr_t mpnum;
- mpz_t mpi;
- } nm;
-#else
- AWKNUM fltnum; /* this is here for optimal packing of
- * the structure on many machines
- */
-#endif
char *sp;
size_t slen;
long sref;
@@ -398,7 +382,14 @@ typedef struct exp_node {
#if MBS_SUPPORT
wchar_t *wsp;
size_t wslen;
-#endif
+#endif
+ union {
+ AWKNUM fltnum;
+ void *pq;
+ } nmb;
+#define numbr sub.val.nmb.fltnum
+#define qnumbr sub.val.nmb.pq
+
} val;
} sub;
NODETYPE type;
@@ -464,13 +455,6 @@ typedef struct exp_node {
#define stfmt sub.val.idx
#define wstptr sub.val.wsp
#define wstlen sub.val.wslen
-#ifdef HAVE_MPFR
-#define mpg_numbr sub.val.nm.mpnum
-#define mpg_i sub.val.nm.mpi
-#define numbr sub.val.nm.fltnum
-#else
-#define numbr sub.val.fltnum
-#endif
/* Node_arrayfor */
#define for_list sub.nodep.r.av
@@ -548,18 +532,19 @@ typedef enum opcodeval {
Op_illegal,
/* binary operators */
+ Op_plus,
+ Op_minus,
Op_times,
- Op_times_i,
Op_quotient,
- Op_quotient_i,
Op_mod,
- Op_mod_i,
- Op_plus,
- Op_plus_i,
- Op_minus,
- Op_minus_i,
Op_exp,
- Op_exp_i,
+ Op_assign_plus,
+ Op_assign_minus,
+ Op_assign_times,
+ Op_assign_quotient,
+ Op_assign_mod,
+ Op_assign_exp,
+
Op_concat,
/* line range instruction pair */
@@ -574,6 +559,7 @@ typedef enum opcodeval {
Op_predecrement,
Op_postincrement,
Op_postdecrement,
+ Op_unary_plus,
Op_unary_minus,
Op_field_spec,
@@ -585,12 +571,6 @@ typedef enum opcodeval {
Op_store_var, /* simple variable assignment optimization */
Op_store_sub, /* array[subscript] assignment optimization */
Op_store_field, /* $n assignment optimization */
- Op_assign_times,
- Op_assign_quotient,
- Op_assign_mod,
- Op_assign_plus,
- Op_assign_minus,
- Op_assign_exp,
Op_assign_concat,
/* boolean binaries */
@@ -747,7 +727,6 @@ typedef struct exp_instruction {
#define GENSUB 0x02 /* builtin is gensub */
#define LITERAL 0x04 /* target is a literal string */
-
/* Op_K_exit */
#define target_end d.di
#define target_atexit x.xi
@@ -877,6 +856,74 @@ typedef struct exp_instruction {
/* Op_store_var */
#define initval x.xn
+
+typedef struct {
+ const char *name; /* name of the built-in */
+ NODE *(*ptr)(int); /* function that implements this built-in */
+} bltin_t;
+
+struct format_spec;
+struct print_fmt_buf;
+
+typedef struct {
+ bool (*init)(bltin_t **); /* initialization */
+ const char *(*version_str)(void); /* library version */
+ void (*load_procinfo)(void); /* load relevant PROCINFO entries */
+
+ NODE *(*gawk_make_number)(AWKNUM); /* convert AWKNUM to numeric value */
+ NODE *(*gawk_str2number)(char *, char **, int, bool); /* convert a C-style string
+ to number */
+ NODE *(*gawk_copy_number)(const NODE *); /* deep-copy a numeric NODE */
+
+ void (*gawk_free_number)(NODE *); /* free internally allocated space */
+
+ NODE *(*gawk_force_number)(NODE *); /* force a NODE value to be numeric */
+ void (*gawk_negate_number)(NODE *); /* in place negation of a number */
+ int (*gawk_cmp_numbers)(const NODE *, const NODE *); /* compare two numbers */
+
+ int (*gawk_sgn_number)(const NODE *); /* test if a numeric node is zero,
+ positive or negative */
+ bool (*gawk_isinteger)(const NODE *); /* test if a number is an integer */
+ bool (*gawk_isnan)(const NODE *); /* test if NaN */
+ bool (*gawk_isinf)(const NODE *); /* test if infinity */
+
+ NODE *(*gawk_fmt_number)(const char *, int, NODE *); /* stringify a numeric value
+ based on awk input/output format */
+
+ /* (s)printf formatting of numbers */
+ int (*gawk_format_printf)(NODE *, struct format_spec *, struct print_fmt_buf *);
+
+ /* conversion to C types */
+ double (*gawk_todouble)(const NODE *); /* number to double */
+ long (*gawk_tolong)(const NODE *); /* number to long */
+ unsigned long (*gawk_toulong)(const NODE *); /* number to unsigned long */
+ uintmax_t (*gawk_touintmax_t)(const NODE *); /* number to uintmax_t */
+
+ /* operators */
+ NODE *(*add)(const NODE *, const NODE *); /* addition */
+ NODE *(*sub)(const NODE *, const NODE *); /* subtraction */
+ NODE *(*mul)(const NODE *, const NODE *); /* multiplication */
+ NODE *(*div)(const NODE *, const NODE *); /* division */
+ NODE *(*mod)(const NODE *, const NODE *); /* remainder */
+ NODE *(*pow)(const NODE *, const NODE *); /* exponentiation */
+
+ NODE *(*add_long)(const NODE *, long); /* add a long to a number */
+
+ NODE *(*update_numvar)(NODE *); /* update a NODE value from
+ internal variable(s) */
+ void (*set_numvar)(const NODE *); /* update internal variable(s)
+ from a NODE value */
+ long (*increment_var)(const NODE *, long); /* update NR or FNR related internal
+ variables -- efficiency hack */
+ void (*init_numvars)(void); /* set default values for PREC etc. */
+} numbr_handler_t;
+
+
+struct fmt_list_item {
+ NODE *fmt; /* format string */
+ struct format_spec *spec; /* parsed format code */
+};
+
typedef struct iobuf {
awk_input_buf_t public; /* exposed to extensions */
char *buf; /* start data buffer */
@@ -1041,14 +1088,30 @@ extern NODE *LINT_node, *ERRNO_node, *TEXTDOMAIN_node, *FPAT_node;
extern NODE *PREC_node, *ROUNDMODE_node;
extern NODE *Nnull_string;
extern NODE *Null_field;
+extern NODE *true_node, *false_node;
extern NODE **fields_arr;
extern int sourceline;
extern char *source;
extern int (*interpret)(INSTRUCTION *); /* interpreter routine */
-extern NODE *(*make_number)(double); /* double instead of AWKNUM on purpose */
+
+extern numbr_handler_t awknum_hndlr; /* double */
+extern numbr_handler_t mpfp_hndlr; /* arbitrary-precision floating-point */
+extern numbr_handler_t *numbr_hndlr; /* active handler */
+
+extern NODE *(*make_number)(AWKNUM);
extern NODE *(*str2number)(NODE *);
extern NODE *(*format_val)(const char *, int, NODE *);
extern int (*cmp_numbers)(const NODE *, const NODE *);
+extern NODE *(*str2node)(char *, char **, int, bool);
+extern void (*free_number)(NODE *);
+extern unsigned long (*get_number_ui)(const NODE *);
+extern long (*get_number_si)(const NODE *);
+extern double (*get_number_d)(const NODE *);
+extern uintmax_t (*get_number_uj)(const NODE *);
+extern int (*sgn_number)(const NODE *);
+extern int (*format_number_printf)(NODE *, struct format_spec *, struct print_fmt_buf *);
+
+extern struct fmt_list_item *fmt_list;
/* built-in array types */
extern afunc_t str_array_func[];
@@ -1077,7 +1140,6 @@ enum do_flag_values {
DO_SANDBOX = 0x0800, /* sandbox mode - disable 'system' function & redirections */
DO_PROFILE = 0x1000, /* profile the program */
DO_DEBUG = 0x2000, /* debug the program */
- DO_MPFR = 0x4000 /* arbitrary-precision floating-point math */
};
#define do_traditional (do_flags & DO_TRADITIONAL)
@@ -1091,7 +1153,6 @@ enum do_flag_values {
#define do_tidy_mem (do_flags & DO_TIDY_MEM)
#define do_sandbox (do_flags & DO_SANDBOX)
#define do_debug (do_flags & DO_DEBUG)
-#define do_mpfr (do_flags & DO_MPFR)
extern bool do_optimize;
extern int use_lc_numeric;
@@ -1119,15 +1180,6 @@ extern int ngroups;
extern struct lconv loc;
#endif /* HAVE_LOCALE_H */
-#ifdef HAVE_MPFR
-extern mpfr_prec_t PRECISION;
-extern mpfr_rnd_t ROUND_MODE;
-extern mpz_t MNR;
-extern mpz_t MFNR;
-extern mpz_t mpzval;
-extern bool do_ieee_fmt; /* emulate IEEE 754 floating-point format */
-#endif
-
extern const char *myname;
extern const char def_strftime_format[];
@@ -1190,43 +1242,8 @@ DEREF(NODE *r)
#define TOP_NUMBER() force_number(TOP_SCALAR())
/* ------------------------- Pseudo-functions ------------------------- */
-#ifdef HAVE_MPFR
-/* conversion to C types */
-#define get_number_ui(n) (((n)->flags & MPFN) ? mpfr_get_ui((n)->mpg_numbr, ROUND_MODE) \
- : ((n)->flags & MPZN) ? mpz_get_ui((n)->mpg_i) \
- : (unsigned long) (n)->numbr)
-#define get_number_si(n) (((n)->flags & MPFN) ? mpfr_get_si((n)->mpg_numbr, ROUND_MODE) \
- : ((n)->flags & MPZN) ? mpz_get_si((n)->mpg_i) \
- : (long) (n)->numbr)
-#define get_number_d(n) (((n)->flags & MPFN) ? mpfr_get_d((n)->mpg_numbr, ROUND_MODE) \
- : ((n)->flags & MPZN) ? mpz_get_d((n)->mpg_i) \
- : (double) (n)->numbr)
-#define get_number_uj(n) (((n)->flags & MPFN) ? mpfr_get_uj((n)->mpg_numbr, ROUND_MODE) \
- : ((n)->flags & MPZN) ? (uintmax_t) mpz_get_d((n)->mpg_i) \
- : (uintmax_t) (n)->numbr)
-
-#define iszero(n) (((n)->flags & MPFN) ? mpfr_zero_p((n)->mpg_numbr) \
- : ((n)->flags & MPZN) ? (mpz_sgn((n)->mpg_i) == 0) \
- : ((n)->numbr == 0.0))
-
-#define IEEE_FMT(r, t) (void) (do_ieee_fmt && format_ieee(r, t))
-
-#define mpg_float() mpg_node(MPFN)
-#define mpg_integer() mpg_node(MPZN)
-#define is_mpg_float(n) (((n)->flags & MPFN) != 0)
-#define is_mpg_integer(n) (((n)->flags & MPZN) != 0)
-#define is_mpg_number(n) (((n)->flags & (MPZN|MPFN)) != 0)
-#else
-#define get_number_ui(n) (unsigned long) (n)->numbr
-#define get_number_si(n) (long) (n)->numbr
-#define get_number_d(n) (double) (n)->numbr
-#define get_number_uj(n) (uintmax_t) (n)->numbr
-
-#define is_mpg_number(n) 0
-#define is_mpg_float(n) 0
-#define is_mpg_integer(n) 0
-#define iszero(n) ((n)->numbr == 0.0)
-#endif
+#define iszero(n) (sgn_number(n) == 0)
+#define isinteger(n) numbr_hndlr->gawk_isinteger(n)
#define var_uninitialized(n) ((n)->var_value == Nnull_string)
@@ -1369,7 +1386,6 @@ extern void free_srcfile(SRCFILE *thisfile);
extern void register_deferred_variable(const char *name, NODE *(*load_func)(void));
extern int files_are_same(char *path, SRCFILE *src);
extern void valinfo(NODE *n, Func_print print_func, FILE *fp);
-extern void negate_num(NODE *n);
typedef NODE *(*builtin_func_t)(int); /* function that implements a built-in */
extern builtin_func_t lookup_builtin(const char *name);
extern void install_builtins(void);
@@ -1377,19 +1393,13 @@ extern bool is_alpha(int c);
extern bool is_alnum(int c);
extern bool is_identchar(int c);
/* builtin.c */
-extern double double_to_int(double d);
-extern NODE *do_exp(int nargs);
extern NODE *do_fflush(int nargs);
extern NODE *do_index(int nargs);
-extern NODE *do_int(int nargs);
extern NODE *do_isarray(int nargs);
extern NODE *do_length(int nargs);
-extern NODE *do_log(int nargs);
extern NODE *do_mktime(int nargs);
extern NODE *do_sprintf(int nargs);
extern void do_printf(int nargs, int redirtype);
-extern void print_simple(NODE *tree, FILE *fp);
-extern NODE *do_sqrt(int nargs);
extern NODE *do_substr(int nargs);
extern NODE *do_strftime(int nargs);
extern NODE *do_systime(int nargs);
@@ -1398,22 +1408,8 @@ extern void do_print(int nargs, int redirtype);
extern void do_print_rec(int args, int redirtype);
extern NODE *do_tolower(int nargs);
extern NODE *do_toupper(int nargs);
-extern NODE *do_atan2(int nargs);
-extern NODE *do_sin(int nargs);
-extern NODE *do_cos(int nargs);
-extern NODE *do_rand(int nargs);
-extern NODE *do_srand(int nargs);
extern NODE *do_match(int nargs);
extern NODE *do_sub(int nargs, unsigned int flags);
-extern NODE *format_tree(const char *, size_t, NODE **, long);
-extern NODE *do_lshift(int nargs);
-extern NODE *do_rshift(int nargs);
-extern NODE *do_and(int nargs);
-extern NODE *do_or(int nargs);
-extern NODE *do_xor(int nargs);
-extern NODE *do_compl(int nargs);
-extern NODE *do_strtonum(int nargs);
-extern AWKNUM nondec2awknum(char *str, size_t len);
extern NODE *do_dcgettext(int nargs);
extern NODE *do_dcngettext(int nargs);
extern NODE *do_bindtextdomain(int nargs);
@@ -1422,12 +1418,12 @@ extern NODE *do_div(int nargs);
extern int strncasecmpmbs(const unsigned char *,
const unsigned char *, size_t);
#endif
+
/* eval.c */
extern void PUSH_CODE(INSTRUCTION *cp);
extern INSTRUCTION *POP_CODE(void);
extern void init_interpret(void);
extern int cmp_nodes(NODE *t1, NODE *t2);
-extern int cmp_awknums(const NODE *t1, const NODE *t2);
extern void set_IGNORECASE(void);
extern void set_OFS(void);
extern void set_ORS(void);
@@ -1447,13 +1443,13 @@ extern const char *flags2str(int);
extern const char *genflags2str(int flagval, const struct flagtab *tab);
extern const char *nodetype2str(NODETYPE type);
extern void load_casetable(void);
-extern AWKNUM calc_exp(AWKNUM x1, AWKNUM x2);
extern const char *opcode2str(OPCODE type);
extern const char *op2str(OPCODE type);
extern NODE **r_get_lhs(NODE *n, bool reference);
extern STACK_ITEM *grow_stack(void);
extern void dump_fcall_stack(FILE *fp);
extern int register_exec_hook(Func_pre_exec preh, Func_post_exec posth);
+
/* ext.c */
extern NODE *do_ext(int nargs);
void load_ext(const char *lib_name); /* temporary */
@@ -1467,12 +1463,15 @@ extern NODE *get_actual_argument(int, bool, bool);
#define get_scalar_argument(i, opt) get_actual_argument((i), (opt), false)
#define get_array_argument(i, opt) get_actual_argument((i), (opt), true)
#endif
+
/* field.c */
extern void init_fields(void);
extern void set_record(const char *buf, int cnt);
extern void reset_record(void);
extern void rebuild_record(void);
extern void set_NF(void);
+extern void set_PREC(void);
+extern void set_ROUNDMODE(void);
extern NODE **get_field(long num, Func_ptr *assign);
extern NODE *do_split(int nargs);
extern NODE *do_patsplit(int nargs);
@@ -1521,7 +1520,6 @@ extern void register_output_wrapper(awk_output_wrapper_t *wrapper);
extern void register_two_way_processor(awk_two_way_processor_t *processor);
extern void set_FNR(void);
extern void set_NR(void);
-
extern struct redirect *redirect(NODE *redir_exp, int redirtype, int *errflg);
extern NODE *do_close(int nargs);
extern int flush_io(void);
@@ -1534,6 +1532,7 @@ extern NODE *do_getline(int intovar, IOBUF *iop);
extern struct redirect *getredirect(const char *str, int len);
extern bool inrec(IOBUF *iop, int *errcode);
extern int nextfile(IOBUF **curfile, bool skipping);
+
/* main.c */
extern int arg_assign(char *arg, bool initing);
extern int is_std_var(const char *var);
@@ -1542,42 +1541,11 @@ extern char *estrdup(const char *str, size_t len);
extern void update_global_values();
extern long getenv_long(const char *name);
-/* mpfr.c */
-extern void set_PREC(void);
-extern void set_ROUNDMODE(void);
-extern void mpfr_unset(NODE *n);
-#ifdef HAVE_MPFR
-extern int mpg_cmp(const NODE *, const NODE *);
-extern int format_ieee(mpfr_ptr, int);
-extern NODE *mpg_update_var(NODE *);
-extern long mpg_set_var(NODE *);
-extern NODE *do_mpfr_and(int);
-extern NODE *do_mpfr_atan2(int);
-extern NODE *do_mpfr_compl(int);
-extern NODE *do_mpfr_cos(int);
-extern NODE *do_mpfr_div(int);
-extern NODE *do_mpfr_exp(int);
-extern NODE *do_mpfr_int(int);
-extern NODE *do_mpfr_log(int);
-extern NODE *do_mpfr_lshift(int);
-extern NODE *do_mpfr_or(int);
-extern NODE *do_mpfr_rand(int);
-extern NODE *do_mpfr_rshift(int);
-extern NODE *do_mpfr_sin(int);
-extern NODE *do_mpfr_sqrt(int);
-extern NODE *do_mpfr_srand(int);
-extern NODE *do_mpfr_strtonum(int);
-extern NODE *do_mpfr_xor(int);
-extern void init_mpfr(mpfr_prec_t, const char *);
-extern void cleanup_mpfr(void);
-extern NODE *mpg_node(unsigned int);
-extern const char *mpg_fmt(const char *, ...);
-extern int mpg_strtoui(mpz_ptr, char *, size_t, char **, int);
-#endif
/* msg.c */
extern void gawk_exit(int status);
extern void final_exit(int status) ATTRIBUTE_NORETURN;
extern void err(bool isfatal, const char *s, const char *emsg, va_list argp) ATTRIBUTE_PRINTF(3, 0);
+const char *fmt_number(const char *format, const NODE *n);
extern void msg (const char *mesg, ...) ATTRIBUTE_PRINTF_1;
extern void error (const char *mesg, ...) ATTRIBUTE_PRINTF_1;
extern void r_warning (const char *mesg, ...) ATTRIBUTE_PRINTF_1;
@@ -1588,6 +1556,7 @@ extern void (*lintfunc)(const char *mesg, ...) ATTRIBUTE_PRINTF_1;
#else
extern void (*lintfunc)(const char *mesg, ...);
#endif
+
/* profile.c */
extern void init_profiling_signals(void);
extern void set_prof_file(const char *filename);
@@ -1598,6 +1567,7 @@ extern char *pp_node(NODE *n);
extern int pp_func(INSTRUCTION *pc, void *);
extern void pp_string_fp(Func_print print_func, FILE *fp, const char *str,
size_t namelen, int delim, bool breaklines);
+
/* node.c */
extern NODE *r_force_number(NODE *n);
extern NODE *r_format_val(const char *format, int index, NODE *s);
@@ -1605,6 +1575,7 @@ extern NODE *r_dupnode(NODE *n);
extern NODE *make_str_node(const char *s, size_t len, int flags);
extern void *more_blocks(int id);
extern int parse_escape(const char **string_ptr);
+extern int get_numbase(const char *str, bool use_locale);
#if MBS_SUPPORT
extern NODE *str2wstr(NODE *n, size_t **ptr);
extern NODE *wstr2str(NODE *n);
@@ -1622,6 +1593,7 @@ extern void init_btowc_cache();
#else
#define free_wstr(NODE) /* empty */
#endif
+
/* re.c */
extern Regexp *make_regexp(const char *s, size_t len, bool ignorecase, bool dfa, bool canfatal);
extern int research(Regexp *rp, char *str, int start, size_t len, int flags);
@@ -1632,7 +1604,6 @@ extern void resyntax(int syntax);
extern void resetup(void);
extern int avoid_dfa(NODE *re, char *str, size_t len);
extern int reisstring(const char *text, size_t len, Regexp *re, const char *buf);
-extern int get_numbase(const char *str, bool use_locale);
/* symbol.c */
extern void load_symbols();
@@ -1771,7 +1742,7 @@ in_array(NODE *a, NODE *s)
NODE **ret;
ret = a->aexists(a, s);
-
+
return ret ? *ret : NULL;
}
diff --git a/awkgram.c b/awkgram.c
index 4369666a..861ab0bf 100644
--- a/awkgram.c
+++ b/awkgram.c
@@ -110,7 +110,6 @@ static INSTRUCTION *mk_expression_list(INSTRUCTION *list, INSTRUCTION *s1);
static INSTRUCTION *mk_for_loop(INSTRUCTION *forp, INSTRUCTION *init, INSTRUCTION *cond,
INSTRUCTION *incr, INSTRUCTION *body);
static void fix_break_continue(INSTRUCTION *list, INSTRUCTION *b_target, INSTRUCTION *c_target);
-static INSTRUCTION *mk_binary(INSTRUCTION *s1, INSTRUCTION *s2, INSTRUCTION *op);
static INSTRUCTION *mk_boolean(INSTRUCTION *left, INSTRUCTION *right, INSTRUCTION *op);
static INSTRUCTION *mk_assignment(INSTRUCTION *lhs, INSTRUCTION *rhs, INSTRUCTION *op);
static INSTRUCTION *mk_getline(INSTRUCTION *op, INSTRUCTION *opt_var, INSTRUCTION *redir, int redirtype);
@@ -195,7 +194,7 @@ extern double fmod(double x, double y);
#define YYSTYPE INSTRUCTION *
-#line 199 "awkgram.c" /* yacc.c:339 */
+#line 198 "awkgram.c" /* yacc.c:339 */
# ifndef YY_NULLPTR
# if defined __cplusplus && 201103L <= __cplusplus
@@ -349,7 +348,7 @@ int yyparse (void);
/* Copy the second part of user declarations. */
-#line 353 "awkgram.c" /* yacc.c:358 */
+#line 352 "awkgram.c" /* yacc.c:358 */
#ifdef short
# undef short
@@ -651,25 +650,25 @@ static const yytype_uint8 yytranslate[] =
/* YYRLINE[YYN] -- Source line where rule number YYN was defined. */
static const yytype_uint16 yyrline[] =
{
- 0, 198, 198, 200, 205, 206, 212, 224, 228, 239,
- 245, 250, 258, 266, 268, 273, 281, 283, 289, 290,
- 292, 318, 329, 340, 346, 355, 365, 367, 369, 375,
- 380, 381, 385, 404, 403, 437, 439, 444, 445, 458,
- 463, 464, 468, 470, 472, 479, 569, 611, 653, 766,
- 773, 780, 790, 799, 808, 817, 828, 844, 843, 867,
- 879, 879, 977, 977, 1010, 1040, 1046, 1047, 1053, 1054,
- 1061, 1066, 1078, 1092, 1094, 1102, 1107, 1109, 1117, 1119,
- 1128, 1129, 1137, 1142, 1142, 1153, 1157, 1165, 1166, 1169,
- 1171, 1176, 1177, 1186, 1187, 1192, 1197, 1203, 1205, 1207,
- 1214, 1215, 1221, 1222, 1227, 1229, 1234, 1236, 1244, 1249,
- 1258, 1265, 1267, 1269, 1285, 1295, 1302, 1304, 1309, 1311,
- 1313, 1321, 1323, 1328, 1330, 1335, 1337, 1339, 1389, 1391,
- 1393, 1395, 1397, 1399, 1401, 1403, 1417, 1422, 1427, 1452,
- 1458, 1460, 1462, 1464, 1466, 1468, 1473, 1477, 1509, 1511,
- 1517, 1523, 1536, 1537, 1538, 1543, 1548, 1552, 1556, 1571,
- 1584, 1589, 1625, 1643, 1644, 1650, 1651, 1656, 1658, 1665,
- 1682, 1699, 1701, 1708, 1713, 1721, 1731, 1743, 1752, 1756,
- 1760, 1764, 1768, 1772, 1775, 1777, 1781, 1785, 1789
+ 0, 197, 197, 199, 204, 205, 211, 223, 227, 238,
+ 244, 249, 257, 265, 267, 272, 280, 282, 288, 289,
+ 291, 317, 328, 339, 345, 354, 364, 366, 368, 374,
+ 379, 380, 384, 403, 402, 436, 438, 443, 444, 457,
+ 462, 463, 467, 469, 471, 478, 568, 610, 652, 765,
+ 772, 779, 789, 798, 807, 816, 827, 843, 842, 866,
+ 878, 878, 976, 976, 1009, 1039, 1045, 1046, 1052, 1053,
+ 1060, 1065, 1077, 1091, 1093, 1101, 1106, 1108, 1116, 1118,
+ 1127, 1128, 1136, 1141, 1141, 1152, 1156, 1164, 1165, 1168,
+ 1170, 1175, 1176, 1185, 1186, 1191, 1196, 1202, 1204, 1206,
+ 1213, 1214, 1220, 1221, 1226, 1228, 1233, 1235, 1243, 1248,
+ 1257, 1264, 1266, 1268, 1284, 1294, 1301, 1303, 1308, 1310,
+ 1312, 1320, 1322, 1327, 1329, 1334, 1336, 1338, 1388, 1390,
+ 1392, 1394, 1396, 1398, 1400, 1402, 1416, 1421, 1426, 1451,
+ 1457, 1459, 1461, 1463, 1465, 1467, 1472, 1476, 1508, 1510,
+ 1516, 1522, 1535, 1536, 1537, 1542, 1547, 1551, 1555, 1570,
+ 1582, 1587, 1623, 1641, 1642, 1648, 1649, 1654, 1656, 1663,
+ 1680, 1697, 1699, 1706, 1711, 1719, 1729, 1741, 1750, 1754,
+ 1758, 1762, 1766, 1770, 1773, 1775, 1779, 1783, 1787
};
#endif
@@ -1842,26 +1841,26 @@ yyreduce:
switch (yyn)
{
case 3:
-#line 201 "awkgram.y" /* yacc.c:1646 */
+#line 200 "awkgram.y" /* yacc.c:1646 */
{
rule = 0;
yyerrok;
}
-#line 1851 "awkgram.c" /* yacc.c:1646 */
+#line 1850 "awkgram.c" /* yacc.c:1646 */
break;
case 5:
-#line 207 "awkgram.y" /* yacc.c:1646 */
+#line 206 "awkgram.y" /* yacc.c:1646 */
{
next_sourcefile();
if (sourcefile == srcfiles)
process_deferred();
}
-#line 1861 "awkgram.c" /* yacc.c:1646 */
+#line 1860 "awkgram.c" /* yacc.c:1646 */
break;
case 6:
-#line 213 "awkgram.y" /* yacc.c:1646 */
+#line 212 "awkgram.y" /* yacc.c:1646 */
{
rule = 0;
/*
@@ -1870,19 +1869,19 @@ yyreduce:
*/
/* yyerrok; */
}
-#line 1874 "awkgram.c" /* yacc.c:1646 */
+#line 1873 "awkgram.c" /* yacc.c:1646 */
break;
case 7:
-#line 225 "awkgram.y" /* yacc.c:1646 */
+#line 224 "awkgram.y" /* yacc.c:1646 */
{
(void) append_rule((yyvsp[-1]), (yyvsp[0]));
}
-#line 1882 "awkgram.c" /* yacc.c:1646 */
+#line 1881 "awkgram.c" /* yacc.c:1646 */
break;
case 8:
-#line 229 "awkgram.y" /* yacc.c:1646 */
+#line 228 "awkgram.y" /* yacc.c:1646 */
{
if (rule != Rule) {
msg(_("%s blocks must have an action part"), ruletab[rule]);
@@ -1893,39 +1892,39 @@ yyreduce:
} else /* pattern rule with non-empty pattern */
(void) append_rule((yyvsp[-1]), NULL);
}
-#line 1897 "awkgram.c" /* yacc.c:1646 */
+#line 1896 "awkgram.c" /* yacc.c:1646 */
break;
case 9:
-#line 240 "awkgram.y" /* yacc.c:1646 */
+#line 239 "awkgram.y" /* yacc.c:1646 */
{
in_function = NULL;
(void) mk_function((yyvsp[-1]), (yyvsp[0]));
yyerrok;
}
-#line 1907 "awkgram.c" /* yacc.c:1646 */
+#line 1906 "awkgram.c" /* yacc.c:1646 */
break;
case 10:
-#line 246 "awkgram.y" /* yacc.c:1646 */
+#line 245 "awkgram.y" /* yacc.c:1646 */
{
want_source = false;
yyerrok;
}
-#line 1916 "awkgram.c" /* yacc.c:1646 */
+#line 1915 "awkgram.c" /* yacc.c:1646 */
break;
case 11:
-#line 251 "awkgram.y" /* yacc.c:1646 */
+#line 250 "awkgram.y" /* yacc.c:1646 */
{
want_source = false;
yyerrok;
}
-#line 1925 "awkgram.c" /* yacc.c:1646 */
+#line 1924 "awkgram.c" /* yacc.c:1646 */
break;
case 12:
-#line 259 "awkgram.y" /* yacc.c:1646 */
+#line 258 "awkgram.y" /* yacc.c:1646 */
{
if (include_source((yyvsp[0])) < 0)
YYABORT;
@@ -1933,23 +1932,23 @@ yyreduce:
bcfree((yyvsp[0]));
(yyval) = NULL;
}
-#line 1937 "awkgram.c" /* yacc.c:1646 */
+#line 1936 "awkgram.c" /* yacc.c:1646 */
break;
case 13:
-#line 267 "awkgram.y" /* yacc.c:1646 */
+#line 266 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = NULL; }
-#line 1943 "awkgram.c" /* yacc.c:1646 */
+#line 1942 "awkgram.c" /* yacc.c:1646 */
break;
case 14:
-#line 269 "awkgram.y" /* yacc.c:1646 */
+#line 268 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = NULL; }
-#line 1949 "awkgram.c" /* yacc.c:1646 */
+#line 1948 "awkgram.c" /* yacc.c:1646 */
break;
case 15:
-#line 274 "awkgram.y" /* yacc.c:1646 */
+#line 273 "awkgram.y" /* yacc.c:1646 */
{
if (load_library((yyvsp[0])) < 0)
YYABORT;
@@ -1957,35 +1956,35 @@ yyreduce:
bcfree((yyvsp[0]));
(yyval) = NULL;
}
-#line 1961 "awkgram.c" /* yacc.c:1646 */
+#line 1960 "awkgram.c" /* yacc.c:1646 */
break;
case 16:
-#line 282 "awkgram.y" /* yacc.c:1646 */
+#line 281 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = NULL; }
-#line 1967 "awkgram.c" /* yacc.c:1646 */
+#line 1966 "awkgram.c" /* yacc.c:1646 */
break;
case 17:
-#line 284 "awkgram.y" /* yacc.c:1646 */
+#line 283 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = NULL; }
-#line 1973 "awkgram.c" /* yacc.c:1646 */
+#line 1972 "awkgram.c" /* yacc.c:1646 */
break;
case 18:
-#line 289 "awkgram.y" /* yacc.c:1646 */
+#line 288 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = NULL; rule = Rule; }
-#line 1979 "awkgram.c" /* yacc.c:1646 */
+#line 1978 "awkgram.c" /* yacc.c:1646 */
break;
case 19:
-#line 291 "awkgram.y" /* yacc.c:1646 */
+#line 290 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = (yyvsp[0]); rule = Rule; }
-#line 1985 "awkgram.c" /* yacc.c:1646 */
+#line 1984 "awkgram.c" /* yacc.c:1646 */
break;
case 20:
-#line 293 "awkgram.y" /* yacc.c:1646 */
+#line 292 "awkgram.y" /* yacc.c:1646 */
{
INSTRUCTION *tp;
@@ -2011,11 +2010,11 @@ yyreduce:
(yyval) = list_append(list_merge((yyvsp[-3]), (yyvsp[0])), tp);
rule = Rule;
}
-#line 2015 "awkgram.c" /* yacc.c:1646 */
+#line 2014 "awkgram.c" /* yacc.c:1646 */
break;
case 21:
-#line 319 "awkgram.y" /* yacc.c:1646 */
+#line 318 "awkgram.y" /* yacc.c:1646 */
{
static int begin_seen = 0;
if (do_lint_old && ++begin_seen == 2)
@@ -2026,11 +2025,11 @@ yyreduce:
(yyvsp[0])->source_file = source;
(yyval) = (yyvsp[0]);
}
-#line 2030 "awkgram.c" /* yacc.c:1646 */
+#line 2029 "awkgram.c" /* yacc.c:1646 */
break;
case 22:
-#line 330 "awkgram.y" /* yacc.c:1646 */
+#line 329 "awkgram.y" /* yacc.c:1646 */
{
static int end_seen = 0;
if (do_lint_old && ++end_seen == 2)
@@ -2041,70 +2040,70 @@ yyreduce:
(yyvsp[0])->source_file = source;
(yyval) = (yyvsp[0]);
}
-#line 2045 "awkgram.c" /* yacc.c:1646 */
+#line 2044 "awkgram.c" /* yacc.c:1646 */
break;
case 23:
-#line 341 "awkgram.y" /* yacc.c:1646 */
+#line 340 "awkgram.y" /* yacc.c:1646 */
{
(yyvsp[0])->in_rule = rule = BEGINFILE;
(yyvsp[0])->source_file = source;
(yyval) = (yyvsp[0]);
}
-#line 2055 "awkgram.c" /* yacc.c:1646 */
+#line 2054 "awkgram.c" /* yacc.c:1646 */
break;
case 24:
-#line 347 "awkgram.y" /* yacc.c:1646 */
+#line 346 "awkgram.y" /* yacc.c:1646 */
{
(yyvsp[0])->in_rule = rule = ENDFILE;
(yyvsp[0])->source_file = source;
(yyval) = (yyvsp[0]);
}
-#line 2065 "awkgram.c" /* yacc.c:1646 */
+#line 2064 "awkgram.c" /* yacc.c:1646 */
break;
case 25:
-#line 356 "awkgram.y" /* yacc.c:1646 */
+#line 355 "awkgram.y" /* yacc.c:1646 */
{
if ((yyvsp[-3]) == NULL)
(yyval) = list_create(instruction(Op_no_op));
else
(yyval) = (yyvsp[-3]);
}
-#line 2076 "awkgram.c" /* yacc.c:1646 */
+#line 2075 "awkgram.c" /* yacc.c:1646 */
break;
case 26:
-#line 366 "awkgram.y" /* yacc.c:1646 */
+#line 365 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = (yyvsp[0]); }
-#line 2082 "awkgram.c" /* yacc.c:1646 */
+#line 2081 "awkgram.c" /* yacc.c:1646 */
break;
case 27:
-#line 368 "awkgram.y" /* yacc.c:1646 */
+#line 367 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = (yyvsp[0]); }
-#line 2088 "awkgram.c" /* yacc.c:1646 */
+#line 2087 "awkgram.c" /* yacc.c:1646 */
break;
case 28:
-#line 370 "awkgram.y" /* yacc.c:1646 */
+#line 369 "awkgram.y" /* yacc.c:1646 */
{
yyerror(_("`%s' is a built-in function, it cannot be redefined"),
tokstart);
YYABORT;
}
-#line 2098 "awkgram.c" /* yacc.c:1646 */
+#line 2097 "awkgram.c" /* yacc.c:1646 */
break;
case 29:
-#line 376 "awkgram.y" /* yacc.c:1646 */
+#line 375 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = (yyvsp[0]); }
-#line 2104 "awkgram.c" /* yacc.c:1646 */
+#line 2103 "awkgram.c" /* yacc.c:1646 */
break;
case 32:
-#line 386 "awkgram.y" /* yacc.c:1646 */
+#line 385 "awkgram.y" /* yacc.c:1646 */
{
(yyvsp[-5])->source_file = source;
if (install_function((yyvsp[-4])->lextok, (yyvsp[-5]), (yyvsp[-2])) < 0)
@@ -2115,17 +2114,17 @@ yyreduce:
/* $4 already free'd in install_function */
(yyval) = (yyvsp[-5]);
}
-#line 2119 "awkgram.c" /* yacc.c:1646 */
+#line 2118 "awkgram.c" /* yacc.c:1646 */
break;
case 33:
-#line 404 "awkgram.y" /* yacc.c:1646 */
+#line 403 "awkgram.y" /* yacc.c:1646 */
{ want_regexp = true; }
-#line 2125 "awkgram.c" /* yacc.c:1646 */
+#line 2124 "awkgram.c" /* yacc.c:1646 */
break;
case 34:
-#line 406 "awkgram.y" /* yacc.c:1646 */
+#line 405 "awkgram.y" /* yacc.c:1646 */
{
NODE *n, *exp;
char *re;
@@ -2154,23 +2153,23 @@ yyreduce:
(yyval)->opcode = Op_match_rec;
(yyval)->memory = n;
}
-#line 2158 "awkgram.c" /* yacc.c:1646 */
+#line 2157 "awkgram.c" /* yacc.c:1646 */
break;
case 35:
-#line 438 "awkgram.y" /* yacc.c:1646 */
+#line 437 "awkgram.y" /* yacc.c:1646 */
{ bcfree((yyvsp[0])); }
-#line 2164 "awkgram.c" /* yacc.c:1646 */
+#line 2163 "awkgram.c" /* yacc.c:1646 */
break;
case 37:
-#line 444 "awkgram.y" /* yacc.c:1646 */
+#line 443 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = NULL; }
-#line 2170 "awkgram.c" /* yacc.c:1646 */
+#line 2169 "awkgram.c" /* yacc.c:1646 */
break;
case 38:
-#line 446 "awkgram.y" /* yacc.c:1646 */
+#line 445 "awkgram.y" /* yacc.c:1646 */
{
if ((yyvsp[0]) == NULL)
(yyval) = (yyvsp[-1]);
@@ -2183,40 +2182,40 @@ yyreduce:
}
yyerrok;
}
-#line 2187 "awkgram.c" /* yacc.c:1646 */
+#line 2186 "awkgram.c" /* yacc.c:1646 */
break;
case 39:
-#line 459 "awkgram.y" /* yacc.c:1646 */
+#line 458 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = NULL; }
-#line 2193 "awkgram.c" /* yacc.c:1646 */
+#line 2192 "awkgram.c" /* yacc.c:1646 */
break;
case 42:
-#line 469 "awkgram.y" /* yacc.c:1646 */
+#line 468 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = NULL; }
-#line 2199 "awkgram.c" /* yacc.c:1646 */
+#line 2198 "awkgram.c" /* yacc.c:1646 */
break;
case 43:
-#line 471 "awkgram.y" /* yacc.c:1646 */
+#line 470 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = (yyvsp[-1]); }
-#line 2205 "awkgram.c" /* yacc.c:1646 */
+#line 2204 "awkgram.c" /* yacc.c:1646 */
break;
case 44:
-#line 473 "awkgram.y" /* yacc.c:1646 */
+#line 472 "awkgram.y" /* yacc.c:1646 */
{
if (do_pretty_print)
(yyval) = list_prepend((yyvsp[0]), instruction(Op_exec_count));
else
(yyval) = (yyvsp[0]);
}
-#line 2216 "awkgram.c" /* yacc.c:1646 */
+#line 2215 "awkgram.c" /* yacc.c:1646 */
break;
case 45:
-#line 480 "awkgram.y" /* yacc.c:1646 */
+#line 479 "awkgram.y" /* yacc.c:1646 */
{
INSTRUCTION *dflt, *curr = NULL, *cexp, *cstmt;
INSTRUCTION *ip, *nextc, *tbreak;
@@ -2306,11 +2305,11 @@ yyreduce:
break_allowed--;
fix_break_continue(ip, tbreak, NULL);
}
-#line 2310 "awkgram.c" /* yacc.c:1646 */
+#line 2309 "awkgram.c" /* yacc.c:1646 */
break;
case 46:
-#line 570 "awkgram.y" /* yacc.c:1646 */
+#line 569 "awkgram.y" /* yacc.c:1646 */
{
/*
* -----------------
@@ -2352,11 +2351,11 @@ yyreduce:
continue_allowed--;
fix_break_continue(ip, tbreak, tcont);
}
-#line 2356 "awkgram.c" /* yacc.c:1646 */
+#line 2355 "awkgram.c" /* yacc.c:1646 */
break;
case 47:
-#line 612 "awkgram.y" /* yacc.c:1646 */
+#line 611 "awkgram.y" /* yacc.c:1646 */
{
/*
* -----------------
@@ -2398,11 +2397,11 @@ yyreduce:
} /* else
$1 and $4 are NULLs */
}
-#line 2402 "awkgram.c" /* yacc.c:1646 */
+#line 2401 "awkgram.c" /* yacc.c:1646 */
break;
case 48:
-#line 654 "awkgram.y" /* yacc.c:1646 */
+#line 653 "awkgram.y" /* yacc.c:1646 */
{
INSTRUCTION *ip;
char *var_name = (yyvsp[-5])->lextok;
@@ -2515,44 +2514,44 @@ regular_loop:
break_allowed--;
continue_allowed--;
}
-#line 2519 "awkgram.c" /* yacc.c:1646 */
+#line 2518 "awkgram.c" /* yacc.c:1646 */
break;
case 49:
-#line 767 "awkgram.y" /* yacc.c:1646 */
+#line 766 "awkgram.y" /* yacc.c:1646 */
{
(yyval) = mk_for_loop((yyvsp[-11]), (yyvsp[-9]), (yyvsp[-6]), (yyvsp[-3]), (yyvsp[0]));
break_allowed--;
continue_allowed--;
}
-#line 2530 "awkgram.c" /* yacc.c:1646 */
+#line 2529 "awkgram.c" /* yacc.c:1646 */
break;
case 50:
-#line 774 "awkgram.y" /* yacc.c:1646 */
+#line 773 "awkgram.y" /* yacc.c:1646 */
{
(yyval) = mk_for_loop((yyvsp[-10]), (yyvsp[-8]), (INSTRUCTION *) NULL, (yyvsp[-3]), (yyvsp[0]));
break_allowed--;
continue_allowed--;
}
-#line 2541 "awkgram.c" /* yacc.c:1646 */
+#line 2540 "awkgram.c" /* yacc.c:1646 */
break;
case 51:
-#line 781 "awkgram.y" /* yacc.c:1646 */
+#line 780 "awkgram.y" /* yacc.c:1646 */
{
if (do_pretty_print)
(yyval) = list_prepend((yyvsp[0]), instruction(Op_exec_count));
else
(yyval) = (yyvsp[0]);
}
-#line 2552 "awkgram.c" /* yacc.c:1646 */
+#line 2551 "awkgram.c" /* yacc.c:1646 */
break;
case 52:
-#line 791 "awkgram.y" /* yacc.c:1646 */
+#line 790 "awkgram.y" /* yacc.c:1646 */
{
if (! break_allowed)
error_ln((yyvsp[-1])->source_line,
@@ -2561,11 +2560,11 @@ regular_loop:
(yyval) = list_create((yyvsp[-1]));
}
-#line 2565 "awkgram.c" /* yacc.c:1646 */
+#line 2564 "awkgram.c" /* yacc.c:1646 */
break;
case 53:
-#line 800 "awkgram.y" /* yacc.c:1646 */
+#line 799 "awkgram.y" /* yacc.c:1646 */
{
if (! continue_allowed)
error_ln((yyvsp[-1])->source_line,
@@ -2574,11 +2573,11 @@ regular_loop:
(yyval) = list_create((yyvsp[-1]));
}
-#line 2578 "awkgram.c" /* yacc.c:1646 */
+#line 2577 "awkgram.c" /* yacc.c:1646 */
break;
case 54:
-#line 809 "awkgram.y" /* yacc.c:1646 */
+#line 808 "awkgram.y" /* yacc.c:1646 */
{
/* if inside function (rule = 0), resolve context at run-time */
if (rule && rule != Rule)
@@ -2587,11 +2586,11 @@ regular_loop:
(yyvsp[-1])->target_jmp = ip_rec;
(yyval) = list_create((yyvsp[-1]));
}
-#line 2591 "awkgram.c" /* yacc.c:1646 */
+#line 2590 "awkgram.c" /* yacc.c:1646 */
break;
case 55:
-#line 818 "awkgram.y" /* yacc.c:1646 */
+#line 817 "awkgram.y" /* yacc.c:1646 */
{
/* if inside function (rule = 0), resolve context at run-time */
if (rule == BEGIN || rule == END || rule == ENDFILE)
@@ -2602,11 +2601,11 @@ regular_loop:
(yyvsp[-1])->target_endfile = ip_endfile;
(yyval) = list_create((yyvsp[-1]));
}
-#line 2606 "awkgram.c" /* yacc.c:1646 */
+#line 2605 "awkgram.c" /* yacc.c:1646 */
break;
case 56:
-#line 829 "awkgram.y" /* yacc.c:1646 */
+#line 828 "awkgram.y" /* yacc.c:1646 */
{
/* Initialize the two possible jump targets, the actual target
* is resolved at run-time.
@@ -2621,20 +2620,20 @@ regular_loop:
} else
(yyval) = list_append((yyvsp[-1]), (yyvsp[-2]));
}
-#line 2625 "awkgram.c" /* yacc.c:1646 */
+#line 2624 "awkgram.c" /* yacc.c:1646 */
break;
case 57:
-#line 844 "awkgram.y" /* yacc.c:1646 */
+#line 843 "awkgram.y" /* yacc.c:1646 */
{
if (! in_function)
yyerror(_("`return' used outside function context"));
}
-#line 2634 "awkgram.c" /* yacc.c:1646 */
+#line 2633 "awkgram.c" /* yacc.c:1646 */
break;
case 58:
-#line 847 "awkgram.y" /* yacc.c:1646 */
+#line 846 "awkgram.y" /* yacc.c:1646 */
{
if ((yyvsp[-1]) == NULL) {
(yyval) = list_create((yyvsp[-3]));
@@ -2655,17 +2654,17 @@ regular_loop:
(yyval) = list_append((yyvsp[-1]), (yyvsp[-3]));
}
}
-#line 2659 "awkgram.c" /* yacc.c:1646 */
+#line 2658 "awkgram.c" /* yacc.c:1646 */
break;
case 60:
-#line 879 "awkgram.y" /* yacc.c:1646 */
+#line 878 "awkgram.y" /* yacc.c:1646 */
{ in_print = true; in_parens = 0; }
-#line 2665 "awkgram.c" /* yacc.c:1646 */
+#line 2664 "awkgram.c" /* yacc.c:1646 */
break;
case 61:
-#line 880 "awkgram.y" /* yacc.c:1646 */
+#line 879 "awkgram.y" /* yacc.c:1646 */
{
/*
* Optimization: plain `print' has no expression list, so $3 is null.
@@ -2762,17 +2761,17 @@ regular_print:
}
}
}
-#line 2766 "awkgram.c" /* yacc.c:1646 */
+#line 2765 "awkgram.c" /* yacc.c:1646 */
break;
case 62:
-#line 977 "awkgram.y" /* yacc.c:1646 */
+#line 976 "awkgram.y" /* yacc.c:1646 */
{ sub_counter = 0; }
-#line 2772 "awkgram.c" /* yacc.c:1646 */
+#line 2771 "awkgram.c" /* yacc.c:1646 */
break;
case 63:
-#line 978 "awkgram.y" /* yacc.c:1646 */
+#line 977 "awkgram.y" /* yacc.c:1646 */
{
char *arr = (yyvsp[-2])->lextok;
@@ -2805,11 +2804,11 @@ regular_print:
(yyval) = list_append(list_append((yyvsp[0]), (yyvsp[-2])), (yyvsp[-3]));
}
}
-#line 2809 "awkgram.c" /* yacc.c:1646 */
+#line 2808 "awkgram.c" /* yacc.c:1646 */
break;
case 64:
-#line 1015 "awkgram.y" /* yacc.c:1646 */
+#line 1014 "awkgram.y" /* yacc.c:1646 */
{
static bool warned = false;
char *arr = (yyvsp[-1])->lextok;
@@ -2835,52 +2834,52 @@ regular_print:
fatal(_("`delete' is not allowed with FUNCTAB"));
}
}
-#line 2839 "awkgram.c" /* yacc.c:1646 */
+#line 2838 "awkgram.c" /* yacc.c:1646 */
break;
case 65:
-#line 1041 "awkgram.y" /* yacc.c:1646 */
+#line 1040 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = optimize_assignment((yyvsp[0])); }
-#line 2845 "awkgram.c" /* yacc.c:1646 */
+#line 2844 "awkgram.c" /* yacc.c:1646 */
break;
case 66:
-#line 1046 "awkgram.y" /* yacc.c:1646 */
+#line 1045 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = NULL; }
-#line 2851 "awkgram.c" /* yacc.c:1646 */
+#line 2850 "awkgram.c" /* yacc.c:1646 */
break;
case 67:
-#line 1048 "awkgram.y" /* yacc.c:1646 */
+#line 1047 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = (yyvsp[0]); }
-#line 2857 "awkgram.c" /* yacc.c:1646 */
+#line 2856 "awkgram.c" /* yacc.c:1646 */
break;
case 68:
-#line 1053 "awkgram.y" /* yacc.c:1646 */
+#line 1052 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = NULL; }
-#line 2863 "awkgram.c" /* yacc.c:1646 */
+#line 2862 "awkgram.c" /* yacc.c:1646 */
break;
case 69:
-#line 1055 "awkgram.y" /* yacc.c:1646 */
+#line 1054 "awkgram.y" /* yacc.c:1646 */
{
if ((yyvsp[-1]) == NULL)
(yyval) = list_create((yyvsp[0]));
else
(yyval) = list_prepend((yyvsp[-1]), (yyvsp[0]));
}
-#line 2874 "awkgram.c" /* yacc.c:1646 */
+#line 2873 "awkgram.c" /* yacc.c:1646 */
break;
case 70:
-#line 1062 "awkgram.y" /* yacc.c:1646 */
+#line 1061 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = NULL; }
-#line 2880 "awkgram.c" /* yacc.c:1646 */
+#line 2879 "awkgram.c" /* yacc.c:1646 */
break;
case 71:
-#line 1067 "awkgram.y" /* yacc.c:1646 */
+#line 1066 "awkgram.y" /* yacc.c:1646 */
{
INSTRUCTION *casestmt = (yyvsp[0]);
if ((yyvsp[0]) == NULL)
@@ -2892,11 +2891,11 @@ regular_print:
bcfree((yyvsp[-2]));
(yyval) = (yyvsp[-4]);
}
-#line 2896 "awkgram.c" /* yacc.c:1646 */
+#line 2895 "awkgram.c" /* yacc.c:1646 */
break;
case 72:
-#line 1079 "awkgram.y" /* yacc.c:1646 */
+#line 1078 "awkgram.y" /* yacc.c:1646 */
{
INSTRUCTION *casestmt = (yyvsp[0]);
if ((yyvsp[0]) == NULL)
@@ -2907,89 +2906,89 @@ regular_print:
(yyvsp[-3])->case_stmt = casestmt;
(yyval) = (yyvsp[-3]);
}
-#line 2911 "awkgram.c" /* yacc.c:1646 */
+#line 2910 "awkgram.c" /* yacc.c:1646 */
break;
case 73:
-#line 1093 "awkgram.y" /* yacc.c:1646 */
+#line 1092 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = (yyvsp[0]); }
-#line 2917 "awkgram.c" /* yacc.c:1646 */
+#line 2916 "awkgram.c" /* yacc.c:1646 */
break;
case 74:
-#line 1095 "awkgram.y" /* yacc.c:1646 */
+#line 1094 "awkgram.y" /* yacc.c:1646 */
{
NODE *n = (yyvsp[0])->memory;
(void) force_number(n);
- negate_num(n);
+ numbr_hndlr->gawk_negate_number(n);
bcfree((yyvsp[-1]));
(yyval) = (yyvsp[0]);
}
-#line 2929 "awkgram.c" /* yacc.c:1646 */
+#line 2928 "awkgram.c" /* yacc.c:1646 */
break;
case 75:
-#line 1103 "awkgram.y" /* yacc.c:1646 */
+#line 1102 "awkgram.y" /* yacc.c:1646 */
{
bcfree((yyvsp[-1]));
(yyval) = (yyvsp[0]);
}
-#line 2938 "awkgram.c" /* yacc.c:1646 */
+#line 2937 "awkgram.c" /* yacc.c:1646 */
break;
case 76:
-#line 1108 "awkgram.y" /* yacc.c:1646 */
+#line 1107 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = (yyvsp[0]); }
-#line 2944 "awkgram.c" /* yacc.c:1646 */
+#line 2943 "awkgram.c" /* yacc.c:1646 */
break;
case 77:
-#line 1110 "awkgram.y" /* yacc.c:1646 */
+#line 1109 "awkgram.y" /* yacc.c:1646 */
{
(yyvsp[0])->opcode = Op_push_re;
(yyval) = (yyvsp[0]);
}
-#line 2953 "awkgram.c" /* yacc.c:1646 */
+#line 2952 "awkgram.c" /* yacc.c:1646 */
break;
case 78:
-#line 1118 "awkgram.y" /* yacc.c:1646 */
+#line 1117 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = (yyvsp[0]); }
-#line 2959 "awkgram.c" /* yacc.c:1646 */
+#line 2958 "awkgram.c" /* yacc.c:1646 */
break;
case 79:
-#line 1120 "awkgram.y" /* yacc.c:1646 */
+#line 1119 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = (yyvsp[0]); }
-#line 2965 "awkgram.c" /* yacc.c:1646 */
+#line 2964 "awkgram.c" /* yacc.c:1646 */
break;
case 81:
-#line 1130 "awkgram.y" /* yacc.c:1646 */
+#line 1129 "awkgram.y" /* yacc.c:1646 */
{
(yyval) = (yyvsp[-1]);
}
-#line 2973 "awkgram.c" /* yacc.c:1646 */
+#line 2972 "awkgram.c" /* yacc.c:1646 */
break;
case 82:
-#line 1137 "awkgram.y" /* yacc.c:1646 */
+#line 1136 "awkgram.y" /* yacc.c:1646 */
{
in_print = false;
in_parens = 0;
(yyval) = NULL;
}
-#line 2983 "awkgram.c" /* yacc.c:1646 */
+#line 2982 "awkgram.c" /* yacc.c:1646 */
break;
case 83:
-#line 1142 "awkgram.y" /* yacc.c:1646 */
+#line 1141 "awkgram.y" /* yacc.c:1646 */
{ in_print = false; in_parens = 0; }
-#line 2989 "awkgram.c" /* yacc.c:1646 */
+#line 2988 "awkgram.c" /* yacc.c:1646 */
break;
case 84:
-#line 1143 "awkgram.y" /* yacc.c:1646 */
+#line 1142 "awkgram.y" /* yacc.c:1646 */
{
if ((yyvsp[-2])->redir_type == redirect_twoway
&& (yyvsp[0])->lasti->opcode == Op_K_getline_redir
@@ -2997,136 +2996,136 @@ regular_print:
yyerror(_("multistage two-way pipelines don't work"));
(yyval) = list_prepend((yyvsp[0]), (yyvsp[-2]));
}
-#line 3001 "awkgram.c" /* yacc.c:1646 */
+#line 3000 "awkgram.c" /* yacc.c:1646 */
break;
case 85:
-#line 1154 "awkgram.y" /* yacc.c:1646 */
+#line 1153 "awkgram.y" /* yacc.c:1646 */
{
(yyval) = mk_condition((yyvsp[-3]), (yyvsp[-5]), (yyvsp[0]), NULL, NULL);
}
-#line 3009 "awkgram.c" /* yacc.c:1646 */
+#line 3008 "awkgram.c" /* yacc.c:1646 */
break;
case 86:
-#line 1159 "awkgram.y" /* yacc.c:1646 */
+#line 1158 "awkgram.y" /* yacc.c:1646 */
{
(yyval) = mk_condition((yyvsp[-6]), (yyvsp[-8]), (yyvsp[-3]), (yyvsp[-2]), (yyvsp[0]));
}
-#line 3017 "awkgram.c" /* yacc.c:1646 */
+#line 3016 "awkgram.c" /* yacc.c:1646 */
break;
case 91:
-#line 1176 "awkgram.y" /* yacc.c:1646 */
+#line 1175 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = NULL; }
-#line 3023 "awkgram.c" /* yacc.c:1646 */
+#line 3022 "awkgram.c" /* yacc.c:1646 */
break;
case 92:
-#line 1178 "awkgram.y" /* yacc.c:1646 */
+#line 1177 "awkgram.y" /* yacc.c:1646 */
{
bcfree((yyvsp[-1]));
(yyval) = (yyvsp[0]);
}
-#line 3032 "awkgram.c" /* yacc.c:1646 */
+#line 3031 "awkgram.c" /* yacc.c:1646 */
break;
case 93:
-#line 1186 "awkgram.y" /* yacc.c:1646 */
+#line 1185 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = NULL; }
-#line 3038 "awkgram.c" /* yacc.c:1646 */
+#line 3037 "awkgram.c" /* yacc.c:1646 */
break;
case 94:
-#line 1188 "awkgram.y" /* yacc.c:1646 */
+#line 1187 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = (yyvsp[0]) ; }
-#line 3044 "awkgram.c" /* yacc.c:1646 */
+#line 3043 "awkgram.c" /* yacc.c:1646 */
break;
case 95:
-#line 1193 "awkgram.y" /* yacc.c:1646 */
+#line 1192 "awkgram.y" /* yacc.c:1646 */
{
(yyvsp[0])->param_count = 0;
(yyval) = list_create((yyvsp[0]));
}
-#line 3053 "awkgram.c" /* yacc.c:1646 */
+#line 3052 "awkgram.c" /* yacc.c:1646 */
break;
case 96:
-#line 1198 "awkgram.y" /* yacc.c:1646 */
+#line 1197 "awkgram.y" /* yacc.c:1646 */
{
(yyvsp[0])->param_count = (yyvsp[-2])->lasti->param_count + 1;
(yyval) = list_append((yyvsp[-2]), (yyvsp[0]));
yyerrok;
}
-#line 3063 "awkgram.c" /* yacc.c:1646 */
+#line 3062 "awkgram.c" /* yacc.c:1646 */
break;
case 97:
-#line 1204 "awkgram.y" /* yacc.c:1646 */
+#line 1203 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = NULL; }
-#line 3069 "awkgram.c" /* yacc.c:1646 */
+#line 3068 "awkgram.c" /* yacc.c:1646 */
break;
case 98:
-#line 1206 "awkgram.y" /* yacc.c:1646 */
+#line 1205 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = (yyvsp[-1]); }
-#line 3075 "awkgram.c" /* yacc.c:1646 */
+#line 3074 "awkgram.c" /* yacc.c:1646 */
break;
case 99:
-#line 1208 "awkgram.y" /* yacc.c:1646 */
+#line 1207 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = (yyvsp[-2]); }
-#line 3081 "awkgram.c" /* yacc.c:1646 */
+#line 3080 "awkgram.c" /* yacc.c:1646 */
break;
case 100:
-#line 1214 "awkgram.y" /* yacc.c:1646 */
+#line 1213 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = NULL; }
-#line 3087 "awkgram.c" /* yacc.c:1646 */
+#line 3086 "awkgram.c" /* yacc.c:1646 */
break;
case 101:
-#line 1216 "awkgram.y" /* yacc.c:1646 */
+#line 1215 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = (yyvsp[0]); }
-#line 3093 "awkgram.c" /* yacc.c:1646 */
+#line 3092 "awkgram.c" /* yacc.c:1646 */
break;
case 102:
-#line 1221 "awkgram.y" /* yacc.c:1646 */
+#line 1220 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = NULL; }
-#line 3099 "awkgram.c" /* yacc.c:1646 */
+#line 3098 "awkgram.c" /* yacc.c:1646 */
break;
case 103:
-#line 1223 "awkgram.y" /* yacc.c:1646 */
+#line 1222 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = (yyvsp[0]); }
-#line 3105 "awkgram.c" /* yacc.c:1646 */
+#line 3104 "awkgram.c" /* yacc.c:1646 */
break;
case 104:
-#line 1228 "awkgram.y" /* yacc.c:1646 */
+#line 1227 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = mk_expression_list(NULL, (yyvsp[0])); }
-#line 3111 "awkgram.c" /* yacc.c:1646 */
+#line 3110 "awkgram.c" /* yacc.c:1646 */
break;
case 105:
-#line 1230 "awkgram.y" /* yacc.c:1646 */
+#line 1229 "awkgram.y" /* yacc.c:1646 */
{
(yyval) = mk_expression_list((yyvsp[-2]), (yyvsp[0]));
yyerrok;
}
-#line 3120 "awkgram.c" /* yacc.c:1646 */
+#line 3119 "awkgram.c" /* yacc.c:1646 */
break;
case 106:
-#line 1235 "awkgram.y" /* yacc.c:1646 */
+#line 1234 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = NULL; }
-#line 3126 "awkgram.c" /* yacc.c:1646 */
+#line 3125 "awkgram.c" /* yacc.c:1646 */
break;
case 107:
-#line 1237 "awkgram.y" /* yacc.c:1646 */
+#line 1236 "awkgram.y" /* yacc.c:1646 */
{
/*
* Returning the expression list instead of NULL lets
@@ -3134,52 +3133,52 @@ regular_print:
*/
(yyval) = (yyvsp[-1]);
}
-#line 3138 "awkgram.c" /* yacc.c:1646 */
+#line 3137 "awkgram.c" /* yacc.c:1646 */
break;
case 108:
-#line 1245 "awkgram.y" /* yacc.c:1646 */
+#line 1244 "awkgram.y" /* yacc.c:1646 */
{
/* Ditto */
(yyval) = mk_expression_list((yyvsp[-2]), (yyvsp[0]));
}
-#line 3147 "awkgram.c" /* yacc.c:1646 */
+#line 3146 "awkgram.c" /* yacc.c:1646 */
break;
case 109:
-#line 1250 "awkgram.y" /* yacc.c:1646 */
+#line 1249 "awkgram.y" /* yacc.c:1646 */
{
/* Ditto */
(yyval) = (yyvsp[-2]);
}
-#line 3156 "awkgram.c" /* yacc.c:1646 */
+#line 3155 "awkgram.c" /* yacc.c:1646 */
break;
case 110:
-#line 1259 "awkgram.y" /* yacc.c:1646 */
+#line 1258 "awkgram.y" /* yacc.c:1646 */
{
if (do_lint && (yyvsp[0])->lasti->opcode == Op_match_rec)
lintwarn_ln((yyvsp[-1])->source_line,
_("regular expression on right of assignment"));
(yyval) = mk_assignment((yyvsp[-2]), (yyvsp[0]), (yyvsp[-1]));
}
-#line 3167 "awkgram.c" /* yacc.c:1646 */
+#line 3166 "awkgram.c" /* yacc.c:1646 */
break;
case 111:
-#line 1266 "awkgram.y" /* yacc.c:1646 */
+#line 1265 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = mk_boolean((yyvsp[-2]), (yyvsp[0]), (yyvsp[-1])); }
-#line 3173 "awkgram.c" /* yacc.c:1646 */
+#line 3172 "awkgram.c" /* yacc.c:1646 */
break;
case 112:
-#line 1268 "awkgram.y" /* yacc.c:1646 */
+#line 1267 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = mk_boolean((yyvsp[-2]), (yyvsp[0]), (yyvsp[-1])); }
-#line 3179 "awkgram.c" /* yacc.c:1646 */
+#line 3178 "awkgram.c" /* yacc.c:1646 */
break;
case 113:
-#line 1270 "awkgram.y" /* yacc.c:1646 */
+#line 1269 "awkgram.y" /* yacc.c:1646 */
{
if ((yyvsp[-2])->lasti->opcode == Op_match_rec)
warning_ln((yyvsp[-1])->source_line,
@@ -3195,11 +3194,11 @@ regular_print:
(yyval) = list_append(list_merge((yyvsp[-2]), (yyvsp[0])), (yyvsp[-1]));
}
}
-#line 3199 "awkgram.c" /* yacc.c:1646 */
+#line 3198 "awkgram.c" /* yacc.c:1646 */
break;
case 114:
-#line 1286 "awkgram.y" /* yacc.c:1646 */
+#line 1285 "awkgram.y" /* yacc.c:1646 */
{
if (do_lint_old)
warning_ln((yyvsp[-1])->source_line,
@@ -3209,91 +3208,91 @@ regular_print:
(yyvsp[-1])->expr_count = 1;
(yyval) = list_append(list_merge((yyvsp[-2]), (yyvsp[0])), (yyvsp[-1]));
}
-#line 3213 "awkgram.c" /* yacc.c:1646 */
+#line 3212 "awkgram.c" /* yacc.c:1646 */
break;
case 115:
-#line 1296 "awkgram.y" /* yacc.c:1646 */
+#line 1295 "awkgram.y" /* yacc.c:1646 */
{
if (do_lint && (yyvsp[0])->lasti->opcode == Op_match_rec)
lintwarn_ln((yyvsp[-1])->source_line,
_("regular expression on right of comparison"));
(yyval) = list_append(list_merge((yyvsp[-2]), (yyvsp[0])), (yyvsp[-1]));
}
-#line 3224 "awkgram.c" /* yacc.c:1646 */
+#line 3223 "awkgram.c" /* yacc.c:1646 */
break;
case 116:
-#line 1303 "awkgram.y" /* yacc.c:1646 */
+#line 1302 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = mk_condition((yyvsp[-4]), (yyvsp[-3]), (yyvsp[-2]), (yyvsp[-1]), (yyvsp[0])); }
-#line 3230 "awkgram.c" /* yacc.c:1646 */
+#line 3229 "awkgram.c" /* yacc.c:1646 */
break;
case 117:
-#line 1305 "awkgram.y" /* yacc.c:1646 */
+#line 1304 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = (yyvsp[0]); }
-#line 3236 "awkgram.c" /* yacc.c:1646 */
+#line 3235 "awkgram.c" /* yacc.c:1646 */
break;
case 118:
-#line 1310 "awkgram.y" /* yacc.c:1646 */
+#line 1309 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = (yyvsp[0]); }
-#line 3242 "awkgram.c" /* yacc.c:1646 */
+#line 3241 "awkgram.c" /* yacc.c:1646 */
break;
case 119:
-#line 1312 "awkgram.y" /* yacc.c:1646 */
+#line 1311 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = (yyvsp[0]); }
-#line 3248 "awkgram.c" /* yacc.c:1646 */
+#line 3247 "awkgram.c" /* yacc.c:1646 */
break;
case 120:
-#line 1314 "awkgram.y" /* yacc.c:1646 */
+#line 1313 "awkgram.y" /* yacc.c:1646 */
{
(yyvsp[0])->opcode = Op_assign_quotient;
(yyval) = (yyvsp[0]);
}
-#line 3257 "awkgram.c" /* yacc.c:1646 */
+#line 3256 "awkgram.c" /* yacc.c:1646 */
break;
case 121:
-#line 1322 "awkgram.y" /* yacc.c:1646 */
+#line 1321 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = (yyvsp[0]); }
-#line 3263 "awkgram.c" /* yacc.c:1646 */
+#line 3262 "awkgram.c" /* yacc.c:1646 */
break;
case 122:
-#line 1324 "awkgram.y" /* yacc.c:1646 */
+#line 1323 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = (yyvsp[0]); }
-#line 3269 "awkgram.c" /* yacc.c:1646 */
+#line 3268 "awkgram.c" /* yacc.c:1646 */
break;
case 123:
-#line 1329 "awkgram.y" /* yacc.c:1646 */
+#line 1328 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = (yyvsp[0]); }
-#line 3275 "awkgram.c" /* yacc.c:1646 */
+#line 3274 "awkgram.c" /* yacc.c:1646 */
break;
case 124:
-#line 1331 "awkgram.y" /* yacc.c:1646 */
+#line 1330 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = (yyvsp[0]); }
-#line 3281 "awkgram.c" /* yacc.c:1646 */
+#line 3280 "awkgram.c" /* yacc.c:1646 */
break;
case 125:
-#line 1336 "awkgram.y" /* yacc.c:1646 */
+#line 1335 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = (yyvsp[0]); }
-#line 3287 "awkgram.c" /* yacc.c:1646 */
+#line 3286 "awkgram.c" /* yacc.c:1646 */
break;
case 126:
-#line 1338 "awkgram.y" /* yacc.c:1646 */
+#line 1337 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = (yyvsp[0]); }
-#line 3293 "awkgram.c" /* yacc.c:1646 */
+#line 3292 "awkgram.c" /* yacc.c:1646 */
break;
case 127:
-#line 1340 "awkgram.y" /* yacc.c:1646 */
+#line 1339 "awkgram.y" /* yacc.c:1646 */
{
int count = 2;
bool is_simple_var = false;
@@ -3340,47 +3339,47 @@ regular_print:
max_args = count;
}
}
-#line 3344 "awkgram.c" /* yacc.c:1646 */
+#line 3343 "awkgram.c" /* yacc.c:1646 */
break;
case 129:
-#line 1392 "awkgram.y" /* yacc.c:1646 */
- { (yyval) = mk_binary((yyvsp[-2]), (yyvsp[0]), (yyvsp[-1])); }
-#line 3350 "awkgram.c" /* yacc.c:1646 */
+#line 1391 "awkgram.y" /* yacc.c:1646 */
+ { (yyval) = list_append(list_merge((yyvsp[-2]), (yyvsp[0])), (yyvsp[-1])); }
+#line 3349 "awkgram.c" /* yacc.c:1646 */
break;
case 130:
-#line 1394 "awkgram.y" /* yacc.c:1646 */
- { (yyval) = mk_binary((yyvsp[-2]), (yyvsp[0]), (yyvsp[-1])); }
-#line 3356 "awkgram.c" /* yacc.c:1646 */
+#line 1393 "awkgram.y" /* yacc.c:1646 */
+ { (yyval) = list_append(list_merge((yyvsp[-2]), (yyvsp[0])), (yyvsp[-1])); }
+#line 3355 "awkgram.c" /* yacc.c:1646 */
break;
case 131:
-#line 1396 "awkgram.y" /* yacc.c:1646 */
- { (yyval) = mk_binary((yyvsp[-2]), (yyvsp[0]), (yyvsp[-1])); }
-#line 3362 "awkgram.c" /* yacc.c:1646 */
+#line 1395 "awkgram.y" /* yacc.c:1646 */
+ { (yyval) = list_append(list_merge((yyvsp[-2]), (yyvsp[0])), (yyvsp[-1])); }
+#line 3361 "awkgram.c" /* yacc.c:1646 */
break;
case 132:
-#line 1398 "awkgram.y" /* yacc.c:1646 */
- { (yyval) = mk_binary((yyvsp[-2]), (yyvsp[0]), (yyvsp[-1])); }
-#line 3368 "awkgram.c" /* yacc.c:1646 */
+#line 1397 "awkgram.y" /* yacc.c:1646 */
+ { (yyval) = list_append(list_merge((yyvsp[-2]), (yyvsp[0])), (yyvsp[-1])); }
+#line 3367 "awkgram.c" /* yacc.c:1646 */
break;
case 133:
-#line 1400 "awkgram.y" /* yacc.c:1646 */
- { (yyval) = mk_binary((yyvsp[-2]), (yyvsp[0]), (yyvsp[-1])); }
-#line 3374 "awkgram.c" /* yacc.c:1646 */
+#line 1399 "awkgram.y" /* yacc.c:1646 */
+ { (yyval) = list_append(list_merge((yyvsp[-2]), (yyvsp[0])), (yyvsp[-1])); }
+#line 3373 "awkgram.c" /* yacc.c:1646 */
break;
case 134:
-#line 1402 "awkgram.y" /* yacc.c:1646 */
- { (yyval) = mk_binary((yyvsp[-2]), (yyvsp[0]), (yyvsp[-1])); }
-#line 3380 "awkgram.c" /* yacc.c:1646 */
+#line 1401 "awkgram.y" /* yacc.c:1646 */
+ { (yyval) = list_append(list_merge((yyvsp[-2]), (yyvsp[0])), (yyvsp[-1])); }
+#line 3379 "awkgram.c" /* yacc.c:1646 */
break;
case 135:
-#line 1404 "awkgram.y" /* yacc.c:1646 */
+#line 1403 "awkgram.y" /* yacc.c:1646 */
{
/*
* In BEGINFILE/ENDFILE, allow `getline [var] < file'
@@ -3394,29 +3393,29 @@ regular_print:
_("non-redirected `getline' undefined inside END action"));
(yyval) = mk_getline((yyvsp[-2]), (yyvsp[-1]), (yyvsp[0]), redirect_input);
}
-#line 3398 "awkgram.c" /* yacc.c:1646 */
+#line 3397 "awkgram.c" /* yacc.c:1646 */
break;
case 136:
-#line 1418 "awkgram.y" /* yacc.c:1646 */
+#line 1417 "awkgram.y" /* yacc.c:1646 */
{
(yyvsp[0])->opcode = Op_postincrement;
(yyval) = mk_assignment((yyvsp[-1]), NULL, (yyvsp[0]));
}
-#line 3407 "awkgram.c" /* yacc.c:1646 */
+#line 3406 "awkgram.c" /* yacc.c:1646 */
break;
case 137:
-#line 1423 "awkgram.y" /* yacc.c:1646 */
+#line 1422 "awkgram.y" /* yacc.c:1646 */
{
(yyvsp[0])->opcode = Op_postdecrement;
(yyval) = mk_assignment((yyvsp[-1]), NULL, (yyvsp[0]));
}
-#line 3416 "awkgram.c" /* yacc.c:1646 */
+#line 3415 "awkgram.c" /* yacc.c:1646 */
break;
case 138:
-#line 1428 "awkgram.y" /* yacc.c:1646 */
+#line 1427 "awkgram.y" /* yacc.c:1646 */
{
if (do_lint_old) {
warning_ln((yyvsp[-1])->source_line,
@@ -3436,64 +3435,64 @@ regular_print:
(yyval) = list_append(list_merge(t, (yyvsp[0])), (yyvsp[-1]));
}
}
-#line 3440 "awkgram.c" /* yacc.c:1646 */
+#line 3439 "awkgram.c" /* yacc.c:1646 */
break;
case 139:
-#line 1453 "awkgram.y" /* yacc.c:1646 */
+#line 1452 "awkgram.y" /* yacc.c:1646 */
{
(yyval) = mk_getline((yyvsp[-1]), (yyvsp[0]), (yyvsp[-3]), (yyvsp[-2])->redir_type);
bcfree((yyvsp[-2]));
}
-#line 3449 "awkgram.c" /* yacc.c:1646 */
+#line 3448 "awkgram.c" /* yacc.c:1646 */
break;
case 140:
-#line 1459 "awkgram.y" /* yacc.c:1646 */
- { (yyval) = mk_binary((yyvsp[-2]), (yyvsp[0]), (yyvsp[-1])); }
-#line 3455 "awkgram.c" /* yacc.c:1646 */
+#line 1458 "awkgram.y" /* yacc.c:1646 */
+ { (yyval) = list_append(list_merge((yyvsp[-2]), (yyvsp[0])), (yyvsp[-1])); }
+#line 3454 "awkgram.c" /* yacc.c:1646 */
break;
case 141:
-#line 1461 "awkgram.y" /* yacc.c:1646 */
- { (yyval) = mk_binary((yyvsp[-2]), (yyvsp[0]), (yyvsp[-1])); }
-#line 3461 "awkgram.c" /* yacc.c:1646 */
+#line 1460 "awkgram.y" /* yacc.c:1646 */
+ { (yyval) = list_append(list_merge((yyvsp[-2]), (yyvsp[0])), (yyvsp[-1])); }
+#line 3460 "awkgram.c" /* yacc.c:1646 */
break;
case 142:
-#line 1463 "awkgram.y" /* yacc.c:1646 */
- { (yyval) = mk_binary((yyvsp[-2]), (yyvsp[0]), (yyvsp[-1])); }
-#line 3467 "awkgram.c" /* yacc.c:1646 */
+#line 1462 "awkgram.y" /* yacc.c:1646 */
+ { (yyval) = list_append(list_merge((yyvsp[-2]), (yyvsp[0])), (yyvsp[-1])); }
+#line 3466 "awkgram.c" /* yacc.c:1646 */
break;
case 143:
-#line 1465 "awkgram.y" /* yacc.c:1646 */
- { (yyval) = mk_binary((yyvsp[-2]), (yyvsp[0]), (yyvsp[-1])); }
-#line 3473 "awkgram.c" /* yacc.c:1646 */
+#line 1464 "awkgram.y" /* yacc.c:1646 */
+ { (yyval) = list_append(list_merge((yyvsp[-2]), (yyvsp[0])), (yyvsp[-1])); }
+#line 3472 "awkgram.c" /* yacc.c:1646 */
break;
case 144:
-#line 1467 "awkgram.y" /* yacc.c:1646 */
- { (yyval) = mk_binary((yyvsp[-2]), (yyvsp[0]), (yyvsp[-1])); }
-#line 3479 "awkgram.c" /* yacc.c:1646 */
+#line 1466 "awkgram.y" /* yacc.c:1646 */
+ { (yyval) = list_append(list_merge((yyvsp[-2]), (yyvsp[0])), (yyvsp[-1])); }
+#line 3478 "awkgram.c" /* yacc.c:1646 */
break;
case 145:
-#line 1469 "awkgram.y" /* yacc.c:1646 */
- { (yyval) = mk_binary((yyvsp[-2]), (yyvsp[0]), (yyvsp[-1])); }
-#line 3485 "awkgram.c" /* yacc.c:1646 */
+#line 1468 "awkgram.y" /* yacc.c:1646 */
+ { (yyval) = list_append(list_merge((yyvsp[-2]), (yyvsp[0])), (yyvsp[-1])); }
+#line 3484 "awkgram.c" /* yacc.c:1646 */
break;
case 146:
-#line 1474 "awkgram.y" /* yacc.c:1646 */
+#line 1473 "awkgram.y" /* yacc.c:1646 */
{
(yyval) = list_create((yyvsp[0]));
}
-#line 3493 "awkgram.c" /* yacc.c:1646 */
+#line 3492 "awkgram.c" /* yacc.c:1646 */
break;
case 147:
-#line 1478 "awkgram.y" /* yacc.c:1646 */
+#line 1477 "awkgram.y" /* yacc.c:1646 */
{
if ((yyvsp[0])->opcode == Op_match_rec) {
(yyvsp[0])->opcode = Op_nomatch;
@@ -3525,37 +3524,37 @@ regular_print:
}
}
}
-#line 3529 "awkgram.c" /* yacc.c:1646 */
+#line 3528 "awkgram.c" /* yacc.c:1646 */
break;
case 148:
-#line 1510 "awkgram.y" /* yacc.c:1646 */
+#line 1509 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = (yyvsp[-1]); }
-#line 3535 "awkgram.c" /* yacc.c:1646 */
+#line 3534 "awkgram.c" /* yacc.c:1646 */
break;
case 149:
-#line 1512 "awkgram.y" /* yacc.c:1646 */
+#line 1511 "awkgram.y" /* yacc.c:1646 */
{
(yyval) = snode((yyvsp[-1]), (yyvsp[-3]));
if ((yyval) == NULL)
YYABORT;
}
-#line 3545 "awkgram.c" /* yacc.c:1646 */
+#line 3544 "awkgram.c" /* yacc.c:1646 */
break;
case 150:
-#line 1518 "awkgram.y" /* yacc.c:1646 */
+#line 1517 "awkgram.y" /* yacc.c:1646 */
{
(yyval) = snode((yyvsp[-1]), (yyvsp[-3]));
if ((yyval) == NULL)
YYABORT;
}
-#line 3555 "awkgram.c" /* yacc.c:1646 */
+#line 3554 "awkgram.c" /* yacc.c:1646 */
break;
case 151:
-#line 1524 "awkgram.y" /* yacc.c:1646 */
+#line 1523 "awkgram.y" /* yacc.c:1646 */
{
static bool warned = false;
@@ -3568,52 +3567,52 @@ regular_print:
if ((yyval) == NULL)
YYABORT;
}
-#line 3572 "awkgram.c" /* yacc.c:1646 */
+#line 3571 "awkgram.c" /* yacc.c:1646 */
break;
case 154:
-#line 1539 "awkgram.y" /* yacc.c:1646 */
+#line 1538 "awkgram.y" /* yacc.c:1646 */
{
(yyvsp[-1])->opcode = Op_preincrement;
(yyval) = mk_assignment((yyvsp[0]), NULL, (yyvsp[-1]));
}
-#line 3581 "awkgram.c" /* yacc.c:1646 */
+#line 3580 "awkgram.c" /* yacc.c:1646 */
break;
case 155:
-#line 1544 "awkgram.y" /* yacc.c:1646 */
+#line 1543 "awkgram.y" /* yacc.c:1646 */
{
(yyvsp[-1])->opcode = Op_predecrement;
(yyval) = mk_assignment((yyvsp[0]), NULL, (yyvsp[-1]));
}
-#line 3590 "awkgram.c" /* yacc.c:1646 */
+#line 3589 "awkgram.c" /* yacc.c:1646 */
break;
case 156:
-#line 1549 "awkgram.y" /* yacc.c:1646 */
+#line 1548 "awkgram.y" /* yacc.c:1646 */
{
(yyval) = list_create((yyvsp[0]));
}
-#line 3598 "awkgram.c" /* yacc.c:1646 */
+#line 3597 "awkgram.c" /* yacc.c:1646 */
break;
case 157:
-#line 1553 "awkgram.y" /* yacc.c:1646 */
+#line 1552 "awkgram.y" /* yacc.c:1646 */
{
(yyval) = list_create((yyvsp[0]));
}
-#line 3606 "awkgram.c" /* yacc.c:1646 */
+#line 3605 "awkgram.c" /* yacc.c:1646 */
break;
case 158:
-#line 1557 "awkgram.y" /* yacc.c:1646 */
+#line 1556 "awkgram.y" /* yacc.c:1646 */
{
if ((yyvsp[0])->lasti->opcode == Op_push_i
&& ((yyvsp[0])->lasti->memory->flags & (STRCUR|STRING)) == 0
) {
NODE *n = (yyvsp[0])->lasti->memory;
(void) force_number(n);
- negate_num(n);
+ numbr_hndlr->gawk_negate_number(n);
(yyval) = (yyvsp[0]);
bcfree((yyvsp[-1]));
} else {
@@ -3621,34 +3620,33 @@ regular_print:
(yyval) = list_append((yyvsp[0]), (yyvsp[-1]));
}
}
-#line 3625 "awkgram.c" /* yacc.c:1646 */
+#line 3624 "awkgram.c" /* yacc.c:1646 */
break;
case 159:
-#line 1572 "awkgram.y" /* yacc.c:1646 */
+#line 1571 "awkgram.y" /* yacc.c:1646 */
{
/*
* was: $$ = $2
* POSIX semantics: force a conversion to numeric type
*/
- (yyvsp[-1])->opcode = Op_plus_i;
- (yyvsp[-1])->memory = make_number(0.0);
+ (yyvsp[-1])->opcode = Op_unary_plus;
(yyval) = list_append((yyvsp[0]), (yyvsp[-1]));
}
-#line 3639 "awkgram.c" /* yacc.c:1646 */
+#line 3637 "awkgram.c" /* yacc.c:1646 */
break;
case 160:
-#line 1585 "awkgram.y" /* yacc.c:1646 */
+#line 1583 "awkgram.y" /* yacc.c:1646 */
{
func_use((yyvsp[0])->lasti->func_name, FUNC_USE);
(yyval) = (yyvsp[0]);
}
-#line 3648 "awkgram.c" /* yacc.c:1646 */
+#line 3646 "awkgram.c" /* yacc.c:1646 */
break;
case 161:
-#line 1590 "awkgram.y" /* yacc.c:1646 */
+#line 1588 "awkgram.y" /* yacc.c:1646 */
{
/* indirect function call */
INSTRUCTION *f, *t;
@@ -3681,11 +3679,11 @@ regular_print:
(yyval) = list_prepend((yyvsp[0]), t);
}
-#line 3685 "awkgram.c" /* yacc.c:1646 */
+#line 3683 "awkgram.c" /* yacc.c:1646 */
break;
case 162:
-#line 1626 "awkgram.y" /* yacc.c:1646 */
+#line 1624 "awkgram.y" /* yacc.c:1646 */
{
param_sanity((yyvsp[-1]));
(yyvsp[-3])->opcode = Op_func_call;
@@ -3699,49 +3697,49 @@ regular_print:
(yyval) = list_append(t, (yyvsp[-3]));
}
}
-#line 3703 "awkgram.c" /* yacc.c:1646 */
+#line 3701 "awkgram.c" /* yacc.c:1646 */
break;
case 163:
-#line 1643 "awkgram.y" /* yacc.c:1646 */
+#line 1641 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = NULL; }
-#line 3709 "awkgram.c" /* yacc.c:1646 */
+#line 3707 "awkgram.c" /* yacc.c:1646 */
break;
case 164:
-#line 1645 "awkgram.y" /* yacc.c:1646 */
+#line 1643 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = (yyvsp[0]); }
-#line 3715 "awkgram.c" /* yacc.c:1646 */
+#line 3713 "awkgram.c" /* yacc.c:1646 */
break;
case 165:
-#line 1650 "awkgram.y" /* yacc.c:1646 */
+#line 1648 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = NULL; }
-#line 3721 "awkgram.c" /* yacc.c:1646 */
+#line 3719 "awkgram.c" /* yacc.c:1646 */
break;
case 166:
-#line 1652 "awkgram.y" /* yacc.c:1646 */
+#line 1650 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = (yyvsp[-1]); }
-#line 3727 "awkgram.c" /* yacc.c:1646 */
+#line 3725 "awkgram.c" /* yacc.c:1646 */
break;
case 167:
-#line 1657 "awkgram.y" /* yacc.c:1646 */
+#line 1655 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = (yyvsp[0]); }
-#line 3733 "awkgram.c" /* yacc.c:1646 */
+#line 3731 "awkgram.c" /* yacc.c:1646 */
break;
case 168:
-#line 1659 "awkgram.y" /* yacc.c:1646 */
+#line 1657 "awkgram.y" /* yacc.c:1646 */
{
(yyval) = list_merge((yyvsp[-1]), (yyvsp[0]));
}
-#line 3741 "awkgram.c" /* yacc.c:1646 */
+#line 3739 "awkgram.c" /* yacc.c:1646 */
break;
case 169:
-#line 1666 "awkgram.y" /* yacc.c:1646 */
+#line 1664 "awkgram.y" /* yacc.c:1646 */
{
INSTRUCTION *ip = (yyvsp[0])->lasti;
int count = ip->sub_count; /* # of SUBSEP-seperated expressions */
@@ -3755,11 +3753,11 @@ regular_print:
sub_counter++; /* count # of dimensions */
(yyval) = (yyvsp[0]);
}
-#line 3759 "awkgram.c" /* yacc.c:1646 */
+#line 3757 "awkgram.c" /* yacc.c:1646 */
break;
case 170:
-#line 1683 "awkgram.y" /* yacc.c:1646 */
+#line 1681 "awkgram.y" /* yacc.c:1646 */
{
INSTRUCTION *t = (yyvsp[-1]);
if ((yyvsp[-1]) == NULL) {
@@ -3773,31 +3771,31 @@ regular_print:
(yyvsp[0])->sub_count = count_expressions(&t, false);
(yyval) = list_append(t, (yyvsp[0]));
}
-#line 3777 "awkgram.c" /* yacc.c:1646 */
+#line 3775 "awkgram.c" /* yacc.c:1646 */
break;
case 171:
-#line 1700 "awkgram.y" /* yacc.c:1646 */
+#line 1698 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = (yyvsp[0]); }
-#line 3783 "awkgram.c" /* yacc.c:1646 */
+#line 3781 "awkgram.c" /* yacc.c:1646 */
break;
case 172:
-#line 1702 "awkgram.y" /* yacc.c:1646 */
+#line 1700 "awkgram.y" /* yacc.c:1646 */
{
(yyval) = list_merge((yyvsp[-1]), (yyvsp[0]));
}
-#line 3791 "awkgram.c" /* yacc.c:1646 */
+#line 3789 "awkgram.c" /* yacc.c:1646 */
break;
case 173:
-#line 1709 "awkgram.y" /* yacc.c:1646 */
+#line 1707 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = (yyvsp[-1]); }
-#line 3797 "awkgram.c" /* yacc.c:1646 */
+#line 3795 "awkgram.c" /* yacc.c:1646 */
break;
case 174:
-#line 1714 "awkgram.y" /* yacc.c:1646 */
+#line 1712 "awkgram.y" /* yacc.c:1646 */
{
char *var_name = (yyvsp[0])->lextok;
@@ -3805,22 +3803,22 @@ regular_print:
(yyvsp[0])->memory = variable((yyvsp[0])->source_line, var_name, Node_var_new);
(yyval) = list_create((yyvsp[0]));
}
-#line 3809 "awkgram.c" /* yacc.c:1646 */
+#line 3807 "awkgram.c" /* yacc.c:1646 */
break;
case 175:
-#line 1722 "awkgram.y" /* yacc.c:1646 */
+#line 1720 "awkgram.y" /* yacc.c:1646 */
{
char *arr = (yyvsp[-1])->lextok;
(yyvsp[-1])->memory = variable((yyvsp[-1])->source_line, arr, Node_var_new);
(yyvsp[-1])->opcode = Op_push_array;
(yyval) = list_prepend((yyvsp[0]), (yyvsp[-1]));
}
-#line 3820 "awkgram.c" /* yacc.c:1646 */
+#line 3818 "awkgram.c" /* yacc.c:1646 */
break;
case 176:
-#line 1732 "awkgram.y" /* yacc.c:1646 */
+#line 1730 "awkgram.y" /* yacc.c:1646 */
{
INSTRUCTION *ip = (yyvsp[0])->nexti;
if (ip->opcode == Op_push
@@ -3832,73 +3830,73 @@ regular_print:
} else
(yyval) = (yyvsp[0]);
}
-#line 3836 "awkgram.c" /* yacc.c:1646 */
+#line 3834 "awkgram.c" /* yacc.c:1646 */
break;
case 177:
-#line 1744 "awkgram.y" /* yacc.c:1646 */
+#line 1742 "awkgram.y" /* yacc.c:1646 */
{
(yyval) = list_append((yyvsp[-1]), (yyvsp[-2]));
if ((yyvsp[0]) != NULL)
mk_assignment((yyvsp[-1]), NULL, (yyvsp[0]));
}
-#line 3846 "awkgram.c" /* yacc.c:1646 */
+#line 3844 "awkgram.c" /* yacc.c:1646 */
break;
case 178:
-#line 1753 "awkgram.y" /* yacc.c:1646 */
+#line 1751 "awkgram.y" /* yacc.c:1646 */
{
(yyvsp[0])->opcode = Op_postincrement;
}
-#line 3854 "awkgram.c" /* yacc.c:1646 */
+#line 3852 "awkgram.c" /* yacc.c:1646 */
break;
case 179:
-#line 1757 "awkgram.y" /* yacc.c:1646 */
+#line 1755 "awkgram.y" /* yacc.c:1646 */
{
(yyvsp[0])->opcode = Op_postdecrement;
}
-#line 3862 "awkgram.c" /* yacc.c:1646 */
+#line 3860 "awkgram.c" /* yacc.c:1646 */
break;
case 180:
-#line 1760 "awkgram.y" /* yacc.c:1646 */
+#line 1758 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = NULL; }
-#line 3868 "awkgram.c" /* yacc.c:1646 */
+#line 3866 "awkgram.c" /* yacc.c:1646 */
break;
case 182:
-#line 1768 "awkgram.y" /* yacc.c:1646 */
+#line 1766 "awkgram.y" /* yacc.c:1646 */
{ yyerrok; }
-#line 3874 "awkgram.c" /* yacc.c:1646 */
+#line 3872 "awkgram.c" /* yacc.c:1646 */
break;
case 183:
-#line 1772 "awkgram.y" /* yacc.c:1646 */
+#line 1770 "awkgram.y" /* yacc.c:1646 */
{ yyerrok; }
-#line 3880 "awkgram.c" /* yacc.c:1646 */
+#line 3878 "awkgram.c" /* yacc.c:1646 */
break;
case 186:
-#line 1781 "awkgram.y" /* yacc.c:1646 */
+#line 1779 "awkgram.y" /* yacc.c:1646 */
{ yyerrok; }
-#line 3886 "awkgram.c" /* yacc.c:1646 */
+#line 3884 "awkgram.c" /* yacc.c:1646 */
break;
case 187:
-#line 1785 "awkgram.y" /* yacc.c:1646 */
+#line 1783 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = (yyvsp[0]); yyerrok; }
-#line 3892 "awkgram.c" /* yacc.c:1646 */
+#line 3890 "awkgram.c" /* yacc.c:1646 */
break;
case 188:
-#line 1789 "awkgram.y" /* yacc.c:1646 */
+#line 1787 "awkgram.y" /* yacc.c:1646 */
{ yyerrok; }
-#line 3898 "awkgram.c" /* yacc.c:1646 */
+#line 3896 "awkgram.c" /* yacc.c:1646 */
break;
-#line 3902 "awkgram.c" /* yacc.c:1646 */
+#line 3900 "awkgram.c" /* yacc.c:1646 */
default: break;
}
/* User semantic actions sometimes alter yychar, and that requires
@@ -4126,7 +4124,7 @@ yyreturn:
#endif
return yyresult;
}
-#line 1791 "awkgram.y" /* yacc.c:1906 */
+#line 1789 "awkgram.y" /* yacc.c:1906 */
struct token {
@@ -4143,9 +4141,9 @@ struct token {
# define BREAK 0x0800 /* break allowed inside */
# define CONTINUE 0x1000 /* continue allowed inside */
# define DEBUG_USE 0x2000 /* for use by developers */
+# define ARG3_IS_ARR 0x4000 /* hack for div/do_mpfp_div */
NODE *(*ptr)(int); /* function that implements this keyword */
- NODE *(*ptr2)(int); /* alternate arbitrary-precision function */
};
#if 'a' == 0x81 /* it's EBCDIC */
@@ -4169,91 +4167,86 @@ tokcompare(const void *l, const void *r)
* Function pointers come from declarations in awk.h.
*/
-#ifdef HAVE_MPFR
-#define MPF(F) do_mpfr_##F
-#else
-#define MPF(F) 0
-#endif
-static const struct token tokentab[] = {
-{"BEGIN", Op_rule, LEX_BEGIN, 0, 0, 0},
-{"BEGINFILE", Op_rule, LEX_BEGINFILE, GAWKX, 0, 0},
-{"END", Op_rule, LEX_END, 0, 0, 0},
-{"ENDFILE", Op_rule, LEX_ENDFILE, GAWKX, 0, 0},
+static struct token tokentab[] = {
+{"BEGIN", Op_rule, LEX_BEGIN, 0, 0 },
+{"BEGINFILE", Op_rule, LEX_BEGINFILE, GAWKX, 0 },
+{"END", Op_rule, LEX_END, 0, 0 },
+{"ENDFILE", Op_rule, LEX_ENDFILE, GAWKX, 0 },
#ifdef ARRAYDEBUG
-{"adump", Op_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2)|DEBUG_USE, do_adump, 0},
+{"adump", Op_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2)|DEBUG_USE, do_adump },
#endif
-{"and", Op_builtin, LEX_BUILTIN, GAWKX, do_and, MPF(and)},
-{"asort", Op_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2)|A(3), do_asort, 0},
-{"asorti", Op_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2)|A(3), do_asorti, 0},
-{"atan2", Op_builtin, LEX_BUILTIN, NOT_OLD|A(2), do_atan2, MPF(atan2)},
-{"bindtextdomain", Op_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2), do_bindtextdomain, 0},
-{"break", Op_K_break, LEX_BREAK, 0, 0, 0},
-{"case", Op_K_case, LEX_CASE, GAWKX, 0, 0},
-{"close", Op_builtin, LEX_BUILTIN, NOT_OLD|A(1)|A(2), do_close, 0},
-{"compl", Op_builtin, LEX_BUILTIN, GAWKX|A(1), do_compl, MPF(compl)},
-{"continue", Op_K_continue, LEX_CONTINUE, 0, 0, 0},
-{"cos", Op_builtin, LEX_BUILTIN, NOT_OLD|A(1), do_cos, MPF(cos)},
-{"dcgettext", Op_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2)|A(3), do_dcgettext, 0},
-{"dcngettext", Op_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2)|A(3)|A(4)|A(5), do_dcngettext, 0},
-{"default", Op_K_default, LEX_DEFAULT, GAWKX, 0, 0},
-{"delete", Op_K_delete, LEX_DELETE, NOT_OLD, 0, 0},
-{"div", Op_builtin, LEX_BUILTIN, GAWKX|A(3), do_div, MPF(div)},
-{"do", Op_K_do, LEX_DO, NOT_OLD|BREAK|CONTINUE, 0, 0},
-{"else", Op_K_else, LEX_ELSE, 0, 0, 0},
-{"eval", Op_symbol, LEX_EVAL, 0, 0, 0},
-{"exit", Op_K_exit, LEX_EXIT, 0, 0, 0},
-{"exp", Op_builtin, LEX_BUILTIN, A(1), do_exp, MPF(exp)},
+{"and", Op_builtin, LEX_BUILTIN, GAWKX, 0 },
+{"asort", Op_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2)|A(3), do_asort },
+{"asorti", Op_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2)|A(3), do_asorti },
+{"atan2", Op_builtin, LEX_BUILTIN, NOT_OLD|A(2), 0 },
+{"bindtextdomain", Op_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2), do_bindtextdomain },
+{"break", Op_K_break, LEX_BREAK, 0, 0 },
+{"case", Op_K_case, LEX_CASE, GAWKX, 0 },
+{"close", Op_builtin, LEX_BUILTIN, NOT_OLD|A(1)|A(2), do_close },
+{"compl", Op_builtin, LEX_BUILTIN, GAWKX|A(1), 0 },
+{"continue", Op_K_continue, LEX_CONTINUE, 0, 0 },
+{"cos", Op_builtin, LEX_BUILTIN, NOT_OLD|A(1), 0 },
+{"dcgettext", Op_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2)|A(3), do_dcgettext },
+{"dcngettext", Op_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2)|A(3)|A(4)|A(5), do_dcngettext },
+{"default", Op_K_default, LEX_DEFAULT, GAWKX, 0 },
+{"delete", Op_K_delete, LEX_DELETE, NOT_OLD, 0 },
+{"div", Op_builtin, LEX_BUILTIN, GAWKX|A(3)|ARG3_IS_ARR, do_div },
+{"do", Op_K_do, LEX_DO, NOT_OLD|BREAK|CONTINUE, 0 },
+{"else", Op_K_else, LEX_ELSE, 0, 0 },
+{"eval", Op_symbol, LEX_EVAL, 0, 0 },
+{"exit", Op_K_exit, LEX_EXIT, 0, 0 },
+{"exp", Op_builtin, LEX_BUILTIN, A(1), 0 },
#ifdef DYNAMIC
-{"extension", Op_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2)|A(3), do_ext, 0},
+{"extension", Op_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2)|A(3), do_ext },
#endif
-{"fflush", Op_builtin, LEX_BUILTIN, A(0)|A(1), do_fflush, 0},
-{"for", Op_K_for, LEX_FOR, BREAK|CONTINUE, 0, 0},
-{"func", Op_func, LEX_FUNCTION, NOT_POSIX|NOT_OLD, 0, 0},
-{"function",Op_func, LEX_FUNCTION, NOT_OLD, 0, 0},
-{"gensub", Op_sub_builtin, LEX_BUILTIN, GAWKX|A(3)|A(4), 0, 0},
-{"getline", Op_K_getline_redir, LEX_GETLINE, NOT_OLD, 0, 0},
-{"gsub", Op_sub_builtin, LEX_BUILTIN, NOT_OLD|A(2)|A(3), 0, 0},
-{"if", Op_K_if, LEX_IF, 0, 0, 0},
-{"in", Op_symbol, LEX_IN, 0, 0, 0},
-{"include", Op_symbol, LEX_INCLUDE, GAWKX, 0, 0},
-{"index", Op_builtin, LEX_BUILTIN, A(2), do_index, 0},
-{"int", Op_builtin, LEX_BUILTIN, A(1), do_int, MPF(int)},
-{"isarray", Op_builtin, LEX_BUILTIN, GAWKX|A(1), do_isarray, 0},
-{"length", Op_builtin, LEX_LENGTH, A(0)|A(1), do_length, 0},
-{"load", Op_symbol, LEX_LOAD, GAWKX, 0, 0},
-{"log", Op_builtin, LEX_BUILTIN, A(1), do_log, MPF(log)},
-{"lshift", Op_builtin, LEX_BUILTIN, GAWKX|A(2), do_lshift, MPF(lshift)},
-{"match", Op_builtin, LEX_BUILTIN, NOT_OLD|A(2)|A(3), do_match, 0},
-{"mktime", Op_builtin, LEX_BUILTIN, GAWKX|A(1), do_mktime, 0},
-{"next", Op_K_next, LEX_NEXT, 0, 0, 0},
-{"nextfile", Op_K_nextfile, LEX_NEXTFILE, 0, 0, 0},
-{"or", Op_builtin, LEX_BUILTIN, GAWKX, do_or, MPF(or)},
-{"patsplit", Op_builtin, LEX_BUILTIN, GAWKX|A(2)|A(3)|A(4), do_patsplit, 0},
-{"print", Op_K_print, LEX_PRINT, 0, 0, 0},
-{"printf", Op_K_printf, LEX_PRINTF, 0, 0, 0},
-{"rand", Op_builtin, LEX_BUILTIN, NOT_OLD|A(0), do_rand, MPF(rand)},
-{"return", Op_K_return, LEX_RETURN, NOT_OLD, 0, 0},
-{"rshift", Op_builtin, LEX_BUILTIN, GAWKX|A(2), do_rshift, MPF(rshift)},
-{"sin", Op_builtin, LEX_BUILTIN, NOT_OLD|A(1), do_sin, MPF(sin)},
-{"split", Op_builtin, LEX_BUILTIN, A(2)|A(3)|A(4), do_split, 0},
-{"sprintf", Op_builtin, LEX_BUILTIN, 0, do_sprintf, 0},
-{"sqrt", Op_builtin, LEX_BUILTIN, A(1), do_sqrt, MPF(sqrt)},
-{"srand", Op_builtin, LEX_BUILTIN, NOT_OLD|A(0)|A(1), do_srand, MPF(srand)},
+{"fflush", Op_builtin, LEX_BUILTIN, A(0)|A(1), do_fflush },
+{"for", Op_K_for, LEX_FOR, BREAK|CONTINUE, 0 },
+{"func", Op_func, LEX_FUNCTION, NOT_POSIX|NOT_OLD, 0 },
+{"function",Op_func, LEX_FUNCTION, NOT_OLD, 0 },
+{"gensub", Op_sub_builtin, LEX_BUILTIN, GAWKX|A(3)|A(4), 0 },
+{"getline", Op_K_getline_redir, LEX_GETLINE, NOT_OLD, 0 },
+{"gsub", Op_sub_builtin, LEX_BUILTIN, NOT_OLD|A(2)|A(3), 0 },
+{"if", Op_K_if, LEX_IF, 0, 0 },
+{"in", Op_symbol, LEX_IN, 0, 0 },
+{"include", Op_symbol, LEX_INCLUDE, GAWKX, 0 },
+{"index", Op_builtin, LEX_BUILTIN, A(2), do_index },
+{"int", Op_builtin, LEX_BUILTIN, A(1), 0 },
+{"isarray", Op_builtin, LEX_BUILTIN, GAWKX|A(1), do_isarray },
+{"length", Op_builtin, LEX_LENGTH, A(0)|A(1), do_length },
+{"load", Op_symbol, LEX_LOAD, GAWKX, 0 },
+{"log", Op_builtin, LEX_BUILTIN, A(1), 0 },
+{"lshift", Op_builtin, LEX_BUILTIN, GAWKX|A(2), 0 },
+{"match", Op_builtin, LEX_BUILTIN, NOT_OLD|A(2)|A(3), do_match },
+{"mktime", Op_builtin, LEX_BUILTIN, GAWKX|A(1), do_mktime },
+{"next", Op_K_next, LEX_NEXT, 0, 0 },
+{"nextfile", Op_K_nextfile, LEX_NEXTFILE, 0, 0 },
+{"or", Op_builtin, LEX_BUILTIN, GAWKX, 0 },
+{"patsplit", Op_builtin, LEX_BUILTIN, GAWKX|A(2)|A(3)|A(4), do_patsplit },
+{"print", Op_K_print, LEX_PRINT, 0, 0 },
+{"printf", Op_K_printf, LEX_PRINTF, 0, 0 },
+{"rand", Op_builtin, LEX_BUILTIN, NOT_OLD|A(0), 0 },
+{"return", Op_K_return, LEX_RETURN, NOT_OLD, 0 },
+{"rshift", Op_builtin, LEX_BUILTIN, GAWKX|A(2), 0 },
+{"sin", Op_builtin, LEX_BUILTIN, NOT_OLD|A(1), 0 },
+{"split", Op_builtin, LEX_BUILTIN, A(2)|A(3)|A(4), do_split },
+{"sprintf", Op_builtin, LEX_BUILTIN, 0, do_sprintf },
+{"sqrt", Op_builtin, LEX_BUILTIN, A(1), 0 },
+{"srand", Op_builtin, LEX_BUILTIN, NOT_OLD|A(0)|A(1), 0 },
#if defined(GAWKDEBUG) || defined(ARRAYDEBUG) /* || ... */
-{"stopme", Op_builtin, LEX_BUILTIN, GAWKX|A(0)|DEBUG_USE, stopme, 0},
+{"stopme", Op_builtin, LEX_BUILTIN, GAWKX|A(0)|DEBUG_USE, stopme },
#endif
-{"strftime", Op_builtin, LEX_BUILTIN, GAWKX|A(0)|A(1)|A(2)|A(3), do_strftime, 0},
-{"strtonum", Op_builtin, LEX_BUILTIN, GAWKX|A(1), do_strtonum, MPF(strtonum)},
-{"sub", Op_sub_builtin, LEX_BUILTIN, NOT_OLD|A(2)|A(3), 0, 0},
-{"substr", Op_builtin, LEX_BUILTIN, A(2)|A(3), do_substr, 0},
-{"switch", Op_K_switch, LEX_SWITCH, GAWKX|BREAK, 0, 0},
-{"system", Op_builtin, LEX_BUILTIN, NOT_OLD|A(1), do_system, 0},
-{"systime", Op_builtin, LEX_BUILTIN, GAWKX|A(0), do_systime, 0},
-{"tolower", Op_builtin, LEX_BUILTIN, NOT_OLD|A(1), do_tolower, 0},
-{"toupper", Op_builtin, LEX_BUILTIN, NOT_OLD|A(1), do_toupper, 0},
-{"while", Op_K_while, LEX_WHILE, BREAK|CONTINUE, 0, 0},
-{"xor", Op_builtin, LEX_BUILTIN, GAWKX, do_xor, MPF(xor)},
+{"strftime", Op_builtin, LEX_BUILTIN, GAWKX|A(0)|A(1)|A(2)|A(3), do_strftime },
+{"strtonum", Op_builtin, LEX_BUILTIN, GAWKX|A(1), 0 },
+{"sub", Op_sub_builtin, LEX_BUILTIN, NOT_OLD|A(2)|A(3), 0 },
+{"substr", Op_builtin, LEX_BUILTIN, A(2)|A(3), do_substr },
+{"switch", Op_K_switch, LEX_SWITCH, GAWKX|BREAK, 0 },
+{"system", Op_builtin, LEX_BUILTIN, NOT_OLD|A(1), do_system },
+{"systime", Op_builtin, LEX_BUILTIN, GAWKX|A(0), do_systime },
+{"tolower", Op_builtin, LEX_BUILTIN, NOT_OLD|A(1), do_tolower },
+{"toupper", Op_builtin, LEX_BUILTIN, NOT_OLD|A(1), do_toupper },
+{"while", Op_K_while, LEX_WHILE, BREAK|CONTINUE, 0 },
+{"xor", Op_builtin, LEX_BUILTIN, GAWKX, 0 },
};
#if MBS_SUPPORT
@@ -4283,53 +4276,12 @@ getfname(NODE *(*fptr)(int))
j = sizeof(tokentab) / sizeof(tokentab[0]);
/* linear search, no other way to do it */
for (i = 0; i < j; i++)
- if (tokentab[i].ptr == fptr || tokentab[i].ptr2 == fptr)
+ if (tokentab[i].ptr == fptr)
return tokentab[i].operator;
return NULL;
}
-/* negate_num --- negate a number in NODE */
-
-void
-negate_num(NODE *n)
-{
-#ifdef HAVE_MPFR
- int tval = 0;
-#endif
-
- if (! is_mpg_number(n)) {
- n->numbr = -n->numbr;
- return;
- }
-
-#ifdef HAVE_MPFR
- if (is_mpg_integer(n)) {
- if (! iszero(n)) {
- mpz_neg(n->mpg_i, n->mpg_i);
- return;
- }
-
- /*
- * 0 --> -0 conversion. Requires turning the MPG integer
- * into an MPFR float.
- */
-
- mpz_clear(n->mpg_i); /* release the integer storage */
-
- /* Convert and fall through. */
- tval = mpfr_set_d(n->mpg_numbr, 0.0, ROUND_MODE);
- IEEE_FMT(n->mpg_numbr, tval);
- n->flags &= ~MPZN;
- n->flags |= MPFN;
- }
-
- /* mpfr float case */
- tval = mpfr_neg(n->mpg_numbr, n->mpg_numbr, ROUND_MODE);
- IEEE_FMT(n->mpg_numbr, tval);
-#endif
-}
-
/* print_included_from --- print `Included from ..' file names and locations */
static void
@@ -4498,6 +4450,18 @@ yyerror(const char *m, ...)
efree(buf);
}
+void
+init_parser(const bltin_t *numbr_bltins)
+{
+ int i, tokentab_idx;
+
+ for (i = 0; numbr_bltins[i].name != NULL; i++) {
+ tokentab_idx = check_special(numbr_bltins[i].name);
+ tokentab[tokentab_idx].ptr = numbr_bltins[i].ptr;
+ }
+}
+
+
/* mk_program --- create a single list of instructions */
static INSTRUCTION *
@@ -5336,7 +5300,6 @@ yylex(void)
char *tokkey;
bool inhex = false;
bool intlstr = false;
- AWKNUM d;
#define GET_INSTRUCTION(op) bcalloc(op, 1, sourceline)
@@ -5914,32 +5877,7 @@ retry:
}
}
-#ifdef HAVE_MPFR
- if (do_mpfr) {
- NODE *r;
-
- if (! seen_point && ! seen_e) {
- r = mpg_integer();
- mpg_strtoui(r->mpg_i, tokstart, strlen(tokstart), NULL, base);
- errno = 0;
- } else {
- int tval;
- r = mpg_float();
- tval = mpfr_strtofr(r->mpg_numbr, tokstart, NULL, base, ROUND_MODE);
- errno = 0;
- IEEE_FMT(r->mpg_numbr, tval);
- }
- yylval->memory = r;
- return lasttok = YNUMBER;
- }
-#endif
- if (base != 10)
- d = nondec2awknum(tokstart, strlen(tokstart));
- else
- d = atof(tokstart);
- yylval->memory = make_number(d);
- if (d <= INT32_MAX && d >= INT32_MIN && d == (int32_t) d)
- yylval->memory->flags |= NUMINT;
+ yylval->memory = str2node(tokstart, NULL, base, ! (seen_point || seen_e));
return lasttok = YNUMBER;
case '&':
@@ -6243,13 +6181,7 @@ snode(INSTRUCTION *subn, INSTRUCTION *r)
}
}
-#ifdef HAVE_MPFR
- /* N.B.: If necessary, add special processing for alternate builtin, below */
- if (do_mpfr && tokentab[idx].ptr2)
- r->builtin = tokentab[idx].ptr2;
- else
-#endif
- r->builtin = tokentab[idx].ptr;
+ r->builtin = tokentab[idx].ptr;
/* special case processing for a few builtins */
@@ -6273,11 +6205,7 @@ snode(INSTRUCTION *subn, INSTRUCTION *r)
arg = subn->nexti;
if (arg->nexti == arg->lasti && arg->nexti->opcode == Op_push)
arg->nexti->opcode = Op_push_arg; /* argument may be array */
- } else if (r->builtin == do_div
-#ifdef HAVE_MPFR
- || r->builtin == MPF(div)
-#endif
- ) {
+ } else if ((tokentab[idx].flags & ARG3_IS_ARR) != 0) {
arg = subn->nexti->lasti->nexti->lasti->nexti; /* 3rd arg list */
ip = arg->lasti;
if (ip->opcode == Op_push)
@@ -6471,26 +6399,12 @@ valinfo(NODE *n, Func_print print_func, FILE *fp)
pp_string_fp(print_func, fp, n->stptr, n->stlen, '"', false);
print_func(fp, "\n");
} else if (n->flags & NUMBER) {
-#ifdef HAVE_MPFR
- if (is_mpg_float(n))
- print_func(fp, "%s\n", mpg_fmt("%.17R*g", ROUND_MODE, n->mpg_numbr));
- else if (is_mpg_integer(n))
- print_func(fp, "%s\n", mpg_fmt("%Zd", n->mpg_i));
- else
-#endif
- print_func(fp, "%.17g\n", n->numbr);
+ print_func(fp, "%s\n", fmt_number("%.17g", n));
} 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) {
-#ifdef HAVE_MPFR
- if (is_mpg_float(n))
- print_func(fp, "%s\n", mpg_fmt("%.17R*g", ROUND_MODE, n->mpg_numbr));
- else if (is_mpg_integer(n))
- print_func(fp, "%s\n", mpg_fmt("%Zd", n->mpg_i));
- else
-#endif
- print_func(fp, "%.17g\n", n->numbr);
+ print_func(fp, "%s\n", fmt_number("%.17g", n));
} else
print_func(fp, "?? flags %s\n", flags2str(n->flags));
}
@@ -6958,20 +6872,15 @@ isnoeffect(OPCODE type)
{
switch (type) {
case Op_times:
- case Op_times_i:
case Op_quotient:
- case Op_quotient_i:
case Op_mod:
- case Op_mod_i:
case Op_plus:
- case Op_plus_i:
case Op_minus:
- case Op_minus_i:
case Op_subscript:
case Op_concat:
case Op_exp:
- case Op_exp_i:
case Op_unary_minus:
+ case Op_unary_plus:
case Op_field_spec:
case Op_and_final:
case Op_or_final:
@@ -7074,113 +6983,6 @@ dumpintlstr2(const char *str1, size_t len1, const char *str2, size_t len2)
fflush(stdout);
}
-/* mk_binary --- instructions for binary operators */
-
-static INSTRUCTION *
-mk_binary(INSTRUCTION *s1, INSTRUCTION *s2, INSTRUCTION *op)
-{
- INSTRUCTION *ip1,*ip2;
- AWKNUM res;
-
- ip2 = s2->nexti;
- if (s2->lasti == ip2 && ip2->opcode == Op_push_i) {
- /* do any numeric constant folding */
- ip1 = s1->nexti;
- if (do_optimize
- && ip1 == s1->lasti && ip1->opcode == Op_push_i
- && (ip1->memory->flags & (MPFN|MPZN|STRCUR|STRING)) == 0
- && (ip2->memory->flags & (MPFN|MPZN|STRCUR|STRING)) == 0
- ) {
- NODE *n1 = ip1->memory, *n2 = ip2->memory;
- res = force_number(n1)->numbr;
- (void) force_number(n2);
- switch (op->opcode) {
- case Op_times:
- res *= n2->numbr;
- break;
- case Op_quotient:
- if (n2->numbr == 0.0) {
- /* don't fatalize, allow parsing rest of the input */
- error_ln(op->source_line, _("division by zero attempted"));
- goto regular;
- }
-
- res /= n2->numbr;
- break;
- case Op_mod:
- if (n2->numbr == 0.0) {
- /* don't fatalize, allow parsing rest of the input */
- error_ln(op->source_line, _("division by zero attempted in `%%'"));
- goto regular;
- }
-#ifdef HAVE_FMOD
- res = fmod(res, n2->numbr);
-#else /* ! HAVE_FMOD */
- (void) modf(res / n2->numbr, &res);
- res = n1->numbr - res * n2->numbr;
-#endif /* ! HAVE_FMOD */
- break;
- case Op_plus:
- res += n2->numbr;
- break;
- case Op_minus:
- res -= n2->numbr;
- break;
- case Op_exp:
- res = calc_exp(res, n2->numbr);
- break;
- default:
- goto regular;
- }
-
- op->opcode = Op_push_i;
- op->memory = make_number(res);
- unref(n1);
- unref(n2);
- bcfree(ip1);
- bcfree(ip2);
- bcfree(s1);
- bcfree(s2);
- return list_create(op);
- } else {
- /* do basic arithmetic optimisation */
- /* convert (Op_push_i Node_val) + (Op_plus) to (Op_plus_i Node_val) */
- switch (op->opcode) {
- case Op_times:
- op->opcode = Op_times_i;
- break;
- case Op_quotient:
- op->opcode = Op_quotient_i;
- break;
- case Op_mod:
- op->opcode = Op_mod_i;
- break;
- case Op_plus:
- op->opcode = Op_plus_i;
- break;
- case Op_minus:
- op->opcode = Op_minus_i;
- break;
- case Op_exp:
- op->opcode = Op_exp_i;
- break;
- default:
- goto regular;
- }
-
- op->memory = ip2->memory;
- bcfree(ip2);
- bcfree(s2); /* Op_list */
- return list_append(s1, op);
- }
- }
-
-regular:
- /* append lists s1, s2 and add `op' bytecode */
- (void) list_merge(s1, s2);
- return list_append(s1, op);
-}
-
/* mk_boolean --- instructions for boolean and, or */
static INSTRUCTION *
@@ -7578,8 +7380,8 @@ optimize_assignment(INSTRUCTION *exp)
i3->opcode = Op_store_sub;
i3->memory = i2->memory;
i3->expr_count = 1; /* sub_count shadows memory,
- * so use expr_count instead.
- */
+ * so use expr_count instead
+ */
i3->nexti = NULL;
i2->opcode = Op_no_op;
bcfree(i1); /* Op_assign */
@@ -8062,10 +7864,6 @@ lookup_builtin(const char *name)
if (mid == -1 || tokentab[mid].class != LEX_BUILTIN)
return NULL;
-#ifdef HAVE_MPFR
- if (do_mpfr)
- return tokentab[mid].ptr2;
-#endif
return tokentab[mid].ptr;
}
diff --git a/awkgram.y b/awkgram.y
index 1218f77b..eaa615a2 100644
--- a/awkgram.y
+++ b/awkgram.y
@@ -70,7 +70,6 @@ static INSTRUCTION *mk_expression_list(INSTRUCTION *list, INSTRUCTION *s1);
static INSTRUCTION *mk_for_loop(INSTRUCTION *forp, INSTRUCTION *init, INSTRUCTION *cond,
INSTRUCTION *incr, INSTRUCTION *body);
static void fix_break_continue(INSTRUCTION *list, INSTRUCTION *b_target, INSTRUCTION *c_target);
-static INSTRUCTION *mk_binary(INSTRUCTION *s1, INSTRUCTION *s2, INSTRUCTION *op);
static INSTRUCTION *mk_boolean(INSTRUCTION *left, INSTRUCTION *right, INSTRUCTION *op);
static INSTRUCTION *mk_assignment(INSTRUCTION *lhs, INSTRUCTION *rhs, INSTRUCTION *op);
static INSTRUCTION *mk_getline(INSTRUCTION *op, INSTRUCTION *opt_var, INSTRUCTION *redir, int redirtype);
@@ -1095,7 +1094,7 @@ case_value
{
NODE *n = $2->memory;
(void) force_number(n);
- negate_num(n);
+ numbr_hndlr->gawk_negate_number(n);
bcfree($1);
$$ = $2;
}
@@ -1389,17 +1388,17 @@ simp_exp
: non_post_simp_exp
/* Binary operators in order of decreasing precedence. */
| simp_exp '^' simp_exp
- { $$ = mk_binary($1, $3, $2); }
+ { $$ = list_append(list_merge($1, $3), $2); }
| simp_exp '*' simp_exp
- { $$ = mk_binary($1, $3, $2); }
+ { $$ = list_append(list_merge($1, $3), $2); }
| simp_exp '/' simp_exp
- { $$ = mk_binary($1, $3, $2); }
+ { $$ = list_append(list_merge($1, $3), $2); }
| simp_exp '%' simp_exp
- { $$ = mk_binary($1, $3, $2); }
+ { $$ = list_append(list_merge($1, $3), $2); }
| simp_exp '+' simp_exp
- { $$ = mk_binary($1, $3, $2); }
+ { $$ = list_append(list_merge($1, $3), $2); }
| simp_exp '-' simp_exp
- { $$ = mk_binary($1, $3, $2); }
+ { $$ = list_append(list_merge($1, $3), $2); }
| LEX_GETLINE opt_variable input_redir
{
/*
@@ -1456,17 +1455,17 @@ simp_exp_nc
}
/* Binary operators in order of decreasing precedence. */
| simp_exp_nc '^' simp_exp
- { $$ = mk_binary($1, $3, $2); }
+ { $$ = list_append(list_merge($1, $3), $2); }
| simp_exp_nc '*' simp_exp
- { $$ = mk_binary($1, $3, $2); }
+ { $$ = list_append(list_merge($1, $3), $2); }
| simp_exp_nc '/' simp_exp
- { $$ = mk_binary($1, $3, $2); }
+ { $$ = list_append(list_merge($1, $3), $2); }
| simp_exp_nc '%' simp_exp
- { $$ = mk_binary($1, $3, $2); }
+ { $$ = list_append(list_merge($1, $3), $2); }
| simp_exp_nc '+' simp_exp
- { $$ = mk_binary($1, $3, $2); }
+ { $$ = list_append(list_merge($1, $3), $2); }
| simp_exp_nc '-' simp_exp
- { $$ = mk_binary($1, $3, $2); }
+ { $$ = list_append(list_merge($1, $3), $2); }
;
non_post_simp_exp
@@ -1560,7 +1559,7 @@ non_post_simp_exp
) {
NODE *n = $2->lasti->memory;
(void) force_number(n);
- negate_num(n);
+ numbr_hndlr->gawk_negate_number(n);
$$ = $2;
bcfree($1);
} else {
@@ -1574,8 +1573,7 @@ non_post_simp_exp
* was: $$ = $2
* POSIX semantics: force a conversion to numeric type
*/
- $1->opcode = Op_plus_i;
- $1->memory = make_number(0.0);
+ $1->opcode = Op_unary_plus;
$$ = list_append($2, $1);
}
;
@@ -1804,9 +1802,9 @@ struct token {
# define BREAK 0x0800 /* break allowed inside */
# define CONTINUE 0x1000 /* continue allowed inside */
# define DEBUG_USE 0x2000 /* for use by developers */
+# define ARG3_IS_ARR 0x4000 /* hack for div/do_mpfp_div */
NODE *(*ptr)(int); /* function that implements this keyword */
- NODE *(*ptr2)(int); /* alternate arbitrary-precision function */
};
#if 'a' == 0x81 /* it's EBCDIC */
@@ -1830,91 +1828,86 @@ tokcompare(const void *l, const void *r)
* Function pointers come from declarations in awk.h.
*/
-#ifdef HAVE_MPFR
-#define MPF(F) do_mpfr_##F
-#else
-#define MPF(F) 0
-#endif
-static const struct token tokentab[] = {
-{"BEGIN", Op_rule, LEX_BEGIN, 0, 0, 0},
-{"BEGINFILE", Op_rule, LEX_BEGINFILE, GAWKX, 0, 0},
-{"END", Op_rule, LEX_END, 0, 0, 0},
-{"ENDFILE", Op_rule, LEX_ENDFILE, GAWKX, 0, 0},
+static struct token tokentab[] = {
+{"BEGIN", Op_rule, LEX_BEGIN, 0, 0 },
+{"BEGINFILE", Op_rule, LEX_BEGINFILE, GAWKX, 0 },
+{"END", Op_rule, LEX_END, 0, 0 },
+{"ENDFILE", Op_rule, LEX_ENDFILE, GAWKX, 0 },
#ifdef ARRAYDEBUG
-{"adump", Op_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2)|DEBUG_USE, do_adump, 0},
+{"adump", Op_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2)|DEBUG_USE, do_adump },
#endif
-{"and", Op_builtin, LEX_BUILTIN, GAWKX, do_and, MPF(and)},
-{"asort", Op_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2)|A(3), do_asort, 0},
-{"asorti", Op_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2)|A(3), do_asorti, 0},
-{"atan2", Op_builtin, LEX_BUILTIN, NOT_OLD|A(2), do_atan2, MPF(atan2)},
-{"bindtextdomain", Op_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2), do_bindtextdomain, 0},
-{"break", Op_K_break, LEX_BREAK, 0, 0, 0},
-{"case", Op_K_case, LEX_CASE, GAWKX, 0, 0},
-{"close", Op_builtin, LEX_BUILTIN, NOT_OLD|A(1)|A(2), do_close, 0},
-{"compl", Op_builtin, LEX_BUILTIN, GAWKX|A(1), do_compl, MPF(compl)},
-{"continue", Op_K_continue, LEX_CONTINUE, 0, 0, 0},
-{"cos", Op_builtin, LEX_BUILTIN, NOT_OLD|A(1), do_cos, MPF(cos)},
-{"dcgettext", Op_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2)|A(3), do_dcgettext, 0},
-{"dcngettext", Op_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2)|A(3)|A(4)|A(5), do_dcngettext, 0},
-{"default", Op_K_default, LEX_DEFAULT, GAWKX, 0, 0},
-{"delete", Op_K_delete, LEX_DELETE, NOT_OLD, 0, 0},
-{"div", Op_builtin, LEX_BUILTIN, GAWKX|A(3), do_div, MPF(div)},
-{"do", Op_K_do, LEX_DO, NOT_OLD|BREAK|CONTINUE, 0, 0},
-{"else", Op_K_else, LEX_ELSE, 0, 0, 0},
-{"eval", Op_symbol, LEX_EVAL, 0, 0, 0},
-{"exit", Op_K_exit, LEX_EXIT, 0, 0, 0},
-{"exp", Op_builtin, LEX_BUILTIN, A(1), do_exp, MPF(exp)},
+{"and", Op_builtin, LEX_BUILTIN, GAWKX, 0 },
+{"asort", Op_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2)|A(3), do_asort },
+{"asorti", Op_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2)|A(3), do_asorti },
+{"atan2", Op_builtin, LEX_BUILTIN, NOT_OLD|A(2), 0 },
+{"bindtextdomain", Op_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2), do_bindtextdomain },
+{"break", Op_K_break, LEX_BREAK, 0, 0 },
+{"case", Op_K_case, LEX_CASE, GAWKX, 0 },
+{"close", Op_builtin, LEX_BUILTIN, NOT_OLD|A(1)|A(2), do_close },
+{"compl", Op_builtin, LEX_BUILTIN, GAWKX|A(1), 0 },
+{"continue", Op_K_continue, LEX_CONTINUE, 0, 0 },
+{"cos", Op_builtin, LEX_BUILTIN, NOT_OLD|A(1), 0 },
+{"dcgettext", Op_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2)|A(3), do_dcgettext },
+{"dcngettext", Op_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2)|A(3)|A(4)|A(5), do_dcngettext },
+{"default", Op_K_default, LEX_DEFAULT, GAWKX, 0 },
+{"delete", Op_K_delete, LEX_DELETE, NOT_OLD, 0 },
+{"div", Op_builtin, LEX_BUILTIN, GAWKX|A(3)|ARG3_IS_ARR, do_div },
+{"do", Op_K_do, LEX_DO, NOT_OLD|BREAK|CONTINUE, 0 },
+{"else", Op_K_else, LEX_ELSE, 0, 0 },
+{"eval", Op_symbol, LEX_EVAL, 0, 0 },
+{"exit", Op_K_exit, LEX_EXIT, 0, 0 },
+{"exp", Op_builtin, LEX_BUILTIN, A(1), 0 },
#ifdef DYNAMIC
-{"extension", Op_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2)|A(3), do_ext, 0},
+{"extension", Op_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2)|A(3), do_ext },
#endif
-{"fflush", Op_builtin, LEX_BUILTIN, A(0)|A(1), do_fflush, 0},
-{"for", Op_K_for, LEX_FOR, BREAK|CONTINUE, 0, 0},
-{"func", Op_func, LEX_FUNCTION, NOT_POSIX|NOT_OLD, 0, 0},
-{"function",Op_func, LEX_FUNCTION, NOT_OLD, 0, 0},
-{"gensub", Op_sub_builtin, LEX_BUILTIN, GAWKX|A(3)|A(4), 0, 0},
-{"getline", Op_K_getline_redir, LEX_GETLINE, NOT_OLD, 0, 0},
-{"gsub", Op_sub_builtin, LEX_BUILTIN, NOT_OLD|A(2)|A(3), 0, 0},
-{"if", Op_K_if, LEX_IF, 0, 0, 0},
-{"in", Op_symbol, LEX_IN, 0, 0, 0},
-{"include", Op_symbol, LEX_INCLUDE, GAWKX, 0, 0},
-{"index", Op_builtin, LEX_BUILTIN, A(2), do_index, 0},
-{"int", Op_builtin, LEX_BUILTIN, A(1), do_int, MPF(int)},
-{"isarray", Op_builtin, LEX_BUILTIN, GAWKX|A(1), do_isarray, 0},
-{"length", Op_builtin, LEX_LENGTH, A(0)|A(1), do_length, 0},
-{"load", Op_symbol, LEX_LOAD, GAWKX, 0, 0},
-{"log", Op_builtin, LEX_BUILTIN, A(1), do_log, MPF(log)},
-{"lshift", Op_builtin, LEX_BUILTIN, GAWKX|A(2), do_lshift, MPF(lshift)},
-{"match", Op_builtin, LEX_BUILTIN, NOT_OLD|A(2)|A(3), do_match, 0},
-{"mktime", Op_builtin, LEX_BUILTIN, GAWKX|A(1), do_mktime, 0},
-{"next", Op_K_next, LEX_NEXT, 0, 0, 0},
-{"nextfile", Op_K_nextfile, LEX_NEXTFILE, 0, 0, 0},
-{"or", Op_builtin, LEX_BUILTIN, GAWKX, do_or, MPF(or)},
-{"patsplit", Op_builtin, LEX_BUILTIN, GAWKX|A(2)|A(3)|A(4), do_patsplit, 0},
-{"print", Op_K_print, LEX_PRINT, 0, 0, 0},
-{"printf", Op_K_printf, LEX_PRINTF, 0, 0, 0},
-{"rand", Op_builtin, LEX_BUILTIN, NOT_OLD|A(0), do_rand, MPF(rand)},
-{"return", Op_K_return, LEX_RETURN, NOT_OLD, 0, 0},
-{"rshift", Op_builtin, LEX_BUILTIN, GAWKX|A(2), do_rshift, MPF(rshift)},
-{"sin", Op_builtin, LEX_BUILTIN, NOT_OLD|A(1), do_sin, MPF(sin)},
-{"split", Op_builtin, LEX_BUILTIN, A(2)|A(3)|A(4), do_split, 0},
-{"sprintf", Op_builtin, LEX_BUILTIN, 0, do_sprintf, 0},
-{"sqrt", Op_builtin, LEX_BUILTIN, A(1), do_sqrt, MPF(sqrt)},
-{"srand", Op_builtin, LEX_BUILTIN, NOT_OLD|A(0)|A(1), do_srand, MPF(srand)},
+{"fflush", Op_builtin, LEX_BUILTIN, A(0)|A(1), do_fflush },
+{"for", Op_K_for, LEX_FOR, BREAK|CONTINUE, 0 },
+{"func", Op_func, LEX_FUNCTION, NOT_POSIX|NOT_OLD, 0 },
+{"function",Op_func, LEX_FUNCTION, NOT_OLD, 0 },
+{"gensub", Op_sub_builtin, LEX_BUILTIN, GAWKX|A(3)|A(4), 0 },
+{"getline", Op_K_getline_redir, LEX_GETLINE, NOT_OLD, 0 },
+{"gsub", Op_sub_builtin, LEX_BUILTIN, NOT_OLD|A(2)|A(3), 0 },
+{"if", Op_K_if, LEX_IF, 0, 0 },
+{"in", Op_symbol, LEX_IN, 0, 0 },
+{"include", Op_symbol, LEX_INCLUDE, GAWKX, 0 },
+{"index", Op_builtin, LEX_BUILTIN, A(2), do_index },
+{"int", Op_builtin, LEX_BUILTIN, A(1), 0 },
+{"isarray", Op_builtin, LEX_BUILTIN, GAWKX|A(1), do_isarray },
+{"length", Op_builtin, LEX_LENGTH, A(0)|A(1), do_length },
+{"load", Op_symbol, LEX_LOAD, GAWKX, 0 },
+{"log", Op_builtin, LEX_BUILTIN, A(1), 0 },
+{"lshift", Op_builtin, LEX_BUILTIN, GAWKX|A(2), 0 },
+{"match", Op_builtin, LEX_BUILTIN, NOT_OLD|A(2)|A(3), do_match },
+{"mktime", Op_builtin, LEX_BUILTIN, GAWKX|A(1), do_mktime },
+{"next", Op_K_next, LEX_NEXT, 0, 0 },
+{"nextfile", Op_K_nextfile, LEX_NEXTFILE, 0, 0 },
+{"or", Op_builtin, LEX_BUILTIN, GAWKX, 0 },
+{"patsplit", Op_builtin, LEX_BUILTIN, GAWKX|A(2)|A(3)|A(4), do_patsplit },
+{"print", Op_K_print, LEX_PRINT, 0, 0 },
+{"printf", Op_K_printf, LEX_PRINTF, 0, 0 },
+{"rand", Op_builtin, LEX_BUILTIN, NOT_OLD|A(0), 0 },
+{"return", Op_K_return, LEX_RETURN, NOT_OLD, 0 },
+{"rshift", Op_builtin, LEX_BUILTIN, GAWKX|A(2), 0 },
+{"sin", Op_builtin, LEX_BUILTIN, NOT_OLD|A(1), 0 },
+{"split", Op_builtin, LEX_BUILTIN, A(2)|A(3)|A(4), do_split },
+{"sprintf", Op_builtin, LEX_BUILTIN, 0, do_sprintf },
+{"sqrt", Op_builtin, LEX_BUILTIN, A(1), 0 },
+{"srand", Op_builtin, LEX_BUILTIN, NOT_OLD|A(0)|A(1), 0 },
#if defined(GAWKDEBUG) || defined(ARRAYDEBUG) /* || ... */
-{"stopme", Op_builtin, LEX_BUILTIN, GAWKX|A(0)|DEBUG_USE, stopme, 0},
+{"stopme", Op_builtin, LEX_BUILTIN, GAWKX|A(0)|DEBUG_USE, stopme },
#endif
-{"strftime", Op_builtin, LEX_BUILTIN, GAWKX|A(0)|A(1)|A(2)|A(3), do_strftime, 0},
-{"strtonum", Op_builtin, LEX_BUILTIN, GAWKX|A(1), do_strtonum, MPF(strtonum)},
-{"sub", Op_sub_builtin, LEX_BUILTIN, NOT_OLD|A(2)|A(3), 0, 0},
-{"substr", Op_builtin, LEX_BUILTIN, A(2)|A(3), do_substr, 0},
-{"switch", Op_K_switch, LEX_SWITCH, GAWKX|BREAK, 0, 0},
-{"system", Op_builtin, LEX_BUILTIN, NOT_OLD|A(1), do_system, 0},
-{"systime", Op_builtin, LEX_BUILTIN, GAWKX|A(0), do_systime, 0},
-{"tolower", Op_builtin, LEX_BUILTIN, NOT_OLD|A(1), do_tolower, 0},
-{"toupper", Op_builtin, LEX_BUILTIN, NOT_OLD|A(1), do_toupper, 0},
-{"while", Op_K_while, LEX_WHILE, BREAK|CONTINUE, 0, 0},
-{"xor", Op_builtin, LEX_BUILTIN, GAWKX, do_xor, MPF(xor)},
+{"strftime", Op_builtin, LEX_BUILTIN, GAWKX|A(0)|A(1)|A(2)|A(3), do_strftime },
+{"strtonum", Op_builtin, LEX_BUILTIN, GAWKX|A(1), 0 },
+{"sub", Op_sub_builtin, LEX_BUILTIN, NOT_OLD|A(2)|A(3), 0 },
+{"substr", Op_builtin, LEX_BUILTIN, A(2)|A(3), do_substr },
+{"switch", Op_K_switch, LEX_SWITCH, GAWKX|BREAK, 0 },
+{"system", Op_builtin, LEX_BUILTIN, NOT_OLD|A(1), do_system },
+{"systime", Op_builtin, LEX_BUILTIN, GAWKX|A(0), do_systime },
+{"tolower", Op_builtin, LEX_BUILTIN, NOT_OLD|A(1), do_tolower },
+{"toupper", Op_builtin, LEX_BUILTIN, NOT_OLD|A(1), do_toupper },
+{"while", Op_K_while, LEX_WHILE, BREAK|CONTINUE, 0 },
+{"xor", Op_builtin, LEX_BUILTIN, GAWKX, 0 },
};
#if MBS_SUPPORT
@@ -1944,53 +1937,12 @@ getfname(NODE *(*fptr)(int))
j = sizeof(tokentab) / sizeof(tokentab[0]);
/* linear search, no other way to do it */
for (i = 0; i < j; i++)
- if (tokentab[i].ptr == fptr || tokentab[i].ptr2 == fptr)
+ if (tokentab[i].ptr == fptr)
return tokentab[i].operator;
return NULL;
}
-/* negate_num --- negate a number in NODE */
-
-void
-negate_num(NODE *n)
-{
-#ifdef HAVE_MPFR
- int tval = 0;
-#endif
-
- if (! is_mpg_number(n)) {
- n->numbr = -n->numbr;
- return;
- }
-
-#ifdef HAVE_MPFR
- if (is_mpg_integer(n)) {
- if (! iszero(n)) {
- mpz_neg(n->mpg_i, n->mpg_i);
- return;
- }
-
- /*
- * 0 --> -0 conversion. Requires turning the MPG integer
- * into an MPFR float.
- */
-
- mpz_clear(n->mpg_i); /* release the integer storage */
-
- /* Convert and fall through. */
- tval = mpfr_set_d(n->mpg_numbr, 0.0, ROUND_MODE);
- IEEE_FMT(n->mpg_numbr, tval);
- n->flags &= ~MPZN;
- n->flags |= MPFN;
- }
-
- /* mpfr float case */
- tval = mpfr_neg(n->mpg_numbr, n->mpg_numbr, ROUND_MODE);
- IEEE_FMT(n->mpg_numbr, tval);
-#endif
-}
-
/* print_included_from --- print `Included from ..' file names and locations */
static void
@@ -2159,6 +2111,18 @@ yyerror(const char *m, ...)
efree(buf);
}
+void
+init_parser(const bltin_t *numbr_bltins)
+{
+ int i, tokentab_idx;
+
+ for (i = 0; numbr_bltins[i].name != NULL; i++) {
+ tokentab_idx = check_special(numbr_bltins[i].name);
+ tokentab[tokentab_idx].ptr = numbr_bltins[i].ptr;
+ }
+}
+
+
/* mk_program --- create a single list of instructions */
static INSTRUCTION *
@@ -2997,7 +2961,6 @@ yylex(void)
char *tokkey;
bool inhex = false;
bool intlstr = false;
- AWKNUM d;
#define GET_INSTRUCTION(op) bcalloc(op, 1, sourceline)
@@ -3575,32 +3538,7 @@ retry:
}
}
-#ifdef HAVE_MPFR
- if (do_mpfr) {
- NODE *r;
-
- if (! seen_point && ! seen_e) {
- r = mpg_integer();
- mpg_strtoui(r->mpg_i, tokstart, strlen(tokstart), NULL, base);
- errno = 0;
- } else {
- int tval;
- r = mpg_float();
- tval = mpfr_strtofr(r->mpg_numbr, tokstart, NULL, base, ROUND_MODE);
- errno = 0;
- IEEE_FMT(r->mpg_numbr, tval);
- }
- yylval->memory = r;
- return lasttok = YNUMBER;
- }
-#endif
- if (base != 10)
- d = nondec2awknum(tokstart, strlen(tokstart));
- else
- d = atof(tokstart);
- yylval->memory = make_number(d);
- if (d <= INT32_MAX && d >= INT32_MIN && d == (int32_t) d)
- yylval->memory->flags |= NUMINT;
+ yylval->memory = str2node(tokstart, NULL, base, ! (seen_point || seen_e));
return lasttok = YNUMBER;
case '&':
@@ -3904,13 +3842,7 @@ snode(INSTRUCTION *subn, INSTRUCTION *r)
}
}
-#ifdef HAVE_MPFR
- /* N.B.: If necessary, add special processing for alternate builtin, below */
- if (do_mpfr && tokentab[idx].ptr2)
- r->builtin = tokentab[idx].ptr2;
- else
-#endif
- r->builtin = tokentab[idx].ptr;
+ r->builtin = tokentab[idx].ptr;
/* special case processing for a few builtins */
@@ -3934,11 +3866,7 @@ snode(INSTRUCTION *subn, INSTRUCTION *r)
arg = subn->nexti;
if (arg->nexti == arg->lasti && arg->nexti->opcode == Op_push)
arg->nexti->opcode = Op_push_arg; /* argument may be array */
- } else if (r->builtin == do_div
-#ifdef HAVE_MPFR
- || r->builtin == MPF(div)
-#endif
- ) {
+ } else if ((tokentab[idx].flags & ARG3_IS_ARR) != 0) {
arg = subn->nexti->lasti->nexti->lasti->nexti; /* 3rd arg list */
ip = arg->lasti;
if (ip->opcode == Op_push)
@@ -4132,26 +4060,12 @@ valinfo(NODE *n, Func_print print_func, FILE *fp)
pp_string_fp(print_func, fp, n->stptr, n->stlen, '"', false);
print_func(fp, "\n");
} else if (n->flags & NUMBER) {
-#ifdef HAVE_MPFR
- if (is_mpg_float(n))
- print_func(fp, "%s\n", mpg_fmt("%.17R*g", ROUND_MODE, n->mpg_numbr));
- else if (is_mpg_integer(n))
- print_func(fp, "%s\n", mpg_fmt("%Zd", n->mpg_i));
- else
-#endif
- print_func(fp, "%.17g\n", n->numbr);
+ print_func(fp, "%s\n", fmt_number("%.17g", n));
} 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) {
-#ifdef HAVE_MPFR
- if (is_mpg_float(n))
- print_func(fp, "%s\n", mpg_fmt("%.17R*g", ROUND_MODE, n->mpg_numbr));
- else if (is_mpg_integer(n))
- print_func(fp, "%s\n", mpg_fmt("%Zd", n->mpg_i));
- else
-#endif
- print_func(fp, "%.17g\n", n->numbr);
+ print_func(fp, "%s\n", fmt_number("%.17g", n));
} else
print_func(fp, "?? flags %s\n", flags2str(n->flags));
}
@@ -4619,20 +4533,15 @@ isnoeffect(OPCODE type)
{
switch (type) {
case Op_times:
- case Op_times_i:
case Op_quotient:
- case Op_quotient_i:
case Op_mod:
- case Op_mod_i:
case Op_plus:
- case Op_plus_i:
case Op_minus:
- case Op_minus_i:
case Op_subscript:
case Op_concat:
case Op_exp:
- case Op_exp_i:
case Op_unary_minus:
+ case Op_unary_plus:
case Op_field_spec:
case Op_and_final:
case Op_or_final:
@@ -4735,113 +4644,6 @@ dumpintlstr2(const char *str1, size_t len1, const char *str2, size_t len2)
fflush(stdout);
}
-/* mk_binary --- instructions for binary operators */
-
-static INSTRUCTION *
-mk_binary(INSTRUCTION *s1, INSTRUCTION *s2, INSTRUCTION *op)
-{
- INSTRUCTION *ip1,*ip2;
- AWKNUM res;
-
- ip2 = s2->nexti;
- if (s2->lasti == ip2 && ip2->opcode == Op_push_i) {
- /* do any numeric constant folding */
- ip1 = s1->nexti;
- if (do_optimize
- && ip1 == s1->lasti && ip1->opcode == Op_push_i
- && (ip1->memory->flags & (MPFN|MPZN|STRCUR|STRING)) == 0
- && (ip2->memory->flags & (MPFN|MPZN|STRCUR|STRING)) == 0
- ) {
- NODE *n1 = ip1->memory, *n2 = ip2->memory;
- res = force_number(n1)->numbr;
- (void) force_number(n2);
- switch (op->opcode) {
- case Op_times:
- res *= n2->numbr;
- break;
- case Op_quotient:
- if (n2->numbr == 0.0) {
- /* don't fatalize, allow parsing rest of the input */
- error_ln(op->source_line, _("division by zero attempted"));
- goto regular;
- }
-
- res /= n2->numbr;
- break;
- case Op_mod:
- if (n2->numbr == 0.0) {
- /* don't fatalize, allow parsing rest of the input */
- error_ln(op->source_line, _("division by zero attempted in `%%'"));
- goto regular;
- }
-#ifdef HAVE_FMOD
- res = fmod(res, n2->numbr);
-#else /* ! HAVE_FMOD */
- (void) modf(res / n2->numbr, &res);
- res = n1->numbr - res * n2->numbr;
-#endif /* ! HAVE_FMOD */
- break;
- case Op_plus:
- res += n2->numbr;
- break;
- case Op_minus:
- res -= n2->numbr;
- break;
- case Op_exp:
- res = calc_exp(res, n2->numbr);
- break;
- default:
- goto regular;
- }
-
- op->opcode = Op_push_i;
- op->memory = make_number(res);
- unref(n1);
- unref(n2);
- bcfree(ip1);
- bcfree(ip2);
- bcfree(s1);
- bcfree(s2);
- return list_create(op);
- } else {
- /* do basic arithmetic optimisation */
- /* convert (Op_push_i Node_val) + (Op_plus) to (Op_plus_i Node_val) */
- switch (op->opcode) {
- case Op_times:
- op->opcode = Op_times_i;
- break;
- case Op_quotient:
- op->opcode = Op_quotient_i;
- break;
- case Op_mod:
- op->opcode = Op_mod_i;
- break;
- case Op_plus:
- op->opcode = Op_plus_i;
- break;
- case Op_minus:
- op->opcode = Op_minus_i;
- break;
- case Op_exp:
- op->opcode = Op_exp_i;
- break;
- default:
- goto regular;
- }
-
- op->memory = ip2->memory;
- bcfree(ip2);
- bcfree(s2); /* Op_list */
- return list_append(s1, op);
- }
- }
-
-regular:
- /* append lists s1, s2 and add `op' bytecode */
- (void) list_merge(s1, s2);
- return list_append(s1, op);
-}
-
/* mk_boolean --- instructions for boolean and, or */
static INSTRUCTION *
@@ -5239,8 +5041,8 @@ optimize_assignment(INSTRUCTION *exp)
i3->opcode = Op_store_sub;
i3->memory = i2->memory;
i3->expr_count = 1; /* sub_count shadows memory,
- * so use expr_count instead.
- */
+ * so use expr_count instead
+ */
i3->nexti = NULL;
i2->opcode = Op_no_op;
bcfree(i1); /* Op_assign */
@@ -5723,10 +5525,6 @@ lookup_builtin(const char *name)
if (mid == -1 || tokentab[mid].class != LEX_BUILTIN)
return NULL;
-#ifdef HAVE_MPFR
- if (do_mpfr)
- return tokentab[mid].ptr2;
-#endif
return tokentab[mid].ptr;
}
diff --git a/awklib/ChangeLog b/awklib/ChangeLog
index 6ef0bbde..4173938f 100644
--- a/awklib/ChangeLog
+++ b/awklib/ChangeLog
@@ -20,6 +20,10 @@
* eg/lib/inplace.awk: Add new file generated from doc/gawk.texi.
+2013-01-06 John Haque <j.eh@mchsi.com>
+
+ * eg/lib/repl_math.awk: New file.
+
2012-12-24 Arnold D. Robbins <arnold@skeeve.com>
* 4.0.2: Release tar ball made.
diff --git a/builtin.c b/builtin.c
index 3d59e359..4b3670a1 100644
--- a/builtin.c
+++ b/builtin.c
@@ -23,14 +23,12 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
-
#include "awk.h"
+#include "format.h"
+
#if defined(HAVE_FCNTL_H)
#include <fcntl.h>
#endif
-#include <math.h>
-#include "random.h"
-#include "floatmagic.h"
#if defined(HAVE_POPEN_H)
#include "popen.h"
@@ -59,16 +57,6 @@
#define SIZE_MAX ((size_t) -1)
#endif
-#define DEFAULT_G_PRECISION 6
-
-static size_t mbc_byte_count(const char *ptr, size_t numchars);
-static size_t mbc_char_count(const char *ptr, size_t numbytes);
-
-/* Can declare these, since we always use the random shipped with gawk */
-extern char *initstate(unsigned long seed, char *state, long n);
-extern char *setstate(char *state);
-extern long random(void);
-extern void srandom(unsigned long seed);
extern NODE **args_array;
extern int max_args;
@@ -86,12 +74,6 @@ fatal(_("attempt to use array `%s' in a scalar context"), array_vname(s1)); \
}} while (false)
-/*
- * Since we supply the version of random(), we know what
- * value to use here.
- */
-#define GAWK_RANDOM_MAX 0x7fffffffL
-
/* efwrite --- like fwrite, but with error checking */
static void
@@ -135,25 +117,6 @@ wrerror:
errno ? strerror(errno) : _("reason unknown"));
}
-/* do_exp --- exponential function */
-
-NODE *
-do_exp(int nargs)
-{
- NODE *tmp;
- double d, res;
-
- tmp = POP_SCALAR();
- if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
- lintwarn(_("exp: received non-numeric argument"));
- d = force_number(tmp)->numbr;
- DEREF(tmp);
- errno = 0;
- res = exp(d);
- if (errno == ERANGE)
- warning(_("exp: argument %g is out of range"), d);
- return make_number((AWKNUM) res);
-}
/* stdfile --- return fp for a standard file */
@@ -463,35 +426,6 @@ out:
return make_number((AWKNUM) ret);
}
-/* double_to_int --- convert double to int, used several places */
-
-double
-double_to_int(double d)
-{
- if (d >= 0)
- d = floor(d);
- else
- d = ceil(d);
- return d;
-}
-
-/* do_int --- convert double to int for awk */
-
-NODE *
-do_int(int nargs)
-{
- NODE *tmp;
- double d;
-
- tmp = POP_SCALAR();
- if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
- lintwarn(_("int: received non-numeric argument"));
- d = force_number(tmp)->numbr;
- d = double_to_int(d);
- DEREF(tmp);
- return make_number((AWKNUM) d);
-}
-
/* do_isarray --- check if argument is array */
NODE *
@@ -562,1054 +496,6 @@ do_length(int nargs)
return make_number((AWKNUM) len);
}
-/* do_log --- the log function */
-
-NODE *
-do_log(int nargs)
-{
- NODE *tmp;
- double d, arg;
-
- tmp = POP_SCALAR();
- if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
- lintwarn(_("log: received non-numeric argument"));
- arg = force_number(tmp)->numbr;
- if (arg < 0.0)
- warning(_("log: received negative argument %g"), arg);
- d = log(arg);
- DEREF(tmp);
- return make_number((AWKNUM) d);
-}
-
-
-#ifdef HAVE_MPFR
-
-/*
- * mpz2mpfr --- convert an arbitrary-precision integer to a float
- * without any loss of precision. The returned value is only
- * good for temporary use.
- */
-
-
-static mpfr_ptr
-mpz2mpfr(mpz_ptr zi)
-{
- size_t prec;
- static mpfr_t mpfrval;
- static bool inited = false;
- int tval;
-
- /* estimate minimum precision for exact conversion */
- prec = mpz_sizeinbase(zi, 2); /* most significant 1 bit position starting at 1 */
- prec -= (size_t) mpz_scan1(zi, 0); /* least significant 1 bit index starting at 0 */
- if (prec < MPFR_PREC_MIN)
- prec = MPFR_PREC_MIN;
- else if (prec > MPFR_PREC_MAX)
- prec = MPFR_PREC_MAX;
-
- if (! inited) {
- mpfr_init2(mpfrval, prec);
- inited = true;
- } else
- mpfr_set_prec(mpfrval, prec);
- tval = mpfr_set_z(mpfrval, zi, ROUND_MODE);
- IEEE_FMT(mpfrval, tval);
- return mpfrval;
-}
-#endif
-
-/*
- * format_tree() formats arguments of sprintf,
- * and accordingly to a fmt_string providing a format like in
- * printf family from C library. Returns a string node which value
- * is a formatted string. Called by sprintf function.
- *
- * It is one of the uglier parts of gawk. Thanks to Michal Jaegermann
- * for taming this beast and making it compatible with ANSI C.
- */
-
-NODE *
-format_tree(
- const char *fmt_string,
- size_t n0,
- NODE **the_args,
- long num_args)
-{
-/* copy 'l' bytes from 's' to 'obufout' checking for space in the process */
-/* difference of pointers should be of ptrdiff_t type, but let us be kind */
-#define bchunk(s, l) if (l) { \
- while ((l) > ofre) { \
- size_t olen = obufout - obuf; \
- erealloc(obuf, char *, osiz * 2, "format_tree"); \
- ofre += osiz; \
- osiz *= 2; \
- obufout = obuf + olen; \
- } \
- memcpy(obufout, s, (size_t) (l)); \
- obufout += (l); \
- ofre -= (l); \
-}
-
-/* copy one byte from 's' to 'obufout' checking for space in the process */
-#define bchunk_one(s) { \
- if (ofre < 1) { \
- size_t olen = obufout - obuf; \
- erealloc(obuf, char *, osiz * 2, "format_tree"); \
- ofre += osiz; \
- osiz *= 2; \
- obufout = obuf + olen; \
- } \
- *obufout++ = *s; \
- --ofre; \
-}
-
-/* Is there space for something L big in the buffer? */
-#define chksize(l) if ((l) >= ofre) { \
- size_t olen = obufout - obuf; \
- size_t delta = osiz+l-ofre; \
- erealloc(obuf, char *, osiz + delta, "format_tree"); \
- obufout = obuf + olen; \
- ofre += delta; \
- osiz += delta; \
-}
-
- size_t cur_arg = 0;
- NODE *r = NULL;
- int i, nc;
- bool toofew = false;
- char *obuf, *obufout;
- size_t osiz, ofre;
- const char *chbuf;
- const char *s0, *s1;
- int cs1;
- NODE *arg;
- long fw, prec, argnum;
- bool used_dollar;
- bool lj, alt, big_flag, bigbig_flag, small_flag, have_prec, need_format;
- long *cur = NULL;
- uintmax_t uval;
- bool sgn;
- int base;
- /*
- * Although this is an array, the elements serve two different
- * purposes. The first element is the general buffer meant
- * to hold the entire result string. The second one is a
- * temporary buffer for large floating point values. They
- * could just as easily be separate variables, and the
- * code might arguably be clearer.
- */
- struct {
- char *buf;
- size_t bufsize;
- char stackbuf[30];
- } cpbufs[2];
-#define cpbuf cpbufs[0].buf
- char *cend = &cpbufs[0].stackbuf[sizeof(cpbufs[0].stackbuf)];
- char *cp;
- const char *fill;
- AWKNUM tmpval = 0.0;
- char signchar = '\0';
- size_t len;
- bool zero_flag = false;
- bool quote_flag = false;
- int ii, jj;
- char *chp;
- size_t copy_count, char_count;
-#ifdef HAVE_MPFR
- mpz_ptr zi;
- mpfr_ptr mf;
-#endif
- enum { MP_NONE = 0, MP_INT_WITH_PREC = 1, MP_INT_WITHOUT_PREC, MP_FLOAT } fmt_type;
-
- static const char sp[] = " ";
- static const char zero_string[] = "0";
- static const char lchbuf[] = "0123456789abcdef";
- static const char Uchbuf[] = "0123456789ABCDEF";
-
-#define INITIAL_OUT_SIZE 512
- emalloc(obuf, char *, INITIAL_OUT_SIZE, "format_tree");
- obufout = obuf;
- osiz = INITIAL_OUT_SIZE;
- ofre = osiz - 2;
-
- cur_arg = 1;
-
- {
- size_t k;
- for (k = 0; k < sizeof(cpbufs)/sizeof(cpbufs[0]); k++) {
- cpbufs[k].bufsize = sizeof(cpbufs[k].stackbuf);
- cpbufs[k].buf = cpbufs[k].stackbuf;
- }
- }
-
- /*
- * The point of this goop is to grow the buffer
- * holding the converted number, so that large
- * values don't overflow a fixed length buffer.
- */
-#define PREPEND(CH) do { \
- if (cp == cpbufs[0].buf) { \
- char *prev = cpbufs[0].buf; \
- emalloc(cpbufs[0].buf, char *, 2*cpbufs[0].bufsize, \
- "format_tree"); \
- memcpy((cp = cpbufs[0].buf+cpbufs[0].bufsize), prev, \
- cpbufs[0].bufsize); \
- cpbufs[0].bufsize *= 2; \
- if (prev != cpbufs[0].stackbuf) \
- efree(prev); \
- cend = cpbufs[0].buf+cpbufs[0].bufsize; \
- } \
- *--cp = (CH); \
-} while(0)
-
- /*
- * Check first for use of `count$'.
- * If plain argument retrieval was used earlier, choke.
- * Otherwise, return the requested argument.
- * If not `count$' now, but it was used earlier, choke.
- * If this format is more than total number of args, choke.
- * Otherwise, return the current argument.
- */
-#define parse_next_arg() { \
- if (argnum > 0) { \
- if (cur_arg > 1) { \
- msg(_("fatal: must use `count$' on all formats or none")); \
- goto out; \
- } \
- arg = the_args[argnum]; \
- } else if (used_dollar) { \
- msg(_("fatal: must use `count$' on all formats or none")); \
- arg = 0; /* shutup the compiler */ \
- goto out; \
- } else if (cur_arg >= num_args) { \
- arg = 0; /* shutup the compiler */ \
- toofew = true; \
- break; \
- } else { \
- arg = the_args[cur_arg]; \
- cur_arg++; \
- } \
-}
-
- need_format = false;
- used_dollar = false;
-
- s0 = s1 = fmt_string;
- while (n0-- > 0) {
- if (*s1 != '%') {
- s1++;
- continue;
- }
- need_format = true;
- bchunk(s0, s1 - s0);
- s0 = s1;
- cur = &fw;
- fw = 0;
- prec = 0;
- base = 0;
- argnum = 0;
- base = 0;
- have_prec = false;
- signchar = '\0';
- zero_flag = false;
- quote_flag = false;
-#ifdef HAVE_MPFR
- mf = NULL;
- zi = NULL;
-#endif
- fmt_type = MP_NONE;
-
- lj = alt = big_flag = bigbig_flag = small_flag = false;
- fill = sp;
- cp = cend;
- chbuf = lchbuf;
- s1++;
-
-retry:
- if (n0-- == 0) /* ran out early! */
- break;
-
- switch (cs1 = *s1++) {
- case (-1): /* dummy case to allow for checking */
-check_pos:
- if (cur != &fw)
- break; /* reject as a valid format */
- goto retry;
- case '%':
- need_format = false;
- /*
- * 29 Oct. 2002:
- * The C99 standard pages 274 and 279 seem to imply that
- * since there's no arg converted, the field width doesn't
- * apply. The code already was that way, but this
- * comment documents it, at least in the code.
- */
- if (do_lint) {
- const char *msg = NULL;
-
- if (fw && ! have_prec)
- msg = _("field width is ignored for `%%' specifier");
- else if (fw == 0 && have_prec)
- msg = _("precision is ignored for `%%' specifier");
- else if (fw && have_prec)
- msg = _("field width and precision are ignored for `%%' specifier");
-
- if (msg != NULL)
- lintwarn("%s", msg);
- }
- bchunk_one("%");
- s0 = s1;
- break;
-
- case '0':
- /*
- * Only turn on zero_flag if we haven't seen
- * the field width or precision yet. Otherwise,
- * screws up floating point formatting.
- */
- if (cur == & fw)
- zero_flag = true;
- if (lj)
- goto retry;
- /* FALL through */
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- if (cur == NULL)
- break;
- if (prec >= 0)
- *cur = cs1 - '0';
- /*
- * with a negative precision *cur is already set
- * to -1, so it will remain negative, but we have
- * to "eat" precision digits in any case
- */
- while (n0 > 0 && *s1 >= '0' && *s1 <= '9') {
- --n0;
- *cur = *cur * 10 + *s1++ - '0';
- }
- if (prec < 0) /* negative precision is discarded */
- have_prec = false;
- if (cur == &prec)
- cur = NULL;
- if (n0 == 0) /* badly formatted control string */
- continue;
- goto retry;
- case '$':
- if (do_traditional) {
- msg(_("fatal: `$' is not permitted in awk formats"));
- goto out;
- }
-
- if (cur == &fw) {
- argnum = fw;
- fw = 0;
- used_dollar = true;
- if (argnum <= 0) {
- msg(_("fatal: arg count with `$' must be > 0"));
- goto out;
- }
- if (argnum >= num_args) {
- msg(_("fatal: arg count %ld greater than total number of supplied arguments"), argnum);
- goto out;
- }
- } else {
- msg(_("fatal: `$' not permitted after period in format"));
- goto out;
- }
-
- goto retry;
- case '*':
- if (cur == NULL)
- break;
- if (! do_traditional && isdigit((unsigned char) *s1)) {
- int val = 0;
-
- for (; n0 > 0 && *s1 && isdigit((unsigned char) *s1); s1++, n0--) {
- val *= 10;
- val += *s1 - '0';
- }
- if (*s1 != '$') {
- msg(_("fatal: no `$' supplied for positional field width or precision"));
- goto out;
- } else {
- s1++;
- n0--;
- }
- if (val >= num_args) {
- toofew = true;
- break;
- }
- arg = the_args[val];
- } else {
- parse_next_arg();
- }
- (void) force_number(arg);
- *cur = get_number_si(arg);
- if (*cur < 0 && cur == &fw) {
- *cur = -*cur;
- lj++;
- }
- if (cur == &prec) {
- if (*cur >= 0)
- have_prec = true;
- else
- have_prec = false;
- cur = NULL;
- }
- goto retry;
- case ' ': /* print ' ' or '-' */
- /* 'space' flag is ignored */
- /* if '+' already present */
- if (signchar != false)
- goto check_pos;
- /* FALL THROUGH */
- case '+': /* print '+' or '-' */
- signchar = cs1;
- goto check_pos;
- case '-':
- if (prec < 0)
- break;
- if (cur == &prec) {
- prec = -1;
- goto retry;
- }
- fill = sp; /* if left justified then other */
- lj++; /* filling is ignored */
- goto check_pos;
- case '.':
- if (cur != &fw)
- break;
- cur = &prec;
- have_prec = true;
- goto retry;
- case '#':
- alt = true;
- goto check_pos;
- case '\'':
-#if defined(HAVE_LOCALE_H)
- quote_flag = true;
- goto check_pos;
-#else
- goto retry;
-#endif
- case 'l':
- if (big_flag)
- break;
- else {
- static bool warned = false;
-
- if (do_lint && ! warned) {
- lintwarn(_("`l' is meaningless in awk formats; ignored"));
- warned = true;
- }
- if (do_posix) {
- msg(_("fatal: `l' is not permitted in POSIX awk formats"));
- goto out;
- }
- }
- big_flag = true;
- goto retry;
- case 'L':
- if (bigbig_flag)
- break;
- else {
- static bool warned = false;
-
- if (do_lint && ! warned) {
- lintwarn(_("`L' is meaningless in awk formats; ignored"));
- warned = true;
- }
- if (do_posix) {
- msg(_("fatal: `L' is not permitted in POSIX awk formats"));
- goto out;
- }
- }
- bigbig_flag = true;
- goto retry;
- case 'h':
- if (small_flag)
- break;
- else {
- static bool warned = false;
-
- if (do_lint && ! warned) {
- lintwarn(_("`h' is meaningless in awk formats; ignored"));
- warned = true;
- }
- if (do_posix) {
- msg(_("fatal: `h' is not permitted in POSIX awk formats"));
- goto out;
- }
- }
- small_flag = true;
- goto retry;
- case 'c':
- need_format = false;
- parse_next_arg();
- /* user input that looks numeric is numeric */
- if ((arg->flags & (MAYBE_NUM|NUMBER)) == MAYBE_NUM)
- (void) force_number(arg);
- if ((arg->flags & NUMBER) != 0) {
- uval = get_number_uj(arg);
-#if MBS_SUPPORT
- if (gawk_mb_cur_max > 1) {
- char buf[100];
- wchar_t wc;
- mbstate_t mbs;
- size_t count;
-
- memset(& mbs, 0, sizeof(mbs));
-
- /* handle systems with too small wchar_t */
- if (sizeof(wchar_t) < 4 && uval > 0xffff) {
- if (do_lint)
- lintwarn(
- _("[s]printf: value %g is too big for %%c format"),
- arg->numbr);
-
- goto out0;
- }
-
- wc = uval;
-
- count = wcrtomb(buf, wc, & mbs);
- if (count == 0
- || count == (size_t) -1) {
- if (do_lint)
- lintwarn(
- _("[s]printf: value %g is not a valid wide character"),
- arg->numbr);
-
- goto out0;
- }
-
- memcpy(cpbuf, buf, count);
- prec = count;
- cp = cpbuf;
- goto pr_tail;
- }
-out0:
- ;
- /* else,
- fall through */
-#endif
- cpbuf[0] = uval;
- prec = 1;
- cp = cpbuf;
- goto pr_tail;
- }
- /*
- * As per POSIX, only output first character of a
- * string value. Thus, we ignore any provided
- * precision, forcing it to 1. (Didn't this
- * used to work? 6/2003.)
- */
- cp = arg->stptr;
- prec = 1;
-#if MBS_SUPPORT
- /*
- * First character can be multiple bytes if
- * it's a multibyte character. Grr.
- */
- if (gawk_mb_cur_max > 1) {
- mbstate_t state;
- size_t count;
-
- memset(& state, 0, sizeof(state));
- count = mbrlen(cp, arg->stlen, & state);
- if (count != (size_t) -1 && count != (size_t) -2 && count > 0) {
- prec = count;
- /* may need to increase fw so that padding happens, see pr_tail code */
- if (fw > 0)
- fw += count - 1;
- }
- }
-#endif
- goto pr_tail;
- case 's':
- need_format = false;
- parse_next_arg();
- arg = force_string(arg);
- if (fw == 0 && ! have_prec)
- prec = arg->stlen;
- else {
- char_count = mbc_char_count(arg->stptr, arg->stlen);
- if (! have_prec || prec > char_count)
- prec = char_count;
- }
- cp = arg->stptr;
- goto pr_tail;
- case 'd':
- case 'i':
- need_format = false;
- parse_next_arg();
- (void) force_number(arg);
-#ifdef HAVE_MPFR
- if (is_mpg_float(arg))
- goto mpf0;
- else if (is_mpg_integer(arg))
- goto mpz0;
- else
-#endif
- tmpval = arg->numbr;
-
- /*
- * Check for Nan or Inf.
- */
- if (isnan(tmpval) || isinf(tmpval))
- goto out_of_range;
- else
- tmpval = double_to_int(tmpval);
-
- /*
- * ``The result of converting a zero value with a
- * precision of zero is no characters.''
- */
- if (have_prec && prec == 0 && tmpval == 0)
- goto pr_tail;
-
- if (tmpval < 0) {
- tmpval = -tmpval;
- sgn = true;
- } else {
- if (tmpval == -0.0)
- /* avoid printing -0 */
- tmpval = 0.0;
- sgn = false;
- }
- /*
- * Use snprintf return value to tell if there
- * is enough room in the buffer or not.
- */
- while ((i = snprintf(cpbufs[1].buf,
- cpbufs[1].bufsize, "%.0f",
- tmpval)) >=
- cpbufs[1].bufsize) {
- if (cpbufs[1].buf == cpbufs[1].stackbuf)
- cpbufs[1].buf = NULL;
- if (i > 0) {
- cpbufs[1].bufsize += ((i > cpbufs[1].bufsize) ?
- i : cpbufs[1].bufsize);
- }
- else
- cpbufs[1].bufsize *= 2;
- assert(cpbufs[1].bufsize > 0);
- erealloc(cpbufs[1].buf, char *,
- cpbufs[1].bufsize, "format_tree");
- }
- if (i < 1)
- goto out_of_range;
-#if defined(HAVE_LOCALE_H)
- quote_flag = (quote_flag && loc.thousands_sep[0] != 0);
-#endif
- chp = &cpbufs[1].buf[i-1];
- ii = jj = 0;
- do {
- PREPEND(*chp);
- chp--; i--;
-#if defined(HAVE_LOCALE_H)
- if (quote_flag && loc.grouping[ii] && ++jj == loc.grouping[ii]) {
- if (i) { /* only add if more digits coming */
- int k;
- const char *ts = loc.thousands_sep;
-
- for (k = strlen(ts) - 1; k >= 0; k--) {
- PREPEND(ts[k]);
- }
- }
- if (loc.grouping[ii+1] == 0)
- jj = 0; /* keep using current val in loc.grouping[ii] */
- else if (loc.grouping[ii+1] == CHAR_MAX)
- quote_flag = false;
- else {
- ii++;
- jj = 0;
- }
- }
-#endif
- } while (i > 0);
-
- /* add more output digits to match the precision */
- if (have_prec) {
- while (cend - cp < prec)
- PREPEND('0');
- }
-
- if (sgn)
- PREPEND('-');
- else if (signchar)
- PREPEND(signchar);
- /*
- * When to fill with zeroes is of course not simple.
- * First: No zero fill if left-justifying.
- * Next: There seem to be two cases:
- * A '0' without a precision, e.g. %06d
- * A precision with no field width, e.g. %.10d
- * Any other case, we don't want to fill with zeroes.
- */
- if (! lj
- && ((zero_flag && ! have_prec)
- || (fw == 0 && have_prec)))
- fill = zero_string;
- if (prec > fw)
- fw = prec;
- prec = cend - cp;
- if (fw > prec && ! lj && fill != sp
- && (*cp == '-' || signchar)) {
- bchunk_one(cp);
- cp++;
- prec--;
- fw--;
- }
- goto pr_tail;
- case 'X':
- chbuf = Uchbuf; /* FALL THROUGH */
- case 'x':
- base += 6; /* FALL THROUGH */
- case 'u':
- base += 2; /* FALL THROUGH */
- case 'o':
- base += 8;
- need_format = false;
- parse_next_arg();
- (void) force_number(arg);
-#ifdef HAVE_MPFR
- if (is_mpg_integer(arg)) {
-mpz0:
- zi = arg->mpg_i;
-
- if (cs1 != 'd' && cs1 != 'i') {
- if (mpz_sgn(zi) <= 0) {
- /*
- * Negative value or 0 requires special handling.
- * Unlike MPFR, GMP does not allow conversion
- * to (u)intmax_t. So we first convert GMP type to
- * a MPFR type.
- */
- mf = mpz2mpfr(zi);
- goto mpf1;
- }
- signchar = '\0'; /* Don't print '+' */
- }
-
- /* See comments above about when to fill with zeros */
- zero_flag = (! lj
- && ((zero_flag && ! have_prec)
- || (fw == 0 && have_prec)));
-
- fmt_type = have_prec ? MP_INT_WITH_PREC : MP_INT_WITHOUT_PREC;
- goto fmt0;
-
- } else if (is_mpg_float(arg)) {
-mpf0:
- mf = arg->mpg_numbr;
- if (! mpfr_number_p(mf)) {
- /* inf or NaN */
- cs1 = 'g';
- fmt_type = MP_FLOAT;
- goto fmt1;
- }
-
- if (cs1 != 'd' && cs1 != 'i') {
-mpf1:
- /*
- * The output of printf("%#.0x", 0) is 0 instead of 0x, hence <= in
- * the comparison below.
- */
- if (mpfr_sgn(mf) <= 0) {
- if (! mpfr_fits_intmax_p(mf, ROUND_MODE)) {
- /* -ve number is too large */
- cs1 = 'g';
- fmt_type = MP_FLOAT;
- goto fmt1;
- }
-
- tmpval = uval = (uintmax_t) mpfr_get_sj(mf, ROUND_MODE);
- if (! alt && have_prec && prec == 0 && tmpval == 0)
- goto pr_tail; /* printf("%.0x", 0) is no characters */
- goto int0;
- }
- signchar = '\0'; /* Don't print '+' */
- }
-
- /* See comments above about when to fill with zeros */
- zero_flag = (! lj
- && ((zero_flag && ! have_prec)
- || (fw == 0 && have_prec)));
-
- (void) mpfr_get_z(mpzval, mf, MPFR_RNDZ); /* convert to GMP integer */
- fmt_type = have_prec ? MP_INT_WITH_PREC : MP_INT_WITHOUT_PREC;
- zi = mpzval;
- goto fmt0;
- } else
-#endif
- tmpval = arg->numbr;
-
- /*
- * ``The result of converting a zero value with a
- * precision of zero is no characters.''
- *
- * If I remember the ANSI C standard, though,
- * it says that for octal conversions
- * the precision is artificially increased
- * to add an extra 0 if # is supplied.
- * Indeed, in C,
- * printf("%#.0o\n", 0);
- * prints a single 0.
- */
- if (! alt && have_prec && prec == 0 && tmpval == 0)
- goto pr_tail;
-
- if (tmpval < 0) {
- uval = (uintmax_t) (intmax_t) tmpval;
- if ((AWKNUM)(intmax_t)uval != double_to_int(tmpval))
- goto out_of_range;
- } else {
- uval = (uintmax_t) tmpval;
- if ((AWKNUM)uval != double_to_int(tmpval))
- goto out_of_range;
- }
-#ifdef HAVE_MPFR
- int0:
-#endif
-#if defined(HAVE_LOCALE_H)
- quote_flag = (quote_flag && loc.thousands_sep[0] != 0);
-#endif
- /*
- * When to fill with zeroes is of course not simple.
- * First: No zero fill if left-justifying.
- * Next: There seem to be two cases:
- * A '0' without a precision, e.g. %06d
- * A precision with no field width, e.g. %.10d
- * Any other case, we don't want to fill with zeroes.
- */
- if (! lj
- && ((zero_flag && ! have_prec)
- || (fw == 0 && have_prec)))
- fill = zero_string;
- ii = jj = 0;
- do {
- PREPEND(chbuf[uval % base]);
- uval /= base;
-#if defined(HAVE_LOCALE_H)
- if (base == 10 && quote_flag && loc.grouping[ii] && ++jj == loc.grouping[ii]) {
- if (uval) { /* only add if more digits coming */
- int k;
- const char *ts = loc.thousands_sep;
-
- for (k = strlen(ts) - 1; k >= 0; k--) {
- PREPEND(ts[k]);
- }
- }
- if (loc.grouping[ii+1] == 0)
- jj = 0; /* keep using current val in loc.grouping[ii] */
- else if (loc.grouping[ii+1] == CHAR_MAX)
- quote_flag = false;
- else {
- ii++;
- jj = 0;
- }
- }
-#endif
- } while (uval > 0);
-
- /* add more output digits to match the precision */
- if (have_prec) {
- while (cend - cp < prec)
- PREPEND('0');
- }
-
- if (alt && tmpval != 0) {
- if (base == 16) {
- PREPEND(cs1);
- PREPEND('0');
- if (fill != sp) {
- bchunk(cp, 2);
- cp += 2;
- fw -= 2;
- }
- } else if (base == 8)
- PREPEND('0');
- }
- base = 0;
- if (prec > fw)
- fw = prec;
- prec = cend - cp;
- pr_tail:
- if (! lj) {
- while (fw > prec) {
- bchunk_one(fill);
- fw--;
- }
- }
- copy_count = prec;
- if (fw == 0 && ! have_prec)
- ;
- else if (gawk_mb_cur_max > 1) {
- if (cs1 == 's') {
- assert(cp == arg->stptr || cp == cpbuf);
- copy_count = mbc_byte_count(arg->stptr, prec);
- }
- /* prec was set by code for %c */
- /* else
- copy_count = prec; */
- }
- bchunk(cp, copy_count);
- while (fw > prec) {
- bchunk_one(fill);
- fw--;
- }
- s0 = s1;
- break;
-
- out_of_range:
- /* out of range - emergency use of %g format */
- if (do_lint)
- lintwarn(_("[s]printf: value %g is out of range for `%%%c' format"),
- (double) tmpval, cs1);
- cs1 = 'g';
- goto fmt1;
-
- case 'F':
-#if ! defined(PRINTF_HAS_F_FORMAT) || PRINTF_HAS_F_FORMAT != 1
- cs1 = 'f';
- /* FALL THROUGH */
-#endif
- case 'g':
- case 'G':
- case 'e':
- case 'f':
- case 'E':
- need_format = false;
- parse_next_arg();
- (void) force_number(arg);
-
- if (! is_mpg_number(arg))
- tmpval = arg->numbr;
-#ifdef HAVE_MPFR
- else if (is_mpg_float(arg)) {
- mf = arg->mpg_numbr;
- fmt_type = MP_FLOAT;
- } else {
- /* arbitrary-precision integer, convert to MPFR float */
- assert(mf == NULL);
- mf = mpz2mpfr(arg->mpg_i);
- fmt_type = MP_FLOAT;
- }
-#endif
- fmt1:
- if (! have_prec)
- prec = DEFAULT_G_PRECISION;
-#ifdef HAVE_MPFR
- fmt0:
-#endif
- chksize(fw + prec + 11); /* 11 == slop */
- cp = cpbuf;
- *cp++ = '%';
- if (lj)
- *cp++ = '-';
- if (signchar)
- *cp++ = signchar;
- if (alt)
- *cp++ = '#';
- if (zero_flag)
- *cp++ = '0';
- if (quote_flag)
- *cp++ = '\'';
-
-#if defined(LC_NUMERIC)
- if (quote_flag && ! use_lc_numeric)
- setlocale(LC_NUMERIC, "");
-#endif
-
- switch (fmt_type) {
-#ifdef HAVE_MPFR
- case MP_INT_WITH_PREC:
- sprintf(cp, "*.*Z%c", cs1);
- while ((nc = mpfr_snprintf(obufout, ofre, cpbuf,
- (int) fw, (int) prec, zi)) >= ofre)
- chksize(nc)
- break;
- case MP_INT_WITHOUT_PREC:
- sprintf(cp, "*Z%c", cs1);
- while ((nc = mpfr_snprintf(obufout, ofre, cpbuf,
- (int) fw, zi)) >= ofre)
- chksize(nc)
- break;
- case MP_FLOAT:
- sprintf(cp, "*.*R*%c", cs1);
- while ((nc = mpfr_snprintf(obufout, ofre, cpbuf,
- (int) fw, (int) prec, ROUND_MODE, mf)) >= ofre)
- chksize(nc)
- break;
-#endif
- default:
- sprintf(cp, "*.*%c", cs1);
- while ((nc = snprintf(obufout, ofre, cpbuf,
- (int) fw, (int) prec,
- (double) tmpval)) >= ofre)
- chksize(nc)
- }
-
-#if defined(LC_NUMERIC)
- if (quote_flag && ! use_lc_numeric)
- setlocale(LC_NUMERIC, "C");
-#endif
-
- len = strlen(obufout);
- ofre -= len;
- obufout += len;
- s0 = s1;
- break;
- default:
- if (do_lint && is_alpha(cs1))
- lintwarn(_("ignoring unknown format specifier character `%c': no argument converted"), cs1);
- break;
- }
- if (toofew) {
- msg("%s\n\t`%s'\n\t%*s%s",
- _("fatal: not enough arguments to satisfy format string"),
- fmt_string, (int) (s1 - fmt_string - 1), "",
- _("^ ran out for this one"));
- goto out;
- }
- }
- if (do_lint) {
- if (need_format)
- lintwarn(
- _("[s]printf: format specifier does not have control letter"));
- if (cur_arg < num_args)
- lintwarn(
- _("too many arguments supplied for format string"));
- }
- bchunk(s0, s1 - s0);
- r = make_str_node(obuf, obufout - obuf, ALREADY_MALLOCED);
- obuf = NULL;
-out:
- {
- size_t k;
- size_t count = sizeof(cpbufs)/sizeof(cpbufs[0]);
- for (k = 0; k < count; k++) {
- if (cpbufs[k].buf != cpbufs[k].stackbuf)
- efree(cpbufs[k].buf);
- }
- if (obuf != NULL)
- efree(obuf);
- }
-
- if (r == NULL)
- gawk_exit(EXIT_FATAL);
- return r;
-}
-
-
/* printf_common --- common code for sprintf and printf */
static NODE *
@@ -1710,45 +596,25 @@ do_printf(int nargs, int redirtype)
gawk_exit(EXIT_FATAL);
}
-/* do_sqrt --- do the sqrt function */
-
-NODE *
-do_sqrt(int nargs)
-{
- NODE *tmp;
- double arg;
-
- tmp = POP_SCALAR();
- if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
- lintwarn(_("sqrt: received non-numeric argument"));
- arg = (double) force_number(tmp)->numbr;
- DEREF(tmp);
- if (arg < 0.0)
- warning(_("sqrt: called with negative argument %g"), arg);
- return make_number((AWKNUM) sqrt(arg));
-}
-
/* do_substr --- do the substr function */
NODE *
do_substr(int nargs)
{
- NODE *t1;
- NODE *r;
+ NODE *t1, *t2, *t3 = NULL;
+ NODE *r = NULL;
size_t indx;
size_t length = 0;
double d_index = 0, d_length = 0;
size_t src_len;
if (nargs == 3) {
- t1 = POP_NUMBER();
- d_length = get_number_d(t1);
- DEREF(t1);
+ t3 = POP_NUMBER();
+ d_length = get_number_d(t3);
}
- t1 = POP_NUMBER();
- d_index = get_number_d(t1);
- DEREF(t1);
+ t2 = POP_NUMBER();
+ d_index = get_number_d(t2);
t1 = POP_STRING();
@@ -1758,7 +624,6 @@ do_substr(int nargs)
lintwarn(_("substr: length %g is not >= 1"), d_length);
else if (do_lint == DO_LINT_INVALID && ! (d_length >= 0))
lintwarn(_("substr: length %g is not >= 0"), d_length);
- DEREF(t1);
/*
* Return explicit null string instead of doing
* dupnode(Nnull_string) so that if the result
@@ -1766,10 +631,11 @@ do_substr(int nargs)
* and lint, no error is reported about using
* an uninitialized value. Same thing later, too.
*/
- return make_string("", 0);
+ r = make_string("", 0);
+ goto finish;
}
if (do_lint) {
- if (double_to_int(d_length) != d_length)
+ if (! isinteger(t3))
lintwarn(
_("substr: non-integer length %g will be truncated"),
d_length);
@@ -1792,7 +658,7 @@ do_substr(int nargs)
d_index);
d_index = 1;
}
- if (do_lint && double_to_int(d_index) != d_index)
+ if (do_lint && ! isinteger(t2))
lintwarn(_("substr: non-integer start index %g will be truncated"),
d_index);
@@ -1819,8 +685,8 @@ do_substr(int nargs)
/* substr("", 1, 0) produces a warning only if LINT_ALL */
if (do_lint && (do_lint == DO_LINT_ALL || ((indx | length) != 0)))
lintwarn(_("substr: source string is zero length"));
- DEREF(t1);
- return make_string("", 0);
+ r = make_string("", 0);
+ goto finish;
}
/* get total len of input string, for following checks */
@@ -1836,8 +702,8 @@ do_substr(int nargs)
if (do_lint)
lintwarn(_("substr: start index %g is past end of string"),
d_index);
- DEREF(t1);
- return make_string("", 0);
+ r = make_string("", 0);
+ goto finish;
}
if (length > src_len - indx) {
if (do_lint)
@@ -1881,6 +747,10 @@ do_substr(int nargs)
r = make_string(t1->stptr + indx, length);
#endif
+finish:
+ if (t3 != NULL)
+ DEREF(t3);
+ DEREF(t2);
DEREF(t1);
return r;
}
@@ -2346,175 +1216,6 @@ do_toupper(int nargs)
return t2;
}
-/* do_atan2 --- do the atan2 function */
-
-NODE *
-do_atan2(int nargs)
-{
- NODE *t1, *t2;
- double d1, d2;
-
- POP_TWO_SCALARS(t1, t2);
- if (do_lint) {
- if ((t1->flags & (NUMCUR|NUMBER)) == 0)
- lintwarn(_("atan2: received non-numeric first argument"));
- if ((t2->flags & (NUMCUR|NUMBER)) == 0)
- lintwarn(_("atan2: received non-numeric second argument"));
- }
- d1 = force_number(t1)->numbr;
- d2 = force_number(t2)->numbr;
- DEREF(t1);
- DEREF(t2);
- return make_number((AWKNUM) atan2(d1, d2));
-}
-
-/* do_sin --- do the sin function */
-
-NODE *
-do_sin(int nargs)
-{
- NODE *tmp;
- double d;
-
- tmp = POP_SCALAR();
- if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
- lintwarn(_("sin: received non-numeric argument"));
- d = sin((double) force_number(tmp)->numbr);
- DEREF(tmp);
- return make_number((AWKNUM) d);
-}
-
-/* do_cos --- do the cos function */
-
-NODE *
-do_cos(int nargs)
-{
- NODE *tmp;
- double d;
-
- tmp = POP_SCALAR();
- if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
- lintwarn(_("cos: received non-numeric argument"));
- d = cos((double) force_number(tmp)->numbr);
- DEREF(tmp);
- return make_number((AWKNUM) d);
-}
-
-/* do_rand --- do the rand function */
-
-static bool firstrand = true;
-/* Some systems require this array to be integer aligned. Sigh. */
-#define SIZEOF_STATE 256
-static uint32_t istate[SIZEOF_STATE/sizeof(uint32_t)];
-static char *const state = (char *const) istate;
-
-/* ARGSUSED */
-NODE *
-do_rand(int nargs ATTRIBUTE_UNUSED)
-{
- double tmprand;
-#define RAND_DIVISOR ((double)GAWK_RANDOM_MAX+1.0)
- if (firstrand) {
- (void) initstate((unsigned) 1, state, SIZEOF_STATE);
- /* don't need to srandom(1), initstate() does it for us. */
- firstrand = false;
- setstate(state);
- }
- /*
- * Per historical practice and POSIX, return value N is
- *
- * 0 <= n < 1
- */
- /*
- * Date: Wed, 28 Aug 2013 17:52:46 -0700
- * From: Bob Jewett <jewett@bill.scs.agilent.com>
- *
- * Call random() twice to fill in more bits in the value
- * of the double. Also, there is a bug in random() such
- * that when the values of successive values are combined
- * like (rand1*rand2)^2, (rand3*rand4)^2, ... the
- * resulting time series is not white noise. The
- * following also seems to fix that bug.
- *
- * The add/subtract 0.5 keeps small bits from filling
- * below 2^-53 in the double, not that anyone should be
- * looking down there.
- *
- * Date: Wed, 25 Sep 2013 10:45:38 -0600 (MDT)
- * From: "Nelson H. F. Beebe" <beebe@math.utah.edu>
- * (4) The code is typical of many published fragments for converting
- * from integer to floating-point, and I discuss the serious pitfalls
- * in my book, because it leads to platform-dependent behavior at the
- * end points of the interval [0,1]
- *
- * (5) the documentation in the gawk info node says
- *
- * `rand()'
- * Return a random number. The values of `rand()' are uniformly
- * distributed between zero and one. The value could be zero but is
- * never one.(1)
- *
- * The division by RAND_DIVISOR may not guarantee that 1.0 is never
- * returned: the programmer forgot the platform-dependent issue of
- * rounding.
- *
- * For points 4 and 5, the safe way is a loop:
- *
- * double
- * rand(void) // return value in [0.0, 1.0)
- * {
- * value = internal_rand();
- *
- * while (value == 1.0)
- * value = internal_rand();
- *
- * return (value);
- * }
- */
-
- do {
- long d1, d2;
- /*
- * Do the calls in predictable order to avoid
- * compiler differences in order of evaluation.
- */
- d1 = random();
- d2 = random();
- tmprand = 0.5 + ( (d1/RAND_DIVISOR + d2) / RAND_DIVISOR );
- tmprand -= 0.5;
- } while (tmprand == 1.0);
-
- return make_number((AWKNUM) tmprand);
-}
-
-/* do_srand --- seed the random number generator */
-
-NODE *
-do_srand(int nargs)
-{
- NODE *tmp;
- static long save_seed = 1;
- long ret = save_seed; /* SVR4 awk srand returns previous seed */
-
- if (firstrand) {
- (void) initstate((unsigned) 1, state, SIZEOF_STATE);
- /* don't need to srandom(1), we're changing the seed below */
- firstrand = false;
- (void) setstate(state);
- }
-
- if (nargs == 0)
- srandom((unsigned int) (save_seed = (long) time((time_t *) 0)));
- else {
- tmp = POP_SCALAR();
- if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
- lintwarn(_("srand: received non-numeric argument"));
- srandom((unsigned int) (save_seed = (long) force_number(tmp)->numbr));
- DEREF(tmp);
- }
- return make_number((AWKNUM) ret);
-}
-
/* do_match --- match a regexp, set RSTART and RLENGTH,
* optional third arg is array filled with text of
* subpatterns enclosed in parens and start and len info.
@@ -3094,316 +1795,6 @@ done:
}
-/* make_integer - Convert an integer to a number node. */
-
-static NODE *
-make_integer(uintmax_t n)
-{
- n = adjust_uint(n);
-
- return make_number((AWKNUM) n);
-}
-
-/* do_lshift --- perform a << operation */
-
-NODE *
-do_lshift(int nargs)
-{
- NODE *s1, *s2;
- uintmax_t uval, ushift, res;
- AWKNUM val, shift;
-
- POP_TWO_SCALARS(s1, s2);
- if (do_lint) {
- if ((s1->flags & (NUMCUR|NUMBER)) == 0)
- lintwarn(_("lshift: received non-numeric first argument"));
- if ((s2->flags & (NUMCUR|NUMBER)) == 0)
- lintwarn(_("lshift: received non-numeric second argument"));
- }
- val = force_number(s1)->numbr;
- shift = force_number(s2)->numbr;
- if (do_lint) {
- if (val < 0 || shift < 0)
- lintwarn(_("lshift(%f, %f): negative values will give strange results"), val, shift);
- if (double_to_int(val) != val || double_to_int(shift) != shift)
- lintwarn(_("lshift(%f, %f): fractional values will be truncated"), val, shift);
- if (shift >= sizeof(uintmax_t) * CHAR_BIT)
- lintwarn(_("lshift(%f, %f): too large shift value will give strange results"), val, shift);
- }
-
- DEREF(s1);
- DEREF(s2);
-
- uval = (uintmax_t) val;
- ushift = (uintmax_t) shift;
-
- res = uval << ushift;
- return make_integer(res);
-}
-
-/* do_rshift --- perform a >> operation */
-
-NODE *
-do_rshift(int nargs)
-{
- NODE *s1, *s2;
- uintmax_t uval, ushift, res;
- AWKNUM val, shift;
-
- POP_TWO_SCALARS(s1, s2);
- if (do_lint) {
- if ((s1->flags & (NUMCUR|NUMBER)) == 0)
- lintwarn(_("rshift: received non-numeric first argument"));
- if ((s2->flags & (NUMCUR|NUMBER)) == 0)
- lintwarn(_("rshift: received non-numeric second argument"));
- }
- val = force_number(s1)->numbr;
- shift = force_number(s2)->numbr;
- if (do_lint) {
- if (val < 0 || shift < 0)
- lintwarn(_("rshift(%f, %f): negative values will give strange results"), val, shift);
- if (double_to_int(val) != val || double_to_int(shift) != shift)
- lintwarn(_("rshift(%f, %f): fractional values will be truncated"), val, shift);
- if (shift >= sizeof(uintmax_t) * CHAR_BIT)
- lintwarn(_("rshift(%f, %f): too large shift value will give strange results"), val, shift);
- }
-
- DEREF(s1);
- DEREF(s2);
-
- uval = (uintmax_t) val;
- ushift = (uintmax_t) shift;
-
- res = uval >> ushift;
- return make_integer(res);
-}
-
-/* do_and --- perform an & operation */
-
-NODE *
-do_and(int nargs)
-{
- NODE *s1;
- uintmax_t res, uval;
- AWKNUM val;
- int i;
-
- res = ~0; /* start off with all ones */
- if (nargs < 2)
- fatal(_("and: called with less than two arguments"));
-
- for (i = 1; nargs > 0; nargs--, i++) {
- s1 = POP_SCALAR();
- if (do_lint && (s1->flags & (NUMCUR|NUMBER)) == 0)
- lintwarn(_("and: argument %d is non-numeric"), i);
-
- val = force_number(s1)->numbr;
- if (do_lint && val < 0)
- lintwarn(_("and: argument %d negative value %g will give strange results"), i, val);
-
- uval = (uintmax_t) val;
- res &= uval;
-
- DEREF(s1);
- }
-
- return make_integer(res);
-}
-
-/* do_or --- perform an | operation */
-
-NODE *
-do_or(int nargs)
-{
- NODE *s1;
- uintmax_t res, uval;
- AWKNUM val;
- int i;
-
- res = 0;
- if (nargs < 2)
- fatal(_("or: called with less than two arguments"));
-
- for (i = 1; nargs > 0; nargs--, i++) {
- s1 = POP_SCALAR();
- if (do_lint && (s1->flags & (NUMCUR|NUMBER)) == 0)
- lintwarn(_("or: argument %d is non-numeric"), i);
-
- val = force_number(s1)->numbr;
- if (do_lint && val < 0)
- lintwarn(_("or: argument %d negative value %g will give strange results"), i, val);
-
- uval = (uintmax_t) val;
- res |= uval;
-
- DEREF(s1);
- }
-
- return make_integer(res);
-}
-
-/* do_xor --- perform an ^ operation */
-
-NODE *
-do_xor(int nargs)
-{
- NODE *s1;
- uintmax_t res, uval;
- AWKNUM val;
- int i;
-
- if (nargs < 2)
- fatal(_("xor: called with less than two arguments"));
-
- res = 0; /* silence compiler warning */
- for (i = 1; nargs > 0; nargs--, i++) {
- s1 = POP_SCALAR();
- if (do_lint && (s1->flags & (NUMCUR|NUMBER)) == 0)
- lintwarn(_("xor: argument %d is non-numeric"), i);
-
- val = force_number(s1)->numbr;
- if (do_lint && val < 0)
- lintwarn(_("xor: argument %d negative value %g will give strange results"), i, val);
-
- uval = (uintmax_t) val;
- if (i == 1)
- res = uval;
- else
- res ^= uval;
-
- DEREF(s1);
- }
-
- return make_integer(res);
-}
-
-/* do_compl --- perform a ~ operation */
-
-NODE *
-do_compl(int nargs)
-{
- NODE *tmp;
- double d;
- uintmax_t uval;
-
- tmp = POP_SCALAR();
- if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
- lintwarn(_("compl: received non-numeric argument"));
- d = force_number(tmp)->numbr;
- DEREF(tmp);
-
- if (do_lint) {
- if (d < 0)
- lintwarn(_("compl(%f): negative value will give strange results"), d);
- if (double_to_int(d) != d)
- lintwarn(_("compl(%f): fractional value will be truncated"), d);
- }
-
- uval = (uintmax_t) d;
- uval = ~ uval;
- return make_integer(uval);
-}
-
-/* do_strtonum --- the strtonum function */
-
-NODE *
-do_strtonum(int nargs)
-{
- NODE *tmp;
- AWKNUM d;
-
- tmp = POP_SCALAR();
- if ((tmp->flags & (NUMBER|NUMCUR)) != 0)
- d = (AWKNUM) force_number(tmp)->numbr;
- else if (get_numbase(tmp->stptr, use_lc_numeric) != 10)
- d = nondec2awknum(tmp->stptr, tmp->stlen);
- else
- d = (AWKNUM) force_number(tmp)->numbr;
-
- DEREF(tmp);
- return make_number((AWKNUM) d);
-}
-
-/* nondec2awknum --- convert octal or hex value to double */
-
-/*
- * Because of awk's concatenation rules and the way awk.y:yylex()
- * collects a number, this routine has to be willing to stop on the
- * first invalid character.
- */
-
-AWKNUM
-nondec2awknum(char *str, size_t len)
-{
- AWKNUM retval = 0.0;
- char save;
- short val;
- char *start = str;
-
- if (*str == '0' && (str[1] == 'x' || str[1] == 'X')) {
- /*
- * User called strtonum("0x") or some such,
- * so just quit early.
- */
- if (len <= 2)
- return (AWKNUM) 0.0;
-
- for (str += 2, len -= 2; len > 0; len--, str++) {
- switch (*str) {
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- val = *str - '0';
- break;
- case 'a':
- case 'b':
- case 'c':
- case 'd':
- case 'e':
- case 'f':
- val = *str - 'a' + 10;
- break;
- case 'A':
- case 'B':
- case 'C':
- case 'D':
- case 'E':
- case 'F':
- val = *str - 'A' + 10;
- break;
- default:
- goto done;
- }
- retval = (retval * 16) + val;
- }
- } else if (*str == '0') {
- for (; len > 0; len--) {
- if (! isdigit((unsigned char) *str))
- goto done;
- else if (*str == '8' || *str == '9') {
- str = start;
- goto decimal;
- }
- retval = (retval * 8) + (*str - '0');
- str++;
- }
- } else {
-decimal:
- save = str[len];
- retval = strtod(str, NULL);
- str[len] = save;
- }
-done:
- return retval;
-}
-
/* do_dcgettext, do_dcngettext --- handle i18n translations */
#if ENABLE_NLS && defined(LC_MESSAGES) && HAVE_DCGETTEXT
@@ -3537,7 +1928,6 @@ do_dcngettext(int nargs)
NODE *tmp, *t1, *t2, *t3;
char *string1, *string2;
unsigned long number;
- AWKNUM d;
char *the_result;
#if ENABLE_NLS && defined(LC_MESSAGES) && HAVE_DCGETTEXT
@@ -3569,10 +1959,9 @@ do_dcngettext(int nargs)
#endif
t2 = POP_NUMBER(); /* third argument */
- d = get_number_d(t2);
+ number = get_number_ui(t2);
DEREF(t2);
- number = (unsigned long) double_to_int(d);
t2 = POP_STRING(); /* second argument */
string2 = t2->stptr;
t1 = POP_STRING(); /* first argument */
@@ -3632,134 +2021,3 @@ do_bindtextdomain(int nargs)
return make_string(the_result, strlen(the_result));
}
-
-/* do_div --- do integer division, return quotient and remainder in dest array */
-
-/*
- * We define the semantics as:
- * numerator = int(numerator)
- * denominator = int(denonmator)
- * quotient = int(numerator / denomator)
- * remainder = int(numerator % denomator)
- */
-
-NODE *
-do_div(int nargs)
-{
- NODE *numerator, *denominator, *result;
- double num, denom, quotient, remainder;
- NODE *sub, **lhs;
-
- result = POP_PARAM();
- if (result->type != Node_var_array)
- fatal(_("div: third argument is not an array"));
- assoc_clear(result);
-
- denominator = POP_SCALAR();
- numerator = POP_SCALAR();
-
- if (do_lint) {
- if ((numerator->flags & (NUMCUR|NUMBER)) == 0)
- lintwarn(_("div: received non-numeric first argument"));
- if ((denominator->flags & (NUMCUR|NUMBER)) == 0)
- lintwarn(_("div: received non-numeric second argument"));
- }
-
- (void) force_number(numerator);
- (void) force_number(denominator);
- num = double_to_int(get_number_d(numerator));
- denom = double_to_int(get_number_d(denominator));
-
- if (denom == 0.0)
- fatal(_("div: division by zero attempted"));
-
- quotient = double_to_int(num / denom);
- /*
- * FIXME: This code is duplicated, factor it out to a
- * separate function.
- */
-#ifdef HAVE_FMOD
- remainder = fmod(num, denom);
-#else /* ! HAVE_FMOD */
- (void) modf(num / denom, & remainder);
- remainder = num - remainder * denom;
-#endif /* ! HAVE_FMOD */
- remainder = double_to_int(remainder);
-
- sub = make_string("quotient", 8);
- lhs = assoc_lookup(result, sub);
- unref(*lhs);
- *lhs = make_number((AWKNUM) quotient);
-
- sub = make_string("remainder", 9);
- lhs = assoc_lookup(result, sub);
- unref(*lhs);
- *lhs = make_number((AWKNUM) remainder);
-
- return make_number((AWKNUM) 0.0);
-}
-
-
-/* mbc_byte_count --- return number of bytes for corresponding numchars multibyte characters */
-
-static size_t
-mbc_byte_count(const char *ptr, size_t numchars)
-{
-#if MBS_SUPPORT
- mbstate_t cur_state;
- size_t sum = 0;
- int mb_len;
-
- memset(& cur_state, 0, sizeof(cur_state));
-
- assert(gawk_mb_cur_max > 1);
- mb_len = mbrlen(ptr, numchars * gawk_mb_cur_max, &cur_state);
- if (mb_len <= 0)
- return numchars; /* no valid m.b. char */
-
- for (; numchars > 0; numchars--) {
- mb_len = mbrlen(ptr, numchars * gawk_mb_cur_max, &cur_state);
- if (mb_len <= 0)
- break;
- sum += mb_len;
- ptr += mb_len;
- }
-
- return sum;
-#else
- return numchars;
-#endif
-}
-
-/* mbc_char_count --- return number of m.b. chars in string, up to numbytes bytes */
-
-static size_t
-mbc_char_count(const char *ptr, size_t numbytes)
-{
-#if MBS_SUPPORT
- mbstate_t cur_state;
- size_t sum = 0;
- int mb_len;
-
- if (gawk_mb_cur_max == 1)
- return numbytes;
-
- memset(& cur_state, 0, sizeof(cur_state));
-
- mb_len = mbrlen(ptr, numbytes * gawk_mb_cur_max, &cur_state);
- if (mb_len <= 0)
- return numbytes; /* no valid m.b. char */
-
- for (; numbytes > 0; numbytes--) {
- mb_len = mbrlen(ptr, numbytes * gawk_mb_cur_max, &cur_state);
- if (mb_len <= 0)
- break;
- sum++;
- ptr += mb_len;
- }
-
- return sum;
-#else
- return numbytes;
-#endif
-}
diff --git a/command.c b/command.c
index ad0dc372..a5ed47bf 100644
--- a/command.c
+++ b/command.c
@@ -2181,7 +2181,7 @@ yyreduce:
if ((n->flags & NUMBER) == 0)
yyerror(_("non-numeric value found, numeric expected"));
else
- negate_num(n);
+ numbr_hndlr->gawk_negate_number(n);
(yyval) = (yyvsp[0]);
}
#line 2188 "command.c" /* yacc.c:1646 */
@@ -2995,24 +2995,9 @@ err:
if (isdigit((unsigned char) tokstart[0])) {
NODE *r = NULL;
- errno = 0;
-#ifdef HAVE_MPFR
- if (do_mpfr) {
- int tval;
- r = mpg_float();
- tval = mpfr_strtofr(r->mpg_numbr, tokstart, & lexptr, 0, ROUND_MODE);
- IEEE_FMT(r->mpg_numbr, tval);
- if (mpfr_integer_p(r->mpg_numbr)) {
- /* integral value, convert to a GMP type. */
- NODE *tmp = r;
- r = mpg_integer();
- mpfr_get_z(r->mpg_i, tmp->mpg_numbr, MPFR_RNDZ);
- unref(tmp);
- }
- } else
-#endif
- r = make_number(strtod(tokstart, & lexptr));
-
+ /* XXX: not accepting a hex or octal number, maybe should? */
+
+ r = str2node(tokstart, & lexptr, 0, false);
if (errno != 0) {
yyerror(strerror(errno));
unref(r);
@@ -3212,7 +3197,8 @@ do_help(CMDARG *arg, int cmd)
#ifdef HAVE_LIBREADLINE
-/* next_word --- find the next word in a line to complete
+/*
+ * next_word --- find the next word in a line to complete
* (word seperation characters are space and tab).
*/
@@ -3238,9 +3224,11 @@ next_word(char *p, int len, char **endp)
return p;
}
-/* command_completion --- attempt to complete based on the word number in line;
- * try to complete on command names if this is the first word; for the next
- * word(s), the type of completion depends on the command name (first word).
+
+/*
+ * command_completion --- attempt to complete based on the word number in line;
+ * try to complete on command names if this is the first word; for the next
+ * word(s), the type of completion depends on the command name (first word).
*/
#ifndef RL_READLINE_VERSION /* < 4.2a */
diff --git a/command.y b/command.y
index c67753b7..a8942513 100644
--- a/command.y
+++ b/command.y
@@ -686,7 +686,7 @@ node
if ((n->flags & NUMBER) == 0)
yyerror(_("non-numeric value found, numeric expected"));
else
- negate_num(n);
+ numbr_hndlr->gawk_negate_number(n);
$$ = $2;
}
;
@@ -1244,24 +1244,9 @@ err:
if (isdigit((unsigned char) tokstart[0])) {
NODE *r = NULL;
- errno = 0;
-#ifdef HAVE_MPFR
- if (do_mpfr) {
- int tval;
- r = mpg_float();
- tval = mpfr_strtofr(r->mpg_numbr, tokstart, & lexptr, 0, ROUND_MODE);
- IEEE_FMT(r->mpg_numbr, tval);
- if (mpfr_integer_p(r->mpg_numbr)) {
- /* integral value, convert to a GMP type. */
- NODE *tmp = r;
- r = mpg_integer();
- mpfr_get_z(r->mpg_i, tmp->mpg_numbr, MPFR_RNDZ);
- unref(tmp);
- }
- } else
-#endif
- r = make_number(strtod(tokstart, & lexptr));
-
+ /* XXX: not accepting a hex or octal number, maybe should? */
+
+ r = str2node(tokstart, & lexptr, 0, false);
if (errno != 0) {
yyerror(strerror(errno));
unref(r);
@@ -1461,7 +1446,8 @@ do_help(CMDARG *arg, int cmd)
#ifdef HAVE_LIBREADLINE
-/* next_word --- find the next word in a line to complete
+/*
+ * next_word --- find the next word in a line to complete
* (word seperation characters are space and tab).
*/
@@ -1487,9 +1473,11 @@ next_word(char *p, int len, char **endp)
return p;
}
-/* command_completion --- attempt to complete based on the word number in line;
- * try to complete on command names if this is the first word; for the next
- * word(s), the type of completion depends on the command name (first word).
+
+/*
+ * command_completion --- attempt to complete based on the word number in line;
+ * try to complete on command names if this is the first word; for the next
+ * word(s), the type of completion depends on the command name (first word).
*/
#ifndef RL_READLINE_VERSION /* < 4.2a */
diff --git a/debug.c b/debug.c
index 5d7db01b..d129c4e3 100644
--- a/debug.c
+++ b/debug.c
@@ -40,6 +40,7 @@ extern FILE *output_fp;
extern IOBUF *curfile;
extern const char *command_file;
extern const char *get_spec_varname(Func_ptr fptr);
+extern NODE *format_tree(const char *, size_t, NODE **, long); /* format.c */
extern int zzparse(void);
#define read_command() (void) zzparse()
@@ -3676,27 +3677,13 @@ print_memory(NODE *m, NODE *func, Func_print print_func, FILE *fp)
case Node_val:
if (m == Nnull_string)
print_func(fp, "Nnull_string");
- else if ((m->flags & NUMBER) != 0) {
-#ifdef HAVE_MPFR
- if ((m->flags & MPFN) != 0)
- print_func(fp, "%s", mpg_fmt("%R*g", ROUND_MODE, m->mpg_numbr));
- else if ((m->flags & MPZN) != 0)
- print_func(fp, "%s", mpg_fmt("%Zd", m->mpg_i));
- else
-#endif
- print_func(fp, "%g", m->numbr);
- } else if ((m->flags & STRING) != 0)
+ else if ((m->flags & NUMBER) != 0)
+ print_func(fp, "%s", fmt_number("%0.17g", m));
+ else if ((m->flags & STRING) != 0)
pp_string_fp(print_func, fp, m->stptr, m->stlen, '"', false);
- else if ((m->flags & NUMCUR) != 0) {
-#ifdef HAVE_MPFR
- if ((m->flags & MPFN) != 0)
- print_func(fp, "%s", mpg_fmt("%R*g", ROUND_MODE, m->mpg_numbr));
- else if ((m->flags & MPZN) != 0)
- print_func(fp, "%s", mpg_fmt("%Zd", m->mpg_i));
- else
-#endif
- print_func(fp, "%g", m->numbr);
- } else if ((m->flags & STRCUR) != 0)
+ else if ((m->flags & NUMCUR) != 0)
+ print_func(fp, "%s", fmt_number("%0.17g", m));
+ else if ((m->flags & STRCUR) != 0)
pp_string_fp(print_func, fp, m->stptr, m->stlen, '"', false);
else
print_func(fp, "-?-");
@@ -3988,12 +3975,6 @@ print_instruction(INSTRUCTION *pc, Func_print print_func, FILE *fp, int in_dump)
case Op_match_rec:
case Op_match:
case Op_nomatch:
- case Op_plus_i:
- case Op_minus_i:
- case Op_times_i:
- case Op_exp_i:
- case Op_quotient_i:
- case Op_mod_i:
case Op_assign_concat:
print_memory(pc->memory, func, print_func, fp);
/* fall through */
diff --git a/double.c b/double.c
new file mode 100644
index 00000000..cfb2fbf9
--- /dev/null
+++ b/double.c
@@ -0,0 +1,1641 @@
+/*
+ * double.c - routines for C double support in gawk.
+ */
+
+/*
+ * Copyright (C) 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
+ */
+
+#include "awk.h"
+#include <math.h>
+#include "random.h"
+#include "floatmagic.h" /* definition of isnan */
+
+#include "format.h"
+
+/* Can declare these, since we always use the random shipped with gawk */
+extern char *initstate(unsigned long seed, char *state, long n);
+extern char *setstate(char *state);
+extern long random(void);
+extern void srandom(unsigned long seed);
+
+/*
+ * Since we supply the version of random(), we know what
+ * value to use here.
+ */
+#define GAWK_RANDOM_MAX 0x7fffffffL
+
+/* exported routines */
+
+static NODE *make_awknum(AWKNUM);
+static int cmp_awknums(const NODE *, const NODE *);
+static void negate_awknum(NODE *);
+static NODE *str2awknum(char *, char **, int, bool);
+static NODE *force_awknum(NODE *);
+static NODE *format_awknum_val(const char *, int, NODE *);
+static unsigned long awknum_toulong(const NODE *);
+static long awknum_tolong(const NODE *);
+static double awknum_todouble(const NODE *);
+static uintmax_t awknum_touintmax_t(const NODE *);
+static int awknum_sgn(const NODE *);
+static bool awknum_isinteger(const NODE *);
+static bool awknum_isnan(const NODE *);
+static bool awknum_isinf(const NODE *);
+static NODE *awknum_copy(const NODE *);
+static int format_awknum_printf(NODE *, struct format_spec *, struct print_fmt_buf *);
+static bool awknum_init(bltin_t **);
+static NODE *awknum_add(const NODE *, const NODE *);
+static NODE *awknum_sub(const NODE *, const NODE *);
+static NODE *awknum_mul(const NODE *, const NODE *);
+static NODE *awknum_div(const NODE *, const NODE *);
+static NODE *awknum_mod(const NODE *, const NODE *);
+static NODE *awknum_pow(const NODE *, const NODE *);
+static NODE *awknum_add_long(const NODE *, long);
+static NODE *awknum_update_var(NODE *);
+static void awknum_set_var(const NODE *);
+static long awknum_increment_var(const NODE *, long);
+static void awknum_init_vars(void);
+
+static NODE *do_and(int);
+static NODE *do_atan2(int);
+static NODE *do_compl(int);
+static NODE *do_cos(int);
+static NODE *do_exp(int);
+static NODE *do_int(int);
+static NODE *do_log(int);
+static NODE *do_lshift(int);
+static NODE *do_or(int);
+static NODE *do_rand(int);
+static NODE *do_rshift(int);
+static NODE *do_sin(int);
+static NODE *do_sqrt(int);
+static NODE *do_srand(int);
+static NODE *do_strtonum(int);
+static NODE *do_xor(int);
+
+/* internal routines */
+static double double_to_int(double d);
+static int is_ieee_magic_val(const char *val);
+static AWKNUM get_ieee_magic_val(const char *val);
+static AWKNUM calc_exp(AWKNUM x1, AWKNUM x2);
+
+
+numbr_handler_t awknum_hndlr = {
+ awknum_init,
+ NULL, /* version_str */
+ NULL, /* load_procinfo */
+ make_awknum,
+ str2awknum,
+ awknum_copy,
+ NULL, /* free_awknum --- not needed for AWKNUM */
+ force_awknum,
+ negate_awknum,
+ cmp_awknums,
+ awknum_sgn,
+ awknum_isinteger,
+ awknum_isnan,
+ awknum_isinf,
+ format_awknum_val,
+ format_awknum_printf,
+ awknum_todouble,
+ awknum_tolong,
+ awknum_toulong,
+ awknum_touintmax_t,
+ awknum_add,
+ awknum_sub,
+ awknum_mul,
+ awknum_div,
+ awknum_mod,
+ awknum_pow,
+ awknum_add_long,
+ awknum_update_var,
+ awknum_set_var,
+ awknum_increment_var,
+ awknum_init_vars,
+};
+
+/* awknum_init --- initialization routine */
+
+static bool
+awknum_init(bltin_t **numbr_bltins)
+{
+ static bltin_t awknum_bltins[] = {
+ { "and", do_and },
+ { "atan2", do_atan2 },
+ { "compl", do_compl },
+ { "cos", do_cos },
+ { "div", do_div },
+ { "exp", do_exp },
+ { "int", do_int },
+ { "log", do_log },
+ { "lshift", do_lshift },
+ { "or", do_or },
+ { "rand", do_rand },
+ { "rshift", do_rshift },
+ { "sin", do_sin },
+ { "sqrt", do_sqrt },
+ { "srand", do_srand },
+ { "strtonum", do_strtonum },
+ { "xor", do_xor },
+ { NULL, NULL },
+ };
+
+ /* set the numeric value of null string */
+ Nnull_string->numbr = 0.0;
+ Nnull_string->flags |= (NUMCUR|NUMBER);
+
+ /* initialize TRUE and FALSE nodes */
+ false_node = make_awknum(0.0);
+ true_node = make_awknum(1.0);
+ false_node->flags |= NUMINT;
+ true_node->flags |= NUMINT;
+
+ *numbr_bltins = awknum_bltins;
+ return true;
+}
+
+/* awknum_toulong --- conversion to unsigned long */
+
+static unsigned long
+awknum_toulong(const NODE *n)
+{
+ return n->numbr;
+}
+
+/* awknum_tolong --- conversion to long */
+
+static long
+awknum_tolong(const NODE *n)
+{
+ return n->numbr;
+}
+
+/* awknum_todouble --- conversion to AWKNUM */
+
+static double
+awknum_todouble(const NODE *n)
+{
+ return n->numbr;
+}
+
+/* awknum_touintmax_t --- conversion to uintmax_t */
+
+static uintmax_t
+awknum_touintmax_t(const NODE *n)
+{
+ return n->numbr;
+}
+
+/* awknum_sgn --- return 1 if number > 0, zero if number == 0, and -1 if number < 0 */
+
+static int
+awknum_sgn(const NODE *n)
+{
+ return (n->numbr < 0.0 ? -1 : n->numbr > 0.0);
+}
+
+/* awknum_isinteger --- check if a number is an integer */
+
+static bool
+awknum_isinteger(const NODE *n)
+{
+ if (isnan(n->numbr) || isinf(n->numbr))
+ return false;
+ return double_to_int(n->numbr) == n->numbr;
+}
+
+/* awknum_isnan --- check if number is NaN */
+
+static bool
+awknum_isnan(const NODE *n)
+{
+ return isnan(n->numbr);
+}
+
+/* awknum_isinf --- check if number is infinity */
+
+static bool
+awknum_isinf(const NODE *n)
+{
+ return isinf(n->numbr);
+}
+
+
+/* negate_awknum --- negate AWKNUM in NODE */
+
+static void
+negate_awknum(NODE *n)
+{
+ n->numbr = - n->numbr;
+}
+
+/* awknum_add --- add two numbers */
+
+static NODE *
+awknum_add(const NODE *t1, const NODE *t2)
+{
+ return make_awknum(t1->numbr + t2->numbr);
+}
+
+/* awknum_sub --- subtract two numbers */
+
+static NODE *
+awknum_sub(const NODE *t1, const NODE *t2)
+{
+ return make_awknum(t1->numbr - t2->numbr);
+}
+
+/* awknum_mul --- multiply two numbers */
+
+static NODE *
+awknum_mul(const NODE *t1, const NODE *t2)
+{
+ return make_awknum(t1->numbr * t2->numbr);
+}
+
+/* awknum_add --- quotient of two numbers */
+
+static NODE *
+awknum_div(const NODE *t1, const NODE *t2)
+{
+ if (t2->numbr == 0)
+ fatal(_("division by zero attempted"));
+ return make_awknum(t1->numbr / t2->numbr);
+}
+
+/* awknum_add_long --- add long value to a number */
+
+static NODE *
+awknum_add_long(const NODE *t1, long n)
+{
+ return make_awknum(t1->numbr + n);
+}
+
+/* awknum_copy --- copy a number */
+
+static NODE *
+awknum_copy(const NODE *t1)
+{
+ return make_awknum(t1->numbr);
+}
+
+/* awknum_update_var --- update a special variable from internal variables */
+
+static NODE *
+awknum_update_var(NODE *var)
+{
+ NODE *val = var->var_value;
+
+ if (var == NR_node) {
+ if (val->numbr != NR) {
+ unref(val);
+ val = NR_node->var_value = make_awknum(NR);
+ }
+ return val;
+ }
+
+ assert(var == FNR_node);
+ if (val->numbr != FNR) {
+ unref(val);
+ val = FNR_node->var_value = make_awknum(FNR);
+ }
+ return val;
+}
+
+/*
+ * awknum_set_vars --- update internal variables for assignment
+ * to a special variable.
+ */
+
+static void
+awknum_set_var(const NODE *var)
+{
+ NODE *val = var->var_value;
+ if (var == NR_node)
+ NR = val->numbr;
+ else if (var == FNR_node)
+ FNR = val->numbr;
+ else {
+ /* PREC and ROUNMODE */
+ if (do_lint)
+ lintwarn(_("setting `%s' has no effect"),
+ var == PREC_node ? "PREC" : "ROUNDMODE");
+ }
+}
+
+/* awknum_increment_var --- increment NR or FNR */
+
+static long
+awknum_increment_var(const NODE *var ATTRIBUTE_UNUSED, long nr)
+{
+ /* var == (F)NR_node */
+ return ++nr;
+}
+
+/* awknum_init_vars --- initialize special variables */
+
+static void
+awknum_init_vars()
+{
+ unref(PREC_node->var_value);
+ PREC_node->var_value = make_awknum(DBL_MANT_DIG);
+ PREC_node->var_value->flags |= NUMINT;
+ unref(ROUNDMODE_node->var_value);
+ ROUNDMODE_node->var_value = make_string("N", 1);
+}
+
+/* make_awknum --- allocate a node with defined number */
+
+static NODE *
+make_awknum(AWKNUM x)
+{
+ NODE *r;
+ getnode(r);
+ r->type = Node_val;
+ r->numbr = x;
+ r->flags = MALLOC|NUMBER|NUMCUR;
+ r->valref = 1;
+ r->stptr = NULL;
+ r->stlen = 0;
+#if MBS_SUPPORT
+ r->wstptr = NULL;
+ r->wstlen = 0;
+#endif /* defined MBS_SUPPORT */
+ return r;
+}
+
+/* make_integer - Convert an integer to a number node. */
+
+static inline NODE *
+make_integer(uintmax_t n)
+{
+ n = adjust_uint(n);
+ return make_awknum(n);
+}
+
+/* do_lshift --- perform a << operation */
+
+static NODE *
+do_lshift(int nargs)
+{
+ NODE *s1, *s2;
+ uintmax_t uval, ushift, res;
+ AWKNUM val, shift;
+
+ s2 = POP_SCALAR();
+ s1 = POP_SCALAR();
+ if (do_lint) {
+ if ((s1->flags & (NUMCUR|NUMBER)) == 0)
+ lintwarn(_("lshift: received non-numeric first argument"));
+ if ((s2->flags & (NUMCUR|NUMBER)) == 0)
+ lintwarn(_("lshift: received non-numeric second argument"));
+ }
+ val = force_number(s1)->numbr;
+ shift = force_number(s2)->numbr;
+ if (do_lint) {
+ if (val < 0 || shift < 0)
+ lintwarn(_("lshift(%f, %f): negative values will give strange results"),
+ (double) val, (double) shift);
+ if (double_to_int(val) != val || double_to_int(shift) != shift)
+ lintwarn(_("lshift(%f, %f): fractional values will be truncated"),
+ (double) val, (double) shift);
+ if (shift >= sizeof(uintmax_t) * CHAR_BIT)
+ lintwarn(_("lshift(%f, %f): too large shift value will give strange results"),
+ (double) val, (double) shift);
+ }
+
+ DEREF(s1);
+ DEREF(s2);
+
+ uval = (uintmax_t) val;
+ ushift = (uintmax_t) shift;
+
+ res = uval << ushift;
+ return make_integer(res);
+}
+
+/* do_rshift --- perform a >> operation */
+
+static NODE *
+do_rshift(int nargs)
+{
+ NODE *s1, *s2;
+ uintmax_t uval, ushift, res;
+ AWKNUM val, shift;
+
+ s2 = POP_SCALAR();
+ s1 = POP_SCALAR();
+ if (do_lint) {
+ if ((s1->flags & (NUMCUR|NUMBER)) == 0)
+ lintwarn(_("rshift: received non-numeric first argument"));
+ if ((s2->flags & (NUMCUR|NUMBER)) == 0)
+ lintwarn(_("rshift: received non-numeric second argument"));
+ }
+ val = force_number(s1)->numbr;
+ shift = force_number(s2)->numbr;
+ if (do_lint) {
+ if (val < 0 || shift < 0)
+ lintwarn(_("rshift(%f, %f): negative values will give strange results"),
+ (double) val, (double) shift);
+ if (double_to_int(val) != val || double_to_int(shift) != shift)
+ lintwarn(_("rshift(%f, %f): fractional values will be truncated"),
+ (double) val, (double) shift);
+ if (shift >= sizeof(uintmax_t) * CHAR_BIT)
+ lintwarn(_("rshift(%f, %f): too large shift value will give strange results"),
+ (double) val, (double) shift);
+ }
+
+ DEREF(s1);
+ DEREF(s2);
+
+ uval = (uintmax_t) val;
+ ushift = (uintmax_t) shift;
+
+ res = uval >> ushift;
+ return make_integer(res);
+}
+
+/* do_and --- perform an & operation */
+
+static NODE *
+do_and(int nargs)
+{
+ NODE *s1;
+ uintmax_t res, uval;
+ AWKNUM val;
+ int i;
+
+ res = ~0; /* start off with all ones */
+ if (nargs < 2)
+ fatal(_("and: called with less than two arguments"));
+
+ for (i = 1; nargs > 0; nargs--, i++) {
+ s1 = POP_SCALAR();
+ if (do_lint && (s1->flags & (NUMCUR|NUMBER)) == 0)
+ lintwarn(_("and: argument %d is non-numeric"), i);
+
+ val = force_number(s1)->numbr;
+ if (do_lint && val < 0)
+ lintwarn(_("and: argument %d negative value %g will give strange results"),
+ i, (double) val);
+
+ uval = (uintmax_t) val;
+ res &= uval;
+
+ DEREF(s1);
+ }
+
+ return make_integer(res);
+}
+
+/* do_or --- perform an | operation */
+
+static NODE *
+do_or(int nargs)
+{
+ NODE *s1;
+ uintmax_t res, uval;
+ AWKNUM val;
+ int i;
+
+ res = 0;
+ if (nargs < 2)
+ fatal(_("or: called with less than two arguments"));
+
+ for (i = 1; nargs > 0; nargs--, i++) {
+ s1 = POP_SCALAR();
+ if (do_lint && (s1->flags & (NUMCUR|NUMBER)) == 0)
+ lintwarn(_("or: argument %d is non-numeric"), i);
+
+ val = force_number(s1)->numbr;
+ if (do_lint && val < 0)
+ lintwarn(_("or: argument %d negative value %g will give strange results"),
+ i, (double) val);
+
+ uval = (uintmax_t) val;
+ res |= uval;
+
+ DEREF(s1);
+ }
+
+ return make_integer(res);
+}
+
+/* do_xor --- perform an ^ operation */
+
+static NODE *
+do_xor(int nargs)
+{
+ NODE *s1;
+ uintmax_t res, uval;
+ AWKNUM val;
+ int i;
+
+ if (nargs < 2)
+ fatal(_("xor: called with less than two arguments"));
+
+ res = 0; /* silence compiler warning */
+ for (i = 1; nargs > 0; nargs--, i++) {
+ s1 = POP_SCALAR();
+ if (do_lint && (s1->flags & (NUMCUR|NUMBER)) == 0)
+ lintwarn(_("xor: argument %d is non-numeric"), i);
+
+ val = force_number(s1)->numbr;
+ if (do_lint && val < 0)
+ lintwarn(_("xor: argument %d negative value %g will give strange results"),
+ i, (double) val);
+
+ uval = (uintmax_t) val;
+ if (i == 1)
+ res = uval;
+ else
+ res ^= uval;
+
+ DEREF(s1);
+ }
+
+ return make_integer(res);
+}
+
+/* do_compl --- perform a ~ operation */
+
+static NODE *
+do_compl(int nargs)
+{
+ NODE *tmp;
+ AWKNUM d;
+ uintmax_t uval;
+
+ tmp = POP_SCALAR();
+ if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
+ lintwarn(_("compl: received non-numeric argument"));
+ d = force_number(tmp)->numbr;
+ DEREF(tmp);
+
+ if (do_lint) {
+ if (d < 0)
+ lintwarn(_("compl(%f): negative value will give strange results"),
+ (double) d);
+ if (double_to_int(d) != d)
+ lintwarn(_("compl(%f): fractional value will be truncated"),
+ (double) d);
+ }
+
+ uval = (uintmax_t) d;
+ uval = ~ uval;
+ return make_integer(uval);
+}
+
+/* nondec2awknum --- convert octal or hex value to double */
+
+/*
+ * Because of awk's concatenation rules and the way awk.y:yylex()
+ * collects a number, this routine has to be willing to stop on the
+ * first invalid character.
+ */
+
+static AWKNUM
+nondec2awknum(char *str, size_t len)
+{
+ AWKNUM retval = 0.0;
+ char save;
+ short val;
+ char *start = str;
+
+ if (*str == '0' && (str[1] == 'x' || str[1] == 'X')) {
+ /*
+ * User called strtonum("0x") or some such,
+ * so just quit early.
+ */
+ if (len <= 2)
+ return (AWKNUM) 0.0;
+
+ for (str += 2, len -= 2; len > 0; len--, str++) {
+ switch (*str) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ val = *str - '0';
+ break;
+ case 'a':
+ case 'b':
+ case 'c':
+ case 'd':
+ case 'e':
+ case 'f':
+ val = *str - 'a' + 10;
+ break;
+ case 'A':
+ case 'B':
+ case 'C':
+ case 'D':
+ case 'E':
+ case 'F':
+ val = *str - 'A' + 10;
+ break;
+ default:
+ goto done;
+ }
+ retval = (retval * 16) + val;
+ }
+ } else if (*str == '0') {
+ for (; len > 0; len--) {
+ if (! isdigit((unsigned char) *str))
+ goto done;
+ else if (*str == '8' || *str == '9') {
+ str = start;
+ goto decimal;
+ }
+ retval = (retval * 8) + (*str - '0');
+ str++;
+ }
+ } else {
+decimal:
+ save = str[len];
+ retval = strtod(str, NULL);
+ str[len] = save;
+ }
+done:
+ return retval;
+}
+
+
+/* do_rand --- do the rand function */
+
+static bool firstrand = true;
+/* Some systems require this array to be integer aligned. Sigh. */
+#define SIZEOF_STATE 256
+static uint32_t istate[SIZEOF_STATE/sizeof(uint32_t)];
+static char *const state = (char *const) istate;
+
+/* ARGSUSED */
+static NODE *
+do_rand(int nargs ATTRIBUTE_UNUSED)
+{
+ double tmprand;
+#define RAND_DIVISOR ((double)GAWK_RANDOM_MAX+1.0)
+ if (firstrand) {
+ (void) initstate((unsigned) 1, state, SIZEOF_STATE);
+ /* don't need to srandom(1), initstate() does it for us. */
+ firstrand = false;
+ setstate(state);
+ }
+ /*
+ * Per historical practice and POSIX, return value N is
+ *
+ * 0 <= n < 1
+ */
+ /*
+ * Date: Wed, 28 Aug 2013 17:52:46 -0700
+ * From: Bob Jewett <jewett@bill.scs.agilent.com>
+ *
+ * Call random() twice to fill in more bits in the value
+ * of the double. Also, there is a bug in random() such
+ * that when the values of successive values are combined
+ * like (rand1*rand2)^2, (rand3*rand4)^2, ... the
+ * resulting time series is not white noise. The
+ * following also seems to fix that bug.
+ *
+ * The add/subtract 0.5 keeps small bits from filling
+ * below 2^-53 in the double, not that anyone should be
+ * looking down there.
+ *
+ * Date: Wed, 25 Sep 2013 10:45:38 -0600 (MDT)
+ * From: "Nelson H. F. Beebe" <beebe@math.utah.edu>
+ * (4) The code is typical of many published fragments for converting
+ * from integer to floating-point, and I discuss the serious pitfalls
+ * in my book, because it leads to platform-dependent behavior at the
+ * end points of the interval [0,1]
+ *
+ * (5) the documentation in the gawk info node says
+ *
+ * `rand()'
+ * Return a random number. The values of `rand()' are uniformly
+ * distributed between zero and one. The value could be zero but is
+ * never one.(1)
+ *
+ * The division by RAND_DIVISOR may not guarantee that 1.0 is never
+ * returned: the programmer forgot the platform-dependent issue of
+ * rounding.
+ *
+ * For points 4 and 5, the safe way is a loop:
+ *
+ * double
+ * rand(void) // return value in [0.0, 1.0)
+ * {
+ * value = internal_rand();
+ *
+ * while (value == 1.0)
+ * value = internal_rand();
+ *
+ * return (value);
+ * }
+ */
+
+ do {
+ tmprand = 0.5 + ( (random()/RAND_DIVISOR + random())
+ / RAND_DIVISOR);
+ tmprand -= 0.5;
+ } while (tmprand == 1.0);
+
+ return make_number((AWKNUM) tmprand);
+}
+
+/* do_srand --- seed the random number generator */
+
+static NODE *
+do_srand(int nargs)
+{
+ NODE *tmp;
+ static long save_seed = 1;
+ long ret = save_seed; /* SVR4 awk srand returns previous seed */
+
+ if (firstrand) {
+ (void) initstate((unsigned) 1, state, SIZEOF_STATE);
+ /* don't need to srandom(1), we're changing the seed below */
+ firstrand = false;
+ (void) setstate(state);
+ }
+
+ if (nargs == 0)
+ srandom((unsigned int) (save_seed = (long) time((time_t *) 0)));
+ else {
+ tmp = POP_SCALAR();
+ if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
+ lintwarn(_("srand: received non-numeric argument"));
+ srandom((unsigned int) (save_seed = (long) force_number(tmp)->numbr));
+ DEREF(tmp);
+ }
+ return make_awknum((AWKNUM) ret);
+}
+
+
+/* str2awknum --- create a number node from string */
+
+static NODE *
+str2awknum(char *str, char **endptr, int base, bool is_integer ATTRIBUTE_UNUSED)
+{
+ NODE *r;
+ AWKNUM d;
+
+ if (base == 0) {
+ /*
+ * special case -- only used to parse input in the debugger?
+ * FIXME: reject ieee specials we don't want and/or use the same
+ * rules when reading numbers from a source file and nuke this case.
+ */
+
+ errno = 0;
+ d = strtod(str, endptr);
+ if (errno != 0)
+ d = 0;
+ } else {
+ if (base == 8 || base == 16)
+ d = nondec2awknum(str, strlen(str));
+ else
+ d = atof(str);
+ }
+ r = make_awknum(d);
+ if (d <= INT32_MAX && d >= INT32_MIN && d == (int32_t) d)
+ r->flags |= NUMINT;
+ return r;
+}
+
+/* awknum_mod --- remainder from division of two numbers */
+
+static NODE *
+awknum_mod(const NODE *t1, const NODE *t2)
+{
+ AWKNUM x;
+
+ if (t2->numbr == 0)
+ fatal(_("division by zero attempted in `%%'"));
+#ifdef HAVE_FMOD
+ x = fmod(t1->numbr, t2->numbr);
+#else /* ! HAVE_FMOD */
+ (void) modf(t1->numbr / t2->numbr, & x);
+ x = t1->numbr - x * t2->numbr;
+#endif /* ! HAVE_FMOD */
+ return make_awknum(x);
+}
+
+/* awknum_pow --- power function */
+
+static NODE *
+awknum_pow(const NODE *t1, const NODE *t2)
+{
+ return make_awknum(calc_exp(t1->numbr, t2->numbr));
+}
+
+
+/*
+ * calc_exp_posint --- calculate x^n for positive integral n,
+ * using exponentiation by squaring without recursion.
+ */
+
+static AWKNUM
+calc_exp_posint(AWKNUM x, long n)
+{
+ AWKNUM mult = 1;
+
+ while (n > 1) {
+ if ((n % 2) == 1)
+ mult *= x;
+ x *= x;
+ n /= 2;
+ }
+ return mult * x;
+}
+
+/* calc_exp --- calculate x1^x2 */
+
+static AWKNUM
+calc_exp(AWKNUM x1, AWKNUM x2)
+{
+ long lx;
+
+ if ((lx = x2) == x2) { /* integer exponent */
+ if (lx == 0)
+ return 1;
+ return (lx > 0) ? calc_exp_posint(x1, lx)
+ : 1.0 / calc_exp_posint(x1, -lx);
+ }
+ return (AWKNUM) pow((double) x1, (double) x2);
+}
+
+/* cmp_awknums --- compare two AWKNUMs */
+
+static int
+cmp_awknums(const NODE *t1, const NODE *t2)
+{
+ /*
+ * This routine is also used to sort numeric array indices or values.
+ * For the purposes of sorting, NaN is considered greater than
+ * any other value, and all NaN values are considered equivalent and equal.
+ * This isn't in compliance with IEEE standard, but compliance w.r.t. NaN
+ * comparison at the awk level is a different issue, and needs to be dealt
+ * with in the interpreter for each opcode seperately.
+ */
+
+ if (isnan(t1->numbr))
+ return ! isnan(t2->numbr);
+ if (isnan(t2->numbr))
+ return -1;
+ /* don't subtract, in case one or both are infinite */
+ if (t1->numbr == t2->numbr)
+ return 0;
+ if (t1->numbr < t2->numbr)
+ return -1;
+ return 1;
+}
+
+/* force_awknum --- force a value to be numeric */
+
+static NODE *
+force_awknum(NODE *n)
+{
+ char *cp;
+ char *cpend;
+ char save;
+ char *ptr;
+ unsigned int newflags;
+
+ if ((n->flags & NUMCUR) != 0)
+ return n;
+
+ /* all the conditionals are an attempt to avoid the expensive strtod */
+
+ /* Note: only set NUMCUR if we actually convert some digits */
+
+ n->numbr = 0.0;
+
+ if (n->stlen == 0) {
+ return n;
+ }
+
+ cp = n->stptr;
+ /*
+ * 2/2007:
+ * POSIX, by way of severe language lawyering, seems to
+ * allow things like "inf" and "nan" to mean something.
+ * So if do_posix, the user gets what he deserves.
+ * This also allows hexadecimal floating point. Ugh.
+ */
+ if (! do_posix) {
+ if (isalpha((unsigned char) *cp)) {
+ return n;
+ } else if (n->stlen == 4 && is_ieee_magic_val(n->stptr)) {
+ if ((n->flags & MAYBE_NUM) != 0)
+ n->flags &= ~MAYBE_NUM;
+ n->flags |= NUMBER|NUMCUR;
+ n->numbr = get_ieee_magic_val(n->stptr);
+ return n;
+ }
+ /* else
+ fall through */
+ }
+ /* else not POSIX, so
+ fall through */
+
+ cpend = cp + n->stlen;
+ while (cp < cpend && isspace((unsigned char) *cp))
+ cp++;
+
+ if ( cp == cpend /* only spaces, or */
+ || (! do_posix /* not POSIXLY paranoid and */
+ && (isalpha((unsigned char) *cp) /* letter, or */
+ /* CANNOT do non-decimal and saw 0x */
+ || (! do_non_decimal_data && cp[0] == '0'
+ && (cp[1] == 'x' || cp[1] == 'X'))))) {
+ return n;
+ }
+
+ if ((n->flags & MAYBE_NUM) != 0) {
+ newflags = NUMBER;
+ n->flags &= ~MAYBE_NUM;
+ } else
+ newflags = 0;
+
+ if (cpend - cp == 1) { /* only one character */
+ if (isdigit((unsigned char) *cp)) { /* it's a digit! */
+ n->numbr = (AWKNUM)(*cp - '0');
+ n->flags |= newflags;
+ n->flags |= NUMCUR;
+ if (cp == n->stptr) /* no leading spaces */
+ n->flags |= NUMINT;
+ }
+ return n;
+ }
+
+ if (do_non_decimal_data) { /* main.c assures false if do_posix */
+ errno = 0;
+ if (! do_traditional && get_numbase(cp, true) != 10) {
+ n->numbr = nondec2awknum(cp, cpend - cp);
+ n->flags |= NUMCUR;
+ ptr = cpend;
+ goto finish;
+ }
+ }
+
+ errno = 0;
+ save = *cpend;
+ *cpend = '\0';
+ n->numbr = (AWKNUM) strtod((const char *) cp, &ptr);
+
+ /* POSIX says trailing space is OK for NUMBER */
+ while (isspace((unsigned char) *ptr))
+ ptr++;
+ *cpend = save;
+finish:
+ if (errno == 0 && ptr == cpend) {
+ n->flags |= newflags;
+ n->flags |= NUMCUR;
+ } else {
+ errno = 0;
+ }
+
+ return n;
+}
+
+
+/*
+ * The following lookup table is used as an optimization in force_string;
+ * (more complicated) variations on this theme didn't seem to pay off, but
+ * systematic testing might be in order at some point.
+ */
+static const char *values[] = {
+ "0",
+ "1",
+ "2",
+ "3",
+ "4",
+ "5",
+ "6",
+ "7",
+ "8",
+ "9",
+};
+#define NVAL (sizeof(values)/sizeof(values[0]))
+
+/* format_awknum_val --- format a numeric value based on format */
+
+static NODE *
+format_awknum_val(const char *format, int index, NODE *s)
+{
+ char buf[BUFSIZ];
+ char *sp = buf;
+ double val;
+
+ /*
+ * 2/2007: Simplify our lives here. Instead of worrying about
+ * whether or not the value will fit into a long just so we
+ * can use sprintf("%ld", val) on it, always format it ourselves.
+ * The only thing to worry about is that integral values always
+ * format as integers. %.0f does that very well.
+ *
+ * 6/2008: Would that things were so simple. Always using %.0f
+ * imposes a notable performance penalty for applications that
+ * do a lot of conversion of integers to strings. So, we reinstate
+ * the old code, but use %.0f for integral values that are outside
+ * the range of a long. This seems a reasonable compromise.
+ *
+ * 12/2009: Use <= and >= in the comparisons with LONG_xxx instead of
+ * < and > so that things work correctly on systems with 64 bit integers.
+ */
+
+ if ((s->flags & STRCUR) != 0)
+ efree(s->stptr);
+ free_wstr(s);
+
+
+ /* not an integral value, or out of range */
+ if ((val = double_to_int(s->numbr)) != s->numbr
+ || val <= LONG_MIN || val >= LONG_MAX
+ ) {
+ struct format_spec spec;
+ struct print_fmt_buf *outb;
+
+ /*
+ * Once upon a time, we just blindly did this:
+ * sprintf(sp, format, s->numbr);
+ * s->stlen = strlen(sp);
+ * s->stfmt = (char) index;
+ * but that's no good if, e.g., OFMT is %s. So we punt,
+ * and just always format the value ourselves.
+ */
+
+ /* XXX: format_spec copied since can be altered in the formatting routine */
+
+ if (val == s->numbr) {
+ /* integral value, but outside range of %ld, use %.0f */
+ spec = *fmt_list[INT_0f_FMT_INDEX].spec;
+ s->stfmt = -1;
+ } else {
+ assert(fmt_list[index].spec != NULL); /* or can use fmt_parse() --- XXX */
+ spec = *fmt_list[index].spec;
+ s->stfmt = (char) index;
+ }
+
+ outb = get_fmt_buf();
+ (void) format_awknum_printf(s, & spec, outb);
+ (void) bytes2node(outb, s);
+ free_fmt_buf(outb);
+
+ s->stptr[s->stlen] = '\0';
+ } else {
+ /*
+ * integral value; force conversion to long only once.
+ */
+ long num = (long) val;
+
+ if (num < NVAL && num >= 0) {
+ sp = (char *) values[num];
+ s->stlen = 1;
+ } else {
+ (void) sprintf(sp, "%ld", num);
+ s->stlen = strlen(sp);
+ }
+ s->stfmt = -1;
+ if ((s->flags & INTIND) != 0) {
+ s->flags &= ~(INTIND|NUMBER);
+ s->flags |= STRING;
+ }
+
+ emalloc(s->stptr, char *, s->stlen + 2, "format_awknum_val");
+ memcpy(s->stptr, sp, s->stlen + 1);
+ }
+
+ s->flags |= STRCUR;
+ return s;
+}
+
+/* is_ieee_magic_val --- return true for +inf, -inf, +nan, -nan */
+
+static int
+is_ieee_magic_val(const char *val)
+{
+ /*
+ * Avoid strncasecmp: it mishandles ASCII bytes in some locales.
+ * Assume the length is 4, as the caller checks this.
+ */
+ return ( (val[0] == '+' || val[0] == '-')
+ && ( ( (val[1] == 'i' || val[1] == 'I')
+ && (val[2] == 'n' || val[2] == 'N')
+ && (val[3] == 'f' || val[3] == 'F'))
+ || ( (val[1] == 'n' || val[1] == 'N')
+ && (val[2] == 'a' || val[2] == 'A')
+ && (val[3] == 'n' || val[3] == 'N'))));
+}
+
+/* get_ieee_magic_val --- return magic value for string */
+
+static AWKNUM
+get_ieee_magic_val(const char *val)
+{
+ static bool first = true;
+ static AWKNUM inf;
+ static AWKNUM nan;
+ char *ptr;
+ AWKNUM v;
+
+ v = strtod(val, & ptr);
+
+ if (val == ptr) { /* Older strtod implementations don't support inf or nan. */
+ if (first) {
+ first = false;
+ nan = sqrt(-1.0);
+ inf = -log(0.0);
+ }
+
+ v = ((val[1] == 'i' || val[1] == 'I') ? inf : nan);
+ if (val[0] == '-')
+ v = -v;
+ }
+
+ return v;
+}
+
+/* double_to_int --- convert double to int, used in several places */
+
+static double
+double_to_int(double d)
+{
+ if (d >= 0)
+ d = floor(d);
+ else
+ d = ceil(d);
+ return d;
+}
+
+/* do_int --- convert double to int for awk */
+
+static NODE *
+do_int(int nargs)
+{
+ NODE *tmp;
+ AWKNUM d;
+
+ tmp = POP_SCALAR();
+ if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
+ lintwarn(_("int: received non-numeric argument"));
+ (void) force_number(tmp);
+ d = tmp->numbr;
+ DEREF(tmp);
+ return make_awknum(double_to_int(d));
+}
+
+/* do_log --- the log function */
+
+static NODE *
+do_log(int nargs)
+{
+ NODE *tmp;
+ AWKNUM d, arg;
+
+ tmp = POP_SCALAR();
+ if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
+ lintwarn(_("log: received non-numeric argument"));
+ arg = force_number(tmp)->numbr;
+ if (arg < 0.0)
+ warning(_("log: received negative argument %g"), (double) arg);
+ d = log(arg);
+ DEREF(tmp);
+ return make_awknum(d);
+}
+
+/* do_sqrt --- do the sqrt function */
+
+static NODE *
+do_sqrt(int nargs)
+{
+ NODE *tmp;
+ AWKNUM arg;
+
+ tmp = POP_SCALAR();
+ if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
+ lintwarn(_("sqrt: received non-numeric argument"));
+ arg = force_number(tmp)->numbr;
+ DEREF(tmp);
+ if (arg < 0.0)
+ warning(_("sqrt: called with negative argument %g"), (double) arg);
+ return make_awknum(sqrt(arg));
+}
+
+/* do_exp --- exponential function */
+
+static NODE *
+do_exp(int nargs)
+{
+ NODE *tmp;
+ AWKNUM d, res;
+
+ tmp = POP_SCALAR();
+ if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
+ lintwarn(_("exp: received non-numeric argument"));
+ d = force_number(tmp)->numbr;
+ DEREF(tmp);
+ errno = 0;
+ res = exp(d);
+ if (errno == ERANGE)
+ warning(_("exp: argument %g is out of range"), (double) d);
+ return make_awknum(res);
+}
+
+
+/* do_atan2 --- do the atan2 function */
+
+static NODE *
+do_atan2(int nargs)
+{
+ NODE *t1, *t2;
+ AWKNUM d1, d2;
+
+ t2 = POP_SCALAR();
+ t1 = POP_SCALAR();
+ if (do_lint) {
+ if ((t1->flags & (NUMCUR|NUMBER)) == 0)
+ lintwarn(_("atan2: received non-numeric first argument"));
+ if ((t2->flags & (NUMCUR|NUMBER)) == 0)
+ lintwarn(_("atan2: received non-numeric second argument"));
+ }
+ d1 = force_number(t1)->numbr;
+ d2 = force_number(t2)->numbr;
+ DEREF(t1);
+ DEREF(t2);
+ return make_awknum(atan2(d1, d2));
+}
+
+/* do_sin --- do the sin function */
+
+static NODE *
+do_sin(int nargs)
+{
+ NODE *tmp;
+ AWKNUM d;
+
+ tmp = POP_SCALAR();
+ if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
+ lintwarn(_("sin: received non-numeric argument"));
+ d = sin(force_number(tmp)->numbr);
+ DEREF(tmp);
+ return make_awknum(d);
+}
+
+/* do_cos --- do the cos function */
+
+static NODE *
+do_cos(int nargs)
+{
+ NODE *tmp;
+ AWKNUM d;
+
+ tmp = POP_SCALAR();
+ if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
+ lintwarn(_("cos: received non-numeric argument"));
+ d = cos(force_number(tmp)->numbr);
+ DEREF(tmp);
+ return make_awknum(d);
+}
+
+/* do_strtonum --- the strtonum function */
+
+static NODE *
+do_strtonum(int nargs)
+{
+ NODE *tmp;
+ AWKNUM d;
+
+ tmp = POP_SCALAR();
+ if ((tmp->flags & (NUMBER|NUMCUR)) != 0)
+ d = force_number(tmp)->numbr;
+ else if (get_numbase(tmp->stptr, use_lc_numeric) != 10)
+ d = nondec2awknum(tmp->stptr, tmp->stlen);
+ else
+ d = force_number(tmp)->numbr;
+
+ DEREF(tmp);
+ return make_awknum(d);
+}
+
+/* do_div --- do integer division, return quotient and remainder in dest array */
+
+/*
+ * We define the semantics as:
+ * numerator = int(numerator)
+ * denominator = int(denonmator)
+ * quotient = int(numerator / denomator)
+ * remainder = int(numerator % denomator)
+ */
+
+NODE *
+do_div(int nargs)
+{
+ NODE *numerator, *denominator, *result;
+ double num, denom, quotient, remainder;
+ NODE *sub, **lhs;
+
+ result = POP_PARAM();
+ if (result->type != Node_var_array)
+ fatal(_("div: third argument is not an array"));
+ assoc_clear(result);
+
+ denominator = POP_SCALAR();
+ numerator = POP_SCALAR();
+
+ if (do_lint) {
+ if ((numerator->flags & (NUMCUR|NUMBER)) == 0)
+ lintwarn(_("div: received non-numeric first argument"));
+ if ((denominator->flags & (NUMCUR|NUMBER)) == 0)
+ lintwarn(_("div: received non-numeric second argument"));
+ }
+
+ (void) force_number(numerator);
+ (void) force_number(denominator);
+ num = double_to_int(get_number_d(numerator));
+ denom = double_to_int(get_number_d(denominator));
+
+ if (denom == 0.0)
+ fatal(_("div: division by zero attempted"));
+
+ quotient = double_to_int(num / denom);
+ /*
+ * FIXME: This code is duplicated, factor it out to a
+ * separate function.
+ */
+#ifdef HAVE_FMOD
+ remainder = fmod(num, denom);
+#else /* ! HAVE_FMOD */
+ (void) modf(num / denom, & remainder);
+ remainder = num - remainder * denom;
+#endif /* ! HAVE_FMOD */
+ remainder = double_to_int(remainder);
+
+ sub = make_string("quotient", 8);
+ lhs = assoc_lookup(result, sub);
+ unref(*lhs);
+ *lhs = make_number((AWKNUM) quotient);
+
+ sub = make_string("remainder", 9);
+ lhs = assoc_lookup(result, sub);
+ unref(*lhs);
+ *lhs = make_number((AWKNUM) remainder);
+
+ return make_number((AWKNUM) 0.0);
+}
+
+/* format_awknum_printf --- format a number for (s)printf */
+
+static int
+format_awknum_printf(NODE *arg, struct format_spec *spec, struct print_fmt_buf *outb)
+{
+ AWKNUM tmpval;
+ uintmax_t uval;
+ bool sgn;
+ int i, ii, jj;
+ char *chp, *cp;
+ char cs1;
+ int nc;
+
+ static char stackbuf[64]; /* temporary buffer for integer formatting */
+ static char *intbuf = stackbuf;
+ size_t intbuf_size = 64;
+
+# define CP cpbuf_start(outb)
+# define CEND cpbuf_end(outb)
+# define CPBUF cpbuf(outb)
+
+
+ tmpval = arg->numbr;
+ spec->fill = space_string;
+ spec->chbuf = lchbuf;
+
+ cp = CP;
+ cs1 = spec->fmtchar;
+ switch (cs1) {
+ case 'd':
+ case 'i':
+ if (isnan(tmpval) || isinf(tmpval))
+ goto out_of_range;
+ else
+ tmpval = double_to_int(tmpval);
+
+ /*
+ * ``The result of converting a zero value with a
+ * precision of zero is no characters.''
+ */
+ if (spec->have_prec && spec->prec == 0 && tmpval == 0) {
+ pr_num_tail(cp, spec->prec, spec, outb);
+ return 0;
+ }
+
+ if (tmpval < 0) {
+ tmpval = -tmpval;
+ sgn = true;
+ } else {
+ if (tmpval == -0.0) /* avoid printing -0 */
+ tmpval = 0.0;
+ sgn = false;
+ }
+
+ /*
+ * Use snprintf return value to tell if there
+ * is enough room in the buffer or not.
+ */
+ while ((i = snprintf(intbuf, intbuf_size, "%.0f", tmpval)) >= intbuf_size) {
+ if (intbuf == stackbuf)
+ intbuf = NULL;
+ intbuf_size = i + 1;
+ erealloc(intbuf, char *, intbuf_size, "format_tree");
+ }
+
+ if (i < 1)
+ goto out_of_range;
+
+ chp = & intbuf[i-1];
+ ii = jj = 0;
+ do {
+ tmpbuf_prepend(outb, *chp);
+ chp--; i--;
+#if defined(HAVE_LOCALE_H)
+ if (spec->quote_flag && loc.grouping[ii] && ++jj == loc.grouping[ii]) {
+ if (i) /* only add if more digits coming */
+ tmpbuf_prepend(outb, loc.thousands_sep[0]); /* XXX - assumption it's one char */
+ if (loc.grouping[ii+1] == 0)
+ jj = 0; /* keep using current val in loc.grouping[ii] */
+ else if (loc.grouping[ii+1] == CHAR_MAX)
+ spec->quote_flag= false;
+ else {
+ ii++;
+ jj = 0;
+ }
+ }
+#endif
+ } while (i > 0);
+
+
+ /* add more output digits to match the precision */
+ if (spec->have_prec) {
+ while (CEND - CP < spec->prec)
+ tmpbuf_prepend(outb, '0');
+ }
+
+ if (sgn)
+ tmpbuf_prepend(outb, '-');
+ else if (spec->signchar)
+ tmpbuf_prepend(outb, spec->signchar);
+ /*
+ * When to fill with zeroes is of course not simple.
+ * First: No zero fill if left-justifying.
+ * Next: There seem to be two cases:
+ * A '0' without a precision, e.g. %06d
+ * A precision with no field width, e.g. %.10d
+ * Any other case, we don't want to fill with zeroes.
+ */
+ if (! spec->lj
+ && ((spec->zero_flag && ! spec->have_prec)
+ || (spec->fw == 0 && spec->have_prec)))
+ spec->fill = zero_string;
+ if (spec->prec > spec->fw)
+ spec->fw = spec->prec;
+ spec->prec = CEND - CP;
+ if (spec->fw > spec->prec && ! spec->lj && spec->fill != space_string
+ && (*CP == '-' || spec->signchar)) {
+ bchunk_one(outb, CP);
+ CP++;
+ spec->prec--;
+ spec->fw--;
+ }
+ cp = CP;
+
+ pr_num_tail(CP, spec->prec, spec, outb);
+ return 0;
+
+ case 'X':
+ spec->chbuf = Uchbuf;
+ /* FALL THROUGH */
+ case 'x':
+ /* FALL THROUGH */
+ case 'u':
+ /* FALL THROUGH */
+ case 'o':
+ /*
+ * ``The result of converting a zero value with a
+ * precision of zero is no characters.''
+ *
+ * If I remember the ANSI C standard, though,
+ * it says that for octal conversions
+ * the precision is artificially increased
+ * to add an extra 0 if # is supplied.
+ * Indeed, in C,
+ * printf("%#.0o\n", 0);
+ * prints a single 0.
+ */
+
+ if (! spec->alt && spec->have_prec && spec->prec == 0 && tmpval == 0) {
+ pr_num_tail(cp, spec->prec, spec, outb);
+ return 0;
+ }
+
+ if (tmpval < 0) {
+ uval = (uintmax_t) (intmax_t) tmpval;
+ if ((AWKNUM)(intmax_t) uval != double_to_int(tmpval))
+ goto out_of_range;
+ } else {
+ uval = (uintmax_t) tmpval;
+ if ((AWKNUM) uval != double_to_int(tmpval))
+ goto out_of_range;
+ }
+
+ /* spec->fmtchar = cs1; */
+ format_nondecimal(uval, spec, outb);
+ return 0;
+
+out_of_range:
+ /* out of range - emergency use of %g format */
+ if (do_lint)
+ lintwarn(_("[s]printf: value %g is out of range for `%%%c' format"),
+ (double) tmpval, cs1);
+ cs1 = 'g';
+ goto fmt1;
+
+ case 'F':
+#if ! defined(PRINTF_HAS_F_FORMAT) || PRINTF_HAS_F_FORMAT != 1
+ cs1 = 'f';
+ /* FALL THROUGH */
+#endif
+ case 'g':
+ case 'G':
+ case 'e':
+ case 'f':
+ case 'E':
+fmt1:
+ if (! spec->have_prec)
+ spec->prec = DEFAULT_G_PRECISION;
+
+ chksize(outb, spec->fw + spec->prec + 11); /* 11 == slop */
+ cp = CPBUF; /* XXX --- using the temporary prepend-buffer and
+ * we know it has enough room (>=11).
+ */
+ *cp++ = '%';
+ if (spec->lj)
+ *cp++ = '-';
+ if (spec->signchar)
+ *cp++ = spec->signchar;
+ if (spec->alt)
+ *cp++ = '#';
+ if (spec->zero_flag)
+ *cp++ = '0';
+ if (spec->quote_flag)
+ *cp++ = '\'';
+
+#if defined(LC_NUMERIC)
+ if (spec->quote_flag && ! use_lc_numeric)
+ setlocale(LC_NUMERIC, "");
+#endif
+
+ sprintf(cp, "*.*%c", cs1);
+ while ((nc = snprintf(buf_end(outb), buf_space(outb), CPBUF,
+ (int) spec->fw, (int) spec->prec, tmpval)) >= buf_space(outb))
+ chksize(outb, nc + 1);
+
+#if defined(LC_NUMERIC)
+ if (spec->quote_flag && ! use_lc_numeric)
+ setlocale(LC_NUMERIC, "C");
+#endif
+
+ buf_adjust(outb, nc); /* adjust data and free space in output buffer */
+ return 0;
+
+ default:
+ cant_happen();
+ }
+
+ return -1;
+#undef CP
+#undef CEND
+#undef CPBUF
+}
diff --git a/eval.c b/eval.c
index 0d6a07b6..7bca21a4 100644
--- a/eval.c
+++ b/eval.c
@@ -34,6 +34,8 @@ long fcall_count = 0;
int currule = 0;
IOBUF *curfile = NULL; /* current data file */
bool exiting = false;
+NODE *true_node;
+NODE *false_node;
int (*interpret)(INSTRUCTION *);
#define MAX_EXEC_HOOKS 10
@@ -48,7 +50,6 @@ int ORSlen;
int OFMTidx;
int CONVFMTidx;
-static NODE *node_Boolean[2];
/* This rather ugly macro is for VMS C */
#ifdef C
@@ -265,18 +266,18 @@ static struct optypetab {
char *operator;
} optypes[] = {
{ "Op_illegal", NULL },
+ { "Op_plus", " + " },
+ { "Op_minus", " - " },
{ "Op_times", " * " },
- { "Op_times_i", " * " },
{ "Op_quotient", " / " },
- { "Op_quotient_i", " / " },
{ "Op_mod", " % " },
- { "Op_mod_i", " % " },
- { "Op_plus", " + " },
- { "Op_plus_i", " + " },
- { "Op_minus", " - " },
- { "Op_minus_i", " - " },
{ "Op_exp", " ^ " },
- { "Op_exp_i", " ^ " },
+ { "Op_assign_plus", " += " },
+ { "Op_assign_minus", " -= " },
+ { "Op_assign_times", " *= " },
+ { "Op_assign_quotient", " /= " },
+ { "Op_assign_mod", " %= " },
+ { "Op_assign_exp", " ^= " },
{ "Op_concat", " " },
{ "Op_line_range", NULL },
{ "Op_cond_pair", ", " },
@@ -286,6 +287,7 @@ static struct optypetab {
{ "Op_predecrement", "--" },
{ "Op_postincrement", "++" },
{ "Op_postdecrement", "--" },
+ { "Op_unary_plus", "+" },
{ "Op_unary_minus", "-" },
{ "Op_field_spec", "$" },
{ "Op_not", "! " },
@@ -293,12 +295,6 @@ static struct optypetab {
{ "Op_store_var", " = " },
{ "Op_store_sub", " = " },
{ "Op_store_field", " = " },
- { "Op_assign_times", " *= " },
- { "Op_assign_quotient", " /= " },
- { "Op_assign_mod", " %= " },
- { "Op_assign_plus", " += " },
- { "Op_assign_minus", " -= " },
- { "Op_assign_exp", " ^= " },
{ "Op_assign_concat", " " },
{ "Op_and", " && " },
{ "Op_and_final", NULL },
@@ -850,16 +846,12 @@ set_ORS()
/* fmt_ok --- is the conversion format a valid one? */
-NODE **fmt_list = NULL;
-static int fmt_ok(NODE *n);
+struct fmt_list_item *fmt_list = NULL;
static int fmt_index(NODE *n);
-static int
-fmt_ok(NODE *n)
+bool
+fmt_ok(const char *p)
{
- NODE *tmp = force_string(n);
- const char *p = tmp->stptr;
-
#if ! defined(PRINTF_HAS_F_FORMAT) || PRINTF_HAS_F_FORMAT != 1
static const char float_formats[] = "efgEG";
#else
@@ -872,22 +864,22 @@ fmt_ok(NODE *n)
#endif
if (*p++ != '%')
- return 0;
+ return false;
while (*p && strchr(flags, *p) != NULL) /* flags */
p++;
while (*p && isdigit((unsigned char) *p)) /* width - %*.*g is NOT allowed */
p++;
if (*p == '\0' || (*p != '.' && ! isdigit((unsigned char) *p)))
- return 0;
+ return false;
if (*p == '.')
p++;
while (*p && isdigit((unsigned char) *p)) /* precision */
p++;
if (*p == '\0' || strchr(float_formats, *p) == NULL)
- return 0;
+ return false;
if (*++p != '\0')
- return 0;
- return 1;
+ return false;
+ return true;
}
/* fmt_index --- track values of OFMT and CONVFMT to keep semantics correct */
@@ -896,30 +888,77 @@ static int
fmt_index(NODE *n)
{
int ix = 0;
- static int fmt_num = 4;
+ static int fmt_num = 6;
static int fmt_hiwater = 0;
+ struct format_spec *spec = NULL;
+ extern struct format_spec *fmt_parse(NODE *, const char *, size_t);
+
+ /*
+ * BEGIN { CONVFMT="%s"; print 1.1234567 "X" }
+ * number -> force_string -> CONVFMT = %s -> force_string -> ...
+ */
+
+ if (fmt_list == NULL) {
+ NODE *t;
+
+ emalloc(fmt_list, struct fmt_list_item *, fmt_num * sizeof(*fmt_list), "fmt_index");
+
+ /*
+ * XXX: Insert "%d" and "%.0f" at known indices, used to convert integers.
+ * The indices are defined using `enum { INT_d_FMT_INDEX, INT_0f_FMT_INDEX }'
+ * in format.h;
+ * We want to avoid calling format_tree() directly in case the current
+ * number handler hasn't been initialized, or we need a different handler;
+ * may also be a bit more efficient.
+ */
+
+ t = make_string("%d", 2);
+ spec = fmt_parse(CONVFMT_node, t->stptr, t->stlen);
+ assert(spec != NULL);
+ fmt_list[fmt_hiwater].fmt = t;
+ fmt_list[fmt_hiwater].spec = spec;
+ fmt_hiwater++;
+
+ t = make_string("%.0f", 4);
+ spec = fmt_parse(CONVFMT_node, t->stptr, t->stlen);
+ assert(spec != NULL);
+ fmt_list[fmt_hiwater].fmt = t;
+ fmt_list[fmt_hiwater].spec = spec;
+ fmt_hiwater++;
+ }
- if (fmt_list == NULL)
- emalloc(fmt_list, NODE **, fmt_num*sizeof(*fmt_list), "fmt_index");
n = force_string(n);
while (ix < fmt_hiwater) {
- if (cmp_nodes(fmt_list[ix], n) == 0)
+ if (cmp_nodes(fmt_list[ix].fmt, n) == 0)
return ix;
ix++;
}
/* not found */
+
n->stptr[n->stlen] = '\0';
- if (do_lint && ! fmt_ok(n))
+ if (do_lint && ! fmt_ok(n->stptr))
lintwarn(_("bad `%sFMT' specification `%s'"),
n == CONVFMT_node->var_value ? "CONV"
: n == OFMT_node->var_value ? "O"
: "", n->stptr);
+ if (n == CONVFMT_node->var_value) {
+ /* XXX -- %s or %c not allowed for CONVFMT */
+ spec = fmt_parse(CONVFMT_node, n->stptr, n->stlen);
+ if (spec == NULL)
+ fatal(_("invalid CONVFMT specification `%s'"), n->stptr);
+ } else if (n == OFMT_node->var_value) {
+ spec = fmt_parse(OFMT_node, n->stptr, n->stlen);
+ if (spec == NULL)
+ fatal(_("invalid OFMT specification `%s'"), n->stptr);
+ }
+
if (fmt_hiwater >= fmt_num) {
fmt_num *= 2;
- erealloc(fmt_list, NODE **, fmt_num * sizeof(*fmt_list), "fmt_index");
+ erealloc(fmt_list, struct fmt_list_item *, fmt_num * sizeof(*fmt_list), "fmt_index");
}
- fmt_list[fmt_hiwater] = dupnode(n);
+ fmt_list[fmt_hiwater].fmt = dupnode(n);
+ fmt_list[fmt_hiwater].spec = spec;
return fmt_hiwater++;
}
@@ -929,7 +968,7 @@ void
set_OFMT()
{
OFMTidx = fmt_index(OFMT_node->var_value);
- OFMT = fmt_list[OFMTidx]->stptr;
+ OFMT = fmt_list[OFMTidx].fmt->stptr;
}
/* set_CONVFMT --- track CONVFMT correctly */
@@ -938,7 +977,7 @@ void
set_CONVFMT()
{
CONVFMTidx = fmt_index(CONVFMT_node->var_value);
- CONVFMT = fmt_list[CONVFMTidx]->stptr;
+ CONVFMT = fmt_list[CONVFMTidx].fmt->stptr;
}
/* set_LINT --- update LINT as appropriate */
@@ -1019,6 +1058,23 @@ set_TEXTDOMAIN()
*/
}
+/* set_PREC --- tarck PREC correctly */
+
+void
+set_PREC()
+{
+ numbr_hndlr->set_numvar(PREC_node);
+}
+
+/* set_ROUNDMODE --- track ROUNDMODE correctly */
+
+void
+set_ROUNDMODE()
+{
+ numbr_hndlr->set_numvar(ROUNDMODE_node);
+}
+
+
/* update_ERRNO_int --- update the value of ERRNO based on argument */
void
@@ -1058,15 +1114,7 @@ unset_ERRNO(void)
void
update_NR()
{
-#ifdef HAVE_MPFR
- if (is_mpg_number(NR_node->var_value))
- (void) mpg_update_var(NR_node);
- else
-#endif
- if (NR_node->var_value->numbr != NR) {
- unref(NR_node->var_value);
- NR_node->var_value = make_number(NR);
- }
+ (void) numbr_hndlr->update_numvar(NR_node);
}
/* update_NF --- update the value of NF */
@@ -1090,15 +1138,7 @@ update_NF()
void
update_FNR()
{
-#ifdef HAVE_MPFR
- if (is_mpg_number(FNR_node->var_value))
- (void) mpg_update_var(FNR_node);
- else
-#endif
- if (FNR_node->var_value->numbr != FNR) {
- unref(FNR_node->var_value);
- FNR_node->var_value = make_number(FNR);
- }
+ (void) numbr_hndlr->update_numvar(FNR_node);
}
@@ -1216,42 +1256,6 @@ r_get_field(NODE *n, Func_ptr *assign, bool reference)
}
-/*
- * calc_exp_posint --- calculate x^n for positive integral n,
- * using exponentiation by squaring without recursion.
- */
-
-static AWKNUM
-calc_exp_posint(AWKNUM x, long n)
-{
- AWKNUM mult = 1;
-
- while (n > 1) {
- if ((n % 2) == 1)
- mult *= x;
- x *= x;
- n /= 2;
- }
- return mult * x;
-}
-
-/* calc_exp --- calculate x1^x2 */
-
-AWKNUM
-calc_exp(AWKNUM x1, AWKNUM x2)
-{
- long lx;
-
- if ((lx = x2) == x2) { /* integer exponent */
- if (lx == 0)
- return 1;
- return (lx > 0) ? calc_exp_posint(x1, lx)
- : 1.0 / calc_exp_posint(x1, -lx);
- }
- return (AWKNUM) pow((double) x1, (double) x2);
-}
-
-
/* setup_frame --- setup new frame for function call */
static INSTRUCTION *
@@ -1527,10 +1531,10 @@ unwind_stack(long n)
static inline int
eval_condition(NODE *t)
{
- if (t == node_Boolean[false])
+ if (t == false_node)
return false;
- if (t == node_Boolean[true])
+ if (t == true_node)
return true;
if ((t->flags & MAYBE_NUM) != 0)
@@ -1570,63 +1574,43 @@ static void
op_assign(OPCODE op)
{
NODE **lhs;
- NODE *t1, *t2;
- AWKNUM x = 0.0, x1, x2;
+ NODE *r, *t1, *t2;
lhs = POP_ADDRESS();
t1 = *lhs;
- x1 = force_number(t1)->numbr;
+ (void) force_number(t1);
- t2 = TOP_SCALAR();
- x2 = force_number(t2)->numbr;
- DEREF(t2);
+ t2 = TOP_NUMBER();
switch (op) {
case Op_assign_plus:
- x = x1 + x2;
+ r = numbr_hndlr->add(t1, t2);
break;
case Op_assign_minus:
- x = x1 - x2;
+ r = numbr_hndlr->sub(t1, t2);
break;
case Op_assign_times:
- x = x1 * x2;
+ r = numbr_hndlr->mul(t1, t2);
break;
case Op_assign_quotient:
- if (x2 == (AWKNUM) 0) {
- decr_sp();
- fatal(_("division by zero attempted in `/='"));
- }
- x = x1 / x2;
+ r = numbr_hndlr->div(t1, t2);
break;
case Op_assign_mod:
- if (x2 == (AWKNUM) 0) {
- decr_sp();
- fatal(_("division by zero attempted in `%%='"));
- }
-#ifdef HAVE_FMOD
- x = fmod(x1, x2);
-#else /* ! HAVE_FMOD */
- (void) modf(x1 / x2, &x);
- x = x1 - x2 * x;
-#endif /* ! HAVE_FMOD */
+ r = numbr_hndlr->mod(t1, t2);
break;
case Op_assign_exp:
- x = calc_exp((double) x1, (double) x2);
+ r = numbr_hndlr->pow(t1, t2);
break;
default:
- break;
- }
-
- if (t1->valref == 1 && t1->flags == (MALLOC|NUMCUR|NUMBER)) {
- /* optimization */
- t1->numbr = x;
- } else {
- unref(t1);
- t1 = *lhs = make_number(x);
+ r = NULL; /* keep warnings quiet */
+ cant_happen();
}
- UPREF(t1);
- REPLACE(t1);
+ DEREF(t2);
+ unref(*lhs);
+ *lhs = r;
+ UPREF(r);
+ REPLACE(r);
}
/* PUSH_CODE --- push a code onto the runtime stack */
@@ -1766,7 +1750,7 @@ register_exec_hook(Func_pre_exec preh, Func_post_exec posth)
/* interpreter routine when not debugging */
#include "interpret.h"
-/* interpreter routine with exec hook(s). Used when debugging and/or with MPFR. */
+/* interpreter routine with exec hook(s). Used when debugging */
#define r_interpret h_interpret
#define EXEC_HOOK 1
#include "interpret.h"
@@ -1794,14 +1778,6 @@ init_interpret()
frame_ptr->num_tail_calls = 0;
frame_ptr->vname = NULL;
- /* initialize true and false nodes */
- node_Boolean[false] = make_number(0.0);
- node_Boolean[true] = make_number(1.0);
- if (! is_mpg_number(node_Boolean[false])) {
- node_Boolean[false]->flags |= NUMINT;
- node_Boolean[true]->flags |= NUMINT;
- }
-
/*
* Select the interpreter routine. The version without
* any exec hook support (r_interpret) is faster by about
diff --git a/field.c b/field.c
index 4819ea94..ffbfc6de 100644
--- a/field.c
+++ b/field.c
@@ -196,28 +196,24 @@ rebuild_record()
*/
for (cops = ops, i = 1; i <= NF; i++) {
NODE *r = fields_arr[i];
+
if (r->stlen > 0) {
NODE *n;
- getnode(n);
if ((r->flags & FIELD) == 0) {
- *n = *Null_field;
- n->stlen = r->stlen;
if ((r->flags & (NUMCUR|NUMBER)) != 0) {
- n->flags |= (r->flags & (MPFN|MPZN|NUMCUR|NUMBER));
-#ifdef HAVE_MPFR
- if (is_mpg_float(r)) {
- mpfr_init(n->mpg_numbr);
- mpfr_set(n->mpg_numbr, r->mpg_numbr, ROUND_MODE);
- } else if (is_mpg_integer(r)) {
- mpz_init(n->mpg_i);
- mpz_set(n->mpg_i, r->mpg_i);
- } else
-#endif
- n->numbr = r->numbr;
+ n = numbr_hndlr->gawk_copy_number(r);
+ n->flags |= Null_field->flags;
+ n->flags &= ~MALLOC;
+ } else {
+ getnode(n);
+ *n = *Null_field;
}
+ n->stlen = r->stlen;
} else {
+ getnode(n);
*n = *r;
+ assert((n->flags & (NUMCUR|NUMBER)) == 0);
n->flags &= ~(MALLOC|STRING);
}
diff --git a/format.c b/format.c
new file mode 100644
index 00000000..2322d563
--- /dev/null
+++ b/format.c
@@ -0,0 +1,791 @@
+/*
+ * format.c - routines for (s)printf formatting.
+ */
+
+/*
+ * Copyright (C) 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
+ */
+
+#include "awk.h"
+
+#include "format.h"
+
+char lchbuf[] = "0123456789abcdef";
+char Uchbuf[] = "0123456789ABCDEF";
+char space_string[] = " ";
+char zero_string[] = "0";
+
+/* mbc_byte_count --- return number of bytes for corresponding numchars multibyte characters */
+
+static size_t
+mbc_byte_count(const char *ptr, size_t numchars)
+{
+#if MBS_SUPPORT
+ mbstate_t cur_state;
+ size_t sum = 0;
+ int mb_len;
+
+ memset(& cur_state, 0, sizeof(cur_state));
+
+ assert(gawk_mb_cur_max > 1);
+ mb_len = mbrlen(ptr, numchars * gawk_mb_cur_max, &cur_state);
+ if (mb_len <= 0)
+ return numchars; /* no valid m.b. char */
+
+ for (; numchars > 0; numchars--) {
+ mb_len = mbrlen(ptr, numchars * gawk_mb_cur_max, &cur_state);
+ if (mb_len <= 0)
+ break;
+ sum += mb_len;
+ ptr += mb_len;
+ }
+
+ return sum;
+#else
+ return numchars;
+#endif
+}
+
+/* mbc_char_count --- return number of m.b. chars in string, up to numbytes bytes */
+
+static size_t
+mbc_char_count(const char *ptr, size_t numbytes)
+{
+#if MBS_SUPPORT
+ mbstate_t cur_state;
+ size_t sum = 0;
+ int mb_len;
+
+ if (gawk_mb_cur_max == 1)
+ return numbytes;
+
+ memset(& cur_state, 0, sizeof(cur_state));
+
+ mb_len = mbrlen(ptr, numbytes * gawk_mb_cur_max, &cur_state);
+ if (mb_len <= 0)
+ return numbytes; /* no valid m.b. char */
+
+ for (; numbytes > 0; numbytes--) {
+ mb_len = mbrlen(ptr, numbytes * gawk_mb_cur_max, &cur_state);
+ if (mb_len <= 0)
+ break;
+ sum++;
+ ptr += mb_len;
+ }
+
+ return sum;
+#else
+ return numbytes;
+#endif
+}
+
+
+#define OUTBUF_INIT_SIZE 510
+
+/* chksize__internal --- make room for something LEN big in the output buffer */
+
+static void
+chksize__internal(struct print_fmt_buf *outb, size_t len)
+{
+ size_t delta, newsize;
+
+ assert(outb->buf != NULL);
+ delta = outb->dataend - outb->buf;
+ newsize = delta + len + OUTBUF_INIT_SIZE;
+ erealloc(outb->buf, char *, newsize + 2, "chksize__internal");
+ outb->dataend = outb->buf + delta;
+ outb->bufsize = newsize;
+ outb->room_left = len + OUTBUF_INIT_SIZE;
+}
+
+/* cpbuf_chksize__internal --- enlarge the temporary buffer */
+
+static void
+cpbuf_chksize__internal(struct print_fmt_buf *outb)
+{
+ char *cp, *prev = outb->cpbuf.buf;
+ size_t oldsize = outb->cpbuf.bufsize;
+ size_t newsize;
+
+ newsize = outb->cpbuf.bufsize = 2 * oldsize;
+ emalloc(outb->cpbuf.buf, char *, newsize + 2, "cpbuf_chksize__internal");
+ memcpy((cp = outb->cpbuf.buf + oldsize), prev, oldsize);
+ efree(prev);
+ outb->cpbuf.bufend = outb->cpbuf.buf + newsize;
+ outb->cpbuf.databegin = cp;
+}
+
+static struct print_fmt_buf static_outb;
+
+/* get_fmt_buf --- buffer(s) to manage (s)printf formatting */
+
+struct print_fmt_buf *
+get_fmt_buf()
+{
+ struct print_fmt_buf *outb;
+
+ if (static_outb.buf == NULL)
+ outb = & static_outb;
+ else {
+ emalloc(outb, struct print_fmt_buf *, sizeof (struct print_fmt_buf), "get_fmt_buf");
+ outb->is_malloced = true;
+ }
+
+ emalloc(outb->buf, char *, OUTBUF_INIT_SIZE + 2, "get_fmt_buf");
+ outb->bufsize = OUTBUF_INIT_SIZE;
+ outb->room_left = outb->bufsize;
+ outb->dataend = outb->buf;
+ outb->chksize = chksize__internal;
+
+ emalloc(outb->cpbuf.buf, char *, 64, "get_fmt_buf");
+ outb->cpbuf.bufsize = 62;
+ outb->cpbuf.databegin = outb->cpbuf.bufend = outb->cpbuf.buf + outb->cpbuf.bufsize;
+ outb->cpbuf_chksize = cpbuf_chksize__internal;
+ return outb;
+}
+
+/* fmt_parse --- parse a single format code */
+
+struct format_spec *
+fmt_parse(NODE *n, const char *fmt_string, size_t fmt_len)
+{
+ struct format_spec *spec = NULL;
+
+ spec = (struct format_spec *) format_tree(fmt_string, fmt_len, NULL, LONG_MIN);
+ if (spec != NULL && n == CONVFMT_node
+ && (spec->fmtchar == 's' || spec->fmtchar == 'c')
+ ) {
+ efree(spec);
+ spec = NULL;
+ }
+ return spec;
+}
+
+
+/* format_nondecimal --- output a nondecimal number according to a format */
+
+void
+format_nondecimal(uintmax_t val, struct format_spec *spec, struct print_fmt_buf *outb)
+{
+ uintmax_t uval = val;
+ int ii, jj;
+ const char *chbuf = spec->chbuf;
+
+# define CP cpbuf_start(outb)
+# define CEND cpbuf_end(outb)
+
+ /*
+ * When to fill with zeroes is of course not simple.
+ * First: No zero fill if left-justifying.
+ * Next: There seem to be two cases:
+ * A '0' without a precision, e.g. %06d
+ * A precision with no field width, e.g. %.10d
+ * Any other case, we don't want to fill with zeroes.
+ */
+ if (! spec->lj
+ && ((spec->zero_flag && ! spec->have_prec)
+ || (spec->fw == 0 && spec->have_prec))
+ )
+ spec->fill = zero_string;
+
+ ii = jj = 0;
+ do {
+ tmpbuf_prepend(outb, chbuf[uval % spec->base]);
+ uval /= spec->base;
+#if defined(HAVE_LOCALE_H)
+ if (spec->base == 10 && spec->quote_flag && loc.grouping[ii] && ++jj == loc.grouping[ii]) {
+ if (uval) /* only add if more digits coming */
+ tmpbuf_prepend(outb, loc.thousands_sep[0]); /* XXX --- assumption it's one char */
+ if (loc.grouping[ii+1] == 0)
+ jj = 0; /* keep using current val in loc.grouping[ii] */
+ else if (loc.grouping[ii+1] == CHAR_MAX)
+ spec->quote_flag= false;
+ else {
+ ii++;
+ jj = 0;
+ }
+ }
+#endif
+ } while (uval > 0);
+
+ /* add more output digits to match the precision */
+ if (spec->have_prec) {
+ while (CEND - CP < spec->prec)
+ tmpbuf_prepend(outb, '0');
+ }
+
+ if (spec->alt && val != 0) {
+ if (spec->base == 16) {
+ tmpbuf_prepend(outb, spec->fmtchar);
+ tmpbuf_prepend(outb, '0');
+ if (spec->fill != space_string) {
+ bchunk(outb, CP, 2);
+ CP += 2;
+ spec->fw -= 2;
+ }
+ } else if (spec->base == 8)
+ tmpbuf_prepend(outb, '0');
+ }
+
+ spec->base = 0;
+ if (spec->prec > spec->fw)
+ spec->fw = spec->prec;
+ spec->prec = CEND - CP;
+ pr_num_tail(CP, spec->prec, spec, outb);
+
+#undef CP
+#undef CEND
+}
+
+
+/*
+ * format_tree() formats arguments of sprintf,
+ * and accordingly to a fmt_string providing a format like in
+ * printf family from C library. Returns a string node which value
+ * is a formatted string. Called by sprintf function.
+ *
+ * It is one of the uglier parts of gawk. Thanks to Michal Jaegermann
+ * for taming this beast and making it compatible with ANSI C.
+ */
+
+
+NODE *
+format_tree(
+ const char *fmt_string,
+ size_t n0,
+ NODE **the_args,
+ long num_args)
+{
+ size_t cur_arg = 0;
+ NODE *retval = NULL;
+ bool toofew = false;
+ const char *s0, *s1;
+ int cs1;
+ NODE *arg;
+ long argnum;
+
+ bool used_dollar;
+ bool big_flag, bigbig_flag, small_flag, need_format;
+ long *cur = NULL;
+ uintmax_t uval;
+ char *cp;
+ size_t copy_count, char_count;
+
+ struct print_fmt_buf *outb;
+ struct format_spec spec;
+
+# define CP cpbuf_start(outb)
+# define CEND cpbuf_end(outb)
+# define CPBUF cpbuf(outb)
+
+/* parse a single format specifier */
+#define do_parse_fmt (num_args == LONG_MIN)
+
+ /*
+ * Check first for use of `count$'.
+ * If plain argument retrieval was used earlier, choke.
+ * Otherwise, return the requested argument.
+ * If not `count$' now, but it was used earlier, choke.
+ * If this format is more than total number of args, choke.
+ * Otherwise, return the current argument.
+ */
+#define parse_next_arg() { \
+ if (do_parse_fmt) \
+ goto out; \
+ else if (argnum > 0) { \
+ if (cur_arg > 1) { \
+ msg(_("fatal: must use `count$' on all formats or none")); \
+ goto out; \
+ } \
+ arg = the_args[argnum]; \
+ } else if (used_dollar) { \
+ msg(_("fatal: must use `count$' on all formats or none")); \
+ arg = 0; /* shutup the compiler */ \
+ goto out; \
+ } else if (cur_arg >= num_args) { \
+ arg = 0; /* shutup the compiler */ \
+ toofew = true; \
+ break; \
+ } else { \
+ arg = the_args[cur_arg]; \
+ cur_arg++; \
+ } \
+}
+
+ outb = get_fmt_buf();
+ cur_arg = 1;
+
+ need_format = false;
+ used_dollar = false;
+
+ s0 = s1 = fmt_string;
+
+ while (n0-- > 0) {
+ if (*s1 != '%') {
+ s1++;
+ continue;
+ }
+ need_format = true;
+ bchunk(outb, s0, s1 - s0);
+ s0 = s1;
+ argnum = 0;
+
+ memset(& spec, '\0', sizeof (spec));
+ cur = & spec.fw;
+ spec.fill = space_string; /* always space for string */
+
+ big_flag = bigbig_flag = small_flag = false;
+ CP = CEND;
+ s1++;
+
+retry:
+ if (n0-- == 0) /* ran out early! */
+ break;
+
+ switch (cs1 = *s1++) {
+ case (-1): /* dummy case to allow for checking */
+check_pos:
+ if (cur != & spec.fw)
+ break; /* reject as a valid format */
+ goto retry;
+ case '%':
+ need_format = false;
+ /*
+ * 29 Oct. 2002:
+ * The C99 standard pages 274 and 279 seem to imply that
+ * since there's no arg converted, the field width doesn't
+ * apply. The code already was that way, but this
+ * comment documents it, at least in the code.
+ */
+ if (do_lint) {
+ const char *msg = NULL;
+
+ if (spec.fw && ! spec.have_prec)
+ msg = _("field width is ignored for `%%' specifier");
+ else if (spec.fw == 0 && spec.have_prec)
+ msg = _("precision is ignored for `%%' specifier");
+ else if (spec.fw && spec.have_prec)
+ msg = _("field width and precision are ignored for `%%' specifier");
+
+ if (msg != NULL)
+ lintwarn("%s", msg);
+ }
+ bchunk_one(outb, "%");
+ s0 = s1;
+ break;
+
+ case '0':
+ /*
+ * Only turn on zero_flag if we haven't seen
+ * the field width or precision yet. Otherwise,
+ * screws up floating point formatting.
+ */
+ if (cur == & spec.fw)
+ spec.zero_flag = true;
+ if (spec.lj)
+ goto retry;
+ /* FALL through */
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ if (cur == NULL)
+ break;
+ if (spec.prec >= 0)
+ *cur = cs1 - '0';
+ /*
+ * with a negative precision *cur is already set
+ * to -1, so it will remain negative, but we have
+ * to "eat" precision digits in any case
+ */
+ while (n0 > 0 && *s1 >= '0' && *s1 <= '9') {
+ --n0;
+ *cur = *cur * 10 + *s1++ - '0';
+ }
+ if (spec.prec < 0) /* negative precision is discarded */
+ spec.have_prec = false;
+ if (cur == & spec.prec)
+ cur = NULL;
+ if (n0 == 0) /* badly formatted control string */
+ continue;
+ goto retry;
+ case '$':
+ if (do_traditional) {
+ msg(_("fatal: `$' is not permitted in awk formats"));
+ goto out;
+ }
+ if (do_parse_fmt)
+ goto out;
+
+ if (cur == & spec.fw) {
+ argnum = spec.fw;
+ spec.fw = 0;
+ used_dollar = true;
+ if (argnum <= 0) {
+ msg(_("fatal: arg count with `$' must be > 0"));
+ goto out;
+ }
+ if (argnum >= num_args) {
+ msg(_("fatal: arg count %ld greater than total number of supplied arguments"), argnum);
+ goto out;
+ }
+ } else {
+ msg(_("fatal: `$' not permitted after period in format"));
+ goto out;
+ }
+
+ goto retry;
+ case '*':
+ if (cur == NULL)
+ break;
+ if (! do_traditional && isdigit((unsigned char) *s1)) {
+ int val = 0;
+
+ for (; n0 > 0 && *s1 && isdigit((unsigned char) *s1); s1++, n0--) {
+ val *= 10;
+ val += *s1 - '0';
+ }
+ if (*s1 != '$') {
+ msg(_("fatal: no `$' supplied for positional field width or precision"));
+ goto out;
+ } else {
+ s1++;
+ n0--;
+ }
+ if (val >= num_args) {
+ toofew = true;
+ break;
+ }
+ arg = the_args[val];
+ } else {
+ parse_next_arg();
+ }
+
+ (void) force_number(arg);
+ *cur = get_number_si(arg);
+ if (*cur < 0 && cur == & spec.fw) {
+ *cur = -*cur;
+ spec.lj++;
+ }
+ if (cur == & spec.prec) {
+ if (*cur >= 0)
+ spec.have_prec = true;
+ else
+ spec.have_prec = false;
+ cur = NULL;
+ }
+ goto retry;
+ case ' ': /* print ' ' or '-' */
+ /* 'space' flag is ignored */
+ /* if '+' already present */
+ if (spec.signchar != false)
+ goto check_pos;
+ /* FALL THROUGH */
+ case '+': /* print '+' or '-' */
+ spec.signchar = cs1;
+ goto check_pos;
+ case '-':
+ if (spec.prec < 0)
+ break;
+ if (cur == & spec.prec) {
+ spec.prec = -1;
+ goto retry;
+ }
+ spec.lj++; /* filling is ignored */
+ goto check_pos;
+ case '.':
+ if (cur != & spec.fw)
+ break;
+ cur = & spec.prec;
+ spec.have_prec = true;
+ goto retry;
+ case '#':
+ spec.alt = true;
+ goto check_pos;
+ case '\'':
+#if defined(HAVE_LOCALE_H)
+ /* allow quote_flag if there is a thousands separator. */
+ if (loc.thousands_sep[0] != '\0')
+ spec.quote_flag= true;
+ goto check_pos;
+#else
+ goto retry;
+#endif
+ case 'l':
+ if (big_flag)
+ break;
+ else {
+ static bool warned = false;
+
+ if (do_lint && ! warned) {
+ lintwarn(_("`l' is meaningless in awk formats; ignored"));
+ warned = true;
+ }
+ if (do_posix) {
+ msg(_("fatal: `l' is not permitted in POSIX awk formats"));
+ goto out;
+ }
+ }
+ big_flag = true;
+ goto retry;
+ case 'L':
+ if (bigbig_flag)
+ break;
+ else {
+ static bool warned = false;
+
+ if (do_lint && ! warned) {
+ lintwarn(_("`L' is meaningless in awk formats; ignored"));
+ warned = true;
+ }
+ if (do_posix) {
+ msg(_("fatal: `L' is not permitted in POSIX awk formats"));
+ goto out;
+ }
+ }
+ bigbig_flag = true;
+ goto retry;
+ case 'h':
+ if (small_flag)
+ break;
+ else {
+ static bool warned = false;
+
+ if (do_lint && ! warned) {
+ lintwarn(_("`h' is meaningless in awk formats; ignored"));
+ warned = true;
+ }
+ if (do_posix) {
+ msg(_("fatal: `h' is not permitted in POSIX awk formats"));
+ goto out;
+ }
+ }
+ small_flag = true;
+ goto retry;
+ case 'c':
+ need_format = false;
+ spec.fmtchar = cs1;
+ parse_next_arg();
+ /* user input that looks numeric is numeric */
+ if ((arg->flags & (MAYBE_NUM|NUMBER)) == MAYBE_NUM)
+ (void) force_number(arg);
+ if ((arg->flags & NUMBER) != 0) {
+ uval = get_number_uj(arg);
+#if MBS_SUPPORT
+ if (gawk_mb_cur_max > 1) {
+ char buf[100];
+ wchar_t wc;
+ mbstate_t mbs;
+ size_t count;
+
+ memset(& mbs, 0, sizeof(mbs));
+
+ /* handle systems with too small wchar_t */
+ if (sizeof(wchar_t) < 4 && uval > 0xffff) {
+ if (do_lint)
+ lintwarn(
+ _("[s]printf: value %g is too big for %%c format"),
+ arg->numbr);
+
+ goto out0;
+ }
+
+ wc = uval;
+
+ count = wcrtomb(buf, wc, & mbs);
+ if (count == 0
+ || count == (size_t) -1) {
+ if (do_lint)
+ lintwarn(
+ _("[s]printf: value %g is not a valid wide character"),
+ arg->numbr);
+
+ goto out0;
+ }
+
+ memcpy(CPBUF, buf, count);
+ spec.prec = count;
+ cp = CPBUF;
+ goto pr_tail;
+ }
+out0:
+ ;
+ /* else,
+ fall through */
+#endif
+ CPBUF[0] = uval;
+ spec.prec = 1;
+ cp = CPBUF;
+ goto pr_tail;
+ }
+ /*
+ * As per POSIX, only output first character of a
+ * string value. Thus, we ignore any provided
+ * precision, forcing it to 1. (Didn't this
+ * used to work? 6/2003.)
+ */
+ cp = arg->stptr;
+ spec.prec = 1;
+#if MBS_SUPPORT
+ /*
+ * First character can be multiple bytes if
+ * it's a multibyte character. Grr.
+ */
+ if (gawk_mb_cur_max > 1) {
+ mbstate_t state;
+ size_t count;
+
+ memset(& state, 0, sizeof(state));
+ count = mbrlen(cp, arg->stlen, & state);
+ if (count != (size_t) -1 && count != (size_t) -2 && count > 0) {
+ spec.prec = count;
+ /* may need to increase fw so that padding happens, see pr_tail code */
+ if (spec.fw > 0)
+ spec.fw += count - 1;
+ }
+ }
+#endif
+ goto pr_tail;
+ case 's':
+ need_format = false;
+ spec.fmtchar = cs1;
+ parse_next_arg();
+ arg = force_string(arg);
+ if (spec.fw == 0 && ! spec.have_prec)
+ spec.prec = arg->stlen;
+ else {
+ char_count = mbc_char_count(arg->stptr, arg->stlen);
+ if (! spec.have_prec || spec.prec > char_count)
+ spec.prec = char_count;
+ }
+ cp = arg->stptr;
+ pr_tail:
+ if (! spec.lj)
+ pr_fill(& spec, outb);
+
+ copy_count = spec.prec;
+ if (spec.fw == 0 && ! spec.have_prec)
+ ;
+ else if (gawk_mb_cur_max > 1) {
+ if (cs1 == 's') {
+ assert(cp == arg->stptr || cp == CPBUF);
+ copy_count = mbc_byte_count(arg->stptr, spec.prec);
+ }
+ /* prec was set by code for %c */
+ /* else
+ copy_count = prec; */
+ }
+
+ bchunk(outb, cp, copy_count);
+ pr_fill(& spec, outb);
+
+ s0 = s1;
+ break;
+
+ case 'X':
+ /* FALL THROUGH */
+ case 'x':
+ spec.base += 6;
+ /* FALL THROUGH */
+ case 'u':
+ spec.base += 2;
+ /* FALL THROUGH */
+ case 'o':
+ spec.base += 8;
+ goto fmt1;
+ case 'F':
+#if ! defined(PRINTF_HAS_F_FORMAT) || PRINTF_HAS_F_FORMAT != 1
+ cs1 = 'f';
+ /* FALL THROUGH */
+#endif
+ case 'g':
+ case 'G':
+ case 'e':
+ case 'f':
+ case 'E':
+ case 'd':
+ case 'i':
+ fmt1:
+ need_format = false;
+ spec.fmtchar = cs1;
+ parse_next_arg();
+ (void) force_number(arg);
+ spec.fmtchar = cs1;
+ if (format_number_printf(arg, & spec, outb) < 0)
+ goto out;
+
+ s0 = s1;
+ break;
+
+ default:
+ if (isalpha(cs1)) {
+ if (do_lint)
+ lintwarn(_("ignoring unknown format specifier character `%c': no argument converted"), cs1);
+ if (do_parse_fmt)
+ goto out;
+ }
+ break;
+ }
+ if (toofew) {
+ msg("%s\n\t`%s'\n\t%*s%s",
+ _("fatal: not enough arguments to satisfy format string"),
+ fmt_string, (int) (s1 - fmt_string - 1), "",
+ _("^ ran out for this one"));
+ goto out;
+ }
+ }
+
+ if (do_lint) {
+ if (need_format)
+ lintwarn(_("[s]printf: format specifier does not have control letter"));
+ if (cur_arg < num_args)
+ lintwarn(_("too many arguments supplied for format string"));
+ }
+
+ bchunk(outb, s0, s1 - s0);
+ retval = bytes2node(outb, NULL);
+out:
+ free_fmt_buf(outb);
+
+ if (do_parse_fmt) {
+ struct format_spec *cp_spec;
+
+ assert(retval == NULL);
+ if (spec.fmtchar == (char) 0)
+ return NULL;
+ emalloc(cp_spec, struct format_spec *, sizeof (*cp_spec), "format_tree");
+ *cp_spec = spec;
+ return (NODE *) cp_spec;
+ }
+
+ if (retval == NULL)
+ gawk_exit(EXIT_FATAL); /* debugger needs this */
+
+ return retval;
+
+#undef CP
+#undef CEND
+#undef CPBUF
+}
diff --git a/format.h b/format.h
new file mode 100644
index 00000000..0c9140dc
--- /dev/null
+++ b/format.h
@@ -0,0 +1,189 @@
+/*
+ * format.h - (s)printf formatting related definitions.
+ */
+
+/*
+ * Copyright (C) 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
+ */
+
+/* format specification */
+
+struct format_spec {
+ int base;
+ long fw;
+ long prec;
+ const char *fill;
+ const char *chbuf;
+ bool lj;
+ bool alt;
+ bool have_prec;
+ bool zero_flag;
+ bool quote_flag;
+ char signchar;
+ char fmtchar;
+};
+
+/* indices in `fmt_index' for "%d" and "%.0f" */
+
+enum { INT_d_FMT_INDEX, INT_0f_FMT_INDEX };
+
+
+/* struct to manage awk (s)printf formatted string */
+
+struct print_fmt_buf {
+ char *buf; /* beginning of buffer */
+ char *dataend; /* end of current data */
+ size_t bufsize;
+ size_t room_left;
+ bool is_malloced; /* true if this struct is malloc-ed */
+ void (*chksize)(struct print_fmt_buf *, size_t);
+ void (*cpbuf_chksize)(struct print_fmt_buf *);
+
+ /*
+ * temporary buffer: can be used to prepend one character at a time
+ * without overflowing the buffer; used primarily to format integers.
+ */
+ struct {
+ char *buf; /* beginning of buffer */
+ char *bufend; /* end of buffer */
+ size_t bufsize;
+ char *databegin; /* start of current data */
+ } cpbuf;
+};
+
+extern struct print_fmt_buf *get_fmt_buf(void);
+extern void format_nondecimal(uintmax_t, struct format_spec *, struct print_fmt_buf *);
+extern NODE *format_tree(const char *, size_t, NODE **, long);
+
+extern char lchbuf[];
+extern char Uchbuf[];
+extern char space_string[];
+extern char zero_string[];
+
+# define buf_start(ob) ((ob)->buf)
+# define buf_end(ob) ((ob)->dataend)
+# define buf_space(ob) ((ob)->room_left)
+# define cpbuf_start(ob) ((ob)->cpbuf.databegin)
+# define cpbuf_end(ob) ((ob)->cpbuf.bufend)
+# define cpbuf(ob) ((ob)->cpbuf.buf)
+
+
+/* chksize --- make room for something LEN big in the output buffer */
+
+static inline void
+chksize(struct print_fmt_buf *outb, size_t len)
+{
+ if (len > outb->room_left)
+ outb->chksize(outb, len);
+}
+
+/* bchunk --- copy LEN bytes from STR checking for space in the process */
+
+static inline void
+bchunk(struct print_fmt_buf *outb, const char *str, size_t len)
+{
+ if (len > 0) {
+ if (len > outb->room_left)
+ outb->chksize(outb, len);
+ outb->dataend = (char *) memcpy(outb->dataend, str, len) + len;
+ outb->room_left -= len;
+ }
+}
+
+/* bchunk_one --- copy one byte from STR checking for space in the process */
+
+static inline void
+bchunk_one(struct print_fmt_buf *outb, const char *str)
+{
+ if (1 > outb->room_left)
+ outb->chksize(outb, 1);
+ *outb->dataend++ = *str;
+ --outb->room_left;
+}
+
+/* buf_adjust --- adjust buffer after appending LEN bytes */
+
+static inline void
+buf_adjust(struct print_fmt_buf *outb, size_t len)
+{
+ assert(len <= outb->room_left);
+ outb->dataend += len;
+ outb->room_left -= len;
+}
+
+/* bytes2node --- convert bytes to string NODE */
+
+static inline NODE *
+bytes2node(struct print_fmt_buf *outb, NODE *node)
+{
+ /* FIXME -- realloc buf? AFAIK, never done before or an issue at all -- JH */
+ if (node != NULL) {
+ node->stptr = outb->buf;
+ node->stlen = outb->dataend - outb->buf;
+ } else
+ node = make_str_node(outb->buf, outb->dataend - outb->buf, ALREADY_MALLOCED);
+ outb->buf = NULL;
+ return node;
+}
+
+/* tmpbuf_prepend --- prepend one byte to temporary buffer */
+
+static inline void
+tmpbuf_prepend(struct print_fmt_buf *outb, char ch)
+{
+ if (outb->cpbuf.databegin == outb->cpbuf.buf)
+ outb->cpbuf_chksize(outb);
+ *--outb->cpbuf.databegin = ch;
+}
+
+/* pr_fill --- fill buffer with current fill character */
+
+static inline void
+pr_fill(struct format_spec *spec, struct print_fmt_buf *outb)
+{
+ while (spec->fw > spec->prec) {
+ bchunk_one(outb, spec->fill);
+ spec->fw--;
+ }
+}
+
+static inline void
+pr_num_tail(const char *cp, size_t copy_count, struct format_spec *spec, struct print_fmt_buf *outb)
+{
+ if (! spec->lj)
+ pr_fill(spec, outb);
+ bchunk(outb, cp, copy_count);
+ pr_fill(spec, outb);
+}
+
+
+/* free_print_fmt_buf --- free buffer */
+
+static inline void
+free_fmt_buf(struct print_fmt_buf *outb)
+{
+ if (outb->buf != NULL) {
+ efree(outb->buf);
+ outb->buf = NULL;
+ }
+ efree(outb->cpbuf.buf);
+ if (outb->is_malloced)
+ efree(outb);
+}
diff --git a/gawkapi.c b/gawkapi.c
index bcf8d90a..87e12448 100644
--- a/gawkapi.c
+++ b/gawkapi.c
@@ -636,7 +636,7 @@ api_sym_update_scalar(awk_ext_id_t id,
*/
switch (value->val_type) {
case AWK_NUMBER:
- if (node->var_value->valref == 1 && ! do_mpfr) {
+ if (node->var_value->valref == 1 && numbr_hndlr == & awknum_hndlr) {
NODE *r = node->var_value;
/* r_unref: */
@@ -660,7 +660,8 @@ api_sym_update_scalar(awk_ext_id_t id,
if ((r->flags & (MALLOC|STRCUR)) == (MALLOC|STRCUR))
efree(r->stptr);
- mpfr_unset(r);
+ if (free_number && (r->flags & (NUMBER|NUMCUR)) != 0)
+ free_number(r);
free_wstr(r);
/* make_str_node(s, l, ALREADY_MALLOCED): */
@@ -1130,7 +1131,7 @@ init_ext_api()
api_impl.do_flags[2] = (do_profile ? 1 : 0);
api_impl.do_flags[3] = (do_sandbox ? 1 : 0);
api_impl.do_flags[4] = (do_debug ? 1 : 0);
- api_impl.do_flags[5] = (do_mpfr ? 1 : 0);
+ api_impl.do_flags[5] = (numbr_hndlr != & awknum_hndlr);
}
/* update_ext_api --- update the variables in the API that can change */
diff --git a/int_array.c b/int_array.c
index c2bf37b5..6caf512e 100644
--- a/int_array.c
+++ b/int_array.c
@@ -85,7 +85,7 @@ is_integer(NODE *symbol, NODE *subs)
long l;
AWKNUM d;
- if (subs == Nnull_string || do_mpfr)
+ if (subs == Nnull_string)
return NULL;
if ((subs->flags & NUMINT) != 0)
diff --git a/interpret.h b/interpret.h
index 28804330..e84c7b36 100644
--- a/interpret.h
+++ b/interpret.h
@@ -34,9 +34,9 @@ r_interpret(INSTRUCTION *code)
INSTRUCTION *ni;
NODE *t1, *t2;
NODE **lhs;
- AWKNUM x, x2;
int di;
Regexp *rp;
+ NODE *booleans[] = { false_node, true_node };
NODE *set_array = NULL; /* array with a post-assignment routine */
NODE *set_idx = NULL; /* the index of the array element */
@@ -186,7 +186,7 @@ uninitialized_scalar:
cant_happen();
}
}
- break;
+ break;
case Op_push_param: /* function argument */
m = pc->memory;
@@ -398,7 +398,7 @@ uninitialized_scalar:
DEREF(t1);
if ((op == Op_and && di) || (op == Op_or && ! di))
break;
- r = node_Boolean[di];
+ r = booleans[di];
UPREF(r);
PUSH(r);
ni = pc->target_jmp;
@@ -407,7 +407,7 @@ uninitialized_scalar:
case Op_and_final:
case Op_or_final:
t1 = TOP_SCALAR();
- r = node_Boolean[eval_condition(t1)];
+ r = booleans[eval_condition(t1)];
DEREF(t1);
UPREF(r);
REPLACE(r);
@@ -415,181 +415,115 @@ uninitialized_scalar:
case Op_not:
t1 = TOP_SCALAR();
- r = node_Boolean[! eval_condition(t1)];
+ r = booleans[! eval_condition(t1)];
DEREF(t1);
UPREF(r);
REPLACE(r);
break;
case Op_equal:
- r = node_Boolean[cmp_scalars() == 0];
+ r = booleans[cmp_scalars() == 0];
UPREF(r);
REPLACE(r);
break;
case Op_notequal:
- r = node_Boolean[cmp_scalars() != 0];
+ r = booleans[cmp_scalars() != 0];
UPREF(r);
REPLACE(r);
break;
case Op_less:
- r = node_Boolean[cmp_scalars() < 0];
+ r = booleans[cmp_scalars() < 0];
UPREF(r);
REPLACE(r);
break;
case Op_greater:
- r = node_Boolean[cmp_scalars() > 0];
+ r = booleans[cmp_scalars() > 0];
UPREF(r);
REPLACE(r);
break;
case Op_leq:
- r = node_Boolean[cmp_scalars() <= 0];
+ r = booleans[cmp_scalars() <= 0];
UPREF(r);
REPLACE(r);
break;
case Op_geq:
- r = node_Boolean[cmp_scalars() >= 0];
+ r = booleans[cmp_scalars() >= 0];
UPREF(r);
REPLACE(r);
break;
- case Op_plus_i:
- x2 = force_number(pc->memory)->numbr;
- goto plus;
+#define ARITHOP(OP) \
+t2 = POP_NUMBER(); \
+t1 = TOP_NUMBER(); \
+r = numbr_hndlr->OP(t1, t2); \
+DEREF(t1); \
+DEREF(t2); REPLACE(r)
+
case Op_plus:
- t2 = POP_NUMBER();
- x2 = t2->numbr;
- DEREF(t2);
-plus:
- t1 = TOP_NUMBER();
- r = make_number(t1->numbr + x2);
- DEREF(t1);
- REPLACE(r);
+ ARITHOP(add);
break;
- case Op_minus_i:
- x2 = force_number(pc->memory)->numbr;
- goto minus;
case Op_minus:
- t2 = POP_NUMBER();
- x2 = t2->numbr;
- DEREF(t2);
-minus:
- t1 = TOP_NUMBER();
- r = make_number(t1->numbr - x2);
- DEREF(t1);
- REPLACE(r);
+ ARITHOP(sub);
break;
- case Op_times_i:
- x2 = force_number(pc->memory)->numbr;
- goto times;
case Op_times:
- t2 = POP_NUMBER();
- x2 = t2->numbr;
- DEREF(t2);
-times:
- t1 = TOP_NUMBER();
- r = make_number(t1->numbr * x2);
- DEREF(t1);
- REPLACE(r);
+ ARITHOP(mul);
break;
- case Op_exp_i:
- x2 = force_number(pc->memory)->numbr;
- goto exp;
- case Op_exp:
- t2 = POP_NUMBER();
- x2 = t2->numbr;
- DEREF(t2);
-exp:
- t1 = TOP_NUMBER();
- r = make_number(calc_exp(t1->numbr, x2));
- DEREF(t1);
- REPLACE(r);
+ case Op_quotient:
+ ARITHOP(div);
break;
- case Op_quotient_i:
- x2 = force_number(pc->memory)->numbr;
- goto quotient;
- case Op_quotient:
- t2 = POP_NUMBER();
- x2 = t2->numbr;
- DEREF(t2);
-quotient:
- t1 = TOP_NUMBER();
- if (x2 == 0)
- fatal(_("division by zero attempted"));
- r = make_number(t1->numbr / x2);
- DEREF(t1);
- REPLACE(r);
- break;
+ case Op_exp:
+ ARITHOP(pow);
+ break;
- case Op_mod_i:
- x2 = force_number(pc->memory)->numbr;
- goto mod;
case Op_mod:
- t2 = POP_NUMBER();
- x2 = t2->numbr;
- DEREF(t2);
-mod:
- t1 = TOP_NUMBER();
- if (x2 == 0)
- fatal(_("division by zero attempted in `%%'"));
-#ifdef HAVE_FMOD
- x = fmod(t1->numbr, x2);
-#else /* ! HAVE_FMOD */
- (void) modf(t1->numbr / x2, &x);
- x = t1->numbr - x * x2;
-#endif /* ! HAVE_FMOD */
- r = make_number(x);
-
- DEREF(t1);
- REPLACE(r);
+ ARITHOP(mod);
break;
+#undef ARITHOP
case Op_preincrement:
case Op_predecrement:
- x = op == Op_preincrement ? 1.0 : -1.0;
lhs = TOP_ADDRESS();
- t1 = *lhs;
- force_number(t1);
- if (t1->valref == 1 && t1->flags == (MALLOC|NUMCUR|NUMBER)) {
- /* optimization */
- t1->numbr += x;
- r = t1;
- } else {
- r = *lhs = make_number(t1->numbr + x);
- unref(t1);
- }
+ t1 = force_number(*lhs);
+ r = *lhs = numbr_hndlr->add_long(t1, op == Op_preincrement ? 1 : -1);
+ unref(t1);
UPREF(r);
REPLACE(r);
break;
case Op_postincrement:
case Op_postdecrement:
- x = op == Op_postincrement ? 1.0 : -1.0;
lhs = TOP_ADDRESS();
- t1 = *lhs;
- force_number(t1);
- r = make_number(t1->numbr);
- if (t1->valref == 1 && t1->flags == (MALLOC|NUMCUR|NUMBER)) {
- /* optimization */
- t1->numbr += x;
- } else {
- *lhs = make_number(t1->numbr + x);
- unref(t1);
- }
+ t1 = force_number(*lhs);
+ r = numbr_hndlr->gawk_copy_number(t1);
+ *lhs = numbr_hndlr->add_long(t1, op == Op_postincrement ? 1 : -1);
+ unref(t1);
+ REPLACE(r);
+ break;
+
+ case Op_unary_plus:
+ /*
+ * POSIX semantics: force a conversion to numeric type.
+ * Arbitrary-precision semantics: force the working precision.
+ */
+ t1 = TOP_NUMBER();
+ r = numbr_hndlr->gawk_copy_number(t1);
+ DEREF(t1);
REPLACE(r);
break;
case Op_unary_minus:
t1 = TOP_NUMBER();
- r = make_number(-t1->numbr);
+ r = numbr_hndlr->gawk_copy_number(t1);
+ numbr_hndlr->gawk_negate_number(r);
DEREF(t1);
REPLACE(r);
break;
@@ -840,7 +774,7 @@ mod:
case Op_in_array:
t1 = POP_ARRAY();
t2 = mk_sub(pc->expr_count);
- r = node_Boolean[(in_array(t1, t2) != NULL)];
+ r = booleans[(in_array(t1, t2) != NULL)];
DEREF(t2);
UPREF(r);
PUSH(r);
@@ -989,13 +923,13 @@ match_re:
*/
di = research(rp, t1->stptr, 0, t1->stlen,
- avoid_dfa(m, t1->stptr, t1->stlen));
+ avoid_dfa(m, t1->stptr, t1->stlen));
di = (di == -1) ^ (op != Op_nomatch);
if (op != Op_match_rec) {
decr_sp();
DEREF(t1);
}
- r = node_Boolean[di];
+ r = booleans[di];
UPREF(r);
PUSH(r);
break;
@@ -1368,8 +1302,8 @@ match_re:
}
result = ip->triggered || di;
- ip->triggered ^= di; /* update triggered flag */
- r = node_Boolean[result]; /* final value of condition pair */
+ ip->triggered ^= di; /* update triggered flag */
+ r = booleans[result]; /* final value of condition pair */
UPREF(r);
REPLACE(r);
JUMPTO(pc->target_jmp);
diff --git a/io.c b/io.c
index 7930904d..feef47eb 100644
--- a/io.c
+++ b/io.c
@@ -192,14 +192,6 @@
# endif
#endif
-#ifdef HAVE_MPFR
-/* increment NR or FNR */
-#define INCREMENT_REC(X) (do_mpfr && X == (LONG_MAX - 1)) ? \
- (mpz_add_ui(M##X, M##X, 1), X = 0) : X++
-#else
-#define INCREMENT_REC(X) X++
-#endif
-
typedef enum { CLOSE_ALL, CLOSE_TO, CLOSE_FROM } two_way_close_type;
/* Several macros to make the code a bit clearer. */
@@ -458,6 +450,7 @@ nextfile(IOBUF **curfile, bool skipping)
return 0;
}
+ (void) force_number(ARGC_node->var_value); /* make no assumptions! */
argc = get_number_si(ARGC_node->var_value);
for (; i < argc; i++) {
@@ -481,11 +474,11 @@ nextfile(IOBUF **curfile, bool skipping)
/* manage the awk variables: */
unref(FILENAME_node->var_value);
FILENAME_node->var_value = dupnode(arg);
-#ifdef HAVE_MPFR
- if (is_mpg_number(FNR_node->var_value))
- mpz_set_ui(MFNR, 0);
-#endif
- FNR = 0;
+
+ unref(FNR_node->var_value);
+ FNR_node->var_value = dupnode(false_node);
+ numbr_hndlr->set_numvar(FNR_node);
+ assert(FNR == 0);
/* IOBUF management: */
errno = 0;
@@ -547,14 +540,8 @@ nextfile(IOBUF **curfile, bool skipping)
void
set_FNR()
{
- NODE *n = FNR_node->var_value;
- (void) force_number(n);
-#ifdef HAVE_MPFR
- if (is_mpg_number(n))
- FNR = mpg_set_var(FNR_node);
- else
-#endif
- FNR = get_number_si(n);
+ (void) force_number(FNR_node->var_value);
+ numbr_hndlr->set_numvar(FNR_node);
}
/* set_NR --- update internal NR from awk variable */
@@ -562,14 +549,8 @@ set_FNR()
void
set_NR()
{
- NODE *n = NR_node->var_value;
- (void) force_number(n);
-#ifdef HAVE_MPFR
- if (is_mpg_number(n))
- NR = mpg_set_var(NR_node);
- else
-#endif
- NR = get_number_si(n);
+ (void) force_number(NR_node->var_value);
+ numbr_hndlr->set_numvar(NR_node);
}
/* inrec --- This reads in a record from the input file */
@@ -591,8 +572,17 @@ inrec(IOBUF *iop, int *errcode)
if (cnt == EOF) {
retval = false;
} else {
- INCREMENT_REC(NR);
- INCREMENT_REC(FNR);
+#if 0
+ /* XXX: looser if AWKNUM is long double */
+ if (numbr_hndlr == & awknum_hndlr) {
+ NR++;
+ FNR++;
+ } else
+#endif
+ {
+ NR = numbr_hndlr->increment_var(NR_node, NR);
+ FNR = numbr_hndlr->increment_var(FNR_node, FNR);
+ }
set_record(begin, cnt);
if (*errcode > 0)
retval = false;
@@ -2472,8 +2462,17 @@ do_getline(int into_variable, IOBUF *iop)
if (cnt == EOF)
return NULL; /* try next file */
- INCREMENT_REC(NR);
- INCREMENT_REC(FNR);
+#if 0
+ /* XXX: looser if AWKNUM is long double */
+ if (numbr_hndlr == & awknum_hndlr) {
+ NR++;
+ FNR++;
+ } else
+#endif
+ {
+ NR = numbr_hndlr->increment_var(NR_node, NR);
+ FNR = numbr_hndlr->increment_var(FNR_node, FNR);
+ }
if (! into_variable) /* no optional var. */
set_record(s, cnt);
diff --git a/main.c b/main.c
index 41f10a17..4a31459e 100644
--- a/main.c
+++ b/main.c
@@ -45,8 +45,6 @@ typedef void *stackoverflow_context_t;
#define DEFAULT_PROFILE "awkprof.out" /* where to put profile */
#define DEFAULT_VARFILE "awkvars.out" /* where to put vars */
-#define DEFAULT_PREC 53
-#define DEFAULT_ROUNDMODE "N" /* round to nearest */
static const char *varfile = DEFAULT_VARFILE;
const char *command_file = NULL; /* debugger commands */
@@ -68,9 +66,12 @@ static void version(void) ATTRIBUTE_NORETURN;
static void init_fds(void);
static void init_groupset(void);
static void save_argv(int, char **);
+static void init_numbr_handler(bltin_t **);
+static void print_numbr_hndlr_versions(void);
extern int debug_prog(INSTRUCTION *pc); /* debug.c */
-extern int init_debug(); /* debug.c */
+extern int init_debug(void); /* debug.c */
+extern void init_parser(const bltin_t *); /* awkgram.c */
/* These nodes store all the special variables AWK uses */
NODE *ARGC_node, *ARGIND_node, *ARGV_node, *BINMODE_node, *CONVFMT_node;
@@ -121,6 +122,8 @@ INSTRUCTION *rule_list;
int exit_val = EXIT_SUCCESS; /* exit value */
+numbr_handler_t *numbr_hndlr; /* number handler */
+
#if defined(YYDEBUG) || defined(GAWKDEBUG)
extern int yydebug;
#endif
@@ -221,6 +224,10 @@ main(int argc, char **argv)
char *extra_stack;
int have_srcfile = 0;
SRCFILE *s;
+ bltin_t *numbr_bltins;
+
+ /* default number handler */
+ numbr_hndlr = & awknum_hndlr;
/* do these checks early */
if (getenv("TIDYMEM") != NULL)
@@ -308,7 +315,7 @@ main(int argc, char **argv)
#undef STACK_SIZE
myname = gawk_name(argv[0]);
- os_arg_fixup(&argc, &argv); /* emulate redirection, expand wildcards */
+ os_arg_fixup(& argc, & argv); /* emulate redirection, expand wildcards */
if (argc < 2)
usage(EXIT_FAILURE, stderr);
@@ -319,12 +326,6 @@ main(int argc, char **argv)
/* Robustness: check that file descriptors 0, 1, 2 are open */
init_fds();
- /* init array handling. */
- array_init();
-
- /* init the symbol tables */
- init_symbol_table();
-
output_fp = stdout;
/* we do error messages ourselves on invalid options */
@@ -470,7 +471,7 @@ main(int argc, char **argv)
case 'M':
#ifdef HAVE_MPFR
- do_flags |= DO_MPFR;
+ numbr_hndlr = & mpfp_hndlr;
#else
warning(_("-M ignored: MPFR/GMP support not compiled in"));
#endif
@@ -595,29 +596,21 @@ out:
}
#endif
+ /* Set up number handler */
+ init_numbr_handler(& numbr_bltins);
+
if (do_debug) /* Need to register the debugger pre-exec hook before any other */
init_debug();
-#ifdef HAVE_MPFR
- /* Set up MPFR defaults, and register pre-exec hook to process arithmetic opcodes */
- if (do_mpfr)
- init_mpfr(DEFAULT_PREC, DEFAULT_ROUNDMODE);
-#endif
+ /* init array handling. */
+ array_init();
+
+ /* init the symbol tables */
+ init_symbol_table();
/* load group set */
init_groupset();
-#ifdef HAVE_MPFR
- if (do_mpfr) {
- mpz_init(Nnull_string->mpg_i);
- Nnull_string->flags = (MALLOC|STRCUR|STRING|MPZN|NUMCUR|NUMBER);
- } else
-#endif
- {
- Nnull_string->numbr = 0.0;
- Nnull_string->flags = (MALLOC|STRCUR|STRING|NUMCUR|NUMBER);
- }
-
/*
* Tell the regex routines how they should work.
* Do this before initializing variables, since
@@ -682,7 +675,7 @@ out:
optind++;
}
- /* Select the interpreter routine */
+ /* select the interpreter routine */
init_interpret();
init_args(optind, argc,
@@ -697,6 +690,10 @@ out:
*/
setlocale(LC_NUMERIC, "C");
#endif
+
+ /* initialize parser related variables */
+ init_parser(numbr_bltins);
+
/* Read in the program */
if (parse_program(& code_block) != 0)
exit(EXIT_FAILURE);
@@ -755,11 +752,6 @@ out:
if (do_dump_vars)
dump_vars(varfile);
-#ifdef HAVE_MPFR
- if (do_mpfr)
- cleanup_mpfr();
-#endif
-
if (do_tidy_mem)
release_all_vars();
@@ -1011,7 +1003,7 @@ static const struct varinit varinit[] = {
{&FPAT_node, "FPAT", "[^[:space:]]+", 0, NULL, set_FPAT, false, NON_STANDARD },
{&IGNORECASE_node, "IGNORECASE", NULL, 0, NULL, set_IGNORECASE, false, NON_STANDARD },
{&LINT_node, "LINT", NULL, 0, NULL, set_LINT, false, NON_STANDARD },
-{&PREC_node, "PREC", NULL, DEFAULT_PREC, NULL, set_PREC, false, NON_STANDARD},
+{&PREC_node, "PREC", NULL, 0, NULL, set_PREC, false, NON_STANDARD},
{&NF_node, "NF", NULL, -1, update_NF, set_NF, false, 0 },
{&NR_node, "NR", NULL, 0, update_NR, set_NR, true, 0 },
{&OFMT_node, "OFMT", "%.6g", 0, NULL, set_OFMT, true, 0 },
@@ -1019,7 +1011,7 @@ static const struct varinit varinit[] = {
{&ORS_node, "ORS", "\n", 0, NULL, set_ORS, true, 0 },
{NULL, "PROCINFO", NULL, 0, NULL, NULL, false, NO_INSTALL | NON_STANDARD | NOT_OFF_LIMITS },
{&RLENGTH_node, "RLENGTH", NULL, 0, NULL, NULL, false, 0 },
-{&ROUNDMODE_node, "ROUNDMODE", DEFAULT_ROUNDMODE, 0, NULL, set_ROUNDMODE, false, NON_STANDARD },
+{&ROUNDMODE_node, "ROUNDMODE", "", 0, NULL, set_ROUNDMODE, false, NON_STANDARD },
{&RS_node, "RS", "\n", 0, NULL, set_RS, true, 0 },
{&RSTART_node, "RSTART", NULL, 0, NULL, NULL, false, 0 },
{&RT_node, "RT", "", 0, NULL, NULL, false, NON_STANDARD },
@@ -1050,6 +1042,8 @@ init_vars()
(*(vp->assign))();
}
+ numbr_hndlr->init_numvars(); /* set default values for variables e.g. PREC */
+
/* Set up deferred variables (loaded only when accessed). */
if (! do_traditional)
register_deferred_variable("PROCINFO", load_procinfo);
@@ -1142,7 +1136,7 @@ load_procinfo()
#if defined (HAVE_GETGROUPS) && defined(NGROUPS_MAX) && NGROUPS_MAX > 0
int i;
#endif
-#if (defined (HAVE_GETGROUPS) && defined(NGROUPS_MAX) && NGROUPS_MAX > 0) || defined(HAVE_MPFR)
+#if (defined (HAVE_GETGROUPS) && defined(NGROUPS_MAX) && NGROUPS_MAX > 0)
char name[100];
#endif
AWKNUM value;
@@ -1158,14 +1152,8 @@ load_procinfo()
update_PROCINFO_str("version", VERSION);
update_PROCINFO_str("strftime", def_strftime_format);
-#ifdef HAVE_MPFR
- sprintf(name, "GNU MPFR %s", mpfr_get_version());
- update_PROCINFO_str("mpfr_version", name);
- sprintf(name, "GNU MP %s", gmp_version);
- update_PROCINFO_str("gmp_version", name);
- update_PROCINFO_num("prec_max", MPFR_PREC_MAX);
- update_PROCINFO_num("prec_min", MPFR_PREC_MIN);
-#endif
+ if (numbr_hndlr != & awknum_hndlr && numbr_hndlr->load_procinfo)
+ numbr_hndlr->load_procinfo();
#ifdef DYNAMIC
update_PROCINFO_num("api_major", GAWK_API_MAJOR_VERSION);
@@ -1469,9 +1457,7 @@ version()
#ifdef DYNAMIC
printf(", API: %d.%d", GAWK_API_MAJOR_VERSION, GAWK_API_MINOR_VERSION);
#endif
-#ifdef HAVE_MPFR
- printf(" (GNU MPFR %s, GNU MP %s)", mpfr_get_version(), gmp_version);
-#endif
+ print_numbr_hndlr_versions();
printf("\n");
print_ext_versions();
@@ -1588,6 +1574,44 @@ init_locale(struct lconv *l)
}
#endif /* LOCALE_H */
+static void
+init_numbr_handler(bltin_t **bltins)
+{
+ if (! numbr_hndlr->init(bltins)) {
+ /* not available */
+ numbr_hndlr = & awknum_hndlr; /* fall back to AWKNUM */
+ (void) numbr_hndlr->init(bltins);
+ }
+
+ make_number = numbr_hndlr->gawk_make_number;
+ str2number = numbr_hndlr->gawk_force_number;
+ format_val = numbr_hndlr->gawk_fmt_number;
+ cmp_numbers = numbr_hndlr->gawk_cmp_numbers;
+ str2node = numbr_hndlr->gawk_str2number;
+ free_number = numbr_hndlr->gawk_free_number;
+ format_number_printf = numbr_hndlr->gawk_format_printf;
+ get_number_d = numbr_hndlr->gawk_todouble;
+ get_number_si = numbr_hndlr->gawk_tolong;
+ get_number_ui = numbr_hndlr->gawk_toulong;
+ get_number_uj = numbr_hndlr->gawk_touintmax_t;
+ sgn_number = numbr_hndlr->gawk_sgn_number;
+}
+
+static void
+print_numbr_hndlr_versions()
+{
+ static numbr_handler_t *hndlrs[] = {
+ & awknum_hndlr,
+ & mpfp_hndlr,
+ };
+ int i;
+
+ for (i = 0; i < sizeof(hndlrs) / sizeof(hndlrs[0]); i++)
+ if (hndlrs[i]->version_str)
+ printf(" (%s)", hndlrs[i]->version_str());
+}
+
+
/* save_argv --- save argv array */
static void
diff --git a/misc/ap_math.awk b/misc/ap_math.awk
new file mode 100644
index 00000000..941a4d61
--- /dev/null
+++ b/misc/ap_math.awk
@@ -0,0 +1,331 @@
+# ap_math.awk --- arbitrary-precision math functions
+
+#
+# ap_sin -- Compute sin(x)
+# ap_cos -- Compute cos(x)
+# ap_atan2 -- Compute atan2(y, x)
+#
+
+#
+# Machin's formula to compute pi (http://mathworld.wolfram.com/MachinsFormula.html):
+# pi / 4 = 4 acot(5) - acot(239)
+# = 4 atan(1/5) - atan(1/239)
+#
+# Euler atan formula (http://mathworld.wolfram.com/InverseTangent.html):
+# atan(x) = (y/x) (1 + 2/3 y + (2·4)/(3·5) y^2 + (2·4·6)/(3·5·7) y^3 +...)
+# where
+# y = (x^2) / (1 + x^2) and -1 <= x <= 1
+#
+# Substituting x = 1/x, for x >= 1
+# atan(1/x) = (x / (1 + x^2)) + (2/3) * (x / (1 + x^2)^2)
+# + (2*4/(3*5)) * (x / (1 + x^2)^3)
+# + (2*4*6/(3*5*7)) * (x / (1 + x^2)^4) + ...
+#
+
+function euler_atan_one_over(x, \
+ xpow2_plus_one, term, sum, i, sign, err)
+{
+ sign = 1
+ if (x < 0) {
+ sign = -1
+ x = -x
+ }
+
+ xpow2_plus_one = x * x + 1
+ term = x / xpow2_plus_one
+ sum = term
+ i = 0
+
+ do {
+ term *= (i + 2) / (i + 3)
+ err = term /= xpow2_plus_one
+ i += 2
+ sum += term
+ err = term / sum
+ } while (err > __REL_ERROR__)
+
+ return sign * sum
+}
+
+function setup_ap_math( \
+ prec, curr_prec, digits, extra_prec)
+{
+ switch (PREC) {
+ case "half": prec = 11; break;
+ case "single": prec = 24; break;
+ case "double": prec = 53; break;
+ case "quad": prec = 113; break;
+ case "oct": prec = 237; break;
+ default: prec = PREC + 0;
+ }
+
+ if (prec <= 0) {
+ # double or long double ?
+ print "PREC value not specified" > "/dev/stderr"
+ exit(1)
+ }
+
+ curr_prec = PREC
+ extra_prec = 10 # temporarily raise precision by this amount; Why 10???
+
+ # unlike PREC, `prec' is always a number
+ PREC = prec + extra_prec
+
+ if (PREC != __PI_PREC__) {
+ # compute PI only once for a given precision
+ digits = int (PREC / 3.32193)
+ __REL_ERROR__ = sprintf("5.0e-%d", digits) + 0
+ __PI_PREC__ = PREC
+ __PI_OVER_4__ = 4 * euler_atan_one_over(5) - euler_atan_one_over(239)
+ }
+ return curr_prec
+}
+
+#
+# atan2(y, x) = atan(y/x), x > 0
+# = atan(y/x) + pi, x < 0, y >= 0
+# = atan(y/x) - pi, x < 0, y < 0
+# = pi/2, x = 0, y > 0
+# = -pi/2, x = 0, y < 0
+# = ? x = 0, y = 0
+#
+
+function euler_atan2(y, x, \
+ sign, plus_inf, minus_inf)
+{
+ # Using Euler atan(1/x) and the identity:
+ # atan(x) = - pi / 2 - atan(1/x), x < 0
+ # = pi / 2 - atan(1/x), x > 0
+
+ plus_inf = "+inf" + 0
+ minus_inf = "-inf" + 0
+
+ # detect all the "abnormal" cases first
+ x = + x # or x += 0.0 or x = x + 0.0
+ y = + y
+ if (x == "+nan" + 0 || x == "-nan" + 0 ||
+ y == "+nan" + 0 || y == "-nan" + 0)
+ return "nan" + 0
+
+ if (y == plus_inf) {
+ if (x == minus_inf)
+ return 3 * __PI_OVER_4__
+ else if (x == plus_inf)
+ return __PI_OVER_4__
+ else
+ return 2 * __PI_OVER_4__
+ } else if (y == minus_inf) {
+ if (x == minus_inf)
+ return - 3 * __PI_OVER_4__
+ else if (x == plus_inf)
+ return - __PI_OVER_4__
+ else
+ return - 2 * __PI_OVER_4__
+ }
+
+ if (x == plus_inf)
+ return atan2(y, x) # use builtin, returns +0 or -0
+ if (x == minus_inf) {
+ if (y >= 0)
+ return 4 * __PI_OVER_4__
+ # y < 0
+ return - 4 * __PI_OVER_4__
+ }
+
+ if (x > 0) {
+ if (y == 0)
+ return atan2(y, x); # use builtin; returns +0 or -0
+ sign = 1
+ if (y < 0) {
+ sign = -1
+ y = -y
+ }
+ if (y > x)
+ return sign * (2 * __PI_OVER_4__ - euler_atan_one_over(y / x))
+ return sign * euler_atan_one_over(x / y)
+ }
+
+ if (x < 0) {
+ if (y == 0) {
+ if (atan2(y, x) < 0) # use builtin to detect sign
+ return - 4 * __PI_OVER_4__
+ return 4 * __PI_OVER_4__
+ }
+
+ if (y < 0) {
+ y = -y
+ x = -x
+ if (y > x)
+ return - 2 * __PI_OVER_4__ - euler_atan_one_over(y / x)
+ return euler_atan_one_over(x / y) - 4 * __PI_OVER_4__
+ }
+ # y > 0
+ x = -x
+ if (y > x)
+ return 2 * __PI_OVER_4__ + euler_atan_one_over(y / x)
+ return - euler_atan_one_over(x / y) + 4 * __PI_OVER_4__
+ }
+
+ if (atan2(y, x) < 0) # atan2(-0, -0)
+ return - 4.0 * __PI_OVER_4__
+ if (atan2(y, x) > 0) # atan2(+0, -0)
+ return 4.0 * __PI_OVER_4__
+ return 0; # atan2(+0, +0) or atan2(-0, 0)
+}
+
+#
+# Collect two terms in each iteration for the Taylor series:
+# sin(x) = (x - x^3/3!) + (x^5/5! - x^7/7!) + ...
+#
+
+function taylor_sin(x, \
+ i, fact, xpow2, xpow_odd, sum, term, err)
+{
+ # XXX: this assumes x >= 0
+
+ if (x == 0)
+ return x
+ i = 3
+ fact = 6 # 3!
+ xpow2 = x * x
+ xpow_odd = xpow2 * x
+ sum = x - xpow_odd / fact
+
+ do {
+ fact *= (i + 1) * (i + 2)
+ i += 2
+ xpow_odd *= xpow2
+ term = xpow_odd / fact
+
+ fact *= (i + 1) * (i + 2)
+ i += 2
+ xpow_odd *= xpow2
+ term -= xpow_odd / fact
+
+ sum += term
+ err = term / sum
+ } while (err > __REL_ERROR__)
+
+ return sum
+}
+
+#
+# Collect two terms in each iteration for the Taylor series:
+# cos(x) = (1 - x^2/2!) + (x^4/4! - x^6/6!)...
+#
+
+function taylor_cos(x, \
+ i, fact, xpow2, xpow_even, sum, term, err)
+{
+ if (x == 0)
+ return 1
+
+ i = 2
+ fact = 2
+ xpow2 = x * x
+ xpow_even = xpow2
+ sum = 1 - xpow2 / fact
+
+ do {
+ fact *= (i + 1) * (i + 2)
+ i += 2
+ xpow_even *= xpow2
+ term = xpow_even / fact
+
+ fact *= (i + 1) * (i + 2)
+ i += 2
+ xpow_even *= xpow2
+ term -= xpow_even / fact
+
+ sum += term
+ err = term / sum
+ } while (err > __REL_ERROR__)
+
+ return sum
+}
+
+#
+# For 0 <= x <= PI/4, using Taylor series approximation for sin(x):
+# x - x^3/3! + x^5/5! - ...
+#
+# for PI/4 < x <= PI/2, use identity sin(x) = cos(PI/2 - x).
+#
+#
+
+function ap_sin(x, \
+ k, sign, y, sv, curr_prec)
+{
+ curr_prec = setup_ap_math()
+ x = + x # or x += 0.0 or x = x + 0.0
+ if (x == "+inf" + 0 || x == "-inf" + 0 ||
+ x == "+nan" + 0 || x == "-nan" + 0)
+ return "nan" + 0
+
+ if (x < 0) {
+ # sin(-x) = - sin(x)
+ sign = -1
+ x = -x
+ } else
+ sign = 1
+
+ # range reduction -- 0 <= y <= pi / 4
+
+ k = int(x / __PI_OVER_4__)
+ sign *= ( int(k / 4) % 2 ? -1 : 1 )
+ switch (k % 4) {
+ case 0: y = x - k * __PI_OVER_4__; sv = taylor_sin(y); break;
+ case 1: y = (k + 1) * __PI_OVER_4__ - x; sv = taylor_cos(y); break;
+ case 2: y = x - k * __PI_OVER_4__; sv = taylor_cos(y); break;
+ case 3: y = (k + 1) * __PI_OVER_4__ - x; sv = taylor_sin(y); break;
+ }
+ sv *= sign
+
+ PREC = curr_prec
+ return +sv; # unary plus returns a number with current precision
+}
+
+#
+# Using Taylor series approximation for sin(x) for 0 <= x <= PI/4:
+# 1 - x^2/2! + x^4/4! - ...
+# for PI/4 < x < PI/2, use identity cos(x) = sin(PI/2 - x).
+#
+
+
+function ap_cos(x, \
+ k, sign, y, cv, curr_prec)
+{
+ curr_prec = setup_ap_math()
+
+ x = + x # or x += 0.0 or x = x + 0.0
+ if (x == "+inf" + 0 || x == "-inf" + 0 ||
+ x == "+nan" + 0 || x == "-nan" + 0)
+ return "nan" + 0
+
+ if (x < 0) # cos(x) = cos(-x)
+ x = -x
+
+ # range reduction -- 0 <= y <= pi / 4
+
+ k = int(x / __PI_OVER_4__)
+ sign = ( int(k / 4) % 2 ? -1 : 1 )
+ switch (k % 4) {
+ case 0: y = x - k * __PI_OVER_4__; cv = taylor_cos(y); break;
+ case 1: y = (k + 1) * __PI_OVER_4__ - x; cv = taylor_sin(y); break;
+ case 2: y = x - k * __PI_OVER_4__; cv = -taylor_sin(y); break;
+ case 3: y = (k + 1) * __PI_OVER_4__ - x; cv = -taylor_cos(y); break;
+ }
+ cv *= sign
+
+ PREC = curr_prec
+ return +cv # unary plus to apply current precision
+}
+
+function ap_atan2(y, x, \
+ tv, curr_prec)
+{
+ curr_prec = setup_ap_math()
+ tv = euler_atan2(y, x)
+
+ PREC = curr_prec
+ return +tv # unary plus to apply current precision
+}
diff --git a/mpfr.c b/mpfr.c
index 758adfb1..d7d22b07 100644
--- a/mpfr.c
+++ b/mpfr.c
@@ -3,7 +3,7 @@
*/
/*
- * Copyright (C) 2012, 2013 the Free Software Foundation, Inc.
+ * Copyright (C) 2012 the Free Software Foundation, Inc.
*
* This file is part of GAWK, the GNU implementation of the
* AWK Programming Language.
@@ -26,99 +26,331 @@
#include "awk.h"
#ifdef HAVE_MPFR
+#include <gmp.h>
+#include <mpfr.h>
+
+#include "format.h"
+
+#ifndef MPFR_RNDN
+/* for compatibility with MPFR 2.X */
+#define MPFR_RNDN GMP_RNDN
+#define MPFR_RNDZ GMP_RNDZ
+#define MPFR_RNDU GMP_RNDU
+#define MPFR_RNDD GMP_RNDD
+#endif
#if !defined(MPFR_VERSION_MAJOR) || MPFR_VERSION_MAJOR < 3
typedef mp_exp_t mpfr_exp_t;
#endif
-extern NODE **fmt_list; /* declared in eval.c */
-
-mpz_t mpzval; /* GMP integer type, used as temporary in few places */
-mpz_t MNR;
-mpz_t MFNR;
-bool do_ieee_fmt; /* IEEE-754 floating-point emulation */
-mpfr_rnd_t ROUND_MODE;
-
-static mpfr_rnd_t get_rnd_mode(const char rmode);
-static NODE *mpg_force_number(NODE *n);
-static NODE *mpg_make_number(double);
-static NODE *mpg_format_val(const char *format, int index, NODE *s);
-static int mpg_interpret(INSTRUCTION **cp);
+#define DEFAULT_PREC 53
+#define DEFAULT_ROUNDMODE "N" /* round to nearest */
+
+/* exported functions */
+static NODE *mpfp_make_number(AWKNUM);
+static int mpfp_compare(const NODE *, const NODE *);
+static void mpfp_negate_num(NODE *);
+static NODE *mpfp_str2node(char *, char **, int, bool);
+static NODE *mpfp_force_number(NODE *);
+static void mpfp_free_num(NODE *);
+static NODE *mpfp_format_val(const char *, int, NODE *);
+static unsigned long mpfp_toulong(const NODE *);
+static long mpfp_tolong(const NODE *);
+static double mpfp_todouble(const NODE *);
+static uintmax_t mpfp_touintmax_t(const NODE *);
+static int mpfp_sgn(const NODE *);
+static bool mpfp_isinteger(const NODE *);
+static bool mpfp_isnan(const NODE *);
+static bool mpfp_isinf(const NODE *);
+static NODE *mpfp_copy_number(const NODE *);
+static int mpfp_format_printf(NODE *, struct format_spec *, struct print_fmt_buf *);
+static bool mpfp_init(bltin_t **);
+static NODE *mpfp_add(const NODE *, const NODE *);
+static NODE *mpfp_sub(const NODE *, const NODE *);
+static NODE *mpfp_mul(const NODE *, const NODE *);
+static NODE *mpfp_div(const NODE *, const NODE *);
+static NODE *mpfp_mod(const NODE *, const NODE *);
+static NODE *mpfp_pow(const NODE *, const NODE *);
+static NODE *mpfp_add_long(const NODE *, long);
+static NODE *mpfp_update_var(NODE *);
+static void mpfp_set_var(const NODE *);
+static long mpfp_increment_var(const NODE *, long);
+static void mpfp_init_vars(void);
+static void mpfp_load_procinfo(void);
+static const char *mpfp_version_string(void);
+
+/* builtins */
+static NODE *do_mpfp_and(int);
+static NODE *do_mpfp_atan2(int);
+static NODE *do_mpfp_compl(int);
+static NODE *do_mpfp_cos(int);
+static NODE *do_mpfp_div(int);
+static NODE *do_mpfp_exp(int);
+static NODE *do_mpfp_int(int);
+static NODE *do_mpfp_log(int);
+static NODE *do_mpfp_lshift(int);
+static NODE *do_mpfp_or(int);
+static NODE *do_mpfp_rand(int);
+static NODE *do_mpfp_rshift(int);
+static NODE *do_mpfp_sin(int);
+static NODE *do_mpfp_sqrt(int);
+static NODE *do_mpfp_srand(int);
+static NODE *do_mpfp_strtonum(int);
+static NODE *do_mpfp_xor(int);
+
+/* internal functions */
+static NODE *mpfp_make_node(unsigned int type);
+static int mpfp_format_ieee(mpfr_ptr, int);
+static const char *mpfp_sprintf(const char *, ...);
+static int mpfp_strtoui(mpz_ptr, char *, size_t, char **, int);
+static mpfr_rnd_t mpfp_get_rounding_mode(const char rmode);
+static mpfr_ptr mpz2mpfr(mpz_ptr mpz_val, mpfr_ptr mpfr_val);
+
+static mpfr_rnd_t ROUND_MODE;
+static mpz_t MNR;
+static mpz_t MFNR;
+static bool do_ieee_fmt; /* emulate IEEE 754 floating-point format */
static mpfr_exp_t min_exp = MPFR_EMIN_DEFAULT;
static mpfr_exp_t max_exp = MPFR_EMAX_DEFAULT;
+/* needed for MPFR and GMP macros */
+#define MPFR_T(x) ((mpfr_ptr) x)
+#define MPZ_T(x) ((mpz_ptr) x)
+
+
/* temporary MPFR floats used to hold converted GMP integer operands */
-static mpfr_t _mpf_t1;
-static mpfr_t _mpf_t2;
+static mpfr_t _mp1;
+static mpfr_t _mp2;
/*
- * PRECISION_MIN is the precision used to initialize _mpf_t1 and _mpf_t2.
+ * PRECISION_MIN is the precision used to initialize _mp1 and _mp2.
* 64 bits should be enough for exact conversion of most integers to floats.
*/
#define PRECISION_MIN 64
-/* mf = { _mpf_t1, _mpf_t2 } */
-static inline mpfr_ptr mpg_tofloat(mpfr_ptr mf, mpz_ptr mz);
-/* T = {t1, t2} */
-#define MP_FLOAT(T) is_mpg_integer(T) ? mpg_tofloat(_mpf_##T, (T)->mpg_i) : (T)->mpg_numbr
+static mpz_t _mpzval; /* GMP type for float to int conversion in format_tree() */
+static mpfr_t _mpfrval; /* MPFR type for int to float conversion in format_tree() */
+
+#define IEEE_FMT(r, t) (void) (do_ieee_fmt && mpfp_format_ieee(r, t))
+
+#define mpfp_float() mpfp_make_node(MPFN)
+#define mpfp_integer() mpfp_make_node(MPZN)
+#define is_mpfp_float(n) (((n)->flags & MPFN) != 0)
+#define is_mpfp_integer(n) (((n)->flags & MPZN) != 0)
+#define is_mpfp_number(n) (((n)->flags & (MPZN|MPFN)) != 0)
-/* init_mpfr --- set up MPFR related variables */
+/* mpfp_tofloat --- convert GMP integer to MPFR float without loosing any precision */
+
+static inline mpfr_ptr
+mpfp_tofloat(const NODE *t, mpfr_ptr pf)
+{
+ return is_mpfp_float(t) ? t->qnumbr : mpz2mpfr(t->qnumbr, pf);
+}
+
-void
-init_mpfr(mpfr_prec_t prec, const char *rmode)
+numbr_handler_t mpfp_hndlr = {
+ mpfp_init,
+ mpfp_version_string,
+ mpfp_load_procinfo,
+ mpfp_make_number,
+ mpfp_str2node,
+ mpfp_copy_number,
+ mpfp_free_num,
+ mpfp_force_number,
+ mpfp_negate_num,
+ mpfp_compare,
+ mpfp_sgn,
+ mpfp_isinteger,
+ mpfp_isnan,
+ mpfp_isinf,
+ mpfp_format_val,
+ mpfp_format_printf,
+ mpfp_todouble,
+ mpfp_tolong,
+ mpfp_toulong,
+ mpfp_touintmax_t,
+ mpfp_add,
+ mpfp_sub,
+ mpfp_mul,
+ mpfp_div,
+ mpfp_mod,
+ mpfp_pow,
+ mpfp_add_long,
+ mpfp_update_var,
+ mpfp_set_var,
+ mpfp_increment_var,
+ mpfp_init_vars,
+};
+
+
+/* mpfp_init --- set up MPFR related variables */
+
+static bool
+mpfp_init(bltin_t **numbr_bltins)
{
- mpfr_set_default_prec(prec);
- ROUND_MODE = get_rnd_mode(rmode[0]);
+ static bltin_t mpfp_bltins[] = {
+ { "and", do_mpfp_and },
+ { "atan2", do_mpfp_atan2 },
+ { "compl", do_mpfp_compl },
+ { "cos", do_mpfp_cos },
+ { "div", do_mpfp_div },
+ { "exp", do_mpfp_exp },
+ { "int", do_mpfp_int },
+ { "log", do_mpfp_log },
+ { "lshift", do_mpfp_lshift },
+ { "or", do_mpfp_or },
+ { "rand", do_mpfp_rand },
+ { "rshift", do_mpfp_rshift },
+ { "sin", do_mpfp_sin },
+ { "sqrt", do_mpfp_sqrt },
+ { "srand", do_mpfp_srand },
+ { "strtonum", do_mpfp_strtonum },
+ { "xor", do_mpfp_xor },
+ { NULL, NULL },
+ };
+ const char *rndmode = DEFAULT_ROUNDMODE;
+
+ mpfr_set_default_prec(DEFAULT_PREC);
+ ROUND_MODE = mpfp_get_rounding_mode(rndmode[0]);
mpfr_set_default_rounding_mode(ROUND_MODE);
- make_number = mpg_make_number;
- str2number = mpg_force_number;
- format_val = mpg_format_val;
- cmp_numbers = mpg_cmp;
mpz_init(MNR);
mpz_init(MFNR);
do_ieee_fmt = false;
- mpfr_init2(_mpf_t1, PRECISION_MIN);
- mpfr_init2(_mpf_t2, PRECISION_MIN);
- mpz_init(mpzval);
+ mpfr_init2(_mp1, PRECISION_MIN);
+ mpfr_init2(_mp2, PRECISION_MIN);
+ mpz_init(_mpzval);
+ mpfr_init2(_mpfrval, PRECISION_MIN);
+
+ /* set the numeric value of null string */
+ emalloc(Nnull_string->qnumbr, void *, sizeof (mpz_t), "mpfp_init");
+ mpz_init(Nnull_string->qnumbr); /* initialized to 0 */
+ Nnull_string->flags |= (MPZN|NUMCUR|NUMBER);
+
+ /* initialize TRUE and FALSE nodes */
+ false_node = mpfp_integer();
+ true_node = mpfp_integer();
+ mpz_set_si(true_node->qnumbr, 1);
+
+ *numbr_bltins = mpfp_bltins;
+ return true;
+}
+
+static void
+mpfp_load_procinfo()
+{
+ char name[64];
+
+ snprintf(name, 64, "GNU MPFR %s", mpfr_get_version());
+ update_PROCINFO_str("mpfr_version", name);
+ snprintf(name, 64, "GNU MP %s", gmp_version);
+ update_PROCINFO_str("gmp_version", name);
+ update_PROCINFO_num("prec_max", MPFR_PREC_MAX);
+ update_PROCINFO_num("prec_min", MPFR_PREC_MIN);
+}
+
+static const char *
+mpfp_version_string()
+{
+ static char version_string[64];
+ snprintf(version_string, 64, "GNU MPFR %s, GNU MP %s", mpfr_get_version(), gmp_version);
+ return version_string;
+}
+
+/* mpfp_toulong --- conversion to unsigned long */
+
+static unsigned long
+mpfp_toulong(const NODE *n)
+{
+ return (n->flags & MPFN) != 0 ? mpfr_get_ui(n->qnumbr, ROUND_MODE) : mpz_get_ui(n->qnumbr);
+}
+
+/* mpfp_tolong --- conversion to long */
+
+static long
+mpfp_tolong(const NODE *n)
+{
+ return (n->flags & MPFN) != 0 ? mpfr_get_si(n->qnumbr, ROUND_MODE) : mpz_get_si(n->qnumbr);
+}
+
+/* mpfp_todouble --- conversion to AWKNUM */
+
+static double
+mpfp_todouble(const NODE *n)
+{
+ return (n->flags & MPFN) != 0 ? mpfr_get_d(n->qnumbr, ROUND_MODE) : mpz_get_d(n->qnumbr);
+}
+
+/* mpfp_touintmax_t --- conversion to uintmax_t */
+
+static uintmax_t
+mpfp_touintmax_t(const NODE *n)
+{
+ return (n->flags & MPFN) != 0 ? mpfr_get_uj(n->qnumbr, ROUND_MODE) \
+ : (uintmax_t) mpz_get_d(n->qnumbr);
+}
+
+/* mpfp_sgn --- return 1 if number > 0, zero if number == 0, and -1 if number < 0 */
+
+static int
+mpfp_sgn(const NODE *n)
+{
+ return (n->flags & MPFN) != 0 ? mpfr_sgn(MPFR_T(n->qnumbr)) \
+ : mpz_sgn(MPZ_T(n->qnumbr));
+}
+
+/* mpfp_isinteger --- check if a number is an integer */
+
+static bool
+mpfp_isinteger(const NODE *n)
+{
+ return is_mpfp_integer(n) ? true : mpfr_integer_p(n->qnumbr);
+}
+
+/* mpfp_isnan --- check if a number is NaN */
- register_exec_hook(mpg_interpret, 0);
+static bool
+mpfp_isnan(const NODE *n)
+{
+ return is_mpfp_float(n) && mpfr_nan_p(MPFR_T(n->qnumbr));
}
-/* cleanup_mpfr --- clean stuff up, mainly for valgrind */
+/* mpfp_isinf --- check if a number is infinity */
-void
-cleanup_mpfr(void)
+static bool
+mpfp_isinf(const NODE *n)
{
- mpfr_clear(_mpf_t1);
- mpfr_clear(_mpf_t2);
+ return is_mpfp_float(n) && mpfr_inf_p(MPFR_T(n->qnumbr));
}
-/* mpg_node --- allocate a node to store MPFR float or GMP integer */
-NODE *
-mpg_node(unsigned int tp)
+/* mpfp_make_node --- allocate a node to store MPFR float or GMP integer */
+
+static NODE *
+mpfp_make_node(unsigned int type)
{
NODE *r;
+
getnode(r);
r->type = Node_val;
-
- if (tp == MPFN) {
+ if (type == MPFN) {
/* Initialize, set precision to the default precision, and value to NaN */
- mpfr_init(r->mpg_numbr);
+ emalloc(r->qnumbr, void *, sizeof (mpfr_t), "mpfp_make_node");
+ mpfr_init(r->qnumbr);
r->flags = MPFN;
} else {
/* Initialize and set value to 0 */
- mpz_init(r->mpg_i);
+ emalloc(r->qnumbr, void *, sizeof (mpz_t), "mpfp_make_node");
+ mpz_init(r->qnumbr);
r->flags = MPZN;
}
r->valref = 1;
- r->flags |= MALLOC|NUMBER|NUMCUR;
+ r->flags |= (MALLOC|NUMBER|NUMCUR);
r->stptr = NULL;
r->stlen = 0;
#if MBS_SUPPORT
@@ -129,32 +361,26 @@ mpg_node(unsigned int tp)
}
/*
- * mpg_make_number --- make a arbitrary-precision number node
- * and initialize with a C double
+ * mpfp_make_number --- make a arbitrary-precision number node
+ * and initialize with AWKNUM.
*/
static NODE *
-mpg_make_number(double x)
+mpfp_make_number(AWKNUM x)
{
NODE *r;
- double ival;
+ int tval;
- if ((ival = double_to_int(x)) != x) {
- int tval;
- r = mpg_float();
- tval = mpfr_set_d(r->mpg_numbr, x, ROUND_MODE);
- IEEE_FMT(r->mpg_numbr, tval);
- } else {
- r = mpg_integer();
- mpz_set_d(r->mpg_i, ival);
- }
+ r = mpfp_float();
+ tval = mpfr_set_d(r->qnumbr, x, ROUND_MODE);
+ IEEE_FMT(r->qnumbr, tval);
return r;
}
-/* mpg_strtoui --- assign arbitrary-precision integral value from a string */
+/* mpfp_strtoui --- assign arbitrary-precision integral value from a string */
-int
-mpg_strtoui(mpz_ptr zi, char *str, size_t len, char **end, int base)
+static int
+mpfp_strtoui(mpz_ptr zi, char *str, size_t len, char **end, int base)
{
char *s = str;
char *start;
@@ -219,10 +445,10 @@ done:
}
-/* mpg_maybe_float --- test if a string may contain arbitrary-precision float */
+/* mpfp_maybe_float --- test if a string may contain arbitrary-precision float */
static int
-mpg_maybe_float(const char *str, int use_locale)
+mpfp_maybe_float(const char *str, int use_locale)
{
int dec_point = '.';
const char *s = str;
@@ -254,34 +480,40 @@ mpg_maybe_float(const char *str, int use_locale)
}
-/* mpg_zero --- initialize with arbitrary-precision integer(GMP) and set value to zero */
+/*
+ * mpfp_init_zero --- initialize with arbitrary-precision integer and set value to zero.
+ * N.B. : this function also converts MPFR number to GMP number.
+ */
-static inline void
-mpg_zero(NODE *n)
+static void
+mpfp_init_zero(NODE *n)
{
- if (is_mpg_float(n)) {
- mpfr_clear(n->mpg_numbr);
+ if (is_mpfp_float(n)) {
+ mpfr_clear(n->qnumbr);
+ efree(n->qnumbr);
+ n->qnumbr = NULL;
n->flags &= ~MPFN;
}
- if (! is_mpg_integer(n)) {
- mpz_init(n->mpg_i); /* this also sets its value to 0 */
+ if (! is_mpfp_integer(n)) {
+ emalloc(n->qnumbr, void *, sizeof (mpz_t), "mpfp_init_zero");
+ mpz_init(n->qnumbr); /* this also sets its value to 0 */
n->flags |= MPZN;
} else
- mpz_set_si(n->mpg_i, 0);
+ mpz_set_si(n->qnumbr, 0);
}
-/* force_mpnum --- force a value to be a GMP integer or MPFR float */
+/* mpfp_str2num --- force a value to be a GMP integer or MPFR float */
-static int
-force_mpnum(NODE *n, int do_nondec, int use_locale)
+static bool
+mpfp_str2num(NODE *n, int do_nondec, int use_locale)
{
char *cp, *cpend, *ptr, *cp1;
char save;
int tval, base = 10;
if (n->stlen == 0) {
- mpg_zero(n);
+ mpfp_init_zero(n); /* GMP integer */
return false;
}
@@ -290,7 +522,7 @@ force_mpnum(NODE *n, int do_nondec, int use_locale)
while (cp < cpend && isspace((unsigned char) *cp))
cp++;
if (cp == cpend) { /* only spaces */
- mpg_zero(n);
+ mpfp_init_zero(n);
return false;
}
@@ -305,28 +537,30 @@ force_mpnum(NODE *n, int do_nondec, int use_locale)
if (do_nondec)
base = get_numbase(cp1, use_locale);
- if (! mpg_maybe_float(cp1, use_locale)) {
- mpg_zero(n);
+ if (! mpfp_maybe_float(cp1, use_locale)) {
+ mpfp_init_zero(n); /* GMP integer */
errno = 0;
- mpg_strtoui(n->mpg_i, cp1, cpend - cp1, & ptr, base);
+ mpfp_strtoui(n->qnumbr, cp1, cpend - cp1, & ptr, base);
if (*cp == '-')
- mpz_neg(n->mpg_i, n->mpg_i);
+ mpz_neg(n->qnumbr, n->qnumbr);
goto done;
}
- if (is_mpg_integer(n)) {
- mpz_clear(n->mpg_i);
+ if (is_mpfp_integer(n)) {
+ mpz_clear(n->qnumbr);
+ efree(n->qnumbr);
n->flags &= ~MPZN;
}
- if (! is_mpg_float(n)) {
- mpfr_init(n->mpg_numbr);
+ if (! is_mpfp_float(n)) {
+ emalloc(n->qnumbr, void *, sizeof (mpfr_t), "mpfp_str2num");
+ mpfr_init(n->qnumbr);
n->flags |= MPFN;
}
errno = 0;
- tval = mpfr_strtofr(n->mpg_numbr, cp, & ptr, base, ROUND_MODE);
- IEEE_FMT(n->mpg_numbr, tval);
+ tval = mpfr_strtofr(n->qnumbr, cp, & ptr, base, ROUND_MODE);
+ IEEE_FMT(n->qnumbr, tval);
done:
/* trailing space is OK for NUMBER */
while (isspace((unsigned char) *ptr))
@@ -335,17 +569,17 @@ done:
if (errno == 0 && ptr == cpend)
return true;
errno = 0;
- return false;
+ return false;
}
-/* mpg_force_number --- force a value to be a multiple-precision number */
+/* mpfp_force_number --- force a value to be a multiple-precision number */
static NODE *
-mpg_force_number(NODE *n)
+mpfp_force_number(NODE *n)
{
unsigned int newflags = 0;
- if (is_mpg_number(n) && (n->flags & NUMCUR) != 0)
+ if (is_mpfp_number(n) && (n->flags & NUMCUR) != 0)
return n;
if ((n->flags & MAYBE_NUM) != 0) {
@@ -353,150 +587,130 @@ mpg_force_number(NODE *n)
newflags = NUMBER;
}
- if (force_mpnum(n, (do_non_decimal_data && ! do_traditional), true)) {
+ if (mpfp_str2num(n, (do_non_decimal_data && ! do_traditional), true)) {
n->flags |= newflags;
n->flags |= NUMCUR;
}
return n;
}
-/* mpg_format_val --- format a numeric value based on format */
+
+/* mpfp_format_val --- format a numeric value based on format */
static NODE *
-mpg_format_val(const char *format, int index, NODE *s)
+mpfp_format_val(const char *format, int index, NODE *s)
{
- NODE *dummy[2], *r;
- unsigned int oflags;
+ struct format_spec spec;
+ struct print_fmt_buf *outb;
- /* create dummy node for a sole use of format_tree */
- dummy[1] = s;
- oflags = s->flags;
+ if ((s->flags & STRCUR) != 0)
+ efree(s->stptr);
+ free_wstr(s);
- if (is_mpg_integer(s) || mpfr_integer_p(s->mpg_numbr)) {
+ /* XXX: format_spec copied since can be altered in the formatting routine */
+
+ if (is_mpfp_integer(s) || mpfr_integer_p(s->qnumbr)) {
/* integral value, use %d */
- r = format_tree("%d", 2, dummy, 2);
+ spec = *fmt_list[INT_d_FMT_INDEX].spec;
s->stfmt = -1;
} else {
- r = format_tree(format, fmt_list[index]->stlen, dummy, 2);
- assert(r != NULL);
+ assert(fmt_list[index].spec != NULL); /* or can use fmt_parse() --- XXX */
+ spec = *fmt_list[index].spec;
s->stfmt = (char) index;
}
- s->flags = oflags;
- s->stlen = r->stlen;
- if ((s->flags & STRCUR) != 0)
- efree(s->stptr);
- s->stptr = r->stptr;
- freenode(r); /* Do not unref(r)! We want to keep s->stptr == r->stpr. */
-
- s->flags |= STRCUR;
- free_wstr(s);
+
+ outb = get_fmt_buf();
+ mpfp_format_printf(s, & spec, outb);
+ (void) bytes2node(outb, s);
+ free_fmt_buf(outb);
+
+ s->stptr[s->stlen] = '\0';
+ s->flags |= STRCUR;
return s;
}
-/* mpg_cmp --- compare two numbers */
+/* mpfp_str2node --- create an arbitrary-pecision number from string */
+
+static NODE *
+mpfp_str2node(char *str, char **endptr, int base, bool is_integer)
+{
+ NODE *r;
-int
-mpg_cmp(const NODE *t1, const NODE *t2)
+ if (is_integer) {
+ r = mpfp_integer();
+ mpfp_strtoui(r->qnumbr, str, strlen(str), endptr, base);
+ } else {
+ int tval;
+ r = mpfp_float();
+ tval = mpfr_strtofr(r->qnumbr, str, endptr, base, ROUND_MODE);
+ IEEE_FMT(r->qnumbr, tval);
+ }
+ return r;
+}
+
+/* mpfp_free_num --- free all storage allocated for a multiple-precision number */
+
+static void
+mpfp_free_num(NODE *tmp)
+{
+ assert((tmp->flags & (MPFN|MPZN)) != 0);
+ if (is_mpfp_float(tmp))
+ mpfr_clear(tmp->qnumbr);
+ else /* if (is_mpfp_integer(tmp)) */
+ mpz_clear(tmp->qnumbr);
+ efree(tmp->qnumbr);
+ tmp->qnumbr = NULL;
+}
+
+/* mpfp_compare --- compare two numbers */
+
+static int
+mpfp_compare(const NODE *t1, const NODE *t2)
{
/*
* For the purposes of sorting, NaN is considered greater than
* any other value, and all NaN values are considered equivalent and equal.
*/
- if (is_mpg_float(t1)) {
- if (is_mpg_float(t2)) {
- if (mpfr_nan_p(t1->mpg_numbr))
- return ! mpfr_nan_p(t2->mpg_numbr);
- if (mpfr_nan_p(t2->mpg_numbr))
+ if (is_mpfp_float(t1)) {
+ if (is_mpfp_float(t2)) {
+ if (mpfr_nan_p(MPFR_T(t1->qnumbr)))
+ return ! mpfr_nan_p(MPFR_T(t2->qnumbr));
+ if (mpfr_nan_p(MPFR_T(t2->qnumbr)))
return -1;
- return mpfr_cmp(t1->mpg_numbr, t2->mpg_numbr);
+ return mpfr_cmp(t1->qnumbr, t2->qnumbr);
}
- if (mpfr_nan_p(t1->mpg_numbr))
+ if (mpfr_nan_p(MPFR_T(t1->qnumbr)))
return 1;
- return mpfr_cmp_z(t1->mpg_numbr, t2->mpg_i);
- } else if (is_mpg_float(t2)) {
+ return mpfr_cmp_z(t1->qnumbr, t2->qnumbr);
+ } else if (is_mpfp_float(t2)) {
int ret;
- if (mpfr_nan_p(t2->mpg_numbr))
+
+ if (mpfr_nan_p(MPFR_T(t2->qnumbr)))
return -1;
- ret = mpfr_cmp_z(t2->mpg_numbr, t1->mpg_i);
+ ret = mpfr_cmp_z(t2->qnumbr, t1->qnumbr);
return ret > 0 ? -1 : (ret < 0);
- } else if (is_mpg_integer(t1)) {
- return mpz_cmp(t1->mpg_i, t2->mpg_i);
}
-
- /* t1 and t2 are AWKNUMs */
- return cmp_awknums(t1, t2);
+ assert(is_mpfp_integer(t1) == true);
+ return mpz_cmp(t1->qnumbr, t2->qnumbr);
}
+/* mpfp_init_vars --- set PREC and ROUNDMODE defaults */
-/*
- * mpg_update_var --- update NR or FNR.
- * NR_node->var_value(mpz_t) = MNR(mpz_t) * LONG_MAX + NR(long)
- */
-
-NODE *
-mpg_update_var(NODE *n)
+static void
+mpfp_init_vars()
{
- NODE *val = n->var_value;
- long nr = 0;
- mpz_ptr nq = 0;
-
- if (n == NR_node) {
- nr = NR;
- nq = MNR;
- } else if (n == FNR_node) {
- nr = FNR;
- nq = MFNR;
- } else
- cant_happen();
-
- if (mpz_sgn(nq) == 0) {
- /* Efficiency hack similar to that for AWKNUM */
- if (is_mpg_float(val) || mpz_get_si(val->mpg_i) != nr) {
- unref(n->var_value);
- val = n->var_value = mpg_integer();
- mpz_set_si(val->mpg_i, nr);
- }
- } else {
- unref(n->var_value);
- val = n->var_value = mpg_integer();
- mpz_set_si(val->mpg_i, nr);
- mpz_addmul_ui(val->mpg_i, nq, LONG_MAX); /* val->mpg_i += nq * LONG_MAX */
- }
- return val;
+ unref(PREC_node->var_value);
+ PREC_node->var_value = mpfp_make_number(DEFAULT_PREC);
+ unref(ROUNDMODE_node->var_value);
+ ROUNDMODE_node->var_value = make_string(DEFAULT_ROUNDMODE, strlen(DEFAULT_ROUNDMODE));
}
-/* mpg_set_var --- set NR or FNR */
-long
-mpg_set_var(NODE *n)
-{
- long nr = 0;
- mpz_ptr nq = 0, r;
- NODE *val = n->var_value;
-
- if (n == NR_node)
- nq = MNR;
- else if (n == FNR_node)
- nq = MFNR;
- else
- cant_happen();
-
- if (is_mpg_integer(val))
- r = val->mpg_i;
- else {
- /* convert float to integer */
- mpfr_get_z(mpzval, val->mpg_numbr, MPFR_RNDZ);
- r = mpzval;
- }
- nr = mpz_fdiv_q_ui(nq, r, LONG_MAX); /* nq (MNR or MFNR) is quotient */
- return nr; /* remainder (NR or FNR) */
-}
+/* mpfp_set_PREC --- update MPFR PRECISION related variables when PREC assigned to */
-/* set_PREC --- update MPFR PRECISION related variables when PREC assigned to */
-
-void
-set_PREC()
+static void
+mpfp_set_PREC(const NODE *var)
{
long prec = 0;
NODE *val;
@@ -520,12 +734,9 @@ set_PREC()
*/
};
- if (! do_mpfr)
- return;
-
- val = PREC_node->var_value;
+ val = var->var_value;
if ((val->flags & MAYBE_NUM) != 0)
- force_number(val);
+ (void) force_number(val);
if ((val->flags & (STRING|NUMBER)) == STRING) {
int i, j;
@@ -546,7 +757,6 @@ set_PREC()
*/
max_exp = ieee_fmts[i].emax;
min_exp = ieee_fmts[i].emin;
-
do_ieee_fmt = true;
}
}
@@ -555,7 +765,7 @@ set_PREC()
force_number(val);
prec = get_number_si(val);
if (prec < MPFR_PREC_MIN || prec > MPFR_PREC_MAX) {
- force_string(val);
+ (void) force_string(val);
warning(_("PREC value `%.*s' is invalid"), (int) val->stlen, val->stptr);
prec = 0;
} else
@@ -567,10 +777,10 @@ set_PREC()
}
-/* get_rnd_mode --- convert string to MPFR rounding mode */
+/* mpfp_get_rounding_mode --- convert string to MPFR rounding mode */
static mpfr_rnd_t
-get_rnd_mode(const char rmode)
+mpfp_get_rounding_mode(const char rmode)
{
switch (rmode) {
case 'N':
@@ -597,32 +807,116 @@ get_rnd_mode(const char rmode)
}
/*
- * set_ROUNDMODE --- update MPFR rounding mode related variables
+ * mpfp_set_ROUNDMODE --- update MPFR rounding mode related variables
* when ROUNDMODE assigned to
*/
-void
-set_ROUNDMODE()
-{
- if (do_mpfr) {
- mpfr_rnd_t rndm = -1;
- NODE *n;
- n = force_string(ROUNDMODE_node->var_value);
- if (n->stlen == 1)
- rndm = get_rnd_mode(n->stptr[0]);
- if (rndm != -1) {
- mpfr_set_default_rounding_mode(rndm);
- ROUND_MODE = rndm;
- } else
- warning(_("RNDMODE value `%.*s' is invalid"), (int) n->stlen, n->stptr);
+static void
+mpfp_set_ROUNDMODE(const NODE *var)
+{
+ mpfr_rnd_t rndmode = -1;
+ NODE *val;
+
+ val = force_string(var->var_value);
+ if (val->stlen == 1)
+ rndmode = mpfp_get_rounding_mode(val->stptr[0]);
+ if (rndmode != -1) {
+ mpfr_set_default_rounding_mode(rndmode);
+ ROUND_MODE = rndmode;
+ } else
+ warning(_("ROUNDMODE value `%.*s' is invalid"), (int) val->stlen, val->stptr);
+}
+
+/*
+ * mpfp_update_var --- update NR or FNR.
+ * NR_node->var_value(mpz_t) = MNR(mpz_t) * LONG_MAX + NR(long)
+ */
+
+static NODE *
+mpfp_update_var(NODE *n)
+{
+ NODE *val = n->var_value;
+ long nr = 0;
+ mpz_ptr nq = 0;
+
+ if (n == NR_node) {
+ nr = NR;
+ nq = MNR;
+ } else {
+ assert(n == FNR_node);
+ nr = FNR;
+ nq = MFNR;
+ }
+
+ if (mpz_sgn(nq) == 0) {
+ /* Efficiency hack similar to that for AWKNUM */
+ if (is_mpfp_float(val) || mpz_get_si(val->qnumbr) != nr) {
+ unref(val);
+ val = n->var_value = mpfp_integer();
+ mpz_set_si(val->qnumbr, nr);
+ }
+ } else {
+ unref(val);
+ val = n->var_value = mpfp_integer();
+ mpz_set_si(val->qnumbr, nr);
+ mpz_addmul_ui(val->qnumbr, nq, LONG_MAX); /* val->mpg_i += nq * LONG_MAX */
+ }
+ return val;
+}
+
+/* mpfp_set_var --- set internal variables */
+
+static void
+mpfp_set_var(const NODE *var)
+{
+ if (var == PREC_node)
+ mpfp_set_PREC(var);
+ else if (var == ROUNDMODE_node)
+ mpfp_set_ROUNDMODE(var);
+ else {
+ NODE *val = var->var_value;
+ mpz_ptr r;
+ mpz_t mpz_val;
+
+ if (is_mpfp_integer(val))
+ r = val->qnumbr;
+ else {
+ /* convert float to integer */
+ mpz_init(mpz_val);
+ mpfr_get_z(mpz_val, val->qnumbr, MPFR_RNDZ);
+ r = mpz_val;
+ }
+
+ if (var == NR_node)
+ NR = mpz_fdiv_q_ui(MNR, r, LONG_MAX); /* MNR is quotient */
+ else
+ FNR = mpz_fdiv_q_ui(MFNR, r, LONG_MAX);
+
+ if (r != val->qnumbr)
+ mpz_clear(mpz_val);
}
}
+/* mpfp_increment_var --- increment NR or FNR */
-/* format_ieee --- make sure a number follows IEEE-754 floating-point standard */
+static long
+mpfp_increment_var(const NODE *var, long nr)
+{
+ if (nr == LONG_MAX - 1) {
+ /* increment quotient, set remainder(NR or FNR) to 0 */
+ if (var == NR_node)
+ mpz_add_ui(MNR, MNR, 1);
+ else /* if (var == FNR_node) */
+ mpz_add_ui(MFNR, MFNR, 1);
+ return 0;
+ }
+ return ++nr;
+}
-int
-format_ieee(mpfr_ptr x, int tval)
+/* mpfp_format_ieee --- make sure a number follows IEEE-754 floating-point standard */
+
+static int
+mpfp_format_ieee(mpfr_ptr x, int tval)
{
/*
* The MPFR doc says that it's our responsibility to make sure all numbers
@@ -663,11 +957,40 @@ format_ieee(mpfr_ptr x, int tval)
return tval;
}
+/* mpfp_negate_num --- negate a number in NODE */
-/* do_mpfr_atan2 --- do the atan2 function */
+static void
+mpfp_negate_num(NODE *n)
+{
+ if (is_mpfp_float(n)) {
+ int tval;
+ tval = mpfr_neg(n->qnumbr, n->qnumbr, ROUND_MODE);
+ IEEE_FMT(n->qnumbr, tval);
+ } else {
+ /* GMP integer */
+ if (mpz_sgn(MPZ_T(n->qnumbr)) == 0) {
+ /*
+ * The result should be -0.0, a float.
+ * XXX: atan2(0, -0) is PI not 0.
+ */
+ mpz_clear(n->qnumbr);
+ efree(n->qnumbr);
+ n->flags &= ~MPZN;
+ emalloc(n->qnumbr, void *, sizeof (mpfr_t), "mpfp_negate_num");
+ mpfr_init(n->qnumbr);
+ n->flags |= MPFN;
+
+ /* XXX: assuming IEEE 754 double, or could use mpfr_set_str(op, "-0.0", ...) */
+ mpfr_set_d(n->qnumbr, -0.0, ROUND_MODE);
+ } else
+ mpz_neg(n->qnumbr, n->qnumbr);
+ }
+}
+
+/* do_mpfp_atan2 --- do the atan2 function */
-NODE *
-do_mpfr_atan2(int nargs)
+static NODE *
+do_mpfp_atan2(int nargs)
{
NODE *t1, *t2, *res;
mpfr_ptr p1, p2;
@@ -682,124 +1005,132 @@ do_mpfr_atan2(int nargs)
if ((t2->flags & (NUMCUR|NUMBER)) == 0)
lintwarn(_("atan2: received non-numeric second argument"));
}
- force_number(t1);
- force_number(t2);
- p1 = MP_FLOAT(t1);
- p2 = MP_FLOAT(t2);
- res = mpg_float();
+ (void) force_number(t1);
+ (void) force_number(t2);
+
+ p1 = mpfp_tofloat(t1, _mp1);
+ p2 = mpfp_tofloat(t2, _mp2);
+
+ res = mpfp_float();
/* See MPFR documentation for handling of special values like +inf as an argument */
- tval = mpfr_atan2(res->mpg_numbr, p1, p2, ROUND_MODE);
- IEEE_FMT(res->mpg_numbr, tval);
+ tval = mpfr_atan2(res->qnumbr, p1, p2, ROUND_MODE);
+ IEEE_FMT(res->qnumbr, tval);
DEREF(t1);
DEREF(t2);
return res;
}
-/* do_mpfr_func --- run an MPFR function - not inline, for debugging */
+/* do_mpfp_func --- run an MPFR function - not inline, for debugging */
static inline NODE *
-do_mpfr_func(const char *name,
+do_mpfp_func(const char *name,
int (*mpfr_func)(), /* putting argument types just gets the compiler confused */
int nargs)
{
NODE *t1, *res;
mpfr_ptr p1;
int tval;
+ int prec;
t1 = POP_SCALAR();
if (do_lint && (t1->flags & (NUMCUR|NUMBER)) == 0)
lintwarn(_("%s: received non-numeric argument"), name);
force_number(t1);
- p1 = MP_FLOAT(t1);
- res = mpg_float();
- mpfr_set_prec(res->mpg_numbr, mpfr_get_prec(p1)); /* needed at least for sqrt() */
- tval = mpfr_func(res->mpg_numbr, p1, ROUND_MODE);
- IEEE_FMT(res->mpg_numbr, tval);
+
+ if (is_mpfp_integer(t1))
+ p1 = mpfp_tofloat(t1, _mp1);
+ else
+ p1 = MPFR_T(t1);
+
+ res = mpfp_float();
+ prec = mpfr_get_prec(p1);
+ mpfr_set_prec(res->qnumbr, prec); /* needed at least for sqrt() */
+ tval = mpfr_func(res->qnumbr, p1, ROUND_MODE);
+ IEEE_FMT(res->qnumbr, tval);
DEREF(t1);
return res;
}
-#define SPEC_MATH(X) \
+#define MPFPFUNC(X) \
NODE *result; \
-result = do_mpfr_func(#X, mpfr_##X, nargs); \
+result = do_mpfp_func(#X, mpfr_##X, nargs); \
return result
-/* do_mpfr_sin --- do the sin function */
+/* do_mpfp_sin --- do the sin function */
-NODE *
-do_mpfr_sin(int nargs)
+static NODE *
+do_mpfp_sin(int nargs)
{
- SPEC_MATH(sin);
+ MPFPFUNC(sin);
}
-/* do_mpfr_cos --- do the cos function */
+/* do_mpfp_cos --- do the cos function */
-NODE *
-do_mpfr_cos(int nargs)
+static NODE *
+do_mpfp_cos(int nargs)
{
- SPEC_MATH(cos);
+ MPFPFUNC(cos);
}
-/* do_mpfr_exp --- exponential function */
+/* do_mpfp_exp --- exponential function */
-NODE *
-do_mpfr_exp(int nargs)
+static NODE *
+do_mpfp_exp(int nargs)
{
- SPEC_MATH(exp);
+ MPFPFUNC(exp);
}
-/* do_mpfr_log --- the log function */
+/* do_mpfp_log --- the log function */
-NODE *
-do_mpfr_log(int nargs)
+static NODE *
+do_mpfp_log(int nargs)
{
- SPEC_MATH(log);
+ MPFPFUNC(log);
}
-/* do_mpfr_sqrt --- do the sqrt function */
+/* do_mpfp_sqrt --- do the sqrt function */
-NODE *
-do_mpfr_sqrt(int nargs)
+static NODE *
+do_mpfp_sqrt(int nargs)
{
- SPEC_MATH(sqrt);
+ MPFPFUNC(sqrt);
}
-/* do_mpfr_int --- convert double to int for awk */
+/* do_mpfp_int --- convert floating point number to integer for awk */
-NODE *
-do_mpfr_int(int nargs)
+static NODE *
+do_mpfp_int(int nargs)
{
NODE *tmp, *r;
tmp = POP_SCALAR();
if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
lintwarn(_("int: received non-numeric argument"));
- force_number(tmp);
+ tmp = force_number(tmp);
- if (is_mpg_integer(tmp)) {
- r = mpg_integer();
- mpz_set(r->mpg_i, tmp->mpg_i);
+ if (is_mpfp_integer(tmp)) {
+ r = mpfp_integer();
+ mpz_set(r->qnumbr, tmp->qnumbr);
} else {
- if (! mpfr_number_p(tmp->mpg_numbr)) {
+ if (! mpfr_number_p(tmp->qnumbr)) {
/* [+-]inf or NaN */
return tmp;
}
-
- r = mpg_integer();
- mpfr_get_z(r->mpg_i, tmp->mpg_numbr, MPFR_RNDZ);
+ r = mpfp_integer();
+ mpfr_get_z(r->qnumbr, tmp->qnumbr, MPFR_RNDZ);
}
DEREF(tmp);
return r;
}
-/* do_mpfr_compl --- perform a ~ operation */
+/* do_mpfp_compl --- perform a ~ operation */
-NODE *
-do_mpfr_compl(int nargs)
+static NODE *
+do_mpfp_compl(int nargs)
{
NODE *tmp, *r;
mpz_ptr zptr;
@@ -808,9 +1139,9 @@ do_mpfr_compl(int nargs)
if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
lintwarn(_("compl: received non-numeric argument"));
- force_number(tmp);
- if (is_mpg_float(tmp)) {
- mpfr_ptr p = tmp->mpg_numbr;
+ (void) force_number(tmp);
+ if (is_mpfp_float(tmp)) {
+ mpfr_ptr p = tmp->qnumbr;
if (! mpfr_number_p(p)) {
/* [+-]inf or NaN */
@@ -819,33 +1150,41 @@ do_mpfr_compl(int nargs)
if (do_lint) {
if (mpfr_sgn(p) < 0)
lintwarn("%s",
- mpg_fmt(_("compl(%Rg): negative value will give strange results"), p)
+ mpfp_sprintf(_("compl(%Rg): negative value will give strange results"), p)
);
if (! mpfr_integer_p(p))
lintwarn("%s",
- mpg_fmt(_("comp(%Rg): fractional value will be truncated"), p)
+ mpfp_sprintf(_("comp(%Rg): fractional value will be truncated"), p)
);
}
-
- mpfr_get_z(mpzval, p, MPFR_RNDZ); /* float to integer conversion */
- zptr = mpzval;
+
+ emalloc(zptr, mpz_ptr, sizeof (mpz_t), "do_mpfr_compl");
+ mpz_init(zptr);
+ mpfr_get_z(zptr, p, MPFR_RNDZ); /* float to integer conversion */
+
} else {
/* (tmp->flags & MPZN) != 0 */
- zptr = tmp->mpg_i;
+ zptr = tmp->qnumbr;
if (do_lint) {
if (mpz_sgn(zptr) < 0)
lintwarn("%s",
- mpg_fmt(_("cmpl(%Zd): negative values will give strange results"), zptr)
+ mpfp_sprintf(_("cmpl(%Zd): negative values will give strange results"), zptr)
);
}
}
- r = mpg_integer();
- mpz_com(r->mpg_i, zptr);
+ r = mpfp_integer();
+ mpz_com(r->qnumbr, zptr);
+
+ if (zptr != tmp->qnumbr) {
+ mpz_clear(zptr);
+ efree(zptr);
+ }
DEREF(tmp);
return r;
}
+
/* get_intval --- get the (converted) integral operand of a binary function. */
static mpz_ptr
@@ -858,16 +1197,15 @@ get_intval(NODE *t1, int argnum, const char *op)
(void) force_number(t1);
- if (is_mpg_float(t1)) {
- mpfr_ptr left = t1->mpg_numbr;
+ if (is_mpfp_float(t1)) {
+ mpfr_ptr left = t1->qnumbr;
if (! mpfr_number_p(left)) {
/* inf or NaN */
if (do_lint)
lintwarn("%s",
- mpg_fmt(_("%s: argument #%d has invalid value %Rg, using 0"),
+ mpfp_sprintf(_("%s: argument #%d has invalid value %Rg, using 0"),
op, argnum, left)
);
-
emalloc(pz, mpz_ptr, sizeof (mpz_t), "get_intval");
mpz_init(pz);
return pz; /* should be freed */
@@ -876,13 +1214,13 @@ get_intval(NODE *t1, int argnum, const char *op)
if (do_lint) {
if (mpfr_sgn(left) < 0)
lintwarn("%s",
- mpg_fmt(_("%s: argument #%d negative value %Rg will give strange results"),
+ mpfp_sprintf(_("%s: argument #%d negative value %Rg will give strange results"),
op, argnum, left)
);
if (! mpfr_integer_p(left))
lintwarn("%s",
- mpg_fmt(_("%s: argument #%d fractional value %Rg will be truncated"),
+ mpfp_sprintf(_("%s: argument #%d fractional value %Rg will be truncated"),
op, argnum, left)
);
}
@@ -891,36 +1229,35 @@ get_intval(NODE *t1, int argnum, const char *op)
mpz_init(pz);
mpfr_get_z(pz, left, MPFR_RNDZ); /* float to integer conversion */
return pz; /* should be freed */
- }
+ }
+
/* (t1->flags & MPZN) != 0 */
- pz = t1->mpg_i;
+ pz = t1->qnumbr;
if (do_lint) {
if (mpz_sgn(pz) < 0)
lintwarn("%s",
- mpg_fmt(_("%s: argument #%d negative value %Zd will give strange results"),
+ mpfp_sprintf(_("%s: argument #%d negative value %Zd will give strange results"),
op, argnum, pz)
);
}
return pz; /* must not be freed */
}
-
/* free_intval --- free the converted integer value returned by get_intval() */
static inline void
free_intval(NODE *t, mpz_ptr pz)
{
- if ((t->flags & MPZN) == 0) {
+ if (t->qnumbr != pz) {
mpz_clear(pz);
efree(pz);
}
}
+/* do_mpfp_lshift --- perform a << operation */
-/* do_mpfr_lshift --- perform a << operation */
-
-NODE *
-do_mpfr_lshift(int nargs)
+static NODE *
+do_mpfp_lshift(int nargs)
{
NODE *t1, *t2, *res;
unsigned long shift;
@@ -939,8 +1276,8 @@ do_mpfr_lshift(int nargs)
*/
shift = mpz_get_ui(pz2); /* GMP integer => unsigned long conversion */
- res = mpg_integer();
- mpz_mul_2exp(res->mpg_i, pz1, shift); /* res = pz1 * 2^shift */
+ res = mpfp_integer();
+ mpz_mul_2exp(res->qnumbr, pz1, shift); /* res = pz1 * 2^shift */
free_intval(t1, pz1);
free_intval(t2, pz2);
@@ -949,10 +1286,10 @@ do_mpfr_lshift(int nargs)
return res;
}
-/* do_mpfr_rshift --- perform a >> operation */
+/* do_mpfp_rshift --- perform a >> operation */
-NODE *
-do_mpfr_rshift(int nargs)
+static NODE *
+do_mpfp_rshift(int nargs)
{
NODE *t1, *t2, *res;
unsigned long shift;
@@ -966,8 +1303,8 @@ do_mpfr_rshift(int nargs)
/* N.B: See do_mpfp_lshift. */
shift = mpz_get_ui(pz2); /* GMP integer => unsigned long conversion */
- res = mpg_integer();
- mpz_fdiv_q_2exp(res->mpg_i, pz1, shift); /* res = pz1 / 2^shift, round towards −inf */
+ res = mpfp_integer();
+ mpz_fdiv_q_2exp(res->qnumbr, pz1, shift); /* res = pz1 / 2^shift, round towards −inf */
free_intval(t1, pz1);
free_intval(t2, pz2);
@@ -976,11 +1313,10 @@ do_mpfr_rshift(int nargs)
return res;
}
+/* do_mpfp_and --- perform an & operation */
-/* do_mpfr_and --- perform an & operation */
-
-NODE *
-do_mpfr_and(int nargs)
+static NODE *
+do_mpfp_and(int nargs)
{
NODE *t1, *t2, *res;
mpz_ptr pz1, pz2;
@@ -992,27 +1328,26 @@ do_mpfr_and(int nargs)
t2 = POP_SCALAR();
pz2 = get_intval(t2, nargs, "and");
- res = mpg_integer();
+ res = mpfp_integer();
for (i = 1; i < nargs; i++) {
t1 = POP_SCALAR();
pz1 = get_intval(t1, nargs - i, "and");
- mpz_and(res->mpg_i, pz1, pz2);
+ mpz_and(res->qnumbr, pz1, pz2);
free_intval(t1, pz1);
DEREF(t1);
if (i == 1) {
free_intval(t2, pz2);
DEREF(t2);
}
- pz2 = res->mpg_i;
+ pz2 = res->qnumbr;
}
return res;
}
+/* do_mpfp_or --- perform an | operation */
-/* do_mpfr_or --- perform an | operation */
-
-NODE *
-do_mpfr_or(int nargs)
+static NODE *
+do_mpfp_or(int nargs)
{
NODE *t1, *t2, *res;
mpz_ptr pz1, pz2;
@@ -1024,26 +1359,26 @@ do_mpfr_or(int nargs)
t2 = POP_SCALAR();
pz2 = get_intval(t2, nargs, "or");
- res = mpg_integer();
+ res = mpfp_integer();
for (i = 1; i < nargs; i++) {
t1 = POP_SCALAR();
pz1 = get_intval(t1, nargs - i, "or");
- mpz_ior(res->mpg_i, pz1, pz2);
+ mpz_ior(res->qnumbr, pz1, pz2);
free_intval(t1, pz1);
DEREF(t1);
if (i == 1) {
free_intval(t2, pz2);
DEREF(t2);
}
- pz2 = res->mpg_i;
+ pz2 = res->qnumbr;
}
return res;
}
-/* do_mpfr_xor --- perform an ^ operation */
+/* do_mpfp_xor --- perform an ^ operation */
-NODE *
-do_mpfr_xor(int nargs)
+static NODE *
+do_mpfp_xor(int nargs)
{
NODE *t1, *t2, *res;
mpz_ptr pz1, pz2;
@@ -1055,47 +1390,47 @@ do_mpfr_xor(int nargs)
t2 = POP_SCALAR();
pz2 = get_intval(t2, nargs, "xor");
- res = mpg_integer();
+ res = mpfp_integer();
for (i = 1; i < nargs; i++) {
t1 = POP_SCALAR();
pz1 = get_intval(t1, nargs - i, "xor");
- mpz_xor(res->mpg_i, pz1, pz2);
+ mpz_xor(res->qnumbr, pz1, pz2);
free_intval(t1, pz1);
DEREF(t1);
if (i == 1) {
free_intval(t2, pz2);
DEREF(t2);
}
- pz2 = res->mpg_i;
+ pz2 = res->qnumbr;
}
return res;
}
-/* do_mpfr_strtonum --- the strtonum function */
+/* do_mpfp_strtonum --- the strtonum function */
-NODE *
-do_mpfr_strtonum(int nargs)
+static NODE *
+do_mpfp_strtonum(int nargs)
{
NODE *tmp, *r;
tmp = POP_SCALAR();
if ((tmp->flags & (NUMBER|NUMCUR)) == 0) {
- r = mpg_integer(); /* will be changed to MPFR float if necessary in force_mpnum() */
+ r = mpfp_integer(); /* will be changed to MPFR float if necessary in force_mpnum() */
r->stptr = tmp->stptr;
r->stlen = tmp->stlen;
- force_mpnum(r, true, use_lc_numeric);
+ mpfp_str2num(r, true, use_lc_numeric);
r->stptr = NULL;
r->stlen = 0;
} else {
(void) force_number(tmp);
- if (is_mpg_float(tmp)) {
+ if (is_mpfp_float(tmp)) {
int tval;
- r = mpg_float();
- tval = mpfr_set(r->mpg_numbr, tmp->mpg_numbr, ROUND_MODE);
- IEEE_FMT(r->mpg_numbr, tval);
+ r = mpfp_float();
+ tval = mpfr_set(r->qnumbr, (mpfr_ptr) tmp->qnumbr, ROUND_MODE);
+ IEEE_FMT(r->qnumbr, tval);
} else {
- r = mpg_integer();
- mpz_set(r->mpg_i, tmp->mpg_i);
+ r = mpfp_integer();
+ mpz_set(r->qnumbr, tmp->qnumbr);
}
}
@@ -1108,10 +1443,10 @@ static bool firstrand = true;
static gmp_randstate_t state;
static mpz_t seed; /* current seed */
-/* do_mpfr_rand --- do the rand function */
+/* do_mpfp_rand --- do the rand function */
-NODE *
-do_mpfr_rand(int nargs ATTRIBUTE_UNUSED)
+static NODE *
+do_mpfp_rand(int nargs ATTRIBUTE_UNUSED)
{
NODE *res;
int tval;
@@ -1134,17 +1469,17 @@ do_mpfr_rand(int nargs ATTRIBUTE_UNUSED)
gmp_randseed(state, seed);
firstrand = false;
}
- res = mpg_float();
- tval = mpfr_urandomb(res->mpg_numbr, state);
- IEEE_FMT(res->mpg_numbr, tval);
+ res = mpfp_float();
+ tval = mpfr_urandomb(res->qnumbr, state);
+ IEEE_FMT(res->qnumbr, tval);
return res;
}
-/* do_mpfr_srand --- seed the random number generator */
+/* do_mpfp_srand --- seed the random number generator */
-NODE *
-do_mpfr_srand(int nargs)
+static NODE *
+do_mpfp_srand(int nargs)
{
NODE *res;
@@ -1166,8 +1501,8 @@ do_mpfr_srand(int nargs)
firstrand = false;
}
- res = mpg_integer();
- mpz_set(res->mpg_i, seed); /* previous seed */
+ res = mpfp_integer();
+ mpz_set(res->qnumbr, seed); /* previous seed */
if (nargs == 0)
mpz_set_ui(seed, (unsigned long) time((time_t *) 0));
@@ -1176,11 +1511,11 @@ do_mpfr_srand(int nargs)
tmp = POP_SCALAR();
if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
lintwarn(_("srand: received non-numeric argument"));
- force_number(tmp);
- if (is_mpg_float(tmp))
- mpfr_get_z(seed, tmp->mpg_numbr, MPFR_RNDZ);
+ (void) force_number(tmp);
+ if (is_mpfp_float(tmp))
+ mpfr_get_z(seed, tmp->qnumbr, MPFR_RNDZ);
else /* MP integer */
- mpz_set(seed, tmp->mpg_i);
+ mpz_set(seed, tmp->qnumbr);
DEREF(tmp);
}
@@ -1188,7 +1523,7 @@ do_mpfr_srand(int nargs)
return res;
}
-/* do_mpfr_div --- do integer division, return quotient and remainder in dest array */
+/* do_mpfp_div --- do integer division, return quotient and remainder in dest array */
/*
* We define the semantics as:
@@ -1198,8 +1533,8 @@ do_mpfr_srand(int nargs)
* remainder = int(numerator % denomator)
*/
-NODE *
-do_mpfr_div(int nargs)
+static NODE *
+do_mpfp_div(int nargs)
{
NODE *numerator, *denominator, *result;
NODE *num, *denom;
@@ -1225,40 +1560,40 @@ do_mpfr_div(int nargs)
(void) force_number(denominator);
/* convert numerator and denominator to integer */
- if (is_mpg_integer(numerator)) {
- num = mpg_integer();
- mpz_set(num->mpg_i, numerator->mpg_i);
+ if (is_mpfp_integer(numerator)) {
+ num = mpfp_integer();
+ mpz_set(num->qnumbr, numerator->qnumbr);
} else {
- if (! mpfr_number_p(numerator->mpg_numbr)) {
+ if (! mpfr_number_p(numerator->qnumbr)) {
/* [+-]inf or NaN */
return numerator;
}
- num = mpg_integer();
- mpfr_get_z(num->mpg_i, numerator->mpg_numbr, MPFR_RNDZ);
+ num = mpfp_integer();
+ mpfr_get_z(num->qnumbr, numerator->qnumbr, MPFR_RNDZ);
}
- if (is_mpg_integer(denominator)) {
- denom = mpg_integer();
- mpz_set(denom->mpg_i, denominator->mpg_i);
+ if (is_mpfp_integer(denominator)) {
+ denom = mpfp_integer();
+ mpz_set(denom->qnumbr, denominator->qnumbr);
} else {
- if (! mpfr_number_p(denominator->mpg_numbr)) {
+ if (! mpfr_number_p(denominator->qnumbr)) {
/* [+-]inf or NaN */
return denominator;
}
- denom = mpg_integer();
- mpfr_get_z(denom->mpg_i, denominator->mpg_numbr, MPFR_RNDZ);
+ denom = mpfp_integer();
+ mpfr_get_z(denom->qnumbr, denominator->qnumbr, MPFR_RNDZ);
}
- if (mpz_sgn(denom->mpg_i) == 0)
+ if (mpz_sgn(MPZ_T(denom->qnumbr)) == 0)
fatal(_("div: division by zero attempted"));
- quotient = mpg_integer();
- remainder = mpg_integer();
+ quotient = mpfp_integer();
+ remainder = mpfp_integer();
/* do the division */
- mpz_tdiv_qr(quotient->mpg_i, remainder->mpg_i, num->mpg_i, denom->mpg_i);
+ mpz_tdiv_qr(quotient->qnumbr, remainder->qnumbr, num->qnumbr, denom->qnumbr);
unref(num);
unref(denom);
unref(numerator);
@@ -1314,157 +1649,160 @@ mpg_tofloat(mpfr_ptr mf, mpz_ptr mz)
}
-/* mpg_add --- add arbitrary-precision numbers */
+/* mpfp_add --- add arbitrary-precision numbers */
static NODE *
-mpg_add(NODE *t1, NODE *t2)
+mpfp_add(const NODE *t1, const NODE *t2)
{
NODE *r;
int tval;
- if (is_mpg_integer(t1) && is_mpg_integer(t2)) {
- r = mpg_integer();
- mpz_add(r->mpg_i, t1->mpg_i, t2->mpg_i);
+ if (is_mpfp_integer(t1) && is_mpfp_integer(t2)) {
+ r = mpfp_integer();
+ mpz_add(r->qnumbr, t1->qnumbr, t2->qnumbr);
} else {
- r = mpg_float();
- if (is_mpg_integer(t2))
- tval = mpfr_add_z(r->mpg_numbr, t1->mpg_numbr, t2->mpg_i, ROUND_MODE);
- else if (is_mpg_integer(t1))
- tval = mpfr_add_z(r->mpg_numbr, t2->mpg_numbr, t1->mpg_i, ROUND_MODE);
+ r = mpfp_float();
+ if (is_mpfp_integer(t2))
+ tval = mpfr_add_z(r->qnumbr, t1->qnumbr, t2->qnumbr, ROUND_MODE);
+ else if (is_mpfp_integer(t1))
+ tval = mpfr_add_z(r->qnumbr, t2->qnumbr, t1->qnumbr, ROUND_MODE);
else
- tval = mpfr_add(r->mpg_numbr, t1->mpg_numbr, t2->mpg_numbr, ROUND_MODE);
- IEEE_FMT(r->mpg_numbr, tval);
+ tval = mpfr_add(r->qnumbr, t1->qnumbr, t2->qnumbr, ROUND_MODE);
+ IEEE_FMT(r->qnumbr, tval);
}
return r;
}
-/* mpg_sub --- subtract arbitrary-precision numbers */
+/* mpfp_sub --- subtract arbitrary-precision numbers */
static NODE *
-mpg_sub(NODE *t1, NODE *t2)
+mpfp_sub(const NODE *t1, const NODE *t2)
{
NODE *r;
int tval;
- if (is_mpg_integer(t1) && is_mpg_integer(t2)) {
- r = mpg_integer();
- mpz_sub(r->mpg_i, t1->mpg_i, t2->mpg_i);
+ if (is_mpfp_integer(t1) && is_mpfp_integer(t2)) {
+ r = mpfp_integer();
+ mpz_sub(r->qnumbr, t1->qnumbr, t2->qnumbr);
} else {
- r = mpg_float();
- if (is_mpg_integer(t2))
- tval = mpfr_sub_z(r->mpg_numbr, t1->mpg_numbr, t2->mpg_i, ROUND_MODE);
- else if (is_mpg_integer(t1)) {
+ r = mpfp_float();
+ if (is_mpfp_integer(t2))
+ tval = mpfr_sub_z(r->qnumbr, t1->qnumbr, t2->qnumbr, ROUND_MODE);
+ else if (is_mpfp_integer(t1)) {
#if (!defined(MPFR_VERSION) || (MPFR_VERSION < MPFR_VERSION_NUM(3,1,0)))
- NODE *tmp = t1;
+ const NODE *tmp = t1;
+
t1 = t2;
t2 = tmp;
- tval = mpfr_sub_z(r->mpg_numbr, t1->mpg_numbr, t2->mpg_i, ROUND_MODE);
- tval = mpfr_neg(r->mpg_numbr, r->mpg_numbr, ROUND_MODE);
+ tval = mpfr_sub_z(r->qnumbr, t1->qnumbr, t2->qnumbr, ROUND_MODE);
+ tval = mpfr_neg(r->qnumbr, r->qnumbr, ROUND_MODE);
t2 = t1;
t1 = tmp;
#else
- tval = mpfr_z_sub(r->mpg_numbr, t1->mpg_i, t2->mpg_numbr, ROUND_MODE);
+ tval = mpfr_z_sub(r->qnumbr, t1->qnumbr, t2->qnumbr, ROUND_MODE);
#endif
} else
- tval = mpfr_sub(r->mpg_numbr, t1->mpg_numbr, t2->mpg_numbr, ROUND_MODE);
- IEEE_FMT(r->mpg_numbr, tval);
+ tval = mpfr_sub(r->qnumbr, t1->qnumbr, t2->qnumbr, ROUND_MODE);
+ IEEE_FMT(r->qnumbr, tval);
}
return r;
}
-/* mpg_mul --- multiply arbitrary-precision numbers */
+/* mpfp_mul --- multiply arbitrary-precision numbers */
static NODE *
-mpg_mul(NODE *t1, NODE *t2)
+mpfp_mul(const NODE *t1, const NODE *t2)
{
NODE *r;
int tval;
- if (is_mpg_integer(t1) && is_mpg_integer(t2)) {
- r = mpg_integer();
- mpz_mul(r->mpg_i, t1->mpg_i, t2->mpg_i);
+ if (is_mpfp_integer(t1) && is_mpfp_integer(t2)) {
+ r = mpfp_integer();
+ mpz_mul(r->qnumbr, t1->qnumbr, t2->qnumbr);
} else {
- r = mpg_float();
- if (is_mpg_integer(t2))
- tval = mpfr_mul_z(r->mpg_numbr, t1->mpg_numbr, t2->mpg_i, ROUND_MODE);
- else if (is_mpg_integer(t1))
- tval = mpfr_mul_z(r->mpg_numbr, t2->mpg_numbr, t1->mpg_i, ROUND_MODE);
+ r = mpfp_float();
+ if (is_mpfp_integer(t2))
+ tval = mpfr_mul_z(r->qnumbr, t1->qnumbr, t2->qnumbr, ROUND_MODE);
+ else if (is_mpfp_integer(t1))
+ tval = mpfr_mul_z(r->qnumbr, t2->qnumbr, t1->qnumbr, ROUND_MODE);
else
- tval = mpfr_mul(r->mpg_numbr, t1->mpg_numbr, t2->mpg_numbr, ROUND_MODE);
- IEEE_FMT(r->mpg_numbr, tval);
+ tval = mpfr_mul(r->qnumbr, t1->qnumbr, t2->qnumbr, ROUND_MODE);
+ IEEE_FMT(r->qnumbr, tval);
}
return r;
}
-
-/* mpg_pow --- exponentiation involving arbitrary-precision numbers */
+/* mpfp_pow --- exponentiation involving arbitrary-precision numbers */
static NODE *
-mpg_pow(NODE *t1, NODE *t2)
+mpfp_pow(const NODE *t1, const NODE *t2)
{
NODE *r;
int tval;
- if (is_mpg_integer(t1) && is_mpg_integer(t2)) {
- if (mpz_sgn(t2->mpg_i) >= 0 && mpz_fits_ulong_p(t2->mpg_i)) {
- r = mpg_integer();
- mpz_pow_ui(r->mpg_i, t1->mpg_i, mpz_get_ui(t2->mpg_i));
+ if (is_mpfp_integer(t1) && is_mpfp_integer(t2)) {
+ if (mpz_sgn(MPZ_T(t2->qnumbr)) >= 0 && mpz_fits_ulong_p(t2->qnumbr)) {
+ r = mpfp_integer();
+ mpz_pow_ui(r->qnumbr, t1->qnumbr, mpz_get_ui(t2->qnumbr));
} else {
mpfr_ptr p1, p2;
- p1 = MP_FLOAT(t1);
- p2 = MP_FLOAT(t2);
- r = mpg_float();
- tval = mpfr_pow(r->mpg_numbr, p1, p2, ROUND_MODE);
- IEEE_FMT(r->mpg_numbr, tval);
+
+ p1 = mpfp_tofloat(t1, _mp1);
+ p2 = mpfp_tofloat(t2, _mp2);
+ r = mpfp_float();
+ tval = mpfr_pow(r->qnumbr, p1, p2, ROUND_MODE);
+ IEEE_FMT(r->qnumbr, tval);
}
} else {
- r = mpg_float();
- if (is_mpg_integer(t2))
- tval = mpfr_pow_z(r->mpg_numbr, t1->mpg_numbr, t2->mpg_i, ROUND_MODE);
+ r = mpfp_float();
+ if (is_mpfp_integer(t2))
+ tval = mpfr_pow_z(r->qnumbr, t1->qnumbr, t2->qnumbr, ROUND_MODE);
else {
mpfr_ptr p1;
- p1 = MP_FLOAT(t1);
- tval = mpfr_pow(r->mpg_numbr, p1, t2->mpg_numbr, ROUND_MODE);
+
+ p1 = mpfp_tofloat(t1, _mp1);
+ tval = mpfr_pow(r->qnumbr, p1, t2->qnumbr, ROUND_MODE);
}
- IEEE_FMT(r->mpg_numbr, tval);
+ IEEE_FMT(r->qnumbr, tval);
}
return r;
}
-/* mpg_div --- arbitrary-precision division */
+/* mpfp_div --- arbitrary-precision division */
static NODE *
-mpg_div(NODE *t1, NODE *t2)
+mpfp_div(const NODE *t1, const NODE *t2)
{
NODE *r;
int tval;
- if (is_mpg_integer(t1) && is_mpg_integer(t2)
- && (mpz_sgn(t2->mpg_i) != 0) /* not dividing by 0 */
- && mpz_divisible_p(t1->mpg_i, t2->mpg_i)
+ if (is_mpfp_integer(t1) && is_mpfp_integer(t2)
+ && (mpz_sgn(MPZ_T(t2->qnumbr)) != 0) /* not dividing by 0 */
+ && mpz_divisible_p(t1->qnumbr, t2->qnumbr)
) {
- r = mpg_integer();
- mpz_divexact(r->mpg_i, t1->mpg_i, t2->mpg_i);
+ r = mpfp_integer();
+ mpz_divexact(r->qnumbr, t1->qnumbr, t2->qnumbr);
} else {
mpfr_ptr p1, p2;
- p1 = MP_FLOAT(t1);
- p2 = MP_FLOAT(t2);
- r = mpg_float();
- tval = mpfr_div(r->mpg_numbr, p1, p2, ROUND_MODE);
- IEEE_FMT(r->mpg_numbr, tval);
+
+ p1 = mpfp_tofloat(t1, _mp1);
+ p2 = mpfp_tofloat(t2, _mp2);
+ r = mpfp_float();
+ tval = mpfr_div(r->qnumbr, p1, p2, ROUND_MODE);
+ IEEE_FMT(r->qnumbr, tval);
}
return r;
}
-/* mpg_mod --- modulus operation with arbitrary-precision numbers */
+/* mpfp_mod --- modulus operation with arbitrary-precision numbers */
static NODE *
-mpg_mod(NODE *t1, NODE *t2)
+mpfp_mod(const NODE *t1, const NODE *t2)
{
NODE *r;
int tval;
- if (is_mpg_integer(t1) && is_mpg_integer(t2)) {
+ if (is_mpfp_integer(t1) && is_mpfp_integer(t2)) {
/*
* 8/2014: Originally, this was just
*
@@ -1482,259 +1820,70 @@ mpg_mod(NODE *t1, NODE *t2)
*/
NODE *dummy_quotient;
- r = mpg_integer();
- dummy_quotient = mpg_integer();
- mpz_tdiv_qr(dummy_quotient->mpg_i, r->mpg_i, t1->mpg_i, t2->mpg_i);
+ r = mpfp_integer();
+ dummy_quotient = mpfp_integer();
+ mpz_tdiv_qr(dummy_quotient->qnumbr, r->qnumbr, t1->qnumbr, t2->qnumbr);
unref(dummy_quotient);
} else {
mpfr_ptr p1, p2;
- p1 = MP_FLOAT(t1);
- p2 = MP_FLOAT(t2);
- r = mpg_float();
- tval = mpfr_fmod(r->mpg_numbr, p1, p2, ROUND_MODE);
- IEEE_FMT(r->mpg_numbr, tval);
+
+ p1 = mpfp_tofloat(t1, _mp1);
+ p2 = mpfp_tofloat(t2, _mp2);
+ r = mpfp_float();
+ tval = mpfr_fmod(r->qnumbr, p1, p2, ROUND_MODE);
+ IEEE_FMT(r->qnumbr, tval);
}
return r;
}
-
-/*
- * mpg_interpret --- pre-exec hook in the interpreter. Handles
- * arithmetic operations with MPFR/GMP numbers.
- */
-
-static int
-mpg_interpret(INSTRUCTION **cp)
-{
- INSTRUCTION *pc = *cp; /* current instruction */
- OPCODE op; /* current opcode */
- NODE *r = NULL;
- NODE *t1, *t2;
- NODE **lhs;
- int tval; /* the ternary value returned by a MPFR function */
-
- switch ((op = pc->opcode)) {
- case Op_plus_i:
- t2 = force_number(pc->memory);
- goto plus;
- case Op_plus:
- t2 = POP_NUMBER();
-plus:
- t1 = TOP_NUMBER();
- r = mpg_add(t1, t2);
- DEREF(t1);
- if (op == Op_plus)
- DEREF(t2);
- REPLACE(r);
- break;
- case Op_minus_i:
- t2 = force_number(pc->memory);
- goto minus;
- case Op_minus:
- t2 = POP_NUMBER();
-minus:
- t1 = TOP_NUMBER();
- r = mpg_sub(t1, t2);
- DEREF(t1);
- if (op == Op_minus)
- DEREF(t2);
- REPLACE(r);
- break;
-
- case Op_times_i:
- t2 = force_number(pc->memory);
- goto times;
- case Op_times:
- t2 = POP_NUMBER();
-times:
- t1 = TOP_NUMBER();
- r = mpg_mul(t1, t2);
- DEREF(t1);
- if (op == Op_times)
- DEREF(t2);
- REPLACE(r);
- break;
-
- case Op_exp_i:
- t2 = force_number(pc->memory);
- goto exp;
- case Op_exp:
- t2 = POP_NUMBER();
-exp:
- t1 = TOP_NUMBER();
- r = mpg_pow(t1, t2);
- DEREF(t1);
- if (op == Op_exp)
- DEREF(t2);
- REPLACE(r);
- break;
-
- case Op_quotient_i:
- t2 = force_number(pc->memory);
- goto quotient;
- case Op_quotient:
- t2 = POP_NUMBER();
-quotient:
- t1 = TOP_NUMBER();
- r = mpg_div(t1, t2);
- DEREF(t1);
- if (op == Op_quotient)
- DEREF(t2);
- REPLACE(r);
- break;
-
- case Op_mod_i:
- t2 = force_number(pc->memory);
- goto mod;
- case Op_mod:
- t2 = POP_NUMBER();
-mod:
- t1 = TOP_NUMBER();
- r = mpg_mod(t1, t2);
- DEREF(t1);
- if (op == Op_mod)
- DEREF(t2);
- REPLACE(r);
- break;
+/* mpfp_add_long --- add aribitary-precision number to long */
- case Op_preincrement:
- case Op_predecrement:
- lhs = TOP_ADDRESS();
- t1 = *lhs;
- force_number(t1);
-
- if (is_mpg_integer(t1)) {
- if (t1->valref == 1 && t1->flags == (MALLOC|MPZN|NUMCUR|NUMBER))
- /* Efficiency hack. Big speed-up (> 30%) in a tight loop */
- r = t1;
- else
- r = *lhs = mpg_integer();
- if (op == Op_preincrement)
- mpz_add_ui(r->mpg_i, t1->mpg_i, 1);
- else
- mpz_sub_ui(r->mpg_i, t1->mpg_i, 1);
- } else {
+static NODE *
+mpfp_add_long(const NODE *t1, long l)
+{
+ NODE *r;
- /*
- * An optimization like the one above is not going to work
- * for a floating-point number. With it,
- * gawk -M 'BEGIN { PREC=53; i=2^53+0.0; PREC=113; ++i; print i}'
- * will output 2^53 instead of 2^53+1.
- */
-
- r = *lhs = mpg_float();
- tval = mpfr_add_si(r->mpg_numbr, t1->mpg_numbr,
- op == Op_preincrement ? 1 : -1,
- ROUND_MODE);
- IEEE_FMT(r->mpg_numbr, tval);
- }
- if (r != t1)
- unref(t1);
- UPREF(r);
- REPLACE(r);
- break;
+ if (is_mpfp_integer(t1)) {
+ r = mpfp_integer();
+ if (l >= 0)
+ mpz_add_ui(r->qnumbr, t1->qnumbr, l);
+ else
+ mpz_sub_ui(r->qnumbr, t1->qnumbr, -l);
+ } else {
+ int tval;
- case Op_postincrement:
- case Op_postdecrement:
- lhs = TOP_ADDRESS();
- t1 = *lhs;
- force_number(t1);
-
- if (is_mpg_integer(t1)) {
- r = mpg_integer();
- mpz_set(r->mpg_i, t1->mpg_i);
- if (t1->valref == 1 && t1->flags == (MALLOC|MPZN|NUMCUR|NUMBER))
- /* Efficiency hack. Big speed-up (> 30%) in a tight loop */
- t2 = t1;
- else
- t2 = *lhs = mpg_integer();
- if (op == Op_postincrement)
- mpz_add_ui(t2->mpg_i, t1->mpg_i, 1);
- else
- mpz_sub_ui(t2->mpg_i, t1->mpg_i, 1);
- } else {
- r = mpg_float();
- tval = mpfr_set(r->mpg_numbr, t1->mpg_numbr, ROUND_MODE);
- IEEE_FMT(r->mpg_numbr, tval);
- t2 = *lhs = mpg_float();
- tval = mpfr_add_si(t2->mpg_numbr, t1->mpg_numbr,
- op == Op_postincrement ? 1 : -1,
- ROUND_MODE);
- IEEE_FMT(t2->mpg_numbr, tval);
- }
- if (t2 != t1)
- unref(t1);
- REPLACE(r);
- break;
+ r = mpfp_float();
+ tval = mpfr_add_si(r->qnumbr, t1->qnumbr, l, ROUND_MODE);
+ IEEE_FMT(r->qnumbr, tval);
+ }
+ return r;
+}
- case Op_unary_minus:
- t1 = TOP_NUMBER();
- if (is_mpg_float(t1)) {
- r = mpg_float();
- tval = mpfr_neg(r->mpg_numbr, t1->mpg_numbr, ROUND_MODE);
- IEEE_FMT(r->mpg_numbr, tval);
- } else {
- r = mpg_integer();
- mpz_neg(r->mpg_i, t1->mpg_i);
- }
- DEREF(t1);
- REPLACE(r);
- break;
+/* mpfp_copy_number --- copy an arbitrary-precision number */
- case Op_assign_plus:
- case Op_assign_minus:
- case Op_assign_times:
- case Op_assign_quotient:
- case Op_assign_mod:
- case Op_assign_exp:
- lhs = POP_ADDRESS();
- t1 = *lhs;
- force_number(t1);
- t2 = TOP_NUMBER();
-
- switch (op) {
- case Op_assign_plus:
- r = mpg_add(t1, t2);
- break;
- case Op_assign_minus:
- r = mpg_sub(t1, t2);
- break;
- case Op_assign_times:
- r = mpg_mul(t1, t2);
- break;
- case Op_assign_quotient:
- r = mpg_div(t1, t2);
- break;
- case Op_assign_mod:
- r = mpg_mod(t1, t2);
- break;
- case Op_assign_exp:
- r = mpg_pow(t1, t2);
- break;
- default:
- cant_happen();
- }
+static NODE *
+mpfp_copy_number(const NODE *n)
+{
+ NODE *r;
- DEREF(t2);
- unref(*lhs);
- *lhs = r;
- UPREF(r);
- REPLACE(r);
- break;
+ if (is_mpfp_integer(n)) {
+ r = mpfp_integer();
+ mpz_set(r->qnumbr, n->qnumbr);
+ } else {
+ int tval;
- default:
- return true; /* unhandled */
+ r = mpfp_float();
+ tval = mpfr_set(r->qnumbr, MPFR_T(n->qnumbr), ROUND_MODE);
+ IEEE_FMT(r->qnumbr, tval);
}
-
- *cp = pc->nexti; /* next instruction to execute */
- return false;
+ return r;
}
-/* mpg_fmt --- output formatted string with special MPFR/GMP conversion specifiers */
+/* mpfp_sprintf --- output formatted string with special MPFR/GMP conversion specifiers */
-const char *
-mpg_fmt(const char *mesg, ...)
+static const char *
+mpfp_sprintf(const char *mesg, ...)
{
static char *tmp = NULL;
int ret;
@@ -1752,34 +1901,289 @@ mpg_fmt(const char *mesg, ...)
return mesg;
}
-/* mpfr_unset --- clear out the MPFR values */
-void
-mpfr_unset(NODE *n)
-{
- if (is_mpg_float(n))
- mpfr_clear(n->mpg_numbr);
- else if (is_mpg_integer(n))
- mpz_clear(n->mpg_i);
-}
+/*
+ * mpz2mpfr --- convert an arbitrary-precision integer to a float
+ * without any loss of precision. If the 2nd arg is NULL, the returned MPFR
+ * value should be freed when done:
+ * mpfr_clear(mpfrval); efree(mpfrval);
+ * If the 2nd arg is not NULL, it is assumed that the MPFR variable has
+ * already been initialized.
+ */
-#else
-void
-set_PREC()
+static mpfr_ptr
+mpz2mpfr(mpz_ptr mpz_val, mpfr_ptr mpfr_val)
{
- /* dummy function */
+ long prec, prec1;
+ int tval;
+
+ /*
+ * When implicitely converting a GMP integer operand to a MPFR float, use
+ * a precision sufficiently large to hold the converted value exactly.
+ *
+ * $ ./gawk -M 'BEGIN { print 13 % 2 }'
+ * 1
+ * If the user-specified precision is used to convert the integer 13 to a
+ * float, one will get:
+ * $ ./gawk -M 'BEGIN { PREC=2; print 13 % 2.0 }'
+ * 0
+ */
+
+ /* estimate minimum precision for exact conversion */
+ prec = mpz_sizeinbase(mpz_val, 2); /* most significant 1 bit position starting at 1 */
+
+ prec1 = prec; /* silence "prec1 may not be initialized" warnings */
+ if (mpfr_val != NULL && (prec1 = mpfr_get_prec(mpfr_val)) >= prec)
+ goto finish;
+
+ prec -= (long) mpz_scan1(mpz_val, 0); /* least significant 1 bit index starting at 0 */
+ if (prec < MPFR_PREC_MIN)
+ prec = MPFR_PREC_MIN;
+ else if (prec > MPFR_PREC_MAX)
+ prec = MPFR_PREC_MAX;
+
+ if (mpfr_val == NULL) {
+ emalloc(mpfr_val, mpfr_ptr, sizeof (mpfr_t), "mpz2mpfr");
+ mpfr_init2(mpfr_val, prec);
+ } else if (prec > prec1)
+ mpfr_set_prec(mpfr_val, prec);
+
+finish:
+
+ tval = mpfr_set_z(mpfr_val, mpz_val, ROUND_MODE);
+ IEEE_FMT(mpfr_val, tval);
+ return mpfr_val;
}
-void
-set_ROUNDMODE()
+/* mpfp_format_prinf --- format a number for (s)printf */
+
+static int
+mpfp_format_printf(NODE *arg, struct format_spec *spec, struct print_fmt_buf *outb)
{
- /* dummy function */
+ mpz_ptr zi = NULL;
+ mpfr_ptr mf = NULL;
+ enum { MP_INT_WITH_PREC = 1, MP_INT_WITHOUT_PREC, MP_FLOAT } mpfmt_spec;
+
+ uintmax_t uval;
+ char *cp;
+ char cs1;
+ int nc;
+
+# define CP cpbuf_start(outb)
+# define CEND cpbuf_end(outb)
+# define CPBUF cpbuf(outb)
+
+ spec->fill = space_string;
+ spec->chbuf = lchbuf;
+
+ cs1 = spec->fmtchar;
+ cp = CP;
+
+ switch (cs1) {
+ case 'd':
+ case 'i':
+ if (is_mpfp_float(arg))
+ goto mpf0;
+ goto mpz0;
+ case 'X':
+ spec->chbuf = Uchbuf;
+ /* FALL THROUGH */
+ case 'x':
+ /* FALL THROUGH */
+ case 'u':
+ /* FALL THROUGH */
+ case 'o':
+ if (is_mpfp_integer(arg)) {
+mpz0:
+ zi = arg->qnumbr;
+
+ if (cs1 != 'd' && cs1 != 'i') {
+ if (mpz_sgn(zi) <= 0) {
+ /*
+ * Negative value or 0 requires special handling.
+ * Unlike MPFR, GMP does not allow conversion
+ * to (u)intmax_t. So we first convert GMP type to
+ * a MPFR type.
+ */
+ mf = mpz2mpfr(zi, _mpfrval);
+ goto mpf1;
+ }
+ spec->signchar = '\0'; /* Don't print '+' */
+ }
+
+ /* See comments above about when to fill with zeros */
+ spec->zero_flag = (! spec->lj
+ && ((spec->zero_flag && ! spec->have_prec)
+ || (spec->fw == 0 && spec->have_prec)));
+
+ mpfmt_spec = spec->have_prec ? MP_INT_WITH_PREC : MP_INT_WITHOUT_PREC;
+ goto fmt0;
+
+ }
+
+ assert(is_mpfp_float(arg) == true);
+mpf0:
+ mf = arg->qnumbr;
+ if (! mpfr_number_p(mf)) {
+ /* inf or NaN */
+ cs1 = 'g';
+ mpfmt_spec = MP_FLOAT;
+ goto fmt1;
+ }
+
+ if (cs1 != 'd' && cs1 != 'i') {
+mpf1:
+ /*
+ * The output of printf("%#.0x", 0) is 0 instead of 0x, hence <= in
+ * the comparison below.
+ */
+ if (mpfr_sgn(mf) <= 0) {
+ if (! mpfr_fits_intmax_p(mf, ROUND_MODE)) {
+ /* -ve number is too large */
+ cs1 = 'g';
+ mpfmt_spec = MP_FLOAT;
+ goto fmt1;
+ }
+
+ uval = (uintmax_t) mpfr_get_sj(mf, ROUND_MODE);
+ if (! spec->alt && spec->have_prec && spec->prec == 0 && uval == 0) {
+ /* printf("%.0x", 0) is no characters */
+ pr_num_tail(cp, 0, spec, outb);
+ } else
+ format_nondecimal(uval, spec, outb);
+ return 0;
+ }
+ spec->signchar = '\0'; /* Don't print '+' */
+ }
+
+ /* See comments above about when to fill with zeros */
+ spec->zero_flag = (! spec->lj
+ && ((spec->zero_flag && ! spec->have_prec)
+ || (spec->fw == 0 && spec->have_prec)));
+
+ (void) mpfr_get_z(_mpzval, mf, MPFR_RNDZ); /* convert to GMP integer */
+ mpfmt_spec = spec->have_prec ? MP_INT_WITH_PREC : MP_INT_WITHOUT_PREC;
+ zi = _mpzval;
+ goto fmt0;
+
+
+#if 0
+out_of_range:
+ /* out of range - emergency use of %g format */
+ if (do_lint)
+ lintwarn(_("[s]printf: value %g is out of range for `%%%c' format"),
+ (double) tmpval, cs1);
+ cs1 = 'g';
+ goto fmt1;
+
+#endif
+
+ case 'F':
+#if ! defined(PRINTF_HAS_F_FORMAT) || PRINTF_HAS_F_FORMAT != 1
+ cs1 = 'f';
+ /* FALL THROUGH */
+#endif
+ case 'g':
+ case 'G':
+ case 'e':
+ case 'f':
+ case 'E':
+ if (is_mpfp_float(arg)) {
+ mf = arg->qnumbr;
+ mpfmt_spec = MP_FLOAT;
+ } else {
+ /* arbitrary-precision integer, convert to MPFR float */
+ assert(mf == NULL);
+ mf = mpz2mpfr(arg->qnumbr, _mpfrval);
+ mpfmt_spec = MP_FLOAT;
+ }
+fmt1:
+ if (! spec->have_prec)
+ spec->prec = DEFAULT_G_PRECISION;
+
+fmt0:
+ chksize(outb, spec->fw + spec->prec + 11); /* 11 == slop */
+ cp = CPBUF; /* XXX --- using the temporary prepend-buffer and
+ * we know it has enough room (>=11).
+ */
+ *cp++ = '%';
+ if (spec->lj)
+ *cp++ = '-';
+ if (spec->signchar)
+ *cp++ = spec->signchar;
+ if (spec->alt)
+ *cp++ = '#';
+ if (spec->zero_flag)
+ *cp++ = '0';
+ if (spec->quote_flag)
+ *cp++ = '\'';
+
+#if defined(LC_NUMERIC)
+ if (spec->quote_flag && ! use_lc_numeric)
+ setlocale(LC_NUMERIC, "");
+#endif
+
+ switch (mpfmt_spec) {
+ case MP_INT_WITH_PREC:
+ sprintf(cp, "*.*Z%c", cs1);
+ while ((nc = mpfr_snprintf(buf_end(outb), buf_space(outb), CPBUF,
+ (int) spec->fw, (int) spec->prec, zi)) >= buf_space(outb))
+ chksize(outb, nc + 1);
+ break;
+ case MP_INT_WITHOUT_PREC:
+ sprintf(cp, "*Z%c", cs1);
+ while ((nc = mpfr_snprintf(buf_end(outb), buf_space(outb), CPBUF,
+ (int) spec->fw, zi)) >= buf_space(outb))
+ chksize(outb, nc + 1);
+ break;
+ case MP_FLOAT:
+ sprintf(cp, "*.*R*%c", cs1);
+ while ((nc = mpfr_snprintf(buf_end(outb), buf_space(outb), CPBUF,
+ (int) spec->fw, (int) spec->prec, ROUND_MODE, mf)) >= buf_space(outb))
+ chksize(outb, nc + 1);
+ break;
+ default:
+ cant_happen();
+ }
+
+#if defined(LC_NUMERIC)
+ if (spec->quote_flag && ! use_lc_numeric)
+ setlocale(LC_NUMERIC, "C");
+#endif
+
+ buf_adjust(outb, nc); /* adjust data and free space in output buffer */
+ return 0;
+
+ default:
+ cant_happen();
+ }
+
+ return -1;
+
+#undef CP
+#undef CEND
+#undef CPBUF
}
-void
-mpfr_unset(NODE *n)
+#else
+
+static bool mpfp_init(bltin_t **bltins);
+
+numbr_handler_t mpfp_hndlr = {
+ mpfp_init,
+ NULL,
+ NULL,
+};
+
+/* mpfp_init --- set up MPFR related variables */
+
+static bool
+mpfp_init(bltin_t **bltins)
{
- /* dummy function */
+ warning(_("this version of gawk does not support arbitrary-precision numbers"));
+ *bltins = NULL;
+ return false;
}
+
#endif
diff --git a/msg.c b/msg.c
index 16fef73a..cca82a33 100644
--- a/msg.c
+++ b/msg.c
@@ -26,6 +26,7 @@
#include "awk.h"
+extern NODE *format_tree(const char *, size_t, NODE **, long); /* format.c */
extern FILE *output_fp;
int sourceline = 0;
char *source = NULL;
@@ -70,26 +71,16 @@ err(bool isfatal, const char *s, const char *emsg, va_list argp)
(void) fprintf(stderr, "%d: ", sourceline);
}
-#ifdef HAVE_MPFR
- if (FNR_node && is_mpg_number(FNR_node->var_value)) {
+ if (FNR_node != NULL && (FNR_node->var_value->flags & (NUMBER|NUMCUR)) != 0) {
NODE *val;
- val = mpg_update_var(FNR_node);
- assert((val->flags & MPZN) != 0);
- if (mpz_sgn(val->mpg_i) > 0) {
+ val = numbr_hndlr->update_numvar(FNR_node);
+ if (sgn_number(val) > 0) { /* positive nonzero number */
file = FILENAME_node->var_value->stptr;
(void) putc('(', stderr);
if (file)
(void) fprintf(stderr, "FILENAME=%s ", file);
- (void) mpfr_fprintf(stderr, "FNR=%Zd) ", val->mpg_i);
+ fprintf(stderr, "FNR=%s) ", fmt_number("%d", val));
}
- } else
-#endif
- if (FNR > 0) {
- file = FILENAME_node->var_value->stptr;
- (void) putc('(', stderr);
- if (file)
- (void) fprintf(stderr, "FILENAME=%s ", file);
- (void) fprintf(stderr, "FNR=%ld) ", FNR);
}
(void) fprintf(stderr, "%s", s);
@@ -105,6 +96,41 @@ err(bool isfatal, const char *s, const char *emsg, va_list argp)
}
}
+
+/*
+ * fmt_number --- format a number node for use in error messages.
+ *
+ * N.B: format is awk printf format. MUST NOT generate warning
+ * in format_tree(). "%ld" is BAD, "%d" is OK!
+ */
+
+const char *
+fmt_number(const char *format, const NODE *n)
+{
+ NODE *dummy[2], *r, *tmp;
+ static char *num_str;
+ extern bool fmt_ok(const char *p);
+
+ /* FIXME: %d etc -- assert(fmt_ok(format) == true); */
+ assert((n->flags & (NUMBER|NUMCUR)) != 0);
+
+ /* copy number so not to change state of the original including flags */
+ tmp = numbr_hndlr->gawk_copy_number(n);
+ if (num_str != NULL)
+ efree(num_str);
+
+ /* create dummy node for sole use of format_tree */
+ dummy[1] = tmp;
+ r = format_tree(format, strlen(format), dummy, 2);
+ assert(r != NULL);
+ num_str = r->stptr;
+ num_str[r->stlen] = '\0';
+ freenode(r);
+ unref(tmp);
+ return num_str;
+}
+
+
/* msg --- take a varargs error message and print it */
void
diff --git a/node.c b/node.c
index 8dd723b4..81a1e55d 100644
--- a/node.c
+++ b/node.c
@@ -25,240 +25,19 @@
*/
#include "awk.h"
-#include "math.h"
-#include "floatmagic.h" /* definition of isnan */
-static int is_ieee_magic_val(const char *val);
-static NODE *r_make_number(double x);
-static AWKNUM get_ieee_magic_val(const char *val);
-extern NODE **fmt_list; /* declared in eval.c */
-
-NODE *(*make_number)(double) = r_make_number;
-NODE *(*str2number)(NODE *) = r_force_number;
-NODE *(*format_val)(const char *, int, NODE *) = r_format_val;
-int (*cmp_numbers)(const NODE *, const NODE *) = cmp_awknums;
-
-/* force_number --- force a value to be numeric */
-
-NODE *
-r_force_number(NODE *n)
-{
- char *cp;
- char *cpend;
- char save;
- char *ptr;
- unsigned int newflags;
- extern double strtod();
-
- if ((n->flags & NUMCUR) != 0)
- return n;
-
- /* all the conditionals are an attempt to avoid the expensive strtod */
-
- /* Note: only set NUMCUR if we actually convert some digits */
-
- n->numbr = 0.0;
-
- if (n->stlen == 0) {
- return n;
- }
-
- cp = n->stptr;
- /*
- * 2/2007:
- * POSIX, by way of severe language lawyering, seems to
- * allow things like "inf" and "nan" to mean something.
- * So if do_posix, the user gets what he deserves.
- * This also allows hexadecimal floating point. Ugh.
- */
- if (! do_posix) {
- if (is_alpha((unsigned char) *cp)) {
- return n;
- } else if (n->stlen == 4 && is_ieee_magic_val(n->stptr)) {
- if ((n->flags & MAYBE_NUM) != 0)
- n->flags &= ~MAYBE_NUM;
- n->flags |= NUMBER|NUMCUR;
- n->numbr = get_ieee_magic_val(n->stptr);
-
- return n;
- }
- /* else
- fall through */
- }
- /* else not POSIX, so
- fall through */
-
- cpend = cp + n->stlen;
- while (cp < cpend && isspace((unsigned char) *cp))
- cp++;
-
- if ( cp == cpend /* only spaces, or */
- || (! do_posix /* not POSIXLY paranoid and */
- && (is_alpha((unsigned char) *cp) /* letter, or */
- /* CANNOT do non-decimal and saw 0x */
- || (! do_non_decimal_data && cp[0] == '0'
- && (cp[1] == 'x' || cp[1] == 'X'))))) {
- return n;
- }
-
- if ((n->flags & MAYBE_NUM) != 0) {
- newflags = NUMBER;
- n->flags &= ~MAYBE_NUM;
- } else
- newflags = 0;
-
- if (cpend - cp == 1) { /* only one character */
- if (isdigit((unsigned char) *cp)) { /* it's a digit! */
- n->numbr = (AWKNUM)(*cp - '0');
- n->flags |= newflags;
- n->flags |= NUMCUR;
- if (cp == n->stptr) /* no leading spaces */
- n->flags |= NUMINT;
- }
- return n;
- }
-
- if (do_non_decimal_data) { /* main.c assures false if do_posix */
- errno = 0;
- if (! do_traditional && get_numbase(cp, true) != 10) {
- n->numbr = nondec2awknum(cp, cpend - cp);
- n->flags |= NUMCUR;
- ptr = cpend;
- goto finish;
- }
- }
-
- errno = 0;
- save = *cpend;
- *cpend = '\0';
- n->numbr = (AWKNUM) strtod((const char *) cp, &ptr);
-
- /* POSIX says trailing space is OK for NUMBER */
- while (isspace((unsigned char) *ptr))
- ptr++;
- *cpend = save;
-finish:
- if (errno == 0 && ptr == cpend) {
- n->flags |= newflags;
- n->flags |= NUMCUR;
- } else {
- errno = 0;
- }
-
- return n;
-}
-
-
-/*
- * The following lookup table is used as an optimization in force_string;
- * (more complicated) variations on this theme didn't seem to pay off, but
- * systematic testing might be in order at some point.
- */
-static const char *values[] = {
- "0",
- "1",
- "2",
- "3",
- "4",
- "5",
- "6",
- "7",
- "8",
- "9",
-};
-#define NVAL (sizeof(values)/sizeof(values[0]))
-
-/* r_format_val --- format a numeric value based on format */
-
-NODE *
-r_format_val(const char *format, int index, NODE *s)
-{
- char buf[BUFSIZ];
- char *sp = buf;
- double val;
-
- /*
- * 2/2007: Simplify our lives here. Instead of worrying about
- * whether or not the value will fit into a long just so we
- * can use sprintf("%ld", val) on it, always format it ourselves.
- * The only thing to worry about is that integral values always
- * format as integers. %.0f does that very well.
- *
- * 6/2008: Would that things were so simple. Always using %.0f
- * imposes a notable performance penalty for applications that
- * do a lot of conversion of integers to strings. So, we reinstate
- * the old code, but use %.0f for integral values that are outside
- * the range of a long. This seems a reasonable compromise.
- *
- * 12/2009: Use <= and >= in the comparisons with LONG_xxx instead of
- * < and > so that things work correctly on systems with 64 bit integers.
- */
-
- /* not an integral value, or out of range */
- if ((val = double_to_int(s->numbr)) != s->numbr
- || val <= LONG_MIN || val >= LONG_MAX
- ) {
- /*
- * Once upon a time, we just blindly did this:
- * sprintf(sp, format, s->numbr);
- * s->stlen = strlen(sp);
- * s->stfmt = (char) index;
- * but that's no good if, e.g., OFMT is %s. So we punt,
- * and just always format the value ourselves.
- */
-
- NODE *dummy[2], *r;
- unsigned int oflags;
-
- /* create dummy node for a sole use of format_tree */
- dummy[1] = s;
- oflags = s->flags;
-
- if (val == s->numbr) {
- /* integral value, but outside range of %ld, use %.0f */
- r = format_tree("%.0f", 4, dummy, 2);
- s->stfmt = -1;
- } else {
- r = format_tree(format, fmt_list[index]->stlen, dummy, 2);
- assert(r != NULL);
- s->stfmt = (char) index;
- }
- s->flags = oflags;
- s->stlen = r->stlen;
- if ((s->flags & STRCUR) != 0)
- efree(s->stptr);
- s->stptr = r->stptr;
- freenode(r); /* Do not unref(r)! We want to keep s->stptr == r->stpr. */
-
- goto no_malloc;
- } else {
- /*
- * integral value; force conversion to long only once.
- */
- long num = (long) val;
-
- if (num < NVAL && num >= 0) {
- sp = (char *) values[num];
- s->stlen = 1;
- } else {
- (void) sprintf(sp, "%ld", num);
- s->stlen = strlen(sp);
- }
- s->stfmt = -1;
- if ((s->flags & INTIND) != 0) {
- s->flags &= ~(INTIND|NUMBER);
- s->flags |= STRING;
- }
- }
- if (s->stptr != NULL)
- efree(s->stptr);
- emalloc(s->stptr, char *, s->stlen + 2, "format_val");
- memcpy(s->stptr, sp, s->stlen + 1);
-no_malloc:
- s->flags |= STRCUR;
- free_wstr(s);
- return s;
-}
+int (*format_number_printf)(NODE *, struct format_spec *, struct print_fmt_buf *);
+NODE *(*str2node)(char *, char **, int, bool);
+NODE *(*make_number)(AWKNUM);
+NODE *(*str2number)(NODE *);
+NODE *(*format_val)(const char *, int, NODE *);
+int (*cmp_numbers)(const NODE *, const NODE *);
+void (*free_number)(NODE *);
+unsigned long (*get_number_ui)(const NODE *);
+long (*get_number_si)(const NODE *);
+AWKNUM (*get_number_d)(const NODE *);
+uintmax_t (*get_number_uj)(const NODE *);
+int (*sgn_number)(const NODE *);
/* r_dupnode --- duplicate a node */
@@ -309,53 +88,6 @@ r_dupnode(NODE *n)
return r;
}
-/* r_make_number --- allocate a node with defined number */
-
-static NODE *
-r_make_number(double x)
-{
- NODE *r;
- getnode(r);
- r->type = Node_val;
- r->numbr = x;
- r->flags = MALLOC|NUMBER|NUMCUR;
- r->valref = 1;
- r->stptr = NULL;
- r->stlen = 0;
-#if MBS_SUPPORT
- r->wstptr = NULL;
- r->wstlen = 0;
-#endif /* defined MBS_SUPPORT */
- return r;
-}
-
-/* cmp_awknums --- compare two AWKNUMs */
-
-int
-cmp_awknums(const NODE *t1, const NODE *t2)
-{
- /*
- * This routine is also used to sort numeric array indices or values.
- * For the purposes of sorting, NaN is considered greater than
- * any other value, and all NaN values are considered equivalent and equal.
- * This isn't in compliance with IEEE standard, but compliance w.r.t. NaN
- * comparison at the awk level is a different issue, and needs to be dealt
- * with in the interpreter for each opcode seperately.
- */
-
- if (isnan(t1->numbr))
- return ! isnan(t2->numbr);
- if (isnan(t2->numbr))
- return -1;
- /* don't subtract, in case one or both are infinite */
- if (t1->numbr == t2->numbr)
- return 0;
- if (t1->numbr < t2->numbr)
- return -1;
- return 1;
-}
-
-
/* make_str_node --- make a string node */
NODE *
@@ -456,7 +188,8 @@ r_unref(NODE *tmp)
efree(tmp->stptr);
#endif
- mpfr_unset(tmp);
+ if (free_number && (tmp->flags & (NUMBER|NUMCUR)) != 0)
+ free_number(tmp);
free_wstr(tmp);
freenode(tmp);
@@ -892,50 +625,6 @@ out: ;
}
#endif /* MBS_SUPPORT */
-/* is_ieee_magic_val --- return true for +inf, -inf, +nan, -nan */
-
-static int
-is_ieee_magic_val(const char *val)
-{
- /*
- * Avoid strncasecmp: it mishandles ASCII bytes in some locales.
- * Assume the length is 4, as the caller checks this.
- */
- return ( (val[0] == '+' || val[0] == '-')
- && ( ( (val[1] == 'i' || val[1] == 'I')
- && (val[2] == 'n' || val[2] == 'N')
- && (val[3] == 'f' || val[3] == 'F'))
- || ( (val[1] == 'n' || val[1] == 'N')
- && (val[2] == 'a' || val[2] == 'A')
- && (val[3] == 'n' || val[3] == 'N'))));
-}
-
-/* get_ieee_magic_val --- return magic value for string */
-
-static AWKNUM
-get_ieee_magic_val(const char *val)
-{
- static bool first = true;
- static AWKNUM inf;
- static AWKNUM nan;
-
- char *ptr;
- AWKNUM v = strtod(val, &ptr);
-
- if (val == ptr) { /* Older strtod implementations don't support inf or nan. */
- if (first) {
- first = false;
- nan = sqrt(-1.0);
- inf = -log(0.0);
- }
-
- v = ((val[1] == 'i' || val[1] == 'I') ? inf : nan);
- if (val[0] == '-')
- v = -v;
- }
-
- return v;
-}
#if MBS_SUPPORT
wint_t btowc_cache[256];
diff --git a/profile.c b/profile.c
index d07bea4a..6cb4c6a4 100644
--- a/profile.c
+++ b/profile.c
@@ -335,27 +335,6 @@ cleanup:
pc = pc->target_jmp;
break;
- case Op_plus_i:
- case Op_minus_i:
- case Op_times_i:
- case Op_exp_i:
- case Op_quotient_i:
- case Op_mod_i:
- m = pc->memory;
- t1 = pp_pop();
- if (prec_level(pc->opcode) > prec_level(t1->type)
- && is_binary(t1->type)) /* (a - b) * 1 */
- pp_parenthesize(t1);
- if ((m->flags & NUMBER) != 0)
- tmp = pp_number(m);
- else
- tmp = pp_string(m->stptr, m->stlen, '"');
- str = pp_group3(t1->pp_str, op2str(pc->opcode), tmp);
- efree(tmp);
- pp_free(t1);
- pp_push(pc->opcode, str, CAN_FREE);
- break;
-
case Op_plus:
case Op_minus:
case Op_times:
@@ -393,6 +372,7 @@ cleanup:
case Op_field_spec:
case Op_field_spec_lhs:
case Op_unary_minus:
+ case Op_unary_plus:
case Op_not:
t1 = pp_pop();
if (is_binary(t1->type))
@@ -1007,7 +987,6 @@ prec_level(int type)
return 14;
case Op_exp:
- case Op_exp_i:
return 13;
case Op_preincrement:
@@ -1017,21 +996,17 @@ prec_level(int type)
return 12;
case Op_unary_minus:
+ case Op_unary_plus:
case Op_not:
return 11;
case Op_times:
- case Op_times_i:
case Op_quotient:
- case Op_quotient_i:
case Op_mod:
- case Op_mod_i:
return 10;
case Op_plus:
- case Op_plus_i:
case Op_minus:
- case Op_minus_i:
return 9;
case Op_concat:
@@ -1127,12 +1102,6 @@ is_binary(int type)
case Op_mod:
case Op_plus:
case Op_minus:
- case Op_exp_i:
- case Op_times_i:
- case Op_quotient_i:
- case Op_mod_i:
- case Op_plus_i:
- case Op_minus_i:
case Op_concat:
case Op_assign_concat:
case Op_match:
@@ -1277,20 +1246,9 @@ pp_string(const char *in_str, size_t len, int delim)
char *
pp_number(NODE *n)
{
-#define PP_PRECISION 6
- char *str;
-
- emalloc(str, char *, PP_PRECISION + 10, "pp_number");
-#ifdef HAVE_MPFR
- if (is_mpg_float(n))
- mpfr_sprintf(str, "%0.*R*g", PP_PRECISION, ROUND_MODE, n->mpg_numbr);
- else if (is_mpg_integer(n))
- mpfr_sprintf(str, "%Zd", n->mpg_i);
- else
-#endif
- sprintf(str, "%0.*g", PP_PRECISION, n->numbr);
- return str;
-#undef PP_PRECISION
+ const char *str;
+ str = fmt_number("%0.6g", n);
+ return estrdup(str, strlen(str));
}
/* pp_node --- pretty format a node */