[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[gawk-diffs] [SCM] gawk branch, num-handler, created. bb146e0626acb7e302
From: |
John Haque |
Subject: |
[gawk-diffs] [SCM] gawk branch, num-handler, created. bb146e0626acb7e3020f037303fdc8890cb84b46 |
Date: |
Thu, 27 Dec 2012 04:13:04 +0000 |
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "gawk".
The branch, num-handler has been created
at bb146e0626acb7e3020f037303fdc8890cb84b46 (commit)
- Log -----------------------------------------------------------------
http://git.sv.gnu.org/cgit/gawk.git/commit/?id=bb146e0626acb7e3020f037303fdc8890cb84b46
commit bb146e0626acb7e3020f037303fdc8890cb84b46
Author: John Haque <address@hidden>
Date: Wed Dec 26 22:06:08 2012 -0600
Number handler.
diff --git a/ChangeLog b/ChangeLog
index cb0e2d9..b8381a9 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2012-12-27 John Haque <address@hidden>
+
+ 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-19 Arnold D. Robbins <address@hidden>
* bootstrap.sh: Touch extension/aclocal.m4 also.
diff --git a/Makefile.am b/Makefile.am
index 085eadf..7a1b530 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -93,6 +93,7 @@ base_sources = \
debug.c \
dfa.c \
dfa.h \
+ double.c \
eval.c \
ext.c \
field.c \
diff --git a/Makefile.in b/Makefile.in
index 2c7e948..71df2f0 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -105,13 +105,14 @@ 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) \
- regex.$(OBJEXT) replace.$(OBJEXT) str_array.$(OBJEXT) \
- symbol.$(OBJEXT) version.$(OBJEXT)
+ dfa.$(OBJEXT) double.$(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) regex.$(OBJEXT) \
+ replace.$(OBJEXT) str_array.$(OBJEXT) symbol.$(OBJEXT) \
+ version.$(OBJEXT)
am_gawk_OBJECTS = $(am__objects_1)
gawk_OBJECTS = $(am_gawk_OBJECTS)
gawk_LDADD = $(LDADD)
@@ -421,6 +422,7 @@ base_sources = \
debug.c \
dfa.c \
dfa.h \
+ double.c \
eval.c \
ext.c \
field.c \
@@ -584,6 +586,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
@AMDEP_TRUE@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
@AMDEP_TRUE@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
address@hidden@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
@AMDEP_TRUE@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
@AMDEP_TRUE@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
@AMDEP_TRUE@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
diff --git a/TODO.NUMH b/TODO.NUMH
new file mode 100644
index 0000000..c612bd5
--- /dev/null
+++ b/TODO.NUMH
@@ -0,0 +1 @@
+* put back constant-folding code for numbers
diff --git a/array.c b/array.c
index 1953bfe..c5090d9 100644
--- a/array.c
+++ b/array.c
@@ -79,7 +79,7 @@ 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);
}
@@ -652,10 +652,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;
@@ -663,30 +659,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));
@@ -701,9 +679,6 @@ value_info(NODE *n)
fprintf(output_fp, "CONVFMT=\"%s\"", n->stfmt <= -1 ? "%ld"
: fmt_list[n->stfmt]->stptr);
}
-
-#undef PREC_NUM
-#undef PREC_STR
}
@@ -1215,22 +1190,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 0f9b2ec..89f2682 100644
--- a/awk.h
+++ b/awk.h
@@ -210,18 +210,6 @@ typedef void *stackoverflow_context_t;
this is a hack but it gives us the right semantics */
#define lintwarn (*(set_loc(__FILE__, __LINE__),lintfunc))
-#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 {
@@ -244,6 +232,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. */
@@ -386,17 +381,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;
@@ -404,7 +388,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;
@@ -469,13 +460,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
@@ -553,18 +537,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 */
@@ -579,6 +564,7 @@ typedef enum opcodeval {
Op_predecrement,
Op_postincrement,
Op_postdecrement,
+ Op_unary_plus,
Op_unary_minus,
Op_field_spec,
@@ -590,12 +576,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 */
@@ -882,6 +862,63 @@ 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;
+
+
+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_is_integer)(const NODE *); /* test if a number is an
integer */
+
+ NODE *(*gawk_fmt_number)(const char *, int, NODE *); /* stringify a
numeric value
+ based on awk
input/output format */
+ NODE *(*gawk_format_nodes)(const char *, size_t, NODE **, long); /*
format NODES according to
+
user-specified FORMAT */
+
+ /* conversion to C types */
+ AWKNUM (*gawk_todouble)(const NODE *); /* number to AWKNUM */
+ 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;
+
+
typedef struct iobuf {
awk_input_buf_t public; /* exposed to extensions */
char *buf; /* start data buffer */
@@ -1046,14 +1083,28 @@ 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 NODE *(*format_tree)(const char *, size_t, NODE **, long);
/* built-in array types */
extern afunc_t str_array_func[];
@@ -1080,7 +1131,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)
@@ -1094,7 +1144,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;
@@ -1122,15 +1171,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[];
@@ -1193,43 +1233,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_is_integer(n)
#define var_uninitialized(n) ((n)->var_value == Nnull_string)
@@ -1355,6 +1360,7 @@ extern NODE *do_aoption(int nargs);
extern NODE *do_asort(int nargs);
extern NODE *do_asorti(int nargs);
extern unsigned long (*hash)(const char *s, size_t len, unsigned long hsize,
size_t *code);
+
/* awkgram.c */
extern NODE *variable(int location, char *name, NODETYPE type);
extern int parse_program(INSTRUCTION **pcode);
@@ -1369,21 +1375,15 @@ extern SRCFILE *add_srcfile(int stype, char *src,
SRCFILE *curr, bool *already_i
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);
+
/* 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);
@@ -1392,22 +1392,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);
@@ -1415,12 +1401,12 @@ extern NODE *do_bindtextdomain(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);
@@ -1440,13 +1426,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 */
@@ -1460,11 +1446,14 @@ 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 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);
@@ -1512,7 +1501,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);
@@ -1525,6 +1513,7 @@ extern NODE *do_getline(int intovar, IOBUF *iop);
extern struct redirect *getredirect(const char *str, int len);
extern int 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);
@@ -1533,40 +1522,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_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_rhift(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 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 warning (const char *mesg, ...) ATTRIBUTE_PRINTF_1;
@@ -1577,6 +1537,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);
@@ -1587,6 +1548,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);
@@ -1594,6 +1556,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);
@@ -1611,6 +1574,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);
@@ -1621,7 +1585,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();
@@ -1767,7 +1730,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 9fd1156..22269b5 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);
@@ -198,7 +197,7 @@ extern double fmod(double x, double y);
#define is_identchar(c) (isalnum(c) || (c) == '_')
/* Line 371 of yacc.c */
-#line 202 "awkgram.c"
+#line 201 "awkgram.c"
# ifndef YY_NULL
# if defined __cplusplus && 201103L <= __cplusplus
@@ -367,7 +366,7 @@ int yyparse ();
/* Copy the second part of user declarations. */
/* Line 390 of yacc.c */
-#line 371 "awkgram.c"
+#line 370 "awkgram.c"
#ifdef short
# undef short
@@ -731,25 +730,25 @@ static const yytype_int16 yyrhs[] =
/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
static const yytype_uint16 yyrline[] =
{
- 0, 199, 199, 201, 206, 207, 213, 225, 229, 240,
- 246, 251, 259, 267, 269, 274, 282, 284, 290, 291,
- 293, 319, 330, 341, 347, 356, 366, 368, 370, 376,
- 381, 382, 386, 405, 404, 438, 440, 445, 446, 459,
- 464, 465, 469, 471, 473, 480, 570, 612, 654, 767,
- 774, 781, 791, 800, 809, 818, 829, 845, 844, 868,
- 880, 880, 978, 978, 1011, 1041, 1047, 1048, 1054, 1055,
- 1062, 1067, 1079, 1093, 1095, 1103, 1108, 1110, 1118, 1120,
- 1129, 1130, 1138, 1143, 1143, 1154, 1158, 1166, 1167, 1170,
- 1172, 1177, 1178, 1187, 1188, 1193, 1198, 1204, 1206, 1208,
- 1215, 1216, 1222, 1223, 1228, 1230, 1235, 1237, 1239, 1241,
- 1247, 1254, 1256, 1258, 1274, 1284, 1291, 1293, 1298, 1300,
- 1302, 1310, 1312, 1317, 1319, 1324, 1326, 1328, 1378, 1380,
- 1382, 1384, 1386, 1388, 1390, 1392, 1415, 1420, 1425, 1450,
- 1456, 1458, 1460, 1462, 1464, 1466, 1471, 1475, 1507, 1509,
- 1515, 1521, 1534, 1535, 1536, 1541, 1546, 1550, 1554, 1569,
- 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
+ 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, 1238, 1240,
+ 1246, 1253, 1255, 1257, 1273, 1283, 1290, 1292, 1297, 1299,
+ 1301, 1309, 1311, 1316, 1318, 1323, 1325, 1327, 1377, 1379,
+ 1381, 1383, 1385, 1387, 1389, 1391, 1414, 1419, 1424, 1449,
+ 1455, 1457, 1459, 1461, 1463, 1465, 1470, 1474, 1506, 1508,
+ 1514, 1520, 1533, 1534, 1535, 1540, 1545, 1549, 1553, 1568,
+ 1580, 1585, 1621, 1639, 1640, 1646, 1647, 1652, 1654, 1661,
+ 1678, 1695, 1697, 1704, 1709, 1717, 1727, 1739, 1748, 1752,
+ 1756, 1760, 1764, 1768, 1771, 1773, 1777, 1781, 1785
};
#endif
@@ -2036,7 +2035,7 @@ yyreduce:
{
case 3:
/* Line 1792 of yacc.c */
-#line 202 "awkgram.y"
+#line 201 "awkgram.y"
{
rule = 0;
yyerrok;
@@ -2045,7 +2044,7 @@ yyreduce:
case 5:
/* Line 1792 of yacc.c */
-#line 208 "awkgram.y"
+#line 207 "awkgram.y"
{
next_sourcefile();
if (sourcefile == srcfiles)
@@ -2055,7 +2054,7 @@ yyreduce:
case 6:
/* Line 1792 of yacc.c */
-#line 214 "awkgram.y"
+#line 213 "awkgram.y"
{
rule = 0;
/*
@@ -2068,7 +2067,7 @@ yyreduce:
case 7:
/* Line 1792 of yacc.c */
-#line 226 "awkgram.y"
+#line 225 "awkgram.y"
{
(void) append_rule((yyvsp[(1) - (2)]), (yyvsp[(2) - (2)]));
}
@@ -2076,7 +2075,7 @@ yyreduce:
case 8:
/* Line 1792 of yacc.c */
-#line 230 "awkgram.y"
+#line 229 "awkgram.y"
{
if (rule != Rule) {
msg(_("%s blocks must have an action part"),
ruletab[rule]);
@@ -2091,7 +2090,7 @@ yyreduce:
case 9:
/* Line 1792 of yacc.c */
-#line 241 "awkgram.y"
+#line 240 "awkgram.y"
{
in_function = NULL;
(void) mk_function((yyvsp[(1) - (2)]), (yyvsp[(2) - (2)]));
@@ -2101,7 +2100,7 @@ yyreduce:
case 10:
/* Line 1792 of yacc.c */
-#line 247 "awkgram.y"
+#line 246 "awkgram.y"
{
want_source = false;
yyerrok;
@@ -2110,7 +2109,7 @@ yyreduce:
case 11:
/* Line 1792 of yacc.c */
-#line 252 "awkgram.y"
+#line 251 "awkgram.y"
{
want_source = false;
yyerrok;
@@ -2119,7 +2118,7 @@ yyreduce:
case 12:
/* Line 1792 of yacc.c */
-#line 260 "awkgram.y"
+#line 259 "awkgram.y"
{
if (include_source((yyvsp[(1) - (1)])) < 0)
YYABORT;
@@ -2131,19 +2130,19 @@ yyreduce:
case 13:
/* Line 1792 of yacc.c */
-#line 268 "awkgram.y"
+#line 267 "awkgram.y"
{ (yyval) = NULL; }
break;
case 14:
/* Line 1792 of yacc.c */
-#line 270 "awkgram.y"
+#line 269 "awkgram.y"
{ (yyval) = NULL; }
break;
case 15:
/* Line 1792 of yacc.c */
-#line 275 "awkgram.y"
+#line 274 "awkgram.y"
{
if (load_library((yyvsp[(1) - (1)])) < 0)
YYABORT;
@@ -2155,31 +2154,31 @@ yyreduce:
case 16:
/* Line 1792 of yacc.c */
-#line 283 "awkgram.y"
+#line 282 "awkgram.y"
{ (yyval) = NULL; }
break;
case 17:
/* Line 1792 of yacc.c */
-#line 285 "awkgram.y"
+#line 284 "awkgram.y"
{ (yyval) = NULL; }
break;
case 18:
/* Line 1792 of yacc.c */
-#line 290 "awkgram.y"
+#line 289 "awkgram.y"
{ (yyval) = NULL; rule = Rule; }
break;
case 19:
/* Line 1792 of yacc.c */
-#line 292 "awkgram.y"
+#line 291 "awkgram.y"
{ (yyval) = (yyvsp[(1) - (1)]); rule = Rule; }
break;
case 20:
/* Line 1792 of yacc.c */
-#line 294 "awkgram.y"
+#line 293 "awkgram.y"
{
INSTRUCTION *tp;
@@ -2209,7 +2208,7 @@ yyreduce:
case 21:
/* Line 1792 of yacc.c */
-#line 320 "awkgram.y"
+#line 319 "awkgram.y"
{
static int begin_seen = 0;
if (do_lint_old && ++begin_seen == 2)
@@ -2224,7 +2223,7 @@ yyreduce:
case 22:
/* Line 1792 of yacc.c */
-#line 331 "awkgram.y"
+#line 330 "awkgram.y"
{
static int end_seen = 0;
if (do_lint_old && ++end_seen == 2)
@@ -2239,7 +2238,7 @@ yyreduce:
case 23:
/* Line 1792 of yacc.c */
-#line 342 "awkgram.y"
+#line 341 "awkgram.y"
{
(yyvsp[(1) - (1)])->in_rule = rule = BEGINFILE;
(yyvsp[(1) - (1)])->source_file = source;
@@ -2249,7 +2248,7 @@ yyreduce:
case 24:
/* Line 1792 of yacc.c */
-#line 348 "awkgram.y"
+#line 347 "awkgram.y"
{
(yyvsp[(1) - (1)])->in_rule = rule = ENDFILE;
(yyvsp[(1) - (1)])->source_file = source;
@@ -2259,7 +2258,7 @@ yyreduce:
case 25:
/* Line 1792 of yacc.c */
-#line 357 "awkgram.y"
+#line 356 "awkgram.y"
{
if ((yyvsp[(2) - (5)]) == NULL)
(yyval) = list_create(instruction(Op_no_op));
@@ -2270,19 +2269,19 @@ yyreduce:
case 26:
/* Line 1792 of yacc.c */
-#line 367 "awkgram.y"
+#line 366 "awkgram.y"
{ (yyval) = (yyvsp[(1) - (1)]); }
break;
case 27:
/* Line 1792 of yacc.c */
-#line 369 "awkgram.y"
+#line 368 "awkgram.y"
{ (yyval) = (yyvsp[(1) - (1)]); }
break;
case 28:
/* Line 1792 of yacc.c */
-#line 371 "awkgram.y"
+#line 370 "awkgram.y"
{
yyerror(_("`%s' is a built-in function, it cannot be
redefined"),
tokstart);
@@ -2292,13 +2291,13 @@ yyreduce:
case 29:
/* Line 1792 of yacc.c */
-#line 377 "awkgram.y"
+#line 376 "awkgram.y"
{ (yyval) = (yyvsp[(2) - (2)]); }
break;
case 32:
/* Line 1792 of yacc.c */
-#line 387 "awkgram.y"
+#line 386 "awkgram.y"
{
(yyvsp[(1) - (6)])->source_file = source;
if (install_function((yyvsp[(2) - (6)])->lextok, (yyvsp[(1) -
(6)]), (yyvsp[(4) - (6)])) < 0)
@@ -2313,13 +2312,13 @@ yyreduce:
case 33:
/* Line 1792 of yacc.c */
-#line 405 "awkgram.y"
+#line 404 "awkgram.y"
{ want_regexp = true; }
break;
case 34:
/* Line 1792 of yacc.c */
-#line 407 "awkgram.y"
+#line 406 "awkgram.y"
{
NODE *n, *exp;
char *re;
@@ -2352,19 +2351,19 @@ yyreduce:
case 35:
/* Line 1792 of yacc.c */
-#line 439 "awkgram.y"
+#line 438 "awkgram.y"
{ bcfree((yyvsp[(1) - (1)])); }
break;
case 37:
/* Line 1792 of yacc.c */
-#line 445 "awkgram.y"
+#line 444 "awkgram.y"
{ (yyval) = NULL; }
break;
case 38:
/* Line 1792 of yacc.c */
-#line 447 "awkgram.y"
+#line 446 "awkgram.y"
{
if ((yyvsp[(2) - (2)]) == NULL)
(yyval) = (yyvsp[(1) - (2)]);
@@ -2381,25 +2380,25 @@ yyreduce:
case 39:
/* Line 1792 of yacc.c */
-#line 460 "awkgram.y"
+#line 459 "awkgram.y"
{ (yyval) = NULL; }
break;
case 42:
/* Line 1792 of yacc.c */
-#line 470 "awkgram.y"
+#line 469 "awkgram.y"
{ (yyval) = NULL; }
break;
case 43:
/* Line 1792 of yacc.c */
-#line 472 "awkgram.y"
+#line 471 "awkgram.y"
{ (yyval) = (yyvsp[(2) - (3)]); }
break;
case 44:
/* Line 1792 of yacc.c */
-#line 474 "awkgram.y"
+#line 473 "awkgram.y"
{
if (do_pretty_print)
(yyval) = list_prepend((yyvsp[(1) - (1)]),
instruction(Op_exec_count));
@@ -2410,7 +2409,7 @@ yyreduce:
case 45:
/* Line 1792 of yacc.c */
-#line 481 "awkgram.y"
+#line 480 "awkgram.y"
{
INSTRUCTION *dflt, *curr = NULL, *cexp, *cstmt;
INSTRUCTION *ip, *nextc, *tbreak;
@@ -2504,7 +2503,7 @@ yyreduce:
case 46:
/* Line 1792 of yacc.c */
-#line 571 "awkgram.y"
+#line 570 "awkgram.y"
{
/*
* -----------------
@@ -2550,7 +2549,7 @@ yyreduce:
case 47:
/* Line 1792 of yacc.c */
-#line 613 "awkgram.y"
+#line 612 "awkgram.y"
{
/*
* -----------------
@@ -2596,7 +2595,7 @@ yyreduce:
case 48:
/* Line 1792 of yacc.c */
-#line 655 "awkgram.y"
+#line 654 "awkgram.y"
{
INSTRUCTION *ip;
char *var_name = (yyvsp[(3) - (8)])->lextok;
@@ -2713,7 +2712,7 @@ regular_loop:
case 49:
/* Line 1792 of yacc.c */
-#line 768 "awkgram.y"
+#line 767 "awkgram.y"
{
(yyval) = mk_for_loop((yyvsp[(1) - (12)]), (yyvsp[(3) - (12)]),
(yyvsp[(6) - (12)]), (yyvsp[(9) - (12)]), (yyvsp[(12) - (12)]));
@@ -2724,7 +2723,7 @@ regular_loop:
case 50:
/* Line 1792 of yacc.c */
-#line 775 "awkgram.y"
+#line 774 "awkgram.y"
{
(yyval) = mk_for_loop((yyvsp[(1) - (11)]), (yyvsp[(3) - (11)]),
(INSTRUCTION *) NULL, (yyvsp[(8) - (11)]), (yyvsp[(11) - (11)]));
@@ -2735,7 +2734,7 @@ regular_loop:
case 51:
/* Line 1792 of yacc.c */
-#line 782 "awkgram.y"
+#line 781 "awkgram.y"
{
if (do_pretty_print)
(yyval) = list_prepend((yyvsp[(1) - (1)]),
instruction(Op_exec_count));
@@ -2746,7 +2745,7 @@ regular_loop:
case 52:
/* Line 1792 of yacc.c */
-#line 792 "awkgram.y"
+#line 791 "awkgram.y"
{
if (! break_allowed)
error_ln((yyvsp[(1) - (2)])->source_line,
@@ -2759,7 +2758,7 @@ regular_loop:
case 53:
/* Line 1792 of yacc.c */
-#line 801 "awkgram.y"
+#line 800 "awkgram.y"
{
if (! continue_allowed)
error_ln((yyvsp[(1) - (2)])->source_line,
@@ -2772,7 +2771,7 @@ regular_loop:
case 54:
/* Line 1792 of yacc.c */
-#line 810 "awkgram.y"
+#line 809 "awkgram.y"
{
/* if inside function (rule = 0), resolve context at run-time */
if (rule && rule != Rule)
@@ -2785,7 +2784,7 @@ regular_loop:
case 55:
/* Line 1792 of yacc.c */
-#line 819 "awkgram.y"
+#line 818 "awkgram.y"
{
/* if inside function (rule = 0), resolve context at run-time */
if (rule == BEGIN || rule == END || rule == ENDFILE)
@@ -2800,7 +2799,7 @@ regular_loop:
case 56:
/* Line 1792 of yacc.c */
-#line 830 "awkgram.y"
+#line 829 "awkgram.y"
{
/* Initialize the two possible jump targets, the actual target
* is resolved at run-time.
@@ -2819,7 +2818,7 @@ regular_loop:
case 57:
/* Line 1792 of yacc.c */
-#line 845 "awkgram.y"
+#line 844 "awkgram.y"
{
if (! in_function)
yyerror(_("`return' used outside function context"));
@@ -2828,7 +2827,7 @@ regular_loop:
case 58:
/* Line 1792 of yacc.c */
-#line 848 "awkgram.y"
+#line 847 "awkgram.y"
{
if ((yyvsp[(3) - (4)]) == NULL) {
(yyval) = list_create((yyvsp[(1) - (4)]));
@@ -2853,13 +2852,13 @@ regular_loop:
case 60:
/* Line 1792 of yacc.c */
-#line 880 "awkgram.y"
+#line 879 "awkgram.y"
{ in_print = true; in_parens = 0; }
break;
case 61:
/* Line 1792 of yacc.c */
-#line 881 "awkgram.y"
+#line 880 "awkgram.y"
{
/*
* Optimization: plain `print' has no expression list, so $3 is
null.
@@ -2960,13 +2959,13 @@ regular_print:
case 62:
/* Line 1792 of yacc.c */
-#line 978 "awkgram.y"
+#line 977 "awkgram.y"
{ sub_counter = 0; }
break;
case 63:
/* Line 1792 of yacc.c */
-#line 979 "awkgram.y"
+#line 978 "awkgram.y"
{
char *arr = (yyvsp[(2) - (4)])->lextok;
@@ -3003,7 +3002,7 @@ regular_print:
case 64:
/* Line 1792 of yacc.c */
-#line 1016 "awkgram.y"
+#line 1015 "awkgram.y"
{
static bool warned = false;
char *arr = (yyvsp[(3) - (4)])->lextok;
@@ -3033,31 +3032,31 @@ regular_print:
case 65:
/* Line 1792 of yacc.c */
-#line 1042 "awkgram.y"
+#line 1041 "awkgram.y"
{ (yyval) = optimize_assignment((yyvsp[(1) - (1)])); }
break;
case 66:
/* Line 1792 of yacc.c */
-#line 1047 "awkgram.y"
+#line 1046 "awkgram.y"
{ (yyval) = NULL; }
break;
case 67:
/* Line 1792 of yacc.c */
-#line 1049 "awkgram.y"
+#line 1048 "awkgram.y"
{ (yyval) = (yyvsp[(1) - (1)]); }
break;
case 68:
/* Line 1792 of yacc.c */
-#line 1054 "awkgram.y"
+#line 1053 "awkgram.y"
{ (yyval) = NULL; }
break;
case 69:
/* Line 1792 of yacc.c */
-#line 1056 "awkgram.y"
+#line 1055 "awkgram.y"
{
if ((yyvsp[(1) - (2)]) == NULL)
(yyval) = list_create((yyvsp[(2) - (2)]));
@@ -3068,13 +3067,13 @@ regular_print:
case 70:
/* Line 1792 of yacc.c */
-#line 1063 "awkgram.y"
+#line 1062 "awkgram.y"
{ (yyval) = NULL; }
break;
case 71:
/* Line 1792 of yacc.c */
-#line 1068 "awkgram.y"
+#line 1067 "awkgram.y"
{
INSTRUCTION *casestmt = (yyvsp[(5) - (5)]);
if ((yyvsp[(5) - (5)]) == NULL)
@@ -3090,7 +3089,7 @@ regular_print:
case 72:
/* Line 1792 of yacc.c */
-#line 1080 "awkgram.y"
+#line 1079 "awkgram.y"
{
INSTRUCTION *casestmt = (yyvsp[(4) - (4)]);
if ((yyvsp[(4) - (4)]) == NULL)
@@ -3105,17 +3104,17 @@ regular_print:
case 73:
/* Line 1792 of yacc.c */
-#line 1094 "awkgram.y"
+#line 1093 "awkgram.y"
{ (yyval) = (yyvsp[(1) - (1)]); }
break;
case 74:
/* Line 1792 of yacc.c */
-#line 1096 "awkgram.y"
+#line 1095 "awkgram.y"
{
NODE *n = (yyvsp[(2) - (2)])->memory;
(void) force_number(n);
- negate_num(n);
+ numbr_hndlr->gawk_negate_number(n);
bcfree((yyvsp[(1) - (2)]));
(yyval) = (yyvsp[(2) - (2)]);
}
@@ -3123,7 +3122,7 @@ regular_print:
case 75:
/* Line 1792 of yacc.c */
-#line 1104 "awkgram.y"
+#line 1103 "awkgram.y"
{
bcfree((yyvsp[(1) - (2)]));
(yyval) = (yyvsp[(2) - (2)]);
@@ -3132,13 +3131,13 @@ regular_print:
case 76:
/* Line 1792 of yacc.c */
-#line 1109 "awkgram.y"
+#line 1108 "awkgram.y"
{ (yyval) = (yyvsp[(1) - (1)]); }
break;
case 77:
/* Line 1792 of yacc.c */
-#line 1111 "awkgram.y"
+#line 1110 "awkgram.y"
{
(yyvsp[(1) - (1)])->opcode = Op_push_re;
(yyval) = (yyvsp[(1) - (1)]);
@@ -3147,19 +3146,19 @@ regular_print:
case 78:
/* Line 1792 of yacc.c */
-#line 1119 "awkgram.y"
+#line 1118 "awkgram.y"
{ (yyval) = (yyvsp[(1) - (1)]); }
break;
case 79:
/* Line 1792 of yacc.c */
-#line 1121 "awkgram.y"
+#line 1120 "awkgram.y"
{ (yyval) = (yyvsp[(1) - (1)]); }
break;
case 81:
/* Line 1792 of yacc.c */
-#line 1131 "awkgram.y"
+#line 1130 "awkgram.y"
{
(yyval) = (yyvsp[(2) - (3)]);
}
@@ -3167,7 +3166,7 @@ regular_print:
case 82:
/* Line 1792 of yacc.c */
-#line 1138 "awkgram.y"
+#line 1137 "awkgram.y"
{
in_print = false;
in_parens = 0;
@@ -3177,13 +3176,13 @@ regular_print:
case 83:
/* Line 1792 of yacc.c */
-#line 1143 "awkgram.y"
+#line 1142 "awkgram.y"
{ in_print = false; in_parens = 0; }
break;
case 84:
/* Line 1792 of yacc.c */
-#line 1144 "awkgram.y"
+#line 1143 "awkgram.y"
{
if ((yyvsp[(1) - (3)])->redir_type == redirect_twoway
&& (yyvsp[(3) - (3)])->lasti->opcode ==
Op_K_getline_redir
@@ -3195,7 +3194,7 @@ regular_print:
case 85:
/* Line 1792 of yacc.c */
-#line 1155 "awkgram.y"
+#line 1154 "awkgram.y"
{
(yyval) = mk_condition((yyvsp[(3) - (6)]), (yyvsp[(1) - (6)]),
(yyvsp[(6) - (6)]), NULL, NULL);
}
@@ -3203,7 +3202,7 @@ regular_print:
case 86:
/* Line 1792 of yacc.c */
-#line 1160 "awkgram.y"
+#line 1159 "awkgram.y"
{
(yyval) = mk_condition((yyvsp[(3) - (9)]), (yyvsp[(1) - (9)]),
(yyvsp[(6) - (9)]), (yyvsp[(7) - (9)]), (yyvsp[(9) - (9)]));
}
@@ -3211,13 +3210,13 @@ regular_print:
case 91:
/* Line 1792 of yacc.c */
-#line 1177 "awkgram.y"
+#line 1176 "awkgram.y"
{ (yyval) = NULL; }
break;
case 92:
/* Line 1792 of yacc.c */
-#line 1179 "awkgram.y"
+#line 1178 "awkgram.y"
{
bcfree((yyvsp[(1) - (2)]));
(yyval) = (yyvsp[(2) - (2)]);
@@ -3226,19 +3225,19 @@ regular_print:
case 93:
/* Line 1792 of yacc.c */
-#line 1187 "awkgram.y"
+#line 1186 "awkgram.y"
{ (yyval) = NULL; }
break;
case 94:
/* Line 1792 of yacc.c */
-#line 1189 "awkgram.y"
+#line 1188 "awkgram.y"
{ (yyval) = (yyvsp[(1) - (1)]) ; }
break;
case 95:
/* Line 1792 of yacc.c */
-#line 1194 "awkgram.y"
+#line 1193 "awkgram.y"
{
(yyvsp[(1) - (1)])->param_count = 0;
(yyval) = list_create((yyvsp[(1) - (1)]));
@@ -3247,7 +3246,7 @@ regular_print:
case 96:
/* Line 1792 of yacc.c */
-#line 1199 "awkgram.y"
+#line 1198 "awkgram.y"
{
(yyvsp[(3) - (3)])->param_count = (yyvsp[(1) -
(3)])->lasti->param_count + 1;
(yyval) = list_append((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]));
@@ -3257,55 +3256,55 @@ regular_print:
case 97:
/* Line 1792 of yacc.c */
-#line 1205 "awkgram.y"
+#line 1204 "awkgram.y"
{ (yyval) = NULL; }
break;
case 98:
/* Line 1792 of yacc.c */
-#line 1207 "awkgram.y"
+#line 1206 "awkgram.y"
{ (yyval) = (yyvsp[(1) - (2)]); }
break;
case 99:
/* Line 1792 of yacc.c */
-#line 1209 "awkgram.y"
+#line 1208 "awkgram.y"
{ (yyval) = (yyvsp[(1) - (3)]); }
break;
case 100:
/* Line 1792 of yacc.c */
-#line 1215 "awkgram.y"
+#line 1214 "awkgram.y"
{ (yyval) = NULL; }
break;
case 101:
/* Line 1792 of yacc.c */
-#line 1217 "awkgram.y"
+#line 1216 "awkgram.y"
{ (yyval) = (yyvsp[(1) - (1)]); }
break;
case 102:
/* Line 1792 of yacc.c */
-#line 1222 "awkgram.y"
+#line 1221 "awkgram.y"
{ (yyval) = NULL; }
break;
case 103:
/* Line 1792 of yacc.c */
-#line 1224 "awkgram.y"
+#line 1223 "awkgram.y"
{ (yyval) = (yyvsp[(1) - (1)]); }
break;
case 104:
/* Line 1792 of yacc.c */
-#line 1229 "awkgram.y"
+#line 1228 "awkgram.y"
{ (yyval) = mk_expression_list(NULL, (yyvsp[(1) - (1)])); }
break;
case 105:
/* Line 1792 of yacc.c */
-#line 1231 "awkgram.y"
+#line 1230 "awkgram.y"
{
(yyval) = mk_expression_list((yyvsp[(1) - (3)]), (yyvsp[(3) -
(3)]));
yyerrok;
@@ -3314,31 +3313,31 @@ regular_print:
case 106:
/* Line 1792 of yacc.c */
-#line 1236 "awkgram.y"
+#line 1235 "awkgram.y"
{ (yyval) = NULL; }
break;
case 107:
/* Line 1792 of yacc.c */
-#line 1238 "awkgram.y"
+#line 1237 "awkgram.y"
{ (yyval) = NULL; }
break;
case 108:
/* Line 1792 of yacc.c */
-#line 1240 "awkgram.y"
+#line 1239 "awkgram.y"
{ (yyval) = NULL; }
break;
case 109:
/* Line 1792 of yacc.c */
-#line 1242 "awkgram.y"
+#line 1241 "awkgram.y"
{ (yyval) = NULL; }
break;
case 110:
/* Line 1792 of yacc.c */
-#line 1248 "awkgram.y"
+#line 1247 "awkgram.y"
{
if (do_lint && (yyvsp[(3) - (3)])->lasti->opcode ==
Op_match_rec)
lintwarn_ln((yyvsp[(2) - (3)])->source_line,
@@ -3349,19 +3348,19 @@ regular_print:
case 111:
/* Line 1792 of yacc.c */
-#line 1255 "awkgram.y"
+#line 1254 "awkgram.y"
{ (yyval) = mk_boolean((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2)
- (3)])); }
break;
case 112:
/* Line 1792 of yacc.c */
-#line 1257 "awkgram.y"
+#line 1256 "awkgram.y"
{ (yyval) = mk_boolean((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2)
- (3)])); }
break;
case 113:
/* Line 1792 of yacc.c */
-#line 1259 "awkgram.y"
+#line 1258 "awkgram.y"
{
if ((yyvsp[(1) - (3)])->lasti->opcode == Op_match_rec)
warning_ln((yyvsp[(2) - (3)])->source_line,
@@ -3381,7 +3380,7 @@ regular_print:
case 114:
/* Line 1792 of yacc.c */
-#line 1275 "awkgram.y"
+#line 1274 "awkgram.y"
{
if (do_lint_old)
warning_ln((yyvsp[(2) - (3)])->source_line,
@@ -3395,7 +3394,7 @@ regular_print:
case 115:
/* Line 1792 of yacc.c */
-#line 1285 "awkgram.y"
+#line 1284 "awkgram.y"
{
if (do_lint && (yyvsp[(3) - (3)])->lasti->opcode ==
Op_match_rec)
lintwarn_ln((yyvsp[(2) - (3)])->source_line,
@@ -3406,31 +3405,31 @@ regular_print:
case 116:
/* Line 1792 of yacc.c */
-#line 1292 "awkgram.y"
+#line 1291 "awkgram.y"
{ (yyval) = mk_condition((yyvsp[(1) - (5)]), (yyvsp[(2) - (5)]),
(yyvsp[(3) - (5)]), (yyvsp[(4) - (5)]), (yyvsp[(5) - (5)])); }
break;
case 117:
/* Line 1792 of yacc.c */
-#line 1294 "awkgram.y"
+#line 1293 "awkgram.y"
{ (yyval) = (yyvsp[(1) - (1)]); }
break;
case 118:
/* Line 1792 of yacc.c */
-#line 1299 "awkgram.y"
+#line 1298 "awkgram.y"
{ (yyval) = (yyvsp[(1) - (1)]); }
break;
case 119:
/* Line 1792 of yacc.c */
-#line 1301 "awkgram.y"
+#line 1300 "awkgram.y"
{ (yyval) = (yyvsp[(1) - (1)]); }
break;
case 120:
/* Line 1792 of yacc.c */
-#line 1303 "awkgram.y"
+#line 1302 "awkgram.y"
{
(yyvsp[(2) - (2)])->opcode = Op_assign_quotient;
(yyval) = (yyvsp[(2) - (2)]);
@@ -3439,43 +3438,43 @@ regular_print:
case 121:
/* Line 1792 of yacc.c */
-#line 1311 "awkgram.y"
+#line 1310 "awkgram.y"
{ (yyval) = (yyvsp[(1) - (1)]); }
break;
case 122:
/* Line 1792 of yacc.c */
-#line 1313 "awkgram.y"
+#line 1312 "awkgram.y"
{ (yyval) = (yyvsp[(1) - (1)]); }
break;
case 123:
/* Line 1792 of yacc.c */
-#line 1318 "awkgram.y"
+#line 1317 "awkgram.y"
{ (yyval) = (yyvsp[(1) - (1)]); }
break;
case 124:
/* Line 1792 of yacc.c */
-#line 1320 "awkgram.y"
+#line 1319 "awkgram.y"
{ (yyval) = (yyvsp[(1) - (1)]); }
break;
case 125:
/* Line 1792 of yacc.c */
-#line 1325 "awkgram.y"
+#line 1324 "awkgram.y"
{ (yyval) = (yyvsp[(1) - (1)]); }
break;
case 126:
/* Line 1792 of yacc.c */
-#line 1327 "awkgram.y"
+#line 1326 "awkgram.y"
{ (yyval) = (yyvsp[(1) - (1)]); }
break;
case 127:
/* Line 1792 of yacc.c */
-#line 1329 "awkgram.y"
+#line 1328 "awkgram.y"
{
int count = 2;
bool is_simple_var = false;
@@ -3526,43 +3525,43 @@ regular_print:
case 129:
/* Line 1792 of yacc.c */
-#line 1381 "awkgram.y"
- { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) -
(3)])); }
+#line 1380 "awkgram.y"
+ { (yyval) = list_append(list_merge((yyvsp[(1) - (3)]), (yyvsp[(3) -
(3)])), (yyvsp[(2) - (3)])); }
break;
case 130:
/* Line 1792 of yacc.c */
-#line 1383 "awkgram.y"
- { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) -
(3)])); }
+#line 1382 "awkgram.y"
+ { (yyval) = list_append(list_merge((yyvsp[(1) - (3)]), (yyvsp[(3) -
(3)])), (yyvsp[(2) - (3)])); }
break;
case 131:
/* Line 1792 of yacc.c */
-#line 1385 "awkgram.y"
- { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) -
(3)])); }
+#line 1384 "awkgram.y"
+ { (yyval) = list_append(list_merge((yyvsp[(1) - (3)]), (yyvsp[(3) -
(3)])), (yyvsp[(2) - (3)])); }
break;
case 132:
/* Line 1792 of yacc.c */
-#line 1387 "awkgram.y"
- { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) -
(3)])); }
+#line 1386 "awkgram.y"
+ { (yyval) = list_append(list_merge((yyvsp[(1) - (3)]), (yyvsp[(3) -
(3)])), (yyvsp[(2) - (3)])); }
break;
case 133:
/* Line 1792 of yacc.c */
-#line 1389 "awkgram.y"
- { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) -
(3)])); }
+#line 1388 "awkgram.y"
+ { (yyval) = list_append(list_merge((yyvsp[(1) - (3)]), (yyvsp[(3) -
(3)])), (yyvsp[(2) - (3)])); }
break;
case 134:
/* Line 1792 of yacc.c */
-#line 1391 "awkgram.y"
- { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) -
(3)])); }
+#line 1390 "awkgram.y"
+ { (yyval) = list_append(list_merge((yyvsp[(1) - (3)]), (yyvsp[(3) -
(3)])), (yyvsp[(2) - (3)])); }
break;
case 135:
/* Line 1792 of yacc.c */
-#line 1393 "awkgram.y"
+#line 1392 "awkgram.y"
{
/*
* In BEGINFILE/ENDFILE, allow `getline var < file'
@@ -3589,7 +3588,7 @@ regular_print:
case 136:
/* Line 1792 of yacc.c */
-#line 1416 "awkgram.y"
+#line 1415 "awkgram.y"
{
(yyvsp[(2) - (2)])->opcode = Op_postincrement;
(yyval) = mk_assignment((yyvsp[(1) - (2)]), NULL, (yyvsp[(2) -
(2)]));
@@ -3598,7 +3597,7 @@ regular_print:
case 137:
/* Line 1792 of yacc.c */
-#line 1421 "awkgram.y"
+#line 1420 "awkgram.y"
{
(yyvsp[(2) - (2)])->opcode = Op_postdecrement;
(yyval) = mk_assignment((yyvsp[(1) - (2)]), NULL, (yyvsp[(2) -
(2)]));
@@ -3607,7 +3606,7 @@ regular_print:
case 138:
/* Line 1792 of yacc.c */
-#line 1426 "awkgram.y"
+#line 1425 "awkgram.y"
{
if (do_lint_old) {
warning_ln((yyvsp[(4) - (5)])->source_line,
@@ -3631,7 +3630,7 @@ regular_print:
case 139:
/* Line 1792 of yacc.c */
-#line 1451 "awkgram.y"
+#line 1450 "awkgram.y"
{
(yyval) = mk_getline((yyvsp[(3) - (4)]), (yyvsp[(4) - (4)]),
(yyvsp[(1) - (4)]), (yyvsp[(2) - (4)])->redir_type);
bcfree((yyvsp[(2) - (4)]));
@@ -3640,43 +3639,43 @@ regular_print:
case 140:
/* Line 1792 of yacc.c */
-#line 1457 "awkgram.y"
- { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) -
(3)])); }
+#line 1456 "awkgram.y"
+ { (yyval) = list_append(list_merge((yyvsp[(1) - (3)]), (yyvsp[(3) -
(3)])), (yyvsp[(2) - (3)])); }
break;
case 141:
/* Line 1792 of yacc.c */
-#line 1459 "awkgram.y"
- { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) -
(3)])); }
+#line 1458 "awkgram.y"
+ { (yyval) = list_append(list_merge((yyvsp[(1) - (3)]), (yyvsp[(3) -
(3)])), (yyvsp[(2) - (3)])); }
break;
case 142:
/* Line 1792 of yacc.c */
-#line 1461 "awkgram.y"
- { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) -
(3)])); }
+#line 1460 "awkgram.y"
+ { (yyval) = list_append(list_merge((yyvsp[(1) - (3)]), (yyvsp[(3) -
(3)])), (yyvsp[(2) - (3)])); }
break;
case 143:
/* Line 1792 of yacc.c */
-#line 1463 "awkgram.y"
- { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) -
(3)])); }
+#line 1462 "awkgram.y"
+ { (yyval) = list_append(list_merge((yyvsp[(1) - (3)]), (yyvsp[(3) -
(3)])), (yyvsp[(2) - (3)])); }
break;
case 144:
/* Line 1792 of yacc.c */
-#line 1465 "awkgram.y"
- { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) -
(3)])); }
+#line 1464 "awkgram.y"
+ { (yyval) = list_append(list_merge((yyvsp[(1) - (3)]), (yyvsp[(3) -
(3)])), (yyvsp[(2) - (3)])); }
break;
case 145:
/* Line 1792 of yacc.c */
-#line 1467 "awkgram.y"
- { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) -
(3)])); }
+#line 1466 "awkgram.y"
+ { (yyval) = list_append(list_merge((yyvsp[(1) - (3)]), (yyvsp[(3) -
(3)])), (yyvsp[(2) - (3)])); }
break;
case 146:
/* Line 1792 of yacc.c */
-#line 1472 "awkgram.y"
+#line 1471 "awkgram.y"
{
(yyval) = list_create((yyvsp[(1) - (1)]));
}
@@ -3684,7 +3683,7 @@ regular_print:
case 147:
/* Line 1792 of yacc.c */
-#line 1476 "awkgram.y"
+#line 1475 "awkgram.y"
{
if ((yyvsp[(2) - (2)])->opcode == Op_match_rec) {
(yyvsp[(2) - (2)])->opcode = Op_nomatch;
@@ -3720,13 +3719,13 @@ regular_print:
case 148:
/* Line 1792 of yacc.c */
-#line 1508 "awkgram.y"
+#line 1507 "awkgram.y"
{ (yyval) = (yyvsp[(2) - (3)]); }
break;
case 149:
/* Line 1792 of yacc.c */
-#line 1510 "awkgram.y"
+#line 1509 "awkgram.y"
{
(yyval) = snode((yyvsp[(3) - (4)]), (yyvsp[(1) - (4)]));
if ((yyval) == NULL)
@@ -3736,7 +3735,7 @@ regular_print:
case 150:
/* Line 1792 of yacc.c */
-#line 1516 "awkgram.y"
+#line 1515 "awkgram.y"
{
(yyval) = snode((yyvsp[(3) - (4)]), (yyvsp[(1) - (4)]));
if ((yyval) == NULL)
@@ -3746,7 +3745,7 @@ regular_print:
case 151:
/* Line 1792 of yacc.c */
-#line 1522 "awkgram.y"
+#line 1521 "awkgram.y"
{
static bool warned = false;
@@ -3763,7 +3762,7 @@ regular_print:
case 154:
/* Line 1792 of yacc.c */
-#line 1537 "awkgram.y"
+#line 1536 "awkgram.y"
{
(yyvsp[(1) - (2)])->opcode = Op_preincrement;
(yyval) = mk_assignment((yyvsp[(2) - (2)]), NULL, (yyvsp[(1) -
(2)]));
@@ -3772,7 +3771,7 @@ regular_print:
case 155:
/* Line 1792 of yacc.c */
-#line 1542 "awkgram.y"
+#line 1541 "awkgram.y"
{
(yyvsp[(1) - (2)])->opcode = Op_predecrement;
(yyval) = mk_assignment((yyvsp[(2) - (2)]), NULL, (yyvsp[(1) -
(2)]));
@@ -3781,7 +3780,7 @@ regular_print:
case 156:
/* Line 1792 of yacc.c */
-#line 1547 "awkgram.y"
+#line 1546 "awkgram.y"
{
(yyval) = list_create((yyvsp[(1) - (1)]));
}
@@ -3789,7 +3788,7 @@ regular_print:
case 157:
/* Line 1792 of yacc.c */
-#line 1551 "awkgram.y"
+#line 1550 "awkgram.y"
{
(yyval) = list_create((yyvsp[(1) - (1)]));
}
@@ -3797,14 +3796,14 @@ regular_print:
case 158:
/* Line 1792 of yacc.c */
-#line 1555 "awkgram.y"
+#line 1554 "awkgram.y"
{
if ((yyvsp[(2) - (2)])->lasti->opcode == Op_push_i
&& ((yyvsp[(2) - (2)])->lasti->memory->flags &
(STRCUR|STRING)) == 0
) {
NODE *n = (yyvsp[(2) - (2)])->lasti->memory;
(void) force_number(n);
- negate_num(n);
+ numbr_hndlr->gawk_negate_number(n);
(yyval) = (yyvsp[(2) - (2)]);
bcfree((yyvsp[(1) - (2)]));
} else {
@@ -3816,21 +3815,20 @@ regular_print:
case 159:
/* Line 1792 of yacc.c */
-#line 1570 "awkgram.y"
+#line 1569 "awkgram.y"
{
/*
* was: $$ = $2
* POSIX semantics: force a conversion to numeric type
*/
- (yyvsp[(1) - (2)])->opcode = Op_plus_i;
- (yyvsp[(1) - (2)])->memory = make_number(0.0);
+ (yyvsp[(1) - (2)])->opcode = Op_unary_plus;
(yyval) = list_append((yyvsp[(2) - (2)]), (yyvsp[(1) - (2)]));
}
break;
case 160:
/* Line 1792 of yacc.c */
-#line 1583 "awkgram.y"
+#line 1581 "awkgram.y"
{
func_use((yyvsp[(1) - (1)])->lasti->func_name, FUNC_USE);
(yyval) = (yyvsp[(1) - (1)]);
@@ -3839,7 +3837,7 @@ regular_print:
case 161:
/* Line 1792 of yacc.c */
-#line 1588 "awkgram.y"
+#line 1586 "awkgram.y"
{
/* indirect function call */
INSTRUCTION *f, *t;
@@ -3876,7 +3874,7 @@ regular_print:
case 162:
/* Line 1792 of yacc.c */
-#line 1624 "awkgram.y"
+#line 1622 "awkgram.y"
{
param_sanity((yyvsp[(3) - (4)]));
(yyvsp[(1) - (4)])->opcode = Op_func_call;
@@ -3894,37 +3892,37 @@ regular_print:
case 163:
/* Line 1792 of yacc.c */
-#line 1641 "awkgram.y"
+#line 1639 "awkgram.y"
{ (yyval) = NULL; }
break;
case 164:
/* Line 1792 of yacc.c */
-#line 1643 "awkgram.y"
+#line 1641 "awkgram.y"
{ (yyval) = (yyvsp[(1) - (1)]); }
break;
case 165:
/* Line 1792 of yacc.c */
-#line 1648 "awkgram.y"
+#line 1646 "awkgram.y"
{ (yyval) = NULL; }
break;
case 166:
/* Line 1792 of yacc.c */
-#line 1650 "awkgram.y"
+#line 1648 "awkgram.y"
{ (yyval) = (yyvsp[(1) - (2)]); }
break;
case 167:
/* Line 1792 of yacc.c */
-#line 1655 "awkgram.y"
+#line 1653 "awkgram.y"
{ (yyval) = (yyvsp[(1) - (1)]); }
break;
case 168:
/* Line 1792 of yacc.c */
-#line 1657 "awkgram.y"
+#line 1655 "awkgram.y"
{
(yyval) = list_merge((yyvsp[(1) - (2)]), (yyvsp[(2) - (2)]));
}
@@ -3932,7 +3930,7 @@ regular_print:
case 169:
/* Line 1792 of yacc.c */
-#line 1664 "awkgram.y"
+#line 1662 "awkgram.y"
{
INSTRUCTION *ip = (yyvsp[(1) - (1)])->lasti;
int count = ip->sub_count; /* # of SUBSEP-seperated
expressions */
@@ -3950,7 +3948,7 @@ regular_print:
case 170:
/* Line 1792 of yacc.c */
-#line 1681 "awkgram.y"
+#line 1679 "awkgram.y"
{
INSTRUCTION *t = (yyvsp[(2) - (3)]);
if ((yyvsp[(2) - (3)]) == NULL) {
@@ -3968,13 +3966,13 @@ regular_print:
case 171:
/* Line 1792 of yacc.c */
-#line 1698 "awkgram.y"
+#line 1696 "awkgram.y"
{ (yyval) = (yyvsp[(1) - (1)]); }
break;
case 172:
/* Line 1792 of yacc.c */
-#line 1700 "awkgram.y"
+#line 1698 "awkgram.y"
{
(yyval) = list_merge((yyvsp[(1) - (2)]), (yyvsp[(2) - (2)]));
}
@@ -3982,13 +3980,13 @@ regular_print:
case 173:
/* Line 1792 of yacc.c */
-#line 1707 "awkgram.y"
+#line 1705 "awkgram.y"
{ (yyval) = (yyvsp[(1) - (2)]); }
break;
case 174:
/* Line 1792 of yacc.c */
-#line 1712 "awkgram.y"
+#line 1710 "awkgram.y"
{
char *var_name = (yyvsp[(1) - (1)])->lextok;
@@ -4000,7 +3998,7 @@ regular_print:
case 175:
/* Line 1792 of yacc.c */
-#line 1720 "awkgram.y"
+#line 1718 "awkgram.y"
{
char *arr = (yyvsp[(1) - (2)])->lextok;
(yyvsp[(1) - (2)])->memory = variable((yyvsp[(1) -
(2)])->source_line, arr, Node_var_new);
@@ -4011,7 +4009,7 @@ regular_print:
case 176:
/* Line 1792 of yacc.c */
-#line 1730 "awkgram.y"
+#line 1728 "awkgram.y"
{
INSTRUCTION *ip = (yyvsp[(1) - (1)])->nexti;
if (ip->opcode == Op_push
@@ -4027,7 +4025,7 @@ regular_print:
case 177:
/* Line 1792 of yacc.c */
-#line 1742 "awkgram.y"
+#line 1740 "awkgram.y"
{
(yyval) = list_append((yyvsp[(2) - (3)]), (yyvsp[(1) - (3)]));
if ((yyvsp[(3) - (3)]) != NULL)
@@ -4037,7 +4035,7 @@ regular_print:
case 178:
/* Line 1792 of yacc.c */
-#line 1751 "awkgram.y"
+#line 1749 "awkgram.y"
{
(yyvsp[(1) - (1)])->opcode = Op_postincrement;
}
@@ -4045,7 +4043,7 @@ regular_print:
case 179:
/* Line 1792 of yacc.c */
-#line 1755 "awkgram.y"
+#line 1753 "awkgram.y"
{
(yyvsp[(1) - (1)])->opcode = Op_postdecrement;
}
@@ -4053,43 +4051,43 @@ regular_print:
case 180:
/* Line 1792 of yacc.c */
-#line 1758 "awkgram.y"
+#line 1756 "awkgram.y"
{ (yyval) = NULL; }
break;
case 182:
/* Line 1792 of yacc.c */
-#line 1766 "awkgram.y"
+#line 1764 "awkgram.y"
{ yyerrok; }
break;
case 183:
/* Line 1792 of yacc.c */
-#line 1770 "awkgram.y"
+#line 1768 "awkgram.y"
{ yyerrok; }
break;
case 186:
/* Line 1792 of yacc.c */
-#line 1779 "awkgram.y"
+#line 1777 "awkgram.y"
{ yyerrok; }
break;
case 187:
/* Line 1792 of yacc.c */
-#line 1783 "awkgram.y"
+#line 1781 "awkgram.y"
{ (yyval) = (yyvsp[(1) - (1)]); yyerrok; }
break;
case 188:
/* Line 1792 of yacc.c */
-#line 1787 "awkgram.y"
+#line 1785 "awkgram.y"
{ yyerrok; }
break;
/* Line 1792 of yacc.c */
-#line 4105 "awkgram.c"
+#line 4103 "awkgram.c"
default: break;
}
/* User semantic actions sometimes alter yychar, and that requires
@@ -4321,7 +4319,7 @@ yyreturn:
/* Line 2055 of yacc.c */
-#line 1789 "awkgram.y"
+#line 1787 "awkgram.y"
struct token {
@@ -4339,7 +4337,6 @@ struct token {
# define CONTINUE 0x1000 /* continue allowed inside */
NODE *(*ptr)(int); /* function that implements this keyword */
- NODE *(*ptr2)(int); /* alternate arbitrary-precision function */
};
#if 'a' == 0x81 /* it's EBCDIC */
@@ -4363,90 +4360,85 @@ 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),
do_adump, 0},
+{"adump", Op_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2),
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},
-{"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 },
+{"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(rhift)},
-{"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), stopme,
0},
+{"stopme", Op_builtin, LEX_BUILTIN, GAWKX|A(0), 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
@@ -4482,22 +4474,6 @@ getfname(NODE *(*fptr)(int))
return NULL;
}
-/* negate_num --- negate a number in NODE */
-
-void
-negate_num(NODE *n)
-{
-#ifdef HAVE_MPFR
- if (is_mpg_float(n)) {
- int tval;
- tval = mpfr_neg(n->mpg_numbr, n->mpg_numbr, ROUND_MODE);
- IEEE_FMT(n->mpg_numbr, tval);
- } else if (is_mpg_integer(n)) {
- mpz_neg(n->mpg_i, n->mpg_i);
- } else
-#endif
- n->numbr = -n->numbr;
-}
/* print_included_from --- print `Included from ..' file names and locations */
@@ -4667,6 +4643,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 *
@@ -6038,32 +6026,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 '&':
@@ -6367,13 +6330,7 @@ snode(INSTRUCTION *subn, INSTRUCTION *r)
}
}
-#ifdef HAVE_MPFR
- /* N.B.: There isn't any special processing for an alternate function
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 */
@@ -6580,26 +6537,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));
}
@@ -7060,20 +7003,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:
@@ -7176,112 +7114,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 > 1
- && 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 */
@@ -7677,8 +7509,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 */
diff --git a/awkgram.y b/awkgram.y
index b1574c8..bf5ca36 100644
--- a/awkgram.y
+++ b/awkgram.y
@@ -69,7 +69,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);
@@ -1096,7 +1095,7 @@ case_value
{
NODE *n = $2->memory;
(void) force_number(n);
- negate_num(n);
+ numbr_hndlr->gawk_negate_number(n);
bcfree($1);
$$ = $2;
}
@@ -1378,17 +1377,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
{
/*
@@ -1454,17 +1453,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
@@ -1558,7 +1557,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 {
@@ -1572,8 +1571,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);
}
;
@@ -1803,7 +1801,6 @@ struct token {
# define CONTINUE 0x1000 /* continue allowed inside */
NODE *(*ptr)(int); /* function that implements this keyword */
- NODE *(*ptr2)(int); /* alternate arbitrary-precision function */
};
#if 'a' == 0x81 /* it's EBCDIC */
@@ -1827,90 +1824,85 @@ 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),
do_adump, 0},
+{"adump", Op_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2),
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},
-{"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 },
+{"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(rhift)},
-{"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), stopme,
0},
+{"stopme", Op_builtin, LEX_BUILTIN, GAWKX|A(0), 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
@@ -1946,22 +1938,6 @@ getfname(NODE *(*fptr)(int))
return NULL;
}
-/* negate_num --- negate a number in NODE */
-
-void
-negate_num(NODE *n)
-{
-#ifdef HAVE_MPFR
- if (is_mpg_float(n)) {
- int tval;
- tval = mpfr_neg(n->mpg_numbr, n->mpg_numbr, ROUND_MODE);
- IEEE_FMT(n->mpg_numbr, tval);
- } else if (is_mpg_integer(n)) {
- mpz_neg(n->mpg_i, n->mpg_i);
- } else
-#endif
- n->numbr = -n->numbr;
-}
/* print_included_from --- print `Included from ..' file names and locations */
@@ -2131,6 +2107,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 *
@@ -3502,32 +3490,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 '&':
@@ -3831,13 +3794,7 @@ snode(INSTRUCTION *subn, INSTRUCTION *r)
}
}
-#ifdef HAVE_MPFR
- /* N.B.: There isn't any special processing for an alternate function
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 */
@@ -4044,26 +4001,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));
}
@@ -4524,20 +4467,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:
@@ -4640,112 +4578,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 > 1
- && 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 */
@@ -5141,8 +4973,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 */
diff --git a/builtin.c b/builtin.c
index 07169a3..464b6fc 100644
--- a/builtin.c
+++ b/builtin.c
@@ -28,9 +28,6 @@
#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 +56,9 @@
#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 size_t mbc_byte_count(const char *ptr, size_t numchars);
+extern size_t mbc_char_count(const char *ptr, size_t numbytes);
extern NODE **args_array;
extern int max_args;
@@ -86,12 +76,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
@@ -130,25 +114,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 */
@@ -458,35 +423,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 *
@@ -557,1022 +493,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_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 = 0;
-
- 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 = ≺
- have_prec = true;
- goto retry;
- case '#':
- 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')
- 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));
- wc = uval;
-
- count = wcrtomb(buf, wc, & mbs);
- if (count == 0
- || count == (size_t)-1
- || count == (size_t)-2)
- goto out0;
-
- memcpy(cpbuf, buf, count);
- prec = count;
- cp = cpbuf;
- goto pr_tail;
- }
-out0:
- ;
- /* else,
- fall through */
-#endif
- if (do_lint && uval > 255) {
- lintwarn("[s]printf: value %g is too
big for %%c format",
- arg->numbr);
- }
- 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;
-#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 == 0
- || count == (size_t)-1
- || count == (size_t)-2)
- goto out2;
- prec = count;
- goto pr_tail;
- }
-out2:
- ;
-#endif
- prec = 1;
- 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;
- 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 */
- PREPEND(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)
- 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
- /*
- * 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 */
- PREPEND(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)
- 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 && (cs1 == 's' || cs1 ==
'c')) {
- assert(cp == arg->stptr || cp == cpbuf);
- copy_count = mbc_byte_count(arg->stptr, 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 && isalpha(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 */
@@ -1668,45 +588,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();
@@ -1716,11 +616,11 @@ 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 dupnode(Nnull_string);
+ r = dupnode(Nnull_string);
+ 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);
@@ -1743,7 +643,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);
@@ -1770,8 +670,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 dupnode(Nnull_string);
+ r = dupnode(Nnull_string);
+ goto finish;
}
/* get total len of input string, for following checks */
@@ -1787,8 +687,8 @@ do_substr(int nargs)
if (do_lint)
lintwarn(_("substr: start index %g is past end of
string"),
d_index);
- DEREF(t1);
- return dupnode(Nnull_string);
+ r = dupnode(Nnull_string);
+ goto finish;
}
if (length > src_len - indx) {
if (do_lint)
@@ -1832,6 +732,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;
}
@@ -2295,113 +1199,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)
-{
- 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
- */
- return make_number((AWKNUM) (random() % GAWK_RANDOM_MAX) /
GAWK_RANDOM_MAX);
-}
-
-/* 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
@@ -2970,316 +1767,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
@@ -3413,7 +1900,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
@@ -3445,10 +1931,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 */
@@ -3512,7 +1997,7 @@ do_bindtextdomain(int nargs)
/* mbc_byte_count --- return number of bytes for corresponding numchars
multibyte characters */
-static size_t
+size_t
mbc_byte_count(const char *ptr, size_t numchars)
{
#if MBS_SUPPORT
@@ -3543,7 +2028,7 @@ mbc_byte_count(const char *ptr, size_t numchars)
/* mbc_char_count --- return number of m.b. chars in string, up to numbytes
bytes */
-static size_t
+size_t
mbc_char_count(const char *ptr, size_t numbytes)
{
#if MBS_SUPPORT
diff --git a/command.c b/command.c
index 0944a9d..6139cf0 100644
--- a/command.c
+++ b/command.c
@@ -2350,7 +2350,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[(2) - (2)]);
}
break;
@@ -3168,24 +3168,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);
@@ -3383,7 +3368,8 @@ do_help(CMDARG *arg, int cmd)
}
-/* 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).
*/
@@ -3411,9 +3397,10 @@ next_word(char *p, int len, char **endp)
#ifdef HAVE_LIBREADLINE
-/* 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 f6c7981..301d4e3 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);
@@ -1459,7 +1444,8 @@ do_help(CMDARG *arg, int cmd)
}
-/* 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,10 @@ next_word(char *p, int len, char **endp)
#ifdef HAVE_LIBREADLINE
-/* 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 a69b7e3..e679209 100644
--- a/debug.c
+++ b/debug.c
@@ -3656,27 +3656,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, "-?-");
@@ -3968,12 +3954,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 0000000..2c80d82
--- /dev/null
+++ b/double.c
@@ -0,0 +1,2091 @@
+/*
+ * 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 */
+
+/* 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
+
+extern NODE **fmt_list; /* declared in eval.c */
+
+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);
+
+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 AWKNUM awknum_todouble(const NODE *);
+static uintmax_t awknum_touintmax_t(const NODE *);
+static int awknum_sgn(const NODE *);
+static bool awknum_is_integer(const NODE *);
+static NODE *awknum_copy(const NODE *);
+static NODE *format_nodes_awknum(const char *, size_t, NODE **, long);
+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 functions */
+static double double_to_int(double d);
+
+
+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_is_integer,
+ format_awknum_val,
+ format_nodes_awknum,
+ 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 },
+ { "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 AWKNUM
+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_is_integer --- check if a number is an integer */
+
+static bool
+awknum_is_integer(const NODE *n)
+{
+ if (isnan(n->numbr) || isinf(n->numbr))
+ return false;
+ return double_to_int(n->numbr) == 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;
+
+ /* N.B: PREC and ROUNMODE -- not relevant */
+}
+
+/* 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()
+{
+ /* dummy function */
+}
+
+/* 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_number(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)
+{
+ 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
+ */
+ return make_number((AWKNUM) (random() % GAWK_RANDOM_MAX) /
GAWK_RANDOM_MAX);
+}
+
+/* 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_number((AWKNUM) ret);
+}
+
+
+/*-------------------------------------------------------------------*/
+
+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;
+ 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 (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.
+ */
+
+ /* 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_awknum_val");
+ memcpy(s->stptr, sp, s->stlen + 1);
+no_malloc:
+ s->flags |= STRCUR;
+ free_wstr(s);
+ 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_number(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_number(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_number(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_number(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_number(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_number(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_number(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_number(d);
+}
+
+
+/*
+ * 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.
+ */
+
+static NODE *
+format_nodes_awknum(
+ 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;
+
+ 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;
+ 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 = ≺
+ have_prec = true;
+ goto retry;
+ case '#':
+ 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')
+ 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));
+ wc = uval;
+
+ count = wcrtomb(buf, wc, & mbs);
+ if (count == 0
+ || count == (size_t)-1
+ || count == (size_t)-2)
+ goto out0;
+
+ memcpy(cpbuf, buf, count);
+ prec = count;
+ cp = cpbuf;
+ goto pr_tail;
+ }
+out0:
+ ;
+ /* else,
+ fall through */
+#endif
+ if (do_lint && uval > 255) {
+ lintwarn("[s]printf: value %g is too
big for %%c format",
+ arg->numbr);
+ }
+ 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;
+#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 == 0
+ || count == (size_t)-1
+ || count == (size_t)-2)
+ goto out2;
+ prec = count;
+ goto pr_tail;
+ }
+out2:
+ ;
+#endif
+ prec = 1;
+ 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);
+ 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;
+ 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 */
+ PREPEND(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)
+ 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);
+ 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;
+ }
+
+ /*
+ * 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 */
+ PREPEND(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)
+ 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 && (cs1 == 's' || cs1 ==
'c')) {
+ assert(cp == arg->stptr || cp == cpbuf);
+ copy_count = mbc_byte_count(arg->stptr, 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);
+ tmpval = arg->numbr;
+ fmt1:
+ if (! have_prec)
+ prec = DEFAULT_G_PRECISION;
+
+ 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
+
+ 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 && isalpha(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;
+}
diff --git a/eval.c b/eval.c
index 1908c47..5312289 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
@@ -263,18 +264,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", ", " },
@@ -284,6 +285,7 @@ static struct optypetab {
{ "Op_predecrement", "--" },
{ "Op_postincrement", "++" },
{ "Op_postdecrement", "--" },
+ { "Op_unary_plus", "+" },
{ "Op_unary_minus", "-" },
{ "Op_field_spec", "$" },
{ "Op_not", "! " },
@@ -291,12 +293,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 },
@@ -822,15 +818,11 @@ set_ORS()
/* fmt_ok --- is the conversion format a valid one? */
NODE **fmt_list = NULL;
-static int fmt_ok(NODE *n);
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
@@ -843,22 +835,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 */
@@ -880,7 +872,7 @@ fmt_index(NODE *n)
}
/* 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"
@@ -990,6 +982,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
@@ -1029,15 +1038,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 */
@@ -1061,15 +1062,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);
}
@@ -1185,42 +1178,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 *
@@ -1490,10 +1447,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)
@@ -1533,63 +1490,42 @@ 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);
+ 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 */
@@ -1729,7 +1665,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"
@@ -1757,14 +1693,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 3edd5d8..de5dfce 100644
--- a/field.c
+++ b/field.c
@@ -195,28 +195,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/gawkapi.c b/gawkapi.c
index b89bdbc..5ee18f3 100644
--- a/gawkapi.c
+++ b/gawkapi.c
@@ -665,7 +665,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: */
@@ -689,7 +689,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): */
@@ -1149,7 +1150,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 769ac9b..04c7a9a 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 c652624..0cf15b8 100644
--- a/interpret.h
+++ b/interpret.h
@@ -37,6 +37,7 @@ r_interpret(INSTRUCTION *code)
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 */
@@ -180,7 +181,7 @@ top:
cant_happen();
}
}
- break;
+ break;
case Op_push_param: /* function argument */
m = pc->memory;
@@ -392,7 +393,7 @@ top:
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;
@@ -401,7 +402,7 @@ top:
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);
@@ -409,181 +410,115 @@ top:
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;
@@ -834,7 +769,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);
@@ -983,13 +918,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;
@@ -1328,8 +1263,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 0b008fc..666bfde 100644
--- a/io.c
+++ b/io.c
@@ -144,14 +144,6 @@
#define PIPES_SIMULATED
#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. */
@@ -413,11 +405,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;
@@ -474,14 +466,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 */
@@ -489,14 +475,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 */
@@ -520,8 +500,17 @@ inrec(IOBUF *iop, int *errcode)
if (*errcode > 0)
update_ERRNO_int(*errcode);
} 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);
}
@@ -2393,8 +2382,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 437c0cd..24dbb56 100644
--- a/main.c
+++ b/main.c
@@ -35,8 +35,6 @@
#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 */
@@ -58,9 +56,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;
@@ -111,6 +112,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
@@ -210,6 +213,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)
@@ -281,7 +288,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);
@@ -292,12 +299,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 */
@@ -456,9 +457,7 @@ main(int argc, char **argv)
break;
case 'M':
-#ifdef HAVE_MPFR
- do_flags |= DO_MPFR;
-#endif
+ numbr_hndlr = & mpfp_hndlr;
break;
case 'P':
@@ -580,29 +579,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
@@ -667,7 +658,7 @@ out:
optind++;
}
- /* Select the interpreter routine */
+ /* select the interpreter routine */
init_interpret();
init_args(optind, argc,
@@ -682,6 +673,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);
@@ -980,7 +975,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 },
@@ -988,7 +983,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 },
@@ -1019,6 +1014,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);
@@ -1107,7 +1104,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;
@@ -1123,14 +1120,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 GETPGRP_VOID
#define getpgrp_arg() /* nothing */
@@ -1426,9 +1417,7 @@ static void
version()
{
printf("%s", version_string);
-#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();
@@ -1545,6 +1534,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_tree = numbr_hndlr->gawk_format_nodes;
+ 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/mpfr.c b/mpfr.c
index 48fa072..83b37a1 100644
--- a/mpfr.c
+++ b/mpfr.c
@@ -26,103 +26,309 @@
#include "awk.h"
#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
#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 */
+#define DEFAULT_PREC 53
+#define DEFAULT_ROUNDMODE "N" /* round to nearest */
-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;
+extern NODE **fmt_list; /* declared in eval.c */
-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);
+/* 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 AWKNUM mpfp_todouble(const NODE *);
+static uintmax_t mpfp_touintmax_t(const NODE *);
+static int mpfp_sgn(const NODE *);
+static bool mpfp_is_integer(const NODE *n);
+static NODE *mpfp_copy_number(const NODE *);
+static NODE *mpfp_format_nodes(const char *, size_t, NODE **, long);
+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_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;
-/* temporaries used in bit ops */
-static NODE *_tz1;
-static NODE *_tz2;
-static mpz_t _mpz1;
-static mpz_t _mpz2;
-static mpz_ptr mpz1;
-static mpz_ptr mpz2;
+/* needed for MPFR and GMP macros */
+#define MPFR_T(x) ((mpfr_ptr) x)
+#define MPZ_T(x) ((mpz_ptr) x)
-static NODE *get_bit_ops(const char *op);
-#define free_bit_ops() (DEREF(_tz1), DEREF(_tz2))
/* 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)
+
+
+/* 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);
+}
-/* init_mpfr --- set up MPFR related variables */
-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_is_integer,
+ mpfp_format_val,
+ mpfp_format_nodes,
+ 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 },
+ { "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;
- mpz_init(_mpz1);
- mpz_init(_mpz2);
- 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) ? 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) ? mpfr_get_si(n->qnumbr, ROUND_MODE) :
mpz_get_si(n->qnumbr);
+}
+
+/* mpfp_todouble --- conversion to AWKNUM */
- register_exec_hook(mpg_interpret, 0);
+static AWKNUM
+mpfp_todouble(const NODE *n)
+{
+ return (n->flags & MPFN) ? 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) ? 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) ? mpfr_sgn(MPFR_T(n->qnumbr)) \
+ : mpz_sgn(MPZ_T(n->qnumbr));
+}
+
+/* mpfp_is_integer --- check if a number is an integer */
+
+static bool
+mpfp_is_integer(const NODE *n)
+{
+ return is_mpfp_integer(n) ? true : mpfr_integer_p(n->qnumbr);
}
-/* mpg_node --- allocate a node to store MPFR float or GMP integer */
+/* mpfp_make_node --- allocate a node to store MPFR float or GMP integer */
-NODE *
-mpg_node(unsigned int tp)
+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 |= (NUMBER|NUMCUR);
r->stptr = NULL;
r->stlen = 0;
#if MBS_SUPPORT
@@ -133,32 +339,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;
@@ -223,10 +423,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;
@@ -258,34 +458,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;
}
@@ -294,7 +500,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;
}
@@ -309,28 +515,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))
@@ -339,17 +547,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) {
@@ -357,17 +565,17 @@ 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;
@@ -376,12 +584,12 @@ mpg_format_val(const char *format, int index, NODE *s)
dummy[1] = s;
oflags = s->flags;
- if (is_mpg_integer(s) || mpfr_integer_p(s->mpg_numbr)) {
+ if (is_mpfp_integer(s) || mpfr_integer_p(s->qnumbr)) {
/* integral value, use %d */
- r = format_tree("%d", 2, dummy, 2);
+ r = mpfp_format_nodes("%d", 2, dummy, 2);
s->stfmt = -1;
} else {
- r = format_tree(format, fmt_list[index]->stlen, dummy, 2);
+ r = mpfp_format_nodes(format, fmt_list[index]->stlen, dummy, 2);
assert(r != NULL);
s->stfmt = (char) index;
}
@@ -397,110 +605,88 @@ mpg_format_val(const char *format, int index, NODE *s)
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;
+
+ 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 */
-int
-mpg_cmp(const NODE *t1, const NODE *t2)
+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) */
-}
-/* set_PREC --- update MPFR PRECISION related variables when PREC assigned to
*/
+/* mpfp_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;
@@ -524,12 +710,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;
@@ -550,7 +733,6 @@ set_PREC()
*/
max_exp = ieee_fmts[i].emax;
min_exp = ieee_fmts[i].emin;
-
do_ieee_fmt = true;
}
}
@@ -559,7 +741,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
@@ -571,10 +753,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':
@@ -601,32 +783,115 @@ 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()
+static void
+mpfp_set_ROUNDMODE(const NODE *var)
{
- 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);
+ 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 */
+
+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;
+}
-/* format_ieee --- make sure a number follows IEEE-754 floating-point standard
*/
+/* mpfp_format_ieee --- make sure a number follows IEEE-754 floating-point
standard */
-int
-format_ieee(mpfr_ptr x, int tval)
+static int
+mpfp_format_ieee(mpfr_ptr x, int tval)
{
/*
* The MPFR doc says that it's our responsibility to make sure all
numbers
@@ -667,11 +932,23 @@ format_ieee(mpfr_ptr x, int tval)
return tval;
}
+/* mpfp_negate_num --- negate a number in NODE */
+
+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 /* if (is_mpfp_integer(n)) */
+ mpz_neg(n->qnumbr, n->qnumbr);
+}
-/* do_mpfr_atan2 --- do the atan2 function */
+/* 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;
@@ -686,15 +963,17 @@ 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);
@@ -702,95 +981,94 @@ do_mpfr_atan2(int nargs)
}
-#define SPEC_MATH(X) \
+#define MPFPFUNC(X) \
NODE *t1, *res; \
mpfr_ptr p1; \
int tval; \
t1 = POP_SCALAR(); \
if (do_lint && (t1->flags & (NUMCUR|NUMBER)) == 0) \
lintwarn(_("%s: received non-numeric argument"), #X); \
-force_number(t1); \
-p1 = MP_FLOAT(t1); \
-res = mpg_float(); \
-tval = mpfr_##X(res->mpg_numbr, p1, ROUND_MODE); \
-IEEE_FMT(res->mpg_numbr, tval); \
+t1 = force_number(t1); \
+p1 = mpfp_tofloat(t1, _mp1); \
+res = mpfp_float(); \
+tval = mpfr_##X(res->qnumbr, p1, ROUND_MODE); \
+IEEE_FMT(res->qnumbr, tval); \
DEREF(t1); \
return res
-/* 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;
@@ -799,9 +1077,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 */
@@ -810,236 +1088,288 @@ 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_bit_ops --- get the numeric operands of a binary function.
- * Returns a copy of the operand if either is inf or nan. Otherwise
- * each operand is converted to an integer if necessary, and
- * the results are placed in the variables mpz1 and mpz2.
- */
+/* get_intval --- get the (converted) integral operand of a binary function. */
-static NODE *
-get_bit_ops(const char *op)
+static mpz_ptr
+get_intval(NODE *t1, int argnum, const char *op)
{
- _tz2 = POP_SCALAR();
- _tz1 = POP_SCALAR();
+ mpz_ptr pz;
- if (do_lint) {
- if ((_tz1->flags & (NUMCUR|NUMBER)) == 0)
- lintwarn(_("%s: received non-numeric first argument"),
op);
- if ((_tz2->flags & (NUMCUR|NUMBER)) == 0)
- lintwarn(_("%s: received non-numeric second argument"),
op);
- }
+ if (do_lint && (t1->flags & (NUMCUR|NUMBER)) == 0)
+ lintwarn(_("%s: received non-numeric argument #%d"), op,
argnum);
- force_number(_tz1);
- force_number(_tz2);
+ (void) force_number(t1);
- if (is_mpg_float(_tz1)) {
- mpfr_ptr left = _tz1->mpg_numbr;
+ if (is_mpfp_float(t1)) {
+ mpfr_ptr left = t1->qnumbr;
if (! mpfr_number_p(left)) {
/* inf or NaN */
NODE *res;
- res = mpg_float();
- mpfr_set(res->mpg_numbr, _tz1->mpg_numbr, ROUND_MODE);
- return res;
+ if (do_lint)
+ lintwarn("%s",
+ 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 */
}
if (do_lint) {
if (mpfr_sgn(left) < 0)
lintwarn("%s",
- mpg_fmt(_("%s(%Rg, ..): negative values will give
strange results"),
- op, left)
- );
+ 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(%Rg, ..): fractional values will be
truncated"),
- op, left)
+ mpfp_sprintf(_("%s: argument #%d fractional value %Rg will be
truncated"),
+ op, argnum, left)
);
}
-
- mpfr_get_z(_mpz1, left, MPFR_RNDZ); /* float to integer
conversion */
- mpz1 = _mpz1;
- } else {
- /* (_tz1->flags & MPZN) != 0 */
- mpz1 = _tz1->mpg_i;
- if (do_lint) {
- if (mpz_sgn(mpz1) < 0)
- lintwarn("%s",
- mpg_fmt(_("%s(%Zd, ..): negative values will give
strange results"),
- op, mpz1)
- );
- }
- }
- if (is_mpg_float(_tz2)) {
- mpfr_ptr right = _tz2->mpg_numbr;
- if (! mpfr_number_p(right)) {
- /* inf or NaN */
- NODE *res;
- res = mpg_float();
- mpfr_set(res->mpg_numbr, _tz2->mpg_numbr, ROUND_MODE);
- return res;
- }
+ emalloc(pz, mpz_ptr, sizeof (mpz_t), "get_intval");
+ mpz_init(pz);
+ mpfr_get_z(pz, left, MPFR_RNDZ); /* float to integer
conversion */
+ return pz; /* should be freed */
+ }
- if (do_lint) {
- if (mpfr_sgn(right) < 0)
- lintwarn("%s",
- mpg_fmt(_("%s(.., %Rg): negative values will give
strange results"),
- op, right)
- );
- if (! mpfr_integer_p(right))
- lintwarn("%s",
- mpg_fmt(_("%s(.., %Rg): fractional values will be
truncated"),
- op, right)
+ /* (t1->flags & MPZN) != 0 */
+ pz = t1->qnumbr;
+ if (do_lint) {
+ if (mpz_sgn(pz) < 0)
+ lintwarn("%s",
+ mpfp_sprintf(_("%s: argument #%d negative value %Zd will give strange
results"),
+ op, argnum, pz)
);
- }
-
- mpfr_get_z(_mpz2, right, MPFR_RNDZ); /* float to integer
conversion */
- mpz2 = _mpz2;
- } else {
- /* (_tz2->flags & MPZN) != 0 */
- mpz2 = _tz2->mpg_i;
- if (do_lint) {
- if (mpz_sgn(mpz2) < 0)
- lintwarn("%s",
- mpg_fmt(_("%s(.., %Zd): negative values will give
strange results"),
- op, mpz2)
- );
- }
}
+ return pz; /* must not be freed */
+}
+
+/* free_intval --- free the converted integer value returned by get_intval() */
- return NULL;
+static inline void
+free_intval(NODE *t, mpz_ptr pz)
+{
+ if (t->qnumbr != pz) {
+ mpz_clear(pz);
+ efree(pz);
+ }
}
-/* do_mpfr_lshift --- perform a << operation */
+/* do_mpfp_lshift --- perform a << operation */
-NODE *
-do_mpfr_lshift(int nargs)
+static NODE *
+do_mpfp_lshift(int nargs)
{
- NODE *res;
+ NODE *t1, *t2, *res;
unsigned long shift;
+ mpz_ptr pz1, pz2;
+
+ t2 = POP_SCALAR();
+ t1 = POP_SCALAR();
- if ((res = get_bit_ops("lshift")) == NULL) {
+ pz1 = get_intval(t1, 1, "lshift");
+ pz2 = get_intval(t2, 2, "lshift");
- /*
- * mpz_get_ui: If op is too big to fit an unsigned long then
just
- * the least significant bits that do fit are returned.
- * The sign of op is ignored, only the absolute value is used.
- */
+ /*
+ * mpz_get_ui: If op is too big to fit an unsigned long then just
+ * the least significant bits that do fit are returned.
+ * The sign of op is ignored, only the absolute value is used.
+ */
- shift = mpz_get_ui(mpz2); /* GMP integer => unsigned long
conversion */
- res = mpg_integer();
- mpz_mul_2exp(res->mpg_i, mpz1, shift); /* res = mpz1 *
2^shift */
- }
- free_bit_ops();
+ shift = mpz_get_ui(pz2); /* GMP integer => unsigned long
conversion */
+ res = mpfp_integer();
+ mpz_mul_2exp(res->qnumbr, pz1, shift); /* res = pz1 * 2^shift
*/
+
+ free_intval(t1, pz1);
+ free_intval(t2, pz2);
+ DEREF(t2);
+ DEREF(t1);
return res;
}
-/* do_mpfr_rshift --- perform a >> operation */
+/* do_mpfp_rshift --- perform a >> operation */
-NODE *
-do_mpfr_rhift(int nargs)
+static NODE *
+do_mpfp_rshift(int nargs)
{
- NODE *res;
+ NODE *t1, *t2, *res;
unsigned long shift;
+ mpz_ptr pz1, pz2;
+
+ t2 = POP_SCALAR();
+ t1 = POP_SCALAR();
- if ((res = get_bit_ops("rshift")) == NULL) {
- /*
- * mpz_get_ui: If op is too big to fit an unsigned long then
just
- * the least significant bits that do fit are returned.
- * The sign of op is ignored, only the absolute value is used.
- */
+ pz1 = get_intval(t1, 1, "rshift");
+ pz2 = get_intval(t2, 2, "rshift");
- shift = mpz_get_ui(mpz2); /* GMP integer => unsigned long
conversion */
- res = mpg_integer();
- mpz_fdiv_q_2exp(res->mpg_i, mpz1, shift); /* res = mpz1 /
2^shift, round towards −inf */
- }
- free_bit_ops();
+ /* N.B: See do_mpfp_lshift. */
+ shift = mpz_get_ui(pz2); /* GMP integer => unsigned long
conversion */
+ 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);
+ DEREF(t2);
+ DEREF(t1);
return res;
}
-/* do_mpfr_and --- perform an & operation */
+/* do_mpfp_and --- perform an & operation */
-NODE *
-do_mpfr_and(int nargs)
+static NODE *
+do_mpfp_and(int nargs)
{
- NODE *res;
+ NODE *t1, *t2, *res;
+ mpz_ptr pz1, pz2;
+ int i;
- if ((res = get_bit_ops("and")) == NULL) {
- res = mpg_integer();
- mpz_and(res->mpg_i, mpz1, mpz2);
+ if (nargs < 2)
+ fatal(_("and: called with less than two arguments"));
+
+ t2 = POP_SCALAR();
+ pz2 = get_intval(t2, nargs, "and");
+
+ res = mpfp_integer();
+ for (i = 1; i < nargs; i++) {
+ t1 = POP_SCALAR();
+ pz1 = get_intval(t1, nargs - i, "and");
+ mpz_and(res->qnumbr, pz1, pz2);
+ free_intval(t1, pz1);
+ DEREF(t1);
+ if (i == 1) {
+ free_intval(t2, pz2);
+ DEREF(t2);
+ }
+ pz2 = res->qnumbr;
}
- free_bit_ops();
return res;
}
-/* do_mpfr_or --- perform an | operation */
+/* do_mpfp_or --- perform an | operation */
-NODE *
-do_mpfr_or(int nargs)
+static NODE *
+do_mpfp_or(int nargs)
{
- NODE *res;
+ NODE *t1, *t2, *res;
+ mpz_ptr pz1, pz2;
+ int i;
- if ((res = get_bit_ops("or")) == NULL) {
- res = mpg_integer();
- mpz_ior(res->mpg_i, mpz1, mpz2);
+ if (nargs < 2)
+ fatal(_("or: called with less than two arguments"));
+
+ t2 = POP_SCALAR();
+ pz2 = get_intval(t2, nargs, "or");
+
+ res = mpfp_integer();
+ for (i = 1; i < nargs; i++) {
+ t1 = POP_SCALAR();
+ pz1 = get_intval(t1, nargs - i, "or");
+ mpz_ior(res->qnumbr, pz1, pz2);
+ free_intval(t1, pz1);
+ DEREF(t1);
+ if (i == 1) {
+ free_intval(t2, pz2);
+ DEREF(t2);
+ }
+ pz2 = res->qnumbr;
}
- free_bit_ops();
return res;
}
-/* do_mpfr_strtonum --- the strtonum function */
+/* do_mpfp_xor --- perform an ^ operation */
-NODE *
-do_mpfr_strtonum(int nargs)
+static NODE *
+do_mpfp_xor(int nargs)
+{
+ NODE *t1, *t2, *res;
+ mpz_ptr pz1, pz2;
+ int i;
+
+ if (nargs < 2)
+ fatal(_("xor: called with less than two arguments"));
+
+ t2 = POP_SCALAR();
+ pz2 = get_intval(t2, nargs, "xor");
+
+ res = mpfp_integer();
+ for (i = 1; i < nargs; i++) {
+ t1 = POP_SCALAR();
+ pz1 = get_intval(t1, nargs - i, "xor");
+ mpz_xor(res->qnumbr, pz1, pz2);
+ free_intval(t1, pz1);
+ DEREF(t1);
+ if (i == 1) {
+ free_intval(t2, pz2);
+ DEREF(t2);
+ }
+ pz2 = res->qnumbr;
+ }
+ return res;
+}
+
+/* do_mpfp_strtonum --- the strtonum function */
+
+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);
}
}
@@ -1047,30 +1377,15 @@ do_mpfr_strtonum(int nargs)
return r;
}
-/* do_mpfr_xor --- perform an ^ operation */
-
-NODE *
-do_mpfr_xor(int nargs)
-{
- NODE *res;
-
- if ((res = get_bit_ops("xor")) == NULL) {
- res = mpg_integer();
- mpz_xor(res->mpg_i, mpz1, mpz2);
- }
- free_bit_ops();
- return res;
-}
-
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;
@@ -1093,17 +1408,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;
@@ -1125,8 +1440,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));
@@ -1135,11 +1450,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);
}
@@ -1147,445 +1462,223 @@ do_mpfr_srand(int nargs)
return res;
}
-/*
- * mpg_tofloat --- convert an arbitrary-precision integer operand to
- * a float without loss of precision. It is assumed that the
- * MPFR variable has already been initialized.
- */
-static inline mpfr_ptr
-mpg_tofloat(mpfr_ptr mf, mpz_ptr mz)
-{
- size_t prec;
-
- /*
- * 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
- */
-
- prec = mpz_sizeinbase(mz, 2); /* most significant 1 bit position
starting at 1 */
- if (prec > PRECISION_MIN) {
- prec -= (size_t) mpz_scan1(mz, 0); /* least significant 1
bit index starting at 0 */
- if (prec > MPFR_PREC_MAX)
- prec = MPFR_PREC_MAX;
- if (prec > PRECISION_MIN)
- mpfr_set_prec(mf, prec);
- }
-
- mpfr_set_z(mf, mz, ROUND_MODE);
- return mf;
-}
-
-
-/* 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)) {
- r = mpg_integer();
- mpz_mod(r->mpg_i, t1->mpg_i, t2->mpg_i);
+ if (is_mpfp_integer(t1) && is_mpfp_integer(t2)) {
+ r = mpfp_integer();
+ mpz_mod(r->qnumbr, t1->qnumbr, t2->qnumbr);
} 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;
+/* mpfp_add_long --- add aribitary-precision number to long */
- 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;
-
- 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;
@@ -1603,34 +1696,917 @@ mpg_fmt(const char *mesg, ...)
return mesg;
}
-/* mpfr_unset --- clear out the MPFR values */
-void
-mpfr_unset(NODE *n)
+/*
+ * 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.
+ */
+
+
+static mpfr_ptr
+mpz2mpfr(mpz_ptr mpz_val, mpfr_ptr mpfr_val)
{
- if (is_mpg_float(n))
- mpfr_clear(n->mpg_numbr);
- else if (is_mpg_integer(n))
- mpz_clear(n->mpg_i);
+ size_t prec;
+ 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 */
+
+ if (mpfr_val != NULL && mpfr_get_prec(mpfr_val) >= prec)
+ goto finish;
+
+ prec -= (size_t) 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 < mpfr_get_prec(mpfr_val))
+ 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;
}
-#else
-void
-set_PREC()
+
+extern size_t mbc_byte_count(const char *ptr, size_t numchars);
+extern size_t mbc_char_count(const char *ptr, size_t numbytes);
+
+/*
+ * mpfp_format_nodes() 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.
+ */
+
+static NODE *
+mpfp_format_nodes(
+ const char *fmt_string,
+ size_t n0,
+ NODE **the_args,
+ long num_args)
{
- /* dummy function */
+/* 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); \
}
-void
-set_ROUNDMODE()
-{
- /* dummy function */
+/* 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_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 = 0;
+
+ 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 = ≺
+ have_prec = true;
+ goto retry;
+ case '#':
+ 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')
+ 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));
+ wc = uval;
+
+ count = wcrtomb(buf, wc, & mbs);
+ if (count == 0
+ || count == (size_t)-1
+ || count == (size_t)-2)
+ goto out0;
+
+ memcpy(cpbuf, buf, count);
+ prec = count;
+ cp = cpbuf;
+ goto pr_tail;
+ }
+out0:
+ ;
+ /* else,
+ fall through */
+#endif
+ if (do_lint && uval > 255) {
+ lintwarn("[s]printf: value %g is too
big for %%c format",
+ arg->numbr);
+ }
+ 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;
+#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 == 0
+ || count == (size_t)-1
+ || count == (size_t)-2)
+ goto out2;
+ prec = count;
+ goto pr_tail;
+ }
+out2:
+ ;
+#endif
+ prec = 1;
+ 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_mpfp_float(arg))
+ goto mpf0;
+ else {
+ assert(is_mpfp_integer(arg) == true);
+ goto mpz0;
+ }
+#endif
+ 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_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;
+ }
+ 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 {
+ assert(is_mpfp_float(arg) == true);
+mpf0:
+ mf = arg->qnumbr;
+ 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;
+ }
+#endif
+
+#ifdef HAVE_MPFR
+ int0:
+#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 */
+ PREPEND(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)
+ 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 && (cs1 == 's' || cs1 ==
'c')) {
+ assert(cp == arg->stptr || cp == cpbuf);
+ copy_count = mbc_byte_count(arg->stptr, 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_mpfp_number(arg))
+ tmpval = arg->numbr;
+#ifdef HAVE_MPFR
+ else if (is_mpfp_float(arg)) {
+ mf = arg->qnumbr;
+ fmt_type = MP_FLOAT;
+ } else {
+ /* arbitrary-precision integer, convert to MPFR
float */
+ assert(mf == NULL);
+ mf = mpz2mpfr(arg->qnumbr, _mpfrval);
+ 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 && isalpha(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;
}
-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 c0bf38a..d61fea0 100644
--- a/msg.c
+++ b/msg.c
@@ -63,26 +63,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);
@@ -98,6 +88,42 @@ err(bool isfatal, const char *s, const char *emsg, va_list
argp)
}
}
+
+/*
+ * N.B: format is awk printf format, NOT C format or any other special format
+ * supported. MUST NOT throw warning in format tree. "%ld" is BAD, "%d" is Ok!
+ */
+
+
+/* N.B: FORMAT must pass fmt_ok() used to check CONVFMT/OFMT specifier */
+
+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);
+
+ 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 02c78ae..9efd767 100644
--- a/node.c
+++ b/node.c
@@ -25,240 +25,20 @@
*/
#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 *(*format_tree)(const char *, size_t, NODE **, long);
+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 *);
-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 (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]))
-
-/* 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;
-}
/* r_dupnode --- duplicate a node */
@@ -309,53 +89,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 +189,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);
@@ -893,50 +627,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 c3dea0e..b411fd6 100644
--- a/profile.c
+++ b/profile.c
@@ -330,27 +330,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_concat(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:
@@ -388,6 +367,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))
@@ -971,7 +951,6 @@ prec_level(int type)
return 14;
case Op_exp:
- case Op_exp_i:
return 13;
case Op_preincrement:
@@ -981,23 +960,15 @@ 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:
case Op_assign_concat:
return 8;
@@ -1060,12 +1031,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:
@@ -1206,20 +1171,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 */
diff --git a/test/dumpvars.ok b/test/dumpvars.ok
index 73d3d30..3670b7b 100644
--- a/test/dumpvars.ok
+++ b/test/dumpvars.ok
@@ -16,9 +16,9 @@ NR: 3
OFMT: "%.6g"
OFS: " "
ORS: "\n"
-PREC: 53
+PREC: 0
RLENGTH: 0
-ROUNDMODE: "N"
+ROUNDMODE: ""
RS: "\n"
RSTART: 0
RT: "\n"
diff --git a/test/symtab1.ok b/test/symtab1.ok
index 04709e0..dc6a1b7 100644
--- a/test/symtab1.ok
+++ b/test/symtab1.ok
@@ -1,6 +1,6 @@
ARGV[0] = gawk
SYMTAB["i"] = "i"
-SYMTAB["ROUNDMODE"] = "N"
+SYMTAB["ROUNDMODE"] = ""
SYMTAB["ORS"] = "
"
SYMTAB["OFS"] = " "
@@ -18,7 +18,7 @@ SYMTAB["ARGC"] = "1"
SYMTAB["FIELDWIDTHS"] = ""
SYMTAB["CONVFMT"] = "%.6g"
SYMTAB["SUBSEP"] = ""
-SYMTAB["PREC"] = "53"
+SYMTAB["PREC"] = "0"
SYMTAB["RS"] = "
"
SYMTAB["FPAT"] = "[^[:space:]]+"
diff --git a/test/symtab6.ok b/test/symtab6.ok
index 91f27e7..a1fcfb9 100644
--- a/test/symtab6.ok
+++ b/test/symtab6.ok
@@ -16,9 +16,9 @@ NR: 0
OFMT: "%.6g"
OFS: " "
ORS: "\n"
-PREC: 53
+PREC: 0
RLENGTH: 0
-ROUNDMODE: "N"
+ROUNDMODE: ""
RS: "\n"
RSTART: 0
RT: ""
diff --git a/test/symtab8.ok b/test/symtab8.ok
index 8560c75..f0adb1a 100644
--- a/test/symtab8.ok
+++ b/test/symtab8.ok
@@ -17,9 +17,9 @@ NR: 1
OFMT: "%.6g"
OFS: " "
ORS: "\n"
-PREC: 53
+PREC: 0
RLENGTH: 0
-ROUNDMODE: "N"
+ROUNDMODE: ""
RS: "\n"
RSTART: 0
RT: "\n"
-----------------------------------------------------------------------
hooks/post-receive
--
gawk
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [gawk-diffs] [SCM] gawk branch, num-handler, created. bb146e0626acb7e3020f037303fdc8890cb84b46,
John Haque <=