gawk-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[gawk-diffs] [SCM] gawk branch, gawk_performance, created. dae23ec258049


From: John Haque
Subject: [gawk-diffs] [SCM] gawk branch, gawk_performance, created. dae23ec25804903a6c2b7094a2ebd5541e92bb88
Date: Sat, 20 Aug 2011 13:39:00 +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, gawk_performance has been created
        at  dae23ec25804903a6c2b7094a2ebd5541e92bb88 (commit)

- Log -----------------------------------------------------------------
http://git.sv.gnu.org/cgit/gawk.git/commit/?id=dae23ec25804903a6c2b7094a2ebd5541e92bb88

commit dae23ec25804903a6c2b7094a2ebd5541e92bb88
Author: john haque <address@hidden>
Date:   Sat Aug 20 08:28:02 2011 -0500

    Speed/memory performance improvements.

diff --git a/Makefile.am b/Makefile.am
index 855a5e7..1502694 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -84,6 +84,7 @@ base_sources = \
        awk.h \
        awkgram.y \
        builtin.c \
+       cint_array.c \
        custom.h \
        dfa.c \
        dfa.h \
@@ -97,6 +98,7 @@ base_sources = \
        getopt1.c \
        getopt_int.h \
        gettext.h \
+       int_array.c \
        io.c \
        mbsupport.h \
        main.c \
@@ -109,6 +111,8 @@ base_sources = \
        regex.c \
        regex.h \
        replace.c \
+       str_array.c \
+       symbol.c \
        version.c \
        xalloc.h
 
diff --git a/Makefile.in b/Makefile.in
index 2801c61..56f0002 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -88,11 +88,13 @@ CONFIG_CLEAN_VPATH_FILES =
 am__installdirs = "$(DESTDIR)$(bindir)"
 PROGRAMS = $(bin_PROGRAMS)
 am__objects_1 = array.$(OBJEXT) awkgram.$(OBJEXT) builtin.$(OBJEXT) \
-       dfa.$(OBJEXT) ext.$(OBJEXT) field.$(OBJEXT) \
-       floatcomp.$(OBJEXT) gawkmisc.$(OBJEXT) getopt.$(OBJEXT) \
-       getopt1.$(OBJEXT) io.$(OBJEXT) main.$(OBJEXT) msg.$(OBJEXT) \
-       node.$(OBJEXT) random.$(OBJEXT) re.$(OBJEXT) regex.$(OBJEXT) \
-       replace.$(OBJEXT) version.$(OBJEXT)
+       cint_array.$(OBJEXT) dfa.$(OBJEXT) ext.$(OBJEXT) \
+       field.$(OBJEXT) floatcomp.$(OBJEXT) gawkmisc.$(OBJEXT) \
+       getopt.$(OBJEXT) getopt1.$(OBJEXT) int_array.$(OBJEXT) \
+       io.$(OBJEXT) main.$(OBJEXT) msg.$(OBJEXT) node.$(OBJEXT) \
+       random.$(OBJEXT) re.$(OBJEXT) regex.$(OBJEXT) \
+       replace.$(OBJEXT) str_array.$(OBJEXT) symbol.$(OBJEXT) \
+       version.$(OBJEXT)
 am_dgawk_OBJECTS = $(am__objects_1) eval_d.$(OBJEXT) profile.$(OBJEXT) \
        command.$(OBJEXT) debug.$(OBJEXT)
 dgawk_OBJECTS = $(am_dgawk_OBJECTS)
@@ -359,6 +361,7 @@ base_sources = \
        awk.h \
        awkgram.y \
        builtin.c \
+       cint_array.c \
        custom.h \
        dfa.c \
        dfa.h \
@@ -372,6 +375,7 @@ base_sources = \
        getopt1.c \
        getopt_int.h \
        gettext.h \
+       int_array.c \
        io.c \
        mbsupport.h \
        main.c \
@@ -384,6 +388,8 @@ base_sources = \
        regex.c \
        regex.h \
        replace.c \
+       str_array.c \
+       symbol.c \
        version.c \
        xalloc.h
 
@@ -516,6 +522,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@
@@ -528,6 +535,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@
@@ -538,6 +546,8 @@ 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@
address@hidden@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
 @AMDEP_TRUE@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
 
 .c.o:
diff --git a/array.c b/array.c
index 84b9a91..9b12e97 100644
--- a/array.c
+++ b/array.c
@@ -1,5 +1,5 @@
 /*
- * array.c - routines for associative arrays.
+ * array.c - routines for awk arrays.
  */
 
 /* 
@@ -25,69 +25,190 @@
 
 #include "awk.h"
 
-/*
- * Tree walks (``for (iggy in foo)'') and array deletions use expensive
- * linear searching.  So what we do is start out with small arrays and
- * grow them as needed, so that our arrays are hopefully small enough,
- * most of the time, that they're pretty full and we're not looking at
- * wasted space.
- *
- * The decision is made to grow the array if the average chain length is
- * ``too big''. This is defined as the total number of entries in the table
- * divided by the size of the array being greater than some constant.
- *
- * We make the constant a variable, so that it can be tweaked
- * via environment variable.
- */
-
-static size_t AVG_CHAIN_MAX = 2;       /* Modern machines are bigger, reduce 
this from 10. */
+extern FILE *output_fp;
+extern NODE **fmt_list;          /* declared in eval.c */
+extern array_ptr str_array_func[];
+extern array_ptr cint_array_func[];
+extern array_ptr int_array_func[];
 
 static size_t SUBSEPlen;
 static char *SUBSEP;
+static char indent_char[] = "    ";
 
-static NODE *assoc_find(NODE *symbol, NODE *subs, unsigned long hash1, NODE 
**last);
-static void grow_table(NODE *symbol);
+static NODE **e_lookup(NODE *symbol, NODE *subs);
+static array_ptr empty_array_func[NUM_AFUNCS] = {
+       (array_ptr) 0,
+       (array_ptr) 0,
+       e_lookup,
+};
 
-static unsigned long gst_hash_string(const char *str, size_t len, unsigned 
long hsize, size_t *code);
-static unsigned long scramble(unsigned long x);
-static unsigned long awk_hash(const char *s, size_t len, unsigned long hsize, 
size_t *code);
+#define MAX_ATYPE 10
 
-unsigned long (*hash)(const char *s, size_t len, unsigned long hsize, size_t 
*code) = awk_hash;
+static array_ptr *atypes[MAX_ATYPE];
+static int num_atypes = 0;
 
-/* qsort comparison function */
-static int sort_up_index_string(const void *, const void *);
-static int sort_down_index_string(const void *, const void *);
-static int sort_up_index_number(const void *, const void *);
-static int sort_down_index_number(const void *, const void *);
-static int sort_up_value_string(const void *, const void *);
-static int sort_down_value_string(const void *, const void *);
-static int sort_up_value_number(const void *, const void *);
-static int sort_down_value_number(const void *, const void *);
-static int sort_up_value_type(const void *, const void *);
-static int sort_down_value_type(const void *, const void *);
+/*
+ *     index 0 : initialization.
+ *     index 1 : check if index is compatible.
+ *     index 8 : array dump, memory and other statistics (do_adump).
+ *                Also used by debugger 'examine' command.
+ */
+ 
+
+int
+register_array_func(array_ptr *afunc)
+{
+       if (afunc && num_atypes < MAX_ATYPE) {
+               if (afunc != str_array_func && ! afunc[1])
+                       return FALSE;
+               atypes[num_atypes++] = afunc;
+               if (afunc[0])   /* execute init routine if any */
+                       (void) (*afunc[0])(NULL, NULL);
+               return TRUE;
+       }
+       return FALSE;
+}
 
-/* array_init --- check relevant environment variables */
+/* array_init --- register all builtin array types */
 
 void
 array_init()
 {
-       const char *val;
-       char *endptr;
-       size_t newval;
-
-       if ((val = getenv("AVG_CHAIN_MAX")) != NULL && isdigit((unsigned char) 
*val)) {
-               newval = strtoul(val, & endptr, 10);
-               if (endptr != val && newval > 0)
-                       AVG_CHAIN_MAX = newval;
+       (void) register_array_func(str_array_func);     /* the default */
+       (void) register_array_func(int_array_func);
+       (void) register_array_func(cint_array_func);
+}
+
+/* make_array --- create an array node */
+
+NODE *
+make_array()
+{
+       NODE *array;
+       getnode(array);
+       memset(array, '\0', sizeof(NODE));
+       array->type = Node_var_array;
+       array->array_funcs = empty_array_func;
+       /* vname, flags, and parent_array not set here */
+
+       return array;
+}              
+
+
+/* init_array --- initialize an array node */
+
+void
+init_array(NODE *symbol)
+{
+       symbol->type = Node_var_array;
+       symbol->array_funcs = empty_array_func;
+       symbol->buckets = NULL;
+       symbol->table_size = symbol->array_size = 0;
+       symbol->array_capacity = 0;
+
+       assert(symbol->xarray == NULL);
+       /* symbol->xarray = NULL; */
+
+       /* flags, vname, parent_array not (re)initialized */
+}
+
+
+/* e_lookup: assign type to an empty array. */
+
+static NODE **
+e_lookup(NODE *symbol, NODE *subs)
+{
+       int i;
+       array_ptr *afunc = NULL;
+
+       assert(array_empty(symbol) == TRUE);
+
+       /* Check which array type wants to accept this sub; traverse
+        * array type list in reverse order.
+        */
+       for (i = num_atypes - 1; i >= 1; i--) {
+               afunc = atypes[i];
+               if (afunc[1](symbol, subs) != NULL)
+                       break;
+       }
+       if (i == 0 || afunc == NULL)
+               afunc = atypes[0];      /* default is str_array_func */
+       symbol->array_funcs = afunc;
+
+       /* We have the right type of array; install the subscript */
+       return symbol->alookup(symbol, subs);
+}
+
+
+/* assoc_clear --- flush all the values in symbol[] */
+
+void
+assoc_clear(NODE *symbol)
+{
+       if (! array_empty(symbol))
+               (void) symbol->aclear(symbol, NULL);
+}
+
+
+/* r_in_array --- test whether the array element symbol[subs] exists or not,
+ *     return pointer to value if it does.
+ */
+
+NODE *
+r_in_array(NODE *symbol, NODE *subs)
+{
+       NODE **ret;
+
+       if (array_empty(symbol))
+               return NULL;
+       ret = symbol->aexists(symbol, subs);
+       return (ret ? *ret : NULL);
+}
+
+
+/* assoc_remove --- remove an index from symbol[] */
+
+int
+assoc_remove(NODE *symbol, NODE *subs)
+{
+       if (array_empty(symbol))
+               return FALSE;
+       return (symbol->aremove(symbol, subs) != NULL);
+}
+
+
+/* assoc_copy --- duplicate input array "symbol" */
+
+NODE *
+assoc_copy(NODE *symbol, NODE *newsymb)
+{
+       assert(newsymb->vname != NULL);
+
+       assoc_clear(newsymb);
+       if (! array_empty(symbol)) {
+               (void) symbol->acopy(symbol, newsymb);
+               newsymb->array_funcs = symbol->array_funcs;
+               newsymb->flags = symbol->flags;
        }
+       return newsymb;
+}
 
-       if ((val = getenv("AWK_HASH")) != NULL && strcmp(val, "gst") == 0)
-               hash = gst_hash_string; 
+
+/* assoc_dump --- dump array */
+
+void
+assoc_dump(NODE *symbol, NODE *ndump)
+{
+       if (array_empty(symbol))
+               fprintf(output_fp, "array `%s' is empty\n", 
array_vname(symbol));
+       else if (symbol->adump) 
+               (void) symbol->adump(symbol, ndump);
 }
 
+
 /* make_aname --- construct a 'vname' for a (sub)array */
 
-static char *
+const char *
 make_aname(const NODE *symbol)
 {
        static char *aname = NULL;
@@ -115,10 +236,11 @@ make_aname(const NODE *symbol)
                        erealloc(aname, char *, (max_alen + 1) * sizeof(char 
*), "make_aname");
                }
                memcpy(aname, symbol->vname, alen + 1);
-       } 
+       }
        return aname;
-#undef SLEN
 }
+#undef SLEN
+
 
 /*
  * array_vname --- print the name of the array
@@ -128,7 +250,7 @@ make_aname(const NODE *symbol)
  * to save it, they have to make a copy.
  */
 
-char *
+const char *
 array_vname(const NODE *symbol)
 {
        static char *message = NULL;
@@ -164,7 +286,6 @@ array_vname(const NODE *symbol)
        else
                aname = make_aname(symbol);
        len += strlen(aname);
-
        /*
         * Each node contributes by strlen(from) minus the length
         * of "%s" in the translation (which is at least 2)
@@ -218,7 +339,7 @@ get_array(NODE *symbol, int canfatal)
        NODE *save_symbol = symbol;
        int isparam = FALSE;
 
-       if (symbol->type == Node_param_list && (symbol->flags & FUNC) == 0) {
+       if (symbol->type == Node_param_list) {
                save_symbol = symbol = GET_PARAM(symbol->param_cnt);
                isparam = TRUE;
                if (symbol->type == Node_array_ref)
@@ -227,35 +348,24 @@ get_array(NODE *symbol, int canfatal)
 
        switch (symbol->type) {
        case Node_var_new:
-               symbol->type = Node_var_array;
-               symbol->var_array = NULL;
+               init_array(symbol);
                symbol->parent_array = NULL;    /* main array has no parent */
                /* fall through */
        case Node_var_array:
                break;
 
        case Node_array_ref:
-       case Node_param_list:
-               if ((symbol->flags & FUNC) == 0)
-                       cant_happen();
-               /* else
-                       fall through */
-
        default:
-               /* notably Node_var but catches also e.g. FS[1] = "x" */
+               /* notably Node_var but catches also e.g. a[1] = "x"; a[1][1] = 
"y" */
                if (canfatal) {
                        if (symbol->type == Node_val)
                                fatal(_("attempt to use a scalar value as 
array"));
-
-                       if ((symbol->flags & FUNC) != 0)
-                               fatal(_("attempt to use function `%s' as an 
array"),
-                                                               
save_symbol->vname);
-                       else if (isparam)
+                       if (isparam)
                                fatal(_("attempt to use scalar parameter `%s' 
as an array"),
-                                                               
save_symbol->vname);
+                                       save_symbol->vname);
                        else
                                fatal(_("attempt to use scalar `%s' as an 
array"),
-                                                               
save_symbol->vname);
+                                       save_symbol->vname);
                } else
                        break;
        }
@@ -269,16 +379,18 @@ get_array(NODE *symbol, int canfatal)
 void
 set_SUBSEP()
 {
-       SUBSEP = force_string(SUBSEP_node->var_value)->stptr;
+       SUBSEP_node->var_value = force_string(SUBSEP_node->var_value);
+       SUBSEP = SUBSEP_node->var_value->stptr;
        SUBSEPlen = SUBSEP_node->var_value->stlen;
-}                     
+}
+
 
 /* concat_exp --- concatenate expression list into a single string */
 
 NODE *
 concat_exp(int nargs, int do_subsep)
 {
-       /* do_subsep is false for Node-concat */
+       /* do_subsep is FALSE for Op_concat */
        NODE *r;
        char *str;
        char *s;
@@ -295,13 +407,14 @@ concat_exp(int nargs, int do_subsep)
 
        len = 0;
        for (i = 1; i <= nargs; i++) {
-               r = POP();
+               r = TOP();
                if (r->type == Node_var_array) {
                        while (--i > 0)
                                DEREF(args_array[i]);   /* avoid memory leak */
                        fatal(_("attempt to use array `%s' in a scalar 
context"), array_vname(r));
-               } 
-               args_array[i] = force_string(r);
+               }
+               r = POP_STRING();
+               args_array[i] = r;
                len += r->stlen;
        }
        len += (nargs - 1) * subseplen;
@@ -325,247 +438,7 @@ concat_exp(int nargs, int do_subsep)
                DEREF(r);
        }
 
-       return make_str_node(str, len, ALREADY_MALLOCED);
-}
-
-
-/* assoc_clear --- flush all the values in symbol[] */
-
-void
-assoc_clear(NODE *symbol)
-{
-       long i;
-       NODE *bucket, *next;
-
-       if (symbol->var_array == NULL)
-               return;
-
-       for (i = 0; i < symbol->array_size; i++) {
-               for (bucket = symbol->var_array[i]; bucket != NULL; bucket = 
next) {
-                       next = bucket->ahnext;
-                       if (bucket->ahvalue->type == Node_var_array) {
-                               NODE *r = bucket->ahvalue;
-                               assoc_clear(r);         /* recursively clear 
all sub-arrays */
-                               efree(r->vname);                        
-                               freenode(r);
-                       } else
-                               unref(bucket->ahvalue);
-
-                       unref(bucket);  /* unref() will free the ahname_str */
-               }
-               symbol->var_array[i] = NULL;
-       }
-       efree(symbol->var_array);
-       symbol->var_array = NULL;
-       symbol->array_size = symbol->table_size = 0;
-       symbol->flags &= ~ARRAYMAXED;
-}
-
-/* awk_hash --- calculate the hash function of the string in subs */
-
-static unsigned long
-awk_hash(const char *s, size_t len, unsigned long hsize, size_t *code)
-{
-       unsigned long h = 0;
-       unsigned long htmp;
-
-       /*
-        * Ozan Yigit's original sdbm hash, copied from Margo Seltzers
-        * db package.
-        *
-        * This is INCREDIBLY ugly, but fast.  We break the string up into
-        * 8 byte units.  On the first time through the loop we get the
-        * "leftover bytes" (strlen % 8).  On every other iteration, we
-        * perform 8 HASHC's so we handle all 8 bytes.  Essentially, this
-        * saves us 7 cmp & branch instructions.  If this routine is
-        * heavily used enough, it's worth the ugly coding.
-        */
-
-       /*
-        * Even more speed:
-        * #define HASHC   h = *s++ + 65599 * h
-        * Because 65599 = pow(2, 6) + pow(2, 16) - 1 we multiply by shifts
-        *
-        * 4/2011: Force the results to 32 bits, to get the same
-        * result on both 32- and 64-bit systems. This may be a
-        * bad idea.
-        */
-#define HASHC   htmp = (h << 6);  \
-               h = *s++ + htmp + (htmp << 10) - h ; \
-               htmp &= 0xFFFFFFFF; \
-               h &= 0xFFFFFFFF
-
-       h = 0;
-
-       /* "Duff's Device" */
-       if (len > 0) {
-               size_t loop = (len + 8 - 1) >> 3;
-
-               switch (len & (8 - 1)) {
-               case 0:
-                       do {    /* All fall throughs */
-                               HASHC;
-               case 7:         HASHC;
-               case 6:         HASHC;
-               case 5:         HASHC;
-               case 4:         HASHC;
-               case 3:         HASHC;
-               case 2:         HASHC;
-               case 1:         HASHC;
-                       } while (--loop);
-               }
-       }
-
-       if (code != NULL)
-               *code = h;
-
-       if (h >= hsize)
-               h %= hsize;
-       return h;
-}
-
-/* assoc_find --- locate symbol[subs] */
-
-static NODE *                          /* NULL if not found */
-assoc_find(NODE *symbol, NODE *subs, unsigned long hash1, NODE **last)
-{
-       NODE *bucket, *prev;
-       const char *s1_str;
-       size_t s1_len;
-       NODE *s2;
-
-       for (prev = NULL, bucket = symbol->var_array[hash1]; bucket != NULL;
-                       prev = bucket, bucket = bucket->ahnext) {
-               /*
-                * This used to use cmp_nodes() here.  That's wrong.
-                * Array indices are strings; compare as such, always!
-                */
-               s1_str = bucket->ahname_str;
-               s1_len = bucket->ahname_len;
-               s2 = subs;
-
-               if (s1_len == s2->stlen) {
-                       if (s1_len == 0         /* "" is a valid index */
-                           || memcmp(s1_str, s2->stptr, s1_len) == 0)
-                               break;
-               }
-       }
-       if (last != NULL)
-               *last = prev;
-       return bucket;
-}
-
-/* in_array --- test whether the array element symbol[subs] exists or not,
- *             return pointer to value if it does.
- */
-
-NODE *
-in_array(NODE *symbol, NODE *subs)
-{
-       unsigned long hash1;
-       NODE *ret;
-
-       assert(symbol->type == Node_var_array);
-
-       if (symbol->var_array == NULL)
-               return NULL;
-
-       hash1 = hash(subs->stptr, subs->stlen, (unsigned long) 
symbol->array_size, NULL);
-       ret = assoc_find(symbol, subs, hash1, NULL);
-       return (ret ? ret->ahvalue : NULL);
-}
-
-/*
- * assoc_lookup:
- * Find SYMBOL[SUBS] in the assoc array.  Install it with value "" if it
- * isn't there. Returns a pointer ala get_lhs to where its value is stored.
- *
- * SYMBOL is the address of the node (or other pointer) being dereferenced.
- * SUBS is a number or string used as the subscript. 
- */
-
-NODE **
-assoc_lookup(NODE *symbol, NODE *subs, int reference)
-{
-       unsigned long hash1;
-       NODE *bucket;
-       size_t code;
-
-       assert(symbol->type == Node_var_array);
-
-       (void) force_string(subs);
-
-       if (symbol->var_array == NULL) {
-               symbol->array_size = symbol->table_size = 0;    /* sanity */
-               symbol->flags &= ~ARRAYMAXED;
-               grow_table(symbol);
-               hash1 = hash(subs->stptr, subs->stlen,
-                               (unsigned long) symbol->array_size, & code);
-       } else {
-               hash1 = hash(subs->stptr, subs->stlen,
-                               (unsigned long) symbol->array_size, & code);
-               bucket = assoc_find(symbol, subs, hash1, NULL);
-               if (bucket != NULL)
-                       return &(bucket->ahvalue);
-       }
-
-       if (do_lint && reference) {
-               lintwarn(_("reference to uninitialized element `%s[\"%.*s\"]'"),
-                     array_vname(symbol), (int)subs->stlen, subs->stptr);
-       }
-
-       /* It's not there, install it. */
-       if (do_lint && subs->stlen == 0)
-               lintwarn(_("subscript of array `%s' is null string"),
-                       array_vname(symbol));
-
-       /* first see if we would need to grow the array, before installing */
-       symbol->table_size++;
-       if ((symbol->flags & ARRAYMAXED) == 0
-           && (symbol->table_size / symbol->array_size) > AVG_CHAIN_MAX) {
-               grow_table(symbol);
-               /* have to recompute hash value for new size */
-               hash1 = code % (unsigned long) symbol->array_size;
-       }
-
-       getnode(bucket);
-       bucket->type = Node_ahash;
-
-       /*
-        * Freeze this string value --- it must never
-        * change, no matter what happens to the value
-        * that created it or to CONVFMT, etc.
-        *
-        * One day: Use an atom table to track array indices,
-        * and avoid the extra memory overhead.
-        */
-       bucket->flags |= MALLOC;
-       bucket->ahname_ref = 1;
-
-       emalloc(bucket->ahname_str, char *, subs->stlen + 2, "assoc_lookup");
-       bucket->ahname_len = subs->stlen;
-       memcpy(bucket->ahname_str, subs->stptr, subs->stlen);
-       bucket->ahname_str[bucket->ahname_len] = '\0';
-       bucket->ahvalue = Nnull_string;
- 
-       bucket->ahnext = symbol->var_array[hash1];
-       bucket->ahcode = code;
-
-       /*
-        * Set the numeric value for the index if it's  available. Useful
-        * for numeric sorting by index.  Do this only if the numeric
-        * value is available, instead of all the time, since doing it
-        * all the time is a big performance hit for something that may
-        * never be used.
-        */
-       if ((subs->flags & NUMCUR) != 0) {
-               bucket->ahname_num = subs->numbr;
-               bucket->flags |= NUMIND;
-       }
-
-       /* hook it into the symbol table */
-       symbol->var_array[hash1] = bucket;
-       return &(bucket->ahvalue);
+       return make_str_node(str, len);
 }
 
 
@@ -602,7 +475,7 @@ adjust_fcall_stack(NODE *symbol, int nsubs)
        func = frame_ptr->func_node;
        if (func == NULL)       /* in main */
                return;
-       pcount = func->lnode->param_cnt;
+       pcount = func->param_cnt;
        sp = frame_ptr->stack;
 
        for (; pcount > 0; pcount--) {
@@ -627,12 +500,10 @@ adjust_fcall_stack(NODE *symbol, int nsubs)
                         *   function f(c, d) { delete c; ..}
                         *   BEGIN { a[0][0] = 1; f(a[0], a[0]); ...}  
                         */
-                       char *save;
-local_array:
-                       save = r->vname;
-                       memset(r, '\0', sizeof(NODE));
-                       r->vname = save;
-                       r->type = Node_var_array;
+
+                       init_array(r);
+                       r->parent_array = NULL;
+                       r->flags = 0;
                        continue;
                }                       
 
@@ -648,8 +519,10 @@ local_array:
                                 *    BEGIN { a[0][0][0][0] = 1; f(a[0], 
a[0][0][0]); .. }
                                 *
                                 */
-
-                               goto local_array;
+                               init_array(r);
+                               r->parent_array = NULL;
+                               r->flags = 0;
+                               break;
                        }
                }
        }
@@ -660,18 +533,17 @@ local_array:
 
 /*
  * `symbol' is array
- * `nsubs' is number of subscripts
+ * `nsubs' is no of subscripts
  */
 
 void
 do_delete(NODE *symbol, int nsubs)
 {
-       unsigned long hash1 = 0;
-       NODE *subs, *bucket, *last, *r;
+       NODE *val, *subs;
        int i;
 
        assert(symbol->type == Node_var_array);
-       subs = bucket = last = r = NULL;        /* silence the compiler */
+       subs = val = NULL;      /* silence the compiler */
 
        /*
         * The force_string() call is needed to make sure that
@@ -683,16 +555,17 @@ do_delete(NODE *symbol, int nsubs)
         * Without it, the code does not fail.
         */
 
-#define free_subs(n) \
-do {                                                           \
+#define free_subs(n)    do {                                    \
     NODE *s = PEEK(n - 1);                                      \
     if (s->type == Node_val) {                                  \
-        (void) force_string(s);        /* may have side effects ? */   \
+        (void) force_string(s);        /* may have side effects. */    \
         DEREF(s);                                               \
     }                                                           \
 } while (--n > 0)
 
-       if (nsubs == 0) {       /* delete array */
+       if (nsubs == 0) {
+               /* delete array */
+
                adjust_fcall_stack(symbol, 0);  /* fix function call stack; See 
above. */
                assoc_clear(symbol);
                return;
@@ -706,66 +579,46 @@ do {                                                      
        \
                        free_subs(i);
                        fatal(_("attempt to use array `%s' in a scalar 
context"), array_vname(subs));
                }
-               (void) force_string(subs);
 
-               last = NULL;    /* shut up gcc -Wall */
-               hash1 = 0;      /* ditto */
-               bucket = NULL;  /* array may be empty */
-
-               if (symbol->var_array != NULL) {
-                       hash1 = hash(subs->stptr, subs->stlen,
-                                       (unsigned long) symbol->array_size, 
NULL);
-                       bucket = assoc_find(symbol, subs, hash1, &last);
-               }
-
-               if (bucket == NULL) {
-                       if (do_lint)
+               val = in_array(symbol, subs);
+               if (val == NULL) {
+                       if (do_lint) {
+                               subs = force_string(subs);
                                lintwarn(_("delete: index `%s' not in array 
`%s'"),
                                        subs->stptr, array_vname(symbol));
+                       }
                        /* avoid memory leak, free all subs */
                        free_subs(i);
                        return;
                }
 
                if (i > 1) {
-                       if (bucket->ahvalue->type != Node_var_array) {
+                       if (val->type != Node_var_array) {
                                /* e.g.: a[1] = 1; delete a[1][1] */
+
                                free_subs(i);
+                               subs = force_string(subs);
                                fatal(_("attempt to use scalar `%s[\"%.*s\"]' 
as an array"),
                                        array_vname(symbol),
-                                       (int) bucket->ahname_len,
-                                       bucket->ahname_str);
+                                       (int) subs->stlen,
+                                       subs->stptr);
                        }
-                       symbol = bucket->ahvalue;
+                       symbol = val;
+                       DEREF(subs);
                }
-               DEREF(subs);
        }
 
-       r = bucket->ahvalue;
-       if (r->type == Node_var_array) {
-               adjust_fcall_stack(r, nsubs);   /* fix function call stack; See 
above. */
-               assoc_clear(r);
+       if (val->type == Node_var_array) {
+               adjust_fcall_stack(val, nsubs);  /* fix function call stack; 
See above. */
+               assoc_clear(val);
                /* cleared a sub-array, free Node_var_array */
-               efree(r->vname);
-               freenode(r);
+               efree(val->vname);
+               freenode(val);
        } else
-               unref(r);
+               unref(val);
 
-       if (last != NULL)
-               last->ahnext = bucket->ahnext;
-       else
-               symbol->var_array[hash1] = bucket->ahnext;
-
-       unref(bucket);  /* unref() will free the ahname_str */
-       symbol->table_size--;
-       if (symbol->table_size <= 0) {
-               symbol->table_size = symbol->array_size = 0;
-               symbol->flags &= ~ARRAYMAXED;
-               if (symbol->var_array != NULL) {
-                       efree(symbol->var_array);
-                       symbol->var_array = NULL;
-               }
-       }
+       (void) assoc_remove(symbol, subs);
+       DEREF(subs);
 
 #undef free_subs
 }
@@ -782,272 +635,159 @@ do {                                                    
        \
 void
 do_delete_loop(NODE *symbol, NODE **lhs)
 {
-       long i;
-
-       assert(symbol->type == Node_var_array);
+       NODE **list;
+       NODE fl;
 
-       if (symbol->var_array == NULL)
+       if (array_empty(symbol))
                return;
 
-       /* get first index value */
-       for (i = 0; i < symbol->array_size; i++) {
-               if (symbol->var_array[i] != NULL) {
-                       unref(*lhs);
-                       *lhs = make_string(symbol->var_array[i]->ahname_str,
-                                       symbol->var_array[i]->ahname_len);
-                       break;
-               }
-       }
+       fl.flags = AINDEX|ADELETE;      /* need a single index */
+       list = symbol->alist(symbol, & fl);
+       assert(list != NULL);
+
+       unref(*lhs);
+       *lhs = list[0];
+       efree(list);
 
        /* blast the array in one shot */
-       adjust_fcall_stack(symbol, 0);
+       adjust_fcall_stack(symbol, 0);  
        assoc_clear(symbol);
 }
 
-/* grow_table --- grow a hash table */
+
+/* value_info --- print scalar node info */
+
+int PREC_NUM = -1;
+int PREC_STR = -1;
 
 static void
-grow_table(NODE *symbol)
+value_info(NODE *n)
 {
-       NODE **old, **new, *chain, *next;
-       int i, j;
-       unsigned long hash1;
-       unsigned long oldsize, newsize, k;
-       /*
-        * This is an array of primes. We grow the table by an order of
-        * magnitude each time (not just doubling) so that growing is a
-        * rare operation. We expect, on average, that it won't happen
-        * more than twice.  When things are very large (> 8K), we just
-        * double more or less, instead of just jumping from 8K to 64K.
-        */
-       static const long sizes[] = {
-               13, 127, 1021, 8191, 16381, 32749, 65497, 131101, 262147,
-               524309, 1048583, 2097169, 4194319, 8388617, 16777259, 33554467, 
-               67108879, 134217757, 268435459, 536870923, 1073741827
-       };
-
-       /* find next biggest hash size */
-       newsize = oldsize = symbol->array_size;
-       for (i = 0, j = sizeof(sizes)/sizeof(sizes[0]); i < j; i++) {
-               if (oldsize < sizes[i]) {
-                       newsize = sizes[i];
-                       break;
-               }
-       }
-
-       if (newsize == oldsize) {       /* table already at max (!) */
-               symbol->flags |= ARRAYMAXED;
+       if (n == Nnull_string || n == Null_field) {
+               fprintf(output_fp, "<(null)>");
                return;
        }
 
-       /* allocate new table */
-       emalloc(new, NODE **, newsize * sizeof(NODE *), "grow_table");
-       memset(new, '\0', newsize * sizeof(NODE *));
+       if ((n->flags & (STRING|STRCUR)) != 0) {
+               fprintf(output_fp, "<");
+               fprintf(output_fp, "\"%.*s\"", PREC_STR, n->stptr);
+               if ((n->flags & (NUMBER|NUMCUR)) != 0)
+                       fprintf(output_fp, ":%.*g", PREC_NUM, n->numbr);
+               fprintf(output_fp, ">");
+       } else
+               fprintf(output_fp, "<%.*g>", PREC_NUM, n->numbr);
 
-       /* brand new hash table, set things up and return */
-       if (symbol->var_array == NULL) {
-               symbol->table_size = 0;
-               goto done;
-       }
+       fprintf(output_fp, ":%s", flags2str(n->flags));
 
-       /* old hash table there, move stuff to new, free old */
-       old = symbol->var_array;
-       for (k = 0; k < oldsize; k++) {
-               if (old[k] == NULL)
-                       continue;
-
-               for (chain = old[k]; chain != NULL; chain = next) {
-                       next = chain->ahnext;
-                       hash1 = chain->ahcode % newsize;
+       if ((n->flags & FIELD) == 0)
+               fprintf(output_fp, ":%ld", n->valref);
+       else
+               fprintf(output_fp, ":");
 
-                       /* remove from old list, add to new */
-                       chain->ahnext = new[hash1];
-                       new[hash1] = chain;
-               }
+       if ((n->flags & (STRING|STRCUR)) == STRCUR) {
+               fprintf(output_fp, "][");
+               fprintf(output_fp, "stfmt=%d, ", n->stfmt);     
+               fprintf(output_fp, "CONVFMT=\"%s\"", n->stfmt <= -1 ? "%ld"
+                                       : fmt_list[n->stfmt]->stptr);
        }
-       efree(old);
-
-done:
-       /*
-        * note that symbol->table_size does not change if an old array,
-        * and is explicitly set to 0 if a new one.
-        */
-       symbol->var_array = new;
-       symbol->array_size = newsize;
 }
 
-/* pr_node --- print simple node info */
 
-static void
-pr_node(NODE *n)
+#ifdef ARRAYDEBUG
+
+NODE *
+do_aoption(int nargs)
 {
-       if ((n->flags & NUMBER) != 0)
-               printf("%s %g p: %p", flags2str(n->flags), n->numbr, n);
-       else
-               printf("%s %.*s p: %p", flags2str(n->flags),
-                               (int) n->stlen, n->stptr, n);
+       int ret = -1;
+       NODE *opt, *val;
+       int i;
+       array_ptr *afunc;
+
+       val = POP_SCALAR();
+       opt = POP_SCALAR();
+       for (i = 0; i < num_atypes; i++) {
+               afunc = atypes[i];
+               if (afunc[NUM_AFUNCS] && (*afunc[NUM_AFUNCS])(opt, val) != 
NULL) {
+                       ret = 0;
+                       break;
+               }
+       }
+       DEREF(opt);
+       DEREF(val);
+       return make_number((AWKNUM) ret);
 }
 
+#endif
 
-static void
+void
 indent(int indent_level)
 {
-       int k;
-       for (k = 0; k < indent_level; k++)
-               putchar('\t');
+       int i;
+       for (i = 0; i < indent_level; i++)
+               fprintf(output_fp, "%s", indent_char);
 }
 
-/* assoc_dump --- dump the contents of an array */
+/* assoc_info --- print index, value info */
 
-NODE *
-assoc_dump(NODE *symbol, int indent_level)
+void
+assoc_info(NODE *subs, NODE *val, NODE *ndump, const char *aname)
 {
-       long i;
-       NODE *bucket;
+       int indent_level = ndump->alevel;
 
+       indent_level++;
        indent(indent_level);
-       if (symbol->var_array == NULL) {
-               printf(_("%s: empty (null)\n"), symbol->vname);
-               return make_number((AWKNUM) 0);
-       }
-
-       if (symbol->table_size == 0) {
-               printf(_("%s: empty (zero)\n"), symbol->vname);
-               return make_number((AWKNUM) 0);
-       }
+       fprintf(output_fp, "I: [%s:", aname);
+       if ((subs->flags & INTIND) != 0)
+               fprintf(output_fp, "<%ld>", (long) subs->numbr);
+       else
+               value_info(subs);
+       fprintf(output_fp, "]\n");
 
-       printf(_("%s: table_size = %d, array_size = %d\n"), symbol->vname,
-                       (int) symbol->table_size, (int) symbol->array_size);
-
-       for (i = 0; i < symbol->array_size; i++) {
-               for (bucket = symbol->var_array[i]; bucket != NULL;
-                               bucket = bucket->ahnext) {
-                       indent(indent_level);
-                       printf("%s: I: [len %d <%.*s> p: %p] V: [",
-                               symbol->vname,
-                               (int) bucket->ahname_len,
-                               (int) bucket->ahname_len,
-                               bucket->ahname_str,
-                               bucket->ahname_str);
-                       if (bucket->ahvalue->type == Node_var_array) {
-                               printf("\n");
-                               assoc_dump(bucket->ahvalue, indent_level + 1);
-                               indent(indent_level);
-                       } else
-                               pr_node(bucket->ahvalue);
-                       printf("]\n");
-               }
+       indent(indent_level);
+       if (val->type == Node_val) {
+               fprintf(output_fp, "V: [scalar: ");
+               value_info(val);
+       } else {
+               fprintf(output_fp, "V: [");
+               ndump->alevel++;
+               ndump->adepth--;
+               assoc_dump(val, ndump);
+               ndump->adepth++;
+               ndump->alevel--;
+               indent(indent_level);
        }
-
-       return make_number((AWKNUM) 0);
+       fprintf(output_fp, "]\n");
 }
 
+
 /* do_adump --- dump an array: interface to assoc_dump */
 
 NODE *
 do_adump(int nargs)
 {
-       NODE *r, *a;
+       NODE *symbol, *tmp;
+       static NODE ndump;
+       long depth = 0;
 
-       a = POP();
-       if (a->type == Node_param_list) {
-               printf(_("%s: is parameter\n"), a->vname);
-               a = GET_PARAM(a->param_cnt);
-       }
-       if (a->type == Node_array_ref) {
-               printf(_("%s: array_ref to %s\n"), a->vname,
-                                       a->orig_array->vname);
-               a = a->orig_array;
-       }
-       if (a->type != Node_var_array)
-               fatal(_("adump: argument not an array"));
-       r = assoc_dump(a, 0);
-       return r;
-}
-
-/*
- * The following functions implement the builtin
- * asort function.  Initial work by Alan J. Broder,
- * address@hidden
- */
-
-/* dup_table --- recursively duplicate input array "symbol" */
+       /* depth < 0, no index and value info.
+        *       = 0, main array index and value info; does not descend into 
sub-arrays.
+        *       > 0, descends into 'depth' sub-arrays, and prints index and 
value info.
+        */
 
-static NODE *
-dup_table(NODE *symbol, NODE *newsymb)
-{
-       NODE **old, **new, *chain, *bucket;
-       long i;
-       unsigned long cursize;
-
-       /* find the current hash size */
-       cursize = symbol->array_size;
-
-       new = NULL;
-
-       /* input is a brand new hash table, so there's nothing to copy */
-       if (symbol->var_array == NULL)
-               newsymb->table_size = 0;
-       else {
-               /* old hash table there, dupnode stuff into a new table */
-
-               /* allocate new table */
-               emalloc(new, NODE **, cursize * sizeof(NODE *), "dup_table");
-               memset(new, '\0', cursize * sizeof(NODE *));
-
-               /* do the copying/dupnode'ing */
-               old = symbol->var_array;
-               for (i = 0; i < cursize; i++) {
-                       if (old[i] != NULL) {
-                               for (chain = old[i]; chain != NULL;
-                                               chain = chain->ahnext) {
-                                       /* get a node for the linked list */
-                                       getnode(bucket);
-                                       bucket->type = Node_ahash;
-                                       bucket->flags |= MALLOC;
-                                       bucket->ahname_ref = 1;
-                                       bucket->ahcode = chain->ahcode;
-                                       if ((chain->flags & NUMIND) != 0) {
-                                               bucket->ahname_num = 
chain->ahname_num;
-                                               bucket->flags |= NUMIND;
-                                       }
-
-                                       /*
-                                        * copy the corresponding name and
-                                        * value from the original input list
-                                        */
-                                       emalloc(bucket->ahname_str, char *, 
chain->ahname_len + 2, "dup_table");
-                                       bucket->ahname_len = chain->ahname_len;
-
-                                       memcpy(bucket->ahname_str, 
chain->ahname_str, chain->ahname_len);
-                                       bucket->ahname_str[bucket->ahname_len] 
= '\0';
-
-                                       if (chain->ahvalue->type == 
Node_var_array) {
-                                               NODE *r;
-                                               getnode(r);
-                                               r->type = Node_var_array;
-                                               r->vname = 
estrdup(chain->ahname_str, chain->ahname_len);
-                                               r->parent_array = newsymb;
-                                               bucket->ahvalue = 
dup_table(chain->ahvalue, r);
-                                       } else
-                                               bucket->ahvalue = 
dupnode(chain->ahvalue);
-
-                                       /*
-                                        * put the node on the corresponding
-                                        * linked list in the new table
-                                        */
-                                       bucket->ahnext = new[i];
-                                       new[i] = bucket;
-                               }
-                       }
-               }
-               newsymb->table_size = symbol->table_size;
+       if (nargs == 2) {
+               tmp = POP_SCALAR();
+               depth = (long) force_number(tmp);
+               DEREF(tmp);
        }
-
-       newsymb->var_array = new;
-       newsymb->array_size = cursize;
-       newsymb->flags = symbol->flags; /* ARRAYMAXED */
-       return newsymb;
+       symbol = POP_PARAM();
+       if (symbol->type != Node_var_array)
+               fatal(_("adump: first argument not an array"));
+
+       ndump.type = Node_dump_array;
+       ndump.adepth = depth;
+       ndump.alevel = 0;
+       assoc_dump(symbol, & ndump);
+       return make_number((AWKNUM) 0);
 }
 
 
@@ -1059,15 +799,13 @@ asort_actual(int nargs, SORT_CTXT ctxt)
        NODE *array, *dest = NULL, *result;
        NODE *r, *subs, *s;
        NODE **list, **ptr;
-#define TSIZE  100     /* an arbitrary amount */
-       static char buf[TSIZE+2];
        unsigned long num_elems, i;
        const char *sort_str;
 
        if (nargs == 3)  /* 3rd optional arg */
                s = POP_STRING();
        else
-               s = Nnull_string;       /* "" => default sorting */
+               s = dupnode(Nnull_string);      /* "" => default sorting */
 
        s = force_string(s);
        sort_str = s->stptr;
@@ -1078,7 +816,6 @@ asort_actual(int nargs, SORT_CTXT ctxt)
                        sort_str = "@ind_str_asc";
        }
 
-
        if (nargs >= 2) {  /* 2nd optional arg */
                dest = POP_PARAM();
                if (dest->type != Node_var_array) {
@@ -1107,15 +844,16 @@ asort_actual(int nargs, SORT_CTXT ctxt)
                                fatal(ctxt == ASORT ?
                                        _("asort: cannot use a subarray of 
second arg for first arg") :
                                        _("asorti: cannot use a subarray of 
second arg for first arg"));
-                }
+               }
        }
 
-       num_elems = array->table_size;
-       if (num_elems == 0 || array->var_array == NULL) {       /* source array 
is empty */
+       if (array_empty(array)) {
+               /* source array is empty */
                if (dest != NULL && dest != array)
                        assoc_clear(dest);
                return make_number((AWKNUM) 0);
        }
+       num_elems = array->table_size;
 
        /* sorting happens inside assoc_list */
        list = assoc_list(array, sort_str, ctxt);
@@ -1132,70 +870,52 @@ asort_actual(int nargs, SORT_CTXT ctxt)
                result = dest;
        } else {
                /* use 'result' as a temporary destination array */
-               getnode(result);
-               memset(result, '\0', sizeof(NODE));
-               result->type = Node_var_array;
+               result = make_array();
                result->vname = array->vname;
                result->parent_array = array->parent_array;
        }
 
-       subs = make_str_node(buf, TSIZE, ALREADY_MALLOCED);   /* fake it */
-       subs->flags &= ~MALLOC;         /* safety */
-       for (i = 1, ptr = list; i <= num_elems; i++) {
-               sprintf(buf, "%lu", i);
-               subs->stlen = strlen(buf);
-               /* make number valid in case this array gets sorted later */
-               subs->numbr = i;
-               subs->flags |= NUMCUR;
-               r = *ptr++;
-               if (ctxt == ASORTI) {
-                       /*
-                        * We want the indices of the source array as values
-                        * of the 'result' array.
-                        */
-                       *assoc_lookup(result, subs, FALSE) =
-                                       make_string(r->ahname_str, 
r->ahname_len);
-               } else {
-                       NODE *val;
-
-                       /* We want the values of the source array. */
-
-                       val = r->ahvalue;
-                       if (result != dest) {
-                               /* optimization for dest = NULL or dest = array 
*/
-
-                               if (val->type == Node_var_array) {
-                                       /* update subarray index in parent 
array */
-                                       efree(val->vname);
-                                       val->vname = estrdup(subs->stptr, 
subs->stlen);
-                               } 
-                               *assoc_lookup(result, subs, FALSE) = val;
-                               r->ahvalue = Nnull_string;
-                       } else {
-                               if (val->type == Node_val)
-                                       *assoc_lookup(result, subs, FALSE) = 
dupnode(val);
-                               else {
-                                       NODE *arr;
-
-                                       /*
-                                        * There isn't any reference counting 
for
-                                        * subarrays, so recursively copy 
subarrays
-                                        * using dup_table().
-                                        */
-                                       getnode(arr);
-                                       arr->type = Node_var_array;
-                                       arr->var_array = NULL;
-                                       arr->vname = estrdup(subs->stptr, 
subs->stlen);
-                                       arr->parent_array = array; /* actual 
parent, not the temporary one. */
-                                       *assoc_lookup(result, subs, FALSE) = 
dup_table(val, arr);
-                               }
+       subs = make_number((AWKNUM) 0.0);
+
+       if (ctxt == ASORTI) {
+               /* We want the indices of the source array. */
+
+               for (i = 1, ptr = list; i <= num_elems; i++, ptr += 2) {
+                       subs->numbr = (AWKNUM) i;
+                       r = *ptr;
+                       *assoc_lookup(result, subs) = r;
+               }
+       } else {
+               /* We want the values of the source array. */
+
+               for (i = 1, ptr = list; i <= num_elems; i++) {
+                       subs->numbr = (AWKNUM) i;
+
+                       /* free index node */
+                       r = *ptr++;
+                       unref(r);
+
+                       /* value node */
+                       r = *ptr++;
+
+                       /* FIXME: asort(a) optimization */
+
+                       if (r->type == Node_val)
+                               *assoc_lookup(result, subs) = dupnode(r);
+                       else {
+                               NODE *arr;
+                               arr = make_array();
+                               subs = force_string(subs);
+                               arr->vname = subs->stptr;
+                               subs->stptr = NULL;
+                               subs->flags &= ~STRCUR;
+                               arr->parent_array = array; /* actual parent, 
not the temporary one. */
+                               *assoc_lookup(result, subs) = assoc_copy(r, 
arr);
                        }
                }
+       }
 
-               unref(r);
-       }
-
-       freenode(subs); /* stptr(buf) not malloc-ed */
+       unref(subs);
        efree(list);
 
        if (result != dest) {
@@ -1209,7 +929,6 @@ asort_actual(int nargs, SORT_CTXT ctxt)
 
        return make_number((AWKNUM) num_elems);
 }
-#undef TSIZE
 
 /* do_asort --- sort array by value */
 
@@ -1227,6 +946,7 @@ do_asorti(int nargs)
        return asort_actual(nargs, ASORTI);
 }
 
+
 /*
  * cmp_string --- compare two strings; logic similar to cmp_nodes() in eval.c
  *     except the extra case-sensitive comparison when the case-insensitive
@@ -1241,18 +961,10 @@ cmp_string(const NODE *n1, const NODE *n2)
        int ret;
        size_t lmin;
 
-       assert(n1->type == n2->type);
-       if (n1->type == Node_ahash) {
-               s1 = n1->ahname_str;
-               len1 = n1->ahname_len;
-               s2 =  n2->ahname_str;
-               len2 = n2->ahname_len;
-       } else {
-               s1 = n1->stptr;
-               len1 = n1->stlen;
-               s2 =  n2->stptr;
-               len2 = n2->stlen;
-       }
+       s1 = n1->stptr;
+       len1 = n1->stlen;
+       s2 =  n2->stptr;
+       len2 = n2->stlen;
 
        if (len1 == 0)
                return len2 == 0 ? 0 : -1;
@@ -1303,7 +1015,7 @@ sort_up_index_string(const void *p1, const void *p2)
 }
 
 
-/* sort_down_index_string --- descending index strings */
+/* sort_down_index_str --- qsort comparison function; descending index 
strings. */
 
 static int
 sort_down_index_string(const void *p1, const void *p2)
@@ -1326,24 +1038,23 @@ sort_down_index_string(const void *p1, const void *p2)
 static int
 sort_up_index_number(const void *p1, const void *p2)
 {
-       const NODE *n1, *n2;
+       const NODE *t1, *t2;
        int ret;
 
-       n1 = *((const NODE *const *) p1);
-       n2 = *((const NODE *const *) p2);
+       t1 = *((const NODE *const *) p1);
+       t2 = *((const NODE *const *) p2);
 
-       if (n1->ahname_num < n2->ahname_num)
+       if (t1->numbr < t2->numbr)
                ret = -1;
        else
-               ret = (n1->ahname_num > n2->ahname_num);
+               ret = (t1->numbr > t2->numbr);
 
        /* break a tie with the index string itself */
        if (ret == 0)
-               return cmp_string(n1, n2);
+               return cmp_string(t1, t2);
        return ret;
 }
 
-
 /* sort_down_index_number --- qsort comparison function; descending index 
numbers */
 
 static int
@@ -1359,29 +1070,23 @@ static int
 sort_up_value_string(const void *p1, const void *p2)
 {
        const NODE *t1, *t2;
-       NODE *n1, *n2;
-
-       /* we're passed a pair of index (array subscript) nodes */
-       t1 = *(const NODE *const *) p1;
-       t2 = *(const NODE *const *) p2;
 
-       /* and we want to compare the element values they refer to */
-       n1 = t1->ahvalue;
-       n2 = t2->ahvalue;
+       t1 = *((const NODE *const *) p1 + 1);
+       t2 = *((const NODE *const *) p2 + 1);
 
-       if (n1->type == Node_var_array) {
-               /* return 0 if n2 is a sub-array too, else return 1 */
-               return (n2->type != Node_var_array);
+       if (t1->type == Node_var_array) {
+               /* return 0 if t2 is a sub-array too, else return 1 */
+               return (t2->type != Node_var_array);
        }
-       if (n2->type == Node_var_array)
-               return -1;              /* n1 (scalar) < n2 (sub-array) */
+       if (t2->type == Node_var_array)
+               return -1;              /* t1 (scalar) < t2 (sub-array) */
 
-       /* n1 and n2 both have string values; See sort_force_value_string(). */
-       return cmp_string(n1, n2);
+       /* t1 and t2 both have string values */
+       return cmp_string(t1, t2);
 }
 
 
-/* sort_down_value_string --- descending value string */
+/* sort_down_value_string --- qsort comparison function; descending value 
string */
 
 static int
 sort_down_value_string(const void *p1, const void *p2)
@@ -1389,50 +1094,46 @@ sort_down_value_string(const void *p1, const void *p2)
        return -sort_up_value_string(p1, p2);
 }
 
+
 /* sort_up_value_number --- qsort comparison function; ascending value number 
*/
 
 static int
 sort_up_value_number(const void *p1, const void *p2)
 {
-       const NODE *t1, *t2;
-       NODE *n1, *n2;
+       NODE *t1, *t2;
        int ret;
 
-       /* we're passed a pair of index (array subscript) nodes */
-       t1 = *(const NODE *const *) p1;
-       t2 = *(const NODE *const *) p2;
-
-       /* and we want to compare the element values they refer to */
-       n1 = t1->ahvalue;
-       n2 = t2->ahvalue;
+       t1 = *((NODE *const *) p1 + 1);
+       t2 = *((NODE *const *) p2 + 1);
 
-       if (n1->type == Node_var_array) {
-               /* return 0 if n2 is a sub-array too, else return 1 */
-               return (n2->type != Node_var_array);
+       if (t1->type == Node_var_array) {
+               /* return 0 if t2 is a sub-array too, else return 1 */
+               return (t2->type != Node_var_array);
        }
-       if (n2->type == Node_var_array)
-               return -1;              /* n1 (scalar) < n2 (sub-array) */
+       if (t2->type == Node_var_array)
+               return -1;              /* t1 (scalar) < t2 (sub-array) */
 
-       /* n1 and n2 both Node_val, and force_number'ed */
-       if (n1->numbr < n2->numbr)
+       /* t1 and t2 both Node_val, and force_number'ed */
+       if (t1->numbr < t2->numbr)
                ret = -1;
        else
-               ret = (n1->numbr > n2->numbr);
+               ret = (t1->numbr > t2->numbr);
 
        if (ret == 0) {
                /*
                 * Use string value to guarantee same sort order on all
                 * versions of qsort().
                 */
-               n1 = force_string(n1);
-               n2 = force_string(n2);
-               ret = cmp_string(n1, n2);
+               t1 = force_string(t1);
+               t2 = force_string(t2);
+               ret = cmp_string(t1, t2);
        }
 
        return ret;
 }
 
-/* sort_down_value_number --- descending value number */
+
+/* sort_down_value_number --- qsort comparison function; descending value 
number */
 
 static int
 sort_down_value_number(const void *p1, const void *p2)
@@ -1440,21 +1141,17 @@ sort_down_value_number(const void *p1, const void *p2)
        return -sort_up_value_number(p1, p2);
 }
 
+
 /* sort_up_value_type --- qsort comparison function; ascending value type */
 
 static int
 sort_up_value_type(const void *p1, const void *p2)
 {
-       const NODE *t1, *t2;
        NODE *n1, *n2;
 
-       /* we're passed a pair of index (array subscript) nodes */
-       t1 = *(const NODE *const *) p1;
-       t2 = *(const NODE *const *) p2;
-
-       /* and we want to compare the element values they refer to */
-       n1 = t1->ahvalue;
-       n2 = t2->ahvalue;
+       /* we want to compare the element values */
+       n1 = *((NODE *const *) p1 + 1);
+       n2 = *((NODE *const *) p2 + 1);
 
        /* 1. Arrays vs. scalar, scalar is less than array */
        if (n1->type == Node_var_array) {
@@ -1472,6 +1169,12 @@ sort_up_value_type(const void *p1, const void *p2)
        if ((n2->flags & MAYBE_NUM) != 0)
                (void) force_number(n2);
 
+       /* 2.5. Resolve INTIND, so that is STRING, and not NUMBER */
+       if ((n1->flags & INTIND) != 0)
+               (void) force_string(n1);
+       if ((n2->flags & INTIND) != 0)
+               (void) force_string(n2);
+
        if ((n1->flags & NUMBER) != 0 && (n2->flags & NUMBER) != 0) {
                if (n1->numbr < n2->numbr)
                        return -1;
@@ -1492,7 +1195,7 @@ sort_up_value_type(const void *p1, const void *p2)
        return cmp_string(n1, n2);
 }
 
-/* sort_down_value_type --- descending value type */
+/* sort_down_value_type --- qsort comparison function; descending value type */
 
 static int
 sort_down_value_type(const void *p1, const void *p2)
@@ -1505,27 +1208,26 @@ sort_down_value_type(const void *p1, const void *p2)
 static int
 sort_user_func(const void *p1, const void *p2)
 {
-       const NODE *t1, *t2;
        NODE *idx1, *idx2, *val1, *val2;
        AWKNUM ret;
        INSTRUCTION *code;
        extern int exiting;
 
-       t1 = *((const NODE *const *) p1);
-       t2 = *((const NODE *const *) p2);
-
-       idx1 = make_string(t1->ahname_str, t1->ahname_len);
-       idx2 = make_string(t2->ahname_str, t2->ahname_len);
-       val1 = t1->ahvalue;
-       val2 = t2->ahvalue;
+       idx1 = *((NODE *const *) p1);
+       idx2 = *((NODE *const *) p2);
+       val1 = *((NODE *const *) p1 + 1);
+       val2 = *((NODE *const *) p2 + 1);
 
        code = TOP()->code_ptr; /* comparison function call instructions */
 
        /* setup 4 arguments to comp_func() */
+       UPREF(idx1);
        PUSH(idx1);
        if (val1->type == Node_val)
                UPREF(val1);
        PUSH(val1);
+
+       UPREF(idx2);
        PUSH(idx2);
        if (val2->type == Node_val)
                UPREF(val2);
@@ -1543,113 +1245,73 @@ sort_user_func(const void *p1, const void *p2)
        return (ret < 0.0) ? -1 : (ret > 0.0);
 }
 
-/* sort_force_index_number -- pre-process list items for sorting indices as 
numbers */
-
-static void
-sort_force_index_number(NODE **list, size_t num_elems)
-{
-       size_t i;
-       NODE *r;
-       static NODE temp_node;
-
-       for (i = 0; i < num_elems; i++) {
-               r = list[i];
-
-               if ((r->flags & NUMIND) != 0)   /* once in a lifetime is plenty 
*/
-                       continue;
-               temp_node.type = Node_val;
-               temp_node.stptr = r->ahname_str;
-               temp_node.stlen = r->ahname_len;
-               temp_node.flags = 0;    /* only interested in the return value 
of r_force_number */
-               r->ahname_num = r_force_number(& temp_node);
-               r->flags |= NUMIND;
-       }
-}
-
-/* sort_force_value_number -- pre-process list items for sorting values as 
numbers */
-
-static void
-sort_force_value_number(NODE **list, size_t num_elems)
-{
-       size_t i;
-       NODE *r, *val;
-
-       for (i = 0; i < num_elems; i++) {
-               r = list[i];
-               val = r->ahvalue;
-               if (val->type == Node_val)
-                       (void) force_number(val);
-       }
-}
-
-/* sort_force_value_string -- pre-process list items for sorting values as 
strings */
-
-static void
-sort_force_value_string(NODE **list, size_t num_elems)
-{
-       size_t i;
-       NODE *r, *val;
-
-       for (i = 0; i < num_elems; i++) {
-               r = list[i];
-               val = r->ahvalue;
-               if (val->type == Node_val)
-                       r->ahvalue = force_string(val);
-       }
-}
 
 /* assoc_list -- construct, and optionally sort, a list of array elements */  
 
 NODE **
-assoc_list(NODE *array, const char *sort_str, SORT_CTXT sort_ctxt)
+assoc_list(NODE *symbol, const char *sort_str, SORT_CTXT sort_ctxt)
 {
-       typedef void (*qsort_prefunc)(NODE **, size_t);
        typedef int (*qsort_compfunc)(const void *, const void *);
 
        static const struct qsort_funcs {
                const char *name;
                qsort_compfunc comp_func;
-               qsort_prefunc pre_func;         /* pre-processing of list items 
*/
+               enum assoc_list_flags flags;
        } sort_funcs[] = {
-               { "@ind_str_asc",       sort_up_index_string,   0 },
-               { "@ind_num_asc",       sort_up_index_number,   
sort_force_index_number },
-               { "@val_str_asc",       sort_up_value_string,   
sort_force_value_string },
-               { "@val_num_asc",       sort_up_value_number,   
sort_force_value_number },
-               { "@ind_str_desc",      sort_down_index_string, 0 },
-               { "@ind_num_desc",      sort_down_index_number, 
sort_force_index_number },
-               { "@val_str_desc",      sort_down_value_string, 
sort_force_value_string },
-               { "@val_num_desc",      sort_down_value_number, 
sort_force_value_number },
-               { "@val_type_asc",      sort_up_value_type,     0 },
-               { "@val_type_desc",     sort_down_value_type,   0 },
-               { "@unsorted",          0,      0 },
-       };
+{ "@ind_str_asc",      sort_up_index_string,   AINDEX|AISTR|AASC },
+{ "@ind_num_asc",      sort_up_index_number,   AINDEX|AINUM|AASC },
+{ "@val_str_asc",      sort_up_value_string,   AVALUE|AVSTR|AASC },
+{ "@val_num_asc",      sort_up_value_number,   AVALUE|AVNUM|AASC },
+{ "@ind_str_desc",     sort_down_index_string, AINDEX|AISTR|ADESC },
+{ "@ind_num_desc",     sort_down_index_number, AINDEX|AINUM|ADESC },
+{ "@val_str_desc",     sort_down_value_string, AVALUE|AVSTR|ADESC },
+{ "@val_num_desc",     sort_down_value_number, AVALUE|AVNUM|ADESC },
+{ "@val_type_asc",     sort_up_value_type,     AVALUE|AASC },
+{ "@val_type_desc",    sort_down_value_type,   AVALUE|ADESC },
+{ "@unsorted",         0,                      AINDEX },
+};
+
+       /* N.B.: AASC and ADESC are hints to the specific array types.
+        *      See cint_list() in cint_array.c.
+        */
+
        NODE **list;
-       NODE *r;
-       size_t num_elems, i, j;
+       NODE fl;
+       unsigned long num_elems, j;
+       int elem_size, qi;
        qsort_compfunc cmp_func = 0;
-       qsort_prefunc pre_func = 0;
        INSTRUCTION *code = NULL;
-       int qi;
        extern int currule;
        
-       num_elems = array->table_size;
+       num_elems = symbol->table_size;
        assert(num_elems > 0);
 
+       elem_size = 1;
+       fl.flags = 0;
+
        for (qi = 0, j = sizeof(sort_funcs)/sizeof(sort_funcs[0]); qi < j; 
qi++) {
                if (strcmp(sort_funcs[qi].name, sort_str) == 0)
                        break;
        }
 
-       if (qi >= 0 && qi < j) {
+       if (qi < j) {
                cmp_func = sort_funcs[qi].comp_func;
-               pre_func = sort_funcs[qi].pre_func;
+               fl.flags = sort_funcs[qi].flags;
+
+               if (symbol->array_funcs != cint_array_func)
+                       fl.flags &= ~(AASC|ADESC);
 
-       } else {                /* unrecognized */
+               if (sort_ctxt != SORTED_IN || (fl.flags & AVALUE) != 0) {
+                       /* need index and value pair in the list */
+
+                       fl.flags |= (AINDEX|AVALUE);
+                       elem_size = 2;
+               }
+
+       } else {        /* unrecognized */
                NODE *f;
                const char *sp; 
 
-               assert(sort_str != NULL);
-
                for (sp = sort_str; *sp != '\0'
                     && ! isspace((unsigned char) *sp); sp++)
                        continue;
@@ -1663,7 +1325,10 @@ assoc_list(NODE *array, const char *sort_str, SORT_CTXT 
sort_ctxt)
                        fatal(_("sort comparison function `%s' is not 
defined"), sort_str);
 
                cmp_func = sort_user_func;
-               /* pre_func is still NULL */
+
+               /* need index and value pair in the list */
+               fl.flags |= (AVALUE|AINDEX);
+               elem_size = 2;
 
                /* make function call instructions */
                code = bcalloc(Op_func_call, 2, 0);
@@ -1683,23 +1348,12 @@ assoc_list(NODE *array, const char *sort_str, SORT_CTXT 
sort_ctxt)
                PUSH_CODE(code);
        }
 
-       /* allocate space for array; the extra space is used in for(i in a) 
opcode (eval.c) */
-       emalloc(list, NODE **, (num_elems + 1) * sizeof(NODE *), "assoc_list");
-
-       /* populate it */
-       for (i = j = 0; i < array->array_size; i++)
-               for (r = array->var_array[i]; r != NULL; r = r->ahnext)
-                       list[j++] = dupnode(r);
-       list[num_elems] = NULL;
+       list = symbol->alist(symbol, & fl);
 
-       if (! cmp_func) /* unsorted */
-               return list;
+       if (! cmp_func || (fl.flags & (AASC|ADESC)) != 0)
+               return list;    /* unsorted or list already sorted */
 
-       /* special pre-processing of list items */
-       if (pre_func)
-               pre_func(list, num_elems);
-
-       qsort(list, num_elems, sizeof(NODE *), cmp_func); /* shazzam! */
+       qsort(list, num_elems, elem_size * sizeof(NODE *), cmp_func); /* 
shazzam! */
 
        if (cmp_func == sort_user_func) {
                code = POP_CODE();
@@ -1708,72 +1362,17 @@ assoc_list(NODE *array, const char *sort_str, SORT_CTXT 
sort_ctxt)
                bcfree(code);                   /* Op_func_call */
        }
 
-       return list;
-}
-
-
-/*
-From address@hidden  Mon Oct 28 16:05:26 2002
-Date: Mon, 28 Oct 2002 13:33:03 +0100
-From: Paolo Bonzini <address@hidden>
-To: address@hidden
-Subject: Hash function
-Message-ID: <address@hidden>
-
-Here is the hash function I'm using in GNU Smalltalk.  The scrambling is
-needed if you use powers of two as the table sizes.  If you use primes it
-is not needed.
-
-To use double-hashing with power-of-two size, you should use the
-_gst_hash_string(str, len) as the primary hash and
-scramble(_gst_hash_string (str, len)) | 1 as the secondary hash.
-
-Paolo
-
-*/
-/*
- * ADR: Slightly modified to work w/in the context of gawk.
- */
-
-static unsigned long
-gst_hash_string(const char *str, size_t len, unsigned long hsize, size_t *code)
-{
-       unsigned long hashVal = 1497032417;    /* arbitrary value */
-       unsigned long ret;
-
-       while (len--) {
-               hashVal += *str++;
-               hashVal += (hashVal << 10);
-               hashVal ^= (hashVal >> 6);
-       }
-
-       ret = scramble(hashVal);
-
-       if (code != NULL)
-               *code = ret;
-
-       if (ret >= hsize)
-               ret %= hsize;
-
-       return ret;
-}
+       if (sort_ctxt == SORTED_IN
+               && (fl.flags & (AINDEX|AVALUE)) == (AINDEX|AVALUE)
+       ) {
+               /* relocate all index nodes to the first half of the list. */
+               for (j = 1; j < num_elems; j++)
+                       list[j] = list[2 * j];
 
-static unsigned long
-scramble(unsigned long x)
-{
-       if (sizeof(long) == 4) {
-               int y = ~x;
+               /* give back extra memory */
 
-               x += (y << 10) | (y >> 22);
-               x += (x << 6)  | (x >> 26);
-               x -= (x << 16) | (x >> 16);
-       } else {
-               x ^= (~x) >> 31;
-               x += (x << 21) | (x >> 11);
-               x += (x << 5) | (x >> 27);
-               x += (x << 27) | (x >> 5);
-               x += (x << 31);
+               erealloc(list, NODE **, num_elems * sizeof(NODE *), 
"assoc_list");
        }
 
-       return x;
+       return list;
 }
diff --git a/awk.h b/awk.h
index 25abf41..dcf3e9a 100644
--- a/awk.h
+++ b/awk.h
@@ -253,10 +253,9 @@ extern double gawk_strtod();
 #define FALSE  0
 #endif
 
-#define LINT_INVALID   1       /* only warn about invalid */
-#define LINT_ALL       2       /* warn about all things */
+#define INT32_BIT 32
 
-enum defrule {BEGIN = 1, Rule, END, BEGINFILE, ENDFILE,
+enum defrule { BEGIN = 1, Rule, END, BEGINFILE, ENDFILE,
        MAXRULE /* sentinel, not legal */ };
 extern const char *const ruletab[];
 
@@ -275,10 +274,13 @@ typedef enum nodevals {
        Node_var_new,           /* newly created variable, may become an array 
*/
        Node_param_list,        /* lnode is a variable, rnode is more list */
        Node_func,              /* lnode is param. list, rnode is body */
+       Node_ext_func,          /* extension function, code_ptr is builtin code 
*/
 
        Node_hashnode,          /* an identifier in the symbol table */
-       Node_ahash,             /* an array element */
        Node_array_ref,         /* array passed by ref as parameter */
+       Node_array_tree,        /* Hashed array tree (HAT) */
+       Node_array_leaf,        /* Linear 1-D array */
+       Node_dump_array,        /* array info */
 
        /* program execution -- stack item types */
        Node_arrayfor,
@@ -288,9 +290,44 @@ typedef enum nodevals {
        Node_final              /* sentry value, not legal */
 } NODETYPE;
 
+struct exp_node;
+
+typedef union bucket_item {
+       struct {
+               union bucket_item *next;
+               char *str;
+               size_t len;
+               size_t code;
+               struct exp_node *name;
+               struct exp_node *val;
+       } hs;
+       struct {
+               union bucket_item *next;
+               long li[2];
+               struct exp_node *val[2];
+               size_t cnt;
+       } hi;
+} BUCKET;
+
+/* string hash table */
+#define ahnext         hs.next
+#define        ahname          hs.name /* a string index node */
+#define        ahname_str      hs.str  /* shallow copy; = ahname->stptr */
+#define        ahname_len      hs.len  /* = ahname->stlen */
+#define        ahvalue         hs.val
+#define        ahcode          hs.code
+
+/* integer hash table */
+#define        ainext          hi.next
+#define ainum          hi.li   /* integer indices */
+#define aivalue                hi.val
+#define aicount                hi.cnt
 
 struct exp_instruction;
 
+typedef int (*Func_print)(FILE *, const char *, ...);
+typedef struct exp_node **(*array_ptr)(struct exp_node *, struct exp_node *);
+
 /*
  * NOTE - this struct is a rather kludgey -- it is packed to minimize
  * space usage, at the expense of cleanliness.  Alter at own risk.
@@ -301,11 +338,13 @@ typedef struct exp_node {
                        union {
                                struct exp_node *lptr;
                                long ll;
+                               array_ptr *lp;
                        } l;
                        union {
                                struct exp_node *rptr;
                                Regexp *preg;
                                struct exp_node **av;
+                               BUCKET **bv;
                                void (*uptr)(void);
                                struct exp_instruction *iptr;
                        } r;
@@ -316,16 +355,19 @@ typedef struct exp_node {
                                char **param_list;
                        } x;
                        char *name;
+                       size_t reserved;
                        struct exp_node *rn;
+                       unsigned long cnt;
                        unsigned long reflags;
 #                              define  CASE            1
 #                              define  CONSTANT        2
 #                              define  FS_DFLT         4
                } nodep;
+
                struct {
                        AWKNUM fltnum;  /* this is here for optimal packing of
-                                        * the structure on many machines
-                                        */
+                                        * the structure on many machines
+                                        */
                        char *sp;
                        size_t slen;
                        long sref;
@@ -335,96 +377,120 @@ typedef struct exp_node {
                        size_t wslen;
 #endif
                } val;
-               struct {
-                       AWKNUM num;
-                       struct exp_node *next;
-                       char *name;
-                       size_t length;
-                       struct exp_node *value;
-                       long ref;
-                       size_t code;
-               } hash;
-#define        hnext   sub.hash.next
-#define        hname   sub.hash.name
-#define        hlength sub.hash.length
-#define        hvalue  sub.hash.value
-
-#define        ahnext          sub.hash.next
-#define        ahname_str      sub.hash.name
-#define ahname_len     sub.hash.length
-#define ahname_num     sub.hash.num
-#define        ahvalue sub.hash.value
-#define ahname_ref     sub.hash.ref
-#define        ahcode  sub.hash.code
        } sub;
        NODETYPE type;
-       unsigned short flags;
-#              define  MALLOC  1       /* can be free'd */
-#              define  PERM    2       /* can't be free'd */
-#              define  STRING  4       /* assigned as string */
-#              define  STRCUR  8       /* string value is current */
-#              define  NUMCUR  16      /* numeric value is current */
-#              define  NUMBER  32      /* assigned as number */
-#              define  MAYBE_NUM 64    /* user input: if NUMERIC then
-                                        * a NUMBER */
-#              define  ARRAYMAXED 128  /* array is at max size */
-#              define  FUNC    256     /* this parameter is really a
-                                        * function name; see awkgram.y */
-#              define  FIELD   512     /* this is a field */
-#              define  INTLSTR 1024    /* use localized version */
-#              define  NUMIND  2048    /* numeric val of index is current */
-#              define  WSTRCUR 4096    /* wide str value is current */
+       unsigned int flags;
+
+/* any type */
+#              define  MALLOC  0x0001       /* can be free'd */
+
+/* type = Node_val */
+#              define  STRING  0x0002       /* assigned as string */
+#              define  STRCUR  0x0004       /* string value is current */
+#              define  NUMCUR  0x0008       /* numeric value is current */
+#              define  NUMBER  0x0010       /* assigned as number */
+#              define  MAYBE_NUM 0x0020     /* user input: if NUMERIC then
+                                             * a NUMBER */
+#              define  FIELD   0x0040       /* this is a field */
+#              define  INTLSTR 0x0080       /* use localized version */
+#              define  NUMINT  0x0100       /* numeric value is an integer */
+#              define  INTIND  0x0200       /* integral value is array index;
+                                             * lazy conversion to string.
+                                             */
+#              define  WSTRCUR 0x0400       /* wide str value is current */
+
+/* type = Node_var_array */
+#              define  ARRAYMAXED      0x0800       /* array is at max size */
+#              define  HALFHAT         0x1000       /* half-capacity Hashed 
Array Tree;
+                                                     * See cint_array.c */
+#              define  XARRAY          0x2000       /* FIXME: Nuke */
 } NODE;
 
-
 #define vname sub.nodep.name
 
 #define lnode  sub.nodep.l.lptr
 #define nextp  sub.nodep.l.lptr
 #define rnode  sub.nodep.r.rptr
 
-#define        param_cnt       sub.nodep.l.ll
-#define param          vname
+/* Node_hashnode, Node_param_list */
+#define hnext  sub.nodep.r.rptr
+#define        hname   vname
+#define        hlength sub.nodep.reserved
+#define hcode  sub.nodep.cnt
+#define hvalue sub.nodep.x.extra
+
+/* Node_param_list, Node_func */
+#define        param_cnt  sub.nodep.l.ll
+/* Node_param_list */
+#define param      vname
 
-#define parmlist    sub.nodep.x.param_list
+/* Node_func */
+#define fparms         sub.nodep.rn
 #define code_ptr    sub.nodep.r.iptr
 
+/* Node_regex, Node_dynregex */
 #define re_reg sub.nodep.r.preg
 #define re_flags sub.nodep.reflags
 #define re_text lnode
 #define re_exp sub.nodep.x.extra
 #define        re_cnt  flags
 
+/* Node_val */
 #define stptr  sub.val.sp
 #define stlen  sub.val.slen
 #define valref sub.val.sref
 #define        stfmt   sub.val.idx
-
 #define wstptr sub.val.wsp
 #define wstlen sub.val.wslen
-
 #define numbr  sub.val.fltnum
 
+/* Node_arrayfor */
+#define for_list       sub.nodep.r.av
+#define for_list_size  sub.nodep.reflags
+#define cur_idx                sub.nodep.l.ll
+#define for_array      sub.nodep.rn
+
 /* Node_frame: */
 #define stack        sub.nodep.r.av
 #define func_node    sub.nodep.x.extra
 #define reti         sub.nodep.reflags
 
 /* Node_var: */
-#define var_value lnode
+#define var_value    lnode
 #define var_update   sub.nodep.r.uptr
-#define var_assign      sub.nodep.x.aptr
+#define var_assign   sub.nodep.x.aptr
 
 /* Node_var_array: */
-#define var_array    sub.nodep.r.av
-#define array_size   sub.nodep.l.ll
-#define table_size   sub.nodep.x.xl
-#define parent_array sub.nodep.rn
+#define buckets                sub.nodep.r.bv
+#define nodes          sub.nodep.r.av
+#define array_funcs    sub.nodep.l.lp
+#define array_base     sub.nodep.l.ll
+#define table_size     sub.nodep.reflags
+#define array_size     sub.nodep.cnt
+#define array_capacity sub.nodep.reserved
+#define xarray         sub.nodep.rn
+#define parent_array   sub.nodep.x.extra 
+
+/* array_funcs[0] is the array initialization function and
+ * array_funcs[1] is the index type checking function
+ */
+#define alookup        array_funcs[2]
+#define aexists        array_funcs[3]
+#define aclear         array_funcs[4]
+#define aremove                array_funcs[5]
+#define alist          array_funcs[6]
+#define acopy          array_funcs[7]
+#define adump          array_funcs[8]
+#define NUM_AFUNCS     9               /* # of entries in array_funcs */
 
 /* Node_array_ref: */
 #define orig_array lnode
 #define prev_array rnode
 
+/* Node_array_print */
+#define adepth     sub.nodep.l.ll
+#define alevel     sub.nodep.x.xl
+
 /* --------------------------------lint warning 
types----------------------------*/
 typedef enum lintvals {
        LINT_illegal,
@@ -521,6 +587,7 @@ typedef enum opcodeval {
        Op_K_nextfile,
 
        Op_builtin,
+       Op_ext_builtin,
        Op_in_array,            /* boolean test of membership in array */
 
        /* function call instruction */
@@ -553,7 +620,6 @@ typedef enum opcodeval {
        Op_after_beginfile,
        Op_after_endfile,
 
-       Op_ext_func,
        Op_func,
 
        Op_exec_count,
@@ -638,6 +704,8 @@ typedef struct exp_instruction {
 
 /* Op_token */
 #define lextok          d.name
+#define param_count     x.xl
+
 
 /* Op_rule */
 #define in_rule         x.xl
@@ -646,11 +714,11 @@ typedef struct exp_instruction {
  /* Op_K_case, Op_K_default */
 #define case_stmt       x.xi
 #define case_exp        d.di
-#define stmt_start             case_exp
-#define stmt_end               case_stmt
-#define match_exp              x.xl
+#define stmt_start      case_exp
+#define stmt_end        case_stmt
+#define match_exp       x.xl
 
-#define target_stmt       x.xi
+#define target_stmt     x.xi
 
 /* Op_K_switch */
 #define switch_end      x.xi
@@ -707,9 +775,9 @@ typedef struct exp_instruction {
 #define field_assign    x.aptr
 
 /* Op_concat */
-#define concat_flag        d.dl
-#define CSUBSEP                        1
-#define CSVAR                  2
+#define concat_flag     d.dl
+#define CSUBSEP                1
+#define CSVAR          2
 
 /* Op_breakpoint */
 #define break_pt        x.bpt
@@ -739,6 +807,10 @@ typedef struct exp_instruction {
 #define condpair_left   d.di
 #define condpair_right  x.xi 
 
+/* Op_store_var */
+#define initval         x.xn
+
+
 typedef struct iobuf {
        const char *name;       /* filename */
        int fd;                 /* file descriptor */
@@ -831,7 +903,7 @@ typedef struct context {
        SRCFILE srcfiles;
        int sourceline;
        char *source;
-       void (*install_func)(char *);
+       void (*install_func)(NODE *);
        struct context *prev;
 } AWK_CONTEXT;
 
@@ -841,6 +913,20 @@ struct flagtab {
        const char *name;
 };
 
+
+typedef struct block_item {
+       size_t size;
+       struct block_item *freep;
+} BLOCK;
+
+enum block_id {
+       BLOCK_INVALID = 0,      /* not legal */
+       BLOCK_NODE,
+       BLOCK_BUCKET,
+       BLOCK_MAX       /* count */
+};     
+
+
 #ifndef LONG_MAX
 #define LONG_MAX ((long)(~(1L << (sizeof (long) * 8 - 1))))
 #endif
@@ -881,21 +967,53 @@ extern int sourceline;
 extern char *source;
 
 #if __GNUC__ < 2
-extern NODE *_t;       /* used as temporary in tree_eval */
+extern NODE *_t;       /* used as temporary in macros */
 #endif
-extern NODE *_r;       /* used as temporary in stack macros */
+extern NODE *_r;       /* used as temporary in macros */
 
-extern NODE *nextfree;
+extern BLOCK nextfree[];
 extern int field0_valid;
-extern int do_traditional;
-extern int do_posix;
-extern int do_intervals;
-extern int do_intl;
-extern int do_non_decimal_data;
-extern int do_profiling;
-extern int do_dump_vars;
-extern int do_tidy_mem;
-extern int do_sandbox;
+
+extern int do_flags;
+
+/* only warn about invalid */
+#define DO_LINT_INVALID 0x0001 
+/* warn about all things */
+#define        DO_LINT_ALL     0x0002
+/* warn about stuff not in V7 awk */
+#define DO_LINT_OLD     0x0004
+/* no gnu extensions, add traditional weirdnesses */
+#define DO_TRADITIONAL  0x0008
+/* turn off gnu and unix extensions */
+#define DO_POSIX        0x0010
+/* dump locale-izable strings to stdout */
+#define DO_INTL         0x0020
+/* allow octal/hex C style DATA. Use with caution! */
+#define DO_NON_DEC_DATA 0x0040
+/* allow {...,...} in regexps, see resetup() */
+#define DO_INTERVALS    0x0080
+/* profile and pretty print the program */
+#define DO_PROFILING    0x0100
+/* dump all global variables at end */
+#define DO_DUMP_VARS    0x0200
+/* release vars when done */
+#define        DO_TIDY_MEM     0x0400
+/* sandbox mode - disable 'system' function & redirections */
+#define DO_SANDBOX      0x0800
+
+
+#define do_traditional      (do_flags & DO_TRADITIONAL)
+#define        do_posix            (do_flags & DO_POSIX)
+#define        do_intl             (do_flags & DO_INTL)
+#define do_non_decimal_data (do_flags & DO_NON_DEC_DATA)
+#define do_intervals        (do_flags & DO_INTERVALS)
+#define        do_profiling        (do_flags & DO_PROFILING)
+#define do_dump_vars        (do_flags & DO_DUMP_VARS)
+#define do_tidy_mem         (do_flags & DO_TIDY_MEM)
+#define do_sandbox          (do_flags & DO_SANDBOX)
+#define do_annotate         (do_flags & DO_ANNOTATE)
+
+
 extern int do_optimize;
 extern int use_lc_numeric;
 extern int exit_val;
@@ -904,8 +1022,8 @@ extern int exit_val;
 #define do_lint 0
 #define do_lint_old 0
 #else
-extern int do_lint;
-extern int do_lint_old;
+#define do_lint             (do_flags & (DO_LINT_INVALID|DO_LINT_ALL))
+#define do_lint_old         (do_flags & DO_LINT_OLD)
 #endif
 #ifdef MBS_SUPPORT
 extern int gawk_mb_cur_max;
@@ -942,7 +1060,7 @@ extern enum exe_mode which_gawk;   /* (defined in eval.c) 
*/
 
 typedef union stack_item {
        NODE *rptr;             /* variable etc. */
-       NODE **lptr;            /* address of a variable etc. */
+       NODE **lptr;    /* address of a variable etc. */
 } STACK_ITEM;
 
 extern STACK_ITEM *stack_ptr;
@@ -950,84 +1068,75 @@ extern NODE *frame_ptr;
 extern STACK_ITEM *stack_bottom;
 extern STACK_ITEM *stack_top;
 
-#define decr_sp()                      (stack_ptr--)
+#define decr_sp()              (stack_ptr--)
 #define incr_sp()              ((stack_ptr < stack_top) ? ++stack_ptr : 
grow_stack())
-#define stack_adj(n)                   (stack_ptr += (n))
-#define stack_empty()                  (stack_ptr < stack_bottom)
-
-#define POP()                          decr_sp()->rptr
-#define POP_ADDRESS()                  decr_sp()->lptr
-#define PEEK(n)                                (stack_ptr - (n))->rptr
-#define TOP()                          stack_ptr->rptr         /* same as 
PEEK(0) */
-#define TOP_ADDRESS()                  stack_ptr->lptr 
-#define PUSH(r)                                (void) (incr_sp()->rptr = (r))
-#define PUSH_ADDRESS(l)                        (void) (incr_sp()->lptr = (l))
-#define REPLACE(r)                     (void) (stack_ptr->rptr = (r))
-#define REPLACE_ADDRESS(l)             (void) (stack_ptr->lptr = (l))
-
+#define stack_adj(n)           (stack_ptr += (n))
+#define stack_empty()          (stack_ptr < stack_bottom)
+
+#define POP()                  decr_sp()->rptr
+#define POP_ADDRESS()          decr_sp()->lptr
+#define PEEK(n)                        (stack_ptr - (n))->rptr
+#define TOP()                  stack_ptr->rptr         /* same as PEEK(0) */
+#define TOP_ADDRESS()          stack_ptr->lptr 
+#define PUSH(r)                        (void) (incr_sp()->rptr = (r))
+#define PUSH_ADDRESS(l)                (void) (incr_sp()->lptr = (l))
+#define REPLACE(r)             (void) (stack_ptr->rptr = (r))
+#define REPLACE_ADDRESS(l)     (void) (stack_ptr->lptr = (l))
 
 /* function param */
-#define GET_PARAM(n)                   frame_ptr->stack[n]
+#define GET_PARAM(n)   frame_ptr->stack[n]
 
 /*
- * UPREF and DEREF --- simplified versions of dupnode and unref
- * UPREF does not handle FIELD node. Most appropriate use is
- * for elements on the runtime stack. When in doubt, use dupnode.
- */   
+ * UPREF --- simplified versions of dupnode, does not handle FIELD node.
+ * Most appropriate use is for elements on the runtime stack.
+ * When in doubt, use dupnode.
+ */
 
-#define DEREF(r)       ( _r = (r), (!(_r->flags & PERM) && (--_r->valref == 
0)) ?  unref(_r) : (void)0 )
+#define UPREF(r)       (void) ((r)->valref++)
+
+#define DEREF(r)       ( _r = (r), (--_r->valref == 0) ?  r_unref(_r) : 
(void)0 )
 
 #if __GNUC__ >= 2
-#define UPREF(r)       ({ NODE *_t = (r); !(_t->flags & PERM) && 
_t->valref++;})
 
 #define POP_ARRAY()    ({ NODE *_t = POP(); \
-                       _t->type == Node_var_array ? \
-                               _t : get_array(_t, TRUE); })
+               _t->type == Node_var_array ? _t : get_array(_t, TRUE); })
 
 #define POP_PARAM()    ({ NODE *_t = POP(); \
-                       _t->type == Node_var_array ? \
-                               _t : get_array(_t, FALSE); })
+               _t->type == Node_var_array ? _t : get_array(_t, FALSE); })
 
-#define POP_NUMBER(x) ({ NODE *_t = POP_SCALAR(); \
-                               x = force_number(_t); DEREF(_t); })
-#define TOP_NUMBER(x) ({ NODE *_t = TOP_SCALAR(); \
-                               x = force_number(_t); DEREF(_t); })
+#define POP_NUMBER(x) ({ NODE *_t = POP_SCALAR(); x = force_number(_t); 
DEREF(_t); })
+#define TOP_NUMBER(x) ({ NODE *_t = TOP_SCALAR(); x = force_number(_t); 
DEREF(_t); })
 
-#define POP_SCALAR()                   ({ NODE *_t = POP(); _t->type != 
Node_var_array ? _t \
-                       : (fatal(_("attempt to use array `%s' in a scalar 
context"), array_vname(_t)), _t);})
-#define TOP_SCALAR()                   ({ NODE *_t = TOP(); _t->type != 
Node_var_array ? _t \
-                       : (fatal(_("attempt to use array `%s' in a scalar 
context"), array_vname(_t)), _t);})
+#define POP_SCALAR()   ({ NODE *_t = POP(); _t->type != Node_var_array ? _t \
+               : (fatal(_("attempt to use array `%s' in a scalar context"), 
array_vname(_t)), _t);})
+#define TOP_SCALAR()   ({ NODE *_t = TOP(); _t->type != Node_var_array ? _t \
+               : (fatal(_("attempt to use array `%s' in a scalar context"), 
array_vname(_t)), _t);})
 
-#else  /* not __GNUC__ */
+#define POP_STRING()   force_string(POP_SCALAR())
+#define TOP_STRING()   force_string(TOP_SCALAR())
 
-#define UPREF(r)       (_t = (r), !(_t->flags & PERM) && _t->valref++)
+#else  /* not __GNUC__ */
 
 #define POP_ARRAY()    (_t = POP(), \
-                       _t->type == Node_var_array ? \
-                               _t : get_array(_t, TRUE))
+               _t->type == Node_var_array ? _t : get_array(_t, TRUE))
 
 #define POP_PARAM()    (_t = POP(), \
-                       _t->type == Node_var_array ? \
-                               _t : get_array(_t, FALSE))
+               _t->type == Node_var_array ? _t : get_array(_t, FALSE))
 
-#define POP_NUMBER(x) (_t = POP_SCALAR(), \
-                               x = force_number(_t), DEREF(_t))
-#define TOP_NUMBER(x) (_t = TOP_SCALAR(), \
-                               x = force_number(_t), DEREF(_t))
+#define POP_NUMBER(x) (_t = POP_SCALAR(), x = force_number(_t), DEREF(_t))
+#define TOP_NUMBER(x) (_t = TOP_SCALAR(), x = force_number(_t), DEREF(_t))
 
 #define POP_SCALAR()   (_t = POP(), _t->type != Node_var_array ? _t \
-                       : (fatal(_("attempt to use array `%s' in a scalar 
context"), array_vname(_t)), _t))
+               : (fatal(_("attempt to use array `%s' in a scalar context"), 
array_vname(_t)), _t))
 #define TOP_SCALAR()   (_t = TOP(), _t->type != Node_var_array ? _t \
-                       : (fatal(_("attempt to use array `%s' in a scalar 
context"), array_vname(_t)), _t))
-
-#endif /* __GNUC__ */
+               : (fatal(_("attempt to use array `%s' in a scalar context"), 
array_vname(_t)), _t))
 
+#define POP_STRING()   (_r = POP_SCALAR(), m_force_string(_r))
+#define TOP_STRING()   (_r = TOP_SCALAR(), m_force_string(_r))
 
-#define POP_STRING() force_string(POP_SCALAR())
-#define TOP_STRING() force_string(TOP_SCALAR())
+#endif /* __GNUC__ */
 
 /* ------------------------- Pseudo-functions ------------------------- */
-
 #define is_identchar(c)                (isalnum(c) || (c) == '_')
 
 #define var_uninitialized(n)   ((n)->var_value == Nnull_string)
@@ -1035,24 +1144,20 @@ extern STACK_ITEM *stack_top;
 #define get_lhs(n, r)   (n)->type == Node_var && ! var_uninitialized(n) ? \
                                &((n)->var_value) : r_get_lhs((n), (r))
 
-#ifdef MPROF
-#define        getnode(n)      emalloc((n), NODE *, sizeof(NODE), "getnode"), \
-                          (n)->flags = 0
-#define        freenode(n)     efree(n)
-#else  /* not MPROF */
-#define getnode(n)  (void) (nextfree ? \
-                              (n = nextfree, nextfree = nextfree->nextp) \
-                              : (n = more_nodes()))
-#define        freenode(n)     ((n)->flags = 0, (n)->nextp = nextfree, 
nextfree = (n))
-#endif /* not MPROF */
+#define getblock(p, id, ty)  (void) ((p = (ty) nextfree[id].freep) ? \
+                       (ty) (nextfree[id].freep = ((BLOCK *) p)->freep) \
+                       : (p = (ty) more_blocks(id)))
+#define freeblock(p, id)        (void) (((BLOCK *) p)->freep = 
nextfree[id].freep, \
+                                       nextfree[id].freep = (BLOCK *) p)
 
-#define make_number(x)  mk_number((x), (unsigned int)(MALLOC|NUMCUR|NUMBER))
+#define getnode(n)     getblock(n, BLOCK_NODE, NODE *)
+#define freenode(n)    freeblock(n, BLOCK_NODE)
 
-#define        make_string(s, l)               r_make_str_node((s), (size_t) 
(l), 0)
-#define make_str_node(s, l, f) r_make_str_node((s), (size_t) (l), (f))
+#define getbucket(b)   getblock(b, BLOCK_BUCKET, BUCKET *)
+#define freebucket(b)  freeblock(b, BLOCK_BUCKET)
 
-#define                SCAN                    1
-#define                ALREADY_MALLOCED        2
+#define        make_string(s, l)       r_make_str_node((s), (size_t) (l), 
FALSE)
+#define make_str_node(s, l)    r_make_str_node((s), (size_t) (l), TRUE)
 
 #define        cant_happen()   r_fatal("internal error line %d, file: %s", \
                                __LINE__, __FILE__)
@@ -1069,19 +1174,34 @@ extern STACK_ITEM *stack_top;
 
 #ifdef GAWKDEBUG
 #define        force_number    r_force_number
-#define        force_string    r_force_string
+#define dupnode        r_dupnode
+#define unref  r_unref
+#define m_force_string r_force_string
+extern NODE *r_force_string(NODE *s);
 #else /* not GAWKDEBUG */
+
+#define unref(r)       ( _r = (r), (_r == NULL || --_r->valref > 0) ? \
+                       (void)0 : r_unref(_r) )
+
+#define        m_force_string(_ts)     (((_ts->flags & STRCUR) && \
+                       (_ts->stfmt == -1 || _ts->stfmt == CONVFMTidx)) ? \
+                       _ts : format_val(CONVFMT, CONVFMTidx, _ts))
+
 #if __GNUC__ >= 2
-#define        force_number(n) __extension__ ({NODE *_tn = (n);\
-                       (_tn->flags & NUMCUR) ? _tn->numbr : 
r_force_number(_tn);})
+#define dupnode(n)     __extension__ ({ NODE *_tn = (n); \
+       (_tn->flags & MALLOC) ? (_tn->valref++, _tn) : r_dupnode(_tn); })
+
+#define        force_number(n) __extension__ ({ NODE *_tn = (n);\
+       (_tn->flags & NUMCUR) ? _tn->numbr : r_force_number(_tn); })
+
+#define        force_string(s) __extension__ ({ NODE *_ts = (s); 
m_force_string(_ts); })
 
-#define        force_string(s) __extension__ ({NODE *_ts = (s);\
-                          ((_ts->flags & STRCUR) && \
-                          (_ts->stfmt == -1 || _ts->stfmt == CONVFMTidx)) ?\
-                         _ts : format_val(CONVFMT, CONVFMTidx, _ts);})
 #else /* not __GNUC__ */
+#define dupnode(n)     (_t = (n), \
+       (_t->flags & MALLOC) ? (_t->valref++, _t) : r_dupnode(_t))
+
 #define        force_number    r_force_number
-#define        force_string    r_force_string
+#define        force_string(s) (_t = (s), m_force_string(_t))  
 #endif /* __GNUC__ */
 #endif /* GAWKDEBUG */
 
@@ -1102,57 +1222,66 @@ if (val++) \
 if (--val)     \
        memcpy((char *) tag, (const char *) (stack), sizeof(jmp_buf))
 
-/* ------------- Function prototypes or defs (as appropriate) ------------- */
-typedef int (*Func_print)(FILE *, const char *, ...);
+#define array_empty(a) ((a)->table_size == 0)
+#define assoc_lookup(a, s)     (a)->alookup(a, s)
+
+#if __GNUC__ >= 2
+#define in_array(a, s) ({ NODE **_l; array_empty(a) ? NULL \
+                       : (_l = (a)->aexists(a, s), _l ? *_l : NULL); })
+#else /* not __GNUC__ */
+#define in_array(a, s) r_in_array(a, s)
+#endif /* __GNUC__ */
 
+
+/* ------------- Function prototypes or defs (as appropriate) ------------- */
 /* array.c */
 typedef enum sort_context { SORTED_IN = 1, ASORT, ASORTI } SORT_CTXT;
-extern NODE **assoc_list(NODE *array, const char *sort_str, SORT_CTXT 
sort_ctxt);
+enum assoc_list_flags {
+AINDEX = 0x01,         /* list of indices */ 
+AVALUE = 0x02,         /* list of values */
+AINUM = 0x04,          /* numeric index */
+AISTR = 0x08,          /* string index */
+AVNUM = 0x10,          /* numeric scalar value */
+AVSTR = 0x20,          /* string scalar value */
+AASC = 0x40,           /* ascending order */
+ADESC = 0x80,          /* descending order */
+ADELETE = 0x100,       /* need a single index; for use in do_delete_loop */
+};
+
+extern NODE *make_array(void);
+extern void init_array(NODE *symbol);
 extern NODE *get_array(NODE *symbol, int canfatal);
-extern char *array_vname(const NODE *symbol);
+extern const char *make_aname(const NODE *symbol);
+extern const char *array_vname(const NODE *symbol);
 extern void array_init(void);
 extern void set_SUBSEP(void);
 extern NODE *concat_exp(int nargs, int do_subsep);
-extern void ahash_unref(NODE *tmp);
 extern void assoc_clear(NODE *symbol);
-extern NODE *in_array(NODE *symbol, NODE *subs);
-extern NODE **assoc_lookup(NODE *symbol, NODE *subs, int reference);
+extern NODE *r_in_array(NODE *symbol, NODE *subs);
+extern int assoc_remove(NODE *symbol, NODE *subs);
+extern NODE *assoc_copy(NODE *symbol, NODE *newsymb);
+extern void assoc_dump(NODE *symbol, NODE *p);
+extern NODE **assoc_list(NODE *symbol, const char *sort_str, SORT_CTXT 
sort_ctxt);
+extern void assoc_info(NODE *subs, NODE *val, NODE *p, const char *aname);
 extern void do_delete(NODE *symbol, int nsubs);
 extern void do_delete_loop(NODE *symbol, NODE **lhs);
-extern NODE *assoc_dump(NODE *symbol, int indent_level);
 extern NODE *do_adump(int nargs);
+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 *mk_symbol(NODETYPE type, NODE *value);
-extern NODE *install_symbol(char *name, NODE *value);
-extern NODE *remove_symbol(char *name);
-extern NODE *lookup(const char *name);
-extern NODE *variable(char *name, NODETYPE type);
+extern NODE *variable(int location, char *name, NODETYPE type);
 extern int parse_program(INSTRUCTION **pcode);
 extern void dump_funcs(void);
 extern void dump_vars(const char *fname);
-extern void release_all_vars(void);
 extern const char *getfname(NODE *(*)(int));
-extern NODE *stopme(int nargs);
 extern void shadow_funcs(void);
 extern int check_special(const char *name);
-extern int foreach_func(int (*)(INSTRUCTION *, void *), int, void *);
-extern INSTRUCTION *bcalloc(OPCODE op, int size, int srcline);
-extern void bcfree(INSTRUCTION *);
 extern SRCFILE *add_srcfile(int stype, char *src, SRCFILE *curr, int 
*already_included, int *errcode);
 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 print_vars(Func_print print_func, FILE *fp);
-extern AWK_CONTEXT *new_context(void);
-extern void push_context(AWK_CONTEXT *ctxt);
-extern void pop_context();
-extern int in_main_context();
-extern void free_context(AWK_CONTEXT *ctxt, int );
-extern void append_symbol(char *name);
-
 /* builtin.c */
 extern double double_to_int(double d);
 extern NODE *do_exp(int nargs);
@@ -1204,7 +1333,7 @@ extern int strncasecmpmbs(const unsigned char *,
 extern void PUSH_CODE(INSTRUCTION *cp);
 extern INSTRUCTION *POP_CODE(void);
 extern int interpret(INSTRUCTION *);
-extern int cmp_nodes(NODE *, NODE *);
+extern int cmp_nodes(NODE *p1, NODE *p2);
 extern void set_IGNORECASE(void);
 extern void set_OFS(void);
 extern void set_ORS(void);
@@ -1236,7 +1365,6 @@ extern void dump_fcall_stack(FILE *fp);
 NODE *do_ext(int nargs);
 #ifdef DYNAMIC
 void make_builtin(const char *, NODE *(*)(int), int);
-size_t get_curfunc_arg_count(void);
 NODE *get_argument(int);
 NODE *get_actual_argument(int, int, int);
 #define get_scalar_argument(i, opt)  get_actual_argument((i), (opt), FALSE)
@@ -1300,6 +1428,7 @@ extern int arg_assign(char *arg, int initing);
 extern int is_std_var(const char *var);
 extern char *estrdup(const char *str, size_t len);
 extern void update_global_values();
+extern long getenv_long(const char *name);
 /* msg.c */
 extern void gawk_exit(int status);
 extern void err(const char *s, const char *emsg, va_list argp) 
ATTRIBUTE_PRINTF(2, 0);
@@ -1327,13 +1456,14 @@ extern void pp_string_fp(Func_print print_func, FILE 
*fp, const char *str,
 /* node.c */
 extern AWKNUM r_force_number(NODE *n);
 extern NODE *format_val(const char *format, int index, NODE *s);
-extern NODE *r_force_string(NODE *s);
-extern NODE *dupnode(NODE *n);
-extern NODE *mk_number(AWKNUM x, unsigned int flags);
-extern NODE *r_make_str_node(const char *s, unsigned long len, int scan);
-extern NODE *more_nodes(void);
-extern void unref(NODE *tmp);
+extern NODE *r_dupnode(NODE *n);
+extern NODE *make_number(AWKNUM x);
+extern NODE *r_make_str_node(const char *s, size_t len, int already_malloced);
+extern void *more_blocks(int id);
+extern void r_unref(NODE *tmp);
 extern int parse_escape(const char **string_ptr);
+extern size_t scan_escape(char *s, size_t len);
+
 #ifdef MBS_SUPPORT
 extern NODE *str2wstr(NODE *n, size_t **ptr);
 extern NODE *wstr2str(NODE *n);
@@ -1363,6 +1493,29 @@ extern int reisstring(const char *text, size_t len, 
Regexp *re, const char *buf)
 extern int remaybelong(const char *text, size_t len);
 extern int isnondecimal(const char *str, int use_locale);
 
+/* symbol.c */
+extern NODE *install_symbol(char *name, NODETYPE type);
+extern NODE *remove_symbol(NODE *r);
+extern void destroy_symbol(NODE *r);
+extern void release_symbols(NODE *symlist, int keep_globals);
+extern void append_symbol(NODE *r);
+extern NODE *lookup(const char *name);
+extern NODE *make_params(char **pnames, int pcount);
+extern void install_params(NODE *func);
+extern void remove_params(NODE *func);
+extern void release_all_vars(void);
+extern int foreach_func(NODE **table, int (*)(INSTRUCTION *, void *), void *);
+extern INSTRUCTION *bcalloc(OPCODE op, int size, int srcline);
+extern void bcfree(INSTRUCTION *);
+extern AWK_CONTEXT *new_context(void);
+extern void push_context(AWK_CONTEXT *ctxt);
+extern void pop_context();
+extern int in_main_context();
+extern void free_context(AWK_CONTEXT *ctxt, int );
+extern NODE **variable_list();
+extern NODE **function_list(int sort);
+extern void print_vars(NODE **table, Func_print print_func, FILE *fp);
+
 /* floatcomp.c */
 #ifdef VMS     /* VMS linker weirdness? */
 #define Ceil   gawk_ceil
diff --git a/awkgram.c b/awkgram.c
index 4edec57..efc0739 100644
--- a/awkgram.c
+++ b/awkgram.c
@@ -86,19 +86,15 @@ static char *get_src_buf(void);
 static int yylex(void);
 int    yyparse(void); 
 static INSTRUCTION *snode(INSTRUCTION *subn, INSTRUCTION *op);
-static int func_install(INSTRUCTION *fp, INSTRUCTION *def);
-static void pop_params(NODE *params);
-static NODE *make_param(char *pname);
+static char **check_params(char *fname, int pcount, INSTRUCTION *list);
+static int install_function(char *fname, INSTRUCTION *fi, INSTRUCTION *plist);
 static NODE *mk_rexp(INSTRUCTION *exp);
-static void append_param(char *pname);
-static int dup_parms(INSTRUCTION *fp, NODE *func);
 static void param_sanity(INSTRUCTION *arglist);
 static int parms_shadow(INSTRUCTION *pc, int *shadow);
 static int isnoeffect(OPCODE type);
 static INSTRUCTION *make_assignable(INSTRUCTION *ip);
 static void dumpintlstr(const char *str, size_t len);
 static void dumpintlstr2(const char *str1, size_t len1, const char *str2, 
size_t len2);
-static int isarray(NODE *n);
 static int include_source(INSTRUCTION *file);
 static void next_sourcefile(void);
 static char *tokexpand(void);
@@ -107,6 +103,7 @@ static char *tokexpand(void);
 
 static INSTRUCTION *mk_program(void);
 static INSTRUCTION *append_rule(INSTRUCTION *pattern, INSTRUCTION *action);
+static INSTRUCTION *mk_function(INSTRUCTION *fi, INSTRUCTION *def);
 static INSTRUCTION *mk_condition(INSTRUCTION *cond, INSTRUCTION *ifp, 
INSTRUCTION *true_branch,
                INSTRUCTION *elsep,     INSTRUCTION *false_branch);
 static INSTRUCTION *mk_expression_list(INSTRUCTION *list, INSTRUCTION *s1);
@@ -125,13 +122,10 @@ static void add_lint(INSTRUCTION *list, LINTTYPE 
linttype);
 enum defref { FUNC_DEFINE, FUNC_USE };
 static void func_use(const char *name, enum defref how);
 static void check_funcs(void);
-static void free_bcpool(INSTRUCTION *pl);
 
 static ssize_t read_one_line(int fd, void *buffer, size_t count);
 static int one_line_close(int fd);
 
-static void (*install_func)(char *) = NULL;
-
 static int want_source = FALSE;
 static int want_regexp;                /* lexical scanning kludge */
 static int can_return;         /* parsing kludge */
@@ -169,22 +163,11 @@ static int continue_allowed;      /* kludge for continue 
*/
 #define END_SRC        -2000
 
 #define YYDEBUG_LEXER_TEXT (lexeme)
-static int param_counter;
-static NODE *func_params;      /* list of parameters for the current function 
*/
 static char *tokstart = NULL;
 static char *tok = NULL;
 static char *tokend;
 static int errcount = 0;
 
-static NODE *symbol_list;
-extern void destroy_symbol(char *name); 
-
-static long func_count;                /* total number of functions */
-
-#define HASHSIZE       1021    /* this constant only used here */
-NODE *variables[HASHSIZE];
-static int var_count;          /* total number of global variables */
-
 extern char *source;
 extern int sourceline;
 extern SRCFILE *srcfiles;
@@ -206,22 +189,12 @@ static inline INSTRUCTION *list_prepend(INSTRUCTION *l, 
INSTRUCTION *x);
 static inline INSTRUCTION *list_merge(INSTRUCTION *l1, INSTRUCTION *l2);
 
 extern double fmod(double x, double y);
-/*
- * This string cannot occur as a real awk identifier.
- * Use it as a special token to make function parsing
- * uniform, but if it's seen, don't install the function.
- * e.g.
- *     function split(x) { return x }
- *     function x(a) { return a }
- * should only produce one error message, and not core dump.
- */
-static char builtin_func[] = "@builtin";
 
 #define YYSTYPE INSTRUCTION *
 
 
 /* Line 268 of yacc.c  */
-#line 225 "awkgram.c"
+#line 198 "awkgram.c"
 
 /* Enabling traces.  */
 #ifndef YYDEBUG
@@ -367,7 +340,7 @@ typedef int YYSTYPE;
 
 
 /* Line 343 of yacc.c  */
-#line 371 "awkgram.c"
+#line 344 "awkgram.c"
 
 #ifdef short
 # undef short
@@ -583,16 +556,16 @@ union yyalloc
 /* YYFINAL -- State number of the termination state.  */
 #define YYFINAL  2
 /* YYLAST -- Last index in YYTABLE.  */
-#define YYLAST   1157
+#define YYLAST   1150
 
 /* YYNTOKENS -- Number of terminals.  */
 #define YYNTOKENS  74
 /* YYNNTS -- Number of nonterminals.  */
-#define YYNNTS  65
+#define YYNNTS  64
 /* YYNRULES -- Number of rules.  */
-#define YYNRULES  185
+#define YYNRULES  184
 /* YYNRULES -- Number of states.  */
-#define YYNSTATES  330
+#define YYNSTATES  329
 
 /* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX.  */
 #define YYUNDEFTOK  2
@@ -644,110 +617,110 @@ static const yytype_uint16 yyprhs[] =
 {
        0,     0,     3,     4,     7,    10,    13,    16,    19,    22,
       25,    30,    32,    35,    37,    38,    40,    45,    47,    49,
-      51,    53,    59,    61,    63,    65,    68,    70,    72,    73,
-      81,    82,    86,    88,    90,    91,    94,    97,    99,   102,
-     105,   109,   111,   121,   128,   137,   146,   159,   171,   173,
-     176,   179,   182,   185,   189,   190,   195,   198,   199,   204,
-     205,   210,   215,   217,   218,   220,   221,   224,   227,   233,
-     238,   240,   243,   246,   248,   250,   252,   254,   256,   260,
-     261,   262,   266,   273,   283,   285,   288,   289,   291,   292,
-     295,   296,   298,   300,   304,   306,   309,   313,   314,   316,
-     317,   319,   321,   325,   327,   330,   334,   338,   342,   346,
-     350,   354,   358,   362,   368,   370,   372,   374,   377,   379,
-     381,   383,   385,   387,   389,   392,   394,   398,   402,   406,
-     410,   414,   418,   422,   425,   428,   434,   439,   443,   447,
-     451,   455,   459,   463,   465,   468,   472,   477,   482,   484,
-     486,   488,   491,   494,   496,   498,   501,   504,   506,   509,
-     514,   515,   517,   518,   521,   523,   526,   528,   532,   534,
-     537,   540,   542,   545,   547,   551,   553,   555,   556,   559,
-     562,   564,   565,   567,   569,   571
+      51,    53,    59,    61,    63,    65,    68,    70,    72,    79,
+      80,    84,    86,    88,    89,    92,    95,    97,   100,   103,
+     107,   109,   119,   126,   135,   144,   157,   169,   171,   174,
+     177,   180,   183,   187,   188,   193,   196,   197,   202,   203,
+     208,   213,   215,   216,   218,   219,   222,   225,   231,   236,
+     238,   241,   244,   246,   248,   250,   252,   254,   258,   259,
+     260,   264,   271,   281,   283,   286,   287,   289,   290,   293,
+     294,   296,   298,   302,   304,   307,   311,   312,   314,   315,
+     317,   319,   323,   325,   328,   332,   336,   340,   344,   348,
+     352,   356,   360,   366,   368,   370,   372,   375,   377,   379,
+     381,   383,   385,   387,   390,   392,   396,   400,   404,   408,
+     412,   416,   420,   423,   426,   432,   437,   441,   445,   449,
+     453,   457,   461,   463,   466,   470,   475,   480,   482,   484,
+     486,   489,   492,   494,   496,   499,   502,   504,   507,   512,
+     513,   515,   516,   519,   521,   524,   526,   530,   532,   535,
+     538,   540,   543,   545,   549,   551,   553,   554,   557,   560,
+     562,   563,   565,   567,   569
 };
 
 /* YYRHS -- A `-1'-separated list of the rules' RHS.  */
 static const yytype_int16 yyrhs[] =
 {
-      75,     0,    -1,    -1,    75,    76,    -1,    75,   104,    -1,
+      75,     0,    -1,    -1,    75,    76,    -1,    75,   103,    -1,
       75,    47,    -1,    75,     1,    -1,    78,    79,    -1,    78,
-      88,    -1,    82,    79,    -1,    68,    48,    77,    88,    -1,
-       6,    -1,     6,     1,    -1,     1,    -1,    -1,   112,    -1,
-     112,    54,   105,   112,    -1,    17,    -1,    18,    -1,    36,
-      -1,    37,    -1,   132,    87,   133,   135,   105,    -1,     4,
+      87,    -1,    82,    79,    -1,    68,    48,    77,    87,    -1,
+       6,    -1,     6,     1,    -1,     1,    -1,    -1,   111,    -1,
+     111,    54,   104,   111,    -1,    17,    -1,    18,    -1,    36,
+      -1,    37,    -1,   131,    86,   132,   134,   104,    -1,     4,
       -1,     3,    -1,    81,    -1,    68,    49,    -1,    45,    -1,
-      46,    -1,    -1,    35,    83,    80,    66,   107,   134,   105,
-      -1,    -1,    86,    85,     5,    -1,    60,    -1,    51,    -1,
-      -1,    87,    89,    -1,    87,     1,    -1,   104,    -1,   136,
-     105,    -1,   136,   105,    -1,   132,    87,   133,    -1,   103,
-      -1,    23,    66,   112,   134,   105,   132,    96,   105,   133,
-      -1,    26,    66,   112,   134,   105,    89,    -1,    27,   105,
-      89,    26,    66,   112,   134,   105,    -1,    28,    66,     4,
-      40,   129,   134,   105,    89,    -1,    28,    66,    95,   136,
-     105,   112,   136,   105,    95,   134,   105,    89,    -1,    28,
-      66,    95,   136,   105,   136,   105,    95,   134,   105,    89,
-      -1,    90,    -1,    29,    88,    -1,    30,    88,    -1,    33,
-      88,    -1,    39,    88,    -1,    34,   109,    88,    -1,    -1,
-      21,    91,   109,    88,    -1,    92,    88,    -1,    -1,    99,
-      93,   100,   101,    -1,    -1,    22,     4,    94,   123,    -1,
-      22,    66,     4,    67,    -1,   112,    -1,    -1,    92,    -1,
-      -1,    96,    97,    -1,    96,     1,    -1,    24,    98,   137,
-     105,    87,    -1,    25,   137,   105,    87,    -1,     7,    -1,
-      58,     7,    -1,    57,     7,    -1,     8,    -1,    84,    -1,
-      31,    -1,    32,    -1,   110,    -1,    66,   111,   134,    -1,
-      -1,    -1,    10,   102,   116,    -1,    19,    66,   112,   134,
-     105,    89,    -1,    19,    66,   112,   134,   105,    89,    20,
-     105,    89,    -1,    50,    -1,   104,    50,    -1,    -1,   104,
-      -1,    -1,    55,   117,    -1,    -1,   108,    -1,     4,    -1,
-     108,   138,     4,    -1,     1,    -1,   108,     1,    -1,   108,
-     138,     1,    -1,    -1,   112,    -1,    -1,   111,    -1,   112,
-      -1,   111,   138,   112,    -1,     1,    -1,   111,     1,    -1,
-     111,     1,   112,    -1,   111,   138,     1,    -1,   130,   113,
-     112,    -1,   112,    41,   112,    -1,   112,    42,   112,    -1,
-     112,    14,   112,    -1,   112,    40,   129,    -1,   112,   115,
-     112,    -1,   112,    52,   112,    53,   112,    -1,   116,    -1,
-      13,    -1,    12,    -1,    51,    13,    -1,     9,    -1,    55,
-      -1,   114,    -1,    56,    -1,   117,    -1,   118,    -1,   116,
-     117,    -1,   119,    -1,   117,    64,   117,    -1,   117,    59,
-     117,    -1,   117,    60,   117,    -1,   117,    61,   117,    -1,
-     117,    57,   117,    -1,   117,    58,   117,    -1,    38,   122,
-     106,    -1,   130,    43,    -1,   130,    44,    -1,    66,   111,
-     134,    40,   129,    -1,   116,    11,    38,   122,    -1,   118,
-      64,   117,    -1,   118,    59,   117,    -1,   118,    60,   117,
-      -1,   118,    61,   117,    -1,   118,    57,   117,    -1,   118,
-      58,   117,    -1,    84,    -1,    62,   117,    -1,    66,   112,
-     134,    -1,    45,    66,   110,   134,    -1,    46,    66,   110,
-     134,    -1,    46,    -1,   120,    -1,   130,    -1,    43,   130,
-      -1,    44,   130,    -1,     7,    -1,     8,    -1,    58,   117,
-      -1,    57,   117,    -1,   121,    -1,    68,   121,    -1,     3,
-      66,   110,   134,    -1,    -1,   130,    -1,    -1,   124,    16,
-      -1,   125,    -1,   124,   125,    -1,   126,    -1,    69,   111,
-      70,    -1,   126,    -1,   127,   126,    -1,   127,    16,    -1,
-       4,    -1,     4,   128,    -1,   129,    -1,    65,   119,   131,
-      -1,    43,    -1,    44,    -1,    -1,    71,   105,    -1,    72,
-     105,    -1,    67,    -1,    -1,   136,    -1,    73,    -1,    53,
-      -1,    54,   105,    -1
+      46,    -1,    35,    80,    66,   106,   133,   104,    -1,    -1,
+      85,    84,     5,    -1,    60,    -1,    51,    -1,    -1,    86,
+      88,    -1,    86,     1,    -1,   103,    -1,   135,   104,    -1,
+     135,   104,    -1,   131,    86,   132,    -1,   102,    -1,    23,
+      66,   111,   133,   104,   131,    95,   104,   132,    -1,    26,
+      66,   111,   133,   104,    88,    -1,    27,   104,    88,    26,
+      66,   111,   133,   104,    -1,    28,    66,     4,    40,   128,
+     133,   104,    88,    -1,    28,    66,    94,   135,   104,   111,
+     135,   104,    94,   133,   104,    88,    -1,    28,    66,    94,
+     135,   104,   135,   104,    94,   133,   104,    88,    -1,    89,
+      -1,    29,    87,    -1,    30,    87,    -1,    33,    87,    -1,
+      39,    87,    -1,    34,   108,    87,    -1,    -1,    21,    90,
+     108,    87,    -1,    91,    87,    -1,    -1,    98,    92,    99,
+     100,    -1,    -1,    22,     4,    93,   122,    -1,    22,    66,
+       4,    67,    -1,   111,    -1,    -1,    91,    -1,    -1,    95,
+      96,    -1,    95,     1,    -1,    24,    97,   136,   104,    86,
+      -1,    25,   136,   104,    86,    -1,     7,    -1,    58,     7,
+      -1,    57,     7,    -1,     8,    -1,    83,    -1,    31,    -1,
+      32,    -1,   109,    -1,    66,   110,   133,    -1,    -1,    -1,
+      10,   101,   115,    -1,    19,    66,   111,   133,   104,    88,
+      -1,    19,    66,   111,   133,   104,    88,    20,   104,    88,
+      -1,    50,    -1,   103,    50,    -1,    -1,   103,    -1,    -1,
+      55,   116,    -1,    -1,   107,    -1,     4,    -1,   107,   137,
+       4,    -1,     1,    -1,   107,     1,    -1,   107,   137,     1,
+      -1,    -1,   111,    -1,    -1,   110,    -1,   111,    -1,   110,
+     137,   111,    -1,     1,    -1,   110,     1,    -1,   110,     1,
+     111,    -1,   110,   137,     1,    -1,   129,   112,   111,    -1,
+     111,    41,   111,    -1,   111,    42,   111,    -1,   111,    14,
+     111,    -1,   111,    40,   128,    -1,   111,   114,   111,    -1,
+     111,    52,   111,    53,   111,    -1,   115,    -1,    13,    -1,
+      12,    -1,    51,    13,    -1,     9,    -1,    55,    -1,   113,
+      -1,    56,    -1,   116,    -1,   117,    -1,   115,   116,    -1,
+     118,    -1,   116,    64,   116,    -1,   116,    59,   116,    -1,
+     116,    60,   116,    -1,   116,    61,   116,    -1,   116,    57,
+     116,    -1,   116,    58,   116,    -1,    38,   121,   105,    -1,
+     129,    43,    -1,   129,    44,    -1,    66,   110,   133,    40,
+     128,    -1,   115,    11,    38,   121,    -1,   117,    64,   116,
+      -1,   117,    59,   116,    -1,   117,    60,   116,    -1,   117,
+      61,   116,    -1,   117,    57,   116,    -1,   117,    58,   116,
+      -1,    83,    -1,    62,   116,    -1,    66,   111,   133,    -1,
+      45,    66,   109,   133,    -1,    46,    66,   109,   133,    -1,
+      46,    -1,   119,    -1,   129,    -1,    43,   129,    -1,    44,
+     129,    -1,     7,    -1,     8,    -1,    58,   116,    -1,    57,
+     116,    -1,   120,    -1,    68,   120,    -1,     3,    66,   109,
+     133,    -1,    -1,   129,    -1,    -1,   123,    16,    -1,   124,
+      -1,   123,   124,    -1,   125,    -1,    69,   110,    70,    -1,
+     125,    -1,   126,   125,    -1,   126,    16,    -1,     4,    -1,
+       4,   127,    -1,   128,    -1,    65,   118,   130,    -1,    43,
+      -1,    44,    -1,    -1,    71,   104,    -1,    72,   104,    -1,
+      67,    -1,    -1,   135,    -1,    73,    -1,    53,    -1,    54,
+     104,    -1
 };
 
 /* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
 static const yytype_uint16 yyrline[] =
 {
-       0,   218,   218,   220,   225,   226,   230,   242,   246,   257,
-     265,   273,   281,   283,   289,   290,   292,   318,   329,   340,
-     346,   355,   365,   367,   369,   380,   385,   386,   391,   390,
-     420,   419,   452,   454,   459,   460,   473,   478,   479,   483,
-     485,   487,   494,   584,   626,   668,   783,   790,   797,   807,
-     816,   825,   834,   849,   865,   864,   876,   888,   888,   984,
-     984,  1009,  1032,  1038,  1039,  1045,  1046,  1053,  1058,  1070,
-    1084,  1086,  1092,  1097,  1099,  1107,  1109,  1118,  1119,  1127,
-    1132,  1132,  1143,  1147,  1155,  1156,  1159,  1161,  1166,  1167,
-    1174,  1176,  1180,  1186,  1193,  1195,  1197,  1204,  1205,  1211,
-    1212,  1217,  1219,  1224,  1226,  1228,  1230,  1236,  1243,  1245,
-    1247,  1263,  1273,  1280,  1282,  1287,  1289,  1291,  1299,  1301,
-    1306,  1308,  1313,  1315,  1317,  1370,  1372,  1374,  1376,  1378,
-    1380,  1382,  1384,  1407,  1412,  1417,  1442,  1448,  1450,  1452,
-    1454,  1456,  1458,  1463,  1467,  1498,  1500,  1506,  1512,  1525,
-    1526,  1527,  1532,  1537,  1541,  1545,  1557,  1570,  1575,  1611,
-    1629,  1630,  1636,  1637,  1642,  1644,  1651,  1668,  1685,  1687,
-    1694,  1699,  1707,  1721,  1734,  1743,  1747,  1751,  1755,  1759,
-    1763,  1766,  1768,  1772,  1776,  1780
+       0,   191,   191,   193,   198,   199,   203,   215,   219,   230,
+     236,   244,   252,   254,   260,   261,   263,   289,   300,   311,
+     317,   326,   336,   338,   340,   346,   351,   352,   356,   375,
+     374,   408,   410,   415,   416,   429,   434,   435,   439,   441,
+     443,   450,   540,   582,   624,   739,   746,   753,   763,   772,
+     781,   790,   805,   821,   820,   832,   844,   844,   938,   938,
+     963,   986,   992,   993,   999,  1000,  1007,  1012,  1024,  1038,
+    1040,  1046,  1051,  1053,  1061,  1063,  1072,  1073,  1081,  1086,
+    1086,  1097,  1101,  1109,  1110,  1113,  1115,  1120,  1121,  1130,
+    1131,  1136,  1141,  1147,  1149,  1151,  1158,  1159,  1165,  1166,
+    1171,  1173,  1178,  1180,  1182,  1184,  1190,  1197,  1199,  1201,
+    1217,  1227,  1234,  1236,  1241,  1243,  1245,  1253,  1255,  1260,
+    1262,  1267,  1269,  1271,  1321,  1323,  1325,  1327,  1329,  1331,
+    1333,  1335,  1358,  1363,  1368,  1393,  1399,  1401,  1403,  1405,
+    1407,  1409,  1414,  1418,  1449,  1451,  1457,  1463,  1476,  1477,
+    1478,  1483,  1488,  1492,  1496,  1509,  1522,  1527,  1563,  1581,
+    1582,  1588,  1589,  1594,  1596,  1603,  1620,  1637,  1639,  1646,
+    1651,  1659,  1669,  1682,  1691,  1695,  1699,  1703,  1707,  1711,
+    1714,  1716,  1720,  1724,  1728
 };
 #endif
 
@@ -769,10 +742,10 @@ static const char *const yytname[] =
   "'+'", "'-'", "'*'", "'/'", "'%'", "'!'", "UNARY", "'^'", "'$'", "'('",
   "')'", "'@'", "'['", "']'", "'{'", "'}'", "';'", "$accept", "program",
   "rule", "source", "pattern", "action", "func_name", "lex_builtin",
-  "function_prologue", "address@hidden", "regexp", "address@hidden", 
"a_slash", "statements",
-  "statement_term", "statement", "non_compound_stmt", "address@hidden", 
"simple_stmt",
-  "address@hidden", "address@hidden", "opt_simple_stmt", "case_statements", 
"case_statement",
-  "case_value", "print", "print_expression_list", "output_redir", 
"address@hidden",
+  "function_prologue", "regexp", "address@hidden", "a_slash", "statements",
+  "statement_term", "statement", "non_compound_stmt", "address@hidden", 
"simple_stmt",
+  "address@hidden", "address@hidden", "opt_simple_stmt", "case_statements", 
"case_statement",
+  "case_value", "print", "print_expression_list", "output_redir", 
"address@hidden",
   "if_statement", "nls", "opt_nls", "input_redir", "opt_param_list",
   "param_list", "opt_exp", "opt_expression_list", "expression_list", "exp",
   "assign_operator", "relop_or_less", "a_relop", "common_exp", "simp_exp",
@@ -805,23 +778,23 @@ static const yytype_uint8 yyr1[] =
 {
        0,    74,    75,    75,    75,    75,    75,    76,    76,    76,
       76,    77,    77,    77,    78,    78,    78,    78,    78,    78,
-      78,    79,    80,    80,    80,    80,    81,    81,    83,    82,
-      85,    84,    86,    86,    87,    87,    87,    88,    88,    89,
-      89,    89,    89,    89,    89,    89,    89,    89,    89,    90,
-      90,    90,    90,    90,    91,    90,    90,    93,    92,    94,
-      92,    92,    92,    95,    95,    96,    96,    96,    97,    97,
-      98,    98,    98,    98,    98,    99,    99,   100,   100,   101,
-     102,   101,   103,   103,   104,   104,   105,   105,   106,   106,
-     107,   107,   108,   108,   108,   108,   108,   109,   109,   110,
-     110,   111,   111,   111,   111,   111,   111,   112,   112,   112,
-     112,   112,   112,   112,   112,   113,   113,   113,   114,   114,
-     115,   115,   116,   116,   116,   117,   117,   117,   117,   117,
-     117,   117,   117,   117,   117,   117,   118,   118,   118,   118,
-     118,   118,   118,   119,   119,   119,   119,   119,   119,   119,
-     119,   119,   119,   119,   119,   119,   119,   120,   120,   121,
-     122,   122,   123,   123,   124,   124,   125,   126,   127,   127,
-     128,   129,   129,   130,   130,   131,   131,   131,   132,   133,
-     134,   135,   135,   136,   137,   138
+      78,    79,    80,    80,    80,    80,    81,    81,    82,    84,
+      83,    85,    85,    86,    86,    86,    87,    87,    88,    88,
+      88,    88,    88,    88,    88,    88,    88,    88,    89,    89,
+      89,    89,    89,    90,    89,    89,    92,    91,    93,    91,
+      91,    91,    94,    94,    95,    95,    95,    96,    96,    97,
+      97,    97,    97,    97,    98,    98,    99,    99,   100,   101,
+     100,   102,   102,   103,   103,   104,   104,   105,   105,   106,
+     106,   107,   107,   107,   107,   107,   108,   108,   109,   109,
+     110,   110,   110,   110,   110,   110,   111,   111,   111,   111,
+     111,   111,   111,   111,   112,   112,   112,   113,   113,   114,
+     114,   115,   115,   115,   116,   116,   116,   116,   116,   116,
+     116,   116,   116,   116,   116,   117,   117,   117,   117,   117,
+     117,   117,   118,   118,   118,   118,   118,   118,   118,   118,
+     118,   118,   118,   118,   118,   118,   119,   119,   120,   121,
+     121,   122,   122,   123,   123,   124,   125,   126,   126,   127,
+     128,   128,   129,   129,   130,   130,   130,   131,   132,   133,
+     134,   134,   135,   136,   137
 };
 
 /* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN.  */
@@ -829,23 +802,23 @@ static const yytype_uint8 yyr2[] =
 {
        0,     2,     0,     2,     2,     2,     2,     2,     2,     2,
        4,     1,     2,     1,     0,     1,     4,     1,     1,     1,
-       1,     5,     1,     1,     1,     2,     1,     1,     0,     7,
-       0,     3,     1,     1,     0,     2,     2,     1,     2,     2,
-       3,     1,     9,     6,     8,     8,    12,    11,     1,     2,
-       2,     2,     2,     3,     0,     4,     2,     0,     4,     0,
-       4,     4,     1,     0,     1,     0,     2,     2,     5,     4,
-       1,     2,     2,     1,     1,     1,     1,     1,     3,     0,
-       0,     3,     6,     9,     1,     2,     0,     1,     0,     2,
-       0,     1,     1,     3,     1,     2,     3,     0,     1,     0,
-       1,     1,     3,     1,     2,     3,     3,     3,     3,     3,
-       3,     3,     3,     5,     1,     1,     1,     2,     1,     1,
-       1,     1,     1,     1,     2,     1,     3,     3,     3,     3,
-       3,     3,     3,     2,     2,     5,     4,     3,     3,     3,
-       3,     3,     3,     1,     2,     3,     4,     4,     1,     1,
-       1,     2,     2,     1,     1,     2,     2,     1,     2,     4,
-       0,     1,     0,     2,     1,     2,     1,     3,     1,     2,
-       2,     1,     2,     1,     3,     1,     1,     0,     2,     2,
-       1,     0,     1,     1,     1,     2
+       1,     5,     1,     1,     1,     2,     1,     1,     6,     0,
+       3,     1,     1,     0,     2,     2,     1,     2,     2,     3,
+       1,     9,     6,     8,     8,    12,    11,     1,     2,     2,
+       2,     2,     3,     0,     4,     2,     0,     4,     0,     4,
+       4,     1,     0,     1,     0,     2,     2,     5,     4,     1,
+       2,     2,     1,     1,     1,     1,     1,     3,     0,     0,
+       3,     6,     9,     1,     2,     0,     1,     0,     2,     0,
+       1,     1,     3,     1,     2,     3,     0,     1,     0,     1,
+       1,     3,     1,     2,     3,     3,     3,     3,     3,     3,
+       3,     3,     5,     1,     1,     1,     2,     1,     1,     1,
+       1,     1,     1,     2,     1,     3,     3,     3,     3,     3,
+       3,     3,     2,     2,     5,     4,     3,     3,     3,     3,
+       3,     3,     1,     2,     3,     4,     4,     1,     1,     1,
+       2,     2,     1,     1,     2,     2,     1,     2,     4,     0,
+       1,     0,     2,     1,     2,     1,     3,     1,     2,     2,
+       1,     2,     1,     3,     1,     1,     0,     2,     2,     1,
+       0,     1,     1,     1,     2
 };
 
 /* YYDEFACT[STATE-NAME] -- Default reduction number in state STATE-NUM.
@@ -853,353 +826,353 @@ static const yytype_uint8 yyr2[] =
    means the default is an error.  */
 static const yytype_uint8 yydefact[] =
 {
-       2,     0,     1,     6,     0,   171,   153,   154,    17,    18,
-      28,    19,    20,   160,     0,     0,     0,   148,     5,    84,
-      33,     0,     0,    32,     0,     0,     0,     0,     3,     0,
-       0,   143,    30,     4,    15,   114,   122,   123,   125,   149,
-     157,   173,   150,     0,     0,   168,     0,   172,     0,    88,
-     161,   151,   152,     0,     0,     0,   156,   150,   155,   144,
-       0,   177,   150,   103,     0,   101,     0,   158,    86,   183,
-       7,     8,    37,    34,    86,     9,     0,    85,   118,     0,
-       0,     0,     0,     0,    86,   119,   121,   120,     0,     0,
-     124,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,   116,   115,   133,   134,     0,     0,     0,
-       0,   101,     0,   170,   169,    23,    22,    26,    27,     0,
-       0,    24,     0,   132,     0,     0,     0,   175,   176,   174,
-     104,    86,   180,     0,     0,   145,    13,     0,     0,    87,
-     178,     0,    38,    31,   110,   111,   108,   109,     0,     0,
-     112,   160,   130,   131,   127,   128,   129,   126,   141,   142,
-     138,   139,   140,   137,   117,   107,   159,   167,    25,     0,
-      89,   146,   147,   105,   185,     0,   106,   102,    12,    10,
-      36,     0,    54,     0,     0,     0,    86,     0,     0,     0,
-      75,    76,     0,    97,     0,    86,    35,    48,     0,    57,
-      41,    62,    34,   181,    86,     0,    16,   136,    94,    92,
-       0,     0,   135,     0,    97,    59,     0,     0,     0,     0,
-      63,    49,    50,    51,     0,    98,    52,   179,    56,     0,
-       0,    86,   182,    39,   113,    86,    95,     0,     0,     0,
-     162,     0,     0,     0,     0,   171,    64,     0,    53,     0,
-      79,    77,    40,    21,    29,    96,    93,    86,    55,    60,
-       0,   164,   166,    61,    86,    86,     0,     0,    86,     0,
-      80,    58,     0,   163,   165,     0,     0,     0,     0,     0,
-      78,     0,    82,    65,    43,     0,    86,     0,    86,    81,
-      86,     0,    86,     0,    86,    63,     0,    67,     0,     0,
-      66,     0,    44,    45,    63,     0,    83,    70,    73,     0,
-       0,    74,     0,   184,    86,    42,     0,    86,    72,    71,
-      86,    34,    86,     0,    34,     0,     0,    47,     0,    46
+       2,     0,     1,     6,     0,   170,   152,   153,    17,    18,
+       0,    19,    20,   159,     0,     0,     0,   147,     5,    83,
+      32,     0,     0,    31,     0,     0,     0,     0,     3,     0,
+       0,   142,    29,     4,    15,   113,   121,   122,   124,   148,
+     156,   172,   149,     0,     0,   167,     0,   171,    23,    22,
+      26,    27,     0,     0,    24,    87,   160,   150,   151,     0,
+       0,     0,   155,   149,   154,   143,     0,   176,   149,   102,
+       0,   100,     0,   157,    85,   182,     7,     8,    36,    33,
+      85,     9,     0,    84,   117,     0,     0,     0,     0,     0,
+      85,   118,   120,   119,     0,     0,   123,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,   115,
+     114,   132,   133,     0,     0,     0,     0,   100,     0,   169,
+     168,    25,     0,     0,   131,     0,     0,     0,   174,   175,
+     173,   103,    85,   179,     0,     0,   144,    13,     0,     0,
+      86,   177,     0,    37,    30,   109,   110,   107,   108,     0,
+       0,   111,   159,   129,   130,   126,   127,   128,   125,   140,
+     141,   137,   138,   139,   136,   116,   106,   158,   166,    93,
+      91,     0,     0,    88,   145,   146,   104,   184,     0,   105,
+     101,    12,    10,    35,     0,    53,     0,     0,     0,    85,
+       0,     0,     0,    74,    75,     0,    96,     0,    85,    34,
+      47,     0,    56,    40,    61,    33,   180,    85,     0,    16,
+     135,    85,    94,     0,   134,     0,    96,    58,     0,     0,
+       0,     0,    62,    48,    49,    50,     0,    97,    51,   178,
+      55,     0,     0,    85,   181,    38,   112,    28,    95,    92,
+       0,     0,   161,     0,     0,     0,     0,   170,    63,     0,
+      52,     0,    78,    76,    39,    21,    85,    54,    59,     0,
+     163,   165,    60,    85,    85,     0,     0,    85,     0,    79,
+      57,     0,   162,   164,     0,     0,     0,     0,     0,    77,
+       0,    81,    64,    42,     0,    85,     0,    85,    80,    85,
+       0,    85,     0,    85,    62,     0,    66,     0,     0,    65,
+       0,    43,    44,    62,     0,    82,    69,    72,     0,     0,
+      73,     0,   183,    85,    41,     0,    85,    71,    70,    85,
+      33,    85,     0,    33,     0,     0,    46,     0,    45
 };
 
 /* YYDEFGOTO[NTERM-NUM].  */
 static const yytype_int16 yydefgoto[] =
 {
-      -1,     1,    28,   138,    29,    70,   120,   121,    30,    48,
-      31,    76,    32,   141,    71,   196,   197,   214,   198,   229,
-     240,   247,   291,   300,   312,   199,   250,   271,   281,   200,
-     139,   140,   123,   210,   211,   224,   109,   110,   201,   108,
-      87,    88,    35,    36,    37,    38,    39,    40,    49,   259,
-     260,   261,    45,    46,    47,    41,    42,   129,   202,   203,
-     135,   231,   204,   314,   134
+      -1,     1,    28,   139,    29,    76,    53,    54,    30,    31,
+      82,    32,   142,    77,   199,   200,   216,   201,   231,   242,
+     249,   290,   299,   311,   202,   252,   270,   280,   203,   140,
+     141,   124,   171,   172,   226,   115,   116,   204,   114,    93,
+      94,    35,    36,    37,    38,    39,    40,    55,   258,   259,
+     260,    45,    46,    47,    41,    42,   130,   205,   206,   136,
+     233,   207,   313,   135
 };
 
 /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
    STATE-NUM.  */
-#define YYPACT_NINF -269
+#define YYPACT_NINF -264
 static const yytype_int16 yypact[] =
 {
-    -269,   335,  -269,  -269,   -31,   -24,  -269,  -269,  -269,  -269,
-    -269,  -269,  -269,    12,    12,    12,   -19,   -12,  -269,  -269,
-    -269,   978,   978,  -269,   978,  1023,   804,    21,  -269,   115,
-     -21,  -269,  -269,     8,  1062,   952,   -20,   330,  -269,  -269,
-    -269,  -269,   246,   736,   804,  -269,     2,  -269,   205,    15,
-    -269,  -269,  -269,   736,   736,    70,    52,    80,    52,    52,
-     978,   147,  -269,  -269,    50,   308,   174,  -269,    64,  -269,
-    -269,  -269,     8,  -269,    64,  -269,   129,  -269,  -269,   978,
-     143,   978,   978,   978,    64,  -269,  -269,  -269,   978,   112,
-     -20,   978,   978,   978,   978,   978,   978,   978,   978,   978,
-     978,   978,   978,  -269,  -269,  -269,  -269,   141,   978,    90,
-     152,  1101,    48,  -269,  -269,  -269,  -269,  -269,  -269,   111,
-     105,  -269,   978,  -269,    90,    90,   308,  -269,  -269,  -269,
-     978,    64,  -269,   134,   830,  -269,  -269,    13,   -16,     8,
-    -269,   552,  -269,  -269,    53,  -269,   142,   300,  1081,   978,
-     103,    12,   185,   185,    52,    52,    52,    52,   185,   185,
-      52,    52,    52,    52,  -269,  1101,  -269,  -269,  -269,    63,
-     -20,  -269,  -269,  1101,  -269,   143,  -269,  1101,  -269,  -269,
-    -269,   121,  -269,     6,   130,   137,    64,   139,   -16,   -16,
-    -269,  -269,   -16,   978,   -16,    64,  -269,  -269,   -16,  -269,
-    -269,  1101,  -269,   127,    64,   978,  1101,  -269,  -269,  -269,
-      90,   118,  -269,   978,   978,  -269,   180,   978,   978,   665,
-     875,  -269,  -269,  -269,   -16,  1101,  -269,  -269,  -269,   598,
-     552,    64,  -269,  -269,  1101,    64,  -269,    28,   308,   -16,
-     -24,   140,   308,   308,   189,   -14,  -269,   127,  -269,   804,
-     201,  -269,  -269,  -269,  -269,  -269,  -269,    64,  -269,  -269,
-      14,  -269,  -269,  -269,    64,    64,   158,   143,    64,    50,
-    -269,  -269,   665,  -269,  -269,   -21,   665,   978,    90,   710,
-     134,   978,   198,  -269,  -269,   308,    64,  1056,    64,   952,
-      64,    60,    64,   665,    64,   907,   665,  -269,   119,   177,
-    -269,   155,  -269,  -269,   907,    90,  -269,  -269,  -269,   224,
-     228,  -269,   177,  -269,    64,  -269,    90,    64,  -269,  -269,
-      64,  -269,    64,   665,  -269,   406,   665,  -269,   479,  -269
+    -264,   367,  -264,  -264,   -31,   -42,  -264,  -264,  -264,  -264,
+     165,  -264,  -264,    46,    46,    46,   -29,   -27,  -264,  -264,
+    -264,  1010,  1010,  -264,  1010,  1055,   836,    27,  -264,   -35,
+      -7,  -264,  -264,    17,  1088,   984,   288,   362,  -264,  -264,
+    -264,  -264,   146,   768,   836,  -264,     1,  -264,  -264,  -264,
+    -264,  -264,    60,   -18,  -264,    11,  -264,  -264,  -264,   768,
+     768,    74,    52,     9,    52,    52,  1010,    13,  -264,  -264,
+      53,   341,    28,  -264,    79,  -264,  -264,  -264,    17,  -264,
+      79,  -264,   119,  -264,  -264,  1010,   148,  1010,  1010,  1010,
+      79,  -264,  -264,  -264,  1010,   122,   288,  1010,  1010,  1010,
+    1010,  1010,  1010,  1010,  1010,  1010,  1010,  1010,  1010,  -264,
+    -264,  -264,  -264,   151,  1010,    94,    81,  1094,    40,  -264,
+    -264,  -264,    45,  1010,  -264,    94,    94,   341,  -264,  -264,
+    -264,  1010,    79,  -264,   125,   862,  -264,  -264,    82,   -22,
+      17,  -264,   584,  -264,  -264,    62,  -264,   212,   267,   301,
+    1010,   118,    46,   127,   127,    52,    52,    52,    52,   127,
+     127,    52,    52,    52,    52,  -264,  1094,  -264,  -264,  -264,
+    -264,    94,    61,   288,  -264,  -264,  1094,  -264,   148,  -264,
+    1094,  -264,  -264,  -264,   105,  -264,    10,   109,   112,    79,
+     113,   -22,   -22,  -264,  -264,   -22,  1010,   -22,    79,  -264,
+    -264,   -22,  -264,  -264,  1094,  -264,   107,    79,  1010,  1094,
+    -264,    79,  -264,    43,  -264,  1010,  1010,  -264,   180,  1010,
+    1010,   697,   907,  -264,  -264,  -264,   -22,  1094,  -264,  -264,
+    -264,   630,   584,    79,  -264,  -264,  1094,  -264,  -264,  -264,
+     341,   -22,   -42,   126,   341,   341,   166,   -14,  -264,   107,
+    -264,   836,   190,  -264,  -264,  -264,    79,  -264,  -264,    16,
+    -264,  -264,  -264,    79,    79,   136,   148,    79,    53,  -264,
+    -264,   697,  -264,  -264,    -7,   697,  1010,    94,   742,   125,
+    1010,   186,  -264,  -264,   341,    79,   278,    79,   984,    79,
+     132,    79,   697,    79,   939,   697,  -264,   240,   155,  -264,
+     137,  -264,  -264,   939,    94,  -264,  -264,  -264,   205,   206,
+    -264,   155,  -264,    79,  -264,    94,    79,  -264,  -264,    79,
+    -264,    79,   697,  -264,   438,   697,  -264,   511,  -264
 };
 
 /* YYPGOTO[NTERM-NUM].  */
 static const yytype_int16 yypgoto[] =
 {
-    -269,  -269,  -269,  -269,  -269,   208,  -269,  -269,  -269,  -269,
-     -58,  -269,  -269,  -193,    72,  -171,  -269,  -269,  -189,  -269,
-    -269,  -268,  -269,  -269,  -269,  -269,  -269,  -269,  -269,  -269,
-      45,    37,  -269,  -269,  -269,    38,   -48,   -23,    -1,  -269,
-    -269,  -269,   -26,    44,  -269,   217,  -269,     1,   102,  -269,
-    -269,    -3,   -39,  -269,  -269,   -72,    -2,  -269,   -28,  -213,
-     -49,  -269,   -25,   -47,    66
+    -264,  -264,  -264,  -264,  -264,   187,  -264,  -264,  -264,   -74,
+    -264,  -264,  -197,    98,  -203,  -264,  -264,  -213,  -264,  -264,
+    -263,  -264,  -264,  -264,  -264,  -264,  -264,  -264,  -264,    44,
+      73,  -264,  -264,  -264,    18,   -54,   -23,    -1,  -264,  -264,
+    -264,   -55,    39,  -264,   202,  -264,   124,    77,  -264,  -264,
+     -19,   -39,  -264,  -264,   -70,    -2,  -264,   -28,  -222,   -46,
+    -264,   -25,   -79,    70
 };
 
 /* YYTABLE[YYPACT[STATE-NUM]].  What to do in state STATE-NUM.  If
    positive, shift that token.  If negative, reduce the rule which
    number is the opposite.  If YYTABLE_NINF, syntax error.  */
-#define YYTABLE_NINF -101
+#define YYTABLE_NINF -100
 static const yytype_int16 yytable[] =
 {
-      34,    73,    73,    64,    74,   124,   125,   114,   145,   230,
-     215,    50,    51,    52,   178,   133,     5,   252,   113,    57,
-      57,   112,    57,    62,     4,    65,   267,   305,    67,   255,
-     273,   246,   256,    57,    19,    43,   316,    91,    92,    93,
-      94,    95,   111,   111,    96,    44,    33,    53,   244,   130,
-      68,   130,   111,   111,    54,    44,    67,    69,    77,   126,
-     166,   297,    78,   -11,   208,    56,    58,   209,    59,    66,
-     122,    44,   216,     4,    72,   171,   172,    25,   144,    90,
-     146,   147,   148,    44,   298,   299,   -11,   150,   315,    57,
-      57,    57,    57,    57,    57,    57,    57,    57,    57,    57,
-      57,   282,   131,   212,   131,   284,   246,   165,    85,    86,
-      19,   142,  -101,    74,    19,   246,    96,   132,   167,   236,
-      57,   149,   303,   105,   106,   306,   307,   308,   325,   173,
-     -90,   328,   -86,   177,   143,   152,   153,   154,   155,   156,
-     157,   158,   159,   160,   161,   162,   163,     5,   206,    50,
-     151,    78,   327,   130,   164,   329,    79,   132,  -101,  -101,
-     168,   235,  -100,    74,    74,    19,   170,    74,   174,    74,
-      20,   169,   131,    74,   175,   136,   309,   310,   232,    23,
-     137,   251,    80,    72,   241,   -91,    68,   213,    69,   257,
-     127,   128,   225,   264,   265,   278,   217,    85,    86,    74,
-      69,   262,  -100,   218,   234,   220,   131,   263,   115,   116,
-     179,   270,   238,   225,    74,   266,   242,   243,   290,  -100,
-     280,   262,   268,   219,   277,  -100,   269,   195,   111,   286,
-     313,   318,   227,    72,    72,   319,   292,    72,    75,    72,
-     311,   233,    61,    72,    93,    94,    95,   283,    65,    96,
-     117,   118,   239,   207,   288,   289,   317,   274,   103,   104,
-     221,   222,   294,     0,   223,   320,   226,   322,   253,    72,
-     228,     0,   254,   119,     0,     0,   285,   237,   287,    57,
-       0,     0,     0,     0,    72,     0,     0,    57,     0,   105,
-     106,     0,     0,     0,   272,     0,   248,   107,     0,     0,
-       0,   275,   276,     0,     0,   279,     0,     0,     0,    78,
-       0,   258,     0,     0,    79,     0,     0,    78,     0,     0,
-       0,     0,    79,   293,     0,   295,     0,   296,   301,   302,
-       0,   304,     0,    90,     0,     2,     3,     0,     4,     5,
-      80,    81,     6,     7,     0,     0,     0,     0,    80,    81,
-      82,   321,     8,     9,   323,    85,    86,   324,     0,   326,
-      83,     0,     0,    85,    86,     0,     0,     0,     0,     0,
-      10,    11,    12,    13,     0,   132,     0,     0,    14,    15,
-      16,    17,    18,     0,     0,    19,    20,    97,    98,    99,
-     100,   101,    21,    22,   102,    23,     0,    24,     0,     0,
-      25,    26,     0,    27,     0,     0,   -14,   180,   -14,     4,
-       5,     0,     0,     6,     7,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,   181,     0,   182,   183,   184,
-     -69,   -69,   185,   186,   187,   188,   189,   190,   191,   192,
-     193,     0,     0,     0,    13,   194,     0,     0,     0,    14,
-      15,    16,    17,     0,     0,     0,   -69,    20,     0,     0,
-       0,     0,     0,    21,    22,     0,    23,     0,    24,     0,
-       0,    25,    26,     0,    55,     0,     0,    68,   -69,    69,
-     180,     0,     4,     5,     0,     0,     6,     7,     0,     0,
-       0,     0,     0,     0,     0,     0,     0,     0,   181,     0,
-     182,   183,   184,   -68,   -68,   185,   186,   187,   188,   189,
-     190,   191,   192,   193,     0,     0,     0,    13,   194,     0,
-       0,     0,    14,    15,    16,    17,     0,     0,     0,   -68,
-      20,     0,     0,     0,     0,     0,    21,    22,     0,    23,
-       0,    24,     0,     0,    25,    26,     0,    55,     0,     0,
-      68,   -68,    69,   180,     0,     4,     5,     0,     0,     6,
-       7,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,   181,     0,   182,   183,   184,     0,     0,   185,   186,
-     187,   188,   189,   190,   191,   192,   193,     0,     0,     0,
-      13,   194,     0,     0,     0,    14,    15,    16,    17,    63,
-       0,     4,     5,    20,     0,     6,     7,     0,   -99,    21,
-      22,     0,    23,     0,    24,     0,     0,    25,    26,     0,
-      55,     0,     0,    68,   195,    69,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,     0,    13,     0,     0,     0,
-       0,    14,    15,    16,    17,     0,     0,     0,   -99,    20,
+      34,    79,    79,    70,    80,   125,   126,   120,   232,   248,
+     254,    56,    57,    58,   217,    19,   146,   119,   246,    63,
+      63,   118,    63,    68,   134,    71,   266,    44,    19,   137,
+       4,   304,   272,    63,   138,    43,    74,    59,    75,    60,
+     315,   131,   117,   117,   238,    33,   169,   239,   122,   170,
+       5,    75,   111,   112,   131,    44,   128,   129,   117,   117,
+      62,    64,   212,    65,    74,   127,   123,    83,   281,   167,
+      44,    84,   283,    78,    96,    72,   218,     4,   314,   174,
+     175,   248,   131,   181,   145,    44,   147,   148,   149,   302,
+     248,   -99,   305,   151,   132,    63,    63,    63,    63,    63,
+      63,    63,    63,    63,    63,    63,    63,   132,   214,   121,
+     168,    25,   -89,   166,    80,   132,   102,    91,    92,   326,
+     133,    63,   328,   324,   144,   211,   327,  -100,   -90,    19,
+     176,   -99,   -11,   296,   180,   132,   153,   154,   155,   156,
+     157,   158,   159,   160,   161,   162,   163,   164,   -99,   209,
+      56,    73,     5,   143,   -99,   -11,   297,   298,   109,   110,
+     152,   133,   173,   150,   165,   178,    80,    80,    48,    49,
+      80,   215,    80,  -100,  -100,   219,    80,   253,   220,   222,
+      75,   234,    19,    78,   243,    73,    99,   100,   101,   111,
+     112,   102,   265,   262,   256,   227,   277,   113,   263,   264,
+     269,    80,   276,   261,   -85,   177,   289,   236,   312,   198,
+      50,    51,   317,   318,   240,   227,    80,    81,   244,   245,
+     261,    84,   279,   310,   267,   288,    85,    67,   268,   210,
+     117,   285,   319,    52,   241,    78,    78,   182,   291,    78,
+     273,    78,   213,     0,     0,    78,   282,   306,   307,     0,
+      71,     0,    86,   287,     0,     0,     0,     0,   316,     0,
+       0,   293,   221,     0,     0,     0,     0,    91,    92,   321,
+      78,   229,     0,     0,     0,   284,    84,   286,    63,     0,
+     235,    85,     0,     0,   237,    78,    63,    84,     0,   223,
+     224,    20,    85,   225,     0,   228,     0,   308,   309,   230,
+      23,     0,     0,     0,     0,     0,   255,    86,    87,     0,
+      84,     0,     0,     0,     0,    85,     0,     0,    86,    87,
+      88,     0,    91,    92,   250,     0,     0,    96,     0,   271,
+      89,     0,     0,    91,    92,     0,   274,   275,     0,   257,
+     278,    86,    87,    88,     0,    97,    98,    99,   100,   101,
+      84,    75,   102,    89,   208,    85,    91,    92,   292,     0,
+     294,     0,   295,   300,   301,     0,   303,     2,     3,     0,
+       4,     5,     0,     0,     6,     7,     0,     0,     0,     0,
+       0,    86,    87,    88,     8,     9,   320,     0,     0,   322,
+       0,     0,   323,    89,   325,     0,    91,    92,     0,     0,
+       0,     0,    10,    11,    12,    13,     0,     0,   133,     0,
+      14,    15,    16,    17,    18,     0,     0,    19,    20,   103,
+     104,   105,   106,   107,    21,    22,   108,    23,     0,    24,
+       0,     0,    25,    26,     0,    27,     0,     0,   -14,   183,
+     -14,     4,     5,     0,     0,     6,     7,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,   184,     0,   185,
+     186,   187,   -68,   -68,   188,   189,   190,   191,   192,   193,
+     194,   195,   196,     0,     0,     0,    13,   197,     0,     0,
+       0,    14,    15,    16,    17,     0,     0,     0,   -68,    20,
        0,     0,     0,     0,     0,    21,    22,     0,    23,     0,
-      24,     0,     0,    25,   249,   -99,    55,     0,     4,     5,
-       0,   -99,     6,     7,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,   181,     0,   182,   183,   184,     0,
-       0,   185,   186,   187,   188,   189,   190,   191,   192,   193,
-       0,     0,     0,    13,   194,     0,     0,     0,    14,    15,
-      16,    17,     0,     4,     5,     0,    20,     6,     7,     0,
-       0,     0,    21,    22,     0,    23,     0,    24,     0,     0,
-      25,    26,     0,    55,     0,     0,    68,    63,    69,     4,
-       5,     0,     0,     6,     7,     0,     0,     0,    13,     0,
-       0,     0,     0,    14,    15,    16,    17,     0,     0,     0,
-       0,    20,     0,     0,     0,     0,     0,    21,    22,     0,
-      23,     0,    24,     0,    13,    25,    26,     0,    55,    14,
-      15,    16,    17,    69,     0,     0,     0,    20,     0,     0,
-       0,     0,     0,    21,    22,     0,    23,     0,    24,     0,
-       0,    25,    26,   -99,    55,    63,     0,     4,     5,     0,
+      24,     0,     0,    25,    26,     0,    61,     0,     0,    74,
+     -68,    75,   183,     0,     4,     5,     0,     0,     6,     7,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+     184,     0,   185,   186,   187,   -67,   -67,   188,   189,   190,
+     191,   192,   193,   194,   195,   196,     0,     0,     0,    13,
+     197,     0,     0,     0,    14,    15,    16,    17,     0,     0,
+       0,   -67,    20,     0,     0,     0,     0,     0,    21,    22,
+       0,    23,     0,    24,     0,     0,    25,    26,     0,    61,
+       0,     0,    74,   -67,    75,   183,     0,     4,     5,     0,
        0,     6,     7,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,   184,     0,   185,   186,   187,     0,     0,
+     188,   189,   190,   191,   192,   193,   194,   195,   196,     0,
+       0,     0,    13,   197,     0,     0,     0,    14,    15,    16,
+      17,    69,     0,     4,     5,    20,     0,     6,     7,     0,
+     -98,    21,    22,     0,    23,     0,    24,     0,     0,    25,
+      26,     0,    61,     0,     0,    74,   198,    75,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,    13,     0,
+       0,     0,     0,    14,    15,    16,    17,     0,     0,     0,
+     -98,    20,     0,     0,     0,     0,     0,    21,    22,     0,
+      23,     0,    24,     0,     0,    25,   251,   -98,    61,     0,
+       4,     5,     0,   -98,     6,     7,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,   184,     0,   185,   186,
+     187,     0,     0,   188,   189,   190,   191,   192,   193,   194,
+     195,   196,     0,     0,     0,    13,   197,     0,     0,     0,
+      14,    15,    16,    17,     0,     4,     5,     0,    20,     6,
+       7,     0,     0,     0,    21,    22,     0,    23,     0,    24,
+       0,     0,    25,    26,     0,    61,     0,     0,    74,    69,
+      75,     4,     5,     0,     0,     6,     7,     0,     0,     0,
+      13,     0,     0,     0,     0,    14,    15,    16,    17,     0,
+       0,     0,     0,    20,     0,     0,     0,     0,     0,    21,
+      22,     0,    23,     0,    24,     0,    13,    25,    26,     0,
+      61,    14,    15,    16,    17,    75,     0,     0,     0,    20,
+       0,     0,     0,     0,     0,    21,    22,     0,    23,     0,
+      24,     0,     0,    25,    26,   -98,    61,    69,     0,     4,
+       5,     0,     0,     6,     7,     0,     0,     0,     0,     0,
        0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,   176,     0,     4,     5,     0,     0,     6,     7,     0,
+       0,     0,     0,   179,     0,     4,     5,     0,     0,     6,
+       7,     0,     0,     0,    13,     0,     0,     0,     0,    14,
+      15,    16,    17,     0,     0,     0,     0,    20,     0,     0,
+       0,     0,     0,    21,    22,     0,    23,     0,    24,     0,
+      13,    25,    26,     0,    61,    14,    15,    16,    17,     0,
+       4,   247,     0,    20,     6,     7,     0,     0,     0,    21,
+      22,     0,    23,     0,    24,     0,     0,    25,    26,   186,
+      61,     0,     0,     0,     0,     0,     0,     0,   193,   194,
+       0,     0,     4,     5,     0,    13,     6,     7,     0,     0,
+      14,    15,    16,    17,     0,     0,     0,     0,    20,     0,
+       0,   186,     0,     0,    21,    22,     0,    23,     0,    24,
+     193,   194,    25,    26,     0,    61,     0,    13,     0,     0,
+       0,     0,    14,    15,    16,    17,     0,     4,     5,     0,
+      20,     6,     7,     0,     0,    95,    21,    22,     0,    23,
+       0,    24,     0,     0,    25,    26,     0,    61,     0,     0,
+       0,     0,     0,     4,     5,     0,     0,     6,     7,     0,
        0,     0,    13,     0,     0,     0,     0,    14,    15,    16,
       17,     0,     0,     0,     0,    20,     0,     0,     0,     0,
        0,    21,    22,     0,    23,     0,    24,     0,    13,    25,
-      26,     0,    55,    14,    15,    16,    17,     0,     4,   245,
+      26,     0,    61,    14,    15,    16,    17,     0,     4,     5,
        0,    20,     6,     7,     0,     0,     0,    21,    22,     0,
-      23,     0,    24,     0,     0,    25,    26,   183,    55,     0,
-       0,     0,     0,     0,     0,     0,   190,   191,     0,     0,
-       4,     5,     0,    13,     6,     7,     0,     0,    14,    15,
-      16,    17,     0,     0,     0,     0,    20,     0,     0,   183,
-       0,     0,    21,    22,     0,    23,     0,    24,   190,   191,
-      25,    26,     0,    55,     0,    13,     0,     0,     0,     0,
-      14,    15,    16,    17,     0,     4,     5,     0,    20,     6,
-       7,     0,     0,    89,    21,    22,     0,    23,     0,    24,
-       0,     0,    25,    26,     0,    55,     0,     0,     0,     0,
-       0,     4,     5,     0,     0,     6,     7,     0,     0,     0,
-      13,     0,     0,     0,     0,    14,    15,    16,    17,     0,
-       0,     0,     0,    20,     0,     0,     0,     0,     0,    21,
-      22,     0,    23,     0,    24,     0,    13,    25,    26,     0,
-      55,    14,    15,    16,    17,     0,     4,     5,     0,    20,
-       6,     7,     0,     0,     0,    21,    22,     0,    23,     0,
-      24,     0,     0,    25,    26,     0,    55,     0,     0,     0,
+      23,     0,    24,     0,     0,    25,    26,     0,    61,     0,
        0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,    78,    14,    15,    16,    17,
-      79,    78,     0,     0,    20,     0,    79,     0,     0,     0,
-      21,    22,     0,    23,     0,    24,     0,     0,    25,    60,
-      78,    55,     0,     0,     0,    79,    80,    81,    82,     0,
-       0,     0,    80,    81,    82,     0,     0,     0,    83,     0,
-      78,    85,    86,     0,    83,    79,    84,    85,    86,     0,
-       0,    80,    81,    82,     0,     0,     0,     0,     0,    69,
-       0,     0,     0,    83,   205,     0,    85,    86,     0,     0,
-       0,    80,    81,    82,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,    83,     0,     0,    85,    86
+       0,     0,     0,     0,     0,     0,     0,    84,    14,    15,
+      16,    17,    85,    84,     0,     0,    20,     0,    85,     0,
+       0,     0,    21,    22,     0,    23,     0,    24,     0,     0,
+      25,    66,     0,    61,     0,     0,     0,     0,    86,    87,
+      88,     0,     0,     0,    86,    87,    88,     0,     0,     0,
+      89,     0,    90,    91,    92,     0,    89,     0,     0,    91,
+      92
 };
 
 #define yypact_value_is_default(yystate) \
-  ((yystate) == (-269))
+  ((yystate) == (-264))
 
 #define yytable_value_is_error(yytable_value) \
-  ((yytable_value) == (-101))
+  ((yytable_value) == (-100))
 
 static const yytype_int16 yycheck[] =
 {
-       1,    29,    30,    26,    29,    53,    54,    46,    80,   202,
-       4,    13,    14,    15,     1,    64,     4,   230,    16,    21,
-      22,    44,    24,    25,     3,    26,    40,   295,    27,     1,
-      16,   220,     4,    35,    50,    66,   304,    57,    58,    59,
-      60,    61,    43,    44,    64,    69,     1,    66,   219,     1,
-      71,     1,    53,    54,    66,    69,    55,    73,    50,    60,
-     109,     1,     9,    50,     1,    21,    22,     4,    24,    48,
-      55,    69,    66,     3,    29,   124,   125,    65,    79,    35,
-      81,    82,    83,    69,    24,    25,    73,    88,   301,    91,
-      92,    93,    94,    95,    96,    97,    98,    99,   100,   101,
-     102,   272,    54,   175,    54,   276,   295,   108,    55,    56,
-      50,    74,     9,   138,    50,   304,    64,    67,    70,     1,
-     122,    84,   293,    43,    44,   296,     7,     8,   321,   130,
-      67,   324,    72,   134,     5,    91,    92,    93,    94,    95,
-      96,    97,    98,    99,   100,   101,   102,     4,   149,   151,
-      38,     9,   323,     1,    13,   326,    14,    67,    55,    56,
-      49,   210,    10,   188,   189,    50,   122,   192,   131,   194,
-      51,    66,    54,   198,    40,     1,    57,    58,   203,    60,
-       6,   229,    40,   138,     4,    67,    71,    66,    73,   238,
-      43,    44,   193,   242,   243,   267,    66,    55,    56,   224,
-      73,   240,    50,    66,   205,    66,    54,    67,     3,     4,
-     138,    10,   213,   214,   239,    26,   217,   218,    20,    67,
-     269,   260,   247,   186,    66,    73,   249,    72,   229,   278,
-      53,     7,   195,   188,   189,     7,   285,   192,    30,   194,
-     298,   204,    25,   198,    59,    60,    61,   275,   249,    64,
-      45,    46,   214,   151,   279,   281,   305,   260,    12,    13,
-     188,   189,   287,    -1,   192,   312,   194,   316,   231,   224,
-     198,    -1,   235,    68,    -1,    -1,   277,   211,   279,   281,
-      -1,    -1,    -1,    -1,   239,    -1,    -1,   289,    -1,    43,
-      44,    -1,    -1,    -1,   257,    -1,   224,    51,    -1,    -1,
-      -1,   264,   265,    -1,    -1,   268,    -1,    -1,    -1,     9,
-      -1,   239,    -1,    -1,    14,    -1,    -1,     9,    -1,    -1,
-      -1,    -1,    14,   286,    -1,   288,    -1,   290,   291,   292,
-      -1,   294,    -1,   289,    -1,     0,     1,    -1,     3,     4,
-      40,    41,     7,     8,    -1,    -1,    -1,    -1,    40,    41,
-      42,   314,    17,    18,   317,    55,    56,   320,    -1,   322,
-      52,    -1,    -1,    55,    56,    -1,    -1,    -1,    -1,    -1,
-      35,    36,    37,    38,    -1,    67,    -1,    -1,    43,    44,
-      45,    46,    47,    -1,    -1,    50,    51,    57,    58,    59,
-      60,    61,    57,    58,    64,    60,    -1,    62,    -1,    -1,
-      65,    66,    -1,    68,    -1,    -1,    71,     1,    73,     3,
-       4,    -1,    -1,     7,     8,    -1,    -1,    -1,    -1,    -1,
-      -1,    -1,    -1,    -1,    -1,    19,    -1,    21,    22,    23,
-      24,    25,    26,    27,    28,    29,    30,    31,    32,    33,
-      34,    -1,    -1,    -1,    38,    39,    -1,    -1,    -1,    43,
-      44,    45,    46,    -1,    -1,    -1,    50,    51,    -1,    -1,
-      -1,    -1,    -1,    57,    58,    -1,    60,    -1,    62,    -1,
-      -1,    65,    66,    -1,    68,    -1,    -1,    71,    72,    73,
-       1,    -1,     3,     4,    -1,    -1,     7,     8,    -1,    -1,
-      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    19,    -1,
-      21,    22,    23,    24,    25,    26,    27,    28,    29,    30,
-      31,    32,    33,    34,    -1,    -1,    -1,    38,    39,    -1,
-      -1,    -1,    43,    44,    45,    46,    -1,    -1,    -1,    50,
-      51,    -1,    -1,    -1,    -1,    -1,    57,    58,    -1,    60,
-      -1,    62,    -1,    -1,    65,    66,    -1,    68,    -1,    -1,
-      71,    72,    73,     1,    -1,     3,     4,    -1,    -1,     7,
-       8,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-      -1,    19,    -1,    21,    22,    23,    -1,    -1,    26,    27,
-      28,    29,    30,    31,    32,    33,    34,    -1,    -1,    -1,
-      38,    39,    -1,    -1,    -1,    43,    44,    45,    46,     1,
-      -1,     3,     4,    51,    -1,     7,     8,    -1,    10,    57,
-      58,    -1,    60,    -1,    62,    -1,    -1,    65,    66,    -1,
-      68,    -1,    -1,    71,    72,    73,    -1,    -1,    -1,    -1,
-      -1,    -1,    -1,    -1,    -1,    -1,    38,    -1,    -1,    -1,
+       1,    29,    30,    26,    29,    59,    60,    46,   205,   222,
+     232,    13,    14,    15,     4,    50,    86,    16,   221,    21,
+      22,    44,    24,    25,    70,    26,    40,    69,    50,     1,
+       3,   294,    16,    35,     6,    66,    71,    66,    73,    66,
+     303,     1,    43,    44,     1,     1,     1,     4,    66,     4,
+       4,    73,    43,    44,     1,    69,    43,    44,    59,    60,
+      21,    22,     1,    24,    71,    66,    55,    50,   271,   115,
+      69,     9,   275,    29,    35,    48,    66,     3,   300,   125,
+     126,   294,     1,     1,    85,    69,    87,    88,    89,   292,
+     303,    10,   295,    94,    54,    97,    98,    99,   100,   101,
+     102,   103,   104,   105,   106,   107,   108,    54,   178,    49,
+      70,    65,    67,   114,   139,    54,    64,    55,    56,   322,
+      67,   123,   325,   320,     5,   171,   323,     9,    67,    50,
+     131,    50,    50,     1,   135,    54,    97,    98,    99,   100,
+     101,   102,   103,   104,   105,   106,   107,   108,    67,   150,
+     152,    27,     4,    80,    73,    73,    24,    25,    12,    13,
+      38,    67,   123,    90,    13,    40,   191,   192,     3,     4,
+     195,    66,   197,    55,    56,    66,   201,   231,    66,    66,
+      73,   206,    50,   139,     4,    61,    59,    60,    61,    43,
+      44,    64,    26,    67,   240,   196,   266,    51,   244,   245,
+      10,   226,    66,   242,    72,   132,    20,   208,    53,    72,
+      45,    46,     7,     7,   215,   216,   241,    30,   219,   220,
+     259,     9,   268,   297,   249,   280,    14,    25,   251,   152,
+     231,   277,   311,    68,   216,   191,   192,   139,   284,   195,
+     259,   197,   172,    -1,    -1,   201,   274,     7,     8,    -1,
+     251,    -1,    40,   278,    -1,    -1,    -1,    -1,   304,    -1,
+      -1,   286,   189,    -1,    -1,    -1,    -1,    55,    56,   315,
+     226,   198,    -1,    -1,    -1,   276,     9,   278,   280,    -1,
+     207,    14,    -1,    -1,   211,   241,   288,     9,    -1,   191,
+     192,    51,    14,   195,    -1,   197,    -1,    57,    58,   201,
+      60,    -1,    -1,    -1,    -1,    -1,   233,    40,    41,    -1,
+       9,    -1,    -1,    -1,    -1,    14,    -1,    -1,    40,    41,
+      42,    -1,    55,    56,   226,    -1,    -1,   288,    -1,   256,
+      52,    -1,    -1,    55,    56,    -1,   263,   264,    -1,   241,
+     267,    40,    41,    42,    -1,    57,    58,    59,    60,    61,
+       9,    73,    64,    52,    53,    14,    55,    56,   285,    -1,
+     287,    -1,   289,   290,   291,    -1,   293,     0,     1,    -1,
+       3,     4,    -1,    -1,     7,     8,    -1,    -1,    -1,    -1,
+      -1,    40,    41,    42,    17,    18,   313,    -1,    -1,   316,
+      -1,    -1,   319,    52,   321,    -1,    55,    56,    -1,    -1,
+      -1,    -1,    35,    36,    37,    38,    -1,    -1,    67,    -1,
+      43,    44,    45,    46,    47,    -1,    -1,    50,    51,    57,
+      58,    59,    60,    61,    57,    58,    64,    60,    -1,    62,
+      -1,    -1,    65,    66,    -1,    68,    -1,    -1,    71,     1,
+      73,     3,     4,    -1,    -1,     7,     8,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    19,    -1,    21,
+      22,    23,    24,    25,    26,    27,    28,    29,    30,    31,
+      32,    33,    34,    -1,    -1,    -1,    38,    39,    -1,    -1,
       -1,    43,    44,    45,    46,    -1,    -1,    -1,    50,    51,
       -1,    -1,    -1,    -1,    -1,    57,    58,    -1,    60,    -1,
-      62,    -1,    -1,    65,    66,    67,    68,    -1,     3,     4,
-      -1,    73,     7,     8,    -1,    -1,    -1,    -1,    -1,    -1,
-      -1,    -1,    -1,    -1,    19,    -1,    21,    22,    23,    -1,
-      -1,    26,    27,    28,    29,    30,    31,    32,    33,    34,
-      -1,    -1,    -1,    38,    39,    -1,    -1,    -1,    43,    44,
-      45,    46,    -1,     3,     4,    -1,    51,     7,     8,    -1,
-      -1,    -1,    57,    58,    -1,    60,    -1,    62,    -1,    -1,
-      65,    66,    -1,    68,    -1,    -1,    71,     1,    73,     3,
-       4,    -1,    -1,     7,     8,    -1,    -1,    -1,    38,    -1,
-      -1,    -1,    -1,    43,    44,    45,    46,    -1,    -1,    -1,
-      -1,    51,    -1,    -1,    -1,    -1,    -1,    57,    58,    -1,
-      60,    -1,    62,    -1,    38,    65,    66,    -1,    68,    43,
-      44,    45,    46,    73,    -1,    -1,    -1,    51,    -1,    -1,
-      -1,    -1,    -1,    57,    58,    -1,    60,    -1,    62,    -1,
-      -1,    65,    66,    67,    68,     1,    -1,     3,     4,    -1,
+      62,    -1,    -1,    65,    66,    -1,    68,    -1,    -1,    71,
+      72,    73,     1,    -1,     3,     4,    -1,    -1,     7,     8,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      19,    -1,    21,    22,    23,    24,    25,    26,    27,    28,
+      29,    30,    31,    32,    33,    34,    -1,    -1,    -1,    38,
+      39,    -1,    -1,    -1,    43,    44,    45,    46,    -1,    -1,
+      -1,    50,    51,    -1,    -1,    -1,    -1,    -1,    57,    58,
+      -1,    60,    -1,    62,    -1,    -1,    65,    66,    -1,    68,
+      -1,    -1,    71,    72,    73,     1,    -1,     3,     4,    -1,
       -1,     7,     8,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    19,    -1,    21,    22,    23,    -1,    -1,
+      26,    27,    28,    29,    30,    31,    32,    33,    34,    -1,
+      -1,    -1,    38,    39,    -1,    -1,    -1,    43,    44,    45,
+      46,     1,    -1,     3,     4,    51,    -1,     7,     8,    -1,
+      10,    57,    58,    -1,    60,    -1,    62,    -1,    -1,    65,
+      66,    -1,    68,    -1,    -1,    71,    72,    73,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    38,    -1,
+      -1,    -1,    -1,    43,    44,    45,    46,    -1,    -1,    -1,
+      50,    51,    -1,    -1,    -1,    -1,    -1,    57,    58,    -1,
+      60,    -1,    62,    -1,    -1,    65,    66,    67,    68,    -1,
+       3,     4,    -1,    73,     7,     8,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    19,    -1,    21,    22,
+      23,    -1,    -1,    26,    27,    28,    29,    30,    31,    32,
+      33,    34,    -1,    -1,    -1,    38,    39,    -1,    -1,    -1,
+      43,    44,    45,    46,    -1,     3,     4,    -1,    51,     7,
+       8,    -1,    -1,    -1,    57,    58,    -1,    60,    -1,    62,
+      -1,    -1,    65,    66,    -1,    68,    -1,    -1,    71,     1,
+      73,     3,     4,    -1,    -1,     7,     8,    -1,    -1,    -1,
+      38,    -1,    -1,    -1,    -1,    43,    44,    45,    46,    -1,
+      -1,    -1,    -1,    51,    -1,    -1,    -1,    -1,    -1,    57,
+      58,    -1,    60,    -1,    62,    -1,    38,    65,    66,    -1,
+      68,    43,    44,    45,    46,    73,    -1,    -1,    -1,    51,
+      -1,    -1,    -1,    -1,    -1,    57,    58,    -1,    60,    -1,
+      62,    -1,    -1,    65,    66,    67,    68,     1,    -1,     3,
+       4,    -1,    -1,     7,     8,    -1,    -1,    -1,    -1,    -1,
       -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-      -1,     1,    -1,     3,     4,    -1,    -1,     7,     8,    -1,
+      -1,    -1,    -1,     1,    -1,     3,     4,    -1,    -1,     7,
+       8,    -1,    -1,    -1,    38,    -1,    -1,    -1,    -1,    43,
+      44,    45,    46,    -1,    -1,    -1,    -1,    51,    -1,    -1,
+      -1,    -1,    -1,    57,    58,    -1,    60,    -1,    62,    -1,
+      38,    65,    66,    -1,    68,    43,    44,    45,    46,    -1,
+       3,     4,    -1,    51,     7,     8,    -1,    -1,    -1,    57,
+      58,    -1,    60,    -1,    62,    -1,    -1,    65,    66,    22,
+      68,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    31,    32,
+      -1,    -1,     3,     4,    -1,    38,     7,     8,    -1,    -1,
+      43,    44,    45,    46,    -1,    -1,    -1,    -1,    51,    -1,
+      -1,    22,    -1,    -1,    57,    58,    -1,    60,    -1,    62,
+      31,    32,    65,    66,    -1,    68,    -1,    38,    -1,    -1,
+      -1,    -1,    43,    44,    45,    46,    -1,     3,     4,    -1,
+      51,     7,     8,    -1,    -1,    11,    57,    58,    -1,    60,
+      -1,    62,    -1,    -1,    65,    66,    -1,    68,    -1,    -1,
+      -1,    -1,    -1,     3,     4,    -1,    -1,     7,     8,    -1,
       -1,    -1,    38,    -1,    -1,    -1,    -1,    43,    44,    45,
       46,    -1,    -1,    -1,    -1,    51,    -1,    -1,    -1,    -1,
       -1,    57,    58,    -1,    60,    -1,    62,    -1,    38,    65,
       66,    -1,    68,    43,    44,    45,    46,    -1,     3,     4,
       -1,    51,     7,     8,    -1,    -1,    -1,    57,    58,    -1,
-      60,    -1,    62,    -1,    -1,    65,    66,    22,    68,    -1,
-      -1,    -1,    -1,    -1,    -1,    -1,    31,    32,    -1,    -1,
-       3,     4,    -1,    38,     7,     8,    -1,    -1,    43,    44,
-      45,    46,    -1,    -1,    -1,    -1,    51,    -1,    -1,    22,
-      -1,    -1,    57,    58,    -1,    60,    -1,    62,    31,    32,
-      65,    66,    -1,    68,    -1,    38,    -1,    -1,    -1,    -1,
-      43,    44,    45,    46,    -1,     3,     4,    -1,    51,     7,
-       8,    -1,    -1,    11,    57,    58,    -1,    60,    -1,    62,
-      -1,    -1,    65,    66,    -1,    68,    -1,    -1,    -1,    -1,
-      -1,     3,     4,    -1,    -1,     7,     8,    -1,    -1,    -1,
-      38,    -1,    -1,    -1,    -1,    43,    44,    45,    46,    -1,
-      -1,    -1,    -1,    51,    -1,    -1,    -1,    -1,    -1,    57,
-      58,    -1,    60,    -1,    62,    -1,    38,    65,    66,    -1,
-      68,    43,    44,    45,    46,    -1,     3,     4,    -1,    51,
-       7,     8,    -1,    -1,    -1,    57,    58,    -1,    60,    -1,
-      62,    -1,    -1,    65,    66,    -1,    68,    -1,    -1,    -1,
+      60,    -1,    62,    -1,    -1,    65,    66,    -1,    68,    -1,
       -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-      -1,    -1,    -1,    -1,    -1,     9,    43,    44,    45,    46,
-      14,     9,    -1,    -1,    51,    -1,    14,    -1,    -1,    -1,
-      57,    58,    -1,    60,    -1,    62,    -1,    -1,    65,    66,
-       9,    68,    -1,    -1,    -1,    14,    40,    41,    42,    -1,
-      -1,    -1,    40,    41,    42,    -1,    -1,    -1,    52,    -1,
-       9,    55,    56,    -1,    52,    14,    54,    55,    56,    -1,
-      -1,    40,    41,    42,    -1,    -1,    -1,    -1,    -1,    73,
-      -1,    -1,    -1,    52,    53,    -1,    55,    56,    -1,    -1,
-      -1,    40,    41,    42,    -1,    -1,    -1,    -1,    -1,    -1,
-      -1,    -1,    -1,    52,    -1,    -1,    55,    56
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,     9,    43,    44,
+      45,    46,    14,     9,    -1,    -1,    51,    -1,    14,    -1,
+      -1,    -1,    57,    58,    -1,    60,    -1,    62,    -1,    -1,
+      65,    66,    -1,    68,    -1,    -1,    -1,    -1,    40,    41,
+      42,    -1,    -1,    -1,    40,    41,    42,    -1,    -1,    -1,
+      52,    -1,    54,    55,    56,    -1,    52,    -1,    -1,    55,
+      56
 };
 
 /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
@@ -1209,36 +1182,36 @@ static const yytype_uint8 yystos[] =
        0,    75,     0,     1,     3,     4,     7,     8,    17,    18,
       35,    36,    37,    38,    43,    44,    45,    46,    47,    50,
       51,    57,    58,    60,    62,    65,    66,    68,    76,    78,
-      82,    84,    86,   104,   112,   116,   117,   118,   119,   120,
-     121,   129,   130,    66,    69,   126,   127,   128,    83,   122,
-     130,   130,   130,    66,    66,    68,   117,   130,   117,   117,
-      66,   119,   130,     1,   111,   112,    48,   121,    71,    73,
-      79,    88,   104,   132,   136,    79,    85,    50,     9,    14,
-      40,    41,    42,    52,    54,    55,    56,   114,   115,    11,
-     117,    57,    58,    59,    60,    61,    64,    57,    58,    59,
-      60,    61,    64,    12,    13,    43,    44,    51,   113,   110,
-     111,   112,   111,    16,   126,     3,     4,    45,    46,    68,
-      80,    81,    55,   106,   110,   110,   112,    43,    44,   131,
-       1,    54,    67,   134,   138,   134,     1,     6,    77,   104,
-     105,    87,   105,     5,   112,   129,   112,   112,   112,   105,
-     112,    38,   117,   117,   117,   117,   117,   117,   117,   117,
-     117,   117,   117,   117,    13,   112,   134,    70,    49,    66,
-     117,   134,   134,   112,   105,    40,     1,   112,     1,    88,
-       1,    19,    21,    22,    23,    26,    27,    28,    29,    30,
-      31,    32,    33,    34,    39,    72,    89,    90,    92,    99,
-     103,   112,   132,   133,   136,    53,   112,   122,     1,     4,
-     107,   108,   129,    66,    91,     4,    66,    66,    66,   105,
-      66,    88,    88,    88,   109,   112,    88,   105,    88,    93,
-      87,   135,   136,   105,   112,   134,     1,   138,   112,   109,
-      94,     4,   112,   112,    89,     4,    92,    95,    88,    66,
-     100,   110,   133,   105,   105,     1,     4,   134,    88,   123,
-     124,   125,   126,    67,   134,   134,    26,    40,   136,   111,
-      10,   101,   105,    16,   125,   105,   105,    66,   129,   105,
-     134,   102,    89,   132,    89,   112,   134,   112,   136,   116,
-      20,    96,   134,   105,   136,   105,   105,     1,    24,    25,
-      97,   105,   105,    89,   105,    95,    89,     7,     8,    57,
-      58,    84,    98,    53,   137,   133,    95,   134,     7,     7,
-     137,   105,   134,   105,   105,    87,   105,    89,    87,    89
+      82,    83,    85,   103,   111,   115,   116,   117,   118,   119,
+     120,   128,   129,    66,    69,   125,   126,   127,     3,     4,
+      45,    46,    68,    80,    81,   121,   129,   129,   129,    66,
+      66,    68,   116,   129,   116,   116,    66,   118,   129,     1,
+     110,   111,    48,   120,    71,    73,    79,    87,   103,   131,
+     135,    79,    84,    50,     9,    14,    40,    41,    42,    52,
+      54,    55,    56,   113,   114,    11,   116,    57,    58,    59,
+      60,    61,    64,    57,    58,    59,    60,    61,    64,    12,
+      13,    43,    44,    51,   112,   109,   110,   111,   110,    16,
+     125,    49,    66,    55,   105,   109,   109,   111,    43,    44,
+     130,     1,    54,    67,   133,   137,   133,     1,     6,    77,
+     103,   104,    86,   104,     5,   111,   128,   111,   111,   111,
+     104,   111,    38,   116,   116,   116,   116,   116,   116,   116,
+     116,   116,   116,   116,   116,    13,   111,   133,    70,     1,
+       4,   106,   107,   116,   133,   133,   111,   104,    40,     1,
+     111,     1,    87,     1,    19,    21,    22,    23,    26,    27,
+      28,    29,    30,    31,    32,    33,    34,    39,    72,    88,
+      89,    91,    98,   102,   111,   131,   132,   135,    53,   111,
+     121,   133,     1,   137,   128,    66,    90,     4,    66,    66,
+      66,   104,    66,    87,    87,    87,   108,   111,    87,   104,
+      87,    92,    86,   134,   135,   104,   111,   104,     1,     4,
+     111,   108,    93,     4,   111,   111,    88,     4,    91,    94,
+      87,    66,    99,   109,   132,   104,   133,    87,   122,   123,
+     124,   125,    67,   133,   133,    26,    40,   135,   110,    10,
+     100,   104,    16,   124,   104,   104,    66,   128,   104,   133,
+     101,    88,   131,    88,   111,   133,   111,   135,   115,    20,
+      95,   133,   104,   135,   104,   104,     1,    24,    25,    96,
+     104,   104,    88,   104,    94,    88,     7,     8,    57,    58,
+      83,    97,    53,   136,   132,    94,   133,     7,     7,   136,
+     104,   133,   104,   104,    86,   104,    88,    86,    88
 };
 
 #define yyerrok                (yyerrstatus = 0)
@@ -2065,8 +2038,8 @@ yyreduce:
     {
         case 3:
 
-/* Line 1806 of yacc.c  */
-#line 221 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 194 "awkgram.y"
     {
                rule = 0;
                yyerrok;
@@ -2075,8 +2048,8 @@ yyreduce:
 
   case 5:
 
-/* Line 1806 of yacc.c  */
-#line 227 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 200 "awkgram.y"
     {
                next_sourcefile();
          }
@@ -2084,8 +2057,8 @@ yyreduce:
 
   case 6:
 
-/* Line 1806 of yacc.c  */
-#line 231 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 204 "awkgram.y"
     {
                rule = 0;
                /*
@@ -2098,8 +2071,8 @@ yyreduce:
 
   case 7:
 
-/* Line 1806 of yacc.c  */
-#line 243 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 216 "awkgram.y"
     {
                (void) append_rule((yyvsp[(1) - (2)]), (yyvsp[(2) - (2)]));
          }
@@ -2107,8 +2080,8 @@ yyreduce:
 
   case 8:
 
-/* Line 1806 of yacc.c  */
-#line 247 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 220 "awkgram.y"
     {
                if (rule != Rule) {
                        msg(_("%s blocks must have an action part"), 
ruletab[rule]);
@@ -2123,21 +2096,19 @@ yyreduce:
 
   case 9:
 
-/* Line 1806 of yacc.c  */
-#line 258 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 231 "awkgram.y"
     {
                can_return = FALSE;
-               if ((yyvsp[(1) - (2)]) && func_install((yyvsp[(1) - (2)]), 
(yyvsp[(2) - (2)])) < 0)
-                       YYABORT;
-               func_params = NULL;
+               (void) mk_function((yyvsp[(1) - (2)]), (yyvsp[(2) - (2)]));
                yyerrok;
          }
     break;
 
   case 10:
 
-/* Line 1806 of yacc.c  */
-#line 266 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 237 "awkgram.y"
     {
                want_source = FALSE;
                yyerrok;
@@ -2146,8 +2117,8 @@ yyreduce:
 
   case 11:
 
-/* Line 1806 of yacc.c  */
-#line 274 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 245 "awkgram.y"
     {
                if (include_source((yyvsp[(1) - (1)])) < 0)
                        YYABORT;
@@ -2159,36 +2130,36 @@ yyreduce:
 
   case 12:
 
-/* Line 1806 of yacc.c  */
-#line 282 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 253 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 13:
 
-/* Line 1806 of yacc.c  */
-#line 284 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 255 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 14:
 
-/* Line 1806 of yacc.c  */
-#line 289 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 260 "awkgram.y"
     {  (yyval) = NULL; rule = Rule; }
     break;
 
   case 15:
 
-/* Line 1806 of yacc.c  */
-#line 291 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 262 "awkgram.y"
     {  (yyval) = (yyvsp[(1) - (1)]); rule = Rule; }
     break;
 
   case 16:
 
-/* Line 1806 of yacc.c  */
-#line 293 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 264 "awkgram.y"
     {
                INSTRUCTION *tp;
 
@@ -2218,8 +2189,8 @@ yyreduce:
 
   case 17:
 
-/* Line 1806 of yacc.c  */
-#line 319 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 290 "awkgram.y"
     {
                static int begin_seen = 0;
                if (do_lint_old && ++begin_seen == 2)
@@ -2234,8 +2205,8 @@ yyreduce:
 
   case 18:
 
-/* Line 1806 of yacc.c  */
-#line 330 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 301 "awkgram.y"
     {
                static int end_seen = 0;
                if (do_lint_old && ++end_seen == 2)
@@ -2250,8 +2221,8 @@ yyreduce:
 
   case 19:
 
-/* Line 1806 of yacc.c  */
-#line 341 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 312 "awkgram.y"
     {
                (yyvsp[(1) - (1)])->in_rule = rule = BEGINFILE;
                (yyvsp[(1) - (1)])->source_file = source;
@@ -2261,8 +2232,8 @@ yyreduce:
 
   case 20:
 
-/* Line 1806 of yacc.c  */
-#line 347 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 318 "awkgram.y"
     {
                (yyvsp[(1) - (1)])->in_rule = rule = ENDFILE;
                (yyvsp[(1) - (1)])->source_file = source;
@@ -2272,8 +2243,8 @@ yyreduce:
 
   case 21:
 
-/* Line 1806 of yacc.c  */
-#line 356 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 327 "awkgram.y"
     {
                if ((yyvsp[(2) - (5)]) == NULL)
                        (yyval) = list_create(instruction(Op_no_op));
@@ -2284,90 +2255,70 @@ yyreduce:
 
   case 22:
 
-/* Line 1806 of yacc.c  */
-#line 366 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 337 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 23:
 
-/* Line 1806 of yacc.c  */
-#line 368 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 339 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 24:
 
-/* Line 1806 of yacc.c  */
-#line 370 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 341 "awkgram.y"
     {
                yyerror(_("`%s' is a built-in function, it cannot be 
redefined"),
-                       tokstart);
-               (yyvsp[(1) - (1)])->opcode = Op_symbol; /* Op_symbol instead of 
Op_token so that
-                                        * free_bc_internal does not try to 
free it
-                                        */
-               (yyvsp[(1) - (1)])->lextok = builtin_func;
-               (yyval) = (yyvsp[(1) - (1)]);
-               /* yyerrok; */
+                                       tokstart);
+               YYABORT;
          }
     break;
 
   case 25:
 
-/* Line 1806 of yacc.c  */
-#line 381 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 347 "awkgram.y"
     { (yyval) = (yyvsp[(2) - (2)]); }
     break;
 
   case 28:
 
-/* Line 1806 of yacc.c  */
-#line 391 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 357 "awkgram.y"
     {
-               param_counter = 0;
-               func_params = NULL;
+               (yyvsp[(1) - (6)])->source_file = source;
+               if (install_function((yyvsp[(2) - (6)])->lextok, (yyvsp[(1) - 
(6)]), (yyvsp[(4) - (6)])) < 0)
+                       YYABORT;
+               (yyvsp[(2) - (6)])->lextok = NULL;
+               bcfree((yyvsp[(2) - (6)]));
+               /* $4 already free'd in install_function */
+               (yyval) = (yyvsp[(1) - (6)]);
+               can_return = TRUE;
          }
     break;
 
   case 29:
 
-/* Line 1806 of yacc.c  */
-#line 396 "awkgram.y"
-    {
-                       NODE *t;
-
-                       (yyvsp[(1) - (7)])->source_file = source;
-                       t = make_param((yyvsp[(3) - (7)])->lextok);
-                       (yyvsp[(3) - (7)])->lextok = NULL;
-                       bcfree((yyvsp[(3) - (7)]));
-                       t->flags |= FUNC;
-                       t->rnode = func_params;
-                       func_params = t;
-                       (yyval) = (yyvsp[(1) - (7)]);
-                       can_return = TRUE;
-                       /* check for duplicate parameter names */
-                       if (dup_parms((yyvsp[(1) - (7)]), t))
-                               errcount++;
-               }
-    break;
-
-  case 30:
-
-/* Line 1806 of yacc.c  */
-#line 420 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 375 "awkgram.y"
     { ++want_regexp; }
     break;
 
-  case 31:
+  case 30:
 
-/* Line 1806 of yacc.c  */
-#line 422 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 377 "awkgram.y"
     {
                  NODE *n, *exp;
                  char *re;
                  size_t len;
 
                  re = (yyvsp[(3) - (3)])->lextok;
+                 (yyvsp[(3) - (3)])->lextok = NULL;
                  len = strlen(re);
                  if (do_lint) {
                        if (len == 0)
@@ -2379,7 +2330,7 @@ yyreduce:
                                        _("regexp constant `/%s/' looks like a 
C comment, but is not"), re);
                  }
 
-                 exp = make_str_node(re, len, ALREADY_MALLOCED);
+                 exp = make_str_node(re, len);
                  n = make_regnode(Node_regex, exp);
                  if (n == NULL) {
                        unref(exp);
@@ -2391,24 +2342,24 @@ yyreduce:
                }
     break;
 
-  case 32:
+  case 31:
 
-/* Line 1806 of yacc.c  */
-#line 453 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 409 "awkgram.y"
     { bcfree((yyvsp[(1) - (1)])); }
     break;
 
-  case 34:
+  case 33:
 
-/* Line 1806 of yacc.c  */
-#line 459 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 415 "awkgram.y"
     {  (yyval) = NULL; }
     break;
 
-  case 35:
+  case 34:
 
-/* Line 1806 of yacc.c  */
-#line 461 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 417 "awkgram.y"
     {
                if ((yyvsp[(2) - (2)]) == NULL)
                        (yyval) = (yyvsp[(1) - (2)]);
@@ -2423,31 +2374,31 @@ yyreduce:
          }
     break;
 
-  case 36:
+  case 35:
 
-/* Line 1806 of yacc.c  */
-#line 474 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 430 "awkgram.y"
     {  (yyval) = NULL; }
     break;
 
-  case 39:
+  case 38:
 
-/* Line 1806 of yacc.c  */
-#line 484 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 440 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
-  case 40:
+  case 39:
 
-/* Line 1806 of yacc.c  */
-#line 486 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 442 "awkgram.y"
     { (yyval) = (yyvsp[(2) - (3)]); }
     break;
 
-  case 41:
+  case 40:
 
-/* Line 1806 of yacc.c  */
-#line 488 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 444 "awkgram.y"
     {
                if (do_profiling)
                        (yyval) = list_prepend((yyvsp[(1) - (1)]), 
instruction(Op_exec_count));
@@ -2456,10 +2407,10 @@ yyreduce:
          }
     break;
 
-  case 42:
+  case 41:
 
-/* Line 1806 of yacc.c  */
-#line 495 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 451 "awkgram.y"
     {
                INSTRUCTION *dflt, *curr = NULL, *cexp, *cstmt;
                INSTRUCTION *ip, *nextc, *tbreak;
@@ -2551,10 +2502,10 @@ yyreduce:
          }
     break;
 
-  case 43:
+  case 42:
 
-/* Line 1806 of yacc.c  */
-#line 585 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 541 "awkgram.y"
     { 
                /*
                 *    -----------------
@@ -2598,10 +2549,10 @@ yyreduce:
          }
     break;
 
-  case 44:
+  case 43:
 
-/* Line 1806 of yacc.c  */
-#line 627 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 583 "awkgram.y"
     {
                /*
                 *    -----------------
@@ -2645,10 +2596,10 @@ yyreduce:
          }
     break;
 
-  case 45:
+  case 44:
 
-/* Line 1806 of yacc.c  */
-#line 669 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 625 "awkgram.y"
     {
                INSTRUCTION *ip;
                char *var_name = (yyvsp[(3) - (8)])->lextok;
@@ -2715,7 +2666,7 @@ regular_loop:
 
                        tbreak = instruction(Op_arrayfor_final);
                        (yyvsp[(4) - (8)])->opcode = Op_arrayfor_incr;
-                       (yyvsp[(4) - (8)])->array_var = variable(var_name, 
Node_var);
+                       (yyvsp[(4) - (8)])->array_var = variable((yyvsp[(3) - 
(8)])->source_line, var_name, Node_var);
                        (yyvsp[(4) - (8)])->target_jmp = tbreak;
                        tcont = (yyvsp[(4) - (8)]);
                        (yyvsp[(3) - (8)])->opcode = Op_arrayfor_init;
@@ -2765,10 +2716,10 @@ regular_loop:
          }
     break;
 
-  case 46:
+  case 45:
 
-/* Line 1806 of yacc.c  */
-#line 784 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 740 "awkgram.y"
     {
                (yyval) = mk_for_loop((yyvsp[(1) - (12)]), (yyvsp[(3) - (12)]), 
(yyvsp[(6) - (12)]), (yyvsp[(9) - (12)]), (yyvsp[(12) - (12)]));
 
@@ -2777,10 +2728,10 @@ regular_loop:
          }
     break;
 
-  case 47:
+  case 46:
 
-/* Line 1806 of yacc.c  */
-#line 791 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 747 "awkgram.y"
     {
                (yyval) = mk_for_loop((yyvsp[(1) - (11)]), (yyvsp[(3) - (11)]), 
(INSTRUCTION *) NULL, (yyvsp[(8) - (11)]), (yyvsp[(11) - (11)]));
 
@@ -2789,10 +2740,10 @@ regular_loop:
          }
     break;
 
-  case 48:
+  case 47:
 
-/* Line 1806 of yacc.c  */
-#line 798 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 754 "awkgram.y"
     {
                if (do_profiling)
                        (yyval) = list_prepend((yyvsp[(1) - (1)]), 
instruction(Op_exec_count));
@@ -2801,10 +2752,10 @@ regular_loop:
          }
     break;
 
-  case 49:
+  case 48:
 
-/* Line 1806 of yacc.c  */
-#line 808 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 764 "awkgram.y"
     { 
                if (! break_allowed)
                        error_ln((yyvsp[(1) - (2)])->source_line,
@@ -2815,10 +2766,10 @@ regular_loop:
          }
     break;
 
-  case 50:
+  case 49:
 
-/* Line 1806 of yacc.c  */
-#line 817 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 773 "awkgram.y"
     {
                if (! continue_allowed)
                        error_ln((yyvsp[(1) - (2)])->source_line,
@@ -2829,10 +2780,10 @@ regular_loop:
          }
     break;
 
-  case 51:
+  case 50:
 
-/* Line 1806 of yacc.c  */
-#line 826 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 782 "awkgram.y"
     {
                /* if inside function (rule = 0), resolve context at run-time */
                if (rule && rule != Rule)
@@ -2843,10 +2794,10 @@ regular_loop:
          }
     break;
 
-  case 52:
+  case 51:
 
-/* Line 1806 of yacc.c  */
-#line 835 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 791 "awkgram.y"
     {
                if (do_traditional)
                        error_ln((yyvsp[(1) - (2)])->source_line,
@@ -2863,10 +2814,10 @@ regular_loop:
          }
     break;
 
-  case 53:
+  case 52:
 
-/* Line 1806 of yacc.c  */
-#line 850 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 806 "awkgram.y"
     {
                /* Initialize the two possible jump targets, the actual target
                 * is resolved at run-time. 
@@ -2877,47 +2828,47 @@ regular_loop:
                if ((yyvsp[(2) - (3)]) == NULL) {
                        (yyval) = list_create((yyvsp[(1) - (3)]));
                        (void) list_prepend((yyval), instruction(Op_push_i));
-                       (yyval)->nexti->memory = Nnull_string;
+                       (yyval)->nexti->memory = dupnode(Nnull_string);
                } else
                        (yyval) = list_append((yyvsp[(2) - (3)]), (yyvsp[(1) - 
(3)]));
          }
     break;
 
-  case 54:
+  case 53:
 
-/* Line 1806 of yacc.c  */
-#line 865 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 821 "awkgram.y"
     {
                if (! can_return)
                        yyerror(_("`return' used outside function context"));
          }
     break;
 
-  case 55:
+  case 54:
 
-/* Line 1806 of yacc.c  */
-#line 868 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 824 "awkgram.y"
     {
                if ((yyvsp[(3) - (4)]) == NULL) {
                        (yyval) = list_create((yyvsp[(1) - (4)]));
                        (void) list_prepend((yyval), instruction(Op_push_i));
-                       (yyval)->nexti->memory = Nnull_string;
+                       (yyval)->nexti->memory = dupnode(Nnull_string);
                } else
                        (yyval) = list_append((yyvsp[(3) - (4)]), (yyvsp[(1) - 
(4)]));
          }
     break;
 
-  case 57:
+  case 56:
 
-/* Line 1806 of yacc.c  */
-#line 888 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 844 "awkgram.y"
     { in_print = TRUE; in_parens = 0; }
     break;
 
-  case 58:
+  case 57:
 
-/* Line 1806 of yacc.c  */
-#line 889 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 845 "awkgram.y"
     {
                /*
                 * Optimization: plain `print' has no expression list, so $3 is 
null.
@@ -2926,13 +2877,13 @@ regular_loop:
                 */
 
                if ((yyvsp[(1) - (4)])->opcode == Op_K_print &&
-                               ((yyvsp[(3) - (4)]) == NULL
-                                       || ((yyvsp[(3) - (4)])->lasti->opcode 
== Op_field_spec
-                                               && (yyvsp[(3) - 
(4)])->nexti->nexti->nexti == (yyvsp[(3) - (4)])->lasti
-                                               && (yyvsp[(3) - 
(4)])->nexti->nexti->opcode == Op_push_i
-                                               && (yyvsp[(3) - 
(4)])->nexti->nexti->memory->type == Node_val
-                                               && (yyvsp[(3) - 
(4)])->nexti->nexti->memory->numbr == 0.0)
-                               )
+                       ((yyvsp[(3) - (4)]) == NULL
+                               || ((yyvsp[(3) - (4)])->lasti->opcode == 
Op_field_spec
+                                       && (yyvsp[(3) - 
(4)])->nexti->nexti->nexti == (yyvsp[(3) - (4)])->lasti
+                                       && (yyvsp[(3) - 
(4)])->nexti->nexti->opcode == Op_push_i
+                                       && (yyvsp[(3) - 
(4)])->nexti->nexti->memory->type == Node_val
+                                       && (yyvsp[(3) - 
(4)])->nexti->nexti->memory->numbr == 0.0)
+                       )
                ) {
                        static short warned = FALSE;
                        /*   -----------------
@@ -2946,8 +2897,6 @@ regular_loop:
 
                        if ((yyvsp[(3) - (4)]) != NULL) {
                                bcfree((yyvsp[(3) - (4)])->lasti);              
                /* Op_field_spec */
-                               (yyvsp[(3) - (4)])->nexti->nexti->memory->flags 
&= ~PERM;
-                               (yyvsp[(3) - (4)])->nexti->nexti->memory->flags 
|= MALLOC;                      
                                unref((yyvsp[(3) - 
(4)])->nexti->nexti->memory);        /* Node_val */
                                bcfree((yyvsp[(3) - (4)])->nexti->nexti);       
        /* Op_push_i */
                                bcfree((yyvsp[(3) - (4)])->nexti);              
                /* Op_list */
@@ -3014,22 +2963,22 @@ regular_loop:
          }
     break;
 
-  case 59:
+  case 58:
 
-/* Line 1806 of yacc.c  */
-#line 984 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 938 "awkgram.y"
     { sub_counter = 0; }
     break;
 
-  case 60:
+  case 59:
 
-/* Line 1806 of yacc.c  */
-#line 985 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 939 "awkgram.y"
     {
                char *arr = (yyvsp[(2) - (4)])->lextok;
 
                (yyvsp[(2) - (4)])->opcode = Op_push_array;
-               (yyvsp[(2) - (4)])->memory = variable(arr, Node_var_new);
+               (yyvsp[(2) - (4)])->memory = variable((yyvsp[(2) - 
(4)])->source_line, arr, Node_var_new);
 
                if ((yyvsp[(4) - (4)]) == NULL) {
                        static short warned = FALSE;
@@ -3051,10 +3000,10 @@ regular_loop:
          }
     break;
 
-  case 61:
+  case 60:
 
-/* Line 1806 of yacc.c  */
-#line 1014 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 968 "awkgram.y"
     {
                static short warned = FALSE;
                char *arr = (yyvsp[(3) - (4)])->lextok;
@@ -3068,45 +3017,45 @@ regular_loop:
                        error_ln((yyvsp[(1) - (4)])->source_line,
                                _("`delete array' is a gawk extension"));
                }
-               (yyvsp[(3) - (4)])->memory = variable(arr, Node_var_new);
+               (yyvsp[(3) - (4)])->memory = variable((yyvsp[(3) - 
(4)])->source_line, arr, Node_var_new);
                (yyvsp[(3) - (4)])->opcode = Op_push_array;
                (yyvsp[(1) - (4)])->expr_count = 0;
                (yyval) = list_append(list_create((yyvsp[(3) - (4)])), 
(yyvsp[(1) - (4)]));
          }
     break;
 
-  case 62:
+  case 61:
 
-/* Line 1806 of yacc.c  */
-#line 1033 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 987 "awkgram.y"
     {  (yyval) = optimize_assignment((yyvsp[(1) - (1)])); }
     break;
 
-  case 63:
+  case 62:
 
-/* Line 1806 of yacc.c  */
-#line 1038 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 992 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
-  case 64:
+  case 63:
 
-/* Line 1806 of yacc.c  */
-#line 1040 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 994 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
-  case 65:
+  case 64:
 
-/* Line 1806 of yacc.c  */
-#line 1045 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 999 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
-  case 66:
+  case 65:
 
-/* Line 1806 of yacc.c  */
-#line 1047 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1001 "awkgram.y"
     {
                if ((yyvsp[(1) - (2)]) == NULL)
                        (yyval) = list_create((yyvsp[(2) - (2)]));
@@ -3115,17 +3064,17 @@ regular_loop:
          }
     break;
 
-  case 67:
+  case 66:
 
-/* Line 1806 of yacc.c  */
-#line 1054 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1008 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
-  case 68:
+  case 67:
 
-/* Line 1806 of yacc.c  */
-#line 1059 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1013 "awkgram.y"
     {
                INSTRUCTION *casestmt = (yyvsp[(5) - (5)]);
                if ((yyvsp[(5) - (5)]) == NULL)
@@ -3139,10 +3088,10 @@ regular_loop:
          }
     break;
 
-  case 69:
+  case 68:
 
-/* Line 1806 of yacc.c  */
-#line 1071 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1025 "awkgram.y"
     {
                INSTRUCTION *casestmt = (yyvsp[(4) - (4)]);
                if ((yyvsp[(4) - (4)]) == NULL)
@@ -3155,17 +3104,17 @@ regular_loop:
          }
     break;
 
-  case 70:
+  case 69:
 
-/* Line 1806 of yacc.c  */
-#line 1085 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1039 "awkgram.y"
     {  (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
-  case 71:
+  case 70:
 
-/* Line 1806 of yacc.c  */
-#line 1087 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1041 "awkgram.y"
     { 
                (yyvsp[(2) - (2)])->memory->numbr = -(force_number((yyvsp[(2) - 
(2)])->memory));
                bcfree((yyvsp[(1) - (2)]));
@@ -3173,60 +3122,60 @@ regular_loop:
          }
     break;
 
-  case 72:
+  case 71:
 
-/* Line 1806 of yacc.c  */
-#line 1093 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1047 "awkgram.y"
     {
                bcfree((yyvsp[(1) - (2)]));
                (yyval) = (yyvsp[(2) - (2)]);
          }
     break;
 
-  case 73:
+  case 72:
 
-/* Line 1806 of yacc.c  */
-#line 1098 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1052 "awkgram.y"
     {  (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
-  case 74:
+  case 73:
 
-/* Line 1806 of yacc.c  */
-#line 1100 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1054 "awkgram.y"
     {
                (yyvsp[(1) - (1)])->opcode = Op_push_re;
                (yyval) = (yyvsp[(1) - (1)]);
          }
     break;
 
-  case 75:
+  case 74:
 
-/* Line 1806 of yacc.c  */
-#line 1108 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1062 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
-  case 76:
+  case 75:
 
-/* Line 1806 of yacc.c  */
-#line 1110 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1064 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
-  case 78:
+  case 77:
 
-/* Line 1806 of yacc.c  */
-#line 1120 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1074 "awkgram.y"
     {
                (yyval) = (yyvsp[(2) - (3)]);
          }
     break;
 
-  case 79:
+  case 78:
 
-/* Line 1806 of yacc.c  */
-#line 1127 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1081 "awkgram.y"
     {
                in_print = FALSE;
                in_parens = 0;
@@ -3234,17 +3183,17 @@ regular_loop:
          }
     break;
 
-  case 80:
+  case 79:
 
-/* Line 1806 of yacc.c  */
-#line 1132 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1086 "awkgram.y"
     { in_print = FALSE; in_parens = 0; }
     break;
 
-  case 81:
+  case 80:
 
-/* Line 1806 of yacc.c  */
-#line 1133 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1087 "awkgram.y"
     {
                if ((yyvsp[(1) - (3)])->redir_type == redirect_twoway
                        && (yyvsp[(3) - (3)])->lasti->opcode == 
Op_K_getline_redir
@@ -3254,162 +3203,174 @@ regular_loop:
          }
     break;
 
-  case 82:
+  case 81:
 
-/* Line 1806 of yacc.c  */
-#line 1144 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1098 "awkgram.y"
     {
                (yyval) = mk_condition((yyvsp[(3) - (6)]), (yyvsp[(1) - (6)]), 
(yyvsp[(6) - (6)]), NULL, NULL);
          }
     break;
 
-  case 83:
+  case 82:
 
-/* Line 1806 of yacc.c  */
-#line 1149 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1103 "awkgram.y"
     {
                (yyval) = mk_condition((yyvsp[(3) - (9)]), (yyvsp[(1) - (9)]), 
(yyvsp[(6) - (9)]), (yyvsp[(7) - (9)]), (yyvsp[(9) - (9)]));
          }
     break;
 
-  case 88:
+  case 87:
 
-/* Line 1806 of yacc.c  */
-#line 1166 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1120 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
-  case 89:
+  case 88:
 
-/* Line 1806 of yacc.c  */
-#line 1168 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1122 "awkgram.y"
     {
                bcfree((yyvsp[(1) - (2)]));
                (yyval) = (yyvsp[(2) - (2)]);
          }
     break;
 
-  case 92:
+  case 89:
 
-/* Line 1806 of yacc.c  */
-#line 1181 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1130 "awkgram.y"
+    { (yyval) = NULL; }
+    break;
+
+  case 90:
+
+/* Line 1821 of yacc.c  */
+#line 1132 "awkgram.y"
+    { (yyval) = (yyvsp[(1) - (1)]) ; }
+    break;
+
+  case 91:
+
+/* Line 1821 of yacc.c  */
+#line 1137 "awkgram.y"
     {
-               append_param((yyvsp[(1) - (1)])->lextok);
-               (yyvsp[(1) - (1)])->lextok = NULL;
-               bcfree((yyvsp[(1) - (1)]));
+               (yyvsp[(1) - (1)])->param_count = 0;
+               (yyval) = list_create((yyvsp[(1) - (1)]));
          }
     break;
 
-  case 93:
+  case 92:
 
-/* Line 1806 of yacc.c  */
-#line 1187 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1142 "awkgram.y"
     {
-               append_param((yyvsp[(3) - (3)])->lextok);
-               (yyvsp[(3) - (3)])->lextok = NULL;
-               bcfree((yyvsp[(3) - (3)]));
+               (yyvsp[(3) - (3)])->param_count =  (yyvsp[(1) - 
(3)])->lasti->param_count + 1;
+               (yyval) = list_append((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]));
                yyerrok;
          }
     break;
 
-  case 94:
+  case 93:
 
-/* Line 1806 of yacc.c  */
-#line 1194 "awkgram.y"
-    { /* func_params = NULL; */ }
+/* Line 1821 of yacc.c  */
+#line 1148 "awkgram.y"
+    { (yyval) = NULL; }
     break;
 
-  case 95:
+  case 94:
 
-/* Line 1806 of yacc.c  */
-#line 1196 "awkgram.y"
-    { /* func_params = NULL; */ }
+/* Line 1821 of yacc.c  */
+#line 1150 "awkgram.y"
+    { (yyval) = (yyvsp[(1) - (2)]); }
     break;
 
-  case 96:
+  case 95:
 
-/* Line 1806 of yacc.c  */
-#line 1198 "awkgram.y"
-    { /* func_params = NULL; */ }
+/* Line 1821 of yacc.c  */
+#line 1152 "awkgram.y"
+    { (yyval) = (yyvsp[(1) - (3)]); }
     break;
 
-  case 97:
+  case 96:
 
-/* Line 1806 of yacc.c  */
-#line 1204 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1158 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
-  case 98:
+  case 97:
 
-/* Line 1806 of yacc.c  */
-#line 1206 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1160 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
-  case 99:
+  case 98:
 
-/* Line 1806 of yacc.c  */
-#line 1211 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1165 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
-  case 100:
+  case 99:
 
-/* Line 1806 of yacc.c  */
-#line 1213 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1167 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
-  case 101:
+  case 100:
 
-/* Line 1806 of yacc.c  */
-#line 1218 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1172 "awkgram.y"
     {  (yyval) = mk_expression_list(NULL, (yyvsp[(1) - (1)])); }
     break;
 
-  case 102:
+  case 101:
 
-/* Line 1806 of yacc.c  */
-#line 1220 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1174 "awkgram.y"
     {
                (yyval) = mk_expression_list((yyvsp[(1) - (3)]), (yyvsp[(3) - 
(3)]));
                yyerrok;
          }
     break;
 
-  case 103:
+  case 102:
 
-/* Line 1806 of yacc.c  */
-#line 1225 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1179 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
-  case 104:
+  case 103:
 
-/* Line 1806 of yacc.c  */
-#line 1227 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1181 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
-  case 105:
+  case 104:
 
-/* Line 1806 of yacc.c  */
-#line 1229 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1183 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
-  case 106:
+  case 105:
 
-/* Line 1806 of yacc.c  */
-#line 1231 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1185 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
-  case 107:
+  case 106:
 
-/* Line 1806 of yacc.c  */
-#line 1237 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1191 "awkgram.y"
     {
                if (do_lint && (yyvsp[(3) - (3)])->lasti->opcode == 
Op_match_rec)
                        lintwarn_ln((yyvsp[(2) - (3)])->source_line,
@@ -3418,24 +3379,24 @@ regular_loop:
          }
     break;
 
-  case 108:
+  case 107:
 
-/* Line 1806 of yacc.c  */
-#line 1244 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1198 "awkgram.y"
     {  (yyval) = mk_boolean((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) 
- (3)])); }
     break;
 
-  case 109:
+  case 108:
 
-/* Line 1806 of yacc.c  */
-#line 1246 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1200 "awkgram.y"
     {  (yyval) = mk_boolean((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) 
- (3)])); }
     break;
 
-  case 110:
+  case 109:
 
-/* Line 1806 of yacc.c  */
-#line 1248 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1202 "awkgram.y"
     {
                if ((yyvsp[(1) - (3)])->lasti->opcode == Op_match_rec)
                        warning_ln((yyvsp[(2) - (3)])->source_line,
@@ -3453,13 +3414,13 @@ regular_loop:
          }
     break;
 
-  case 111:
+  case 110:
 
-/* Line 1806 of yacc.c  */
-#line 1264 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1218 "awkgram.y"
     {
                if (do_lint_old)
-                 warning_ln((yyvsp[(2) - (3)])->source_line,
+                       warning_ln((yyvsp[(2) - (3)])->source_line,
                                _("old awk does not support the keyword `in' 
except after `for'"));
                (yyvsp[(3) - (3)])->nexti->opcode = Op_push_array;
                (yyvsp[(2) - (3)])->opcode = Op_in_array;
@@ -3468,10 +3429,10 @@ regular_loop:
          }
     break;
 
-  case 112:
+  case 111:
 
-/* Line 1806 of yacc.c  */
-#line 1274 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1228 "awkgram.y"
     {
                if (do_lint && (yyvsp[(3) - (3)])->lasti->opcode == 
Op_match_rec)
                        lintwarn_ln((yyvsp[(2) - (3)])->source_line,
@@ -3480,90 +3441,90 @@ regular_loop:
          }
     break;
 
-  case 113:
+  case 112:
 
-/* Line 1806 of yacc.c  */
-#line 1281 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1235 "awkgram.y"
     { (yyval) = mk_condition((yyvsp[(1) - (5)]), (yyvsp[(2) - (5)]), 
(yyvsp[(3) - (5)]), (yyvsp[(4) - (5)]), (yyvsp[(5) - (5)])); }
     break;
 
-  case 114:
+  case 113:
 
-/* Line 1806 of yacc.c  */
-#line 1283 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1237 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
-  case 115:
+  case 114:
 
-/* Line 1806 of yacc.c  */
-#line 1288 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1242 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
-  case 116:
+  case 115:
 
-/* Line 1806 of yacc.c  */
-#line 1290 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1244 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
-  case 117:
+  case 116:
 
-/* Line 1806 of yacc.c  */
-#line 1292 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1246 "awkgram.y"
     {  
                (yyvsp[(2) - (2)])->opcode = Op_assign_quotient;
                (yyval) = (yyvsp[(2) - (2)]);
          }
     break;
 
+  case 117:
+
+/* Line 1821 of yacc.c  */
+#line 1254 "awkgram.y"
+    { (yyval) = (yyvsp[(1) - (1)]); }
+    break;
+
   case 118:
 
-/* Line 1806 of yacc.c  */
-#line 1300 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1256 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 119:
 
-/* Line 1806 of yacc.c  */
-#line 1302 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1261 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 120:
 
-/* Line 1806 of yacc.c  */
-#line 1307 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1263 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 121:
 
-/* Line 1806 of yacc.c  */
-#line 1309 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1268 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 122:
 
-/* Line 1806 of yacc.c  */
-#line 1314 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1270 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 123:
 
-/* Line 1806 of yacc.c  */
-#line 1316 "awkgram.y"
-    { (yyval) = (yyvsp[(1) - (1)]); }
-    break;
-
-  case 124:
-
-/* Line 1806 of yacc.c  */
-#line 1318 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1272 "awkgram.y"
     {
                int count = 2;
                int is_simple_var = FALSE;
@@ -3575,32 +3536,29 @@ regular_loop:
                        (yyvsp[(1) - (2)])->lasti->opcode = Op_no_op;
                } else {
                        is_simple_var = ((yyvsp[(1) - (2)])->nexti->opcode == 
Op_push
-                                               && (yyvsp[(1) - (2)])->lasti == 
(yyvsp[(1) - (2)])->nexti); /* first exp. is a simple
-                                                                            * 
variable?; kludge for use
-                                                                            * 
in Op_assign_concat.
-                                                                            */
+                                       && (yyvsp[(1) - (2)])->lasti == 
(yyvsp[(1) - (2)])->nexti); /* first exp. is a simple
+                                                                    * 
variable?; kludge for use
+                                                                    * in 
Op_assign_concat.
+                                                                    */
                }
 
                if (do_optimize > 1
-                               && (yyvsp[(1) - (2)])->nexti == (yyvsp[(1) - 
(2)])->lasti && (yyvsp[(1) - (2)])->nexti->opcode == Op_push_i
-                               && (yyvsp[(2) - (2)])->nexti == (yyvsp[(2) - 
(2)])->lasti && (yyvsp[(2) - (2)])->nexti->opcode == Op_push_i
+                       && (yyvsp[(1) - (2)])->nexti == (yyvsp[(1) - 
(2)])->lasti && (yyvsp[(1) - (2)])->nexti->opcode == Op_push_i
+                       && (yyvsp[(2) - (2)])->nexti == (yyvsp[(2) - 
(2)])->lasti && (yyvsp[(2) - (2)])->nexti->opcode == Op_push_i
                ) {
                        NODE *n1 = (yyvsp[(1) - (2)])->nexti->memory;
                        NODE *n2 = (yyvsp[(2) - (2)])->nexti->memory;
                        size_t nlen;
 
-                       (void) force_string(n1);
-                       (void) force_string(n2);
+                       n1 = force_string(n1);
+                       n2 = force_string(n2);
                        nlen = n1->stlen + n2->stlen;
                        erealloc(n1->stptr, char *, nlen + 2, "constant fold");
                        memcpy(n1->stptr + n1->stlen, n2->stptr, n2->stlen);
                        n1->stlen = nlen;
                        n1->stptr[nlen] = '\0';
-                       n1->flags &= ~(NUMCUR|NUMBER);
+                       n1->flags &= ~(NUMCUR|NUMBER|NUMINT);
                        n1->flags |= (STRING|STRCUR);
-
-                       n2->flags &= ~PERM;
-                       n2->flags |= MALLOC;
                        unref(n2);
                        bcfree((yyvsp[(2) - (2)])->nexti);
                        bcfree((yyvsp[(2) - (2)]));
@@ -3615,52 +3573,52 @@ regular_loop:
          }
     break;
 
+  case 125:
+
+/* Line 1821 of yacc.c  */
+#line 1324 "awkgram.y"
+    { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - 
(3)])); }
+    break;
+
   case 126:
 
-/* Line 1806 of yacc.c  */
-#line 1373 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1326 "awkgram.y"
     { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - 
(3)])); }
     break;
 
   case 127:
 
-/* Line 1806 of yacc.c  */
-#line 1375 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1328 "awkgram.y"
     { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - 
(3)])); }
     break;
 
   case 128:
 
-/* Line 1806 of yacc.c  */
-#line 1377 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1330 "awkgram.y"
     { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - 
(3)])); }
     break;
 
   case 129:
 
-/* Line 1806 of yacc.c  */
-#line 1379 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1332 "awkgram.y"
     { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - 
(3)])); }
     break;
 
   case 130:
 
-/* Line 1806 of yacc.c  */
-#line 1381 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1334 "awkgram.y"
     { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - 
(3)])); }
     break;
 
   case 131:
 
-/* Line 1806 of yacc.c  */
-#line 1383 "awkgram.y"
-    { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - 
(3)])); }
-    break;
-
-  case 132:
-
-/* Line 1806 of yacc.c  */
-#line 1385 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1336 "awkgram.y"
     {
                /*
                 * In BEGINFILE/ENDFILE, allow `getline var < file'
@@ -3685,30 +3643,30 @@ regular_loop:
          }
     break;
 
-  case 133:
+  case 132:
 
-/* Line 1806 of yacc.c  */
-#line 1408 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1359 "awkgram.y"
     {
                (yyvsp[(2) - (2)])->opcode = Op_postincrement;
                (yyval) = mk_assignment((yyvsp[(1) - (2)]), NULL, (yyvsp[(2) - 
(2)]));
          }
     break;
 
-  case 134:
+  case 133:
 
-/* Line 1806 of yacc.c  */
-#line 1413 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1364 "awkgram.y"
     {
                (yyvsp[(2) - (2)])->opcode = Op_postdecrement;
                (yyval) = mk_assignment((yyvsp[(1) - (2)]), NULL, (yyvsp[(2) - 
(2)]));
          }
     break;
 
-  case 135:
+  case 134:
 
-/* Line 1806 of yacc.c  */
-#line 1418 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1369 "awkgram.y"
     {
                if (do_lint_old) {
                    warning_ln((yyvsp[(4) - (5)])->source_line,
@@ -3730,81 +3688,81 @@ regular_loop:
          }
     break;
 
-  case 136:
+  case 135:
 
-/* Line 1806 of yacc.c  */
-#line 1443 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1394 "awkgram.y"
     {
                  (yyval) = mk_getline((yyvsp[(3) - (4)]), (yyvsp[(4) - (4)]), 
(yyvsp[(1) - (4)]), (yyvsp[(2) - (4)])->redir_type);
                  bcfree((yyvsp[(2) - (4)]));
                }
     break;
 
+  case 136:
+
+/* Line 1821 of yacc.c  */
+#line 1400 "awkgram.y"
+    { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - 
(3)])); }
+    break;
+
   case 137:
 
-/* Line 1806 of yacc.c  */
-#line 1449 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1402 "awkgram.y"
     { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - 
(3)])); }
     break;
 
   case 138:
 
-/* Line 1806 of yacc.c  */
-#line 1451 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1404 "awkgram.y"
     { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - 
(3)])); }
     break;
 
   case 139:
 
-/* Line 1806 of yacc.c  */
-#line 1453 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1406 "awkgram.y"
     { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - 
(3)])); }
     break;
 
   case 140:
 
-/* Line 1806 of yacc.c  */
-#line 1455 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1408 "awkgram.y"
     { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - 
(3)])); }
     break;
 
   case 141:
 
-/* Line 1806 of yacc.c  */
-#line 1457 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1410 "awkgram.y"
     { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - 
(3)])); }
     break;
 
   case 142:
 
-/* Line 1806 of yacc.c  */
-#line 1459 "awkgram.y"
-    { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - 
(3)])); }
-    break;
-
-  case 143:
-
-/* Line 1806 of yacc.c  */
-#line 1464 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1415 "awkgram.y"
     {
                (yyval) = list_create((yyvsp[(1) - (1)]));
          }
     break;
 
-  case 144:
+  case 143:
 
-/* Line 1806 of yacc.c  */
-#line 1468 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1419 "awkgram.y"
     {
                if ((yyvsp[(2) - (2)])->opcode == Op_match_rec) {
                        (yyvsp[(2) - (2)])->opcode = Op_nomatch;
                        (yyvsp[(1) - (2)])->opcode = Op_push_i;
-                       (yyvsp[(1) - (2)])->memory = mk_number(0.0, 
(PERM|NUMCUR|NUMBER));      
+                       (yyvsp[(1) - (2)])->memory = make_number(0.0);  
                        (yyval) = 
list_append(list_append(list_create((yyvsp[(1) - (2)])),
-                                                               
instruction(Op_field_spec)), (yyvsp[(2) - (2)]));
+                                               instruction(Op_field_spec)), 
(yyvsp[(2) - (2)]));
                } else {
                        if (do_optimize > 1 && (yyvsp[(2) - (2)])->nexti == 
(yyvsp[(2) - (2)])->lasti
-                                                       && (yyvsp[(2) - 
(2)])->nexti->opcode == Op_push_i
+                                       && (yyvsp[(2) - (2)])->nexti->opcode == 
Op_push_i
                        ) {
                                NODE *n = (yyvsp[(2) - (2)])->nexti->memory;
                                if ((n->flags & (STRCUR|STRING)) != 0) {
@@ -3827,17 +3785,17 @@ regular_loop:
           }
     break;
 
-  case 145:
+  case 144:
 
-/* Line 1806 of yacc.c  */
-#line 1499 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1450 "awkgram.y"
     { (yyval) = (yyvsp[(2) - (3)]); }
     break;
 
-  case 146:
+  case 145:
 
-/* Line 1806 of yacc.c  */
-#line 1501 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1452 "awkgram.y"
     {
                (yyval) = snode((yyvsp[(3) - (4)]), (yyvsp[(1) - (4)]));
                if ((yyval) == NULL)
@@ -3845,10 +3803,10 @@ regular_loop:
          }
     break;
 
-  case 147:
+  case 146:
 
-/* Line 1806 of yacc.c  */
-#line 1507 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1458 "awkgram.y"
     {
                (yyval) = snode((yyvsp[(3) - (4)]), (yyvsp[(1) - (4)]));
                if ((yyval) == NULL)
@@ -3856,10 +3814,10 @@ regular_loop:
          }
     break;
 
-  case 148:
+  case 147:
 
-/* Line 1806 of yacc.c  */
-#line 1513 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1464 "awkgram.y"
     {
                static short warned1 = FALSE;
 
@@ -3874,51 +3832,52 @@ regular_loop:
          }
     break;
 
-  case 151:
+  case 150:
 
-/* Line 1806 of yacc.c  */
-#line 1528 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1479 "awkgram.y"
     {
                (yyvsp[(1) - (2)])->opcode = Op_preincrement;
                (yyval) = mk_assignment((yyvsp[(2) - (2)]), NULL, (yyvsp[(1) - 
(2)]));
          }
     break;
 
-  case 152:
+  case 151:
 
-/* Line 1806 of yacc.c  */
-#line 1533 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1484 "awkgram.y"
     {
                (yyvsp[(1) - (2)])->opcode = Op_predecrement;
                (yyval) = mk_assignment((yyvsp[(2) - (2)]), NULL, (yyvsp[(1) - 
(2)]));
          }
     break;
 
-  case 153:
+  case 152:
 
-/* Line 1806 of yacc.c  */
-#line 1538 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1489 "awkgram.y"
     {
                (yyval) = list_create((yyvsp[(1) - (1)]));
          }
     break;
 
-  case 154:
+  case 153:
 
-/* Line 1806 of yacc.c  */
-#line 1542 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1493 "awkgram.y"
     {
                (yyval) = list_create((yyvsp[(1) - (1)]));
          }
     break;
 
-  case 155:
+  case 154:
 
-/* Line 1806 of yacc.c  */
-#line 1546 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1497 "awkgram.y"
     {
                if ((yyvsp[(2) - (2)])->lasti->opcode == Op_push_i
-                               && ((yyvsp[(2) - (2)])->lasti->memory->flags & 
(STRCUR|STRING)) == 0) {
+                       && ((yyvsp[(2) - (2)])->lasti->memory->flags & 
(STRCUR|STRING)) == 0
+               ) {
                        (yyvsp[(2) - (2)])->lasti->memory->numbr = 
-(force_number((yyvsp[(2) - (2)])->lasti->memory));
                        (yyval) = (yyvsp[(2) - (2)]);
                        bcfree((yyvsp[(1) - (2)]));
@@ -3929,35 +3888,35 @@ regular_loop:
          }
     break;
 
-  case 156:
+  case 155:
 
-/* Line 1806 of yacc.c  */
-#line 1558 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1510 "awkgram.y"
     {
            /*
             * was: $$ = $2
             * POSIX semantics: force a conversion to numeric type
             */
                (yyvsp[(1) - (2)])->opcode = Op_plus_i;
-               (yyvsp[(1) - (2)])->memory = mk_number((AWKNUM) 0.0, 
(PERM|NUMCUR|NUMBER));
+               (yyvsp[(1) - (2)])->memory = make_number(0.0);
                (yyval) = list_append((yyvsp[(2) - (2)]), (yyvsp[(1) - (2)]));
          }
     break;
 
-  case 157:
+  case 156:
 
-/* Line 1806 of yacc.c  */
-#line 1571 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1523 "awkgram.y"
     {
                func_use((yyvsp[(1) - (1)])->lasti->func_name, FUNC_USE);
                (yyval) = (yyvsp[(1) - (1)]);
          }
     break;
 
-  case 158:
+  case 157:
 
-/* Line 1806 of yacc.c  */
-#line 1576 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1528 "awkgram.y"
     {
                /* indirect function call */
                INSTRUCTION *f, *t;
@@ -3978,7 +3937,7 @@ regular_loop:
                name = estrdup(f->func_name, strlen(f->func_name));
                if (is_std_var(name))
                        yyerror(_("can not use special variable `%s' for 
indirect function call"), name);
-               indirect_var = variable(name, Node_var_new);
+               indirect_var = variable(f->source_line, name, Node_var_new);
                t = instruction(Op_push);
                t->memory = indirect_var;
 
@@ -3992,10 +3951,10 @@ regular_loop:
          }
     break;
 
-  case 159:
+  case 158:
 
-/* Line 1806 of yacc.c  */
-#line 1612 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1564 "awkgram.y"
     {
                param_sanity((yyvsp[(3) - (4)]));
                (yyvsp[(1) - (4)])->opcode = Op_func_call;
@@ -4011,54 +3970,54 @@ regular_loop:
          }
     break;
 
-  case 160:
+  case 159:
 
-/* Line 1806 of yacc.c  */
-#line 1629 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1581 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
-  case 161:
+  case 160:
 
-/* Line 1806 of yacc.c  */
-#line 1631 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1583 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
-  case 162:
+  case 161:
 
-/* Line 1806 of yacc.c  */
-#line 1636 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1588 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
-  case 163:
+  case 162:
 
-/* Line 1806 of yacc.c  */
-#line 1638 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1590 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (2)]); }
     break;
 
-  case 164:
+  case 163:
 
-/* Line 1806 of yacc.c  */
-#line 1643 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1595 "awkgram.y"
     {  (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
-  case 165:
+  case 164:
 
-/* Line 1806 of yacc.c  */
-#line 1645 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1597 "awkgram.y"
     {
                (yyval) = list_merge((yyvsp[(1) - (2)]), (yyvsp[(2) - (2)]));
          }
     break;
 
-  case 166:
+  case 165:
 
-/* Line 1806 of yacc.c  */
-#line 1652 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1604 "awkgram.y"
     {
                INSTRUCTION *ip = (yyvsp[(1) - (1)])->lasti; 
                int count = ip->sub_count;      /* # of SUBSEP-seperated 
expressions */
@@ -4074,10 +4033,10 @@ regular_loop:
          }
     break;
 
-  case 167:
+  case 166:
 
-/* Line 1806 of yacc.c  */
-#line 1669 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1621 "awkgram.y"
     {
                INSTRUCTION *t = (yyvsp[(2) - (3)]);
                if ((yyvsp[(2) - (3)]) == NULL) {
@@ -4085,7 +4044,7 @@ regular_loop:
                                _("invalid subscript expression"));
                        /* install Null string as subscript. */
                        t = list_create(instruction(Op_push_i));
-                       t->nexti->memory = Nnull_string;
+                       t->nexti->memory = dupnode(Nnull_string);
                        (yyvsp[(3) - (3)])->sub_count = 1;                      
                } else
                        (yyvsp[(3) - (3)])->sub_count = count_expressions(&t, 
FALSE);
@@ -4093,67 +4052,63 @@ regular_loop:
          }
     break;
 
-  case 168:
+  case 167:
 
-/* Line 1806 of yacc.c  */
-#line 1686 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1638 "awkgram.y"
     {  (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
-  case 169:
+  case 168:
 
-/* Line 1806 of yacc.c  */
-#line 1688 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1640 "awkgram.y"
     {
                (yyval) = list_merge((yyvsp[(1) - (2)]), (yyvsp[(2) - (2)]));
          }
     break;
 
-  case 170:
+  case 169:
 
-/* Line 1806 of yacc.c  */
-#line 1695 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1647 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (2)]); }
     break;
 
-  case 171:
+  case 170:
 
-/* Line 1806 of yacc.c  */
-#line 1700 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1652 "awkgram.y"
     {
                char *var_name = (yyvsp[(1) - (1)])->lextok;
 
                (yyvsp[(1) - (1)])->opcode = Op_push;
-               (yyvsp[(1) - (1)])->memory = variable(var_name, Node_var_new);
+               (yyvsp[(1) - (1)])->memory = variable((yyvsp[(1) - 
(1)])->source_line, var_name, Node_var_new);
                (yyval) = list_create((yyvsp[(1) - (1)]));
          }
     break;
 
-  case 172:
+  case 171:
 
-/* Line 1806 of yacc.c  */
-#line 1708 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1660 "awkgram.y"
     {
-               NODE *n;
-
                char *arr = (yyvsp[(1) - (2)])->lextok;
-               if ((n = lookup(arr)) != NULL && ! isarray(n))
-                       yyerror(_("use of non-array as array"));
-               (yyvsp[(1) - (2)])->memory = variable(arr, Node_var_new);
+               (yyvsp[(1) - (2)])->memory = variable((yyvsp[(1) - 
(2)])->source_line, arr, Node_var_new);
                (yyvsp[(1) - (2)])->opcode = Op_push_array;
                (yyval) = list_prepend((yyvsp[(2) - (2)]), (yyvsp[(1) - (2)]));
          }
     break;
 
-  case 173:
+  case 172:
 
-/* Line 1806 of yacc.c  */
-#line 1722 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1670 "awkgram.y"
     {
                INSTRUCTION *ip = (yyvsp[(1) - (1)])->nexti;
                if (ip->opcode == Op_push
-                               && ip->memory->type == Node_var
-                               && ip->memory->var_update
+                       && ip->memory->type == Node_var
+                       && ip->memory->var_update
                ) {
                        (yyval) = list_prepend((yyvsp[(1) - (1)]), 
instruction(Op_var_update));
                        (yyval)->nexti->memory = ip->memory;
@@ -4163,81 +4118,81 @@ regular_loop:
          }
     break;
 
-  case 174:
+  case 173:
 
-/* Line 1806 of yacc.c  */
-#line 1735 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1683 "awkgram.y"
     {
                (yyval) = list_append((yyvsp[(2) - (3)]), (yyvsp[(1) - (3)]));
                if ((yyvsp[(3) - (3)]) != NULL)
-                 mk_assignment((yyvsp[(2) - (3)]), NULL, (yyvsp[(3) - (3)]));
+                       mk_assignment((yyvsp[(2) - (3)]), NULL, (yyvsp[(3) - 
(3)]));
          }
     break;
 
-  case 175:
+  case 174:
 
-/* Line 1806 of yacc.c  */
-#line 1744 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1692 "awkgram.y"
     {
                (yyvsp[(1) - (1)])->opcode = Op_postincrement;
          }
     break;
 
-  case 176:
+  case 175:
 
-/* Line 1806 of yacc.c  */
-#line 1748 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1696 "awkgram.y"
     {
                (yyvsp[(1) - (1)])->opcode = Op_postdecrement;
          }
     break;
 
-  case 177:
+  case 176:
 
-/* Line 1806 of yacc.c  */
-#line 1751 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1699 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
-  case 179:
+  case 178:
 
-/* Line 1806 of yacc.c  */
-#line 1759 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1707 "awkgram.y"
     { yyerrok; }
     break;
 
-  case 180:
+  case 179:
 
-/* Line 1806 of yacc.c  */
-#line 1763 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1711 "awkgram.y"
     { yyerrok; }
     break;
 
-  case 183:
+  case 182:
 
-/* Line 1806 of yacc.c  */
-#line 1772 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1720 "awkgram.y"
     { yyerrok; }
     break;
 
-  case 184:
+  case 183:
 
-/* Line 1806 of yacc.c  */
-#line 1776 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1724 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); yyerrok; }
     break;
 
-  case 185:
+  case 184:
 
-/* Line 1806 of yacc.c  */
-#line 1780 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1728 "awkgram.y"
     { yyerrok; }
     break;
 
 
 
-/* Line 1806 of yacc.c  */
-#line 4253 "awkgram.c"
+/* Line 1821 of yacc.c  */
+#line 4208 "awkgram.c"
       default: break;
     }
   /* User semantic actions sometimes alter yychar, and that requires
@@ -4468,7 +4423,7 @@ yyreturn:
 
 
 /* Line 2067 of yacc.c  */
-#line 1782 "awkgram.y"
+#line 1730 "awkgram.y"
 
 
 struct token {
@@ -4515,9 +4470,12 @@ static const struct token tokentab[] = {
 {"END",                Op_rule,         LEX_END,       0,              0},
 {"ENDFILE",            Op_rule,         LEX_ENDFILE,   GAWKX,          0},
 #ifdef ARRAYDEBUG
-{"adump",      Op_builtin,    LEX_BUILTIN,     GAWKX|A(1),     do_adump},
+{"adump",      Op_builtin,    LEX_BUILTIN,     GAWKX|A(1)|A(2),        
do_adump},
 #endif
 {"and",                Op_builtin,    LEX_BUILTIN,     GAWKX|A(2),     do_and},
+#ifdef ARRAYDEBUG
+{"aoption",    Op_builtin,    LEX_BUILTIN,     GAWKX|A(2),     do_aoption},
+#endif
 {"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),   do_atan2},
@@ -4570,9 +4528,6 @@ static const struct token tokentab[] = {
 {"sprintf",    Op_builtin,      LEX_BUILTIN,   0,              do_sprintf},
 {"sqrt",       Op_builtin,      LEX_BUILTIN,   A(1),           do_sqrt},
 {"srand",      Op_builtin,      LEX_BUILTIN,   NOT_OLD|A(0)|A(1), do_srand},
-#if defined(GAWKDEBUG) || defined(ARRAYDEBUG) /* || ... */
-{"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},
 {"strtonum",   Op_builtin,    LEX_BUILTIN,     GAWKX|A(1),     do_strtonum},
 {"sub",                Op_builtin,      LEX_BUILTIN,   NOT_OLD|A(2)|A(3), 
do_sub},
@@ -5095,6 +5050,7 @@ next_sourcefile()
         *
         * assert(lexeof == TRUE);
         */
+
        lexeof = FALSE;
        eof_warned = FALSE;
        sourcefile->srclines = sourceline;      /* total no of lines in current 
file */
@@ -5483,8 +5439,10 @@ yylex(void)
        int mid;
        static int did_newline = FALSE;
        char *tokkey;
+       size_t toklen;
        int inhex = FALSE;
        int intlstr = FALSE;
+       AWKNUM d;
 
 #define GET_INSTRUCTION(op) bcalloc(op, 1, sourceline)
 
@@ -5916,16 +5874,16 @@ retry:
                        tokadd(c);
                }
                yylval = GET_INSTRUCTION(Op_token);
+               toklen = tok - tokstart;
                if (want_source) {
-                       yylval->lextok = estrdup(tokstart, tok - tokstart);
+                       yylval->lextok = estrdup(tokstart, toklen);
                        return lasttok = FILENAME;
                }
                
                yylval->opcode = Op_push_i;
-               yylval->memory = make_str_node(tokstart,
-                                               tok - tokstart, esc_seen ? SCAN 
: 0);
-               yylval->memory->flags &= ~MALLOC;
-               yylval->memory->flags |= PERM;
+               if (esc_seen)
+                       toklen = scan_escape(tokstart, toklen);
+               yylval->memory = make_string(tokstart, toklen);
                if (intlstr) {
                        yylval->memory->flags |= INTLSTR;
                        intlstr = FALSE;
@@ -6067,10 +6025,12 @@ retry:
                                        lintwarn("numeric constant `%.*s' 
treated as hexadecimal",
                                                (int) strlen(tokstart)-1, 
tokstart);
                        }
-                       yylval->memory = mk_number(nondec2awknum(tokstart, 
strlen(tokstart)),
-                                                                               
        PERM|NUMCUR|NUMBER);
+                       d = nondec2awknum(tokstart, strlen(tokstart));
                } else
-                       yylval->memory = mk_number(atof(tokstart), 
PERM|NUMCUR|NUMBER);
+                       d = atof(tokstart);
+               yylval->memory = make_number(d);
+               if (d <= INT32_MAX && d >= INT32_MIN && d == (int32_t) d)
+                       yylval->memory->flags |= NUMINT;
                return lasttok = YNUMBER;
 
        case '&':
@@ -6247,23 +6207,6 @@ out:
 #undef NEWLINE_EOF
 }
 
-/* mk_symbol --- allocates a symbol for the symbol table. */
-
-NODE *
-mk_symbol(NODETYPE type, NODE *value)
-{
-       NODE *r;
-
-       getnode(r);
-       r->type = type;
-       r->flags = MALLOC;
-       r->lnode = value;
-       r->rnode = NULL;
-       r->parent_array = NULL;
-       r->var_assign = (Func_ptr) 0;
-       return r;
-}
-
 /* snode --- instructions for builtin functions. Checks for arg. count
              and supplies defaults where possible. */
 
@@ -6306,7 +6249,7 @@ snode(INSTRUCTION *subn, INSTRUCTION *r)
                        list = list_create(r);
                        (void) list_prepend(list, instruction(Op_field_spec));
                        (void) list_prepend(list, instruction(Op_push_i));
-                       list->nexti->memory = mk_number((AWKNUM) 0.0, 
(PERM|NUMCUR|NUMBER));
+                       list->nexti->memory = make_number(0.0);
                        return list; 
                } else {
                        arg = subn->nexti;
@@ -6348,7 +6291,7 @@ snode(INSTRUCTION *subn, INSTRUCTION *r)
                if (nexp == 2) {
                        INSTRUCTION *expr;
                        expr = list_create(instruction(Op_push_i));
-                       expr->nexti->memory = mk_number((AWKNUM) 0.0, 
(PERM|NUMCUR|NUMBER));
+                       expr->nexti->memory = make_number(0.0);
                        (void) mk_expression_list(subn,
                                        list_append(expr, 
instruction(Op_field_spec)));
                }
@@ -6396,7 +6339,7 @@ snode(INSTRUCTION *subn, INSTRUCTION *r)
                if (nexp == 3) {
                        arg = subn->nexti->lasti->nexti->lasti->nexti;  /* 3rd 
arg list */
                        ip = instruction(Op_push_i);
-                       ip->memory = mk_number((AWKNUM) 0.0, 
(PERM|NUMCUR|NUMBER));
+                       ip->memory = make_number(0.0);
                        (void) mk_expression_list(subn,
                                        list_append(list_create(ip),
                                                instruction(Op_field_spec)));
@@ -6499,7 +6442,7 @@ snode(INSTRUCTION *subn, INSTRUCTION *r)
                if (ip->opcode == Op_push)
                        ip->opcode = Op_push_array;
        }
-#endif         
+#endif
 
        if (subn != NULL) {
                r->expr_count = count_expressions(&subn, FALSE);
@@ -6510,75 +6453,6 @@ snode(INSTRUCTION *subn, INSTRUCTION *r)
        return list_create(r);
 }
 
-/* append_param --- append PNAME to the list of parameters
- *                  for the current function.
- */
-
-static void
-append_param(char *pname)
-{
-       static NODE *savetail = NULL;
-       NODE *p;
-
-       p = make_param(pname);
-       if (func_params == NULL) {
-               func_params = p;
-               savetail = p;
-       } else if (savetail != NULL) {
-               savetail->rnode = p;
-               savetail = p;
-       }
-}
-
-/* dup_parms --- return TRUE if there are duplicate parameters */
-
-static int
-dup_parms(INSTRUCTION *fp, NODE *func)
-{
-       NODE *np;
-       const char *fname, **names;
-       int count, i, j, dups;
-       NODE *params;
-
-       if (func == NULL)       /* error earlier */
-               return TRUE;
-
-       fname = func->param;
-       count = func->param_cnt;
-       params = func->rnode;
-
-       if (count == 0)         /* no args, no problem */
-               return FALSE;
-
-       if (params == NULL)     /* error earlier */
-               return TRUE;
-
-       emalloc(names, const char **, count * sizeof(char *), "dup_parms");
-
-       i = 0;
-       for (np = params; np != NULL; np = np->rnode) {
-               if (np->param == NULL) { /* error earlier, give up, go home */
-                       efree(names);
-                       return TRUE;
-               }
-               names[i++] = np->param;
-       }
-
-       dups = 0;
-       for (i = 1; i < count; i++) {
-               for (j = 0; j < i; j++) {
-                       if (strcmp(names[i], names[j]) == 0) {
-                               dups++;
-                               error_ln(fp->source_line,
-       _("function `%s': parameter #%d, `%s', duplicates parameter #%d"),
-                                       fname, i + 1, names[j], j+1);
-                       }
-               }
-       }
-
-       efree(names);
-       return (dups > 0 ? TRUE : FALSE);
-}
 
 /* parms_shadow --- check if parameters shadow globals */
 
@@ -6587,18 +6461,19 @@ parms_shadow(INSTRUCTION *pc, int *shadow)
 {
        int pcount, i;
        int ret = FALSE;
-       NODE *func;
+       NODE *func, *fp;
        char *fname;
 
        func = pc->func_body;
-       fname = func->lnode->param;
-       
+       fname = func->vname;
+       fp = func->fparms;
+
 #if 0  /* can't happen, already exited if error ? */
        if (fname == NULL || func == NULL)      /* error earlier */
                return FALSE;
 #endif
 
-       pcount = func->lnode->param_cnt;
+       pcount = func->param_cnt;
 
        if (pcount == 0)                /* no args, no problem */
                return 0;
@@ -6610,10 +6485,10 @@ parms_shadow(INSTRUCTION *pc, int *shadow)
         * about all shadowed parameters.
         */
        for (i = 0; i < pcount; i++) {
-               if (lookup(func->parmlist[i]) != NULL) {
+               if (lookup(fp[i].param) != NULL) {
                        warning(
        _("function `%s': parameter `%s' shadows global variable"),
-                                       fname, func->parmlist[i]);
+                                       fname, fp[i].param);
                        ret = TRUE;
                }
        }
@@ -6623,79 +6498,10 @@ parms_shadow(INSTRUCTION *pc, int *shadow)
 }
 
 
-/*
- * install_symbol:
- * Install a name in the symbol table, even if it is already there.
- * Caller must check against redefinition if that is desired. 
- */
-
-
-NODE *
-install_symbol(char *name, NODE *value)
-{
-       NODE *hp;
-       size_t len;
-       int bucket;
-
-       if (install_func)
-               (*install_func)(name);
-
-       var_count++;
-       len = strlen(name);
-       bucket = hash(name, len, (unsigned long) HASHSIZE, NULL);
-       getnode(hp);
-       hp->type = Node_hashnode;
-       hp->hnext = variables[bucket];
-       variables[bucket] = hp;
-       hp->hlength = len;
-       hp->hvalue = value;
-       hp->hname = name;
-       hp->hvalue->vname = name;
-       return hp->hvalue;
-}
-
-/* lookup --- find the most recent hash node for name installed by 
install_symbol */
-
-NODE *
-lookup(const char *name)
-{
-       NODE *bucket;
-       size_t len;
-
-       len = strlen(name);
-       for (bucket = variables[hash(name, len, (unsigned long) HASHSIZE, 
NULL)];
-                       bucket != NULL; bucket = bucket->hnext)
-               if (bucket->hlength == len && STREQN(bucket->hname, name, len))
-                       return bucket->hvalue;
-       return NULL;
-}
-
-/* sym_comp --- compare two symbol (variable or function) names */
-
-static int
-sym_comp(const void *v1, const void *v2)
-{
-       const NODE *const *npp1, *const *npp2;
-       const NODE *n1, *n2;
-       int minlen;
-
-       npp1 = (const NODE *const *) v1;
-       npp2 = (const NODE *const *) v2;
-       n1 = *npp1;
-       n2 = *npp2;
-
-       if (n1->hlength > n2->hlength)
-               minlen = n1->hlength;
-       else
-               minlen = n2->hlength;
-
-       return strncmp(n1->hname, n2->hname, minlen);
-}
-
 /* valinfo --- dump var info */
 
 void
-valinfo(NODE *n, int (*print_func)(FILE *, const char *, ...), FILE *fp)
+valinfo(NODE *n, Func_print print_func, FILE *fp)
 {
        if (n == Nnull_string)
                print_func(fp, "uninitialized scalar\n");
@@ -6713,52 +6519,6 @@ valinfo(NODE *n, int (*print_func)(FILE *, const char *, 
...), FILE *fp)
                print_func(fp, "?? flags %s\n", flags2str(n->flags));
 }
 
-/* get_varlist --- list of global variables */
-
-NODE **
-get_varlist()
-{
-       int i, j;
-       NODE **table;
-       NODE *p;
-
-       emalloc(table, NODE **, (var_count + 1) * sizeof(NODE *), 
"get_varlist");
-       update_global_values();
-       for (i = j = 0; i < HASHSIZE; i++)
-               for (p = variables[i]; p != NULL; p = p->hnext)
-                       table[j++] = p;
-       assert(j == var_count);
-
-       /* Shazzam! */
-       qsort(table, j, sizeof(NODE *), sym_comp);
-
-       table[j] = NULL;
-       return table;
-}
-
-/* print_vars --- print names and values of global variables */ 
-
-void
-print_vars(int (*print_func)(FILE *, const char *, ...), FILE *fp)
-{
-       int i;
-       NODE **table;
-       NODE *p;
-
-       table = get_varlist();
-       for (i = 0; (p = table[i]) != NULL; i++) {
-               if (p->hvalue->type == Node_func)
-                       continue;
-               print_func(fp, "%.*s: ", (int) p->hlength, p->hname);
-               if (p->hvalue->type == Node_var_array)
-                       print_func(fp, "array, %ld elements\n", 
p->hvalue->table_size);
-               else if (p->hvalue->type == Node_var_new)
-                       print_func(fp, "untyped variable\n");
-               else if (p->hvalue->type == Node_var)
-                       valinfo(p->hvalue->var_value, print_func, fp);
-       }
-       efree(table);
-}
 
 /* dump_vars --- dump the symbol table */
 
@@ -6766,6 +6526,7 @@ void
 dump_vars(const char *fname)
 {
        FILE *fp;
+       NODE **vars;
 
        if (fname == NULL)
                fp = stderr;
@@ -6775,48 +6536,25 @@ dump_vars(const char *fname)
                fp = stderr;
        }
 
-       print_vars(fprintf, fp);
+       vars = variable_list();
+       print_vars(vars, fprintf, fp);
+       efree(vars);
        if (fp != stderr && fclose(fp) != 0)
                warning(_("%s: close failed (%s)"), fname, strerror(errno));
 }
 
-/* release_all_vars --- free all variable memory */
-
-void
-release_all_vars()
-{
-       int i;
-       NODE *p, *next;
-       
-       for (i = 0; i < HASHSIZE; i++) {
-               for (p = variables[i]; p != NULL; p = next) {
-                       next = p->hnext;
-
-                       if (p->hvalue->type == Node_func)
-                               continue;
-                       else if (p->hvalue->type == Node_var_array)
-                               assoc_clear(p->hvalue);
-                       else if (p->hvalue->type != Node_var_new)
-                               unref(p->hvalue->var_value);
-
-                       efree(p->hname);
-                       freenode(p->hvalue);
-                       freenode(p);
-               }
-       }                                                                    
-}
-
 /* dump_funcs --- print all functions */
 
 void
 dump_funcs()
 {
-       if (func_count <= 0)
-               return;
-
-       (void) foreach_func((int (*)(INSTRUCTION *, void *)) pp_func, TRUE, 
(void *) 0);
+       NODE **funcs;
+       funcs = function_list(TRUE);
+       (void) foreach_func(funcs, (int (*)(INSTRUCTION *, void *)) pp_func, 
(void *) 0);
+       efree(funcs);
 }
 
+
 /* shadow_funcs --- check all functions for parameters that shadow globals */
 
 void
@@ -6824,175 +6562,152 @@ shadow_funcs()
 {
        static int calls = 0;
        int shadow = FALSE;
-
-       if (func_count <= 0)
-               return;
+       NODE **funcs;
 
        if (calls++ != 0)
                fatal(_("shadow_funcs() called twice!"));
 
-       (void) foreach_func((int (*)(INSTRUCTION *, void *)) parms_shadow, 
TRUE, &shadow);
+       funcs = function_list(TRUE);
+       (void) foreach_func(funcs, (int (*)(INSTRUCTION *, void *)) 
parms_shadow, & shadow);
+       efree(funcs);
 
        /* End with fatal if the user requested it.  */
        if (shadow && lintfunc != warning)
                lintwarn(_("there were shadowed variables."));
 }
 
-/*
- * func_install:
- * check if name is already installed;  if so, it had better have Null value,
- * in which case def is added as the value. Otherwise, install name with def
- * as value. 
- *
- * Extra work, build up and save a list of the parameter names in a table
- * and hang it off params->parmlist. This is used to set the `vname' field
- * of each function parameter during a function call. See eval.c.
+
+/* mk_function --- finalize function definition node; remove parameters
+ *     out of the symbol table.
  */
 
-static int
-func_install(INSTRUCTION *func, INSTRUCTION *def)
+static INSTRUCTION *
+mk_function(INSTRUCTION *fi, INSTRUCTION *def)
 {
-       NODE *params;
-       NODE *r, *n, *thisfunc, *hp;
-       char **pnames = NULL;
-       char *fname;
-       int pcount = 0;
-       int i;
-
-       params = func_params;
-
-       /* check for function foo(foo) { ... }.  bleah. */
-       for (n = params->rnode; n != NULL; n = n->rnode) {
-               if (strcmp(n->param, params->param) == 0) {
-                       error_ln(func->source_line,
-                               _("function `%s': can't use function name as 
parameter name"), params->param);
-                       return -1;
-               } else if (is_std_var(n->param)) {
-                       error_ln(func->source_line,
-                               _("function `%s': can't use special variable 
`%s' as a function parameter"),
-                                       params->param, n->param);
-                       return -1;
-               }
-       }
-
-       thisfunc = NULL;        /* turn off warnings */
+       NODE *thisfunc;
 
-       fname = params->param;
-       /* symbol table management */
-       hp = remove_symbol(params->param);  /* remove function name out of 
symbol table */ 
-       if (hp != NULL)
-               freenode(hp);
-       r = lookup(fname);
-       if (r != NULL) {
-               error_ln(func->source_line,
-                        _("function name `%s' previously defined"), fname);
-               return -1;
-       } else if (fname == builtin_func)       /* not a valid function name */
-               goto remove_params;
+       thisfunc = fi->func_body;
+       assert(thisfunc != NULL);
 
        /* add an implicit return at end;
         * also used by 'return' command in debugger
         */
-      
+
        (void) list_append(def, instruction(Op_push_i));
-       def->lasti->memory = Nnull_string;
+       def->lasti->memory = dupnode(Nnull_string);
        (void) list_append(def, instruction(Op_K_return));
 
        if (do_profiling)
                (void) list_prepend(def, instruction(Op_exec_count));
 
-       /* func->opcode is Op_func */
-       (func + 1)->firsti = def->nexti;
-       (func + 1)->lasti = def->lasti;
-       (func + 2)->first_line = func->source_line;
-       (func + 2)->last_line = lastline;
-
-       func->nexti = def->nexti;
+       /* fi->opcode = Op_func */
+       (fi + 1)->firsti = def->nexti;
+       (fi + 1)->lasti = def->lasti;
+       (fi + 2)->first_line = fi->source_line;
+       (fi + 2)->last_line = lastline;
+       fi->nexti = def->nexti;
        bcfree(def);
 
-       (void) list_append(rule_list, func + 1);        /* debugging */
-
-       /* install the function */
-       thisfunc = mk_symbol(Node_func, params);
-       (void) install_symbol(fname, thisfunc);
-       thisfunc->code_ptr = func;
-       func->func_body = thisfunc;
-
-       for (n = params->rnode; n != NULL; n = n->rnode)
-               pcount++;
-
-       if (pcount != 0) {
-               emalloc(pnames, char **, (pcount + 1) * sizeof(char *), 
"func_install");
-               for (i = 0, n = params->rnode; i < pcount; i++, n = n->rnode)
-                       pnames[i] = n->param;
-               pnames[pcount] = NULL;
-       }
-       thisfunc->parmlist = pnames;
+       (void) list_append(rule_list, fi + 1);  /* debugging */
 
        /* update lint table info */
-       func_use(fname, FUNC_DEFINE);
-
-       func_count++;   /* used in profiler / pretty printer */
+       func_use(thisfunc->vname, FUNC_DEFINE);
 
-remove_params:
        /* remove params from symbol table */
-       pop_params(params->rnode);
-       return 0;
+       remove_params(thisfunc);
+       return fi;
 }
 
-/* remove_symbol --- remove a variable from the symbol table */
+/* 
+ * install_function:
+ * install function name in the symbol table.
+ * Extra work, build up and install a list of the parameter names.
+ */
 
-NODE *
-remove_symbol(char *name)
+static int
+install_function(char *fname, INSTRUCTION *fi, INSTRUCTION *plist)
 {
-       NODE *bucket, **save;
-       size_t len;
+       NODE *r, *f;
+       int pcount = 0;
 
-       len = strlen(name);
-       save = &(variables[hash(name, len, (unsigned long) HASHSIZE, NULL)]);
-       for (bucket = *save; bucket != NULL; bucket = bucket->hnext) {
-               if (len == bucket->hlength && STREQN(bucket->hname, name, len)) 
{
-                       var_count--;
-                       *save = bucket->hnext;
-                       return bucket;
-               }
-               save = &(bucket->hnext);
+       r = lookup(fname);
+       if (r != NULL) {
+               error_ln(fi->source_line, _("function name `%s' previously 
defined"), fname);
+               return -1;
        }
-       return NULL;
+
+       if (plist != NULL)
+               pcount = plist->lasti->param_count + 1;
+       f = install_symbol(fname, Node_func);
+       fi->func_body = f;
+       f->param_cnt = pcount;
+       f->code_ptr = fi;
+       f->fparms = NULL; 
+       if (pcount > 0) {
+               char **pnames;
+               pnames = check_params(fname, pcount, plist);    /* frees plist 
*/
+               f->fparms = make_params(pnames, pcount);
+               efree(pnames);
+               install_params(f);
+       }
+       return 0;
 }
 
-/* pop_params --- remove list of function parameters from symbol table */
 
-/*
- * pop parameters out of the symbol table. do this in reverse order to
- * avoid reading freed memory if there were duplicated parameters.
+/* check_params --- build a list of function parameter names after
+ *     making sure that the names are valid and there are no duplicates.
  */
-static void
-pop_params(NODE *params)
+
+static char **
+check_params(char *fname, int pcount, INSTRUCTION *list)
 {
-       NODE *hp;
-       if (params == NULL)
-               return;
-       pop_params(params->rnode);
-       hp = remove_symbol(params->param);
-       if (hp != NULL)
-               freenode(hp);
-}
+       INSTRUCTION *p, *np;
+       int i, j;
+       char *name;
+       char **pnames;
 
-/* make_param --- make NAME into a function parameter */
+       assert(pcount > 0);
 
-static NODE *
-make_param(char *name)
-{
-       NODE *r;
+       emalloc(pnames, char **, pcount * sizeof(char *), "check_params");
 
-       getnode(r);
-       r->type = Node_param_list;
-       r->rnode = NULL;
-       r->param_cnt = param_counter++;
-       return (install_symbol(name, r));
+       for (i = 0, p = list->nexti; p != NULL; i++, p = np) {
+               np = p->nexti;
+               name = p->lextok;
+               p->lextok = NULL;
+
+               if (strcmp(name, fname) == 0) {
+                       /* check for function foo(foo) { ... }.  bleah. */
+                       error_ln(p->source_line,
+                               _("function `%s': can't use function name as 
parameter name"), fname);
+               } else if (is_std_var(name)) {
+                       error_ln(p->source_line,
+                               _("function `%s': can't use special variable 
`%s' as a function parameter"),
+                                       fname, name);
+               }
+
+               /* check for duplicate parameters */
+               for (j = 0; j < i; j++) {
+                       if (strcmp(name, pnames[j]) == 0) {
+                               error_ln(p->source_line,
+                                       _("function `%s': parameter #%d, `%s', 
duplicates parameter #%d"),
+                                       fname, i + 1, name, j + 1);
+                       }
+               }
+
+               pnames[i] = name;
+               bcfree(p);
+       }
+       bcfree(list);
+
+       return pnames; 
 }
 
+
+#ifdef HASHSIZE
+undef HASHSIZE
+#endif
+#define HASHSIZE 1021
+ 
 static struct fdesc {
        char *name;
        short used;
@@ -7100,69 +6815,6 @@ param_sanity(INSTRUCTION *arglist)
        }
 }
 
-/* foreach_func --- execute given function for each awk function in symbol 
table. */
-
-int
-foreach_func(int (*pfunc)(INSTRUCTION *, void *), int sort, void *data)
-{
-       int i, j;
-       NODE *p;
-       int ret = 0;
-
-       if (sort) {
-               NODE **tab;
-
-               /*
-                * Walk through symbol table counting functions.
-                * Could be more than func_count if there are
-                * extension functions.
-                */
-               for (i = j = 0; i < HASHSIZE; i++) {
-                       for (p = variables[i]; p != NULL; p = p->hnext) {
-                               if (p->hvalue->type == Node_func) {
-                                       j++;
-                               }
-                       }
-               }
-
-               if (j == 0)
-                       return 0;
-
-               emalloc(tab, NODE **, j * sizeof(NODE *), "foreach_func");
-
-               /* now walk again, copying info */
-               for (i = j = 0; i < HASHSIZE; i++) {
-                       for (p = variables[i]; p != NULL; p = p->hnext) {
-                               if (p->hvalue->type == Node_func) {
-                                       tab[j] = p;
-                                       j++;
-                               }
-                       }
-               }
-
-               /* Shazzam! */
-               qsort(tab, j, sizeof(NODE *), sym_comp);
-
-               for (i = 0; i < j; i++) {
-                       if ((ret = pfunc(tab[i]->hvalue->code_ptr, data)) != 0)
-                               break;
-               }
-
-               efree(tab);
-               return ret;
-       }
-
-       /* unsorted */
-       for (i = 0; i < HASHSIZE; i++) {
-               for (p = variables[i]; p != NULL; p = p->hnext) {
-                       if (p->hvalue->type == Node_func
-                                       && (ret = pfunc(p->hvalue->code_ptr, 
data)) != 0)
-                               return ret;
-               }
-       }
-       return 0;
-}
-
 /* deferred variables --- those that are only defined if needed. */
 
 /*
@@ -7197,17 +6849,14 @@ register_deferred_variable(const char *name, NODE 
*(*load_func)(void))
 /* variable --- make sure NAME is in the symbol table */
 
 NODE *
-variable(char *name, NODETYPE type)
+variable(int location, char *name, NODETYPE type)
 {
        NODE *r;
 
        if ((r = lookup(name)) != NULL) {
-               if (r->type == Node_func) {
-                       error(_("function `%s' called with space between name 
and `(',\nor used as a variable or an array"),
+               if (r->type == Node_func || r->type == Node_ext_func )
+                       error_ln(location, _("function `%s' called with space 
between name and `(',\nor used as a variable or an array"),
                                r->vname);
-                       errcount++;
-                       r->type = Node_var_new; /* continue parsing instead of 
exiting */
-               }
        } else {
                /* not found */
                struct deferred_variable *dv;
@@ -7217,11 +6866,7 @@ variable(char *name, NODETYPE type)
                        /*
                         * This is the only case in which we may not free the 
string.
                         */
-                               if (type == Node_var)
-                                       r = mk_symbol(type, Nnull_string);
-                               else
-                                       r = mk_symbol(type, (NODE *) NULL);
-                               return install_symbol(name, r);
+                               return install_symbol(name, type);
                        }
                        if (STREQ(name, dv->name)) {
                                r = (*dv->load_func)();
@@ -7328,9 +6973,6 @@ make_assignable(INSTRUCTION *ip)
 {
        switch (ip->opcode) {
        case Op_push:
-               if (ip->memory->type == Node_param_list
-                               && (ip->memory->flags & FUNC) != 0)
-                       return NULL;
                ip->opcode = Op_push_lhs;
                return ip;
        case Op_field_spec:
@@ -7345,14 +6987,6 @@ make_assignable(INSTRUCTION *ip)
        return NULL;
 }
 
-/* stopme --- for debugging */
-
-NODE *
-stopme(int nargs ATTRIBUTE_UNUSED)
-{
-       return (NODE *) 0;
-}
-
 /* dumpintlstr --- write out an initial .po file entry for the string */
 
 static void
@@ -7402,27 +7036,6 @@ dumpintlstr2(const char *str1, size_t len1, const char 
*str2, size_t len2)
        fflush(stdout);
 }
 
-/* isarray --- can this type be subscripted? */
-
-static int
-isarray(NODE *n)
-{
-       switch (n->type) {
-       case Node_var_new:
-       case Node_var_array:
-               return TRUE;
-       case Node_param_list:
-               return (n->flags & FUNC) == 0;
-       case Node_array_ref:
-               cant_happen();
-               break;
-       default:
-               break;  /* keeps gcc -Wall happy */
-       }
-
-       return FALSE;
-}
-
 /* mk_binary --- instructions for binary operators */
 
 static INSTRUCTION *
@@ -7483,11 +7096,7 @@ mk_binary(INSTRUCTION *s1, INSTRUCTION *s2, INSTRUCTION 
*op)
                        }
 
                        op->opcode = Op_push_i;
-                       op->memory = mk_number(res, (PERM|NUMCUR|NUMBER));
-                       n1->flags &= ~PERM;
-                       n1->flags |= MALLOC;
-                       n2->flags &= ~PERM;
-                       n2->flags |= MALLOC;
+                       op->memory = make_number(res);
                        unref(n1);
                        unref(n2);
                        bcfree(ip1);
@@ -7819,9 +7428,7 @@ mk_assignment(INSTRUCTION *lhs, INSTRUCTION *rhs, 
INSTRUCTION *op)
 static INSTRUCTION *
 optimize_assignment(INSTRUCTION *exp)
 {
-       INSTRUCTION *i1;
-       INSTRUCTION *i2;
-       INSTRUCTION *i3;
+       INSTRUCTION *i1, *i2, *i3;
 
        /*
         * Optimize assignment statements array[subs] = x; var = x; $n = x;
@@ -7942,13 +7549,26 @@ optimize_assignment(INSTRUCTION *exp)
 
                case Op_push_lhs:
                        if (i2->nexti == i1
-                                               && i1->opcode == Op_assign
+                                       && i1->opcode == Op_assign
                        ) {
                                /* var = .. */
                                i2->opcode = Op_store_var;
                                i2->nexti = NULL;
                                bcfree(i1);          /* Op_assign */
                                exp->lasti = i2;     /* update Op_list */
+
+                               i3 = exp->nexti;
+                               if (i3->opcode == Op_push_i
+                                       && (i3->memory->flags & INTLSTR) == 0
+                                       && i3->nexti == i2
+                               ) {
+                                       /* constant initializer */ 
+                                       i2->initval = i3->memory;
+                                       bcfree(i3);
+                                       exp->nexti = i2;
+                               } else
+                                       i2->initval = NULL;
+
                                return exp;
                        }
                        break;
@@ -8249,320 +7869,6 @@ fix_break_continue(INSTRUCTION *list, INSTRUCTION 
*b_target, INSTRUCTION *c_targ
        }
 }
 
-
-/* append_symbol --- append symbol to the list of symbols
- *                  installed in the symbol table.
- */
-
-void
-append_symbol(char *name)
-{
-       NODE *hp;
-
-       /* N.B.: func_install removes func name and reinstalls it;
-        * and we get two entries for it here!. destroy_symbol()
-        * will find and destroy the Node_func which is what we want.
-        */
-
-       getnode(hp);
-       hp->hname = name;       /* shallow copy */
-       hp->hnext = symbol_list->hnext;
-       symbol_list->hnext = hp;
-}
-
-/* release_symbol --- free symbol list and optionally remove symbol from 
symbol table */
-
-void
-release_symbols(NODE *symlist, int keep_globals)
-{
-       NODE *hp, *n;
-
-       for (hp = symlist->hnext; hp != NULL; hp = n) {
-               if (! keep_globals) {
-                       /* destroys globals, function, and params
-                        * if still in symbol table and not removed by 
func_install
-                        * due to syntax error.
-                        */
-                       destroy_symbol(hp->hname);
-               }
-               n = hp->hnext;
-               freenode(hp);
-       }
-       symlist->hnext = NULL;
-}
-
-/* destroy_symbol --- remove a symbol from symbol table
-*                     and free all associated memory.
-*/
-
-void
-destroy_symbol(char *name)
-{
-       NODE *symbol, *hp;
-
-       symbol = lookup(name);
-       if (symbol == NULL)
-               return;
-
-       if (symbol->type == Node_func) {
-               char **varnames;
-               NODE *func, *n;
-                               
-               func = symbol;
-               varnames = func->parmlist;
-               if (varnames != NULL)
-                       efree(varnames);
-
-               /* function parameters of type Node_param_list */               
                
-               for (n = func->lnode->rnode; n != NULL; ) {
-                       NODE *np;
-                       np = n->rnode;
-                       efree(n->param);
-                       freenode(n);
-                       n = np;
-               }               
-               freenode(func->lnode);
-               func_count--;
-
-       } else if (symbol->type == Node_var_array)
-               assoc_clear(symbol);
-       else if (symbol->type == Node_var) 
-               unref(symbol->var_value);
-
-       /* remove from symbol table */
-       hp = remove_symbol(name);
-       efree(hp->hname);
-       freenode(hp->hvalue);
-       freenode(hp);
-}
-
-#define pool_size      d.dl
-#define freei          x.xi
-static INSTRUCTION *pool_list;
-static AWK_CONTEXT *curr_ctxt = NULL;
-
-/* new_context --- create a new execution context. */
-
-AWK_CONTEXT *
-new_context()
-{
-       AWK_CONTEXT *ctxt;
-
-       emalloc(ctxt, AWK_CONTEXT *, sizeof(AWK_CONTEXT), "new_context");
-       memset(ctxt, 0, sizeof(AWK_CONTEXT));
-       ctxt->srcfiles.next = ctxt->srcfiles.prev = &ctxt->srcfiles;
-       ctxt->rule_list.opcode = Op_list;
-       ctxt->rule_list.lasti = &ctxt->rule_list;
-       return ctxt;
-}
-
-/* set_context --- change current execution context. */
-
-static void
-set_context(AWK_CONTEXT *ctxt)
-{
-       pool_list = &ctxt->pools;
-       symbol_list = &ctxt->symbols;
-       srcfiles = &ctxt->srcfiles;
-       rule_list = &ctxt->rule_list;
-       install_func = ctxt->install_func;
-       curr_ctxt = ctxt;
-}
-
-/*
- * push_context:
- *
- * Switch to the given context after saving the current one. The set
- * of active execution contexts forms a stack; the global or main context
- * is at the bottom of the stack.
- */
-
-void
-push_context(AWK_CONTEXT *ctxt)
-{
-       ctxt->prev = curr_ctxt;
-       /* save current source and sourceline */
-       if (curr_ctxt != NULL) {
-               curr_ctxt->sourceline = sourceline;
-               curr_ctxt->source = source;
-       }
-       sourceline = 0;
-       source = NULL;
-       set_context(ctxt);
-}
-
-/* pop_context --- switch to previous execution context. */ 
-
-void
-pop_context()
-{
-       AWK_CONTEXT *ctxt;
-
-       assert(curr_ctxt != NULL);
-       ctxt = curr_ctxt->prev;
-       /* restore source and sourceline */
-       sourceline = ctxt->sourceline;
-       source = ctxt->source;
-       set_context(ctxt);
-}
-
-/* in_main_context --- are we in the main context ? */
-
-int
-in_main_context()
-{
-       assert(curr_ctxt != NULL);
-       return (curr_ctxt->prev == NULL);
-}
-
-/* free_context --- free context structure and related data. */ 
-
-void
-free_context(AWK_CONTEXT *ctxt, int keep_globals)
-{
-       SRCFILE *s, *sn;
-
-       if (ctxt == NULL)
-               return;
-
-       assert(curr_ctxt != ctxt);
-
-       /* free all code including function codes */
-       free_bcpool(&ctxt->pools);
-       /* free symbols */
-       release_symbols(&ctxt->symbols, keep_globals);
-       /* free srcfiles */
-       for (s = &ctxt->srcfiles; s != &ctxt->srcfiles; s = sn) {
-               sn = s->next;
-               if (s->stype != SRC_CMDLINE && s->stype != SRC_STDIN)
-                       efree(s->fullpath);
-               efree(s->src);
-               efree(s);
-       }
-       efree(ctxt);
-}
-
-/* free_bc_internal --- free internal memory of an instruction. */ 
-
-static void
-free_bc_internal(INSTRUCTION *cp)
-{
-       NODE *m;
-
-       switch(cp->opcode) {
-       case Op_func_call:
-               if (cp->func_name != NULL
-                               && cp->func_name != builtin_func
-               )
-                       efree(cp->func_name);
-               break;
-       case Op_push_re:
-       case Op_match_rec:
-       case Op_match:
-       case Op_nomatch:
-               m = cp->memory;
-               if (m->re_reg != NULL)
-                       refree(m->re_reg);
-               if (m->re_exp != NULL)
-                       unref(m->re_exp);
-               if (m->re_text != NULL)
-                       unref(m->re_text);
-               freenode(m);
-               break;                  
-       case Op_token:  /* token lost during error recovery in yyparse */
-               if (cp->lextok != NULL)
-                       efree(cp->lextok);
-               break;
-       case Op_illegal:
-               cant_happen();
-       default:
-               break;  
-       }
-}
-
-
-/* INSTR_CHUNK must be > largest code size (3) */
-#define INSTR_CHUNK 127
-
-/* bcfree --- deallocate instruction */
-
-void
-bcfree(INSTRUCTION *cp)
-{
-       cp->opcode = 0;
-       cp->nexti = pool_list->freei;
-       pool_list->freei = cp;
-}      
-
-/* bcalloc --- allocate a new instruction */
-
-INSTRUCTION *
-bcalloc(OPCODE op, int size, int srcline)
-{
-       INSTRUCTION *cp;
-
-       if (size > 1) {
-               /* wide instructions Op_rule, Op_func_call .. */
-               emalloc(cp, INSTRUCTION *, (size + 1) * sizeof(INSTRUCTION), 
"bcalloc");
-               cp->pool_size = size;
-               cp->nexti = pool_list->nexti;
-               pool_list->nexti = cp++;
-       } else {
-               INSTRUCTION *pool;
-
-               pool = pool_list->freei;
-               if (pool == NULL) {
-                       INSTRUCTION *last;
-                       emalloc(cp, INSTRUCTION *, (INSTR_CHUNK + 1) * 
sizeof(INSTRUCTION), "bcalloc");
-
-                       cp->pool_size = INSTR_CHUNK;
-                       cp->nexti = pool_list->nexti;
-                       pool_list->nexti = cp;
-                       pool = ++cp;
-                       last = &pool[INSTR_CHUNK - 1];
-                       for (; cp <= last; cp++) {
-                               cp->opcode = 0;
-                               cp->nexti = cp + 1;
-                       }
-                       --cp;
-                       cp->nexti = NULL;
-               }
-               cp = pool;
-               pool_list->freei = cp->nexti;
-       }
-
-       memset(cp, 0, size * sizeof(INSTRUCTION));
-       cp->opcode = op;
-       cp->source_line = srcline;
-       return cp;
-}
-
-/* free_bcpool --- free list of instruction memory pools */
-
-static void
-free_bcpool(INSTRUCTION *pl)
-{
-       INSTRUCTION *pool, *tmp;
-
-       for (pool = pl->nexti; pool != NULL; pool = tmp) {
-               INSTRUCTION *cp, *last;
-               long psiz;
-               psiz = pool->pool_size;
-               if (psiz == INSTR_CHUNK)
-                       last = pool + psiz;
-               else
-                       last = pool + 1;
-               for (cp = pool + 1; cp <= last ; cp++) {
-                       if (cp->opcode != 0)
-                               free_bc_internal(cp);
-               }
-               tmp = pool->nexti;
-               efree(pool);
-       }
-       memset(pl, 0, sizeof(INSTRUCTION));
-}
-
-
 static inline INSTRUCTION *
 list_create(INSTRUCTION *x)
 {
diff --git a/awkgram.y b/awkgram.y
index 6b28b52..36bf3f9 100644
--- a/awkgram.y
+++ b/awkgram.y
@@ -42,19 +42,15 @@ static char *get_src_buf(void);
 static int yylex(void);
 int    yyparse(void); 
 static INSTRUCTION *snode(INSTRUCTION *subn, INSTRUCTION *op);
-static int func_install(INSTRUCTION *fp, INSTRUCTION *def);
-static void pop_params(NODE *params);
-static NODE *make_param(char *pname);
+static char **check_params(char *fname, int pcount, INSTRUCTION *list);
+static int install_function(char *fname, INSTRUCTION *fi, INSTRUCTION *plist);
 static NODE *mk_rexp(INSTRUCTION *exp);
-static void append_param(char *pname);
-static int dup_parms(INSTRUCTION *fp, NODE *func);
 static void param_sanity(INSTRUCTION *arglist);
 static int parms_shadow(INSTRUCTION *pc, int *shadow);
 static int isnoeffect(OPCODE type);
 static INSTRUCTION *make_assignable(INSTRUCTION *ip);
 static void dumpintlstr(const char *str, size_t len);
 static void dumpintlstr2(const char *str1, size_t len1, const char *str2, 
size_t len2);
-static int isarray(NODE *n);
 static int include_source(INSTRUCTION *file);
 static void next_sourcefile(void);
 static char *tokexpand(void);
@@ -63,6 +59,7 @@ static char *tokexpand(void);
 
 static INSTRUCTION *mk_program(void);
 static INSTRUCTION *append_rule(INSTRUCTION *pattern, INSTRUCTION *action);
+static INSTRUCTION *mk_function(INSTRUCTION *fi, INSTRUCTION *def);
 static INSTRUCTION *mk_condition(INSTRUCTION *cond, INSTRUCTION *ifp, 
INSTRUCTION *true_branch,
                INSTRUCTION *elsep,     INSTRUCTION *false_branch);
 static INSTRUCTION *mk_expression_list(INSTRUCTION *list, INSTRUCTION *s1);
@@ -81,13 +78,10 @@ static void add_lint(INSTRUCTION *list, LINTTYPE linttype);
 enum defref { FUNC_DEFINE, FUNC_USE };
 static void func_use(const char *name, enum defref how);
 static void check_funcs(void);
-static void free_bcpool(INSTRUCTION *pl);
 
 static ssize_t read_one_line(int fd, void *buffer, size_t count);
 static int one_line_close(int fd);
 
-static void (*install_func)(char *) = NULL;
-
 static int want_source = FALSE;
 static int want_regexp;                /* lexical scanning kludge */
 static int can_return;         /* parsing kludge */
@@ -125,22 +119,11 @@ static int continue_allowed;      /* kludge for continue 
*/
 #define END_SRC        -2000
 
 #define YYDEBUG_LEXER_TEXT (lexeme)
-static int param_counter;
-static NODE *func_params;      /* list of parameters for the current function 
*/
 static char *tokstart = NULL;
 static char *tok = NULL;
 static char *tokend;
 static int errcount = 0;
 
-static NODE *symbol_list;
-extern void destroy_symbol(char *name); 
-
-static long func_count;                /* total number of functions */
-
-#define HASHSIZE       1021    /* this constant only used here */
-NODE *variables[HASHSIZE];
-static int var_count;          /* total number of global variables */
-
 extern char *source;
 extern int sourceline;
 extern SRCFILE *srcfiles;
@@ -162,16 +145,6 @@ static inline INSTRUCTION *list_prepend(INSTRUCTION *l, 
INSTRUCTION *x);
 static inline INSTRUCTION *list_merge(INSTRUCTION *l1, INSTRUCTION *l2);
 
 extern double fmod(double x, double y);
-/*
- * This string cannot occur as a real awk identifier.
- * Use it as a special token to make function parsing
- * uniform, but if it's seen, don't install the function.
- * e.g.
- *     function split(x) { return x }
- *     function x(a) { return a }
- * should only produce one error message, and not core dump.
- */
-static char builtin_func[] = "@builtin";
 
 #define YYSTYPE INSTRUCTION *
 %}
@@ -257,9 +230,7 @@ rule
        | function_prologue action
          {
                can_return = FALSE;
-               if ($1 && func_install($1, $2) < 0)
-                       YYABORT;
-               func_params = NULL;
+               (void) mk_function($1, $2);
                yyerrok;
          }
        | '@' LEX_INCLUDE source statement_term
@@ -369,13 +340,8 @@ func_name
        | lex_builtin
          {
                yyerror(_("`%s' is a built-in function, it cannot be 
redefined"),
-                       tokstart);
-               $1->opcode = Op_symbol; /* Op_symbol instead of Op_token so that
-                                        * free_bc_internal does not try to 
free it
-                                        */
-               $1->lextok = builtin_func;
-               $$ = $1;
-               /* yyerrok; */
+                                       tokstart);
+               YYABORT;
          }
        | '@' LEX_EVAL
          { $$ = $2; }
@@ -387,28 +353,17 @@ lex_builtin
        ;
                
 function_prologue
-       : LEX_FUNCTION
+       : LEX_FUNCTION func_name '(' opt_param_list r_paren opt_nls
          {
-               param_counter = 0;
-               func_params = NULL;
+               $1->source_file = source;
+               if (install_function($2->lextok, $1, $4) < 0)
+                       YYABORT;
+               $2->lextok = NULL;
+               bcfree($2);
+               /* $4 already free'd in install_function */
+               $$ = $1;
+               can_return = TRUE;
          }
-               func_name '(' opt_param_list r_paren opt_nls
-               {
-                       NODE *t;
-
-                       $1->source_file = source;
-                       t = make_param($3->lextok);
-                       $3->lextok = NULL;
-                       bcfree($3);
-                       t->flags |= FUNC;
-                       t->rnode = func_params;
-                       func_params = t;
-                       $$ = $1;
-                       can_return = TRUE;
-                       /* check for duplicate parameter names */
-                       if (dup_parms($1, t))
-                               errcount++;
-               }
        ;
 
 regexp
@@ -425,6 +380,7 @@ regexp
                  size_t len;
 
                  re = $3->lextok;
+                 $3->lextok = NULL;
                  len = strlen(re);
                  if (do_lint) {
                        if (len == 0)
@@ -436,7 +392,7 @@ regexp
                                        _("regexp constant `/%s/' looks like a 
C comment, but is not"), re);
                  }
 
-                 exp = make_str_node(re, len, ALREADY_MALLOCED);
+                 exp = make_str_node(re, len);
                  n = make_regnode(Node_regex, exp);
                  if (n == NULL) {
                        unref(exp);
@@ -732,7 +688,7 @@ regular_loop:
 
                        tbreak = instruction(Op_arrayfor_final);
                        $4->opcode = Op_arrayfor_incr;
-                       $4->array_var = variable(var_name, Node_var);
+                       $4->array_var = variable($3->source_line, var_name, 
Node_var);
                        $4->target_jmp = tbreak;
                        tcont = $4;
                        $3->opcode = Op_arrayfor_init;
@@ -857,7 +813,7 @@ non_compound_stmt
                if ($2 == NULL) {
                        $$ = list_create($1);
                        (void) list_prepend($$, instruction(Op_push_i));
-                       $$->nexti->memory = Nnull_string;
+                       $$->nexti->memory = dupnode(Nnull_string);
                } else
                        $$ = list_append($2, $1);
          }
@@ -869,7 +825,7 @@ non_compound_stmt
                if ($3 == NULL) {
                        $$ = list_create($1);
                        (void) list_prepend($$, instruction(Op_push_i));
-                       $$->nexti->memory = Nnull_string;
+                       $$->nexti->memory = dupnode(Nnull_string);
                } else
                        $$ = list_append($3, $1);
          }
@@ -894,13 +850,13 @@ simple_stmt
                 */
 
                if ($1->opcode == Op_K_print &&
-                               ($3 == NULL
-                                       || ($3->lasti->opcode == Op_field_spec
-                                               && $3->nexti->nexti->nexti == 
$3->lasti
-                                               && $3->nexti->nexti->opcode == 
Op_push_i
-                                               && 
$3->nexti->nexti->memory->type == Node_val
-                                               && 
$3->nexti->nexti->memory->numbr == 0.0)
-                               )
+                       ($3 == NULL
+                               || ($3->lasti->opcode == Op_field_spec
+                                       && $3->nexti->nexti->nexti == $3->lasti
+                                       && $3->nexti->nexti->opcode == Op_push_i
+                                       && $3->nexti->nexti->memory->type == 
Node_val
+                                       && $3->nexti->nexti->memory->numbr == 
0.0)
+                       )
                ) {
                        static short warned = FALSE;
                        /*   -----------------
@@ -914,8 +870,6 @@ simple_stmt
 
                        if ($3 != NULL) {
                                bcfree($3->lasti);                              
/* Op_field_spec */
-                               $3->nexti->nexti->memory->flags &= ~PERM;
-                               $3->nexti->nexti->memory->flags |= MALLOC;      
                
                                unref($3->nexti->nexti->memory);        /* 
Node_val */
                                bcfree($3->nexti->nexti);               /* 
Op_push_i */
                                bcfree($3->nexti);                              
/* Op_list */
@@ -986,7 +940,7 @@ simple_stmt
                char *arr = $2->lextok;
 
                $2->opcode = Op_push_array;
-               $2->memory = variable(arr, Node_var_new);
+               $2->memory = variable($2->source_line, arr, Node_var_new);
 
                if ($4 == NULL) {
                        static short warned = FALSE;
@@ -1024,7 +978,7 @@ simple_stmt
                        error_ln($1->source_line,
                                _("`delete array' is a gawk extension"));
                }
-               $3->memory = variable(arr, Node_var_new);
+               $3->memory = variable($3->source_line, arr, Node_var_new);
                $3->opcode = Op_push_array;
                $1->expr_count = 0;
                $$ = list_append(list_create($3), $1);
@@ -1173,29 +1127,29 @@ input_redir
 
 opt_param_list
        : /* empty */
+         { $$ = NULL; }
        | param_list
+         { $$ = $1 ; }
        ;
 
 param_list
        : NAME
          {
-               append_param($1->lextok);
-               $1->lextok = NULL;
-               bcfree($1);
+               $1->param_count = 0;
+               $$ = list_create($1);
          }
        | param_list comma NAME
          {
-               append_param($3->lextok);
-               $3->lextok = NULL;
-               bcfree($3);
+               $3->param_count =  $1->lasti->param_count + 1;
+               $$ = list_append($1, $3);
                yyerrok;
          }
        | error
-         { /* func_params = NULL; */ }
+         { $$ = NULL; }
        | param_list error
-         { /* func_params = NULL; */ }
+         { $$ = $1; }
        | param_list comma error
-         { /* func_params = NULL; */ }
+         { $$ = $1; }
        ;
 
 /* optional expression, as in for loop */
@@ -1263,7 +1217,7 @@ exp
        | exp LEX_IN simple_variable
          {
                if (do_lint_old)
-                 warning_ln($2->source_line,
+                       warning_ln($2->source_line,
                                _("old awk does not support the keyword `in' 
except after `for'"));
                $3->nexti->opcode = Op_push_array;
                $2->opcode = Op_in_array;
@@ -1326,32 +1280,29 @@ common_exp
                        $1->lasti->opcode = Op_no_op;
                } else {
                        is_simple_var = ($1->nexti->opcode == Op_push
-                                               && $1->lasti == $1->nexti); /* 
first exp. is a simple
-                                                                            * 
variable?; kludge for use
-                                                                            * 
in Op_assign_concat.
-                                                                            */
+                                       && $1->lasti == $1->nexti); /* first 
exp. is a simple
+                                                                    * 
variable?; kludge for use
+                                                                    * in 
Op_assign_concat.
+                                                                    */
                }
 
                if (do_optimize > 1
-                               && $1->nexti == $1->lasti && $1->nexti->opcode 
== Op_push_i
-                               && $2->nexti == $2->lasti && $2->nexti->opcode 
== Op_push_i
+                       && $1->nexti == $1->lasti && $1->nexti->opcode == 
Op_push_i
+                       && $2->nexti == $2->lasti && $2->nexti->opcode == 
Op_push_i
                ) {
                        NODE *n1 = $1->nexti->memory;
                        NODE *n2 = $2->nexti->memory;
                        size_t nlen;
 
-                       (void) force_string(n1);
-                       (void) force_string(n2);
+                       n1 = force_string(n1);
+                       n2 = force_string(n2);
                        nlen = n1->stlen + n2->stlen;
                        erealloc(n1->stptr, char *, nlen + 2, "constant fold");
                        memcpy(n1->stptr + n1->stlen, n2->stptr, n2->stlen);
                        n1->stlen = nlen;
                        n1->stptr[nlen] = '\0';
-                       n1->flags &= ~(NUMCUR|NUMBER);
+                       n1->flags &= ~(NUMCUR|NUMBER|NUMINT);
                        n1->flags |= (STRING|STRCUR);
-
-                       n2->flags &= ~PERM;
-                       n2->flags |= MALLOC;
                        unref(n2);
                        bcfree($2->nexti);
                        bcfree($2);
@@ -1469,12 +1420,12 @@ non_post_simp_exp
                if ($2->opcode == Op_match_rec) {
                        $2->opcode = Op_nomatch;
                        $1->opcode = Op_push_i;
-                       $1->memory = mk_number(0.0, (PERM|NUMCUR|NUMBER));      
+                       $1->memory = make_number(0.0);  
                        $$ = list_append(list_append(list_create($1),
-                                                               
instruction(Op_field_spec)), $2);
+                                               instruction(Op_field_spec)), 
$2);
                } else {
                        if (do_optimize > 1 && $2->nexti == $2->lasti
-                                                       && $2->nexti->opcode == 
Op_push_i
+                                       && $2->nexti->opcode == Op_push_i
                        ) {
                                NODE *n = $2->nexti->memory;
                                if ((n->flags & (STRCUR|STRING)) != 0) {
@@ -1545,7 +1496,8 @@ non_post_simp_exp
        | '-' simp_exp    %prec UNARY
          {
                if ($2->lasti->opcode == Op_push_i
-                               && ($2->lasti->memory->flags & (STRCUR|STRING)) 
== 0) {
+                       && ($2->lasti->memory->flags & (STRCUR|STRING)) == 0
+               ) {
                        $2->lasti->memory->numbr = 
-(force_number($2->lasti->memory));
                        $$ = $2;
                        bcfree($1);
@@ -1561,7 +1513,7 @@ non_post_simp_exp
             * POSIX semantics: force a conversion to numeric type
             */
                $1->opcode = Op_plus_i;
-               $1->memory = mk_number((AWKNUM) 0.0, (PERM|NUMCUR|NUMBER));
+               $1->memory = make_number(0.0);
                $$ = list_append($2, $1);
          }
        ;
@@ -1593,7 +1545,7 @@ func_call
                name = estrdup(f->func_name, strlen(f->func_name));
                if (is_std_var(name))
                        yyerror(_("can not use special variable `%s' for 
indirect function call"), name);
-               indirect_var = variable(name, Node_var_new);
+               indirect_var = variable(f->source_line, name, Node_var_new);
                t = instruction(Op_push);
                t->memory = indirect_var;
 
@@ -1673,7 +1625,7 @@ bracketed_exp_list
                                _("invalid subscript expression"));
                        /* install Null string as subscript. */
                        t = list_create(instruction(Op_push_i));
-                       t->nexti->memory = Nnull_string;
+                       t->nexti->memory = dupnode(Nnull_string);
                        $3->sub_count = 1;                      
                } else
                        $3->sub_count = count_expressions(&t, FALSE);
@@ -1701,17 +1653,13 @@ simple_variable
                char *var_name = $1->lextok;
 
                $1->opcode = Op_push;
-               $1->memory = variable(var_name, Node_var_new);
+               $1->memory = variable($1->source_line, var_name, Node_var_new);
                $$ = list_create($1);
          }
        | NAME subscript_list
          {
-               NODE *n;
-
                char *arr = $1->lextok;
-               if ((n = lookup(arr)) != NULL && ! isarray(n))
-                       yyerror(_("use of non-array as array"));
-               $1->memory = variable(arr, Node_var_new);
+               $1->memory = variable($1->source_line, arr, Node_var_new);
                $1->opcode = Op_push_array;
                $$ = list_prepend($2, $1);
          }
@@ -1722,8 +1670,8 @@ variable
          {
                INSTRUCTION *ip = $1->nexti;
                if (ip->opcode == Op_push
-                               && ip->memory->type == Node_var
-                               && ip->memory->var_update
+                       && ip->memory->type == Node_var
+                       && ip->memory->var_update
                ) {
                        $$ = list_prepend($1, instruction(Op_var_update));
                        $$->nexti->memory = ip->memory;
@@ -1735,7 +1683,7 @@ variable
          {
                $$ = list_append($2, $1);
                if ($3 != NULL)
-                 mk_assignment($2, NULL, $3);
+                       mk_assignment($2, NULL, $3);
          }
        ;
 
@@ -1825,9 +1773,12 @@ static const struct token tokentab[] = {
 {"END",                Op_rule,         LEX_END,       0,              0},
 {"ENDFILE",            Op_rule,         LEX_ENDFILE,   GAWKX,          0},
 #ifdef ARRAYDEBUG
-{"adump",      Op_builtin,    LEX_BUILTIN,     GAWKX|A(1),     do_adump},
+{"adump",      Op_builtin,    LEX_BUILTIN,     GAWKX|A(1)|A(2),        
do_adump},
 #endif
 {"and",                Op_builtin,    LEX_BUILTIN,     GAWKX|A(2),     do_and},
+#ifdef ARRAYDEBUG
+{"aoption",    Op_builtin,    LEX_BUILTIN,     GAWKX|A(2),     do_aoption},
+#endif
 {"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),   do_atan2},
@@ -1880,9 +1831,6 @@ static const struct token tokentab[] = {
 {"sprintf",    Op_builtin,      LEX_BUILTIN,   0,              do_sprintf},
 {"sqrt",       Op_builtin,      LEX_BUILTIN,   A(1),           do_sqrt},
 {"srand",      Op_builtin,      LEX_BUILTIN,   NOT_OLD|A(0)|A(1), do_srand},
-#if defined(GAWKDEBUG) || defined(ARRAYDEBUG) /* || ... */
-{"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},
 {"strtonum",   Op_builtin,    LEX_BUILTIN,     GAWKX|A(1),     do_strtonum},
 {"sub",                Op_builtin,      LEX_BUILTIN,   NOT_OLD|A(2)|A(3), 
do_sub},
@@ -2405,6 +2353,7 @@ next_sourcefile()
         *
         * assert(lexeof == TRUE);
         */
+
        lexeof = FALSE;
        eof_warned = FALSE;
        sourcefile->srclines = sourceline;      /* total no of lines in current 
file */
@@ -2793,8 +2742,10 @@ yylex(void)
        int mid;
        static int did_newline = FALSE;
        char *tokkey;
+       size_t toklen;
        int inhex = FALSE;
        int intlstr = FALSE;
+       AWKNUM d;
 
 #define GET_INSTRUCTION(op) bcalloc(op, 1, sourceline)
 
@@ -3226,16 +3177,16 @@ retry:
                        tokadd(c);
                }
                yylval = GET_INSTRUCTION(Op_token);
+               toklen = tok - tokstart;
                if (want_source) {
-                       yylval->lextok = estrdup(tokstart, tok - tokstart);
+                       yylval->lextok = estrdup(tokstart, toklen);
                        return lasttok = FILENAME;
                }
                
                yylval->opcode = Op_push_i;
-               yylval->memory = make_str_node(tokstart,
-                                               tok - tokstart, esc_seen ? SCAN 
: 0);
-               yylval->memory->flags &= ~MALLOC;
-               yylval->memory->flags |= PERM;
+               if (esc_seen)
+                       toklen = scan_escape(tokstart, toklen);
+               yylval->memory = make_string(tokstart, toklen);
                if (intlstr) {
                        yylval->memory->flags |= INTLSTR;
                        intlstr = FALSE;
@@ -3377,10 +3328,12 @@ retry:
                                        lintwarn("numeric constant `%.*s' 
treated as hexadecimal",
                                                (int) strlen(tokstart)-1, 
tokstart);
                        }
-                       yylval->memory = mk_number(nondec2awknum(tokstart, 
strlen(tokstart)),
-                                                                               
        PERM|NUMCUR|NUMBER);
+                       d = nondec2awknum(tokstart, strlen(tokstart));
                } else
-                       yylval->memory = mk_number(atof(tokstart), 
PERM|NUMCUR|NUMBER);
+                       d = atof(tokstart);
+               yylval->memory = make_number(d);
+               if (d <= INT32_MAX && d >= INT32_MIN && d == (int32_t) d)
+                       yylval->memory->flags |= NUMINT;
                return lasttok = YNUMBER;
 
        case '&':
@@ -3557,23 +3510,6 @@ out:
 #undef NEWLINE_EOF
 }
 
-/* mk_symbol --- allocates a symbol for the symbol table. */
-
-NODE *
-mk_symbol(NODETYPE type, NODE *value)
-{
-       NODE *r;
-
-       getnode(r);
-       r->type = type;
-       r->flags = MALLOC;
-       r->lnode = value;
-       r->rnode = NULL;
-       r->parent_array = NULL;
-       r->var_assign = (Func_ptr) 0;
-       return r;
-}
-
 /* snode --- instructions for builtin functions. Checks for arg. count
              and supplies defaults where possible. */
 
@@ -3616,7 +3552,7 @@ snode(INSTRUCTION *subn, INSTRUCTION *r)
                        list = list_create(r);
                        (void) list_prepend(list, instruction(Op_field_spec));
                        (void) list_prepend(list, instruction(Op_push_i));
-                       list->nexti->memory = mk_number((AWKNUM) 0.0, 
(PERM|NUMCUR|NUMBER));
+                       list->nexti->memory = make_number(0.0);
                        return list; 
                } else {
                        arg = subn->nexti;
@@ -3658,7 +3594,7 @@ snode(INSTRUCTION *subn, INSTRUCTION *r)
                if (nexp == 2) {
                        INSTRUCTION *expr;
                        expr = list_create(instruction(Op_push_i));
-                       expr->nexti->memory = mk_number((AWKNUM) 0.0, 
(PERM|NUMCUR|NUMBER));
+                       expr->nexti->memory = make_number(0.0);
                        (void) mk_expression_list(subn,
                                        list_append(expr, 
instruction(Op_field_spec)));
                }
@@ -3706,7 +3642,7 @@ snode(INSTRUCTION *subn, INSTRUCTION *r)
                if (nexp == 3) {
                        arg = subn->nexti->lasti->nexti->lasti->nexti;  /* 3rd 
arg list */
                        ip = instruction(Op_push_i);
-                       ip->memory = mk_number((AWKNUM) 0.0, 
(PERM|NUMCUR|NUMBER));
+                       ip->memory = make_number(0.0);
                        (void) mk_expression_list(subn,
                                        list_append(list_create(ip),
                                                instruction(Op_field_spec)));
@@ -3809,7 +3745,7 @@ snode(INSTRUCTION *subn, INSTRUCTION *r)
                if (ip->opcode == Op_push)
                        ip->opcode = Op_push_array;
        }
-#endif         
+#endif
 
        if (subn != NULL) {
                r->expr_count = count_expressions(&subn, FALSE);
@@ -3820,75 +3756,6 @@ snode(INSTRUCTION *subn, INSTRUCTION *r)
        return list_create(r);
 }
 
-/* append_param --- append PNAME to the list of parameters
- *                  for the current function.
- */
-
-static void
-append_param(char *pname)
-{
-       static NODE *savetail = NULL;
-       NODE *p;
-
-       p = make_param(pname);
-       if (func_params == NULL) {
-               func_params = p;
-               savetail = p;
-       } else if (savetail != NULL) {
-               savetail->rnode = p;
-               savetail = p;
-       }
-}
-
-/* dup_parms --- return TRUE if there are duplicate parameters */
-
-static int
-dup_parms(INSTRUCTION *fp, NODE *func)
-{
-       NODE *np;
-       const char *fname, **names;
-       int count, i, j, dups;
-       NODE *params;
-
-       if (func == NULL)       /* error earlier */
-               return TRUE;
-
-       fname = func->param;
-       count = func->param_cnt;
-       params = func->rnode;
-
-       if (count == 0)         /* no args, no problem */
-               return FALSE;
-
-       if (params == NULL)     /* error earlier */
-               return TRUE;
-
-       emalloc(names, const char **, count * sizeof(char *), "dup_parms");
-
-       i = 0;
-       for (np = params; np != NULL; np = np->rnode) {
-               if (np->param == NULL) { /* error earlier, give up, go home */
-                       efree(names);
-                       return TRUE;
-               }
-               names[i++] = np->param;
-       }
-
-       dups = 0;
-       for (i = 1; i < count; i++) {
-               for (j = 0; j < i; j++) {
-                       if (strcmp(names[i], names[j]) == 0) {
-                               dups++;
-                               error_ln(fp->source_line,
-       _("function `%s': parameter #%d, `%s', duplicates parameter #%d"),
-                                       fname, i + 1, names[j], j+1);
-                       }
-               }
-       }
-
-       efree(names);
-       return (dups > 0 ? TRUE : FALSE);
-}
 
 /* parms_shadow --- check if parameters shadow globals */
 
@@ -3897,18 +3764,19 @@ parms_shadow(INSTRUCTION *pc, int *shadow)
 {
        int pcount, i;
        int ret = FALSE;
-       NODE *func;
+       NODE *func, *fp;
        char *fname;
 
        func = pc->func_body;
-       fname = func->lnode->param;
-       
+       fname = func->vname;
+       fp = func->fparms;
+
 #if 0  /* can't happen, already exited if error ? */
        if (fname == NULL || func == NULL)      /* error earlier */
                return FALSE;
 #endif
 
-       pcount = func->lnode->param_cnt;
+       pcount = func->param_cnt;
 
        if (pcount == 0)                /* no args, no problem */
                return 0;
@@ -3920,10 +3788,10 @@ parms_shadow(INSTRUCTION *pc, int *shadow)
         * about all shadowed parameters.
         */
        for (i = 0; i < pcount; i++) {
-               if (lookup(func->parmlist[i]) != NULL) {
+               if (lookup(fp[i].param) != NULL) {
                        warning(
        _("function `%s': parameter `%s' shadows global variable"),
-                                       fname, func->parmlist[i]);
+                                       fname, fp[i].param);
                        ret = TRUE;
                }
        }
@@ -3933,79 +3801,10 @@ parms_shadow(INSTRUCTION *pc, int *shadow)
 }
 
 
-/*
- * install_symbol:
- * Install a name in the symbol table, even if it is already there.
- * Caller must check against redefinition if that is desired. 
- */
-
-
-NODE *
-install_symbol(char *name, NODE *value)
-{
-       NODE *hp;
-       size_t len;
-       int bucket;
-
-       if (install_func)
-               (*install_func)(name);
-
-       var_count++;
-       len = strlen(name);
-       bucket = hash(name, len, (unsigned long) HASHSIZE, NULL);
-       getnode(hp);
-       hp->type = Node_hashnode;
-       hp->hnext = variables[bucket];
-       variables[bucket] = hp;
-       hp->hlength = len;
-       hp->hvalue = value;
-       hp->hname = name;
-       hp->hvalue->vname = name;
-       return hp->hvalue;
-}
-
-/* lookup --- find the most recent hash node for name installed by 
install_symbol */
-
-NODE *
-lookup(const char *name)
-{
-       NODE *bucket;
-       size_t len;
-
-       len = strlen(name);
-       for (bucket = variables[hash(name, len, (unsigned long) HASHSIZE, 
NULL)];
-                       bucket != NULL; bucket = bucket->hnext)
-               if (bucket->hlength == len && STREQN(bucket->hname, name, len))
-                       return bucket->hvalue;
-       return NULL;
-}
-
-/* sym_comp --- compare two symbol (variable or function) names */
-
-static int
-sym_comp(const void *v1, const void *v2)
-{
-       const NODE *const *npp1, *const *npp2;
-       const NODE *n1, *n2;
-       int minlen;
-
-       npp1 = (const NODE *const *) v1;
-       npp2 = (const NODE *const *) v2;
-       n1 = *npp1;
-       n2 = *npp2;
-
-       if (n1->hlength > n2->hlength)
-               minlen = n1->hlength;
-       else
-               minlen = n2->hlength;
-
-       return strncmp(n1->hname, n2->hname, minlen);
-}
-
 /* valinfo --- dump var info */
 
 void
-valinfo(NODE *n, int (*print_func)(FILE *, const char *, ...), FILE *fp)
+valinfo(NODE *n, Func_print print_func, FILE *fp)
 {
        if (n == Nnull_string)
                print_func(fp, "uninitialized scalar\n");
@@ -4023,52 +3822,6 @@ valinfo(NODE *n, int (*print_func)(FILE *, const char *, 
...), FILE *fp)
                print_func(fp, "?? flags %s\n", flags2str(n->flags));
 }
 
-/* get_varlist --- list of global variables */
-
-NODE **
-get_varlist()
-{
-       int i, j;
-       NODE **table;
-       NODE *p;
-
-       emalloc(table, NODE **, (var_count + 1) * sizeof(NODE *), 
"get_varlist");
-       update_global_values();
-       for (i = j = 0; i < HASHSIZE; i++)
-               for (p = variables[i]; p != NULL; p = p->hnext)
-                       table[j++] = p;
-       assert(j == var_count);
-
-       /* Shazzam! */
-       qsort(table, j, sizeof(NODE *), sym_comp);
-
-       table[j] = NULL;
-       return table;
-}
-
-/* print_vars --- print names and values of global variables */ 
-
-void
-print_vars(int (*print_func)(FILE *, const char *, ...), FILE *fp)
-{
-       int i;
-       NODE **table;
-       NODE *p;
-
-       table = get_varlist();
-       for (i = 0; (p = table[i]) != NULL; i++) {
-               if (p->hvalue->type == Node_func)
-                       continue;
-               print_func(fp, "%.*s: ", (int) p->hlength, p->hname);
-               if (p->hvalue->type == Node_var_array)
-                       print_func(fp, "array, %ld elements\n", 
p->hvalue->table_size);
-               else if (p->hvalue->type == Node_var_new)
-                       print_func(fp, "untyped variable\n");
-               else if (p->hvalue->type == Node_var)
-                       valinfo(p->hvalue->var_value, print_func, fp);
-       }
-       efree(table);
-}
 
 /* dump_vars --- dump the symbol table */
 
@@ -4076,6 +3829,7 @@ void
 dump_vars(const char *fname)
 {
        FILE *fp;
+       NODE **vars;
 
        if (fname == NULL)
                fp = stderr;
@@ -4085,48 +3839,25 @@ dump_vars(const char *fname)
                fp = stderr;
        }
 
-       print_vars(fprintf, fp);
+       vars = variable_list();
+       print_vars(vars, fprintf, fp);
+       efree(vars);
        if (fp != stderr && fclose(fp) != 0)
                warning(_("%s: close failed (%s)"), fname, strerror(errno));
 }
 
-/* release_all_vars --- free all variable memory */
-
-void
-release_all_vars()
-{
-       int i;
-       NODE *p, *next;
-       
-       for (i = 0; i < HASHSIZE; i++) {
-               for (p = variables[i]; p != NULL; p = next) {
-                       next = p->hnext;
-
-                       if (p->hvalue->type == Node_func)
-                               continue;
-                       else if (p->hvalue->type == Node_var_array)
-                               assoc_clear(p->hvalue);
-                       else if (p->hvalue->type != Node_var_new)
-                               unref(p->hvalue->var_value);
-
-                       efree(p->hname);
-                       freenode(p->hvalue);
-                       freenode(p);
-               }
-       }                                                                    
-}
-
 /* dump_funcs --- print all functions */
 
 void
 dump_funcs()
 {
-       if (func_count <= 0)
-               return;
-
-       (void) foreach_func((int (*)(INSTRUCTION *, void *)) pp_func, TRUE, 
(void *) 0);
+       NODE **funcs;
+       funcs = function_list(TRUE);
+       (void) foreach_func(funcs, (int (*)(INSTRUCTION *, void *)) pp_func, 
(void *) 0);
+       efree(funcs);
 }
 
+
 /* shadow_funcs --- check all functions for parameters that shadow globals */
 
 void
@@ -4134,175 +3865,152 @@ shadow_funcs()
 {
        static int calls = 0;
        int shadow = FALSE;
-
-       if (func_count <= 0)
-               return;
+       NODE **funcs;
 
        if (calls++ != 0)
                fatal(_("shadow_funcs() called twice!"));
 
-       (void) foreach_func((int (*)(INSTRUCTION *, void *)) parms_shadow, 
TRUE, &shadow);
+       funcs = function_list(TRUE);
+       (void) foreach_func(funcs, (int (*)(INSTRUCTION *, void *)) 
parms_shadow, & shadow);
+       efree(funcs);
 
        /* End with fatal if the user requested it.  */
        if (shadow && lintfunc != warning)
                lintwarn(_("there were shadowed variables."));
 }
 
-/*
- * func_install:
- * check if name is already installed;  if so, it had better have Null value,
- * in which case def is added as the value. Otherwise, install name with def
- * as value. 
- *
- * Extra work, build up and save a list of the parameter names in a table
- * and hang it off params->parmlist. This is used to set the `vname' field
- * of each function parameter during a function call. See eval.c.
+
+/* mk_function --- finalize function definition node; remove parameters
+ *     out of the symbol table.
  */
 
-static int
-func_install(INSTRUCTION *func, INSTRUCTION *def)
+static INSTRUCTION *
+mk_function(INSTRUCTION *fi, INSTRUCTION *def)
 {
-       NODE *params;
-       NODE *r, *n, *thisfunc, *hp;
-       char **pnames = NULL;
-       char *fname;
-       int pcount = 0;
-       int i;
+       NODE *thisfunc;
 
-       params = func_params;
-
-       /* check for function foo(foo) { ... }.  bleah. */
-       for (n = params->rnode; n != NULL; n = n->rnode) {
-               if (strcmp(n->param, params->param) == 0) {
-                       error_ln(func->source_line,
-                               _("function `%s': can't use function name as 
parameter name"), params->param);
-                       return -1;
-               } else if (is_std_var(n->param)) {
-                       error_ln(func->source_line,
-                               _("function `%s': can't use special variable 
`%s' as a function parameter"),
-                                       params->param, n->param);
-                       return -1;
-               }
-       }
-
-       thisfunc = NULL;        /* turn off warnings */
-
-       fname = params->param;
-       /* symbol table management */
-       hp = remove_symbol(params->param);  /* remove function name out of 
symbol table */ 
-       if (hp != NULL)
-               freenode(hp);
-       r = lookup(fname);
-       if (r != NULL) {
-               error_ln(func->source_line,
-                        _("function name `%s' previously defined"), fname);
-               return -1;
-       } else if (fname == builtin_func)       /* not a valid function name */
-               goto remove_params;
+       thisfunc = fi->func_body;
+       assert(thisfunc != NULL);
 
        /* add an implicit return at end;
         * also used by 'return' command in debugger
         */
-      
+
        (void) list_append(def, instruction(Op_push_i));
-       def->lasti->memory = Nnull_string;
+       def->lasti->memory = dupnode(Nnull_string);
        (void) list_append(def, instruction(Op_K_return));
 
        if (do_profiling)
                (void) list_prepend(def, instruction(Op_exec_count));
 
-       /* func->opcode is Op_func */
-       (func + 1)->firsti = def->nexti;
-       (func + 1)->lasti = def->lasti;
-       (func + 2)->first_line = func->source_line;
-       (func + 2)->last_line = lastline;
-
-       func->nexti = def->nexti;
+       /* fi->opcode = Op_func */
+       (fi + 1)->firsti = def->nexti;
+       (fi + 1)->lasti = def->lasti;
+       (fi + 2)->first_line = fi->source_line;
+       (fi + 2)->last_line = lastline;
+       fi->nexti = def->nexti;
        bcfree(def);
 
-       (void) list_append(rule_list, func + 1);        /* debugging */
-
-       /* install the function */
-       thisfunc = mk_symbol(Node_func, params);
-       (void) install_symbol(fname, thisfunc);
-       thisfunc->code_ptr = func;
-       func->func_body = thisfunc;
-
-       for (n = params->rnode; n != NULL; n = n->rnode)
-               pcount++;
-
-       if (pcount != 0) {
-               emalloc(pnames, char **, (pcount + 1) * sizeof(char *), 
"func_install");
-               for (i = 0, n = params->rnode; i < pcount; i++, n = n->rnode)
-                       pnames[i] = n->param;
-               pnames[pcount] = NULL;
-       }
-       thisfunc->parmlist = pnames;
+       (void) list_append(rule_list, fi + 1);  /* debugging */
 
        /* update lint table info */
-       func_use(fname, FUNC_DEFINE);
-
-       func_count++;   /* used in profiler / pretty printer */
+       func_use(thisfunc->vname, FUNC_DEFINE);
 
-remove_params:
        /* remove params from symbol table */
-       pop_params(params->rnode);
-       return 0;
+       remove_params(thisfunc);
+       return fi;
 }
 
-/* remove_symbol --- remove a variable from the symbol table */
+/* 
+ * install_function:
+ * install function name in the symbol table.
+ * Extra work, build up and install a list of the parameter names.
+ */
 
-NODE *
-remove_symbol(char *name)
+static int
+install_function(char *fname, INSTRUCTION *fi, INSTRUCTION *plist)
 {
-       NODE *bucket, **save;
-       size_t len;
+       NODE *r, *f;
+       int pcount = 0;
 
-       len = strlen(name);
-       save = &(variables[hash(name, len, (unsigned long) HASHSIZE, NULL)]);
-       for (bucket = *save; bucket != NULL; bucket = bucket->hnext) {
-               if (len == bucket->hlength && STREQN(bucket->hname, name, len)) 
{
-                       var_count--;
-                       *save = bucket->hnext;
-                       return bucket;
-               }
-               save = &(bucket->hnext);
+       r = lookup(fname);
+       if (r != NULL) {
+               error_ln(fi->source_line, _("function name `%s' previously 
defined"), fname);
+               return -1;
        }
-       return NULL;
+
+       if (plist != NULL)
+               pcount = plist->lasti->param_count + 1;
+       f = install_symbol(fname, Node_func);
+       fi->func_body = f;
+       f->param_cnt = pcount;
+       f->code_ptr = fi;
+       f->fparms = NULL; 
+       if (pcount > 0) {
+               char **pnames;
+               pnames = check_params(fname, pcount, plist);    /* frees plist 
*/
+               f->fparms = make_params(pnames, pcount);
+               efree(pnames);
+               install_params(f);
+       }
+       return 0;
 }
 
-/* pop_params --- remove list of function parameters from symbol table */
 
-/*
- * pop parameters out of the symbol table. do this in reverse order to
- * avoid reading freed memory if there were duplicated parameters.
+/* check_params --- build a list of function parameter names after
+ *     making sure that the names are valid and there are no duplicates.
  */
-static void
-pop_params(NODE *params)
+
+static char **
+check_params(char *fname, int pcount, INSTRUCTION *list)
 {
-       NODE *hp;
-       if (params == NULL)
-               return;
-       pop_params(params->rnode);
-       hp = remove_symbol(params->param);
-       if (hp != NULL)
-               freenode(hp);
-}
+       INSTRUCTION *p, *np;
+       int i, j;
+       char *name;
+       char **pnames;
 
-/* make_param --- make NAME into a function parameter */
+       assert(pcount > 0);
 
-static NODE *
-make_param(char *name)
-{
-       NODE *r;
+       emalloc(pnames, char **, pcount * sizeof(char *), "check_params");
 
-       getnode(r);
-       r->type = Node_param_list;
-       r->rnode = NULL;
-       r->param_cnt = param_counter++;
-       return (install_symbol(name, r));
+       for (i = 0, p = list->nexti; p != NULL; i++, p = np) {
+               np = p->nexti;
+               name = p->lextok;
+               p->lextok = NULL;
+
+               if (strcmp(name, fname) == 0) {
+                       /* check for function foo(foo) { ... }.  bleah. */
+                       error_ln(p->source_line,
+                               _("function `%s': can't use function name as 
parameter name"), fname);
+               } else if (is_std_var(name)) {
+                       error_ln(p->source_line,
+                               _("function `%s': can't use special variable 
`%s' as a function parameter"),
+                                       fname, name);
+               }
+
+               /* check for duplicate parameters */
+               for (j = 0; j < i; j++) {
+                       if (strcmp(name, pnames[j]) == 0) {
+                               error_ln(p->source_line,
+                                       _("function `%s': parameter #%d, `%s', 
duplicates parameter #%d"),
+                                       fname, i + 1, name, j + 1);
+                       }
+               }
+
+               pnames[i] = name;
+               bcfree(p);
+       }
+       bcfree(list);
+
+       return pnames; 
 }
 
+
+#ifdef HASHSIZE
+undef HASHSIZE
+#endif
+#define HASHSIZE 1021
+ 
 static struct fdesc {
        char *name;
        short used;
@@ -4410,69 +4118,6 @@ param_sanity(INSTRUCTION *arglist)
        }
 }
 
-/* foreach_func --- execute given function for each awk function in symbol 
table. */
-
-int
-foreach_func(int (*pfunc)(INSTRUCTION *, void *), int sort, void *data)
-{
-       int i, j;
-       NODE *p;
-       int ret = 0;
-
-       if (sort) {
-               NODE **tab;
-
-               /*
-                * Walk through symbol table counting functions.
-                * Could be more than func_count if there are
-                * extension functions.
-                */
-               for (i = j = 0; i < HASHSIZE; i++) {
-                       for (p = variables[i]; p != NULL; p = p->hnext) {
-                               if (p->hvalue->type == Node_func) {
-                                       j++;
-                               }
-                       }
-               }
-
-               if (j == 0)
-                       return 0;
-
-               emalloc(tab, NODE **, j * sizeof(NODE *), "foreach_func");
-
-               /* now walk again, copying info */
-               for (i = j = 0; i < HASHSIZE; i++) {
-                       for (p = variables[i]; p != NULL; p = p->hnext) {
-                               if (p->hvalue->type == Node_func) {
-                                       tab[j] = p;
-                                       j++;
-                               }
-                       }
-               }
-
-               /* Shazzam! */
-               qsort(tab, j, sizeof(NODE *), sym_comp);
-
-               for (i = 0; i < j; i++) {
-                       if ((ret = pfunc(tab[i]->hvalue->code_ptr, data)) != 0)
-                               break;
-               }
-
-               efree(tab);
-               return ret;
-       }
-
-       /* unsorted */
-       for (i = 0; i < HASHSIZE; i++) {
-               for (p = variables[i]; p != NULL; p = p->hnext) {
-                       if (p->hvalue->type == Node_func
-                                       && (ret = pfunc(p->hvalue->code_ptr, 
data)) != 0)
-                               return ret;
-               }
-       }
-       return 0;
-}
-
 /* deferred variables --- those that are only defined if needed. */
 
 /*
@@ -4507,17 +4152,14 @@ register_deferred_variable(const char *name, NODE 
*(*load_func)(void))
 /* variable --- make sure NAME is in the symbol table */
 
 NODE *
-variable(char *name, NODETYPE type)
+variable(int location, char *name, NODETYPE type)
 {
        NODE *r;
 
        if ((r = lookup(name)) != NULL) {
-               if (r->type == Node_func) {
-                       error(_("function `%s' called with space between name 
and `(',\nor used as a variable or an array"),
+               if (r->type == Node_func || r->type == Node_ext_func )
+                       error_ln(location, _("function `%s' called with space 
between name and `(',\nor used as a variable or an array"),
                                r->vname);
-                       errcount++;
-                       r->type = Node_var_new; /* continue parsing instead of 
exiting */
-               }
        } else {
                /* not found */
                struct deferred_variable *dv;
@@ -4527,11 +4169,7 @@ variable(char *name, NODETYPE type)
                        /*
                         * This is the only case in which we may not free the 
string.
                         */
-                               if (type == Node_var)
-                                       r = mk_symbol(type, Nnull_string);
-                               else
-                                       r = mk_symbol(type, (NODE *) NULL);
-                               return install_symbol(name, r);
+                               return install_symbol(name, type);
                        }
                        if (STREQ(name, dv->name)) {
                                r = (*dv->load_func)();
@@ -4638,9 +4276,6 @@ make_assignable(INSTRUCTION *ip)
 {
        switch (ip->opcode) {
        case Op_push:
-               if (ip->memory->type == Node_param_list
-                               && (ip->memory->flags & FUNC) != 0)
-                       return NULL;
                ip->opcode = Op_push_lhs;
                return ip;
        case Op_field_spec:
@@ -4655,14 +4290,6 @@ make_assignable(INSTRUCTION *ip)
        return NULL;
 }
 
-/* stopme --- for debugging */
-
-NODE *
-stopme(int nargs ATTRIBUTE_UNUSED)
-{
-       return (NODE *) 0;
-}
-
 /* dumpintlstr --- write out an initial .po file entry for the string */
 
 static void
@@ -4712,27 +4339,6 @@ dumpintlstr2(const char *str1, size_t len1, const char 
*str2, size_t len2)
        fflush(stdout);
 }
 
-/* isarray --- can this type be subscripted? */
-
-static int
-isarray(NODE *n)
-{
-       switch (n->type) {
-       case Node_var_new:
-       case Node_var_array:
-               return TRUE;
-       case Node_param_list:
-               return (n->flags & FUNC) == 0;
-       case Node_array_ref:
-               cant_happen();
-               break;
-       default:
-               break;  /* keeps gcc -Wall happy */
-       }
-
-       return FALSE;
-}
-
 /* mk_binary --- instructions for binary operators */
 
 static INSTRUCTION *
@@ -4793,11 +4399,7 @@ mk_binary(INSTRUCTION *s1, INSTRUCTION *s2, INSTRUCTION 
*op)
                        }
 
                        op->opcode = Op_push_i;
-                       op->memory = mk_number(res, (PERM|NUMCUR|NUMBER));
-                       n1->flags &= ~PERM;
-                       n1->flags |= MALLOC;
-                       n2->flags &= ~PERM;
-                       n2->flags |= MALLOC;
+                       op->memory = make_number(res);
                        unref(n1);
                        unref(n2);
                        bcfree(ip1);
@@ -5129,9 +4731,7 @@ mk_assignment(INSTRUCTION *lhs, INSTRUCTION *rhs, 
INSTRUCTION *op)
 static INSTRUCTION *
 optimize_assignment(INSTRUCTION *exp)
 {
-       INSTRUCTION *i1;
-       INSTRUCTION *i2;
-       INSTRUCTION *i3;
+       INSTRUCTION *i1, *i2, *i3;
 
        /*
         * Optimize assignment statements array[subs] = x; var = x; $n = x;
@@ -5252,13 +4852,26 @@ optimize_assignment(INSTRUCTION *exp)
 
                case Op_push_lhs:
                        if (i2->nexti == i1
-                                               && i1->opcode == Op_assign
+                                       && i1->opcode == Op_assign
                        ) {
                                /* var = .. */
                                i2->opcode = Op_store_var;
                                i2->nexti = NULL;
                                bcfree(i1);          /* Op_assign */
                                exp->lasti = i2;     /* update Op_list */
+
+                               i3 = exp->nexti;
+                               if (i3->opcode == Op_push_i
+                                       && (i3->memory->flags & INTLSTR) == 0
+                                       && i3->nexti == i2
+                               ) {
+                                       /* constant initializer */ 
+                                       i2->initval = i3->memory;
+                                       bcfree(i3);
+                                       exp->nexti = i2;
+                               } else
+                                       i2->initval = NULL;
+
                                return exp;
                        }
                        break;
@@ -5559,320 +5172,6 @@ fix_break_continue(INSTRUCTION *list, INSTRUCTION 
*b_target, INSTRUCTION *c_targ
        }
 }
 
-
-/* append_symbol --- append symbol to the list of symbols
- *                  installed in the symbol table.
- */
-
-void
-append_symbol(char *name)
-{
-       NODE *hp;
-
-       /* N.B.: func_install removes func name and reinstalls it;
-        * and we get two entries for it here!. destroy_symbol()
-        * will find and destroy the Node_func which is what we want.
-        */
-
-       getnode(hp);
-       hp->hname = name;       /* shallow copy */
-       hp->hnext = symbol_list->hnext;
-       symbol_list->hnext = hp;
-}
-
-/* release_symbol --- free symbol list and optionally remove symbol from 
symbol table */
-
-void
-release_symbols(NODE *symlist, int keep_globals)
-{
-       NODE *hp, *n;
-
-       for (hp = symlist->hnext; hp != NULL; hp = n) {
-               if (! keep_globals) {
-                       /* destroys globals, function, and params
-                        * if still in symbol table and not removed by 
func_install
-                        * due to parse error.
-                        */
-                       destroy_symbol(hp->hname);
-               }
-               n = hp->hnext;
-               freenode(hp);
-       }
-       symlist->hnext = NULL;
-}
-
-/* destroy_symbol --- remove a symbol from symbol table
-*                     and free all associated memory.
-*/
-
-void
-destroy_symbol(char *name)
-{
-       NODE *symbol, *hp;
-
-       symbol = lookup(name);
-       if (symbol == NULL)
-               return;
-
-       if (symbol->type == Node_func) {
-               char **varnames;
-               NODE *func, *n;
-                               
-               func = symbol;
-               varnames = func->parmlist;
-               if (varnames != NULL)
-                       efree(varnames);
-
-               /* function parameters of type Node_param_list */               
                
-               for (n = func->lnode->rnode; n != NULL; ) {
-                       NODE *np;
-                       np = n->rnode;
-                       efree(n->param);
-                       freenode(n);
-                       n = np;
-               }               
-               freenode(func->lnode);
-               func_count--;
-
-       } else if (symbol->type == Node_var_array)
-               assoc_clear(symbol);
-       else if (symbol->type == Node_var) 
-               unref(symbol->var_value);
-
-       /* remove from symbol table */
-       hp = remove_symbol(name);
-       efree(hp->hname);
-       freenode(hp->hvalue);
-       freenode(hp);
-}
-
-#define pool_size      d.dl
-#define freei          x.xi
-static INSTRUCTION *pool_list;
-static AWK_CONTEXT *curr_ctxt = NULL;
-
-/* new_context --- create a new execution context. */
-
-AWK_CONTEXT *
-new_context()
-{
-       AWK_CONTEXT *ctxt;
-
-       emalloc(ctxt, AWK_CONTEXT *, sizeof(AWK_CONTEXT), "new_context");
-       memset(ctxt, 0, sizeof(AWK_CONTEXT));
-       ctxt->srcfiles.next = ctxt->srcfiles.prev = &ctxt->srcfiles;
-       ctxt->rule_list.opcode = Op_list;
-       ctxt->rule_list.lasti = &ctxt->rule_list;
-       return ctxt;
-}
-
-/* set_context --- change current execution context. */
-
-static void
-set_context(AWK_CONTEXT *ctxt)
-{
-       pool_list = &ctxt->pools;
-       symbol_list = &ctxt->symbols;
-       srcfiles = &ctxt->srcfiles;
-       rule_list = &ctxt->rule_list;
-       install_func = ctxt->install_func;
-       curr_ctxt = ctxt;
-}
-
-/*
- * push_context:
- *
- * Switch to the given context after saving the current one. The set
- * of active execution contexts forms a stack; the global or main context
- * is at the bottom of the stack.
- */
-
-void
-push_context(AWK_CONTEXT *ctxt)
-{
-       ctxt->prev = curr_ctxt;
-       /* save current source and sourceline */
-       if (curr_ctxt != NULL) {
-               curr_ctxt->sourceline = sourceline;
-               curr_ctxt->source = source;
-       }
-       sourceline = 0;
-       source = NULL;
-       set_context(ctxt);
-}
-
-/* pop_context --- switch to previous execution context. */ 
-
-void
-pop_context()
-{
-       AWK_CONTEXT *ctxt;
-
-       assert(curr_ctxt != NULL);
-       ctxt = curr_ctxt->prev;
-       /* restore source and sourceline */
-       sourceline = ctxt->sourceline;
-       source = ctxt->source;
-       set_context(ctxt);
-}
-
-/* in_main_context --- are we in the main context ? */
-
-int
-in_main_context()
-{
-       assert(curr_ctxt != NULL);
-       return (curr_ctxt->prev == NULL);
-}
-
-/* free_context --- free context structure and related data. */ 
-
-void
-free_context(AWK_CONTEXT *ctxt, int keep_globals)
-{
-       SRCFILE *s, *sn;
-
-       if (ctxt == NULL)
-               return;
-
-       assert(curr_ctxt != ctxt);
-
-       /* free all code including function codes */
-       free_bcpool(&ctxt->pools);
-       /* free symbols */
-       release_symbols(&ctxt->symbols, keep_globals);
-       /* free srcfiles */
-       for (s = &ctxt->srcfiles; s != &ctxt->srcfiles; s = sn) {
-               sn = s->next;
-               if (s->stype != SRC_CMDLINE && s->stype != SRC_STDIN)
-                       efree(s->fullpath);
-               efree(s->src);
-               efree(s);
-       }
-       efree(ctxt);
-}
-
-/* free_bc_internal --- free internal memory of an instruction. */ 
-
-static void
-free_bc_internal(INSTRUCTION *cp)
-{
-       NODE *m;
-
-       switch(cp->opcode) {
-       case Op_func_call:
-               if (cp->func_name != NULL
-                               && cp->func_name != builtin_func
-               )
-                       efree(cp->func_name);
-               break;
-       case Op_push_re:
-       case Op_match_rec:
-       case Op_match:
-       case Op_nomatch:
-               m = cp->memory;
-               if (m->re_reg != NULL)
-                       refree(m->re_reg);
-               if (m->re_exp != NULL)
-                       unref(m->re_exp);
-               if (m->re_text != NULL)
-                       unref(m->re_text);
-               freenode(m);
-               break;                  
-       case Op_token:  /* token lost during error recovery in yyparse */
-               if (cp->lextok != NULL)
-                       efree(cp->lextok);
-               break;
-       case Op_illegal:
-               cant_happen();
-       default:
-               break;  
-       }
-}
-
-
-/* INSTR_CHUNK must be > largest code size (3) */
-#define INSTR_CHUNK 127
-
-/* bcfree --- deallocate instruction */
-
-void
-bcfree(INSTRUCTION *cp)
-{
-       cp->opcode = 0;
-       cp->nexti = pool_list->freei;
-       pool_list->freei = cp;
-}      
-
-/* bcalloc --- allocate a new instruction */
-
-INSTRUCTION *
-bcalloc(OPCODE op, int size, int srcline)
-{
-       INSTRUCTION *cp;
-
-       if (size > 1) {
-               /* wide instructions Op_rule, Op_func_call .. */
-               emalloc(cp, INSTRUCTION *, (size + 1) * sizeof(INSTRUCTION), 
"bcalloc");
-               cp->pool_size = size;
-               cp->nexti = pool_list->nexti;
-               pool_list->nexti = cp++;
-       } else {
-               INSTRUCTION *pool;
-
-               pool = pool_list->freei;
-               if (pool == NULL) {
-                       INSTRUCTION *last;
-                       emalloc(cp, INSTRUCTION *, (INSTR_CHUNK + 1) * 
sizeof(INSTRUCTION), "bcalloc");
-
-                       cp->pool_size = INSTR_CHUNK;
-                       cp->nexti = pool_list->nexti;
-                       pool_list->nexti = cp;
-                       pool = ++cp;
-                       last = &pool[INSTR_CHUNK - 1];
-                       for (; cp <= last; cp++) {
-                               cp->opcode = 0;
-                               cp->nexti = cp + 1;
-                       }
-                       --cp;
-                       cp->nexti = NULL;
-               }
-               cp = pool;
-               pool_list->freei = cp->nexti;
-       }
-
-       memset(cp, 0, size * sizeof(INSTRUCTION));
-       cp->opcode = op;
-       cp->source_line = srcline;
-       return cp;
-}
-
-/* free_bcpool --- free list of instruction memory pools */
-
-static void
-free_bcpool(INSTRUCTION *pl)
-{
-       INSTRUCTION *pool, *tmp;
-
-       for (pool = pl->nexti; pool != NULL; pool = tmp) {
-               INSTRUCTION *cp, *last;
-               long psiz;
-               psiz = pool->pool_size;
-               if (psiz == INSTR_CHUNK)
-                       last = pool + psiz;
-               else
-                       last = pool + 1;
-               for (cp = pool + 1; cp <= last ; cp++) {
-                       if (cp->opcode != 0)
-                               free_bc_internal(cp);
-               }
-               tmp = pool->nexti;
-               efree(pool);
-       }
-       memset(pl, 0, sizeof(INSTRUCTION));
-}
-
-
 static inline INSTRUCTION *
 list_create(INSTRUCTION *x)
 {
diff --git a/builtin.c b/builtin.c
index 724ea6d..6ed7abd 100644
--- a/builtin.c
+++ b/builtin.c
@@ -77,8 +77,10 @@ static NODE *sub_common(int nargs, long how_many, int 
backdigs);
 #define POP_TWO_SCALARS(s1, s2) \
 s2 = POP_SCALAR(); \
 s1 = POP(); \
-if ((s1)->type == Node_var_array) \
-    DEREF(s2), fatal(_("attempt to use array `%s' in a scalar context"), 
array_vname(s1)), 0
+do { if (s1->type == Node_var_array) { \
+DEREF(s2); \
+fatal(_("attempt to use array `%s' in a scalar context"), array_vname(s1)); \
+}} while (FALSE)
 
 
 /*
@@ -331,8 +333,10 @@ do_index(int nargs)
                if ((s2->flags & (STRING|STRCUR)) == 0)
                        lintwarn(_("index: received non-string second 
argument"));
        }
-       force_string(s1);
-       force_string(s2);
+
+       s1 = force_string(s1);
+       s2 = force_string(s2);
+
        p1 = s1->stptr;
        p2 = s2->stptr;
        l1 = s1->stlen;
@@ -499,7 +503,7 @@ do_length(int nargs)
 
        if (do_lint && (tmp->flags & (STRING|STRCUR)) == 0)
                lintwarn(_("length: received non-string argument"));
-       (void) force_string(tmp);
+       tmp = force_string(tmp);
 
 #ifdef MBS_SUPPORT
        if (gawk_mb_cur_max > 1) {
@@ -1345,7 +1349,7 @@ out2:
                        _("too many arguments supplied for format string"));
        }
        bchunk(s0, s1 - s0);
-       r = make_str_node(obuf, obufout - obuf, ALREADY_MALLOCED);
+       r = make_str_node(obuf, obufout - obuf);
        obuf = NULL;
 out:
        {
@@ -1382,7 +1386,7 @@ printf_common(int nargs)
                }
        }
 
-       force_string(args_array[0]);
+       args_array[0] = force_string(args_array[0]);
        r = format_tree(args_array[0]->stptr, args_array[0]->stlen, args_array, 
nargs);
        for (i = 0; i < nargs; i++)
                DEREF(args_array[i]);
@@ -1495,12 +1499,12 @@ do_substr(int nargs)
 
        if (nargs == 3) {
                if (! (d_length >= 1)) {
-                       if (do_lint == LINT_ALL)
+                       if (do_lint == DO_LINT_ALL)
                                lintwarn(_("substr: length %g is not >= 1"), 
d_length);
-                       else if (do_lint == LINT_INVALID && ! (d_length >= 0))
+                       else if (do_lint == DO_LINT_INVALID && ! (d_length >= 
0))
                                lintwarn(_("substr: length %g is not >= 0"), 
d_length);
                        DEREF(t1);
-                       return Nnull_string;
+                       return dupnode(Nnull_string);
                }
                if (do_lint) {
                        if (double_to_int(d_length) != d_length)
@@ -1551,10 +1555,10 @@ do_substr(int nargs)
 
        if (t1->stlen == 0) {
                /* substr("", 1, 0) produces a warning only if LINT_ALL */
-               if (do_lint && (do_lint == LINT_ALL || ((indx | length) != 0)))
+               if (do_lint && (do_lint == DO_LINT_ALL || ((indx | length) != 
0)))
                        lintwarn(_("substr: source string is zero length"));
                DEREF(t1);
-               return Nnull_string;
+               return dupnode(Nnull_string);
        }
 
        /* get total len of input string, for following checks */
@@ -1571,7 +1575,7 @@ do_substr(int nargs)
                        lintwarn(_("substr: start index %g is past end of 
string"),
                                d_index);
                DEREF(t1);
-               return Nnull_string;
+               return dupnode(Nnull_string);
        }
        if (length > src_len - indx) {
                if (do_lint)
@@ -1609,7 +1613,7 @@ do_substr(int nargs)
                        wp++;
                }
                *cp = '\0';
-               r = make_str_node(substr, cp - substr, ALREADY_MALLOCED);
+               r = make_str_node(substr, cp - substr);
        }
 #else
        r = make_string(t1->stptr + indx, length);
@@ -1668,7 +1672,7 @@ do_strftime(int nargs)
                                do_gmt = (t3->stlen > 0);
                        DEREF(t3);
                }
-                       
+
                if (nargs >= 2) {
                        t2 = POP_SCALAR();
                        if (do_lint && (t2->flags & (NUMCUR|NUMBER)) == 0)
@@ -1680,6 +1684,7 @@ do_strftime(int nargs)
                tmp = POP_SCALAR();
                if (do_lint && (tmp->flags & (STRING|STRCUR)) == 0)
                        lintwarn(_("strftime: received non-string first 
argument"));
+       
                t1 = force_string(tmp);
                format = t1->stptr;
                formatlen = t1->stlen;
@@ -1762,13 +1767,13 @@ do_mktime(int nargs)
                        & hour, & minute, & second,
                        & dst);
 
-    if (do_lint /* Ready? Set! Go: */
-       && (    (second < 0 || second > 60)
-        || (minute < 0 || minute > 60)
-        || (hour < 0 || hour > 23)
-        || (day < 1 || day > 31)
-        || (month < 1 || month > 12) ))
-        lintwarn(_("mktime: at least one of the values is out of the default 
range"));
+       if (do_lint /* Ready? Set! Go: */
+               && (    (second < 0 || second > 60)
+               || (minute < 0 || minute > 60)
+               || (hour < 0 || hour > 23)
+               || (day < 1 || day > 31)
+               || (month < 1 || month > 12) ))
+                       lintwarn(_("mktime: at least one of the values is out 
of the default range"));
 
        t1->stptr[t1->stlen] = save;
        DEREF(t1);
@@ -1829,11 +1834,9 @@ do_system(int nargs)
        return make_number((AWKNUM) ret);
 }
 
-extern NODE **fmt_list;  /* declared in eval.c */
-
 /* do_print --- print items, separated by OFS, terminated with ORS */
 
-void 
+void
 do_print(int nargs, int redirtype)
 {
        struct redirect *rp = NULL;
@@ -1841,7 +1844,7 @@ do_print(int nargs, int redirtype)
        FILE *fp = NULL;
        int i;
        NODE *redir_exp = NULL;
-       NODE *tmp;
+       NODE *tmp = NULL;
 
        assert(nargs <= max_args);
 
@@ -1862,12 +1865,10 @@ do_print(int nargs, int redirtype)
                                DEREF(args_array[i]);
                        fatal(_("attempt to use array `%s' in a scalar 
context"), array_vname(tmp));
                }
-               if (do_lint && tmp->type == Node_var_new)
-                       lintwarn(_("reference to uninitialized variable `%s'"),
-                                       tmp->vname);
+
                if ((tmp->flags & (NUMBER|STRING)) == NUMBER) {
                        if (OFMTidx == CONVFMTidx)
-                               (void) force_string(tmp);
+                               args_array[i] = force_string(tmp);
                        else
                                args_array[i] = format_val(OFMT, OFMTidx, tmp);
                }
@@ -2259,7 +2260,7 @@ do_match(int nargs)
                                        it->flags |= MAYBE_NUM; /* user input */
 
                                        sub = make_number((AWKNUM) (ii));
-                                       lhs = assoc_lookup(dest, sub, FALSE);
+                                       lhs = assoc_lookup(dest, sub);
                                        unref(*lhs);
                                        *lhs = it;
                                        unref(sub);
@@ -2282,7 +2283,7 @@ do_match(int nargs)
        
                                        it = make_number((AWKNUM) subpat_start 
+ 1);
                                        sub = make_string(buf, slen);
-                                       lhs = assoc_lookup(dest, sub, FALSE);
+                                       lhs = assoc_lookup(dest, sub);
                                        unref(*lhs);
                                        *lhs = it;
                                        unref(sub);
@@ -2295,7 +2296,7 @@ do_match(int nargs)
        
                                        it = make_number((AWKNUM) subpat_len);
                                        sub = make_string(buf, slen);
-                                       lhs = assoc_lookup(dest, sub, FALSE);
+                                       lhs = assoc_lookup(dest, sub);
                                        unref(*lhs);
                                        *lhs = it;
                                        unref(sub);
@@ -2641,7 +2642,7 @@ sub_common(int nargs, long how_many, int backdigs)
        if (lhs != NULL) {
                if (matches > 0) {
                        unref(*lhs);
-                       *lhs = make_str_node(buf, textlen, ALREADY_MALLOCED);   
+                       *lhs = make_str_node(buf, textlen);     
                } else
                        efree(buf);
        } else {
diff --git a/cmd.h b/cmd.h
index a0c1788..8f8026a 100644
--- a/cmd.h
+++ b/cmd.h
@@ -28,8 +28,7 @@
 #include <readline/history.h>
 extern char **command_completion(const char *text, int start, int end);
 extern void initialize_pager(FILE *fp); /* debug.c */
-extern NODE **get_varlist(void);
-extern char **get_parmlist(void);
+extern NODE *get_function(void);
 #else
 #define initialize_pager(x)            /* nothing */
 #define add_history(x)         /* nothing */
diff --git a/command.c b/command.c
index 2b3b349..b705d5e 100644
--- a/command.c
+++ b/command.c
@@ -1,9 +1,8 @@
-/* A Bison parser, made by GNU Bison 2.4.3.  */
+/* A Bison parser, made by GNU Bison 2.5.  */
 
-/* Skeleton implementation for Bison's Yacc-like parsers in C
+/* Bison implementation for Yacc-like parsers in C
    
-      Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
-   2009, 2010 Free Software Foundation, Inc.
+      Copyright (C) 1984, 1989-1990, 2000-2011 Free Software Foundation, Inc.
    
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -45,7 +44,7 @@
 #define YYBISON 1
 
 /* Bison version.  */
-#define YYBISON_VERSION "2.4.3"
+#define YYBISON_VERSION "2.5"
 
 /* Skeleton name.  */
 #define YYSKELETON_NAME "yacc.c"
@@ -74,7 +73,7 @@
 
 /* Copy the first part of user declarations.  */
 
-/* Line 189 of yacc.c  */
+/* Line 268 of yacc.c  */
 #line 26 "command.y"
 
 #include "awk.h"
@@ -103,7 +102,7 @@ static int num_dim;
 static int in_eval = FALSE;
 static const char start_EVAL[] = "function @eval(){";
 static const char end_EVAL[] = "}";    
-static CMDARG *append_statement(CMDARG *alist, char *stmt);
+static CMDARG *append_statement(CMDARG *stmt_list, char *stmt);
 static char *next_word(char *p, int len, char **endp);
 static NODE *concat_args(CMDARG *a, int count);
 
@@ -143,8 +142,8 @@ static int find_argument(CMDARG *arg);
 #define YYSTYPE CMDARG *
 
 
-/* Line 189 of yacc.c  */
-#line 148 "command.c"
+/* Line 268 of yacc.c  */
+#line 147 "command.c"
 
 /* Enabling traces.  */
 #ifndef YYDEBUG
@@ -281,8 +280,8 @@ typedef int YYSTYPE;
 /* Copy the second part of user declarations.  */
 
 
-/* Line 264 of yacc.c  */
-#line 286 "command.c"
+/* Line 343 of yacc.c  */
+#line 285 "command.c"
 
 #ifdef short
 # undef short
@@ -384,11 +383,11 @@ YYID (yyi)
 #    define alloca _alloca
 #   else
 #    define YYSTACK_ALLOC alloca
-#    if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || 
defined __C99__FUNC__ \
+#    if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS && (defined __STDC__ || 
defined __C99__FUNC__ \
      || defined __cplusplus || defined _MSC_VER)
 #     include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
-#     ifndef _STDLIB_H
-#      define _STDLIB_H 1
+#     ifndef EXIT_SUCCESS
+#      define EXIT_SUCCESS 0
 #     endif
 #    endif
 #   endif
@@ -411,24 +410,24 @@ YYID (yyi)
 #  ifndef YYSTACK_ALLOC_MAXIMUM
 #   define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
 #  endif
-#  if (defined __cplusplus && ! defined _STDLIB_H \
+#  if (defined __cplusplus && ! defined EXIT_SUCCESS \
        && ! ((defined YYMALLOC || defined malloc) \
             && (defined YYFREE || defined free)))
 #   include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
-#   ifndef _STDLIB_H
-#    define _STDLIB_H 1
+#   ifndef EXIT_SUCCESS
+#    define EXIT_SUCCESS 0
 #   endif
 #  endif
 #  ifndef YYMALLOC
 #   define YYMALLOC malloc
-#   if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined 
__C99__FUNC__ \
+#   if ! defined malloc && ! defined EXIT_SUCCESS && (defined __STDC__ || 
defined __C99__FUNC__ \
      || defined __cplusplus || defined _MSC_VER)
 void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
 #   endif
 #  endif
 #  ifndef YYFREE
 #   define YYFREE free
-#   if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined 
__C99__FUNC__ \
+#   if ! defined free && ! defined EXIT_SUCCESS && (defined __STDC__ || 
defined __C99__FUNC__ \
      || defined __cplusplus || defined _MSC_VER)
 void free (void *); /* INFRINGES ON USER NAME SPACE */
 #   endif
@@ -455,23 +454,7 @@ union yyalloc
      ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
       + YYSTACK_GAP_MAXIMUM)
 
-/* Copy COUNT objects from FROM to TO.  The source and destination do
-   not overlap.  */
-# ifndef YYCOPY
-#  if defined __GNUC__ && 1 < __GNUC__
-#   define YYCOPY(To, From, Count) \
-      __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
-#  else
-#   define YYCOPY(To, From, Count)             \
-      do                                       \
-       {                                       \
-         YYSIZE_T yyi;                         \
-         for (yyi = 0; yyi < (Count); yyi++)   \
-           (To)[yyi] = (From)[yyi];            \
-       }                                       \
-      while (YYID (0))
-#  endif
-# endif
+# define YYCOPY_NEEDED 1
 
 /* Relocate STACK from its old location to the new one.  The
    local variables YYSIZE and YYSTACKSIZE give the old and new number of
@@ -491,6 +474,26 @@ union yyalloc
 
 #endif
 
+#if defined YYCOPY_NEEDED && YYCOPY_NEEDED
+/* Copy COUNT objects from FROM to TO.  The source and destination do
+   not overlap.  */
+# ifndef YYCOPY
+#  if defined __GNUC__ && 1 < __GNUC__
+#   define YYCOPY(To, From, Count) \
+      __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
+#  else
+#   define YYCOPY(To, From, Count)             \
+      do                                       \
+       {                                       \
+         YYSIZE_T yyi;                         \
+         for (yyi = 0; yyi < (Count); yyi++)   \
+           (To)[yyi] = (From)[yyi];            \
+       }                                       \
+      while (YYID (0))
+#  endif
+# endif
+#endif /* !YYCOPY_NEEDED */
+
 /* YYFINAL -- State number of the termination state.  */
 #define YYFINAL  2
 /* YYLAST -- Last index in YYTABLE.  */
@@ -721,8 +724,8 @@ static const yytype_uint8 yyr2[] =
        1,     1,     2,     1,     2,     2,     1
 };
 
-/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
-   STATE-NUM when YYTABLE doesn't specify something else to do.  Zero
+/* YYDEFACT[STATE-NAME] -- Default reduction number in state STATE-NUM.
+   Performed when YYTABLE doesn't specify something else to do.  Zero
    means the default is an error.  */
 static const yytype_uint8 yydefact[] =
 {
@@ -801,8 +804,7 @@ static const yytype_int16 yypgoto[] =
 
 /* YYTABLE[YYPACT[STATE-NUM]].  What to do in state STATE-NUM.  If
    positive, shift that token.  If negative, reduce the rule which
-   number is the opposite.  If zero, do what YYDEFACT says.
-   If YYTABLE_NINF, syntax error.  */
+   number is the opposite.  If YYTABLE_NINF, syntax error.  */
 #define YYTABLE_NINF -148
 static const yytype_int16 yytable[] =
 {
@@ -829,6 +831,12 @@ static const yytype_int16 yytable[] =
        0,     0,     0,    45
 };
 
+#define yypact_value_is_default(yystate) \
+  ((yystate) == (-151))
+
+#define yytable_value_is_error(yytable_value) \
+  YYID (0)
+
 static const yytype_int16 yycheck[] =
 {
        3,     6,    17,    17,    81,     1,    83,     1,    85,    86,
@@ -914,7 +922,6 @@ do                                                          
\
     {                                                          \
       yychar = (Token);                                                \
       yylval = (Value);                                                \
-      yytoken = YYTRANSLATE (yychar);                          \
       YYPOPSTACK (1);                                          \
       goto yybackup;                                           \
     }                                                          \
@@ -956,19 +963,10 @@ while (YYID (0))
 #endif
 
 
-/* YY_LOCATION_PRINT -- Print the location on the stream.
-   This macro was not mandated originally: define only if we know
-   we won't break user code: when these are the locations we know.  */
+/* This macro is provided for backward compatibility. */
 
 #ifndef YY_LOCATION_PRINT
-# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
-#  define YY_LOCATION_PRINT(File, Loc)                 \
-     fprintf (File, "%d.%d-%d.%d",                     \
-             (Loc).first_line, (Loc).first_column,     \
-             (Loc).last_line,  (Loc).last_column)
-# else
-#  define YY_LOCATION_PRINT(File, Loc) ((void) 0)
-# endif
+# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
 #endif
 
 
@@ -1156,7 +1154,6 @@ int yydebug;
 # define YYMAXDEPTH 10000
 #endif
 
-
 
 #if YYERROR_VERBOSE
 
@@ -1257,115 +1254,142 @@ yytnamerr (char *yyres, const char *yystr)
 }
 # endif
 
-/* Copy into YYRESULT an error message about the unexpected token
-   YYCHAR while in state YYSTATE.  Return the number of bytes copied,
-   including the terminating null byte.  If YYRESULT is null, do not
-   copy anything; just return the number of bytes that would be
-   copied.  As a special case, return 0 if an ordinary "syntax error"
-   message will do.  Return YYSIZE_MAXIMUM if overflow occurs during
-   size calculation.  */
-static YYSIZE_T
-yysyntax_error (char *yyresult, int yystate, int yychar)
-{
-  int yyn = yypact[yystate];
+/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message
+   about the unexpected token YYTOKEN for the state stack whose top is
+   YYSSP.
 
-  if (! (YYPACT_NINF < yyn && yyn <= YYLAST))
-    return 0;
-  else
+   Return 0 if *YYMSG was successfully written.  Return 1 if *YYMSG is
+   not large enough to hold the message.  In that case, also set
+   *YYMSG_ALLOC to the required number of bytes.  Return 2 if the
+   required number of bytes is too large to store.  */
+static int
+yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
+                yytype_int16 *yyssp, int yytoken)
+{
+  YYSIZE_T yysize0 = yytnamerr (0, yytname[yytoken]);
+  YYSIZE_T yysize = yysize0;
+  YYSIZE_T yysize1;
+  enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
+  /* Internationalized format string. */
+  const char *yyformat = 0;
+  /* Arguments of yyformat. */
+  char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
+  /* Number of reported tokens (one for the "unexpected", one per
+     "expected"). */
+  int yycount = 0;
+
+  /* There are many possibilities here to consider:
+     - Assume YYFAIL is not used.  It's too flawed to consider.  See
+       <http://lists.gnu.org/archive/html/bison-patches/2009-12/msg00024.html>
+       for details.  YYERROR is fine as it does not invoke this
+       function.
+     - If this state is a consistent state with a default action, then
+       the only way this function was invoked is if the default action
+       is an error action.  In that case, don't check for expected
+       tokens because there are none.
+     - The only way there can be no lookahead present (in yychar) is if
+       this state is a consistent state with a default action.  Thus,
+       detecting the absence of a lookahead is sufficient to determine
+       that there is no unexpected or expected token to report.  In that
+       case, just report a simple "syntax error".
+     - Don't assume there isn't a lookahead just because this state is a
+       consistent state with a default action.  There might have been a
+       previous inconsistent state, consistent state with a non-default
+       action, or user semantic action that manipulated yychar.
+     - Of course, the expected token list depends on states to have
+       correct lookahead information, and it depends on the parser not
+       to perform extra reductions after fetching a lookahead from the
+       scanner and before detecting a syntax error.  Thus, state merging
+       (from LALR or IELR) and default reductions corrupt the expected
+       token list.  However, the list is correct for canonical LR with
+       one exception: it will still contain any token that will not be
+       accepted due to an error action in a later state.
+  */
+  if (yytoken != YYEMPTY)
     {
-      int yytype = YYTRANSLATE (yychar);
-      YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]);
-      YYSIZE_T yysize = yysize0;
-      YYSIZE_T yysize1;
-      int yysize_overflow = 0;
-      enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
-      char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
-      int yyx;
-
-# if 0
-      /* This is so xgettext sees the translatable formats that are
-        constructed on the fly.  */
-      YY_("syntax error, unexpected %s");
-      YY_("syntax error, unexpected %s, expecting %s");
-      YY_("syntax error, unexpected %s, expecting %s or %s");
-      YY_("syntax error, unexpected %s, expecting %s or %s or %s");
-      YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s");
-# endif
-      char *yyfmt;
-      char const *yyf;
-      static char const yyunexpected[] = "syntax error, unexpected %s";
-      static char const yyexpecting[] = ", expecting %s";
-      static char const yyor[] = " or %s";
-      char yyformat[sizeof yyunexpected
-                   + sizeof yyexpecting - 1
-                   + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2)
-                      * (sizeof yyor - 1))];
-      char const *yyprefix = yyexpecting;
-
-      /* Start YYX at -YYN if negative to avoid negative indexes in
-        YYCHECK.  */
-      int yyxbegin = yyn < 0 ? -yyn : 0;
-
-      /* Stay within bounds of both yycheck and yytname.  */
-      int yychecklim = YYLAST - yyn + 1;
-      int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
-      int yycount = 1;
-
-      yyarg[0] = yytname[yytype];
-      yyfmt = yystpcpy (yyformat, yyunexpected);
-
-      for (yyx = yyxbegin; yyx < yyxend; ++yyx)
-       if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
-         {
-           if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
-             {
-               yycount = 1;
-               yysize = yysize0;
-               yyformat[sizeof yyunexpected - 1] = '\0';
-               break;
-             }
-           yyarg[yycount++] = yytname[yyx];
-           yysize1 = yysize + yytnamerr (0, yytname[yyx]);
-           yysize_overflow |= (yysize1 < yysize);
-           yysize = yysize1;
-           yyfmt = yystpcpy (yyfmt, yyprefix);
-           yyprefix = yyor;
-         }
+      int yyn = yypact[*yyssp];
+      yyarg[yycount++] = yytname[yytoken];
+      if (!yypact_value_is_default (yyn))
+        {
+          /* Start YYX at -YYN if negative to avoid negative indexes in
+             YYCHECK.  In other words, skip the first -YYN actions for
+             this state because they are default actions.  */
+          int yyxbegin = yyn < 0 ? -yyn : 0;
+          /* Stay within bounds of both yycheck and yytname.  */
+          int yychecklim = YYLAST - yyn + 1;
+          int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+          int yyx;
+
+          for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+            if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR
+                && !yytable_value_is_error (yytable[yyx + yyn]))
+              {
+                if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
+                  {
+                    yycount = 1;
+                    yysize = yysize0;
+                    break;
+                  }
+                yyarg[yycount++] = yytname[yyx];
+                yysize1 = yysize + yytnamerr (0, yytname[yyx]);
+                if (! (yysize <= yysize1
+                       && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
+                  return 2;
+                yysize = yysize1;
+              }
+        }
+    }
 
-      yyf = YY_(yyformat);
-      yysize1 = yysize + yystrlen (yyf);
-      yysize_overflow |= (yysize1 < yysize);
-      yysize = yysize1;
+  switch (yycount)
+    {
+# define YYCASE_(N, S)                      \
+      case N:                               \
+        yyformat = S;                       \
+      break
+      YYCASE_(0, YY_("syntax error"));
+      YYCASE_(1, YY_("syntax error, unexpected %s"));
+      YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s"));
+      YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s"));
+      YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s"));
+      YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or 
%s"));
+# undef YYCASE_
+    }
 
-      if (yysize_overflow)
-       return YYSIZE_MAXIMUM;
+  yysize1 = yysize + yystrlen (yyformat);
+  if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
+    return 2;
+  yysize = yysize1;
 
-      if (yyresult)
-       {
-         /* Avoid sprintf, as that infringes on the user's name space.
-            Don't have undefined behavior even if the translation
-            produced a string with the wrong number of "%s"s.  */
-         char *yyp = yyresult;
-         int yyi = 0;
-         while ((*yyp = *yyf) != '\0')
-           {
-             if (*yyp == '%' && yyf[1] == 's' && yyi < yycount)
-               {
-                 yyp += yytnamerr (yyp, yyarg[yyi++]);
-                 yyf += 2;
-               }
-             else
-               {
-                 yyp++;
-                 yyf++;
-               }
-           }
-       }
-      return yysize;
+  if (*yymsg_alloc < yysize)
+    {
+      *yymsg_alloc = 2 * yysize;
+      if (! (yysize <= *yymsg_alloc
+             && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM))
+        *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM;
+      return 1;
     }
+
+  /* Avoid sprintf, as that infringes on the user's name space.
+     Don't have undefined behavior even if the translation
+     produced a string with the wrong number of "%s"s.  */
+  {
+    char *yyp = *yymsg;
+    int yyi = 0;
+    while ((*yyp = *yyformat) != '\0')
+      if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount)
+        {
+          yyp += yytnamerr (yyp, yyarg[yyi++]);
+          yyformat += 2;
+        }
+      else
+        {
+          yyp++;
+          yyformat++;
+        }
+  }
+  return 0;
 }
 #endif /* YYERROR_VERBOSE */
-
 
 /*-----------------------------------------------.
 | Release the memory associated to this symbol.  |
@@ -1397,6 +1421,7 @@ yydestruct (yymsg, yytype, yyvaluep)
     }
 }
 
+
 /* Prevent warnings from -Wmissing-prototypes.  */
 #ifdef YYPARSE_PARAM
 #if defined __STDC__ || defined __cplusplus
@@ -1423,10 +1448,9 @@ YYSTYPE yylval;
 int yynerrs;
 
 
-
-/*-------------------------.
-| yyparse or yypush_parse.  |
-`-------------------------*/
+/*----------.
+| yyparse.  |
+`----------*/
 
 #ifdef YYPARSE_PARAM
 #if (defined __STDC__ || defined __C99__FUNC__      || defined __cplusplus || 
defined _MSC_VER)
@@ -1448,8 +1472,6 @@ yyparse ()
 #endif
 #endif
 {
-
-
     int yystate;
     /* Number of tokens to shift before error messages enabled.  */
     int yyerrstatus;
@@ -1604,7 +1626,7 @@ yybackup:
 
   /* First try to decide what to do without reference to lookahead token.  */
   yyn = yypact[yystate];
-  if (yyn == YYPACT_NINF)
+  if (yypact_value_is_default (yyn))
     goto yydefault;
 
   /* Not known => get a lookahead token if don't already have one.  */
@@ -1635,8 +1657,8 @@ yybackup:
   yyn = yytable[yyn];
   if (yyn <= 0)
     {
-      if (yyn == 0 || yyn == YYTABLE_NINF)
-       goto yyerrlab;
+      if (yytable_value_is_error (yyn))
+        goto yyerrlab;
       yyn = -yyn;
       goto yyreduce;
     }
@@ -1691,7 +1713,7 @@ yyreduce:
     {
         case 3:
 
-/* Line 1464 of yacc.c  */
+/* Line 1821 of yacc.c  */
 #line 109 "command.y"
     {
                cmd_idx = -1;
@@ -1711,7 +1733,7 @@ yyreduce:
 
   case 5:
 
-/* Line 1464 of yacc.c  */
+/* Line 1821 of yacc.c  */
 #line 128 "command.y"
     {
                if (errcount == 0 && cmd_idx >= 0) {
@@ -1766,7 +1788,7 @@ yyreduce:
 
   case 6:
 
-/* Line 1464 of yacc.c  */
+/* Line 1821 of yacc.c  */
 #line 178 "command.y"
     {
                yyerrok;
@@ -1775,14 +1797,14 @@ yyreduce:
 
   case 22:
 
-/* Line 1464 of yacc.c  */
+/* Line 1821 of yacc.c  */
 #line 212 "command.y"
     { want_nodeval = TRUE; }
     break;
 
   case 23:
 
-/* Line 1464 of yacc.c  */
+/* Line 1821 of yacc.c  */
 #line 217 "command.y"
     {
                if (errcount == 0) {
@@ -1802,7 +1824,7 @@ yyreduce:
 
   case 24:
 
-/* Line 1464 of yacc.c  */
+/* Line 1821 of yacc.c  */
 #line 235 "command.y"
     {
                (yyval) = append_statement(arg_list, (char *) start_EVAL);
@@ -1815,14 +1837,14 @@ yyreduce:
 
   case 25:
 
-/* Line 1464 of yacc.c  */
+/* Line 1821 of yacc.c  */
 #line 242 "command.y"
     { (yyval) = append_statement((yyvsp[(1) - (2)]), lexptr_begin); }
     break;
 
   case 26:
 
-/* Line 1464 of yacc.c  */
+/* Line 1821 of yacc.c  */
 #line 243 "command.y"
     {
                (yyval) = (yyvsp[(3) - (4)]);
@@ -1831,7 +1853,7 @@ yyreduce:
 
   case 27:
 
-/* Line 1464 of yacc.c  */
+/* Line 1821 of yacc.c  */
 #line 250 "command.y"
     {
                arg_list = append_statement((yyvsp[(2) - (3)]), (char *) 
end_EVAL);
@@ -1852,7 +1874,7 @@ yyreduce:
 
   case 28:
 
-/* Line 1464 of yacc.c  */
+/* Line 1821 of yacc.c  */
 #line 266 "command.y"
     {
                NODE *n;
@@ -1868,7 +1890,7 @@ yyreduce:
 
   case 34:
 
-/* Line 1464 of yacc.c  */
+/* Line 1821 of yacc.c  */
 #line 285 "command.y"
     {
                if (cmdtab[cmd_idx].class == D_FRAME
@@ -1879,7 +1901,7 @@ yyreduce:
 
   case 35:
 
-/* Line 1464 of yacc.c  */
+/* Line 1821 of yacc.c  */
 #line 291 "command.y"
     {
                int idx = find_argument((yyvsp[(2) - (2)]));
@@ -1896,49 +1918,49 @@ yyreduce:
 
   case 38:
 
-/* Line 1464 of yacc.c  */
+/* Line 1821 of yacc.c  */
 #line 304 "command.y"
     { want_nodeval = TRUE; }
     break;
 
   case 40:
 
-/* Line 1464 of yacc.c  */
+/* Line 1821 of yacc.c  */
 #line 305 "command.y"
     { want_nodeval = TRUE; }
     break;
 
   case 46:
 
-/* Line 1464 of yacc.c  */
+/* Line 1821 of yacc.c  */
 #line 310 "command.y"
     { want_nodeval = TRUE; }
     break;
 
   case 49:
 
-/* Line 1464 of yacc.c  */
+/* Line 1821 of yacc.c  */
 #line 312 "command.y"
     { want_nodeval = TRUE; }
     break;
 
   case 51:
 
-/* Line 1464 of yacc.c  */
+/* Line 1821 of yacc.c  */
 #line 313 "command.y"
     { want_nodeval = TRUE; }
     break;
 
   case 53:
 
-/* Line 1464 of yacc.c  */
+/* Line 1821 of yacc.c  */
 #line 314 "command.y"
     { want_nodeval = TRUE; }
     break;
 
   case 57:
 
-/* Line 1464 of yacc.c  */
+/* Line 1821 of yacc.c  */
 #line 318 "command.y"
     {
                if (in_cmd_src((yyvsp[(2) - (2)])->a_string))
@@ -1948,7 +1970,7 @@ yyreduce:
 
   case 58:
 
-/* Line 1464 of yacc.c  */
+/* Line 1821 of yacc.c  */
 #line 323 "command.y"
     {
                if (! input_from_tty)
@@ -1958,7 +1980,7 @@ yyreduce:
 
   case 59:
 
-/* Line 1464 of yacc.c  */
+/* Line 1821 of yacc.c  */
 #line 328 "command.y"
     {
                int type = 0;
@@ -1989,7 +2011,7 @@ yyreduce:
 
   case 60:
 
-/* Line 1464 of yacc.c  */
+/* Line 1821 of yacc.c  */
 #line 354 "command.y"
     {
                if (! in_commands)
@@ -2004,7 +2026,7 @@ yyreduce:
 
   case 61:
 
-/* Line 1464 of yacc.c  */
+/* Line 1821 of yacc.c  */
 #line 364 "command.y"
     {
                if (! in_commands)
@@ -2014,7 +2036,7 @@ yyreduce:
 
   case 62:
 
-/* Line 1464 of yacc.c  */
+/* Line 1821 of yacc.c  */
 #line 369 "command.y"
     {
                int idx = find_argument((yyvsp[(2) - (2)]));
@@ -2031,14 +2053,14 @@ yyreduce:
 
   case 63:
 
-/* Line 1464 of yacc.c  */
+/* Line 1821 of yacc.c  */
 #line 380 "command.y"
     { want_nodeval = TRUE; }
     break;
 
   case 64:
 
-/* Line 1464 of yacc.c  */
+/* Line 1821 of yacc.c  */
 #line 381 "command.y"
     {
                int type;
@@ -2051,7 +2073,7 @@ yyreduce:
 
   case 65:
 
-/* Line 1464 of yacc.c  */
+/* Line 1821 of yacc.c  */
 #line 389 "command.y"
     {
                if (in_commands) {
@@ -2067,7 +2089,7 @@ yyreduce:
 
   case 66:
 
-/* Line 1464 of yacc.c  */
+/* Line 1821 of yacc.c  */
 #line 403 "command.y"
     {
                if ((yyvsp[(1) - (1)]) != NULL) {
@@ -2082,42 +2104,42 @@ yyreduce:
 
   case 68:
 
-/* Line 1464 of yacc.c  */
+/* Line 1821 of yacc.c  */
 #line 417 "command.y"
     {  (yyval) = NULL; }
     break;
 
   case 69:
 
-/* Line 1464 of yacc.c  */
+/* Line 1821 of yacc.c  */
 #line 422 "command.y"
     { (yyval) = NULL; }
     break;
 
   case 74:
 
-/* Line 1464 of yacc.c  */
+/* Line 1821 of yacc.c  */
 #line 431 "command.y"
     { (yyval) = NULL; }
     break;
 
   case 75:
 
-/* Line 1464 of yacc.c  */
+/* Line 1821 of yacc.c  */
 #line 436 "command.y"
     { (yyval) = NULL; }
     break;
 
   case 77:
 
-/* Line 1464 of yacc.c  */
+/* Line 1821 of yacc.c  */
 #line 439 "command.y"
     { (yyval) = NULL; }
     break;
 
   case 78:
 
-/* Line 1464 of yacc.c  */
+/* Line 1821 of yacc.c  */
 #line 444 "command.y"
     {
                NODE *n;
@@ -2129,14 +2151,14 @@ yyreduce:
 
   case 79:
 
-/* Line 1464 of yacc.c  */
+/* Line 1821 of yacc.c  */
 #line 454 "command.y"
     { (yyval) = NULL; }
     break;
 
   case 80:
 
-/* Line 1464 of yacc.c  */
+/* Line 1821 of yacc.c  */
 #line 456 "command.y"
     {
                if (find_option((yyvsp[(1) - (1)])->a_string) < 0)
@@ -2146,7 +2168,7 @@ yyreduce:
 
   case 81:
 
-/* Line 1464 of yacc.c  */
+/* Line 1821 of yacc.c  */
 #line 461 "command.y"
     {
                if (find_option((yyvsp[(1) - (3)])->a_string) < 0)
@@ -2156,7 +2178,7 @@ yyreduce:
 
   case 82:
 
-/* Line 1464 of yacc.c  */
+/* Line 1821 of yacc.c  */
 #line 469 "command.y"
     {
                NODE *n;
@@ -2174,56 +2196,56 @@ yyreduce:
 
   case 83:
 
-/* Line 1464 of yacc.c  */
+/* Line 1821 of yacc.c  */
 #line 485 "command.y"
     { (yyval) = NULL; }
     break;
 
   case 88:
 
-/* Line 1464 of yacc.c  */
+/* Line 1821 of yacc.c  */
 #line 494 "command.y"
     { (yyval) = NULL; }
     break;
 
   case 89:
 
-/* Line 1464 of yacc.c  */
+/* Line 1821 of yacc.c  */
 #line 495 "command.y"
     { want_nodeval = TRUE; }
     break;
 
   case 92:
 
-/* Line 1464 of yacc.c  */
+/* Line 1821 of yacc.c  */
 #line 497 "command.y"
     { want_nodeval = TRUE; }
     break;
 
   case 95:
 
-/* Line 1464 of yacc.c  */
+/* Line 1821 of yacc.c  */
 #line 503 "command.y"
     { (yyval) = NULL; }
     break;
 
   case 97:
 
-/* Line 1464 of yacc.c  */
+/* Line 1821 of yacc.c  */
 #line 509 "command.y"
     { (yyval) = NULL; }
     break;
 
   case 99:
 
-/* Line 1464 of yacc.c  */
+/* Line 1821 of yacc.c  */
 #line 515 "command.y"
     { (yyval) = NULL; }
     break;
 
   case 104:
 
-/* Line 1464 of yacc.c  */
+/* Line 1821 of yacc.c  */
 #line 527 "command.y"
     {
                int idx = find_argument((yyvsp[(1) - (2)]));
@@ -2240,7 +2262,7 @@ yyreduce:
 
   case 106:
 
-/* Line 1464 of yacc.c  */
+/* Line 1821 of yacc.c  */
 #line 543 "command.y"
     {
                (yyvsp[(2) - (2)])->type = D_array;     /* dump all items */
@@ -2250,7 +2272,7 @@ yyreduce:
 
   case 107:
 
-/* Line 1464 of yacc.c  */
+/* Line 1821 of yacc.c  */
 #line 548 "command.y"
     {
                (yyvsp[(2) - (3)])->type = D_array;
@@ -2260,21 +2282,21 @@ yyreduce:
 
   case 117:
 
-/* Line 1464 of yacc.c  */
+/* Line 1821 of yacc.c  */
 #line 574 "command.y"
     { (yyval) = NULL; }
     break;
 
   case 118:
 
-/* Line 1464 of yacc.c  */
+/* Line 1821 of yacc.c  */
 #line 576 "command.y"
     { (yyval) = NULL; }
     break;
 
   case 119:
 
-/* Line 1464 of yacc.c  */
+/* Line 1821 of yacc.c  */
 #line 578 "command.y"
     {
                CMDARG *a;
@@ -2286,7 +2308,7 @@ yyreduce:
 
   case 126:
 
-/* Line 1464 of yacc.c  */
+/* Line 1821 of yacc.c  */
 #line 594 "command.y"
     {
                if ((yyvsp[(1) - (3)])->a_int > (yyvsp[(3) - (3)])->a_int)
@@ -2300,28 +2322,28 @@ yyreduce:
 
   case 127:
 
-/* Line 1464 of yacc.c  */
+/* Line 1821 of yacc.c  */
 #line 606 "command.y"
     { (yyval) = NULL; }
     break;
 
   case 134:
 
-/* Line 1464 of yacc.c  */
+/* Line 1821 of yacc.c  */
 #line 620 "command.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 135:
 
-/* Line 1464 of yacc.c  */
+/* Line 1821 of yacc.c  */
 #line 622 "command.y"
     { (yyval) = (yyvsp[(1) - (3)]); }
     break;
 
   case 137:
 
-/* Line 1464 of yacc.c  */
+/* Line 1821 of yacc.c  */
 #line 628 "command.y"
     {
                CMDARG *a;
@@ -2341,21 +2363,21 @@ yyreduce:
 
   case 139:
 
-/* Line 1464 of yacc.c  */
+/* Line 1821 of yacc.c  */
 #line 647 "command.y"
     { (yyval) = (yyvsp[(1) - (1)]); num_dim = 1; }
     break;
 
   case 140:
 
-/* Line 1464 of yacc.c  */
+/* Line 1821 of yacc.c  */
 #line 649 "command.y"
     {  (yyval) = (yyvsp[(1) - (2)]); num_dim++; }
     break;
 
   case 142:
 
-/* Line 1464 of yacc.c  */
+/* Line 1821 of yacc.c  */
 #line 655 "command.y"
     {
                NODE *n = (yyvsp[(2) - (2)])->a_node;
@@ -2369,7 +2391,7 @@ yyreduce:
 
   case 143:
 
-/* Line 1464 of yacc.c  */
+/* Line 1821 of yacc.c  */
 #line 664 "command.y"
     {
                /* a_string is array name, a_count is dimension count */
@@ -2381,14 +2403,14 @@ yyreduce:
 
   case 144:
 
-/* Line 1464 of yacc.c  */
+/* Line 1821 of yacc.c  */
 #line 674 "command.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 145:
 
-/* Line 1464 of yacc.c  */
+/* Line 1821 of yacc.c  */
 #line 676 "command.y"
     { 
                NODE *n = (yyvsp[(2) - (2)])->a_node;
@@ -2400,7 +2422,7 @@ yyreduce:
 
   case 146:
 
-/* Line 1464 of yacc.c  */
+/* Line 1821 of yacc.c  */
 #line 683 "command.y"
     { 
                NODE *n = (yyvsp[(2) - (2)])->a_node;
@@ -2414,35 +2436,35 @@ yyreduce:
 
   case 147:
 
-/* Line 1464 of yacc.c  */
+/* Line 1821 of yacc.c  */
 #line 695 "command.y"
     { (yyval) = NULL; }
     break;
 
   case 148:
 
-/* Line 1464 of yacc.c  */
+/* Line 1821 of yacc.c  */
 #line 697 "command.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 149:
 
-/* Line 1464 of yacc.c  */
+/* Line 1821 of yacc.c  */
 #line 702 "command.y"
     { (yyval) = NULL; }
     break;
 
   case 150:
 
-/* Line 1464 of yacc.c  */
+/* Line 1821 of yacc.c  */
 #line 704 "command.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 151:
 
-/* Line 1464 of yacc.c  */
+/* Line 1821 of yacc.c  */
 #line 709 "command.y"
     {
                if ((yyvsp[(1) - (1)])->a_int == 0)
@@ -2453,7 +2475,7 @@ yyreduce:
 
   case 152:
 
-/* Line 1464 of yacc.c  */
+/* Line 1821 of yacc.c  */
 #line 715 "command.y"
     {
                if ((yyvsp[(2) - (2)])->a_int == 0)
@@ -2464,21 +2486,21 @@ yyreduce:
 
   case 153:
 
-/* Line 1464 of yacc.c  */
+/* Line 1821 of yacc.c  */
 #line 724 "command.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 154:
 
-/* Line 1464 of yacc.c  */
+/* Line 1821 of yacc.c  */
 #line 726 "command.y"
     { (yyval) = (yyvsp[(2) - (2)]); }
     break;
 
   case 155:
 
-/* Line 1464 of yacc.c  */
+/* Line 1821 of yacc.c  */
 #line 728 "command.y"
     {
                (yyvsp[(2) - (2)])->a_int = - (yyvsp[(2) - (2)])->a_int;
@@ -2488,7 +2510,7 @@ yyreduce:
 
   case 156:
 
-/* Line 1464 of yacc.c  */
+/* Line 1821 of yacc.c  */
 #line 736 "command.y"
     {
                if (lexptr_begin != NULL) {
@@ -2502,10 +2524,21 @@ yyreduce:
 
 
 
-/* Line 1464 of yacc.c  */
-#line 2519 "command.c"
+/* Line 1821 of yacc.c  */
+#line 2541 "command.c"
       default: break;
     }
+  /* User semantic actions sometimes alter yychar, and that requires
+     that yytoken be updated with the new translation.  We take the
+     approach of translating immediately before every use of yytoken.
+     One alternative is translating here after every semantic action,
+     but that translation would be missed if the semantic action invokes
+     YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or
+     if it invokes YYBACKUP.  In the case of YYABORT or YYACCEPT, an
+     incorrect destructor might then be invoked immediately.  In the
+     case of YYERROR or YYBACKUP, subsequent parser actions might lead
+     to an incorrect destructor call or verbose syntax error message
+     before the lookahead is translated.  */
   YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
 
   YYPOPSTACK (yylen);
@@ -2533,6 +2566,10 @@ yyreduce:
 | yyerrlab -- here on detecting error |
 `------------------------------------*/
 yyerrlab:
+  /* Make sure we have latest lookahead translation.  See comments at
+     user semantic actions for why this is necessary.  */
+  yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar);
+
   /* If not already recovering from an error, report this error.  */
   if (!yyerrstatus)
     {
@@ -2540,37 +2577,36 @@ yyerrlab:
 #if ! YYERROR_VERBOSE
       yyerror (YY_("syntax error"));
 #else
+# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \
+                                        yyssp, yytoken)
       {
-       YYSIZE_T yysize = yysyntax_error (0, yystate, yychar);
-       if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM)
-         {
-           YYSIZE_T yyalloc = 2 * yysize;
-           if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM))
-             yyalloc = YYSTACK_ALLOC_MAXIMUM;
-           if (yymsg != yymsgbuf)
-             YYSTACK_FREE (yymsg);
-           yymsg = (char *) YYSTACK_ALLOC (yyalloc);
-           if (yymsg)
-             yymsg_alloc = yyalloc;
-           else
-             {
-               yymsg = yymsgbuf;
-               yymsg_alloc = sizeof yymsgbuf;
-             }
-         }
-
-       if (0 < yysize && yysize <= yymsg_alloc)
-         {
-           (void) yysyntax_error (yymsg, yystate, yychar);
-           yyerror (yymsg);
-         }
-       else
-         {
-           yyerror (YY_("syntax error"));
-           if (yysize != 0)
-             goto yyexhaustedlab;
-         }
+        char const *yymsgp = YY_("syntax error");
+        int yysyntax_error_status;
+        yysyntax_error_status = YYSYNTAX_ERROR;
+        if (yysyntax_error_status == 0)
+          yymsgp = yymsg;
+        else if (yysyntax_error_status == 1)
+          {
+            if (yymsg != yymsgbuf)
+              YYSTACK_FREE (yymsg);
+            yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc);
+            if (!yymsg)
+              {
+                yymsg = yymsgbuf;
+                yymsg_alloc = sizeof yymsgbuf;
+                yysyntax_error_status = 2;
+              }
+            else
+              {
+                yysyntax_error_status = YYSYNTAX_ERROR;
+                yymsgp = yymsg;
+              }
+          }
+        yyerror (yymsgp);
+        if (yysyntax_error_status == 2)
+          goto yyexhaustedlab;
       }
+# undef YYSYNTAX_ERROR
 #endif
     }
 
@@ -2629,7 +2665,7 @@ yyerrlab1:
   for (;;)
     {
       yyn = yypact[yystate];
-      if (yyn != YYPACT_NINF)
+      if (!yypact_value_is_default (yyn))
        {
          yyn += YYTERROR;
          if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
@@ -2688,8 +2724,13 @@ yyexhaustedlab:
 
 yyreturn:
   if (yychar != YYEMPTY)
-     yydestruct ("Cleanup: discarding lookahead",
-                yytoken, &yylval);
+    {
+      /* Make sure we have latest lookahead translation.  See comments at
+         user semantic actions for why this is necessary.  */
+      yytoken = YYTRANSLATE (yychar);
+      yydestruct ("Cleanup: discarding lookahead",
+                  yytoken, &yylval);
+    }
   /* Do not reclaim the symbols of the rule which action triggered
      this YYABORT or YYACCEPT.  */
   YYPOPSTACK (yylen);
@@ -2714,7 +2755,7 @@ yyreturn:
 
 
 
-/* Line 1684 of yacc.c  */
+/* Line 2067 of yacc.c  */
 #line 746 "command.y"
 
 
@@ -2722,7 +2763,7 @@ yyreturn:
 /* append_statement --- append 'stmt' to the list of eval awk statements */ 
 
 static CMDARG *
-append_statement(CMDARG *alist, char *stmt) 
+append_statement(CMDARG *stmt_list, char *stmt) 
 {
        CMDARG *a, *arg; 
        char *s;
@@ -2732,7 +2773,7 @@ append_statement(CMDARG *alist, char *stmt)
 
        if (stmt == start_EVAL) {
                len = sizeof(start_EVAL);
-               for (a = alist; a != NULL; a = a->next)
+               for (a = stmt_list; a != NULL; a = a->next)
                        len += strlen(a->a_string) + 1; /* 1 for ',' */
                len += EVALSIZE;
 
@@ -2744,7 +2785,7 @@ append_statement(CMDARG *alist, char *stmt)
                slen = sizeof("function @eval(") - 1;
                memcpy(s, start_EVAL, slen);
 
-               for (a = alist; a != NULL; a = a->next) {
+               for (a = stmt_list; a != NULL; a = a->next) {
                        len = strlen(a->a_string);
                        memcpy(s + slen, a->a_string, len);
                        slen += len;
@@ -2758,14 +2799,14 @@ append_statement(CMDARG *alist, char *stmt)
        }
                 
        len = strlen(stmt) + 1; /* 1 for newline */
-       s = alist->a_string;
+       s = stmt_list->a_string;
        slen = strlen(s);
-       ssize = alist->a_count;
+       ssize = stmt_list->a_count;
        if (len > ssize - slen) {
                ssize = slen + len + EVALSIZE;
                erealloc(s, char *, (ssize + 2) * sizeof(char), 
"append_statement");
-               alist->a_string = s;
-               alist->a_count = ssize;
+               stmt_list->a_string = s;
+               stmt_list->a_count = ssize;
        }
        memcpy(s + slen, stmt, len);
        slen += len;
@@ -2775,8 +2816,8 @@ append_statement(CMDARG *alist, char *stmt)
        }
 
        if (stmt == end_EVAL)
-               erealloc(alist->a_string, char *, slen + 2, "append_statement");
-       return alist;
+               erealloc(stmt_list->a_string, char *, slen + 2, 
"append_statement");
+       return stmt_list;
 
 #undef EVALSIZE
 }
@@ -3136,7 +3177,6 @@ again:
 
        if (c == '"') {
                char *str, *p;
-               int flags = ALREADY_MALLOCED;
                int esc_seen = FALSE;
 
                toklen = lexend - lexptr;
@@ -3165,14 +3205,16 @@ err:
 
                if (! want_nodeval) {
                        yylval = mk_cmdarg(D_string);
-                       yylval->a_string = estrdup(str, p - str);
+                       yylval->a_string = str;
                        append_cmdarg(yylval);
                        return D_STRING;
                } else {        /* awk string */
+                       size_t len;
+                       len = p - str;
                        if (esc_seen)
-                               flags |= SCAN;
+                               len = scan_escape(str, len);
                        yylval = mk_cmdarg(D_node);
-                       yylval->a_node = make_str_node(str, p - str, flags);
+                       yylval->a_node = make_str_node(str, len);
                        append_cmdarg(yylval);
                        return D_NODE;
                }
@@ -3322,7 +3364,7 @@ concat_args(CMDARG *arg, int count)
        }
        str[len] = '\0';
        efree(tmp);
-       return make_str_node(str, len, ALREADY_MALLOCED);
+       return make_str_node(str, len);
 }
 
 /* find_command --- find the index in 'cmdtab' using exact,
@@ -3356,8 +3398,10 @@ find_command(const char *token, size_t toklen)
                                && strncmp(name, token, toklen) == 0
                )
                        return i;
-               if (*name > *token)
+
+               if (*name > *token || i == (k - 1))
                        try_exact = FALSE;
+
                if (abrv_match < 0) {
                        abrv = cmdtab[i].abbrvn;
                        if (abrv[0] == token[0]) {
@@ -3497,6 +3541,7 @@ command_completion(const char *text, int start, int end)
                        return NULL;
                }
        }
+
        if (this_cmd == D_print || this_cmd == D_printf)
                return rl_completion_matches(text, variable_generator);
        return NULL;
@@ -3557,7 +3602,7 @@ argument_generator(const char *text, int state)
 {
        static size_t textlen;
        static int idx;
-       char *name;
+       const char *name;
 
        if (! state) {  /* first time */
                textlen = strlen(text);
@@ -3565,12 +3610,12 @@ argument_generator(const char *text, int state)
        }
 
        if (this_cmd == D_help) {
-               while ((name = (char *) cmdtab[idx++].name) != NULL) {
+               while ((name = cmdtab[idx++].name) != NULL) {
                        if (strncmp(name, text, textlen) == 0)
                                return estrdup(name, strlen(name));
                }
        } else {
-               while ((name = (char *) argtab[idx].name) != NULL) {
+               while ((name = argtab[idx].name) != NULL) {
                        if (this_cmd != argtab[idx++].cmd)
                                continue;
                        if (strncmp(name, text, textlen) == 0)
@@ -3587,45 +3632,39 @@ variable_generator(const char *text, int state)
 {
        static size_t textlen;
        static int idx = 0;
-       static char **pnames = NULL;
-       static NODE **var_table = NULL;
-       char *name;
-       NODE *hp;
+       static NODE *func = NULL;
+       static NODE **vars = NULL;
+       const char *name;
+       NODE *r;
 
        if (! state) {  /* first time */
                textlen = strlen(text);
-               if (var_table != NULL)
-                       efree(var_table);
-               var_table = get_varlist();
+               if (vars != NULL)
+                       efree(vars);
+               vars = variable_list();
                idx = 0;
-               pnames = get_parmlist();  /* names of function params in
-                                          * current context; the array
-                                          * is NULL terminated in
-                                          * awkgram.y (func_install).
-                                          */
+               func = get_function();  /* function in current context */
        }
 
        /* function params */
-       while (pnames != NULL) {
-               name = pnames[idx];
-               if (name == NULL) {
-                       pnames = NULL;  /* don't try to match params again */
+       while (func != NULL) {
+               if (idx >= func->param_cnt) {
+                       func = NULL;    /* don't try to match params again */
                        idx = 0;
                        break;
                }
-               idx++;
+               name = func->fparms[idx++].param;
                if (strncmp(name, text, textlen) == 0)
                        return estrdup(name, strlen(name));
        }
 
        /* globals */
-       while ((hp = var_table[idx]) != NULL) {
-               idx++;
-               if (hp->hvalue->type == Node_func)
-                       continue;
-               if (strncmp(hp->hname, text, textlen) == 0)
-                       return estrdup(hp->hname, hp->hlength);
+       while ((r = vars[idx++]) != NULL) {
+               name = r->vname;
+               if (strncmp(name, text, textlen) == 0)
+                       return estrdup(name, strlen(name));
        }
+
        return NULL;
 }
 
@@ -3651,4 +3690,3 @@ history_expand_line(char **line)
 
 #endif
 
-
diff --git a/command.y b/command.y
index bcaa74f..d2a61a0 100644
--- a/command.y
+++ b/command.y
@@ -50,7 +50,7 @@ static int num_dim;
 static int in_eval = FALSE;
 static const char start_EVAL[] = "function @eval(){";
 static const char end_EVAL[] = "}";    
-static CMDARG *append_statement(CMDARG *alist, char *stmt);
+static CMDARG *append_statement(CMDARG *stmt_list, char *stmt);
 static char *next_word(char *p, int len, char **endp);
 static NODE *concat_args(CMDARG *a, int count);
 
@@ -749,7 +749,7 @@ nls
 /* append_statement --- append 'stmt' to the list of eval awk statements */ 
 
 static CMDARG *
-append_statement(CMDARG *alist, char *stmt) 
+append_statement(CMDARG *stmt_list, char *stmt) 
 {
        CMDARG *a, *arg; 
        char *s;
@@ -759,7 +759,7 @@ append_statement(CMDARG *alist, char *stmt)
 
        if (stmt == start_EVAL) {
                len = sizeof(start_EVAL);
-               for (a = alist; a != NULL; a = a->next)
+               for (a = stmt_list; a != NULL; a = a->next)
                        len += strlen(a->a_string) + 1; /* 1 for ',' */
                len += EVALSIZE;
 
@@ -771,7 +771,7 @@ append_statement(CMDARG *alist, char *stmt)
                slen = sizeof("function @eval(") - 1;
                memcpy(s, start_EVAL, slen);
 
-               for (a = alist; a != NULL; a = a->next) {
+               for (a = stmt_list; a != NULL; a = a->next) {
                        len = strlen(a->a_string);
                        memcpy(s + slen, a->a_string, len);
                        slen += len;
@@ -785,14 +785,14 @@ append_statement(CMDARG *alist, char *stmt)
        }
                 
        len = strlen(stmt) + 1; /* 1 for newline */
-       s = alist->a_string;
+       s = stmt_list->a_string;
        slen = strlen(s);
-       ssize = alist->a_count;
+       ssize = stmt_list->a_count;
        if (len > ssize - slen) {
                ssize = slen + len + EVALSIZE;
                erealloc(s, char *, (ssize + 2) * sizeof(char), 
"append_statement");
-               alist->a_string = s;
-               alist->a_count = ssize;
+               stmt_list->a_string = s;
+               stmt_list->a_count = ssize;
        }
        memcpy(s + slen, stmt, len);
        slen += len;
@@ -802,8 +802,8 @@ append_statement(CMDARG *alist, char *stmt)
        }
 
        if (stmt == end_EVAL)
-               erealloc(alist->a_string, char *, slen + 2, "append_statement");
-       return alist;
+               erealloc(stmt_list->a_string, char *, slen + 2, 
"append_statement");
+       return stmt_list;
 
 #undef EVALSIZE
 }
@@ -1163,7 +1163,6 @@ again:
 
        if (c == '"') {
                char *str, *p;
-               int flags = ALREADY_MALLOCED;
                int esc_seen = FALSE;
 
                toklen = lexend - lexptr;
@@ -1192,14 +1191,16 @@ err:
 
                if (! want_nodeval) {
                        yylval = mk_cmdarg(D_string);
-                       yylval->a_string = estrdup(str, p - str);
+                       yylval->a_string = str;
                        append_cmdarg(yylval);
                        return D_STRING;
                } else {        /* awk string */
+                       size_t len;
+                       len = p - str;
                        if (esc_seen)
-                               flags |= SCAN;
+                               len = scan_escape(str, len);
                        yylval = mk_cmdarg(D_node);
-                       yylval->a_node = make_str_node(str, p - str, flags);
+                       yylval->a_node = make_str_node(str, len);
                        append_cmdarg(yylval);
                        return D_NODE;
                }
@@ -1349,7 +1350,7 @@ concat_args(CMDARG *arg, int count)
        }
        str[len] = '\0';
        efree(tmp);
-       return make_str_node(str, len, ALREADY_MALLOCED);
+       return make_str_node(str, len);
 }
 
 /* find_command --- find the index in 'cmdtab' using exact,
@@ -1383,8 +1384,10 @@ find_command(const char *token, size_t toklen)
                                && strncmp(name, token, toklen) == 0
                )
                        return i;
-               if (*name > *token)
+
+               if (*name > *token || i == (k - 1))
                        try_exact = FALSE;
+
                if (abrv_match < 0) {
                        abrv = cmdtab[i].abbrvn;
                        if (abrv[0] == token[0]) {
@@ -1524,6 +1527,7 @@ command_completion(const char *text, int start, int end)
                        return NULL;
                }
        }
+
        if (this_cmd == D_print || this_cmd == D_printf)
                return rl_completion_matches(text, variable_generator);
        return NULL;
@@ -1584,7 +1588,7 @@ argument_generator(const char *text, int state)
 {
        static size_t textlen;
        static int idx;
-       char *name;
+       const char *name;
 
        if (! state) {  /* first time */
                textlen = strlen(text);
@@ -1592,12 +1596,12 @@ argument_generator(const char *text, int state)
        }
 
        if (this_cmd == D_help) {
-               while ((name = (char *) cmdtab[idx++].name) != NULL) {
+               while ((name = cmdtab[idx++].name) != NULL) {
                        if (strncmp(name, text, textlen) == 0)
                                return estrdup(name, strlen(name));
                }
        } else {
-               while ((name = (char *) argtab[idx].name) != NULL) {
+               while ((name = argtab[idx].name) != NULL) {
                        if (this_cmd != argtab[idx++].cmd)
                                continue;
                        if (strncmp(name, text, textlen) == 0)
@@ -1614,45 +1618,39 @@ variable_generator(const char *text, int state)
 {
        static size_t textlen;
        static int idx = 0;
-       static char **pnames = NULL;
-       static NODE **var_table = NULL;
-       char *name;
-       NODE *hp;
+       static NODE *func = NULL;
+       static NODE **vars = NULL;
+       const char *name;
+       NODE *r;
 
        if (! state) {  /* first time */
                textlen = strlen(text);
-               if (var_table != NULL)
-                       efree(var_table);
-               var_table = get_varlist();
+               if (vars != NULL)
+                       efree(vars);
+               vars = variable_list();
                idx = 0;
-               pnames = get_parmlist();  /* names of function params in
-                                          * current context; the array
-                                          * is NULL terminated in
-                                          * awkgram.y (func_install).
-                                          */
+               func = get_function();  /* function in current context */
        }
 
        /* function params */
-       while (pnames != NULL) {
-               name = pnames[idx];
-               if (name == NULL) {
-                       pnames = NULL;  /* don't try to match params again */
+       while (func != NULL) {
+               if (idx >= func->param_cnt) {
+                       func = NULL;    /* don't try to match params again */
                        idx = 0;
                        break;
                }
-               idx++;
+               name = func->fparms[idx++].param;
                if (strncmp(name, text, textlen) == 0)
                        return estrdup(name, strlen(name));
        }
 
        /* globals */
-       while ((hp = var_table[idx]) != NULL) {
-               idx++;
-               if (hp->hvalue->type == Node_func)
-                       continue;
-               if (strncmp(hp->hname, text, textlen) == 0)
-                       return estrdup(hp->hname, hp->hlength);
+       while ((r = vars[idx++]) != NULL) {
+               name = r->vname;
+               if (strncmp(name, text, textlen) == 0)
+                       return estrdup(name, strlen(name));
        }
+
        return NULL;
 }
 
@@ -1677,4 +1675,3 @@ history_expand_line(char **line)
 }
 
 #endif
-
diff --git a/configure b/configure
index 2fc0835..aa4a04b 100755
--- a/configure
+++ b/configure
@@ -748,8 +748,15 @@ LDFLAGS
 LIBS
 CPPFLAGS
 CPP
+CPPFLAGS
 YACC
-YFLAGS'
+YFLAGS
+CC
+LDFLAGS
+LIBS
+CPPFLAGS
+CPP
+CPPFLAGS'
 
 
 # Initialize some variables set by options.
@@ -5488,7 +5495,7 @@ $as_echo_n "checking for special development options... " 
>&6; }
 if test -f $srcdir/.developing
 then
        # add other debug flags as appropriate, save GAWKDEBUG for emergencies
-       CFLAGS="$CFLAGS -DARRAYDEBUG -DYYDEBUG"
+       CFLAGS="$CFLAGS -DARRAYDEBUG"
        if grep dbug $srcdir/.developing
        then
                CFLAGS="$CFLAGS -DDBUG"
@@ -5498,7 +5505,7 @@ then
        # enable debugging using macros also
        if test "$GCC" = yes
        then
-               CFLAGS="$CFLAGS -Wall -fno-builtin -g3 -gdwarf-2"
+               CFLAGS="$CFLAGS -Wall"
        fi
        { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
 $as_echo "yes" >&6; }
diff --git a/configure.ac b/configure.ac
index d532963..4b266df 100644
--- a/configure.ac
+++ b/configure.ac
@@ -80,7 +80,7 @@ AC_MSG_CHECKING([for special development options])
 if test -f $srcdir/.developing
 then
        # add other debug flags as appropriate, save GAWKDEBUG for emergencies
-       CFLAGS="$CFLAGS -DARRAYDEBUG -DYYDEBUG"
+       CFLAGS="$CFLAGS -DARRAYDEBUG"
        if grep dbug $srcdir/.developing
        then
                CFLAGS="$CFLAGS -DDBUG"
@@ -90,7 +90,7 @@ then
        # enable debugging using macros also
        if test "$GCC" = yes
        then
-               CFLAGS="$CFLAGS -Wall -fno-builtin -g3 -gdwarf-2"
+               CFLAGS="$CFLAGS -Wall"
        fi
        AC_MSG_RESULT([yes])
 else
diff --git a/debug.c b/debug.c
index 9b9db34..a0ccdbd 100644
--- a/debug.c
+++ b/debug.c
@@ -43,8 +43,6 @@ extern int r_interpret(INSTRUCTION *);
 extern int zzparse(void);
 #define read_command()         (void) zzparse()
 
-extern int free_instruction(INSTRUCTION *, int *);
-extern void destroy_symbol(char *name);
 extern const char *redir2str(int redirtype);
 
 static char *linebuf = NULL;   /* used to print a single line of source */
@@ -266,7 +264,7 @@ static void save_options(const char *file);
 
 /* pager */
 jmp_buf pager_quit_tag;
-int pager_quit_tag_valid;
+int pager_quit_tag_valid = FALSE;
 static int screen_width = INT_MAX;     /* no of columns */
 static int screen_height = INT_MAX;    /* no of rows */
 static int pager_lines_printed = 0;    /* no of lines printed so far */ 
@@ -306,8 +304,8 @@ static struct list_item *add_item(struct list_item *list, 
int type, NODE *symbol
 static void delete_item(struct list_item *d);
 static int breakpoint_triggered(BREAKPOINT *b);
 static int watchpoint_triggered(struct list_item *w);
-
 static void print_instruction(INSTRUCTION *pc, Func_print print_func, FILE 
*fp, int in_dump);
+static int print_code(INSTRUCTION *pc, void *x);
 static void next_command();
 static char *g_readline(const char *prompt);
 static int prompt_yes_no(const char *, char , int , FILE *);
@@ -334,9 +332,6 @@ struct command_source
 
 static struct command_source *cmd_src = NULL;
 
-#define get_param_count(f)   (f)->lnode->param_cnt
-#define get_params(f)        (f)->parmlist
-
 
 #define CHECK_PROG_RUNNING() \
        do { \
@@ -718,6 +713,8 @@ list:
 int
 do_info(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
 {
+       NODE **table;
+
        if (arg == NULL || arg->type != D_argument)
                return FALSE;
 
@@ -803,7 +800,6 @@ do_info(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
                INSTRUCTION *pc;
                int arg_count, pcount;
                int i, from, to;
-               char **pnames;
 
                CHECK_PROG_RUNNING();
                f = find_frame(cur_frame);
@@ -814,8 +810,7 @@ do_info(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
                        return FALSE;
                }
 
-               pcount = get_param_count(func);        /* # of defined params */
-               pnames = get_params(func);             /* param names */
+               pcount = func->param_cnt;              /* # of defined params */
 
                pc = (INSTRUCTION *) f->reti;          /* Op_func_call 
instruction */
                arg_count = (pc + 1)->expr_count;      /* # of arguments 
supplied */
@@ -835,7 +830,7 @@ do_info(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
                        r = f->stack[i];
                        if (r->type == Node_array_ref)
                                r = r->orig_array;
-                       fprintf(out_fp, "%s = ", pnames[i]);
+                       fprintf(out_fp, "%s = ", func->fparms[i].param);
                        print_symbol(r, TRUE);
                }
                if (to < from)
@@ -847,25 +842,28 @@ do_info(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
                break;
 
        case A_VARIABLES:
+               table = variable_list();
                initialize_pager(out_fp);
                if (setjmp(pager_quit_tag) == 0) {
                        gprintf(out_fp, _("All defined variables:\n\n"));
-                       print_vars(gprintf, out_fp);
+                       print_vars(table, gprintf, out_fp);
                }
+               efree(table);
                break;
 
        case A_FUNCTIONS:
+               table = function_list(TRUE);
                initialize_pager(out_fp);
                if (setjmp(pager_quit_tag) == 0) {
                        gprintf(out_fp, _("All defined functions:\n\n"));
                        pf_data.print_func = gprintf;
                        pf_data.fp = out_fp;
                        pf_data.defn = TRUE;
-                       (void) foreach_func((int (*)(INSTRUCTION *, void *)) 
print_function,
-                                           FALSE, /* sort */
-                                           &pf_data /* data */
-                                          );
+                       (void) foreach_func(table,
+                                   (int (*)(INSTRUCTION *, void *)) 
print_function,
+                                   &pf_data);
                }
+               efree(table);
                break;
 
        case A_DISPLAY:
@@ -976,6 +974,7 @@ find_param(const char *name, long num, char **pname)
 {
        NODE *r = NULL;
        NODE *f;
+       char *fparam;
 
        if (pname)
                *pname = NULL;
@@ -985,20 +984,18 @@ find_param(const char *name, long num, char **pname)
        f = find_frame(num);
        if (f->func_node != NULL) {             /* in function */
                NODE *func;
-               char **pnames;
                int i, pcount;
 
                func = f->func_node;
-               pnames = get_params(func);
-               pcount = get_param_count(func);
-
+               pcount = func->param_cnt;
                for (i = 0; i < pcount; i++) {
-                       if (STREQ(name, pnames[i])) {
+                       fparam = func->fparms[i].param; 
+                       if (STREQ(name, fparam)) {
                                r = f->stack[i];
                                if (r->type == Node_array_ref)
                                        r = r->orig_array;
                                if (pname)
-                                       *pname = pnames[i];
+                                       *pname = fparam;
                                break;
                        }
                }
@@ -1058,7 +1055,7 @@ print_field(long field_num)
 static int
 print_array(volatile NODE *arr, char *arr_name)
 {
-       NODE *bucket;
+       NODE *subs;
        NODE **list;
        int i;
        size_t num_elems = 0;
@@ -1066,7 +1063,7 @@ print_array(volatile NODE *arr, char *arr_name)
        volatile int ret = 0;
        volatile jmp_buf pager_quit_tag_stack;
 
-       if (arr->var_array == NULL || arr->table_size == 0) {
+       if (array_empty(arr)) {
                gprintf(out_fp, _("array `%s' is empty\n"), arr_name);
                return 0;
        }
@@ -1079,12 +1076,12 @@ print_array(volatile NODE *arr, char *arr_name)
        PUSH_BINDING(pager_quit_tag_stack, pager_quit_tag, 
pager_quit_tag_valid);
        if (setjmp(pager_quit_tag) == 0) {
                for (i = 0; ret == 0 && i < num_elems; i++) {
-                       bucket = list[i];
-                       r = bucket->ahvalue;
+                       subs = list[i];
+                       r = *assoc_lookup((NODE *) arr, subs);
                        if (r->type == Node_var_array)
                                ret = print_array(r, r->vname);
                        else {
-                               gprintf(out_fp, "%s[\"%s\"] = ", arr_name, 
bucket->ahname_str);
+                               gprintf(out_fp, "%s[\"%s\"] = ", arr_name, 
subs->stptr);
                                valinfo((NODE *) r, gprintf, out_fp);
                        }
                }
@@ -1214,7 +1211,7 @@ do_set_var(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
                switch (r->type) {
                case Node_var_new:
                        r->type = Node_var;
-                       r->var_value = Nnull_string;
+                       r->var_value = dupnode(Nnull_string);
                        /* fall through */
                case Node_var:
                        lhs = &r->var_value;
@@ -1254,7 +1251,7 @@ do_set_var(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
                                else {
                                        arg = arg->next;
                                        val = arg->a_node;
-                                       lhs = assoc_lookup(r, subs, FALSE);
+                                       lhs = assoc_lookup(r, subs);
                                        unref(*lhs);
                                        *lhs = dupnode(val);
                                        fprintf(out_fp, "%s[\"%s\"] = ", name, 
subs->stptr);
@@ -1263,12 +1260,10 @@ do_set_var(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
                        } else {
                                if (value == NULL) {
                                        NODE *array;
-
-                                       getnode(array);
-                                       array->type = Node_var_array;
-                                       array->var_array = NULL;
+                                       array = make_array();
                                        array->vname = estrdup(subs->stptr, 
subs->stlen);
-                                       *assoc_lookup(r, subs, FALSE) = array;
+                                       array->parent_array = r;
+                                       *assoc_lookup(r, subs) = array;
                                        r = array;
                                } else if (value->type != Node_var_array) {
                                        d_error(_("attempt to use scalar 
`%s[\"%s\"]' as array"),
@@ -1305,7 +1300,7 @@ do_set_var(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
                break;
        }
        return FALSE;
-}              
+}
 
 /* find_item --- find an item in the watch/display list */
 
@@ -1377,14 +1372,18 @@ add_item(struct list_item *list, int type, NODE 
*symbol, char *pname)
                d->fcall_count = fcall_count - cur_frame;
        }
 
-       if (type == D_field) { /* field number */
+       if (type == D_field) {
+               /* field number */
                d->symbol = symbol;
                d->flags |= FIELD_NUM;
-       } else if (type == D_subscript) {       /* subscript */
+       } else if (type == D_subscript) {
+               /* subscript */
                d->symbol = symbol;
                d->flags |= SUBSCRIPT;
-       } else /* array or variable */
+       } else {
+               /* array or variable */
                d->symbol = symbol;
+       }
 
        /* add to list */
        d->next = list->next;
@@ -1429,7 +1428,7 @@ do_add_item(struct list_item *list, CMDARG *arg)
                        for (i = 0; i < count; i++) {
                                arg = arg->next;
                                subs[i] = dupnode(arg->a_node);
-                               (void) force_string(subs[i]);
+                               subs[i] = force_string(subs[i]);
                        }
                        item->subs = subs;
                        item->num_subs = count;
@@ -1597,7 +1596,6 @@ condition_triggered(struct condition *cndn)
 }
 
 
-
 static int
 find_subscript(struct list_item *item, NODE **ptr)
 {
@@ -1616,7 +1614,8 @@ find_subscript(struct list_item *item, NODE **ptr)
                else if (i < count - 1)
                        return -1;
        }
-       *ptr = r;
+       if (r != NULL)
+               *ptr = r;
        return 0;
 }
 
@@ -1646,8 +1645,7 @@ cmp_val(struct list_item *w, NODE *old, NODE *new)
                if (new->type == Node_val)      /* 7 */
                        return TRUE;
                /* new->type == Node_var_array */       /* 8 */
-               if (new->var_array != NULL)
-                       size = new->table_size;
+               size = new->table_size;
                if (w->cur_size == size)
                        return FALSE;
                return TRUE;
@@ -1721,7 +1719,7 @@ watchpoint_triggered(struct list_item *w)
                        w->flags &= ~CUR_IS_ARRAY;
                        w->cur_value = dupnode(t2);
                } else
-                       w->cur_size = (t2->var_array != NULL) ? t2->table_size 
: 0;
+                       w->cur_size = (t2->type == Node_var_array) ? 
t2->table_size : 0;
        } else if (! t1) { /* 1, 2 */
                w->old_value = 0;
                /* new != NULL */
@@ -1729,7 +1727,7 @@ watchpoint_triggered(struct list_item *w)
                        w->cur_value = dupnode(t2);
                else {
                        w->flags |= CUR_IS_ARRAY;
-                       w->cur_size = (t2->var_array != NULL) ? t2->table_size 
: 0;
+                       w->cur_size = (t2->type == Node_var_array) ? 
t2->table_size : 0;
                }
        } else /* if (t1->type == Node_val) */ {        /* 4, 5, 6 */
                w->old_value = w->cur_value;
@@ -1737,7 +1735,7 @@ watchpoint_triggered(struct list_item *w)
                        w->cur_value = 0;
                else if (t2->type == Node_var_array) {
                        w->flags |= CUR_IS_ARRAY;
-                       w->cur_size = (t2->var_array != NULL) ? t2->table_size 
: 0;
+                       w->cur_size = t2->table_size;
                } else
                        w->cur_value = dupnode(t2);
        }
@@ -1763,7 +1761,7 @@ initialize_watch_item(struct list_item *w)
                        w->cur_value = (NODE *) 0;
                else if (r->type == Node_var_array) { /* it's a sub-array */
                        w->flags |= CUR_IS_ARRAY;
-                       w->cur_size = (r->var_array != NULL) ? r->table_size : 
0;
+                       w->cur_size = r->table_size;
                } else
                        w->cur_value = dupnode(r);
        } else if (IS_FIELD(w)) {
@@ -1780,7 +1778,7 @@ initialize_watch_item(struct list_item *w)
                        w->cur_value = dupnode(r);
                } else if (symbol->type == Node_var_array) {
                        w->flags |= CUR_IS_ARRAY;
-                       w->cur_size = (symbol->var_array != NULL) ? 
symbol->table_size : 0;
+                       w->cur_size = symbol->table_size;
                } /* else
                        can't happen */
        }
@@ -1872,19 +1870,17 @@ print_function(INSTRUCTION *pc, void *x)
 {
        NODE *func;
        int i, pcount;
-       char **pnames;
        struct pf_data *data = (struct pf_data *) x;  
        int defn = data->defn;
        Func_print print_func = data->print_func;       
        FILE *fp = data->fp;
 
        func = pc->func_body;
-       pcount = get_param_count(func);
-       pnames = get_params(func);
+       pcount = func->param_cnt;
 
-       print_func(fp, "%s(", func->lnode->param);
+       print_func(fp, "%s(", func->vname);
        for (i = 0; i < pcount; i++) {
-               print_func(fp, "%s", pnames[i]);
+               print_func(fp, "%s", func->fparms[i].param);
                if (i < pcount - 1)               
                        print_func(fp, ", ");
        }
@@ -2350,7 +2346,7 @@ func:
                rp = func->code_ptr;
                if ((b = set_breakpoint_at(rp, rp->source_line, FALSE)) == NULL)
                        fprintf(out_fp, _("Can't set breakpoint in function 
`%s'\n"),
-                                               func->lnode->param);
+                                               func->vname);
                else if (temporary)
                        b->flags |= BP_TEMP;
                lineno = b->bpi->source_line;
@@ -2477,7 +2473,7 @@ func:
                }
                if (! bp_found)
                        fprintf(out_fp, _("No breakpoint(s) at entry to 
function `%s'\n"),
-                                       func->lnode->param);
+                                       func->vname);
                else
                        fprintf(out_fp, "\n");
                /* fall through */
@@ -2672,19 +2668,17 @@ do_disable_breakpoint(CMDARG *arg, int cmd 
ATTRIBUTE_UNUSED)
 
 #ifdef HAVE_LIBREADLINE
 
-/* get_parmlist --- list of function params in current context */
+/* get_function --- function definition in current context */
 
-char **
-get_parmlist()
+NODE *
+get_function()
 {
        NODE *func;
 
        if (! prog_running)
                return NULL;
        func = find_frame(cur_frame)->func_node;
-       if (func == NULL)       /* in main */
-               return NULL;
-       return func->parmlist;
+       return func;
 }
 
 /* initialize_readline --- initialize readline */
@@ -2915,9 +2909,9 @@ do_run(CMDARG *arg ATTRIBUTE_UNUSED, int cmd 
ATTRIBUTE_UNUSED)
        fatal_tag_valid = FALSE;
        prog_running = FALSE;
        fprintf(out_fp, _("Program exited %s with exit value: %d\n"),
-                                       (! exiting && exit_val != EXIT_SUCCESS) 
? "abnormally"
-                                                                               
: "normally",
-                                       exit_val);
+                       (! exiting && exit_val != EXIT_SUCCESS) ? "abnormally"
+                                                               : "normally",
+                       exit_val);
        need_restart = TRUE;
        return FALSE;
 }
@@ -3117,7 +3111,6 @@ do_next(CMDARG *arg, int cmd)
 static int
 check_nexti(INSTRUCTION **pi)
 {
-
        /* make sure not to step inside function calls */
 
        if (fcall_count < stop.fcall_count) {
@@ -3206,7 +3199,7 @@ check_return(INSTRUCTION **pi)
 int
 do_return(CMDARG *arg, int cmd)
 {
-       NODE *func;
+       NODE *func, *n;
 
        CHECK_PROG_RUNNING();
        func = find_frame(cur_frame)->func_node;
@@ -3223,12 +3216,11 @@ do_return(CMDARG *arg, int cmd)
 
        stop.check_func = check_return;
 
-       if (arg != NULL && arg->type == D_node) {       /* optional return 
value */
-               NODE *n;
+       if (arg != NULL && arg->type == D_node) /* optional return value */
                n = dupnode(arg->a_node);
-               PUSH(n);
-       } else
-               PUSH(Nnull_string);
+       else
+               n = dupnode(Nnull_string);
+       PUSH(n);
 
        return TRUE;
 }
@@ -3297,7 +3289,7 @@ do_until(CMDARG *arg, int cmd)
                s = source_find(arg->a_string);
                arg = arg->next;
                if (s == NULL || arg == NULL
-                       || (arg->type != D_int && arg->type != D_func))
+                               || (arg->type != D_int && arg->type != D_func))
                        return FALSE;
                src = s->src;
                if (arg->type == D_func)
@@ -3327,7 +3319,7 @@ func:
                        }
                }
                fprintf(out_fp, _("Can't find specified location in function 
`%s'\n"),
-                               func->lnode->param);
+                               func->vname);
                /* fall through */
        default:
                return FALSE;
@@ -3596,7 +3588,6 @@ pre_execute(INSTRUCTION **pi)
                return TRUE;
 
        case Op_func:
-       case Op_ext_func:
        case Op_var_update:
                return TRUE;
 
@@ -3631,7 +3622,7 @@ pre_execute(INSTRUCTION **pi)
 /* print_memory --- print a scalar value */
 
 static void 
-print_memory(NODE *m, char **fparms, Func_print print_func, FILE *fp)
+print_memory(NODE *m, NODE *func, Func_print print_func, FILE *fp)
 {
        switch (m->type) {
                case Node_val:
@@ -3658,8 +3649,8 @@ print_memory(NODE *m, char **fparms, Func_print 
print_func, FILE *fp)
                        break;
                        
                case Node_param_list:
-                       assert(fparms != NULL);
-                       print_func(fp, "%s", fparms[m->param_cnt]);
+                       assert(func != NULL);
+                       print_func(fp, "%s", func->fparms[m->param_cnt].param);
                        break;
 
                case Node_var:
@@ -3678,9 +3669,8 @@ print_memory(NODE *m, char **fparms, Func_print 
print_func, FILE *fp)
 static void
 print_instruction(INSTRUCTION *pc, Func_print print_func, FILE *fp, int 
in_dump)
 {
-       static char **fparms = NULL;
        int pcount = 0;
-       NODE *func = NULL;
+       static NODE *func = NULL;
        static int noffset = 0;
 
        if (noffset == 0) {
@@ -3691,25 +3681,17 @@ print_instruction(INSTRUCTION *pc, Func_print 
print_func, FILE *fp, int in_dump)
 
        if (pc->opcode == Op_func) {
                func = pc->func_body;
-               fparms = get_params(func);
-               pcount = get_param_count(func);
+               pcount = func->param_cnt;
                if (in_dump) {
                        int j;
-                       print_func(fp, "\n\t# Function: %s (", 
func->lnode->param);
+                       print_func(fp, "\n\t# Function: %s (", func->vname);
                        for (j = 0; j < pcount; j++) {
-                               print_func(fp, "%s", fparms[j]);
+                               print_func(fp, "%s", func->fparms[j].param);
                                if (j < pcount - 1)
                                        print_func(fp, ", ");
                        }
                        print_func(fp, ")\n\n");
                }
-       } else if (pc->opcode == Op_ext_func) {
-               func = pc->func_body;
-               fparms = get_params(func);
-               pcount = get_param_count(func);
-               if (in_dump)
-                       print_func(fp, "\n\t# Extension function: %s (... %d 
params ...)\n\n",
-                                               func->lnode->param, pcount);
        } else if (pc->opcode == Op_rule) {
                if (in_dump)
                        print_func(fp, "\n\t# %s\n\n", ruletab[pc->in_rule]);
@@ -3725,12 +3707,8 @@ print_instruction(INSTRUCTION *pc, Func_print 
print_func, FILE *fp, int in_dump)
                                pc->source_line, pc, opcode2str(pc->opcode));
 
        if (prog_running && ! in_dump) {
-               /* find params in the current frame */
+               /* find Node_func if in function */
                func = find_frame(0)->func_node;
-               if (func != NULL)
-                       fparms = get_params(func);
-               /* else
-                       fparms = NULL; */
        }
 
                        
@@ -3748,10 +3726,6 @@ print_instruction(INSTRUCTION *pc, Func_print 
print_func, FILE *fp, int in_dump)
                                pc->target_assign, pc->do_reference ? "TRUE" : 
"FALSE");
                break;
 
-       case Op_ext_func:
-               print_func(fp, "[param_cnt = %d]\n", pcount);
-               break; 
-
        case Op_func:
                print_func(fp, "[param_cnt = %d] [source_file = %s]\n", pcount,
                                pc->source_file ? pc->source_file : "cmd. 
line");
@@ -3816,7 +3790,7 @@ print_instruction(INSTRUCTION *pc, Func_print print_func, 
FILE *fp, int in_dump)
        case Op_arrayfor_incr:
                print_func(fp, "[array_var = %s] [target_jmp = %p]\n",
                                pc->array_var->type == Node_param_list ?
-                                  fparms[pc->array_var->param_cnt] : 
pc->array_var->vname,
+                                  func->fparms[pc->array_var->param_cnt].param 
: pc->array_var->vname,
                                pc->target_jmp);
                break;
 
@@ -3831,13 +3805,13 @@ print_instruction(INSTRUCTION *pc, Func_print 
print_func, FILE *fp, int in_dump)
                break;
 
        case Op_builtin:
-       {
-               const char *fname = getfname(pc->builtin);
-               if (fname == NULL)
-                       print_func(fp, "(extension func) [arg_count = %ld]\n", 
pc->expr_count);
-               else
-                       print_func(fp, "%s [arg_count = %ld]\n", fname, 
pc->expr_count);
-       }
+               print_func(fp, "%s [arg_count = %ld]\n", getfname(pc->builtin),
+                                               pc->expr_count);
+               break;
+
+       case Op_ext_builtin:
+               print_func(fp, "%s [arg_count = %ld]\n", (pc + 1)->func_name,
+                                               pc->expr_count);
                break;
 
        case Op_subscript:
@@ -3846,7 +3820,7 @@ print_instruction(INSTRUCTION *pc, Func_print print_func, 
FILE *fp, int in_dump)
                break;
 
        case Op_store_sub:
-               print_memory(pc->memory, fparms, print_func, fp);
+               print_memory(pc->memory, func, print_func, fp);
                print_func(fp, " [sub_count = %ld]\n", pc->expr_count);
                break;
 
@@ -3889,9 +3863,17 @@ print_instruction(INSTRUCTION *pc, Func_print 
print_func, FILE *fp, int in_dump)
                print_func(fp, "[exec_count = %ld]\n", pc->exec_count);
                break;
 
-       case Op_store_var:
+       case Op_store_var:
+               print_memory(pc->memory, func, print_func, fp);
+               if (pc->initval != NULL) {
+                       print_func(fp, " = ");
+                       print_memory(pc->initval, func, print_func, fp);
+               }
+               print_func(fp, "\n");
+               break;
+
        case Op_push_lhs:
-               print_memory(pc->memory, fparms, print_func, fp);
+               print_memory(pc->memory, func, print_func, fp);
                print_func(fp, " [do_reference = %s]\n",
                                pc->do_reference ? "TRUE" : "FALSE");
                break;
@@ -3912,7 +3894,7 @@ print_instruction(INSTRUCTION *pc, Func_print print_func, 
FILE *fp, int in_dump)
        case Op_quotient_i:
        case Op_mod_i:
        case Op_assign_concat:
-               print_memory(pc->memory, fparms, print_func, fp);
+               print_memory(pc->memory, func, print_func, fp);
                /* fall through */
        default:
                print_func(fp, "\n");
@@ -3950,7 +3932,8 @@ int
 do_dump_instructions(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
 {
        FILE *fp;
-  
+       NODE **funcs;
+
        if (arg != NULL && arg->type == D_string) {
                /* dump to a file */
                if ((fp = fopen(arg->a_string, "w")) == NULL) {
@@ -3962,25 +3945,27 @@ do_dump_instructions(CMDARG *arg, int cmd 
ATTRIBUTE_UNUSED)
                pf_data.fp = fp;
                pf_data.defn = TRUE;    /* in_dump = TRUE */
                (void) print_code(code_block, &pf_data);
-               (void) foreach_func((int (*)(INSTRUCTION *, void *)) print_code,
-                                    FALSE, /* sort */
-                                    &pf_data /* data */
-                                  );
+               funcs = function_list(TRUE);
+               (void) foreach_func(funcs,
+                                    (int (*)(INSTRUCTION *, void *)) 
print_code,
+                                    &pf_data);
+               efree(funcs);
                fclose(fp);
                return FALSE;
        }
 
+       funcs = function_list(TRUE);
        initialize_pager(out_fp);
        if (setjmp(pager_quit_tag) == 0) {
                pf_data.print_func = gprintf;
                pf_data.fp = out_fp;
                pf_data.defn = TRUE;    /* in_dump = TRUE */
                (void) print_code(code_block, &pf_data);
-               (void) foreach_func((int (*)(INSTRUCTION *, void *)) print_code,
-                                    FALSE,     /* sort */
-                                    &pf_data   /* data */
-                                  );
+               (void) foreach_func(funcs,
+                                   (int (*)(INSTRUCTION *, void *)) print_code,
+                                    &pf_data);
        }
+       efree(funcs);
        return FALSE;
 }
 
@@ -4901,7 +4886,7 @@ do_print_f(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
                                goto done;
 
                        for (; cnt > 0; cnt--) {
-                               NODE *value, *subs; 
+                               NODE *value, *subs;
                                a = a->next;
                                subs = a->a_node;
                                value = in_array(r, subs);
@@ -4939,7 +4924,7 @@ do_print_f(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
                }
        }
 
-       force_string(tmp[0]);
+       tmp[0] = force_string(tmp[0]);
 
        PUSH_BINDING(fatal_tag_stack, fatal_tag, fatal_tag_valid);
        if (setjmp(fatal_tag) == 0)
@@ -5282,35 +5267,6 @@ close_all()
        set_gawk_output(NULL);  /* closes output_fp if not stdout */ 
 }
 
-/* install_params --- install function parameters into the symbol table */
-
-static void
-install_params(NODE *func)
-{
-       NODE *np;
-
-       if (func == NULL)
-               return;
-       /* function parameters of type Node_param_list */
-       np = func->lnode;                               
-       for (np = np->rnode; np != NULL; np = np->rnode) 
-               install_symbol(np->param, np);          
-}
-
-/* remove_params --- remove function parameters out of the symbol table */
-
-static void
-remove_params(NODE *func)
-{
-       NODE *np;
-
-       if (func == NULL)
-               return;
-       np = func->lnode;                               
-       for (np = np->rnode; np != NULL; np = np->rnode)
-               remove_symbol(np->param);
-}
-
 /* pre_execute_code --- pre_hook for execute_code, called by pre_execute */
 
 static int
@@ -5353,23 +5309,25 @@ execute_code(volatile INSTRUCTION *code)
        volatile NODE *r = NULL;
        volatile jmp_buf fatal_tag_stack;
        STACK_ITEM *ctxt_stack_bottom;
+       int save_flags = do_flags;
 
        /* We use one global stack for all contexts.
         * Remember stack bottom for current context; in case of
         * a fatal error, unwind stack until stack_ptr is below that 'bottom'.
         */ 
        ctxt_stack_bottom = stack_ptr + 1;
+       do_flags = FALSE;
 
        PUSH_BINDING(fatal_tag_stack, fatal_tag, fatal_tag_valid);
        if (setjmp(fatal_tag) == 0) {
                (void) r_interpret((INSTRUCTION *) code);
-               assert(stack_ptr == ctxt_stack_bottom);
+               /* assert(stack_ptr == ctxt_stack_bottom); */
                r = POP_SCALAR();
        } else  /* fatal error */
                unwind_stack(ctxt_stack_bottom);
 
        POP_BINDING(fatal_tag_stack, fatal_tag, fatal_tag_valid);
-
+       do_flags = save_flags;
        if (exit_val != EXIT_SUCCESS) { /* must be EXIT_FATAL? */
                exit_val = EXIT_SUCCESS;
                return NULL;
@@ -5388,9 +5346,9 @@ do_eval(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
        NODE **sp;
        INSTRUCTION *eval, *code = NULL;
        AWK_CONTEXT *ctxt;
-       char **save_parmlist = NULL;
        int ecount = 0, pcount = 0;
        int ret;
+       int save_flags = do_flags;
        
        if (prog_running) {
                this_frame = find_frame(0);
@@ -5402,7 +5360,9 @@ do_eval(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
        ctxt->install_func = append_symbol;     /* keep track of newly 
installed globals */
        push_context(ctxt);
        (void) add_srcfile(SRC_CMDLINE, arg->a_string, srcfiles, NULL, NULL);
+       do_flags = FALSE;
        ret = parse_program(&code);
+       do_flags = save_flags;
        remove_params(this_func);
        if (ret != 0) {
                pop_context();  /* switch to prev context */
@@ -5424,9 +5384,7 @@ do_eval(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
        } else {
                /* execute as a part of the current function */ 
                int i;
-               char **varnames;
                INSTRUCTION *t;
-               NODE *np;
 
                eval = f->code_ptr;     /* Op_func */
                eval->source_file = cur_srcfile->src;
@@ -5435,9 +5393,8 @@ do_eval(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
                t->opcode = Op_stop;
 
                /* add or append eval locals to the current frame stack */
-               ecount = f->lnode->param_cnt;   /* eval local count */
-               pcount = this_func->lnode->param_cnt;
-               save_parmlist = this_func->parmlist;
+               ecount = f->param_cnt;  /* eval local count */
+               pcount = this_func->param_cnt;
                
                if (ecount > 0) {
                        if (pcount == 0)
@@ -5445,26 +5402,22 @@ do_eval(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
                        else
                                erealloc(this_frame->stack, NODE **, (pcount + 
ecount) * sizeof(NODE *), "do_eval");
 
-                       emalloc(varnames, char **, (pcount + ecount + 1) * 
sizeof(char *), "do_eval");
-                       if (pcount > 0) 
-                               memcpy(varnames, save_parmlist, pcount * 
sizeof(char *));
-                       for (np = f->lnode->rnode, i = 0; np != NULL; np = 
np->rnode, i++) {
-                               varnames[pcount + i] = np->param;
-                               np->param_cnt += pcount;        /* appending 
eval locals: fixup param_cnt */
-                       }
-                       varnames[pcount + ecount] = NULL;
                        sp = this_frame->stack + pcount;
                        for (i = 0; i < ecount; i++) {
+                               NODE *np;
+
+                               np = f->fparms + i;
+                               np->param_cnt += pcount;        /* appending 
eval locals: fixup param_cnt */
+
                                getnode(r);
                                memset(r, 0, sizeof(NODE));
                                *sp++ = r;
                                /* local variable */
                                r->type = Node_var_new;
-                               r->vname = varnames[pcount + i];
+                               r->vname = np->param;
                        }
 
-                       this_func->parmlist = varnames;
-                       this_func->lnode->param_cnt += ecount;
+                       this_func->param_cnt += ecount;
                }
        }
 
@@ -5504,9 +5457,7 @@ do_eval(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
                } /* else
                                restore_frame() will free it */
 
-               efree(this_func->parmlist);
-               this_func->parmlist = save_parmlist;
-               this_func->lnode->param_cnt -= ecount;
+               this_func->param_cnt -= ecount;
        }
 
        /* always destroy symbol "@eval", however destroy all newly installed
@@ -5516,7 +5467,7 @@ do_eval(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
        pop_context();  /* switch to prev context */
        free_context(ctxt, (ret_val != NULL));   /* free all instructions and 
optionally symbols */
        if (ret_val != NULL)
-               destroy_symbol("@eval");        /* destroy "@eval" */
+               destroy_symbol(f);      /* destroy "@eval" */
        return FALSE;
 }
 
@@ -5533,13 +5484,13 @@ an error message:
 
 static int invalid_symbol = 0;
 
-void
-check_symbol(char *name)
+static void
+check_symbol(NODE *r)
 {
        invalid_symbol++;
-       d_error(_("No symbol `%s' in current context"), name);
+       d_error(_("No symbol `%s' in current context"), r->vname);
        /* install anyway, but keep track of it */
-       append_symbol(name);
+       append_symbol(r);
 }
 
 /* parse_condition --- compile a condition expression */
@@ -5555,6 +5506,7 @@ parse_condition(int type, int num, char *expr)
        NODE *this_func = NULL;
        INSTRUCTION *it, *stop, *rule;
        struct condition *cndn = NULL;
+       int save_flags = do_flags;
 
        if (type == D_break && (b = find_breakpoint(num)) != NULL) {
                INSTRUCTION *rp;
@@ -5578,7 +5530,9 @@ parse_condition(int type, int num, char *expr)
        ctxt->install_func = check_symbol;
        push_context(ctxt);
        (void) add_srcfile(SRC_CMDLINE, expr, srcfiles, NULL, NULL);
+       do_flags = FALSE;
        ret = parse_program(&code);
+       do_flags = save_flags;
        remove_params(this_func); 
        pop_context();
 
@@ -5598,8 +5552,8 @@ parse_condition(int type, int num, char *expr)
 
        it = rule->firsti;      /* Op_K_print_rec */
        assert(it->opcode == Op_K_print_rec);
-       it->opcode = Op_push_i; 
-       it->memory = mk_number((AWKNUM) 1.0, PERM|NUMBER|NUMCUR);
+       it->opcode = Op_push_i;
+       it->memory = make_number(1.0);
        it->nexti = bcalloc(Op_jmp, 1, 0);
        it->nexti->target_jmp = stop;
        it->nexti->nexti = rule->lasti;
@@ -5607,7 +5561,7 @@ parse_condition(int type, int num, char *expr)
        it = rule->lasti;               /* Op_no_op, target for Op_jmp_false */
        assert(it->opcode == Op_no_op);
        it->opcode = Op_push_i;
-       it->memory = mk_number((AWKNUM) 0.0, PERM|NUMBER|NUMCUR);
+       it->memory = make_number(0.0);
        it->nexti = stop;
 
 out:
@@ -5687,7 +5641,7 @@ push_cmd_src(
        cs->str = NULL;
        cs->next = cmd_src;
        cmd_src = cs;
-
+       
        input_fd = fd;
        input_from_tty = istty;
        read_a_line = readfunc;
diff --git a/eval.c b/eval.c
index 4132474..8278371 100644
--- a/eval.c
+++ b/eval.c
@@ -262,9 +262,12 @@ static const char *const nodetypes[] = {
        "Node_var_new",
        "Node_param_list",
        "Node_func",
+       "Node_ext_func",
        "Node_hashnode",
-       "Node_ahash",
        "Node_array_ref",
+       "Node_array_tree",
+       "Node_array_leaf",
+       "Node_dump_array",
        "Node_arrayfor",
        "Node_frame",
        "Node_instruction",
@@ -348,6 +351,7 @@ static struct optypetab {
        { "Op_K_getline", "getline" },
        { "Op_K_nextfile", "nextfile" },
        { "Op_builtin", NULL },
+       { "Op_ext_builtin", NULL },
        { "Op_in_array", " in " },
        { "Op_func_call", NULL },
        { "Op_indirect_func_call", NULL },
@@ -375,7 +379,6 @@ static struct optypetab {
        { "Op_field_assign", NULL },
        { "Op_after_beginfile", NULL },
        { "Op_after_endfile", NULL },
-       { "Op_ext_func", NULL },
        { "Op_func", NULL },
        { "Op_exec_count", NULL },
        { "Op_breakpoint", NULL },
@@ -445,20 +448,19 @@ flags2str(int flagval)
 {
        static const struct flagtab values[] = {
                { MALLOC, "MALLOC" },
-               { PERM, "PERM" },
                { STRING, "STRING" },
                { STRCUR, "STRCUR" },
                { NUMCUR, "NUMCUR" },
                { NUMBER, "NUMBER" },
                { MAYBE_NUM, "MAYBE_NUM" },
-               { ARRAYMAXED, "ARRAYMAXED" },
-               { FUNC, "FUNC" },
                { FIELD, "FIELD" },
                { INTLSTR, "INTLSTR" },
-               { NUMIND, "NUMIND" },
-#ifdef WSTRCUR
+               { NUMINT, "NUMINT" },
+               { INTIND, "INTIND" },
                { WSTRCUR, "WSTRCUR" },
-#endif
+               { ARRAYMAXED, "ARRAYMAXED" },
+               { HALFHAT, "HALFHAT" },
+               { XARRAY, "XARRAY" },
                { 0,    NULL },
        };
 
@@ -483,7 +485,7 @@ genflags2str(int flagval, const struct flagtab *tab)
                         * the '|' character.
                         */
                        space_needed = (strlen(tab[i].name) + (sp != buffer));
-                       if (space_left < space_needed)
+                       if (space_left <= space_needed)
                                fatal(_("buffer overflow in genflags2str"));
 
                        if (sp != buffer) {
@@ -497,6 +499,7 @@ genflags2str(int flagval, const struct flagtab *tab)
                }
        }
 
+       *sp = '\0';
        return buffer;
 }
 
@@ -581,7 +584,6 @@ posix_compare(NODE *s1, NODE *s2)
        return ret;
 }
 
-
 /* cmp_nodes --- compare two nodes, returning negative, 0, positive */
 
 int
@@ -598,6 +600,11 @@ cmp_nodes(NODE *t1, NODE *t2)
                (void) force_number(t1);
        if (t2->flags & MAYBE_NUM)
                (void) force_number(t2);
+       if (t1->flags & INTIND)
+               t1 = force_string(t1);
+       if (t2->flags & INTIND)
+               t2 = force_string(t2);  
+
        if ((t1->flags & NUMBER) && (t2->flags & NUMBER)) {
                if (t1->numbr == t2->numbr)
                        ret = 0;
@@ -609,8 +616,8 @@ cmp_nodes(NODE *t1, NODE *t2)
                return ret;
        }
 
-       (void) force_string(t1);
-       (void) force_string(t2);
+       t1 = force_string(t1);
+       t2 = force_string(t2);
        len1 = t1->stlen;
        len2 = t2->stlen;
        ldiff = len1 - len2;
@@ -636,7 +643,9 @@ cmp_nodes(NODE *t1, NODE *t2)
                        ret = casetable[*cp1] - casetable[*cp2];
        } else
                ret = memcmp(t1->stptr, t2->stptr, l);
-       return (ret == 0 ? ldiff : ret);
+
+       ret = ret == 0 ? ldiff : ret;
+       return ret;
 }
 
 
@@ -728,9 +737,10 @@ set_IGNORECASE()
        if (do_traditional)
                IGNORECASE = FALSE;
        else if ((IGNORECASE_node->var_value->flags & (STRING|STRCUR)) != 0) {
-               if ((IGNORECASE_node->var_value->flags & MAYBE_NUM) == 0)
-                       IGNORECASE = 
(force_string(IGNORECASE_node->var_value)->stlen > 0);
-               else
+               if ((IGNORECASE_node->var_value->flags & MAYBE_NUM) == 0) {
+                       IGNORECASE_node->var_value = 
force_string(IGNORECASE_node->var_value);
+                       IGNORECASE = (IGNORECASE_node->var_value->stlen > 0);
+               } else
                        IGNORECASE = (force_number(IGNORECASE_node->var_value) 
!= 0.0);
        } else if ((IGNORECASE_node->var_value->flags & (NUMCUR|NUMBER)) != 0)
                IGNORECASE = (force_number(IGNORECASE_node->var_value) != 0.0);
@@ -823,7 +833,8 @@ set_BINMODE()
 void
 set_OFS()
 {
-       OFS = force_string(OFS_node->var_value)->stptr;
+       OFS_node->var_value = force_string(OFS_node->var_value);
+       OFS = OFS_node->var_value->stptr;
        OFSlen = OFS_node->var_value->stlen;
        OFS[OFSlen] = '\0';
 }
@@ -833,7 +844,8 @@ set_OFS()
 void
 set_ORS()
 {
-       ORS = force_string(ORS_node->var_value)->stptr;
+       ORS_node->var_value = force_string(ORS_node->var_value);
+       ORS = ORS_node->var_value->stptr;
        ORSlen = ORS_node->var_value->stlen;
        ORS[ORSlen] = '\0';
 }
@@ -849,6 +861,7 @@ fmt_ok(NODE *n)
 {
        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
@@ -890,7 +903,7 @@ fmt_index(NODE *n)
 
        if (fmt_list == NULL)
                emalloc(fmt_list, NODE **, fmt_num*sizeof(*fmt_list), 
"fmt_index");
-       (void) force_string(n);
+       n = force_string(n);
        while (ix < fmt_hiwater) {
                if (cmp_nodes(fmt_list[ix], n) == 0)
                        return ix;
@@ -942,41 +955,45 @@ set_LINT()
                if ((LINT_node->var_value->flags & MAYBE_NUM) == 0) {
                        const char *lintval;
                        size_t lintlen;
+                       NODE *tmp;
 
-                       do_lint = (force_string(LINT_node->var_value)->stlen > 
0);
-                       lintval = LINT_node->var_value->stptr;
-                       lintlen = LINT_node->var_value->stlen;
-                       if (do_lint) {
-                               do_lint = LINT_ALL;
+                       tmp = LINT_node->var_value = 
force_string(LINT_node->var_value);
+                       lintval = tmp->stptr;
+                       lintlen = tmp->stlen;
+                       if (lintlen > 0) {
+                               do_flags |= DO_LINT_ALL;
                                if (lintlen == 5 && strncmp(lintval, "fatal", 
5) == 0)
                                        lintfunc = r_fatal;
-                               else if (lintlen == 7 && strncmp(lintval, 
"invalid", 7) == 0)
-                                       do_lint = LINT_INVALID;
-                               else
+                               else if (lintlen == 7 && strncmp(lintval, 
"invalid", 7) == 0) {
+                                       do_flags &= ~ DO_LINT_ALL;
+                                       do_flags |= DO_LINT_INVALID;
+                               } else
                                        lintfunc = warning;
-                       } else
+                       } else {
+                               do_flags &= ~(DO_LINT_ALL|DO_LINT_INVALID);
                                lintfunc = warning;
+                       }
                } else {
                        if (force_number(LINT_node->var_value) != 0.0)
-                               do_lint = LINT_ALL;
+                               do_flags |= DO_LINT_ALL;
                        else
-                               do_lint = FALSE;
+                               do_flags &= ~(DO_LINT_ALL|DO_LINT_INVALID);
                        lintfunc = warning;
                }
        } else if ((LINT_node->var_value->flags & (NUMCUR|NUMBER)) != 0) {
                if (force_number(LINT_node->var_value) != 0.0)
-                       do_lint = LINT_ALL;
+                       do_flags |= DO_LINT_ALL;
                else
-                       do_lint = FALSE;
+                       do_flags &= ~(DO_LINT_ALL|DO_LINT_INVALID);
                lintfunc = warning;
        } else
-               do_lint = FALSE;                /* shouldn't happen */
+               do_flags &= ~(DO_LINT_ALL|DO_LINT_INVALID);     /* shouldn't 
happen */
 
        if (! do_lint)
                lintfunc = warning;
 
        /* explicitly use warning() here, in case lintfunc == r_fatal */
-       if (old_lint != do_lint && old_lint && do_lint == FALSE)
+       if (old_lint != do_lint && old_lint && ! do_lint)
                warning(_("turning off `--lint' due to assignment to `LINT'"));
 #endif /* ! NO_LINT */
 }
@@ -987,9 +1004,11 @@ void
 set_TEXTDOMAIN()
 {
        int len;
+       NODE *tmp;
 
-       TEXTDOMAIN = force_string(TEXTDOMAIN_node->var_value)->stptr;
-       len = TEXTDOMAIN_node->var_value->stlen;
+       tmp = TEXTDOMAIN_node->var_value = 
force_string(TEXTDOMAIN_node->var_value);
+       TEXTDOMAIN = tmp->stptr;
+       len = tmp->stlen;
        TEXTDOMAIN[len] = '\0';
        /*
         * Note: don't call textdomain(); this value is for
@@ -1057,7 +1076,6 @@ update_FNR()
 }
 
 
-
 NODE *frame_ptr;        /* current frame */
 STACK_ITEM *stack_ptr = NULL;
 STACK_ITEM *stack_bottom;
@@ -1079,17 +1097,10 @@ STACK_ITEM *
 grow_stack()
 {
        if (stack_ptr == NULL) {
-               char *val;
-
-               if ((val = getenv("GAWK_STACKSIZE")) != NULL) {
-                       if (isdigit((unsigned char) *val)) {
-                               unsigned long n = 0;
-                               for (; *val && isdigit((unsigned char) *val); 
val++)
-                                       n = (n * 10) + *val - '0';
-                               if (n >= 1)
-                                       STACK_SIZE = n;
-                       }
-               }
+               long newval;
+
+               if ((newval = getenv_long("GAWK_STACKSIZE")) > 0)
+                       STACK_SIZE = newval;
 
                emalloc(stack_bottom, STACK_ITEM *, STACK_SIZE * 
sizeof(STACK_ITEM), "grow_stack");
                stack_ptr = stack_bottom - 1;
@@ -1123,9 +1134,6 @@ r_get_lhs(NODE *n, int reference)
        int isparam = FALSE;
 
        if (n->type == Node_param_list) {
-               if ((n->flags & FUNC) != 0)
-                       fatal(_("can't use function name `%s' as variable or 
array"),
-                                       n->vname);
                isparam = TRUE;
                n = GET_PARAM(n->param_cnt);
        }
@@ -1139,11 +1147,11 @@ r_get_lhs(NODE *n, int reference)
                        fatal(_("attempt to use array `%s' in a scalar 
context"),
                                        array_vname(n));
                n->orig_array->type = Node_var;
-               n->orig_array->var_value = Nnull_string;
+               n->orig_array->var_value = dupnode(Nnull_string);
                /* fall through */
        case Node_var_new:
                n->type = Node_var;
-               n->var_value = Nnull_string;
+               n->var_value = dupnode(Nnull_string);
                break;
 
        case Node_var:
@@ -1164,7 +1172,7 @@ r_get_lhs(NODE *n, int reference)
                        _("reference to uninitialized argument `%s'") :
                        _("reference to uninitialized variable `%s'")),
                                n->vname);
-       return &n->var_value;
+       return & n->var_value;
 }
 
 
@@ -1245,15 +1253,13 @@ static void
 setup_frame(INSTRUCTION *pc)
 {
        NODE *r = NULL;
-       NODE *m;
-       NODE *f;
+       NODE *m, *f, *fp;
        NODE **sp = NULL;
-       char **varnames;
        int pcount, arg_count, i;
 
        f = pc->func_body;
-       pcount = f->lnode->param_cnt;
-       varnames = f->parmlist;
+       pcount = f->param_cnt;
+       fp = f->fparms;
        arg_count = (pc + 1)->expr_count;
 
        /* check for extra args */ 
@@ -1280,7 +1286,7 @@ setup_frame(INSTRUCTION *pc)
                if (i >= arg_count) {
                        /* local variable */
                        r->type = Node_var_new;
-                       r->vname = varnames[i];
+                       r->vname = fp[i].param;
                        continue;
                }
 
@@ -1307,8 +1313,9 @@ setup_frame(INSTRUCTION *pc)
                         * scalar during evaluation of expression for a
                         * subsequent param.
                         */
+                       /* fall through */
                        r->type = Node_var;
-                       r->var_value = Nnull_string;
+                       r->var_value = dupnode(Nnull_string);
                        break;
 
                case Node_val:
@@ -1319,7 +1326,7 @@ setup_frame(INSTRUCTION *pc)
                default:
                        cant_happen();
                }
-               r->vname = varnames[i];
+               r->vname = fp[i].param;
        }
        stack_adj(-arg_count);  /* adjust stack pointer */
 
@@ -1332,6 +1339,7 @@ setup_frame(INSTRUCTION *pc)
 
        /* save current frame in stack */
        PUSH(frame_ptr);
+
        /* setup new frame */
        getnode(frame_ptr);
        frame_ptr->type = Node_frame;   
@@ -1355,7 +1363,7 @@ restore_frame(NODE *fp)
        INSTRUCTION *ri;
 
        func = frame_ptr->func_node;
-       n = func->lnode->param_cnt;
+       n = func->param_cnt;
        sp = frame_ptr->stack;
 
        for (; n > 0; n--) {
@@ -1384,11 +1392,14 @@ restore_frame(NODE *fp)
 static inline void
 free_arrayfor(NODE *r)
 {
-       if (r->var_array != NULL) {
-               size_t num_elems = r->table_size;
-               NODE **list = r->var_array;
-               while (num_elems > 0)
-                       unref(list[--num_elems]);
+       if (r->for_list != NULL) {
+               NODE *n;
+               size_t num_elems = r->for_list_size;
+               NODE **list = r->for_list;
+               while (num_elems > 0) {
+                       n = list[--num_elems];
+                       unref(n);
+               }
                efree(list);
        }
        freenode(r);
@@ -1407,20 +1418,16 @@ unwind_stack(STACK_ITEM *sp_bottom)
                case Node_instruction:
                        freenode(r);
                        break;
-
                case Node_frame:
                        (void) restore_frame(r);
                        source = frame_ptr->vname;
                        break;
-
                case Node_arrayfor:
                        free_arrayfor(r);
                        break;
-
                case Node_val:
                        DEREF(r);
                        break;
-
                default:
                        if (in_main_context())
                                fatal(_("unwind_stack: unexpected type `%s'"),
@@ -1570,12 +1577,10 @@ POP_CODE()
  
  /* N.B.:
  *   1) reference counting done for both number and string values.
- *   2) TEMP flag no longer needed (consequence of the above; valref = 0
- *     is the replacement).
- *   3) Stack operations:
+ *   2) Stack operations:
  *       Use REPLACE[_XX] if last stack operation was TOP[_XX],
  *       PUSH[_XX] if last operation was POP[_XX] instead. 
- *   4) UPREF and DREF -- see awk.h 
+ *   3) UPREF and DREF -- see awk.h 
  */
 
 
@@ -1590,11 +1595,8 @@ r_interpret(INSTRUCTION *code)
        NODE *f;        /* function definition */
        NODE **lhs;
        AWKNUM x, x1, x2;
-       int di, pre = FALSE;
+       int di;
        Regexp *rp;
-#if defined(GAWKDEBUG) || defined(ARRAYDEBUG)
-       int last_was_stopme = FALSE;    /* builtin stopme() called ? */
-#endif
        int stdio_problem = FALSE;
 
        if (args_array == NULL)
@@ -1603,7 +1605,7 @@ r_interpret(INSTRUCTION *code)
                erealloc(args_array, NODE **, (max_args + 2)*sizeof(NODE *), 
"r_interpret");
 
 /* array subscript */
-#define mk_sub(n)      (n == 1 ? POP_STRING() : concat_exp(n, TRUE))
+#define mk_sub(n)      (n == 1 ? POP_SCALAR() : concat_exp(n, TRUE))
 
 #ifdef DEBUGGING
 #define JUMPTO(x)      do { post_execute(pc); pc = (x); goto top; } 
while(FALSE)
@@ -1636,7 +1638,6 @@ top:
                        currule = pc->in_rule;   /* for sole use in Op_K_next, 
Op_K_nextfile, Op_K_getline* */
                        /* fall through */
                case Op_func:
-               case Op_ext_func:
                        source = pc->source_file;
                        break;
 
@@ -1670,7 +1671,18 @@ top:
 
                case Op_push_i:
                        m = pc->memory;
-                       PUSH((m->flags & INTLSTR) != 0 ? format_val(CONVFMT, 
CONVFMTidx, m): m);
+                       if (! do_traditional && (m->flags & INTLSTR) != 0) {
+                               char *orig, *trans, save;
+
+                               save = m->stptr[m->stlen];
+                               m->stptr[m->stlen] = '\0';
+                               orig = m->stptr;
+                               trans = dgettext(TEXTDOMAIN, orig);
+                               m->stptr[m->stlen] = save;
+                               m = make_string(trans, strlen(trans));
+                       } else
+                               UPREF(m);
+                       PUSH(m);
                        break;
 
                case Op_push:
@@ -1681,9 +1693,6 @@ top:
 
                        save_symbol = m = pc->memory;
                        if (m->type == Node_param_list) {
-                               if ((m->flags & FUNC) != 0)
-                                       fatal(_("can't use function name `%s' 
as variable or array"),
-                                                       m->vname);
                                isparam = TRUE;
                                save_symbol = m = GET_PARAM(m->param_cnt);
                                if (m->type == Node_array_ref)
@@ -1704,13 +1713,14 @@ top:
 
                        case Node_var_new:
                                m->type = Node_var;
-                               m->var_value = Nnull_string;
+                               m->var_value = dupnode(Nnull_string);
                                if (do_lint)
                                        lintwarn(isparam ?
                                                _("reference to uninitialized 
argument `%s'") :
                                                _("reference to uninitialized 
variable `%s'"),
                                                                
save_symbol->vname);
-                               PUSH(Nnull_string);
+                               m = dupnode(Nnull_string);
+                               PUSH(m);
                                break;
 
                        case Node_var_array:
@@ -1751,7 +1761,16 @@ top:
                case Op_subscript:
                        t2 = mk_sub(pc->sub_count);
                        t1 = POP_ARRAY();
-                       r = *assoc_lookup(t1, t2, TRUE);
+
+                       if (do_lint && in_array(t1, t2) == NULL) {
+                               t2 = force_string(t2);
+                               lintwarn(_("reference to uninitialized element 
`%s[\"%.*s\"]'"),
+                                       array_vname(t1), (int) t2->stlen, 
t2->stptr);
+                               if (t2->stlen == 0)
+                                       lintwarn(_("subscript of array `%s' is 
null string"), array_vname(t1));
+                       }
+
+                       r = *assoc_lookup(t1, t2);
                        DEREF(t2);
                        if (r->type == Node_val)
                                UPREF(r);
@@ -1763,15 +1782,17 @@ top:
                        t1 = POP_ARRAY();
                        r = in_array(t1, t2);
                        if (r == NULL) {
-                               getnode(r);
-                               r->type = Node_var_array;
-                               r->var_array = NULL;
-                               r->vname = estrdup(t2->stptr, t2->stlen);       
/* the subscript in parent array */
+                               r = make_array();
                                r->parent_array = t1;
-                               *assoc_lookup(t1, t2, FALSE) = r;
-                       } else if (r->type != Node_var_array)
+                               *assoc_lookup(t1, t2) = r;
+                               t2 = force_string(t2);
+                               r->vname = estrdup(t2->stptr, t2->stlen);       
/* the subscript in parent array */
+                       } else if (r->type != Node_var_array) {
+                               t2 = force_string(t2);
                                fatal(_("attempt to use scalar `%s[\"%.*s\"]' 
as an array"),
                                                array_vname(t1), (int) 
t2->stlen, t2->stptr);
+                       }
+
                        DEREF(t2);
                        PUSH(r);
                        break;
@@ -1779,10 +1800,22 @@ top:
                case Op_subscript_lhs:
                        t2 = mk_sub(pc->sub_count);
                        t1 = POP_ARRAY();
-                       lhs = assoc_lookup(t1, t2, pc->do_reference);
-                       if ((*lhs)->type == Node_var_array)
+                       if (do_lint && in_array(t1, t2) == NULL) {
+                               t2 = force_string(t2);
+                               if (pc->do_reference) 
+                                       lintwarn(_("reference to uninitialized 
element `%s[\"%.*s\"]'"),
+                                               array_vname(t1), (int) 
t2->stlen, t2->stptr);
+                               if (t2->stlen == 0)
+                                       lintwarn(_("subscript of array `%s' is 
null string"), array_vname(t1));
+                       }
+
+                       lhs = assoc_lookup(t1, t2);
+                       if ((*lhs)->type == Node_var_array) {
+                               t2 = force_string(t2);
                                fatal(_("attempt to use array `%s[\"%.*s\"]' in 
a scalar context"),
                                                array_vname(t1), (int) 
t2->stlen, t2->stptr);
+                       }
+
                        DEREF(t2);
                        PUSH_ADDRESS(lhs);
                        break;
@@ -1792,10 +1825,6 @@ top:
                        lhs = r_get_field(t1, (Func_ptr *) 0, TRUE);
                        decr_sp();
                        DEREF(t1);
-                       /* This used to look like this:
-                           PUSH(dupnode(*lhs));
-                          but was changed to bypass an apparent bug in the 
z/OS C compiler.
-                          Please do not remerge.  */
                        r = dupnode(*lhs);     /* can't use UPREF here */
                        PUSH(r);
                        break;
@@ -1868,39 +1897,39 @@ top:
                        break;
 
                case Op_not:
-                       t1 = TOP_SCALAR(); 
+                       t1 = TOP_SCALAR();
                        r = make_number((AWKNUM) ! eval_condition(t1));
                        DEREF(t1);
                        REPLACE(r);
                        break;
 
                case Op_equal:
-                       r = make_number((AWKNUM) (cmp_scalar() == 0));
+                       r = make_number((AWKNUM) cmp_scalar() == 0);
                        REPLACE(r);
                        break;
 
                case Op_notequal:
-                       r = make_number((AWKNUM) (cmp_scalar() != 0));
+                       r = make_number((AWKNUM) cmp_scalar() != 0);
                        REPLACE(r);
                        break;
 
                case Op_less:
-                       r = make_number((AWKNUM) (cmp_scalar() < 0));
+                       r = make_number((AWKNUM) cmp_scalar() < 0);
                        REPLACE(r);
                        break;
 
                case Op_greater:
-                       r = make_number((AWKNUM) (cmp_scalar() > 0));
+                       r = make_number((AWKNUM) cmp_scalar() > 0);
                        REPLACE(r);
                        break;
 
                case Op_leq:
-                       r = make_number((AWKNUM) (cmp_scalar() <= 0));
+                       r = make_number((AWKNUM) cmp_scalar() <= 0);
                        REPLACE(r);
                        break;
 
                case Op_geq:
-                       r = make_number((AWKNUM) (cmp_scalar() >= 0));
+                       r = make_number((AWKNUM) cmp_scalar() >= 0);
                        REPLACE(r);
                        break;
 
@@ -1991,27 +2020,30 @@ mod:
                        break;          
 
                case Op_preincrement:
-                       pre = TRUE;
-               case Op_postincrement:
-                       x2 = 1.0;
-post:
+               case Op_predecrement:
+                       x2 = pc->opcode == Op_preincrement ? 1.0 : -1.0;
                        lhs = TOP_ADDRESS();
                        x1 = force_number(*lhs);
+                       x = x1 + x2;
+                       r = make_number(x);
                        unref(*lhs);
-                       r = *lhs = make_number(x1 + x2);
-                       if (pre)
-                               UPREF(r);
-                       else
-                               r = make_number(x1);
+                       *lhs = r;
+                       UPREF(r);
                        REPLACE(r);
-                       pre = FALSE;
-                       break;                  
+                       break;
 
-               case Op_predecrement:
-                       pre = TRUE;
+               case Op_postincrement:
                case Op_postdecrement:
-                       x2 = -1.0;
-                       goto post;                                      
+                       x2 = pc->opcode == Op_postincrement ? 1.0 : -1.0;
+                       lhs = TOP_ADDRESS();
+                       x1 = force_number(*lhs);
+                       x = x1 + x2;
+                       t1 = make_number(x);
+                       r = make_number(x1);
+                       unref(*lhs);
+                       *lhs = t1;
+                       REPLACE(r);
+                       break;
 
                case Op_unary_minus:
                        TOP_NUMBER(x1);
@@ -2025,10 +2057,12 @@ post:
                         */
                        t1 = get_array(pc->memory, TRUE);       /* array */
                        t2 = mk_sub(pc->expr_count);    /* subscript */
-                       lhs = assoc_lookup(t1, t2, FALSE);
-                       if ((*lhs)->type == Node_var_array)
+                       lhs = assoc_lookup(t1, t2);
+                       if ((*lhs)->type == Node_var_array) {
+                               t2 = force_string(t2);
                                fatal(_("attempt to use array `%s[\"%.*s\"]' in 
a scalar context"),
                                                array_vname(t1), (int) 
t2->stlen, t2->stptr);
+                       }
                        DEREF(t2);
                        unref(*lhs);
                        *lhs = POP_SCALAR();
@@ -2041,7 +2075,13 @@ post:
        
                        lhs = get_lhs(pc->memory, FALSE);
                        unref(*lhs);
-                       *lhs = POP_SCALAR();
+                       r = pc->initval;
+                       if (r == NULL)
+                               *lhs = POP_SCALAR();
+                       else {
+                               UPREF(r);
+                               *lhs = r;
+                       }
                        break;
 
                case Op_store_field:
@@ -2070,12 +2110,19 @@ post:
 
                        free_wstr(*lhs);
 
-                       if (t1 != t2 && t1->valref == 1 && (t1->flags & PERM) 
== 0) {
+                       if (t1 != *lhs) {
+                               unref(*lhs);
+                               *lhs = dupnode(t1);
+                       }
+
+                       if (t1 != t2 && t1->valref == 1) {
                                size_t nlen = t1->stlen + t2->stlen;
+
                                erealloc(t1->stptr, char *, nlen + 2, 
"r_interpret");
                                memcpy(t1->stptr + t1->stlen, t2->stptr, 
t2->stlen);
                                t1->stlen = nlen;
                                t1->stptr[nlen] = '\0';
+                               t1->flags &= ~(NUMCUR|NUMBER|NUMINT);
                        } else {
                                size_t nlen = t1->stlen + t2->stlen;  
                                char *p;
@@ -2084,9 +2131,8 @@ post:
                                memcpy(p, t1->stptr, t1->stlen);
                                memcpy(p + t1->stlen, t2->stptr, t2->stlen);
                                unref(*lhs);
-                               t1 = *lhs = make_str_node(p, nlen,  
ALREADY_MALLOCED); 
+                               t1 = *lhs = make_str_node(p, nlen); 
                        }
-                       t1->flags &= ~(NUMCUR|NUMBER);
                        DEREF(t2);
                        break;
 
@@ -2129,9 +2175,10 @@ post:
                case Op_K_case:
                        if ((pc + 1)->match_exp) {
                                /* match a constant regex against switch 
expression instead of $0. */
+
                                m = POP();      /* regex */
                                t2 = TOP_SCALAR();      /* switch expression */
-                               (void) force_string(t2);
+                               t2 = force_string(t2);
                                rp = re_update(m);
                                di = (research(rp, t2->stptr, 0, t2->stlen,
                                                        avoid_dfa(m, t2->stptr, 
t2->stlen)) >= 0);
@@ -2142,8 +2189,10 @@ post:
                                DEREF(t1);
                        }
 
-                       if (di) {       /* match found */
-                               decr_sp();
+                       if (di) {
+                               /* match found */
+
+                               t2 = POP_SCALAR();
                                DEREF(t2);
                                JUMPTO(pc->target_jmp);
                        }
@@ -2170,6 +2219,11 @@ post:
                        break;
 
                case Op_arrayfor_init:
+#define idx_list       sub.nodep.r.av
+#define num_idx                sub.nodep.reflags
+#define cur_idx                sub.nodep.l.ll
+#define for_array      sub.nodep.rn
+
                {
                        NODE **list = NULL;
                        NODE *array, *sort_str;
@@ -2181,7 +2235,7 @@ post:
                        array = POP_ARRAY();
 
                        /* sanity: check if empty */
-                       if (array->var_array == NULL || array->table_size == 0)
+                       if (array_empty(array))
                                goto arrayfor;
 
                        num_elems = array->table_size;
@@ -2204,19 +2258,14 @@ post:
                        }
 
                        list = assoc_list(array, how_to_sort, SORTED_IN);
-
-                       /*
-                        * Actual array for use in lint warning
-                        * in Op_arrayfor_incr
-                         */
-                       list[num_elems] = array;
-
+ 
 arrayfor:
                        getnode(r);
                        r->type = Node_arrayfor;
-                       r->var_array = list;
-                       r->table_size = num_elems;     /* # of elements in list 
*/
-                       r->array_size = -1;            /* current index */
+                       r->for_list = list;
+                       r->for_list_size = num_elems;           /* # of 
elements in list */
+                       r->cur_idx = -1;                        /* current 
index */
+                       r->for_array = array;           /* array */
                        PUSH(r);
 
                        if (num_elems == 0)
@@ -2226,20 +2275,20 @@ arrayfor:
 
                case Op_arrayfor_incr:
                        r = TOP();      /* Node_arrayfor */
-                       if (++r->array_size == r->table_size) {
+                       if (++r->cur_idx == r->for_list_size) {
                                NODE *array;
-                               array = r->var_array[r->table_size];    /* 
actual array */
-                               if (do_lint && array->table_size != 
r->table_size)
+                               array = r->for_array;   /* actual array */
+                               if (do_lint && array->table_size != 
r->for_list_size)
                                        lintwarn(_("for loop: array `%s' 
changed size from %ld to %ld during loop execution"),
-                                               array_vname(array), (long) 
r->table_size, (long) array->table_size);
+                                               array_vname(array), (long) 
r->for_list_size, (long) array->table_size);
                                JUMPTO(pc->target_jmp); /* Op_arrayfor_final */
                        }
 
-                       t1 = r->var_array[r->array_size];
+                       t1 = r->for_list[r->cur_idx];
                        lhs = get_lhs(pc->array_var, FALSE);
                        unref(*lhs);
-                       *lhs = make_string(t1->ahname_str, t1->ahname_len);
-                       break;                   
+                       *lhs = dupnode(t1);
+                       break;
 
                case Op_arrayfor_final:
                        r = POP();
@@ -2249,12 +2298,23 @@ arrayfor:
 
                case Op_builtin:
                        r = pc->builtin(pc->expr_count);
-#if defined(GAWKDEBUG) || defined(ARRAYDEBUG)
-                       if (! r)
-                               last_was_stopme = TRUE;
-                       else
-#endif
-                               PUSH(r);
+                       PUSH(r);
+                       break;
+
+               case Op_ext_builtin:
+               {
+                       int arg_count = pc->expr_count;
+
+                       PUSH_CODE(pc);
+                       r = pc->builtin(arg_count);
+                       (void) POP_CODE();
+                       while (arg_count-- > 0) {
+                               t1 = POP();
+                               if (t1->type == Node_val)
+                                       DEREF(t1);
+                       }
+                       PUSH(r);
+               }
                        break;
                        
                case Op_K_print:
@@ -2329,18 +2389,20 @@ match_re:
                        arg_count = (pc + 1)->expr_count;
                        t1 = PEEK(arg_count);   /* indirect var */
                        assert(t1->type == Node_val);   /* @a[1](p) not allowed 
in grammar */
-                       (void) force_string(t1);
+                       t1 = force_string(t1);
                        if (t1->stlen > 0) {
                                /* retrieve function definition node */
                                f = pc->func_body;
-                               if (f != NULL && STREQ(f->vname, t1->stptr))
+                               if (f != NULL && STREQ(f->vname, t1->stptr)) {
                                        /* indirect var hasn't been reassigned 
*/
                                        goto func_call;
+                               }
                                f = lookup(t1->stptr);
                        }
 
                        if (f == NULL || f->type != Node_func)
-                               fatal(_("function called indirectly through 
`%s' does not exist"), pc->func_name);      
+                               fatal(_("function called indirectly through 
`%s' does not exist"),
+                                               pc->func_name); 
                        pc->func_body = f;     /* save for next call */
 
                        goto func_call;
@@ -2351,28 +2413,35 @@ match_re:
                        f = pc->func_body;
                        if (f == NULL) {
                                f = lookup(pc->func_name);
-                               if (f == NULL || f->type != Node_func)
+                               if (f == NULL || (f->type != Node_func && 
f->type != Node_ext_func))
                                        fatal(_("function `%s' not defined"), 
pc->func_name);
                                pc->func_body = f;     /* save for next call */
                        }
 
-                       /* save current frame along with source */
+                       if (f->type == Node_ext_func) {
+                               INSTRUCTION *bc;
+                               char *fname = pc->func_name;
+                               int arg_count = (pc + 1)->expr_count;
+
+                               bc = f->code_ptr;
+                               assert(bc->opcode == Op_symbol);
+                               pc->opcode = Op_ext_builtin;    /* self 
modifying code */
+                               pc->builtin = bc->builtin;
+                               pc->expr_count = arg_count;             /* 
actual argument count */
+                               (pc + 1)->func_name = fname;    /* name of the 
builtin */
+                               (pc + 1)->expr_count = bc->expr_count;  /* 
defined max # of arguments */
+                               ni = pc; 
+                               JUMPTO(ni);
+                       }
 
 func_call:
-                       frame_ptr->vname = source;          /* save current 
source */
-                       setup_frame(pc);
-
-                       ni = f->code_ptr;       /* function code */             
                                        
-                       if (ni->opcode == Op_ext_func) {
-                               /* dynamically set source and line numbers for 
an extension builtin. */
-                               ni->source_file = source;
-                               ni->source_line = sourceline;
-                               ni->nexti->source_line = sourceline;    /* 
Op_builtin */
-                               ni->nexti->nexti->source_line = sourceline;     
/* Op_K_return */
-                       }
+                       ni = f->code_ptr;       /* function code */
 
+                       /* save current frame along with source */
+                       frame_ptr->vname = source;
+                       setup_frame(pc);
                        /* run the function instructions */
-                       JUMPTO(ni);             /* Op_func or Op_ext_func */
+                       JUMPTO(ni);             /* Op_func */
 
                case Op_K_return:
                        m = POP_SCALAR();       /* return value */
@@ -2536,15 +2605,8 @@ func_call:
                        JUMPTO(pc->target_jmp);
 
                case Op_pop:
-#if defined(GAWKDEBUG) || defined(ARRAYDEBUG)
-                       if (last_was_stopme)
-                               last_was_stopme = FALSE;
-                       else
-#endif
-                       {
-                               r = POP_SCALAR();
-                               DEREF(r);
-                       }
+                       r = POP_SCALAR();
+                       DEREF(r);
                        break;
 
                case Op_line_range:
@@ -2573,7 +2635,7 @@ func_call:
                        }
 
                        result = ip->triggered || di;
-                       ip->triggered ^= di;            /* update triggered 
flag */
+                       ip->triggered ^= di;          /* update triggered flag 
*/
                        r = make_number((AWKNUM) result);      /* final value 
of condition pair */
                        REPLACE(r);
                        JUMPTO(pc->target_jmp);
diff --git a/ext.c b/ext.c
index f0290f9..19e0eec 100644
--- a/ext.c
+++ b/ext.c
@@ -50,9 +50,6 @@ do_ext(int nargs)
        int flags = RTLD_LAZY;
        int fatal_error = FALSE;
        int *gpl_compat;
-#if 0
-       static short warned = FALSE;
-#endif
 
 #ifdef __GNUC__
        AWKNUM junk;
@@ -63,14 +60,6 @@ do_ext(int nargs)
        if (do_sandbox)
                fatal(_("extensions are not allowed in sandbox mode"));
 
-#if 0
-       /* already done in parser */
-       if (do_lint && ! warned) {
-               warned = TRUE;
-               lintwarn(_("`extension' is a gawk extension"));
-       }
-#endif
-
        if (do_traditional || do_posix)
                error(_("`extension' is a gawk extension"));
 
@@ -97,7 +86,6 @@ do_ext(int nargs)
                goto done;
        }
 
-
        func = (NODE *(*)(NODE *, void *)) dlsym(dl, fun->stptr);
        if (func == NULL) {
                msg(_("fatal: extension: library `%s': cannot call function 
`%s' (%s)\n"),
@@ -108,7 +96,7 @@ do_ext(int nargs)
 
        tmp = (*func)(obj, dl);
        if (tmp == NULL)
-               tmp = Nnull_string;
+               tmp = dupnode(Nnull_string);
 done:
        DEREF(obj);
        DEREF(fun);
@@ -123,14 +111,10 @@ done:
 void
 make_builtin(const char *name, NODE *(*func)(int), int count)
 {
-       NODE *p, *symbol, *f;
-       INSTRUCTION *b, *r;
+       NODE *symbol, *f;
+       INSTRUCTION *b;
        const char *sp;
-       char *pname;
-       char **vnames = NULL;
-       char c, buf[200];
-       size_t space_needed;
-       int i;
+       char c;
 
        sp = name;
        if (sp == NULL || *sp == '\0')
@@ -146,126 +130,79 @@ make_builtin(const char *name, NODE *(*func)(int), int 
count)
 
        if (f != NULL) {
                if (f->type == Node_func) {
-                       INSTRUCTION *pc = f->code_ptr;
-                       if (pc->opcode != Op_ext_func)  /* user-defined 
function */
-                               fatal(_("extension: can't redefine function 
`%s'"), name);
-                       else {
-                               /* multiple extension() calls etc. */ 
-                               if (do_lint)
-                                       lintwarn(_("extension: function `%s' 
already defined"), name);
-                               return;
-                       }
+                       /* user-defined function */
+                       fatal(_("extension: can't redefine function `%s'"), 
name);
+               } else if (f->type == Node_ext_func) {
+                       /* multiple extension() calls etc. */ 
+                       if (do_lint)
+                               lintwarn(_("extension: function `%s' already 
defined"), name);
+                       return;
                } else
                        /* variable name etc. */ 
                        fatal(_("extension: function name `%s' previously 
defined"), name);
        } else if (check_special(name) >= 0)
                fatal(_("extension: can't use gawk built-in `%s' as function 
name"), name); 
-       /* count parameters, create artificial list of param names */
 
        if (count < 0)
                fatal(_("make_builtin: negative argument count for function 
`%s'"),
-                                       name);
-
-       if (count > 0) {
-               sprintf(buf, "p%d", count);
-               space_needed = strlen(buf) + 1;
-               emalloc(vnames, char **, count * sizeof(char  *), 
"make_builtin");
-               for (i = 0; i < count; i++) {
-                       emalloc(pname, char *, space_needed, "make_builtin");
-                       sprintf(pname, "p%d", i);
-                       vnames[i] = pname;
-               }
-       }
+                               name);
 
-
-       getnode(p);
-       p->type = Node_param_list;
-       p->flags |= FUNC;
-       /* get our own copy for name */
-       p->param = estrdup(name, strlen(name));
-       p->param_cnt = count;
-
-       /* actual source and line numbers set at runtime for these instructions 
*/
-       b = bcalloc(Op_builtin, 1, __LINE__);
+       b = bcalloc(Op_symbol, 1, 0);
        b->builtin = func;
        b->expr_count = count;
-       b->nexti = bcalloc(Op_K_return, 1, __LINE__);
-       r = bcalloc(Op_ext_func, 1, __LINE__);
-       r->source_file = __FILE__;
-       r->nexti = b;
 
        /* NB: extension sub must return something */
 
-       symbol = mk_symbol(Node_func, p);
-       symbol->parmlist = vnames;
-       symbol->code_ptr = r;
-       r->func_body = symbol;
-       (void) install_symbol(p->param, symbol);
-}
-
-
-/* get_curfunc_arg_count --- return number actual parameters */
-
-size_t
-get_curfunc_arg_count()
-{
-       size_t argc;
-       INSTRUCTION *pc;
-       
-       pc = (INSTRUCTION *) frame_ptr->reti;      /* Op_func_call instruction 
*/
-       argc = (pc + 1)->expr_count;        /* # of arguments supplied */
-       return argc;
+               symbol = install_symbol(estrdup(name, strlen(name)), 
Node_ext_func);
+       symbol->code_ptr = b;
 }
 
 
-/* get_argument --- get the n'th argument of a dynamically linked function */
+/* get_argument --- get the i'th argument of a dynamically linked function */
 
 NODE *
 get_argument(int i)
 {
-       int pcount;
-       NODE *t, *f;
-       int actual_args;
+       NODE *t;
+       int arg_count, pcount;
        INSTRUCTION *pc;
        
-       f = frame_ptr->func_node;
-       pcount = f->lnode->param_cnt;
+       pc = TOP()->code_ptr;           /* Op_ext_builtin instruction */
+       pcount = (pc + 1)->expr_count;  /* max # of arguments */
+       arg_count = pc->expr_count;     /* # of arguments supplied */
 
-       pc = (INSTRUCTION *) frame_ptr->reti;     /* Op_func_call instruction */
-       actual_args = (pc + 1)->expr_count;       /* # of arguments supplied */
-         
-       if (i < 0 || i >= pcount || i >= actual_args)
+       if (i < 0 || i >= pcount || i >= arg_count)
                return NULL;
-
-       t = GET_PARAM(i);
-
+       i++;
+       t = PEEK(i);
        if (t->type == Node_array_ref)
-               return t->orig_array;   /* Node_var_new or Node_var_array */
-       if (t->type == Node_var_new || t->type == Node_var_array)
-               return t;
-       return t->var_value;
+               t = t->orig_array;
+       if (t->type == Node_var)        /* See Case Node_var in setup_frame(), 
eval.c */
+               return Nnull_string;
+       /* Node_var_new, Node_var_array or Node_val */
+       return t;
 }
 
 
-/* get_actual_argument --- get a scalar or array, allowed to be optional */
+/* get_actual_argument --- get the i'th scalar or array argument of a
+       dynamically linked function, allowed to be optional.
+*/
 
 NODE *
 get_actual_argument(int i, int optional, int want_array)
 {
-       /* optional : if TRUE and i th argument not present return NULL, else 
fatal. */
-
-       NODE *t, *f;
-       int pcount;
+       NODE *t;
        char *fname;
-
+       int pcount;
+       INSTRUCTION *pc;
+       
+       pc = TOP()->code_ptr;   /* Op_ext_builtin instruction */
+       fname = (pc + 1)->func_name;
+       pcount = (pc + 1)->expr_count;
+ 
        t = get_argument(i);
-
-       f = frame_ptr->func_node;
-       pcount = f->lnode->param_cnt;
-       fname = f->lnode->param;
-
        if (t == NULL) {
-               if (i >= pcount)                /* must be fatal */
+               if (i >= pcount)                /* must be fatal */
                        fatal(_("function `%s' defined to take no more than %d 
argument(s)"),
                                        fname, pcount);
                if (! optional)
@@ -279,8 +216,8 @@ get_actual_argument(int i, int optional, int want_array)
                        return get_array(t, FALSE);
                else {
                        t->type = Node_var;
-                       t->var_value = Nnull_string;
-                       return Nnull_string;
+                       t->var_value = dupnode(Nnull_string);
+                       return t->var_value;
                }
        }
 
@@ -293,6 +230,7 @@ get_actual_argument(int i, int optional, int want_array)
                        fatal(_("function `%s': argument #%d: attempt to use 
array as a scalar"),
                                fname, i + 1);
        }
+       assert(t->type == Node_var_array || t->type == Node_val);
        return t;
 }
 
diff --git a/extension/arrayparm.c b/extension/arrayparm.c
index 8a550ac..b0aee33 100644
--- a/extension/arrayparm.c
+++ b/extension/arrayparm.c
@@ -43,13 +43,13 @@ int plugin_is_GPL_compatible;
  */
 
 static NODE *
-do_mkarray(int args)
+do_mkarray(int nargs)
 {
        int ret = -1;
        NODE *var, *sub, *val;
        NODE **elemval;
 
-       if  (do_lint && get_curfunc_arg_count() > 3)
+       if  (do_lint && nargs > 3)
                lintwarn("mkarray: called with too many arguments");
 
        var = get_array_argument(0, FALSE);
@@ -60,9 +60,9 @@ do_mkarray(int args)
        printf("sub->type = %s\n", nodetype2str(sub->type));
        printf("val->type = %s\n", nodetype2str(val->type));
 
-       assoc_clear(var);
+       assoc_clear(var, NULL);
 
-       elemval = assoc_lookup(var, sub, 0);
+       elemval = assoc_lookup(var, sub);
        *elemval = dupnode(val);
        ret = 0;
 
diff --git a/extension/filefuncs.c b/extension/filefuncs.c
index ad7828f..1a0a86e 100644
--- a/extension/filefuncs.c
+++ b/extension/filefuncs.c
@@ -41,7 +41,7 @@ do_chdir(int nargs)
        NODE *newdir;
        int ret = -1;
 
-       if (do_lint && get_curfunc_arg_count() != 1)
+       if (do_lint && nargs != 1)
                lintwarn("chdir: called with incorrect number of arguments");
 
        newdir = get_scalar_argument(0, FALSE);
@@ -169,7 +169,7 @@ do_stat(int nargs)
        char *pmode;    /* printable mode */
        char *type = "unknown";
 
-       if (do_lint && get_curfunc_arg_count() > 2)
+       if (do_lint && nargs > 2)
                lintwarn("stat: called with too many arguments");
 
        /* file is first arg, array to hold results is second */
@@ -177,7 +177,7 @@ do_stat(int nargs)
        array = get_array_argument(1, FALSE);
 
        /* empty out the array */
-       assoc_clear(array);
+       assoc_clear(array, NULL);
 
        /* lstat the file, if error, set ERRNO and return */
        (void) force_string(file);
@@ -188,76 +188,76 @@ do_stat(int nargs)
        }
 
        /* fill in the array */
-       aptr = assoc_lookup(array, tmp = make_string("name", 4), FALSE);
+       aptr = assoc_lookup(array, tmp = make_string("name", 4));
        *aptr = dupnode(file);
        unref(tmp);
 
-       aptr = assoc_lookup(array, tmp = make_string("dev", 3), FALSE);
+       aptr = assoc_lookup(array, tmp = make_string("dev", 3));
        *aptr = make_number((AWKNUM) sbuf.st_dev);
        unref(tmp);
 
-       aptr = assoc_lookup(array, tmp = make_string("ino", 3), FALSE);
+       aptr = assoc_lookup(array, tmp = make_string("ino", 3));
        *aptr = make_number((AWKNUM) sbuf.st_ino);
        unref(tmp);
 
-       aptr = assoc_lookup(array, tmp = make_string("mode", 4), FALSE);
+       aptr = assoc_lookup(array, tmp = make_string("mode", 4));
        *aptr = make_number((AWKNUM) sbuf.st_mode);
        unref(tmp);
 
-       aptr = assoc_lookup(array, tmp = make_string("nlink", 5), FALSE);
+       aptr = assoc_lookup(array, tmp = make_string("nlink", 5));
        *aptr = make_number((AWKNUM) sbuf.st_nlink);
        unref(tmp);
 
-       aptr = assoc_lookup(array, tmp = make_string("uid", 3), FALSE);
+       aptr = assoc_lookup(array, tmp = make_string("uid", 3));
        *aptr = make_number((AWKNUM) sbuf.st_uid);
        unref(tmp);
 
-       aptr = assoc_lookup(array, tmp = make_string("gid", 3), FALSE);
+       aptr = assoc_lookup(array, tmp = make_string("gid", 3));
        *aptr = make_number((AWKNUM) sbuf.st_gid);
        unref(tmp);
 
-       aptr = assoc_lookup(array, tmp = make_string("size", 4), FALSE);
+       aptr = assoc_lookup(array, tmp = make_string("size", 4));
        *aptr = make_number((AWKNUM) sbuf.st_size);
        unref(tmp);
 
-       aptr = assoc_lookup(array, tmp = make_string("blocks", 6), FALSE);
+       aptr = assoc_lookup(array, tmp = make_string("blocks", 6));
        *aptr = make_number((AWKNUM) sbuf.st_blocks);
        unref(tmp);
 
-       aptr = assoc_lookup(array, tmp = make_string("atime", 5), FALSE);
+       aptr = assoc_lookup(array, tmp = make_string("atime", 5));
        *aptr = make_number((AWKNUM) sbuf.st_atime);
        unref(tmp);
 
-       aptr = assoc_lookup(array, tmp = make_string("mtime", 5), FALSE);
+       aptr = assoc_lookup(array, tmp = make_string("mtime", 5));
        *aptr = make_number((AWKNUM) sbuf.st_mtime);
        unref(tmp);
 
-       aptr = assoc_lookup(array, tmp = make_string("ctime", 5), FALSE);
+       aptr = assoc_lookup(array, tmp = make_string("ctime", 5));
        *aptr = make_number((AWKNUM) sbuf.st_ctime);
        unref(tmp);
 
        /* for block and character devices, add rdev, major and minor numbers */
        if (S_ISBLK(sbuf.st_mode) || S_ISCHR(sbuf.st_mode)) {
-               aptr = assoc_lookup(array, tmp = make_string("rdev", 4), FALSE);
+               aptr = assoc_lookup(array, tmp = make_string("rdev", 4));
                *aptr = make_number((AWKNUM) sbuf.st_rdev);
                unref(tmp);
 
-               aptr = assoc_lookup(array, tmp = make_string("major", 5), 
FALSE);
+               aptr = assoc_lookup(array, tmp = make_string("major", 5));
                *aptr = make_number((AWKNUM) major(sbuf.st_rdev));
                unref(tmp);
 
-               aptr = assoc_lookup(array, tmp = make_string("minor", 5), 
FALSE);
+               aptr = assoc_lookup(array, tmp = make_string("minor", 5));
                *aptr = make_number((AWKNUM) minor(sbuf.st_rdev));
                unref(tmp);
        }
 
 #ifdef HAVE_ST_BLKSIZE
-       aptr = assoc_lookup(array, tmp = make_string("blksize", 7), FALSE);
+       aptr = assoc_lookup(array, tmp = make_string("blksize", 7));
        *aptr = make_number((AWKNUM) sbuf.st_blksize);
        unref(tmp);
 #endif /* HAVE_ST_BLKSIZE */
 
-       aptr = assoc_lookup(array, tmp = make_string("pmode", 5), FALSE);
+       aptr = assoc_lookup(array, tmp = make_string("pmode", 5));
        pmode = format_mode(sbuf.st_mode);
        *aptr = make_string(pmode, strlen(pmode));
        unref(tmp);
@@ -277,7 +277,7 @@ do_stat(int nargs)
                         */
                        buf[linksize] = '\0';
 
-                       aptr = assoc_lookup(array, tmp = make_string("linkval", 
7), FALSE);
+                       aptr = assoc_lookup(array, tmp = make_string("linkval", 
7));
                        *aptr = make_str_node(buf, linksize, ALREADY_MALLOCED);
                        unref(tmp);
                }
@@ -319,7 +319,7 @@ do_stat(int nargs)
 #endif
        }
 
-       aptr = assoc_lookup(array, tmp = make_string("type", 4), FALSE);
+       aptr = assoc_lookup(array, tmp = make_string("type", 4));
        *aptr = make_string(type, strlen(type));
        unref(tmp);
 
diff --git a/extension/fork.c b/extension/fork.c
index aff9b56..8835387 100644
--- a/extension/fork.c
+++ b/extension/fork.c
@@ -38,7 +38,7 @@ do_fork(int nargs)
        NODE **aptr;
        NODE *tmp;
 
-       if  (do_lint && get_curfunc_arg_count() > 0)
+       if  (do_lint && nargs > 0)
                lintwarn("fork: called with too many arguments");
 
        ret = fork();
@@ -48,11 +48,11 @@ do_fork(int nargs)
        else if (ret == 0) {
                /* update PROCINFO in the child */
 
-               aptr = assoc_lookup(PROCINFO_node, tmp = make_string("pid", 3), 
FALSE);
+               aptr = assoc_lookup(PROCINFO_node, tmp = make_string("pid", 3));
                (*aptr)->numbr = (AWKNUM) getpid();
                unref(tmp);
 
-               aptr = assoc_lookup(PROCINFO_node, tmp = make_string("ppid", 
4), FALSE);
+               aptr = assoc_lookup(PROCINFO_node, tmp = make_string("ppid", 
4));
                (*aptr)->numbr = (AWKNUM) getppid();
                unref(tmp);
        }
@@ -73,7 +73,7 @@ do_waitpid(int nargs)
        pid_t pid;
        int options = 0;
 
-       if  (do_lint && get_curfunc_arg_count() > 1)
+       if  (do_lint && nargs > 1)
                lintwarn("waitpid: called with too many arguments");
 
        pidnode = get_scalar_argument(0, FALSE);
diff --git a/extension/ordchr.c b/extension/ordchr.c
index efbc6d5..8926a94 100644
--- a/extension/ordchr.c
+++ b/extension/ordchr.c
@@ -40,7 +40,7 @@ do_ord(int nargs)
        NODE *str;
        int ret = -1;
 
-       if  (do_lint && get_curfunc_arg_count() > 1)
+       if  (do_lint && nargs > 1)
                lintwarn("ord: called with too many arguments");
 
        str = get_scalar_argument(0, FALSE);
@@ -67,7 +67,7 @@ do_chr(int nargs)
 
        str[0] = str[1] = '\0';
 
-       if  (do_lint && get_curfunc_arg_count() > 1)
+       if  (do_lint && nargs > 1)
                lintwarn("chr: called with too many arguments");
 
        num = get_scalar_argument(0, FALSE);
diff --git a/extension/readfile.c b/extension/readfile.c
index e6ee0f2..c9b1efc 100644
--- a/extension/readfile.c
+++ b/extension/readfile.c
@@ -50,7 +50,7 @@ do_readfile(int nargs)
        char *text;
        int fd;
 
-       if  (do_lint && get_curfunc_arg_count() > 1)
+       if  (do_lint && nargs > 1)
                lintwarn("readfile: called with too many arguments");
 
        filename = get_scalar_argument(0, FALSE);
diff --git a/extension/rwarray.c b/extension/rwarray.c
index 3c62957..8175c7c 100644
--- a/extension/rwarray.c
+++ b/extension/rwarray.c
@@ -82,7 +82,7 @@ do_writea(int nargs)
        uint32_t major = MAJOR;
        uint32_t minor = MINOR;
 
-       if (do_lint && get_curfunc_arg_count() > 2)
+       if (do_lint && nargs > 2)
                lintwarn("writea: called with too many arguments");
 
        /* directory is first arg, array to dump is second */
@@ -250,7 +250,7 @@ do_reada(int nargs)
        uint32_t minor;
        char magic_buf[30];
 
-       if (do_lint && get_curfunc_arg_count() > 2)
+       if (do_lint && nargs > 2)
                lintwarn("reada: called with too many arguments");
 
        /* directory is first arg, array to dump is second */
@@ -289,7 +289,7 @@ do_reada(int nargs)
                goto done1;
        }
 
-       assoc_clear(array);
+       assoc_clear(array, NULL);
 
        ret = read_array(fd, array);
        if (ret == 0)
diff --git a/extension/testarg.c b/extension/testarg.c
index ba4d56f..4d012db 100644
--- a/extension/testarg.c
+++ b/extension/testarg.c
@@ -5,17 +5,15 @@ int plugin_is_GPL_compatible;
 static NODE *
 do_check_arg(int nargs)
 {
-       int ret = 0, argc;
+       int ret = 0;
        NODE *arg1, *arg2, *arg3;
 
-       argc = get_curfunc_arg_count();
-       printf("arg count: defined = %d, supplied = %d\n",
-                      nargs, argc);
+       printf("arg count: defined = 3, supplied = %d\n", nargs);
 
        arg1 = get_scalar_argument(0, FALSE);
        arg2 = get_array_argument(1, FALSE);
        arg3 = get_scalar_argument(2, TRUE);    /* optional */
-       if (argc > 3) {
+       if (nargs > 3) {
                /* try to use an extra arg */
                NODE *arg4;
                arg4 = get_array_argument(3, TRUE);
diff --git a/field.c b/field.c
index 0b9c100..67973a9 100644
--- a/field.c
+++ b/field.c
@@ -85,13 +85,13 @@ void
 init_fields()
 {
        emalloc(fields_arr, NODE **, sizeof(NODE *), "init_fields");
-       fields_arr[0] = Nnull_string;
+       fields_arr[0] = dupnode(Nnull_string);
        parse_extent = fields_arr[0]->stptr;
        save_FS = dupnode(FS_node->var_value);
        getnode(Null_field);
        *Null_field = *Nnull_string;
-       Null_field->flags |= FIELD;
-       Null_field->flags &= ~(NUMCUR|NUMBER|MAYBE_NUM|PERM|MALLOC);
+       Null_field->valref = 1;
+       Null_field->flags = (FIELD|STRCUR|STRING);
        field0_valid = TRUE;
 }
 
@@ -185,7 +185,7 @@ rebuild_record()
                        }
                }
        }
-       tmp = make_str_node(ops, tlen, ALREADY_MALLOCED);
+       tmp = make_str_node(ops, tlen);
 
        /*
         * Since we are about to unref fields_arr[0], we want to find
@@ -207,7 +207,7 @@ rebuild_record()
                                }
                        } else {
                                *n = *(fields_arr[i]);
-                               n->flags &= ~(MALLOC|PERM|STRING);
+                               n->flags &= ~(MALLOC|STRING);
                        }
 
                        n->stptr = cops;
@@ -289,7 +289,7 @@ reset_record()
        int i;
        NODE *n;
 
-       (void) force_string(fields_arr[0]);
+       fields_arr[0] = force_string(fields_arr[0]);
 
        NF = -1;
        for (i = 1; i <= parse_high_water; i++) {
@@ -926,7 +926,7 @@ set_element(long num, char *s, long len, NODE *n)
        it = make_string(s, len);
        it->flags |= MAYBE_NUM;
        sub = make_number((AWKNUM) (num));
-       lhs = assoc_lookup(n, sub, FALSE);
+       lhs = assoc_lookup(n, sub);
        unref(sub);
        unref(*lhs);
        *lhs = it;
@@ -987,8 +987,8 @@ do_split(int nargs)
                /*
                 * Skip the work if first arg is the null string.
                 */
-               decr_sp();
-               DEREF(src);
+               tmp = POP_SCALAR();
+               DEREF(tmp);
                return make_number((AWKNUM) 0);
        }
 
@@ -1026,7 +1026,7 @@ do_split(int nargs)
        tmp = make_number((AWKNUM) (*parseit)(UNLIMITED, &s, (int) src->stlen,
                                             fs, rp, set_element, arr, sep_arr, 
FALSE));
 
-       decr_sp();
+       src = POP_SCALAR();     /* really pop off stack */
        DEREF(src);
        return tmp;
 }
@@ -1087,7 +1087,7 @@ do_patsplit(int nargs)
                                set_element, arr, sep_arr, FALSE));
        }
 
-       decr_sp();      /* 1st argument not POP-ed */
+       src = POP_SCALAR();     /* really pop off stack */
        DEREF(src);
        return tmp;
 }
@@ -1103,6 +1103,7 @@ set_FIELDWIDTHS()
        static int fw_alloc = 4;
        static short warned = FALSE;
        int fatal_error = FALSE;
+       NODE *tmp;
 
        if (do_lint && ! warned) {
                warned = TRUE;
@@ -1119,7 +1120,8 @@ set_FIELDWIDTHS()
                (void) get_field(UNLIMITED - 1, 0);
 
        parse_field = fw_parse_field;
-       scan = force_string(FIELDWIDTHS_node->var_value)->stptr;
+       tmp = force_string(FIELDWIDTHS_node->var_value);
+       scan = tmp->stptr;
 
        if (FIELDWIDTHS == NULL)
                emalloc(FIELDWIDTHS, int *, fw_alloc * sizeof(int), 
"set_FIELDWIDTHS");
@@ -1330,7 +1332,7 @@ update_PROCINFO_str(const char *subscript, const char 
*str)
        if (PROCINFO_node == NULL)
                return;
        tmp = make_string(subscript, strlen(subscript));
-       aptr = assoc_lookup(PROCINFO_node, tmp, FALSE);
+       aptr = assoc_lookup(PROCINFO_node, tmp);
        unref(tmp);
        unref(*aptr);
        *aptr = make_string(str, strlen(str));
@@ -1347,7 +1349,7 @@ update_PROCINFO_num(const char *subscript, AWKNUM val)
        if (PROCINFO_node == NULL)
                return;
        tmp = make_string(subscript, strlen(subscript));
-       aptr = assoc_lookup(PROCINFO_node, tmp, FALSE);
+       aptr = assoc_lookup(PROCINFO_node, tmp);
        unref(tmp);
        unref(*aptr);
        *aptr = make_number(val);
diff --git a/io.c b/io.c
index 21301f4..b14be1b 100644
--- a/io.c
+++ b/io.c
@@ -208,7 +208,7 @@ static int inetfile(const char *str, int *length, int 
*family);
 #endif
 
 static struct redirect *red_head = NULL;
-static NODE *RS;
+static NODE *RS = NULL;
 static Regexp *RS_re_yes_case;
 static Regexp *RS_re_no_case;
 static Regexp *RS_regexp;
@@ -610,7 +610,7 @@ redirect(NODE *redir_exp, int redirtype, int *errflg)
        if (do_lint && (redir_exp->flags & STRCUR) == 0)
                lintwarn(_("expression in `%s' redirection only has numeric 
value"),
                        what);
-       redir_exp = force_string(redir_exp);
+       redir_exp= force_string(redir_exp);
        str = redir_exp->stptr;
 
        if (str == NULL || *str == '\0')
@@ -2527,7 +2527,7 @@ iop_alloc(int fd, const char *name, IOBUF *iop, int 
do_openhooks)
 
 #define set_RT_to_null() \
        (void)(! do_traditional && (unref(RT_node->var_value), \
-                          RT_node->var_value = Nnull_string))
+                          RT_node->var_value = dupnode(Nnull_string)))
 
 #define set_RT(str, len) \
        (void)(! do_traditional && (unref(RT_node->var_value), \
@@ -3138,8 +3138,7 @@ pty_vs_pipe(const char *command)
 #ifdef HAVE_TERMIOS_H
        char *full_index;
        size_t full_len;
-       NODE *val;
-       NODE *sub;
+       NODE *val, *sub;
 
        if (PROCINFO_node == NULL)
                return FALSE;
diff --git a/main.c b/main.c
index b30924b..f3f1524 100644
--- a/main.c
+++ b/main.c
@@ -129,23 +129,11 @@ static int disallow_var_assigns = FALSE;  /* true for 
--exec */
 
 static void add_preassign(enum assign_type type, char *val);
 
-#undef do_lint
-#undef do_lint_old
-
-int do_traditional = FALSE;    /* no gnu extensions, add traditional 
weirdnesses */
-int do_posix = FALSE;          /* turn off gnu and unix extensions */
-int do_lint = FALSE;           /* provide warnings about questionable stuff */
-int do_lint_old = FALSE;       /* warn about stuff not in V7 awk */
-int do_intl = FALSE;           /* dump locale-izable strings to stdout */
-int do_non_decimal_data = FALSE;       /* allow octal/hex C style DATA. Use 
with caution! */
-int do_nostalgia = FALSE;      /* provide a blast from the past */
-int do_intervals = FALSE;      /* allow {...,...} in regexps, see resetup() */
-int do_profiling = FALSE;      /* profile and pretty print the program */
-int do_dump_vars = FALSE;      /* dump all global variables at end */
-int do_tidy_mem = FALSE;       /* release vars when done */
-int do_optimize = TRUE;                /* apply default optimizations */
-int do_binary = FALSE;         /* hands off my data! */
-int do_sandbox = FALSE;        /* sandbox mode - disable 'system' function & 
redirections */
+int do_flags = FALSE;
+int do_optimize = TRUE;                                /* apply default 
optimizations */
+static int do_nostalgia = FALSE;       /* provide a blast from the past */
+static int do_binary = FALSE;          /* hands off my data! */
+
 int use_lc_numeric = FALSE;    /* obey locale for decimal point */
 
 #ifdef MBS_SUPPORT
@@ -174,20 +162,20 @@ void (*lintfunc)(const char *mesg, ...) = warning;
  * Note: reserve -l for future use, for xgawk's -l option.
  */
 static const struct option optab[] = {
-       { "traditional",        no_argument,            & do_traditional,       
1 },
+       { "traditional",        no_argument,            NULL,   'c' },
        { "lint",               optional_argument,      NULL,           'L' },
-       { "lint-old",           no_argument,            & do_lint_old,  1 },
-       { "optimize",           no_argument,            & do_optimize,  'O' },
-       { "posix",              no_argument,            & do_posix,     1 },
+       { "lint-old",           no_argument,            NULL,   't' },
+       { "optimize",           no_argument,            NULL,   'O' },
+       { "posix",              no_argument,            NULL,   'P' },
        { "command",            required_argument,      NULL,           'R' },
        { "nostalgia",          no_argument,            & do_nostalgia, 1 },
-       { "gen-pot",            no_argument,            & do_intl,      1 },
-       { "non-decimal-data",   no_argument,            & do_non_decimal_data, 
1 },
+       { "gen-pot",            no_argument,            NULL,   'g' },
+       { "non-decimal-data",   no_argument,            NULL, 'n' },
        { "profile",            optional_argument,      NULL,           'p' },
        { "copyright",          no_argument,            NULL,           'C' },
        { "field-separator",    required_argument,      NULL,           'F' },
        { "file",               required_argument,      NULL,           'f' },
-       { "re-interval",        no_argument,            & do_intervals, 1 },
+       { "re-interval",        no_argument,            NULL,   'r' },
        { "source",             required_argument,      NULL,           'e' },
        { "dump-variables",     optional_argument,      NULL,           'd' },
        { "assign",             required_argument,      NULL,           'v' },
@@ -196,17 +184,13 @@ static const struct option optab[] = {
        { "exec",               required_argument,      NULL,           'E' },
        { "use-lc-numeric",     no_argument,            & use_lc_numeric, 1 },
        { "characters-as-bytes", no_argument,           & do_binary,     'b' },
-       { "sandbox",            no_argument,            & do_sandbox,   1 },
+       { "sandbox",            no_argument,            NULL,   'S' },
 #if defined(YYDEBUG) || defined(GAWKDEBUG)
        { "parsedebug",         no_argument,            NULL,           'Y' },
 #endif
        { NULL, 0, NULL, '\0' }
 };
 
-#ifdef NO_LINT
-#define do_lint 0
-#define do_lint_old 0
-#endif
 
 /* main --- process args, parse program, run it, clean up */
 
@@ -227,7 +211,8 @@ main(int argc, char **argv)
        char *extra_stack;
 
        /* do these checks early */
-       do_tidy_mem = (getenv("TIDYMEM") != NULL);
+       if (getenv("TIDYMEM") != NULL)
+               do_flags |= DO_TIDY_MEM;
 
 #ifdef HAVE_MCHECK_H
 #ifdef HAVE_MTRACE
@@ -373,7 +358,7 @@ main(int argc, char **argv)
                        break;
 
                case 'c':
-                       do_traditional = TRUE;
+                       do_flags |= DO_TRADITIONAL;
                        break;
 
                case 'C':
@@ -381,7 +366,7 @@ main(int argc, char **argv)
                        break;
 
                case 'd':
-                       do_dump_vars = TRUE;
+                       do_flags |= DO_DUMP_VARS;
                        if (optarg != NULL && optarg[0] != '\0')
                                varfile = optarg;
                        break;
@@ -394,7 +379,7 @@ main(int argc, char **argv)
                        break;
 
                case 'g':
-                       do_intl = TRUE;
+                       do_flags |= DO_INTL;
                        break;
 
                case 'h':
@@ -402,19 +387,21 @@ main(int argc, char **argv)
                        usage(EXIT_SUCCESS, stdout);
                        break;
 
-#ifndef NO_LINT
                case 'L':
-                       do_lint = LINT_ALL;
+#ifndef NO_LINT
+                       do_flags |= DO_LINT_ALL;
                        if (optarg != NULL) {
                                if (strcmp(optarg, "fatal") == 0)
                                        lintfunc = r_fatal;
-                               else if (strcmp(optarg, "invalid") == 0)
-                                       do_lint = LINT_INVALID;
+                               else if (strcmp(optarg, "invalid") == 0) {
+                                       do_flags &= ~DO_LINT_ALL;
+                                       do_flags |= DO_LINT_INVALID;
+                               }
                        }
                        break;
 
                case 't':
-                       do_lint_old = TRUE;
+                       do_flags |= DO_LINT_OLD;
                        break;
 #else
                case 'L':
@@ -423,7 +410,7 @@ main(int argc, char **argv)
 #endif
 
                case 'n':
-                       do_non_decimal_data = TRUE;
+                       do_flags |= DO_NON_DEC_DATA;
                        break;
 
                case 'N':
@@ -435,7 +422,7 @@ main(int argc, char **argv)
                        break;
 
                case 'p':
-                       do_profiling = TRUE;
+                       do_flags |= DO_PROFILING;
                        if (optarg != NULL)
                                set_prof_file(optarg);
                        else
@@ -443,15 +430,15 @@ main(int argc, char **argv)
                        break;
 
                case 'P':
-                       do_posix = TRUE;
+                       do_flags |= DO_POSIX;
                        break;
 
                case 'r':
-                       do_intervals = TRUE;
+                       do_flags |= DO_INTERVALS;
                        break;
  
                case 'S':
-                       do_sandbox = TRUE;
+                       do_flags |= DO_SANDBOX;
                        break;
 
                case 'V':
@@ -530,7 +517,7 @@ out:
 
        /* check for POSIXLY_CORRECT environment variable */
        if (! do_posix && getenv("POSIXLY_CORRECT") != NULL) {
-               do_posix = TRUE;
+               do_flags |= DO_POSIX;
                if (do_lint)
                        lintwarn(
        _("environment variable `POSIXLY_CORRECT' set: turning on `--posix'"));
@@ -541,7 +528,7 @@ out:
                if (do_traditional)     /* both on command line */
                        warning(_("`--posix' overrides `--traditional'"));
                else
-                       do_traditional = TRUE;
+                       do_flags |= DO_TRADITIONAL;
                        /*
                         * POSIX compliance also implies
                         * no GNU extensions either.
@@ -549,7 +536,7 @@ out:
        }
 
        if (do_traditional && do_non_decimal_data) {
-               do_non_decimal_data = FALSE;
+               do_flags &= ~DO_NON_DEC_DATA;
                warning(_("`--posix'/`--traditional' overrides 
`--non-decimal-data'"));
        }
 
@@ -570,7 +557,7 @@ out:
         * Don't bother if the command line already set profiling up.
         */
        if (! do_profiling)
-               init_profiling(& do_profiling, DEFAULT_PROFILE);
+               init_profiling(& do_flags, DEFAULT_PROFILE);
 
        /* load group set */
        init_groupset();
@@ -578,8 +565,7 @@ out:
        /* initialize the null string */
        Nnull_string = make_string("", 0);
        Nnull_string->numbr = 0.0;
-       Nnull_string->type = Node_val;
-       Nnull_string->flags = (PERM|STRCUR|STRING|NUMCUR|NUMBER);
+       Nnull_string->flags = (MALLOC|STRCUR|STRING|NUMCUR|NUMBER);
 
        /*
         * Tell the regex routines how they should work.
@@ -734,8 +720,9 @@ usage(int exitval, FILE *fp)
        /* Not factoring out common stuff makes it easier to translate. */
        fprintf(fp, _("Usage: %s [POSIX or GNU style options] -f progfile [--] 
file ...\n"),
                myname);
-       fprintf(fp, _("Usage: %s [POSIX or GNU style options] [--] %cprogram%c 
file ...\n"),
-               myname, quote, quote);
+       if (which_gawk != exe_debugging)
+               fprintf(fp, _("Usage: %s [POSIX or GNU style options] [--] 
%cprogram%c file ...\n"),
+                       myname, quote, quote);
 
        /* GNU long options info. This is too many options. */
 
@@ -842,6 +829,7 @@ static void
 cmdline_fs(char *str)
 {
        NODE **tmp;
+       size_t len;
 
        tmp = &FS_node->var_value;
        unref(*tmp);
@@ -858,7 +846,9 @@ cmdline_fs(char *str)
                if (do_traditional && ! do_posix)
                        str[0] = '\t';
        }
-       *tmp = make_str_node(str, strlen(str), SCAN); /* do process escapes */
+
+       len = scan_escape(str, strlen(str)); /* do process escapes */
+       *tmp = make_string(str, len);
        set_FS();
 }
 
@@ -871,26 +861,27 @@ init_args(int argc0, int argc, const char *argv0, char 
**argv)
        NODE **aptr;
        NODE *tmp;
 
-       ARGV_node = install_symbol(estrdup("ARGV", 4), 
mk_symbol(Node_var_array, (NODE *) NULL));
+       ARGV_node = install_symbol(estrdup("ARGV", 4), Node_var_array);
        tmp =  make_number(0.0);
-       aptr = assoc_lookup(ARGV_node, tmp, FALSE);
+       aptr = assoc_lookup(ARGV_node, tmp);
        unref(tmp);
        unref(*aptr);
        *aptr = make_string(argv0, strlen(argv0));
        (*aptr)->flags |= MAYBE_NUM;
        for (i = argc0, j = 1; i < argc; i++, j++) {
                tmp = make_number((AWKNUM) j);
-               aptr = assoc_lookup(ARGV_node, tmp, FALSE);
+               aptr = assoc_lookup(ARGV_node, tmp);
                unref(tmp);
                unref(*aptr);
                *aptr = make_string(argv[i], strlen(argv[i]));
                (*aptr)->flags |= MAYBE_NUM;
        }
 
-       ARGC_node = install_symbol(estrdup("ARGC", 4),
-                                       mk_symbol(Node_var, 
make_number((AWKNUM) j)));
+       ARGC_node = install_symbol(estrdup("ARGC", 4), Node_var);
+       ARGC_node->var_value = make_number((AWKNUM) j);
 }
 
+
 /*
  * Set all the special variables to their initial values.
  * Note that some of the variables that have set_FOO routines should
@@ -953,13 +944,11 @@ init_vars()
        for (vp = varinit; vp->name != NULL; vp++) {
                if ((vp->flags & NO_INSTALL) != 0)
                        continue;
-               n = mk_symbol(Node_var, vp->strval == NULL
-                               ? make_number(vp->numval)
-                               : make_string(vp->strval, strlen(vp->strval)));
+               n = *(vp->spec) = install_symbol(estrdup(vp->name, 
strlen(vp->name)), Node_var);
+               n->var_value = vp->strval == NULL ? make_number(vp->numval)
+                                                       : 
make_string(vp->strval, strlen(vp->strval));
                n->var_assign = (Func_ptr) vp->assign;
                n->var_update = (Func_ptr) vp->update;
-
-               *(vp->spec) = install_symbol(estrdup(vp->name, 
strlen(vp->name)), n);
                if (vp->do_assign)
                        (*(vp->assign))();
        }
@@ -983,9 +972,7 @@ load_environ()
        int i;
        NODE *tmp;
 
-       ENVIRON_node = install_symbol(estrdup("ENVIRON", 7), 
-                               mk_symbol(Node_var_array, (NODE *) NULL));
-
+       ENVIRON_node = install_symbol(estrdup("ENVIRON", 7), Node_var_array);
        for (i = 0; environ[i] != NULL; i++) {
                static char nullstr[] = "";
 
@@ -996,7 +983,7 @@ load_environ()
                else
                        val = nullstr;
                tmp = make_string(var, strlen(var));
-               aptr = assoc_lookup(ENVIRON_node, tmp, FALSE);
+               aptr = assoc_lookup(ENVIRON_node, tmp);
                unref(tmp);
                unref(*aptr);
                *aptr = make_string(val, strlen(val));
@@ -1019,7 +1006,7 @@ load_environ()
                val = getenv("AWKPATH");
                if (val == NULL)
                        val = defpath;
-               aptr = assoc_lookup(ENVIRON_node, tmp, FALSE);
+               aptr = assoc_lookup(ENVIRON_node, tmp);
                unref(*aptr);
                *aptr = make_string(val, strlen(val));
        }
@@ -1038,8 +1025,7 @@ load_procinfo()
 #endif
        AWKNUM value;
 
-       PROCINFO_node = install_symbol(estrdup("PROCINFO", 8),
-                               mk_symbol(Node_var_array, (NODE *) NULL));
+       PROCINFO_node = install_symbol(estrdup("PROCINFO", 8), Node_var_array);
 
        update_PROCINFO_str("version", VERSION);
        update_PROCINFO_str("strftime", def_strftime_format);
@@ -1133,6 +1119,7 @@ int
 arg_assign(char *arg, int initing)
 {
        char *cp, *cp2;
+       size_t cplen;
        int badvar;
        NODE *var;
        NODE *it;
@@ -1194,7 +1181,8 @@ arg_assign(char *arg, int initing)
                 * BWK awk expands escapes inside assignments.
                 * This makes sense, so we do it too.
                 */
-               it = make_str_node(cp, strlen(cp), SCAN);
+               cplen = scan_escape(cp, strlen(cp));
+               it = make_string(cp, cplen);
                it->flags |= MAYBE_NUM;
 #ifdef LC_NUMERIC
                /*
@@ -1215,7 +1203,7 @@ arg_assign(char *arg, int initing)
 
                cp2 = estrdup(arg, cp - arg);   /* var name */
 
-               var = variable(cp2, Node_var);
+               var = variable(0, cp2, Node_var);
                if (var == NULL)        /* error */
                        exit(EXIT_FATAL);
                if (var->type == Node_var && var->var_update)
@@ -1439,3 +1427,18 @@ update_global_values()
                        vp->update();
        }
 }
+
+/* getenv_long --- read a long value (>= 0) from an environment var. */
+
+long
+getenv_long(const char *name)
+{
+       const char *val;
+       long newval;    
+       if ((val = getenv(name)) != NULL && isdigit((unsigned char) *val)) {
+               for (newval = 0; *val && isdigit((unsigned char) *val); val++)
+                       newval = (newval * 10) + *val - '0';
+               return newval;
+       }
+       return -1;
+}
diff --git a/node.c b/node.c
index 315d46c..36c6004 100644
--- a/node.c
+++ b/node.c
@@ -29,6 +29,8 @@
 
 static int is_ieee_magic_val(const char *val);
 static AWKNUM get_ieee_magic_val(const char *val);
+extern NODE **fmt_list;          /* declared in eval.c */
+
 
 /* force_number --- force a value to be numeric */
 
@@ -104,6 +106,8 @@ r_force_number(NODE *n)
                        n->numbr = (AWKNUM)(*cp - '0');
                        n->flags |= newflags;
                        n->flags |= NUMCUR;
+                       if (cp == n->stptr)             /* no leading spaces */
+                               n->flags |= NUMINT;
                }
                return n->numbr;
        }
@@ -166,18 +170,6 @@ format_val(const char *format, int index, NODE *s)
        char buf[BUFSIZ];
        char *sp = buf;
        double val;
-       char *orig, *trans, save;
-
-       if (! do_traditional && (s->flags & INTLSTR) != 0) {
-               save = s->stptr[s->stlen];
-               s->stptr[s->stlen] = '\0';
-
-               orig = s->stptr;
-               trans = dgettext(TEXTDOMAIN, orig);
-
-               s->stptr[s->stlen] = save;
-               return make_string(trans, strlen(trans));
-       }
 
        /*
         * 2/2007: Simplify our lives here. Instead of worrying about
@@ -210,7 +202,6 @@ format_val(const char *format, int index, NODE *s)
 
                NODE *dummy[2], *r;
                unsigned short oflags;
-               extern NODE **fmt_list;          /* declared in eval.c */
 
                /* create dummy node for a sole use of format_tree */
                dummy[1] = s;
@@ -234,8 +225,7 @@ format_val(const char *format, int index, NODE *s)
                goto no_malloc;
        } else {
                /*
-                * integral value
-                * force conversion to long only once
+                * integral value; force conversion to long only once.
                 */
                long num = (long) val;
 
@@ -247,19 +237,25 @@ format_val(const char *format, int index, NODE *s)
                        s->stlen = strlen(sp);
                }
                s->stfmt = -1;
+               if (s->flags & INTIND) {
+                       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);
+       memcpy(s->stptr, sp, s->stlen + 1);
 no_malloc:
        s->flags |= STRCUR;
        free_wstr(s);
        return s;
 }
 
-/* force_string --- force a value to be a string */
 
+/* r_force_string --- force a value to be a string */
+
+#ifdef GAWKDEBUG
 NODE *
 r_force_string(NODE *s)
 {
@@ -269,28 +265,23 @@ r_force_string(NODE *s)
                return s;
        return format_val(CONVFMT, CONVFMTidx, s);
 }
+#endif
 
-/* dupnode --- duplicate a node */
+/* r_dupnode --- duplicate a node */
 
 NODE *
-dupnode(NODE *n)
+r_dupnode(NODE *n)
 {
        NODE *r;
 
-       if (n->type == Node_ahash) {
-               n->ahname_ref++;
-               return n;
-       }
-
        assert(n->type == Node_val);
 
-       if ((n->flags & PERM) != 0)
-               return n;
-       
+#ifdef GAWKDEBUG
        if ((n->flags & MALLOC) != 0) {
                n->valref++;
                return n;
        }
+#endif
 
        getnode(r);
        *r = *n;
@@ -308,13 +299,13 @@ dupnode(NODE *n)
 #endif /* defined MBS_SUPPORT */
 
        if ((n->flags & STRCUR) != 0) {
-               emalloc(r->stptr, char *, n->stlen + 2, "dupnode");
+               emalloc(r->stptr, char *, n->stlen + 2, "r_dupnode");
                memcpy(r->stptr, n->stptr, n->stlen);
                r->stptr[n->stlen] = '\0';
 #if defined MBS_SUPPORT
                if ((n->flags & WSTRCUR) != 0) {
                        r->wstlen = n->wstlen;
-                       emalloc(r->wstptr, wchar_t *, sizeof(wchar_t) * 
(n->wstlen + 2), "dupnode");
+                       emalloc(r->wstptr, wchar_t *, sizeof(wchar_t) * 
(n->wstlen + 2), "r_dupnode");
                        memcpy(r->wstptr, n->wstptr, n->wstlen * 
sizeof(wchar_t));
                        r->wstptr[n->wstlen] = L'\0';
                        r->flags |= WSTRCUR;
@@ -325,156 +316,78 @@ dupnode(NODE *n)
        return r;
 }
 
-/* mk_number --- allocate a node with defined number */
+/* make_number --- allocate a node with defined number */
 
 NODE *
-mk_number(AWKNUM x, unsigned int flags)
+make_number(AWKNUM x)
 {
        NODE *r;
-
        getnode(r);
        r->type = Node_val;
        r->numbr = x;
        r->valref = 1;
-       r->flags = flags;
+       r->flags = MALLOC|NUMBER|NUMCUR;
        r->stptr = NULL;
        r->stlen = 0;
-       free_wstr(r);
+#ifdef MBS_SUPPORT
+       r->wstptr = NULL;
+       r->wstlen = 0;
+#endif /* defined MBS_SUPPORT */
        return r;
 }
 
-/* make_str_node --- make a string node */
+
+/* r_make_str_node --- make a string node */
 
 NODE *
-r_make_str_node(const char *s, unsigned long len, int flags)
+r_make_str_node(const char *s, size_t len, int already_malloced)
 {
        NODE *r;
 
        getnode(r);
        r->type = Node_val;
+       r->flags = (MALLOC|STRING|STRCUR);
+       r->valref = 1;
        r->numbr = 0;
-       r->flags = (STRING|STRCUR|MALLOC);
-#ifdef MBS_SUPPORT
-       r->wstptr = NULL;
-       r->wstlen = 0;
-#endif /* defined MBS_SUPPORT */
-
-       if (flags & ALREADY_MALLOCED)
+       r->stfmt = -1;
+       r->stlen = len;
+       if (already_malloced)
                r->stptr = (char *) s;
        else {
-               emalloc(r->stptr, char *, len + 2, "make_str_node");
+               emalloc(r->stptr, char *, len + 2, "make_string");
                memcpy(r->stptr, s, len);
        }
        r->stptr[len] = '\0';
 
-       if ((flags & SCAN) != 0) {      /* scan for escape sequences */
-               const char *pf;
-               char *ptm;
-               int c;
-               const char *end;
 #ifdef MBS_SUPPORT
-               mbstate_t cur_state;
-
-               memset(& cur_state, 0, sizeof(cur_state));
-#endif
-
-               end = &(r->stptr[len]);
-               for (pf = ptm = r->stptr; pf < end;) {
-#ifdef MBS_SUPPORT
-                       /*
-                        * Keep multibyte characters together. This avoids
-                        * problems if a subsequent byte of a multibyte
-                        * character happens to be a backslash.
-                        */
-                       if (gawk_mb_cur_max > 1) {
-                               int mblen = mbrlen(pf, end-pf, &cur_state);
-
-                               if (mblen > 1) {
-                                       int i;
-
-                                       for (i = 0; i < mblen; i++)
-                                               *ptm++ = *pf++;
-                                       continue;
-                               }
-                       }
-#endif
-                       c = *pf++;
-                       if (c == '\\') {
-                               c = parse_escape(&pf);
-                               if (c < 0) {
-                                       if (do_lint)
-                                               lintwarn(_("backslash at end of 
string"));
-                                       c = '\\';
-                               }
-                               *ptm++ = c;
-                       } else
-                               *ptm++ = c;
-               }
-               len = ptm - r->stptr;
-               erealloc(r->stptr, char *, len + 1, "make_str_node");
-               r->stptr[len] = '\0';
-               r->flags &= ~MALLOC;
-               r->flags |= PERM;
-       }
-       r->stlen = len;
-       r->valref = 1;
-       r->stfmt = -1;
-
+       r->wstptr = NULL;
+       r->wstlen = 0;
+#endif /* defined MBS_SUPPORT */
        return r;
 }
 
-/* more_nodes --- allocate more nodes */
-
-#define NODECHUNK      100
-
-NODE *nextfree = NULL;
-
-NODE *
-more_nodes()
-{
-       NODE *np;
-
-       /* get more nodes and initialize list */
-       emalloc(nextfree, NODE *, NODECHUNK * sizeof(NODE), "more_nodes");
-       memset(nextfree, 0, NODECHUNK * sizeof(NODE));
-       for (np = nextfree; np <= &nextfree[NODECHUNK - 1]; np++) {
-               np->nextp = np + 1;
-       }
-       --np;
-       np->nextp = NULL;
-       np = nextfree;
-       nextfree = nextfree->nextp;
-       return np;
-}
 
 /* unref --- remove reference to a particular node */
 
 void
-unref(NODE *tmp)
+r_unref(NODE *tmp)
 {
+#ifdef GAWKDEBUG
        if (tmp == NULL)
                return;
-       if ((tmp->flags & PERM) != 0)
-               return;
-
-       if (tmp->type == Node_ahash) {
-               if (tmp->ahname_ref > 1)
-                       tmp->ahname_ref--;
-               else {
-                       efree(tmp->ahname_str);
-                       freenode(tmp);
-               }
-               return;
-       }
-
        if ((tmp->flags & MALLOC) != 0) {
                if (tmp->valref > 1) {
-                       tmp->valref--;  
+                       tmp->valref--;
                        return;
-               } 
+               }
                if (tmp->flags & STRCUR)
                        efree(tmp->stptr);
        }
+#else
+       if ((tmp->flags & (MALLOC|STRCUR)) == (MALLOC|STRCUR))
+               efree(tmp->stptr);
+#endif
+
        free_wstr(tmp);
        freenode(tmp);
 }
@@ -615,6 +528,61 @@ parse_escape(const char **string_ptr)
        }
 }
 
+
+/* scan_escape --- scan for escape sequences */
+
+size_t
+scan_escape(char *s, size_t len)
+{
+       const char *pf;
+       char *ptm;
+       int c;
+       const char *end;
+#ifdef MBS_SUPPORT
+       mbstate_t cur_state;
+
+       memset(& cur_state, 0, sizeof(cur_state));
+#endif
+
+       end = & s[len];
+       for (pf = ptm = s; pf < end;) {
+#ifdef MBS_SUPPORT
+               /*
+                * Keep multibyte characters together. This avoids
+                * problems if a subsequent byte of a multibyte
+                * character happens to be a backslash.
+                */
+               if (gawk_mb_cur_max > 1) {
+                       int mblen = mbrlen(pf, end-pf, &cur_state);
+
+                       if (mblen > 1) {
+                               int i;
+
+                               for (i = 0; i < mblen; i++)
+                                       *ptm++ = *pf++;
+                               continue;
+                       }
+               }
+#endif
+               c = *pf++;
+               if (c == '\\') {
+                       c = parse_escape(&pf);
+                       if (c < 0) {
+                               if (do_lint)
+                                       lintwarn(_("backslash at end of 
string"));
+                               c = '\\';
+                       }
+                       *ptm++ = c;
+               } else
+                       *ptm++ = c;
+       }
+
+       len = ptm - s;
+       s[len] = '\0';
+       return len;
+}
+
+
 /* isnondecimal --- return true if number is not a decimal number */
 
 int
@@ -963,3 +931,41 @@ void init_btowc_cache()
        }
 }
 #endif
+
+#define BLOCKCHUNK 100
+
+BLOCK nextfree[BLOCK_MAX] = {
+       { 0, NULL},     /* invalid */   
+       { sizeof(NODE), NULL },
+       { sizeof(BUCKET), NULL },
+};
+
+
+/* more_blocks --- get more blocks of memory and add to the free list;
+       size of a block must be >= sizeof(BLOCK)
+ */
+
+void *
+more_blocks(int id)
+{
+       BLOCK *freep, *np, *next;
+       char *p, *endp;
+       size_t size;
+
+       size = nextfree[id].size;
+
+       emalloc(freep, BLOCK *, BLOCKCHUNK * size, "more_blocks");
+       p = (char *) freep;
+       endp = p + BLOCKCHUNK * size;
+
+       for (np = freep; ; np = next) {
+               next = (BLOCK *) (p += size);
+               if (p >= endp) {
+                       np->freep = NULL;
+                       break;
+               }
+               np->freep = next;
+       }
+       nextfree[id].freep = freep->freep;
+       return freep;
+}
diff --git a/profile.c b/profile.c
index cba8be9..a4a5e9d 100644
--- a/profile.c
+++ b/profile.c
@@ -51,7 +51,7 @@ static RETSIGTYPE just_dump(int signum);
 /* pretty printing related functions and variables */
 
 static NODE *pp_stack = NULL;
-static char **fparms;  /* function parameter names */
+static NODE *func_params;      /* function parameters */
 static FILE *prof_fp;  /* where to send the profile */
 
 static long indent_level = 0;
@@ -66,7 +66,7 @@ init_profiling(int *flag ATTRIBUTE_UNUSED, const char 
*def_file ATTRIBUTE_UNUSED
 {
 #ifdef PROFILING
        if (*flag == FALSE) {
-               *flag = TRUE;
+               *flag |= DO_PROFILING;
                set_prof_file(def_file);
        }
 #endif
@@ -257,6 +257,9 @@ pprint(INSTRUCTION *startp, INSTRUCTION *endp, int 
in_for_header)
                        break;
 
                case Op_store_var:
+                       if (pc->initval != NULL)
+                               pp_push(Op_push_i, pp_node(pc->initval), 
CAN_FREE);
+                       /* fall through */
                case Op_store_sub:
                case Op_assign_concat:
                case Op_push_lhs:
@@ -267,7 +270,7 @@ pprint(INSTRUCTION *startp, INSTRUCTION *endp, int 
in_for_header)
                        m = pc->memory;
                        switch (m->type) {
                        case Node_param_list:
-                               pp_push(pc->opcode, fparms[m->param_cnt], 
DONT_FREE);
+                               pp_push(pc->opcode, 
func_params[m->param_cnt].param, DONT_FREE);
                                break;
 
                        case Node_var:
@@ -508,9 +511,13 @@ cleanup:
                        break;
 
                case Op_builtin:
+               case Op_ext_builtin:
                {
-                       static char *ext_func = "extension_function()";
-                       const char *fname = getfname(pc->builtin);
+                       const char *fname;
+                       if (pc->opcode == Op_builtin)
+                               fname = getfname(pc->builtin);
+                       else
+                               fname = (pc + 1)->func_name;
                        if (fname != NULL) {
                                if (pc->expr_count > 0) {
                                        tmp = pp_list(pc->expr_count, "()", ", 
");
@@ -520,10 +527,10 @@ cleanup:
                                        str = pp_concat(fname, "()", "");
                                pp_push(Op_builtin, str, CAN_FREE);
                        } else
-                               pp_push(Op_builtin, ext_func, DONT_FREE);
+                               fatal(_("internal error: builtin with null 
fname"));
                }
                        break;
-       
+
                case Op_K_print:
                case Op_K_printf:
                case Op_K_print_rec:
@@ -742,14 +749,15 @@ cleanup:
 
                case Op_K_arrayfor:
                {
-                       char *array, *item;
+                       char *array;
+                       const char *item;
 
                        ip = pc + 1;
                        t1 = pp_pop();
                        array = t1->pp_str;
                        m = ip->forloop_cond->array_var;
                        if (m->type == Node_param_list)
-                               item = fparms[m->param_cnt];
+                               item = func_params[m->param_cnt].param;
                        else
                                item = m->vname;
                        indent(ip->forloop_body->exec_count);
@@ -1307,9 +1315,8 @@ int
 pp_func(INSTRUCTION *pc, void *data ATTRIBUTE_UNUSED)
 {
        int j;
-       char **pnames;
-       NODE *f;
        static int first = TRUE;
+       NODE *func;
        int pcount;
 
        if (first) {
@@ -1317,15 +1324,14 @@ pp_func(INSTRUCTION *pc, void *data ATTRIBUTE_UNUSED)
                fprintf(prof_fp, _("\n\t# Functions, listed alphabetically\n"));
        }
 
-       f = pc->func_body;
+       func = pc->func_body;
        fprintf(prof_fp, "\n");
        indent(pc->nexti->exec_count);
-       fprintf(prof_fp, "%s %s(", op2str(Op_K_function), f->lnode->param);
-       pnames = f->parmlist;
-       fparms = pnames;
-       pcount = f->lnode->param_cnt;
+       fprintf(prof_fp, "%s %s(", op2str(Op_K_function), func->vname);
+       pcount = func->param_cnt;
+       func_params = func->fparms;
        for (j = 0; j < pcount; j++) {
-               fprintf(prof_fp, "%s", pnames[j]);
+               fprintf(prof_fp, "%s", func_params[j].param);
                if (j < pcount - 1)
                        fprintf(prof_fp, ", ");
        }
diff --git a/test/Makefile.am b/test/Makefile.am
index 2d7bf34..256d8ae 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -214,6 +214,7 @@ EXTRA_DIST = \
        fnarray.awk \
        fnarray.ok \
        fnarray2.awk \
+       fnarray2.in \
        fnarray2.ok \
        fnarydel.awk \
        fnarydel.ok \
diff --git a/test/Makefile.in b/test/Makefile.in
index 04ea041..0017424 100644
--- a/test/Makefile.in
+++ b/test/Makefile.in
@@ -399,6 +399,7 @@ EXTRA_DIST = \
        fnarray.awk \
        fnarray.ok \
        fnarray2.awk \
+       fnarray2.in \
        fnarray2.ok \
        fnarydel.awk \
        fnarydel.ok \
@@ -1969,7 +1970,7 @@ fnarray:
 
 fnarray2:
        @echo fnarray2
-       @AWKPATH=$(srcdir) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @AWKPATH=$(srcdir) $(AWK) -f address@hidden  < $(srcdir)/address@hidden 
>_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
        @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
 
 fnaryscl:
diff --git a/test/Maketests b/test/Maketests
index 9a16eb7..8c363e2 100644
--- a/test/Maketests
+++ b/test/Maketests
@@ -242,7 +242,7 @@ fnarray:
 
 fnarray2:
        @echo fnarray2
-       @AWKPATH=$(srcdir) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @AWKPATH=$(srcdir) $(AWK) -f address@hidden  < $(srcdir)/address@hidden 
>_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
        @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
 
 fnaryscl:
diff --git a/test/delfunc.ok b/test/delfunc.ok
index d12f0bc..29a7450 100644
--- a/test/delfunc.ok
+++ b/test/delfunc.ok
@@ -1,2 +1,3 @@
-gawk: delfunc.awk:4: fatal: attempt to use function `f' as an array
-EXIT CODE: 2
+gawk: delfunc.awk:4: error: function `f' called with space between name and 
`(',
+or used as a variable or an array
+EXIT CODE: 1
diff --git a/test/fnamedat.ok b/test/fnamedat.ok
index d32acff..d7b71c4 100644
--- a/test/fnamedat.ok
+++ b/test/fnamedat.ok
@@ -1,2 +1,3 @@
-gawk: fnamedat.awk:1: (FILENAME=- FNR=1) fatal: can't use function name `foo' 
as variable or array
-EXIT CODE: 2
+gawk: fnamedat.awk:1: error: function `foo' called with space between name and 
`(',
+or used as a variable or an array
+EXIT CODE: 1
diff --git a/test/fnarray.ok b/test/fnarray.ok
index 04260b0..6cab913 100644
--- a/test/fnarray.ok
+++ b/test/fnarray.ok
@@ -1,5 +1,3 @@
-gawk: fnarray.awk:5:   Num = foo[c]
-gawk: fnarray.awk:5:              ^ use of non-array as array
 gawk: fnarray.awk:5: error: function `foo' called with space between name and 
`(',
 or used as a variable or an array
 EXIT CODE: 1
diff --git a/test/fnarray2.ok b/test/fnarray2.ok
index 243e4cc..8281505 100644
--- a/test/fnarray2.ok
+++ b/test/fnarray2.ok
@@ -1,3 +1,3 @@
-gawk: fnarray2.awk:3:  r = ++pile[c]
-gawk: fnarray2.awk:3:              ^ use of non-array as array
+gawk: fnarray2.awk:3: error: function `pile' called with space between name 
and `(',
+or used as a variable or an array
 EXIT CODE: 1
diff --git a/test/fnarydel.ok b/test/fnarydel.ok
index 7f3e453..7078c01 100644
--- a/test/fnarydel.ok
+++ b/test/fnarydel.ok
@@ -1,24 +1,24 @@
 first loop
+1
+2
+3
 4
 5
 6
 7
 8
 9
+second loop
+third loop
 1
 2
 3
-second loop
-third loop
 4
 5
 6
 7
 8
 9
-1
-2
-3
 call func
 fourth loop
 You should just see: 4 4
diff --git a/test/fnasgnm.ok b/test/fnasgnm.ok
index 0db5c6d..5cacff2 100644
--- a/test/fnasgnm.ok
+++ b/test/fnasgnm.ok
@@ -1,2 +1,3 @@
-gawk: fnasgnm.awk:14: (FILENAME=- FNR=1) fatal: can't use function name 
`ShowMe' as variable or array
-EXIT CODE: 2
+gawk: fnasgnm.awk:14: error: function `ShowMe' called with space between name 
and `(',
+or used as a variable or an array
+EXIT CODE: 1
diff --git a/test/fnparydl.ok b/test/fnparydl.ok
index 26a5c39..9f79822 100644
--- a/test/fnparydl.ok
+++ b/test/fnparydl.ok
@@ -1,10 +1,10 @@
 BEFORE LOOP
+DELETING KEY 1
+DELETING KEY 2
+DELETING KEY 3
 DELETING KEY 4
 DELETING KEY 5
 DELETING KEY 6
 DELETING KEY 7
-DELETING KEY 1
-DELETING KEY 2
-DELETING KEY 3
 AFTER LOOP
 0 elements still in q[]
diff --git a/test/funsmnam.ok b/test/funsmnam.ok
index e4f2174..cce0d27 100644
--- a/test/funsmnam.ok
+++ b/test/funsmnam.ok
@@ -1,2 +1,2 @@
-gawk: funsmnam.awk:1: error: function `foo': can't use function name as 
parameter name
+gawk: funsmnam.awk:2: error: function `foo': can't use function name as 
parameter name
 EXIT CODE: 1
diff --git a/test/gsubasgn.ok b/test/gsubasgn.ok
index 8817c36..8a309c7 100644
--- a/test/gsubasgn.ok
+++ b/test/gsubasgn.ok
@@ -1,5 +1,5 @@
-gawk: gsubasgn.awk:4: function test1 (r) { gsub(r, "x", test1) }
-gawk: gsubasgn.awk:4:                                        ^ gsub third 
parameter is not a changeable object
-gawk: gsubasgn.awk:8: function test2 () { gsub(/a/, "x", test2) }
-gawk: gsubasgn.awk:8:                                         ^ gsub third 
parameter is not a changeable object
+gawk: gsubasgn.awk:4: error: function `test1' called with space between name 
and `(',
+or used as a variable or an array
+gawk: gsubasgn.awk:8: error: function `test2' called with space between name 
and `(',
+or used as a variable or an array
 EXIT CODE: 1
diff --git a/test/match2.ok b/test/match2.ok
index a4a91e8..ad2e324 100644
--- a/test/match2.ok
+++ b/test/match2.ok
@@ -1,2 +1,3 @@
-gawk: match2.awk:3: fatal: match: third argument is not an array
-EXIT CODE: 2
+gawk: match2.awk:3: error: function `f' called with space between name and `(',
+or used as a variable or an array
+EXIT CODE: 1

-----------------------------------------------------------------------


hooks/post-receive
-- 
gawk



reply via email to

[Prev in Thread] Current Thread [Next in Thread]