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. 118622c2a66b3


From: John Haque
Subject: [gawk-diffs] [SCM] gawk branch, gawk_performance, created. 118622c2a66b302ec9706ccd3296a6cc2b8bfb13
Date: Wed, 12 Oct 2011 13:33:03 +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  118622c2a66b302ec9706ccd3296a6cc2b8bfb13 (commit)

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

commit 118622c2a66b302ec9706ccd3296a6cc2b8bfb13
Author: john haque <address@hidden>
Date:   Tue Oct 11 07:16:35 2011 -0500

    Add GPL notice in symbol.c.

diff --git a/ChangeLog b/ChangeLog
index 292e670..0c3d0c0 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -6,6 +6,11 @@
        (remap_std_file): Per Eli's suggestion, removed the leading close
        of oldfd and will let dup2 do the close for us.
 
+2011-10-11         John Haque     <address@hidden>
+
+       * symbol.c: Add licence notice.
+       * array.c (PREC_NUM, PREC_STR): Define as macros.
+
 2011-10-09         Arnold D. Robbins     <address@hidden>
 
        * dfa.c: Sync with GNU grep.
diff --git a/array.c b/array.c
index a750828..70e0dec 100644
--- a/array.c
+++ b/array.c
@@ -660,12 +660,14 @@ do_delete_loop(NODE *symbol, NODE **lhs)
 
 /* value_info --- print scalar node info */
 
-int PREC_NUM = -1;
-int PREC_STR = -1;
 
 static void
 value_info(NODE *n)
 {
+
+#define PREC_NUM -1
+#define PREC_STR -1
+
        if (n == Nnull_string || n == Null_field) {
                fprintf(output_fp, "<(null)>");
                return;
@@ -693,6 +695,9 @@ value_info(NODE *n)
                fprintf(output_fp, "CONVFMT=\"%s\"", n->stfmt <= -1 ? "%ld"
                                        : fmt_list[n->stfmt]->stptr);
        }
+
+#undef PREC_NUM
+#undef PREC_STR
 }
 
 
diff --git a/symbol.c b/symbol.c
index a1c598e..57ca7be 100644
--- a/symbol.c
+++ b/symbol.c
@@ -1,3 +1,28 @@
+/*
+ * symbol.c - routines for symbol table management and code allocation
+ */
+
+/* 
+ * Copyright (C) 1986, 1988, 1989, 1991-2011 the Free Software Foundation, Inc.
+ * 
+ * This file is part of GAWK, the GNU implementation of the
+ * AWK Programming Language.
+ * 
+ * GAWK is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * GAWK is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
USA
+ */
+
 #include "awk.h"
 
 extern SRCFILE *srcfiles;

http://git.sv.gnu.org/cgit/gawk.git/commit/?id=9d8d0cf6e83832f2d9902b23b8513402c648c59d

commit 9d8d0cf6e83832f2d9902b23b8513402c648c59d
Author: john haque <address@hidden>
Date:   Fri Oct 7 05:13:25 2011 -0500

    Optimize tail-recursive calls.

diff --git a/ChangeLog b/ChangeLog
index bd69e57..292e670 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -10,6 +10,16 @@
 
        * dfa.c: Sync with GNU grep.
 
+2011-10-07         John Haque     <address@hidden>
+
+       Tail recursion optimization.
+       * awkgram.y (grammar, mk_function): Recognize tail-recursive
+       calls.
+       * awk.h (tail_call, num_tail_calls): New defines.
+       * eval.c (setup_frame): Reuse function call stack for
+       tail-recursive calls.
+       (dump_fcall_stack): Reworked.
+
 2011-10-04         Arnold D. Robbins     <address@hidden>
 
        * awk.h, main.c (gawk_mb_cur_max): Make it a constant 1 when
diff --git a/array.c b/array.c
index 3ffc0db..a750828 100644
--- a/array.c
+++ b/array.c
@@ -1285,6 +1285,7 @@ assoc_list(NODE *symbol, const char *sort_str, SORT_CTXT 
sort_ctxt)
        qsort_compfunc cmp_func = 0;
        INSTRUCTION *code = NULL;
        extern int currule;
+       int save_rule;
        
        num_elems = symbol->table_size;
        assert(num_elems > 0);
@@ -1345,7 +1346,7 @@ assoc_list(NODE *symbol, const char *sort_str, SORT_CTXT 
sort_ctxt)
                 * to undefined (0). `exit' is handled in sort_user_func.
                 */
 
-               (code + 1)->inrule = currule;   /* save current rule */
+               save_rule = currule;    /* save current rule */
                currule = 0;
 
                PUSH_CODE(code);
@@ -1360,7 +1361,7 @@ assoc_list(NODE *symbol, const char *sort_str, SORT_CTXT 
sort_ctxt)
 
        if (cmp_func == sort_user_func) {
                code = POP_CODE();
-               currule = (code + 1)->inrule;   /* restore current rule */ 
+               currule = save_rule;            /* restore current rule */ 
                bcfree(code->nexti);            /* Op_stop */
                bcfree(code);                   /* Op_func_call */
        }
diff --git a/awk.h b/awk.h
index f65426b..2bb325b 100644
--- a/awk.h
+++ b/awk.h
@@ -459,6 +459,7 @@ typedef struct exp_node {
 #define func_node    sub.nodep.x.extra
 #define prev_frame_size        sub.nodep.reflags
 #define reti         sub.nodep.l.li
+#define num_tail_calls    sub.nodep.cnt
 
 /* Node_var: */
 #define var_value    lnode
@@ -728,7 +729,6 @@ typedef struct exp_instruction {
 #define lextok          d.name
 #define param_count     x.xl
 
-
 /* Op_rule */
 #define in_rule         x.xl
 #define source_file     d.name
@@ -765,7 +765,7 @@ typedef struct exp_instruction {
 #define func_body       x.xn
 
 /* Op_func_call */
-#define inrule          d.dl
+#define tail_call      d.dl
 
 /* Op_subscript */
 #define sub_count       d.dl
diff --git a/awkgram.c b/awkgram.c
index b9e3002..298e3a0 100644
--- a/awkgram.c
+++ b/awkgram.c
@@ -128,7 +128,7 @@ static int one_line_close(int fd);
 
 static int want_source = FALSE;
 static int want_regexp;                /* lexical scanning kludge */
-static int can_return;         /* parsing kludge */
+static char *in_function;              /* parsing kludge */
 static int rule = 0;
 
 const char *const ruletab[] = {
@@ -707,20 +707,20 @@ static const yytype_uint16 yyrline[] =
      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,   737,   744,   751,   761,   770,
-     779,   788,   803,   819,   818,   830,   842,   842,   936,   936,
-     961,   984,   990,   991,   997,   998,  1005,  1010,  1022,  1036,
-    1038,  1044,  1049,  1051,  1059,  1061,  1070,  1071,  1079,  1084,
-    1084,  1095,  1099,  1107,  1108,  1111,  1113,  1118,  1119,  1128,
-    1129,  1134,  1139,  1145,  1147,  1149,  1156,  1157,  1163,  1164,
-    1169,  1171,  1176,  1178,  1180,  1182,  1188,  1195,  1197,  1199,
-    1215,  1225,  1232,  1234,  1239,  1241,  1243,  1251,  1253,  1258,
-    1260,  1265,  1267,  1269,  1319,  1321,  1323,  1325,  1327,  1329,
-    1331,  1333,  1356,  1361,  1366,  1391,  1397,  1399,  1401,  1403,
-    1405,  1407,  1412,  1416,  1447,  1449,  1455,  1461,  1474,  1475,
-    1476,  1481,  1486,  1490,  1494,  1507,  1520,  1525,  1561,  1579,
-    1580,  1586,  1587,  1592,  1594,  1601,  1618,  1635,  1637,  1644,
-    1649,  1657,  1667,  1679,  1688,  1692,  1696,  1700,  1704,  1708,
-    1711,  1713,  1717,  1721,  1725
+     779,   788,   803,   819,   818,   842,   854,   854,   948,   948,
+     973,   996,  1002,  1003,  1009,  1010,  1017,  1022,  1034,  1048,
+    1050,  1056,  1061,  1063,  1071,  1073,  1082,  1083,  1091,  1096,
+    1096,  1107,  1111,  1119,  1120,  1123,  1125,  1130,  1131,  1140,
+    1141,  1146,  1151,  1157,  1159,  1161,  1168,  1169,  1175,  1176,
+    1181,  1183,  1188,  1190,  1192,  1194,  1200,  1207,  1209,  1211,
+    1227,  1237,  1244,  1246,  1251,  1253,  1255,  1263,  1265,  1270,
+    1272,  1277,  1279,  1281,  1331,  1333,  1335,  1337,  1339,  1341,
+    1343,  1345,  1368,  1373,  1378,  1403,  1409,  1411,  1413,  1415,
+    1417,  1419,  1424,  1428,  1459,  1461,  1467,  1473,  1486,  1487,
+    1488,  1493,  1498,  1502,  1506,  1519,  1532,  1537,  1573,  1591,
+    1592,  1598,  1599,  1604,  1606,  1613,  1630,  1647,  1649,  1656,
+    1661,  1669,  1679,  1691,  1700,  1704,  1708,  1712,  1716,  1720,
+    1723,  1725,  1729,  1733,  1737
 };
 #endif
 
@@ -2099,7 +2099,7 @@ yyreduce:
 /* Line 1821 of yacc.c  */
 #line 231 "awkgram.y"
     {
-               can_return = FALSE;
+               in_function = NULL;
                (void) mk_function((yyvsp[(1) - (2)]), (yyvsp[(2) - (2)]));
                yyerrok;
          }
@@ -2293,11 +2293,11 @@ yyreduce:
                (yyvsp[(1) - (6)])->source_file = source;
                if (install_function((yyvsp[(2) - (6)])->lextok, (yyvsp[(1) - 
(6)]), (yyvsp[(4) - (6)])) < 0)
                        YYABORT;
+               in_function = (yyvsp[(2) - (6)])->lextok;
                (yyvsp[(2) - (6)])->lextok = NULL;
                bcfree((yyvsp[(2) - (6)]));
                /* $4 already free'd in install_function */
                (yyval) = (yyvsp[(1) - (6)]);
-               can_return = TRUE;
          }
     break;
 
@@ -2837,7 +2837,7 @@ regular_loop:
 /* Line 1821 of yacc.c  */
 #line 819 "awkgram.y"
     {
-               if (! can_return)
+               if (! in_function)
                        yyerror(_("`return' used outside function context"));
          }
     break;
@@ -2851,22 +2851,34 @@ regular_loop:
                        (yyval) = list_create((yyvsp[(1) - (4)]));
                        (void) list_prepend((yyval), instruction(Op_push_i));
                        (yyval)->nexti->memory = dupnode(Nnull_string);
-               } else
+               } else {
+                       if (do_optimize > 1
+                               && (yyvsp[(3) - (4)])->lasti->opcode == 
Op_func_call
+                               && STREQ((yyvsp[(3) - (4)])->lasti->func_name, 
in_function)
+                       ) {
+                               /* Do tail recursion optimization. Tail
+                                * call without a return value is recognized
+                                * in mk_function().
+                                */
+                               ((yyvsp[(3) - (4)])->lasti + 1)->tail_call = 
TRUE;
+                       }
+
                        (yyval) = list_append((yyvsp[(3) - (4)]), (yyvsp[(1) - 
(4)]));
+               }
          }
     break;
 
   case 56:
 
 /* Line 1821 of yacc.c  */
-#line 842 "awkgram.y"
+#line 854 "awkgram.y"
     { in_print = TRUE; in_parens = 0; }
     break;
 
   case 57:
 
 /* Line 1821 of yacc.c  */
-#line 843 "awkgram.y"
+#line 855 "awkgram.y"
     {
                /*
                 * Optimization: plain `print' has no expression list, so $3 is 
null.
@@ -2964,14 +2976,14 @@ regular_loop:
   case 58:
 
 /* Line 1821 of yacc.c  */
-#line 936 "awkgram.y"
+#line 948 "awkgram.y"
     { sub_counter = 0; }
     break;
 
   case 59:
 
 /* Line 1821 of yacc.c  */
-#line 937 "awkgram.y"
+#line 949 "awkgram.y"
     {
                char *arr = (yyvsp[(2) - (4)])->lextok;
 
@@ -3001,7 +3013,7 @@ regular_loop:
   case 60:
 
 /* Line 1821 of yacc.c  */
-#line 966 "awkgram.y"
+#line 978 "awkgram.y"
     {
                static short warned = FALSE;
                char *arr = (yyvsp[(3) - (4)])->lextok;
@@ -3025,35 +3037,35 @@ regular_loop:
   case 61:
 
 /* Line 1821 of yacc.c  */
-#line 985 "awkgram.y"
+#line 997 "awkgram.y"
     {  (yyval) = optimize_assignment((yyvsp[(1) - (1)])); }
     break;
 
   case 62:
 
 /* Line 1821 of yacc.c  */
-#line 990 "awkgram.y"
+#line 1002 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 63:
 
 /* Line 1821 of yacc.c  */
-#line 992 "awkgram.y"
+#line 1004 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 64:
 
 /* Line 1821 of yacc.c  */
-#line 997 "awkgram.y"
+#line 1009 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 65:
 
 /* Line 1821 of yacc.c  */
-#line 999 "awkgram.y"
+#line 1011 "awkgram.y"
     {
                if ((yyvsp[(1) - (2)]) == NULL)
                        (yyval) = list_create((yyvsp[(2) - (2)]));
@@ -3065,14 +3077,14 @@ regular_loop:
   case 66:
 
 /* Line 1821 of yacc.c  */
-#line 1006 "awkgram.y"
+#line 1018 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 67:
 
 /* Line 1821 of yacc.c  */
-#line 1011 "awkgram.y"
+#line 1023 "awkgram.y"
     {
                INSTRUCTION *casestmt = (yyvsp[(5) - (5)]);
                if ((yyvsp[(5) - (5)]) == NULL)
@@ -3089,7 +3101,7 @@ regular_loop:
   case 68:
 
 /* Line 1821 of yacc.c  */
-#line 1023 "awkgram.y"
+#line 1035 "awkgram.y"
     {
                INSTRUCTION *casestmt = (yyvsp[(4) - (4)]);
                if ((yyvsp[(4) - (4)]) == NULL)
@@ -3105,14 +3117,14 @@ regular_loop:
   case 69:
 
 /* Line 1821 of yacc.c  */
-#line 1037 "awkgram.y"
+#line 1049 "awkgram.y"
     {  (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 70:
 
 /* Line 1821 of yacc.c  */
-#line 1039 "awkgram.y"
+#line 1051 "awkgram.y"
     { 
                (yyvsp[(2) - (2)])->memory->numbr = -(force_number((yyvsp[(2) - 
(2)])->memory));
                bcfree((yyvsp[(1) - (2)]));
@@ -3123,7 +3135,7 @@ regular_loop:
   case 71:
 
 /* Line 1821 of yacc.c  */
-#line 1045 "awkgram.y"
+#line 1057 "awkgram.y"
     {
                bcfree((yyvsp[(1) - (2)]));
                (yyval) = (yyvsp[(2) - (2)]);
@@ -3133,14 +3145,14 @@ regular_loop:
   case 72:
 
 /* Line 1821 of yacc.c  */
-#line 1050 "awkgram.y"
+#line 1062 "awkgram.y"
     {  (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 73:
 
 /* Line 1821 of yacc.c  */
-#line 1052 "awkgram.y"
+#line 1064 "awkgram.y"
     {
                (yyvsp[(1) - (1)])->opcode = Op_push_re;
                (yyval) = (yyvsp[(1) - (1)]);
@@ -3150,21 +3162,21 @@ regular_loop:
   case 74:
 
 /* Line 1821 of yacc.c  */
-#line 1060 "awkgram.y"
+#line 1072 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 75:
 
 /* Line 1821 of yacc.c  */
-#line 1062 "awkgram.y"
+#line 1074 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 77:
 
 /* Line 1821 of yacc.c  */
-#line 1072 "awkgram.y"
+#line 1084 "awkgram.y"
     {
                (yyval) = (yyvsp[(2) - (3)]);
          }
@@ -3173,7 +3185,7 @@ regular_loop:
   case 78:
 
 /* Line 1821 of yacc.c  */
-#line 1079 "awkgram.y"
+#line 1091 "awkgram.y"
     {
                in_print = FALSE;
                in_parens = 0;
@@ -3184,14 +3196,14 @@ regular_loop:
   case 79:
 
 /* Line 1821 of yacc.c  */
-#line 1084 "awkgram.y"
+#line 1096 "awkgram.y"
     { in_print = FALSE; in_parens = 0; }
     break;
 
   case 80:
 
 /* Line 1821 of yacc.c  */
-#line 1085 "awkgram.y"
+#line 1097 "awkgram.y"
     {
                if ((yyvsp[(1) - (3)])->redir_type == redirect_twoway
                        && (yyvsp[(3) - (3)])->lasti->opcode == 
Op_K_getline_redir
@@ -3204,7 +3216,7 @@ regular_loop:
   case 81:
 
 /* Line 1821 of yacc.c  */
-#line 1096 "awkgram.y"
+#line 1108 "awkgram.y"
     {
                (yyval) = mk_condition((yyvsp[(3) - (6)]), (yyvsp[(1) - (6)]), 
(yyvsp[(6) - (6)]), NULL, NULL);
          }
@@ -3213,7 +3225,7 @@ regular_loop:
   case 82:
 
 /* Line 1821 of yacc.c  */
-#line 1101 "awkgram.y"
+#line 1113 "awkgram.y"
     {
                (yyval) = mk_condition((yyvsp[(3) - (9)]), (yyvsp[(1) - (9)]), 
(yyvsp[(6) - (9)]), (yyvsp[(7) - (9)]), (yyvsp[(9) - (9)]));
          }
@@ -3222,14 +3234,14 @@ regular_loop:
   case 87:
 
 /* Line 1821 of yacc.c  */
-#line 1118 "awkgram.y"
+#line 1130 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 88:
 
 /* Line 1821 of yacc.c  */
-#line 1120 "awkgram.y"
+#line 1132 "awkgram.y"
     {
                bcfree((yyvsp[(1) - (2)]));
                (yyval) = (yyvsp[(2) - (2)]);
@@ -3239,21 +3251,21 @@ regular_loop:
   case 89:
 
 /* Line 1821 of yacc.c  */
-#line 1128 "awkgram.y"
+#line 1140 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 90:
 
 /* Line 1821 of yacc.c  */
-#line 1130 "awkgram.y"
+#line 1142 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]) ; }
     break;
 
   case 91:
 
 /* Line 1821 of yacc.c  */
-#line 1135 "awkgram.y"
+#line 1147 "awkgram.y"
     {
                (yyvsp[(1) - (1)])->param_count = 0;
                (yyval) = list_create((yyvsp[(1) - (1)]));
@@ -3263,7 +3275,7 @@ regular_loop:
   case 92:
 
 /* Line 1821 of yacc.c  */
-#line 1140 "awkgram.y"
+#line 1152 "awkgram.y"
     {
                (yyvsp[(3) - (3)])->param_count =  (yyvsp[(1) - 
(3)])->lasti->param_count + 1;
                (yyval) = list_append((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]));
@@ -3274,63 +3286,63 @@ regular_loop:
   case 93:
 
 /* Line 1821 of yacc.c  */
-#line 1146 "awkgram.y"
+#line 1158 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 94:
 
 /* Line 1821 of yacc.c  */
-#line 1148 "awkgram.y"
+#line 1160 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (2)]); }
     break;
 
   case 95:
 
 /* Line 1821 of yacc.c  */
-#line 1150 "awkgram.y"
+#line 1162 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (3)]); }
     break;
 
   case 96:
 
 /* Line 1821 of yacc.c  */
-#line 1156 "awkgram.y"
+#line 1168 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 97:
 
 /* Line 1821 of yacc.c  */
-#line 1158 "awkgram.y"
+#line 1170 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 98:
 
 /* Line 1821 of yacc.c  */
-#line 1163 "awkgram.y"
+#line 1175 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 99:
 
 /* Line 1821 of yacc.c  */
-#line 1165 "awkgram.y"
+#line 1177 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 100:
 
 /* Line 1821 of yacc.c  */
-#line 1170 "awkgram.y"
+#line 1182 "awkgram.y"
     {  (yyval) = mk_expression_list(NULL, (yyvsp[(1) - (1)])); }
     break;
 
   case 101:
 
 /* Line 1821 of yacc.c  */
-#line 1172 "awkgram.y"
+#line 1184 "awkgram.y"
     {
                (yyval) = mk_expression_list((yyvsp[(1) - (3)]), (yyvsp[(3) - 
(3)]));
                yyerrok;
@@ -3340,35 +3352,35 @@ regular_loop:
   case 102:
 
 /* Line 1821 of yacc.c  */
-#line 1177 "awkgram.y"
+#line 1189 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 103:
 
 /* Line 1821 of yacc.c  */
-#line 1179 "awkgram.y"
+#line 1191 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 104:
 
 /* Line 1821 of yacc.c  */
-#line 1181 "awkgram.y"
+#line 1193 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 105:
 
 /* Line 1821 of yacc.c  */
-#line 1183 "awkgram.y"
+#line 1195 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 106:
 
 /* Line 1821 of yacc.c  */
-#line 1189 "awkgram.y"
+#line 1201 "awkgram.y"
     {
                if (do_lint && (yyvsp[(3) - (3)])->lasti->opcode == 
Op_match_rec)
                        lintwarn_ln((yyvsp[(2) - (3)])->source_line,
@@ -3380,21 +3392,21 @@ regular_loop:
   case 107:
 
 /* Line 1821 of yacc.c  */
-#line 1196 "awkgram.y"
+#line 1208 "awkgram.y"
     {  (yyval) = mk_boolean((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) 
- (3)])); }
     break;
 
   case 108:
 
 /* Line 1821 of yacc.c  */
-#line 1198 "awkgram.y"
+#line 1210 "awkgram.y"
     {  (yyval) = mk_boolean((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) 
- (3)])); }
     break;
 
   case 109:
 
 /* Line 1821 of yacc.c  */
-#line 1200 "awkgram.y"
+#line 1212 "awkgram.y"
     {
                if ((yyvsp[(1) - (3)])->lasti->opcode == Op_match_rec)
                        warning_ln((yyvsp[(2) - (3)])->source_line,
@@ -3415,7 +3427,7 @@ regular_loop:
   case 110:
 
 /* Line 1821 of yacc.c  */
-#line 1216 "awkgram.y"
+#line 1228 "awkgram.y"
     {
                if (do_lint_old)
                        warning_ln((yyvsp[(2) - (3)])->source_line,
@@ -3430,7 +3442,7 @@ regular_loop:
   case 111:
 
 /* Line 1821 of yacc.c  */
-#line 1226 "awkgram.y"
+#line 1238 "awkgram.y"
     {
                if (do_lint && (yyvsp[(3) - (3)])->lasti->opcode == 
Op_match_rec)
                        lintwarn_ln((yyvsp[(2) - (3)])->source_line,
@@ -3442,35 +3454,35 @@ regular_loop:
   case 112:
 
 /* Line 1821 of yacc.c  */
-#line 1233 "awkgram.y"
+#line 1245 "awkgram.y"
     { (yyval) = mk_condition((yyvsp[(1) - (5)]), (yyvsp[(2) - (5)]), 
(yyvsp[(3) - (5)]), (yyvsp[(4) - (5)]), (yyvsp[(5) - (5)])); }
     break;
 
   case 113:
 
 /* Line 1821 of yacc.c  */
-#line 1235 "awkgram.y"
+#line 1247 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 114:
 
 /* Line 1821 of yacc.c  */
-#line 1240 "awkgram.y"
+#line 1252 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 115:
 
 /* Line 1821 of yacc.c  */
-#line 1242 "awkgram.y"
+#line 1254 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 116:
 
 /* Line 1821 of yacc.c  */
-#line 1244 "awkgram.y"
+#line 1256 "awkgram.y"
     {  
                (yyvsp[(2) - (2)])->opcode = Op_assign_quotient;
                (yyval) = (yyvsp[(2) - (2)]);
@@ -3480,49 +3492,49 @@ regular_loop:
   case 117:
 
 /* Line 1821 of yacc.c  */
-#line 1252 "awkgram.y"
+#line 1264 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 118:
 
 /* Line 1821 of yacc.c  */
-#line 1254 "awkgram.y"
+#line 1266 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 119:
 
 /* Line 1821 of yacc.c  */
-#line 1259 "awkgram.y"
+#line 1271 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 120:
 
 /* Line 1821 of yacc.c  */
-#line 1261 "awkgram.y"
+#line 1273 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 121:
 
 /* Line 1821 of yacc.c  */
-#line 1266 "awkgram.y"
+#line 1278 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 122:
 
 /* Line 1821 of yacc.c  */
-#line 1268 "awkgram.y"
+#line 1280 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 123:
 
 /* Line 1821 of yacc.c  */
-#line 1270 "awkgram.y"
+#line 1282 "awkgram.y"
     {
                int count = 2;
                int is_simple_var = FALSE;
@@ -3574,49 +3586,49 @@ regular_loop:
   case 125:
 
 /* Line 1821 of yacc.c  */
-#line 1322 "awkgram.y"
+#line 1334 "awkgram.y"
     { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - 
(3)])); }
     break;
 
   case 126:
 
 /* Line 1821 of yacc.c  */
-#line 1324 "awkgram.y"
+#line 1336 "awkgram.y"
     { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - 
(3)])); }
     break;
 
   case 127:
 
 /* Line 1821 of yacc.c  */
-#line 1326 "awkgram.y"
+#line 1338 "awkgram.y"
     { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - 
(3)])); }
     break;
 
   case 128:
 
 /* Line 1821 of yacc.c  */
-#line 1328 "awkgram.y"
+#line 1340 "awkgram.y"
     { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - 
(3)])); }
     break;
 
   case 129:
 
 /* Line 1821 of yacc.c  */
-#line 1330 "awkgram.y"
+#line 1342 "awkgram.y"
     { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - 
(3)])); }
     break;
 
   case 130:
 
 /* Line 1821 of yacc.c  */
-#line 1332 "awkgram.y"
+#line 1344 "awkgram.y"
     { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - 
(3)])); }
     break;
 
   case 131:
 
 /* Line 1821 of yacc.c  */
-#line 1334 "awkgram.y"
+#line 1346 "awkgram.y"
     {
                /*
                 * In BEGINFILE/ENDFILE, allow `getline var < file'
@@ -3644,7 +3656,7 @@ regular_loop:
   case 132:
 
 /* Line 1821 of yacc.c  */
-#line 1357 "awkgram.y"
+#line 1369 "awkgram.y"
     {
                (yyvsp[(2) - (2)])->opcode = Op_postincrement;
                (yyval) = mk_assignment((yyvsp[(1) - (2)]), NULL, (yyvsp[(2) - 
(2)]));
@@ -3654,7 +3666,7 @@ regular_loop:
   case 133:
 
 /* Line 1821 of yacc.c  */
-#line 1362 "awkgram.y"
+#line 1374 "awkgram.y"
     {
                (yyvsp[(2) - (2)])->opcode = Op_postdecrement;
                (yyval) = mk_assignment((yyvsp[(1) - (2)]), NULL, (yyvsp[(2) - 
(2)]));
@@ -3664,7 +3676,7 @@ regular_loop:
   case 134:
 
 /* Line 1821 of yacc.c  */
-#line 1367 "awkgram.y"
+#line 1379 "awkgram.y"
     {
                if (do_lint_old) {
                    warning_ln((yyvsp[(4) - (5)])->source_line,
@@ -3689,7 +3701,7 @@ regular_loop:
   case 135:
 
 /* Line 1821 of yacc.c  */
-#line 1392 "awkgram.y"
+#line 1404 "awkgram.y"
     {
                  (yyval) = mk_getline((yyvsp[(3) - (4)]), (yyvsp[(4) - (4)]), 
(yyvsp[(1) - (4)]), (yyvsp[(2) - (4)])->redir_type);
                  bcfree((yyvsp[(2) - (4)]));
@@ -3699,49 +3711,49 @@ regular_loop:
   case 136:
 
 /* Line 1821 of yacc.c  */
-#line 1398 "awkgram.y"
+#line 1410 "awkgram.y"
     { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - 
(3)])); }
     break;
 
   case 137:
 
 /* Line 1821 of yacc.c  */
-#line 1400 "awkgram.y"
+#line 1412 "awkgram.y"
     { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - 
(3)])); }
     break;
 
   case 138:
 
 /* Line 1821 of yacc.c  */
-#line 1402 "awkgram.y"
+#line 1414 "awkgram.y"
     { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - 
(3)])); }
     break;
 
   case 139:
 
 /* Line 1821 of yacc.c  */
-#line 1404 "awkgram.y"
+#line 1416 "awkgram.y"
     { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - 
(3)])); }
     break;
 
   case 140:
 
 /* Line 1821 of yacc.c  */
-#line 1406 "awkgram.y"
+#line 1418 "awkgram.y"
     { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - 
(3)])); }
     break;
 
   case 141:
 
 /* Line 1821 of yacc.c  */
-#line 1408 "awkgram.y"
+#line 1420 "awkgram.y"
     { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - 
(3)])); }
     break;
 
   case 142:
 
 /* Line 1821 of yacc.c  */
-#line 1413 "awkgram.y"
+#line 1425 "awkgram.y"
     {
                (yyval) = list_create((yyvsp[(1) - (1)]));
          }
@@ -3750,7 +3762,7 @@ regular_loop:
   case 143:
 
 /* Line 1821 of yacc.c  */
-#line 1417 "awkgram.y"
+#line 1429 "awkgram.y"
     {
                if ((yyvsp[(2) - (2)])->opcode == Op_match_rec) {
                        (yyvsp[(2) - (2)])->opcode = Op_nomatch;
@@ -3786,14 +3798,14 @@ regular_loop:
   case 144:
 
 /* Line 1821 of yacc.c  */
-#line 1448 "awkgram.y"
+#line 1460 "awkgram.y"
     { (yyval) = (yyvsp[(2) - (3)]); }
     break;
 
   case 145:
 
 /* Line 1821 of yacc.c  */
-#line 1450 "awkgram.y"
+#line 1462 "awkgram.y"
     {
                (yyval) = snode((yyvsp[(3) - (4)]), (yyvsp[(1) - (4)]));
                if ((yyval) == NULL)
@@ -3804,7 +3816,7 @@ regular_loop:
   case 146:
 
 /* Line 1821 of yacc.c  */
-#line 1456 "awkgram.y"
+#line 1468 "awkgram.y"
     {
                (yyval) = snode((yyvsp[(3) - (4)]), (yyvsp[(1) - (4)]));
                if ((yyval) == NULL)
@@ -3815,7 +3827,7 @@ regular_loop:
   case 147:
 
 /* Line 1821 of yacc.c  */
-#line 1462 "awkgram.y"
+#line 1474 "awkgram.y"
     {
                static short warned1 = FALSE;
 
@@ -3833,7 +3845,7 @@ regular_loop:
   case 150:
 
 /* Line 1821 of yacc.c  */
-#line 1477 "awkgram.y"
+#line 1489 "awkgram.y"
     {
                (yyvsp[(1) - (2)])->opcode = Op_preincrement;
                (yyval) = mk_assignment((yyvsp[(2) - (2)]), NULL, (yyvsp[(1) - 
(2)]));
@@ -3843,7 +3855,7 @@ regular_loop:
   case 151:
 
 /* Line 1821 of yacc.c  */
-#line 1482 "awkgram.y"
+#line 1494 "awkgram.y"
     {
                (yyvsp[(1) - (2)])->opcode = Op_predecrement;
                (yyval) = mk_assignment((yyvsp[(2) - (2)]), NULL, (yyvsp[(1) - 
(2)]));
@@ -3853,7 +3865,7 @@ regular_loop:
   case 152:
 
 /* Line 1821 of yacc.c  */
-#line 1487 "awkgram.y"
+#line 1499 "awkgram.y"
     {
                (yyval) = list_create((yyvsp[(1) - (1)]));
          }
@@ -3862,7 +3874,7 @@ regular_loop:
   case 153:
 
 /* Line 1821 of yacc.c  */
-#line 1491 "awkgram.y"
+#line 1503 "awkgram.y"
     {
                (yyval) = list_create((yyvsp[(1) - (1)]));
          }
@@ -3871,7 +3883,7 @@ regular_loop:
   case 154:
 
 /* Line 1821 of yacc.c  */
-#line 1495 "awkgram.y"
+#line 1507 "awkgram.y"
     {
                if ((yyvsp[(2) - (2)])->lasti->opcode == Op_push_i
                        && ((yyvsp[(2) - (2)])->lasti->memory->flags & 
(STRCUR|STRING)) == 0
@@ -3889,7 +3901,7 @@ regular_loop:
   case 155:
 
 /* Line 1821 of yacc.c  */
-#line 1508 "awkgram.y"
+#line 1520 "awkgram.y"
     {
            /*
             * was: $$ = $2
@@ -3904,7 +3916,7 @@ regular_loop:
   case 156:
 
 /* Line 1821 of yacc.c  */
-#line 1521 "awkgram.y"
+#line 1533 "awkgram.y"
     {
                func_use((yyvsp[(1) - (1)])->lasti->func_name, FUNC_USE);
                (yyval) = (yyvsp[(1) - (1)]);
@@ -3914,7 +3926,7 @@ regular_loop:
   case 157:
 
 /* Line 1821 of yacc.c  */
-#line 1526 "awkgram.y"
+#line 1538 "awkgram.y"
     {
                /* indirect function call */
                INSTRUCTION *f, *t;
@@ -3952,7 +3964,7 @@ regular_loop:
   case 158:
 
 /* Line 1821 of yacc.c  */
-#line 1562 "awkgram.y"
+#line 1574 "awkgram.y"
     {
                param_sanity((yyvsp[(3) - (4)]));
                (yyvsp[(1) - (4)])->opcode = Op_func_call;
@@ -3971,42 +3983,42 @@ regular_loop:
   case 159:
 
 /* Line 1821 of yacc.c  */
-#line 1579 "awkgram.y"
+#line 1591 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 160:
 
 /* Line 1821 of yacc.c  */
-#line 1581 "awkgram.y"
+#line 1593 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 161:
 
 /* Line 1821 of yacc.c  */
-#line 1586 "awkgram.y"
+#line 1598 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 162:
 
 /* Line 1821 of yacc.c  */
-#line 1588 "awkgram.y"
+#line 1600 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (2)]); }
     break;
 
   case 163:
 
 /* Line 1821 of yacc.c  */
-#line 1593 "awkgram.y"
+#line 1605 "awkgram.y"
     {  (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 164:
 
 /* Line 1821 of yacc.c  */
-#line 1595 "awkgram.y"
+#line 1607 "awkgram.y"
     {
                (yyval) = list_merge((yyvsp[(1) - (2)]), (yyvsp[(2) - (2)]));
          }
@@ -4015,7 +4027,7 @@ regular_loop:
   case 165:
 
 /* Line 1821 of yacc.c  */
-#line 1602 "awkgram.y"
+#line 1614 "awkgram.y"
     {
                INSTRUCTION *ip = (yyvsp[(1) - (1)])->lasti; 
                int count = ip->sub_count;      /* # of SUBSEP-seperated 
expressions */
@@ -4034,7 +4046,7 @@ regular_loop:
   case 166:
 
 /* Line 1821 of yacc.c  */
-#line 1619 "awkgram.y"
+#line 1631 "awkgram.y"
     {
                INSTRUCTION *t = (yyvsp[(2) - (3)]);
                if ((yyvsp[(2) - (3)]) == NULL) {
@@ -4053,14 +4065,14 @@ regular_loop:
   case 167:
 
 /* Line 1821 of yacc.c  */
-#line 1636 "awkgram.y"
+#line 1648 "awkgram.y"
     {  (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 168:
 
 /* Line 1821 of yacc.c  */
-#line 1638 "awkgram.y"
+#line 1650 "awkgram.y"
     {
                (yyval) = list_merge((yyvsp[(1) - (2)]), (yyvsp[(2) - (2)]));
          }
@@ -4069,14 +4081,14 @@ regular_loop:
   case 169:
 
 /* Line 1821 of yacc.c  */
-#line 1645 "awkgram.y"
+#line 1657 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (2)]); }
     break;
 
   case 170:
 
 /* Line 1821 of yacc.c  */
-#line 1650 "awkgram.y"
+#line 1662 "awkgram.y"
     {
                char *var_name = (yyvsp[(1) - (1)])->lextok;
 
@@ -4089,7 +4101,7 @@ regular_loop:
   case 171:
 
 /* Line 1821 of yacc.c  */
-#line 1658 "awkgram.y"
+#line 1670 "awkgram.y"
     {
                char *arr = (yyvsp[(1) - (2)])->lextok;
                (yyvsp[(1) - (2)])->memory = variable((yyvsp[(1) - 
(2)])->source_line, arr, Node_var_new);
@@ -4101,7 +4113,7 @@ regular_loop:
   case 172:
 
 /* Line 1821 of yacc.c  */
-#line 1668 "awkgram.y"
+#line 1680 "awkgram.y"
     {
                INSTRUCTION *ip = (yyvsp[(1) - (1)])->nexti;
                if (ip->opcode == Op_push
@@ -4118,7 +4130,7 @@ regular_loop:
   case 173:
 
 /* Line 1821 of yacc.c  */
-#line 1680 "awkgram.y"
+#line 1692 "awkgram.y"
     {
                (yyval) = list_append((yyvsp[(2) - (3)]), (yyvsp[(1) - (3)]));
                if ((yyvsp[(3) - (3)]) != NULL)
@@ -4129,7 +4141,7 @@ regular_loop:
   case 174:
 
 /* Line 1821 of yacc.c  */
-#line 1689 "awkgram.y"
+#line 1701 "awkgram.y"
     {
                (yyvsp[(1) - (1)])->opcode = Op_postincrement;
          }
@@ -4138,7 +4150,7 @@ regular_loop:
   case 175:
 
 /* Line 1821 of yacc.c  */
-#line 1693 "awkgram.y"
+#line 1705 "awkgram.y"
     {
                (yyvsp[(1) - (1)])->opcode = Op_postdecrement;
          }
@@ -4147,49 +4159,49 @@ regular_loop:
   case 176:
 
 /* Line 1821 of yacc.c  */
-#line 1696 "awkgram.y"
+#line 1708 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 178:
 
 /* Line 1821 of yacc.c  */
-#line 1704 "awkgram.y"
+#line 1716 "awkgram.y"
     { yyerrok; }
     break;
 
   case 179:
 
 /* Line 1821 of yacc.c  */
-#line 1708 "awkgram.y"
+#line 1720 "awkgram.y"
     { yyerrok; }
     break;
 
   case 182:
 
 /* Line 1821 of yacc.c  */
-#line 1717 "awkgram.y"
+#line 1729 "awkgram.y"
     { yyerrok; }
     break;
 
   case 183:
 
 /* Line 1821 of yacc.c  */
-#line 1721 "awkgram.y"
+#line 1733 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); yyerrok; }
     break;
 
   case 184:
 
 /* Line 1821 of yacc.c  */
-#line 1725 "awkgram.y"
+#line 1737 "awkgram.y"
     { yyerrok; }
     break;
 
 
 
 /* Line 1821 of yacc.c  */
-#line 4205 "awkgram.c"
+#line 4217 "awkgram.c"
       default: break;
     }
   /* User semantic actions sometimes alter yychar, and that requires
@@ -4420,7 +4432,7 @@ yyreturn:
 
 
 /* Line 2067 of yacc.c  */
-#line 1727 "awkgram.y"
+#line 1739 "awkgram.y"
 
 
 struct token {
@@ -6596,6 +6608,19 @@ mk_function(INSTRUCTION *fi, INSTRUCTION *def)
        thisfunc = fi->func_body;
        assert(thisfunc != NULL);
 
+       if (do_optimize > 1 && def->lasti->opcode == Op_pop) {
+               /* tail call which does not return any value. */
+
+               INSTRUCTION *t;
+
+               for (t = def->nexti; t->nexti != def->lasti; t = t->nexti)
+                       ;
+               if (t->opcode == Op_func_call
+                       && STREQ(t->func_name, thisfunc->vname)
+               )
+                       (t + 1)->tail_call = TRUE;
+       }
+
        /* add an implicit return at end;
         * also used by 'return' command in debugger
         */
@@ -7470,7 +7495,7 @@ optimize_assignment(INSTRUCTION *exp)
        if (   ! do_optimize
            || (   i1->opcode != Op_assign
                && i1->opcode != Op_field_assign)
-       )
+       ) 
                return list_append(exp, instruction(Op_pop));
 
        for (i2 = exp->nexti; i2 != i1; i2 = i2->nexti) {
diff --git a/awkgram.y b/awkgram.y
index 2157d3e..08eb990 100644
--- a/awkgram.y
+++ b/awkgram.y
@@ -84,7 +84,7 @@ static int one_line_close(int fd);
 
 static int want_source = FALSE;
 static int want_regexp;                /* lexical scanning kludge */
-static int can_return;         /* parsing kludge */
+static char *in_function;              /* parsing kludge */
 static int rule = 0;
 
 const char *const ruletab[] = {
@@ -229,7 +229,7 @@ rule
          }
        | function_prologue action
          {
-               can_return = FALSE;
+               in_function = NULL;
                (void) mk_function($1, $2);
                yyerrok;
          }
@@ -358,11 +358,11 @@ function_prologue
                $1->source_file = source;
                if (install_function($2->lextok, $1, $4) < 0)
                        YYABORT;
+               in_function = $2->lextok;
                $2->lextok = NULL;
                bcfree($2);
                /* $4 already free'd in install_function */
                $$ = $1;
-               can_return = TRUE;
          }
        ;
 
@@ -817,15 +817,27 @@ non_compound_stmt
          }
        | LEX_RETURN
          {
-               if (! can_return)
+               if (! in_function)
                        yyerror(_("`return' used outside function context"));
          } opt_exp statement_term {
                if ($3 == NULL) {
                        $$ = list_create($1);
                        (void) list_prepend($$, instruction(Op_push_i));
                        $$->nexti->memory = dupnode(Nnull_string);
-               } else
+               } else {
+                       if (do_optimize > 1
+                               && $3->lasti->opcode == Op_func_call
+                               && STREQ($3->lasti->func_name, in_function)
+                       ) {
+                               /* Do tail recursion optimization. Tail
+                                * call without a return value is recognized
+                                * in mk_function().
+                                */
+                               ($3->lasti + 1)->tail_call = TRUE;
+                       }
+
                        $$ = list_append($3, $1);
+               }
          }
        | simple_stmt statement_term
        ;
@@ -3899,6 +3911,19 @@ mk_function(INSTRUCTION *fi, INSTRUCTION *def)
        thisfunc = fi->func_body;
        assert(thisfunc != NULL);
 
+       if (do_optimize > 1 && def->lasti->opcode == Op_pop) {
+               /* tail call which does not return any value. */
+
+               INSTRUCTION *t;
+
+               for (t = def->nexti; t->nexti != def->lasti; t = t->nexti)
+                       ;
+               if (t->opcode == Op_func_call
+                       && STREQ(t->func_name, thisfunc->vname)
+               )
+                       (t + 1)->tail_call = TRUE;
+       }
+
        /* add an implicit return at end;
         * also used by 'return' command in debugger
         */
@@ -4773,7 +4798,7 @@ optimize_assignment(INSTRUCTION *exp)
        if (   ! do_optimize
            || (   i1->opcode != Op_assign
                && i1->opcode != Op_field_assign)
-       )
+       ) 
                return list_append(exp, instruction(Op_pop));
 
        for (i2 = exp->nexti; i2 != i1; i2 = i2->nexti) {
diff --git a/eval.c b/eval.c
index d56b56f..daba0a0 100644
--- a/eval.c
+++ b/eval.c
@@ -687,8 +687,8 @@ pop_frame()
 #endif
 }
 #else  /* not PROFILING or DEBUGGING */
-#define push_frame(p)   /* nothing */
-#define pop_frame()            /* nothing */
+#define push_frame(p)  /* nothing */
+#define pop_frame()    /* nothing */
 #endif
 
 
@@ -700,7 +700,7 @@ void
 dump_fcall_stack(FILE *fp)
 {
        NODE *f, *func;
-       long i = 0;
+       long i = 0, j, k = 0;
 
        if (fcall_count == 0)
                return;
@@ -708,16 +708,18 @@ dump_fcall_stack(FILE *fp)
 
        /* current frame */
        func = frame_ptr->func_node;
-       fprintf(fp, "\t# %3ld. %s\n", i, func->lnode->param);
+       for (j = 0; j <= frame_ptr->num_tail_calls; j++)
+               fprintf(fp, "\t# %3ld. %s\n", k++, func->vname);
 
        /* outer frames except main */
        for (i = 1; i < fcall_count; i++) {
                f = fcall_list[i];
                func = f->func_node;
-               fprintf(fp, "\t# %3ld. %s\n", i, func->lnode->param);
+               for (j = 0; j <= f->num_tail_calls; j++)
+                       fprintf(fp, "\t# %3ld. %s\n", k++, func->vname);
        }
 
-       fprintf(fp, "\t# %3ld. -- main --\n", fcall_count);
+       fprintf(fp, "\t# %3ld. -- main --\n", k);
 }
 
 #endif /* PROFILING */
@@ -1111,6 +1113,7 @@ grow_stack()
                frame_ptr->type = Node_frame;
                frame_ptr->stack = NULL;
                frame_ptr->func_node = NULL;    /* in main */
+               frame_ptr->num_tail_calls = 0;
                frame_ptr->vname = NULL;
                return stack_ptr;
        }
@@ -1250,12 +1253,40 @@ setup_frame(INSTRUCTION *pc)
        NODE *m, *f, *fp;
        NODE **sp = NULL;
        int pcount, arg_count, i, j;
+       int tail_optimize = FALSE;
 
        f = pc->func_body;
        pcount = f->param_cnt;
        fp = f->fparms;
        arg_count = (pc + 1)->expr_count;
 
+#ifndef DEBUGGING
+       /* tail recursion optimization */
+       tail_optimize =  (do_optimize > 1 && (pc + 1)->tail_call);
+#endif
+
+       if (tail_optimize) {
+               /* free local vars of calling frame */
+
+               NODE *func;
+               int n;
+
+               func = frame_ptr->func_node;
+               for (n = func->param_cnt, sp = frame_ptr->stack; n > 0; n--) {
+                       r = *sp++;
+                       if (r->type == Node_var)     /* local variable */
+                               DEREF(r->var_value);
+                       else if (r->type == Node_var_array)     /* local array 
*/
+                               assoc_clear(r);
+               }
+               sp = frame_ptr->stack;
+
+       } else if (pcount > 0) {
+               emalloc(sp, NODE **, pcount * sizeof(NODE *), "setup_frame");
+               memset(sp, 0, pcount * sizeof(NODE *));
+       }
+
+
        /* check for extra args */ 
        if (arg_count > pcount) {
                warning(
@@ -1268,15 +1299,15 @@ setup_frame(INSTRUCTION *pc)
                } while (--arg_count > pcount);
        }
 
-       if (pcount > 0) {
-               emalloc(sp, NODE **, pcount * sizeof(NODE *), "setup_frame");
-               memset(sp, 0, pcount * sizeof(NODE *));
-       }
-
        for (i = 0, j = arg_count - 1; i < pcount; i++, j--) {
-               getnode(r);
-               memset(r, 0, sizeof(NODE));
-               sp[i] = r;
+               if (tail_optimize)
+                       r = sp[i];
+               else {
+                       getnode(r);
+                       memset(r, 0, sizeof(NODE));
+                       sp[i] = r;
+               }
+
                if (i >= arg_count) {
                        /* local variable */
                        r->type = Node_var_new;
@@ -1307,7 +1338,6 @@ setup_frame(INSTRUCTION *pc)
                         * scalar during evaluation of expression for a
                         * subsequent param.
                         */
-                       /* fall through */
                        r->type = Node_var;
                        r->var_value = dupnode(Nnull_string);
                        break;
@@ -1322,8 +1352,14 @@ setup_frame(INSTRUCTION *pc)
                }
                r->vname = fp[i].param;
        }
+
        stack_adj(-arg_count);  /* adjust stack pointer */
 
+       if (tail_optimize) {
+               frame_ptr->num_tail_calls++;
+               return;
+       }
+
        if (pc->opcode == Op_indirect_func_call) {
                r = POP();      /* indirect var */
                DEREF(r);
@@ -1342,6 +1378,7 @@ setup_frame(INSTRUCTION *pc)
        frame_ptr->stack = sp;
        frame_ptr->prev_frame_size = (stack_ptr - stack_bottom); /* size of the 
previous stack frame */
        frame_ptr->func_node = f;
+       frame_ptr->num_tail_calls = 0;
        frame_ptr->vname = NULL;
        frame_ptr->reti = pc; /* on return execute pc->nexti */
 
@@ -1372,6 +1409,7 @@ restore_frame(NODE *fp)
                        assoc_clear(r);
                freenode(r);
        }
+
        if (frame_ptr->stack != NULL)
                efree(frame_ptr->stack);
        ri = frame_ptr->reti;     /* execution in calling frame
@@ -1746,7 +1784,7 @@ top:
                        /* avoid false source indications */
                        source = NULL;
                        sourceline = 0;
-                       (void) nextfile(&curfile, TRUE);        /* close input 
data file */ 
+                       (void) nextfile(& curfile, TRUE);       /* close input 
data file */ 
                        /*
                         * This used to be:
                         *
@@ -2522,6 +2560,7 @@ match_re:
                                f = pc->func_body;
                                if (f != NULL && STREQ(f->vname, t1->stptr)) {
                                        /* indirect var hasn't been reassigned 
*/
+
                                        goto func_call;
                                }
                                f = lookup(t1->stptr);

http://git.sv.gnu.org/cgit/gawk.git/commit/?id=4d44431ecc06af0cc82a45c3317a8895c01c004a

commit 4d44431ecc06af0cc82a45c3317a8895c01c004a
Author: john haque <address@hidden>
Date:   Thu Sep 8 04:53:35 2011 -0500

    Optimization for compound assignment, increment and decrement operators.

diff --git a/ChangeLog b/ChangeLog
index f8a285a..bd69e57 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -46,6 +46,12 @@
 
        * dfa.c: Sync with GNU grep.
 
+2011-09-08         John Haque     <address@hidden>
+
+       Optimization for compound assignment, increment and
+       decrement operators; Avoid unref and make_number calls
+       when there is no extra references to the value NODE.
+
 2011-09-03         Arnold D. Robbins     <address@hidden>
 
        * dfa.c: Sync with GNU grep.
diff --git a/eval.c b/eval.c
index 47b6ca1..d56b56f 100644
--- a/eval.c
+++ b/eval.c
@@ -1249,7 +1249,7 @@ setup_frame(INSTRUCTION *pc)
        NODE *r = NULL;
        NODE *m, *f, *fp;
        NODE **sp = NULL;
-       int pcount, arg_count, i;
+       int pcount, arg_count, i, j;
 
        f = pc->func_body;
        pcount = f->param_cnt;
@@ -1273,7 +1273,7 @@ setup_frame(INSTRUCTION *pc)
                memset(sp, 0, pcount * sizeof(NODE *));
        }
 
-       for (i = 0; i < pcount; i++) {
+       for (i = 0, j = arg_count - 1; i < pcount; i++, j--) {
                getnode(r);
                memset(r, 0, sizeof(NODE));
                sp[i] = r;
@@ -1284,7 +1284,7 @@ setup_frame(INSTRUCTION *pc)
                        continue;
                }
 
-               m = PEEK(arg_count - i - 1); /* arguments in reverse order on 
runtime stack */
+               m = PEEK(j); /* arguments in reverse order on runtime stack */
 
                if (m->type == Node_param_list)
                        m = GET_PARAM(m->param_cnt);
@@ -1510,38 +1510,37 @@ cmp_scalar()
        return di;
 }
 
+
 /* op_assign --- assignment operators excluding = */
  
 static void
 op_assign(OPCODE op)
 {
        NODE **lhs;
-       NODE *r = NULL;
-       AWKNUM x1, x2;
-#ifndef HAVE_FMOD
-       AWKNUM x;
-#endif
+       NODE *t1;
+       AWKNUM x = 0.0, x1, x2;
 
        lhs = POP_ADDRESS();
-       x1 = force_number(*lhs);
+       t1 = *lhs;
+       x1 = force_number(t1);
        TOP_NUMBER(x2);
-       unref(*lhs);
+
        switch (op) {
        case Op_assign_plus:
-               r = *lhs = make_number(x1 + x2);
+               x = x1 + x2;
                break;
        case Op_assign_minus:
-               r = *lhs = make_number(x1 - x2);
+               x = x1 - x2;
                break;
        case Op_assign_times:
-               r = *lhs = make_number(x1 * x2);
+               x = x1 * x2;
                break;
        case Op_assign_quotient:
                if (x2 == (AWKNUM) 0) {
                        decr_sp();
                        fatal(_("division by zero attempted in `/='"));
                }
-               r = *lhs = make_number(x1 / x2);
+               x = x1 / x2;
                break;
        case Op_assign_mod:
                if (x2 == (AWKNUM) 0) {
@@ -1549,22 +1548,29 @@ op_assign(OPCODE op)
                        fatal(_("division by zero attempted in `%%='"));
                }
 #ifdef HAVE_FMOD
-               r = *lhs = make_number(fmod(x1, x2));
+               x = fmod(x1, x2);
 #else   /* ! HAVE_FMOD */
                (void) modf(x1 / x2, &x);
                x = x1 - x2 * x;
-               r = *lhs = make_number(x);
 #endif  /* ! HAVE_FMOD */
                break;
        case Op_assign_exp:
-               r = *lhs = make_number((AWKNUM) calc_exp((double) x1, (double) 
x2));
+               x = calc_exp((double) x1, (double) x2);
                break;
        default:
                break;
        }
 
-       UPREF(r);
-       REPLACE(r);
+       if (t1->valref == 1 && t1->flags == (MALLOC|NUMCUR|NUMBER)) {
+               /* optimization */
+               t1->numbr = x;
+       } else {
+               unref(t1);
+               t1 = *lhs = make_number(x);
+       }
+
+       UPREF(t1);
+       REPLACE(t1);
 }
 
 
@@ -2118,25 +2124,33 @@ mod:
                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);
-                       *lhs = r;
-                       UPREF(r);
-                       REPLACE(r);
+                       t1 = *lhs;
+                       x1 = force_number(t1);
+                       if (t1->valref == 1 && t1->flags == 
(MALLOC|NUMCUR|NUMBER)) {
+                               /* optimization */
+                               t1->numbr = x1 + x2;
+                       } else {
+                               unref(t1);
+                               t1 = *lhs = make_number(x1 + x2);
+                       }
+                       UPREF(t1);
+                       REPLACE(t1);
                        break;
 
                case Op_postincrement:
                case Op_postdecrement:
                        x2 = pc->opcode == Op_postincrement ? 1.0 : -1.0;
                        lhs = TOP_ADDRESS();
-                       x1 = force_number(*lhs);
-                       x = x1 + x2;
-                       t1 = make_number(x);
+                       t1 = *lhs;
+                       x1 = force_number(t1);
+                       if (t1->valref == 1 && t1->flags == 
(MALLOC|NUMCUR|NUMBER)) {
+                               /* optimization */
+                               t1->numbr = x1 + x2;
+                       } else {
+                               unref(t1);
+                               *lhs = make_number(x1 + x2);
+                       }
                        r = make_number(x1);
-                       unref(*lhs);
-                       *lhs = t1;
                        REPLACE(r);
                        break;
 
@@ -2170,7 +2184,7 @@ mod:
        
                        lhs = get_lhs(pc->memory, FALSE);
                        unref(*lhs);
-                       r = pc->initval;
+                       r = pc->initval;        /* constant initializer */
                        if (r == NULL)
                                *lhs = POP_SCALAR();
                        else {

http://git.sv.gnu.org/cgit/gawk.git/commit/?id=f0866c5197ee0c01fd1ded16e364cbe612c271be

commit f0866c5197ee0c01fd1ded16e364cbe612c271be
Author: john haque <address@hidden>
Date:   Sun Aug 21 05:54:38 2011 -0500

    Add a test file, cleanup code and update doc.

diff --git a/ChangeLog b/ChangeLog
index 4edb164..f8a285a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -50,6 +50,103 @@
 
        * dfa.c: Sync with GNU grep.
 
+2011-08-31         John Haque     <address@hidden>
+
+       Grammar related changes: Simplify grammar for user-defined
+       functions and general cleanups.
+
+       * symbol.c: New file.
+       * awkgram.y: Move symbol table related routines to the
+       new file.
+       (rule, func_name, function_prologue, param_list): Reworked.
+       (install_function, check_params): Do all error checkings
+       for the function name and parameters before installing in
+       the symbol table.
+       (mk_function): Finalize function definition.
+       (func_install, append_param, dup_params): Nuked.
+       * symbol.c (make_params): allocate function parameter nodes
+       for the symbol table. Use the hash node as Node_param_list;
+       Saves a NODE for each parameter.
+       (install_params): Install function parameters into the symbol
+       table.
+       (remove_params): Remove parameters out of the symbol table.
+       * awk.h (parmlist, FUNC): Nuked.
+       (fparms): New define.
+
+
+       Dynamically loaded function parameters are now handled like
+       those for a builtin.
+
+       * awk.h (Node_ext_func, Op_ext_builtin): New types.
+       (Op_ext_func): Nuked.
+       * ext.c (make_builtin): Simplified.
+       (get_curfunc_arg_count): Nuked; Use the argument 'nargs' of
+       the extension function instead.
+       (get_argument, get_actual_argument): Adjust.
+       * eval.c (r_interpret): Update case Op_func_call for a dynamic
+       extension function. Handle the new opcode Op_ext_builtin.
+       * pprint (profile.c): Adjust.
+
+
+       Use a single variable to process gawk options.
+
+       * awk.h (do_flags): New variable.
+       (DO_LINT_INVALID, DO_LINT_ALL, DO_LINT_OLD, DO_TRADITIONAL,
+       DO_POSIX, DO_INTL, DO_NON_DEC_DATA, DO_INTERVALS,
+       DO_PROFILING, DO_DUMP_VARS, DO_TIDY_MEM,
+       DO_SANDBOX): New defines.
+       (do_traditional, do_posix, do_intervals, do_intl,
+       do_non_decimal_data, do_profiling, do_dump_vars,
+       do_tidy_mem, do_sandbox, do_lint,
+       do_lint_old): Defined as macros.        
+       * main.c: Remove definitions of the do_XX variables. Add
+       do_flags definition.
+       * debug.c (execute_code, do_eval, parse_condition): Save
+       do_flags before executing/parsing and restore afterwards.
+
+
+       Nuke PERM flag. Always increment/decrement the reference
+       count for a Node_val. Simplifies macros and avoids
+       occassional memory leaks, specially in the debugger.
+
+       * awk.h (UPREF, DEREF, dupnode, unref): Simplified.
+       (mk_number): Nuked.
+       * (*.c): Increment the reference count of Nnull_string before
+       assigning as a value.
+
+
+       Revamped array handling mechanism for more speed and
+       less memory consumption.
+
+       * awk.h (union bucket_item, BUCKET): New definitions. Used as
+       bucket elements for the hash table implementations of arrays;
+       40% space saving in 32 bit x86.
+       (buckets, nodes, array_funcs, array_base, array_capacity,
+       xarray, alookup, aexists, aclear, aremove, alist,
+       acopy, adump, NUM_AFUNCS): New defines.
+       (array_empty): New macro to test for an empty array.
+       (assoc_lookup, in_array): Defined as macros.
+       (enum assoc_list_flags): New declaration.
+       (Node_ahash, NUMIND): Nuked.
+       * eval.c (r_interpret): Adjust cases Op_subscript,
+       Op_subscript_lhs, Op_store_var and Op_arrayfor_incr.
+       * node.c (dupnode, unref): Removed code related to Node_ahash. 
+       * str_array.c: New file to handle array with string indices.
+       * int_array.c: New file to handle array with integer indices.
+       * cint_array.c: New file. Special handling of arrays with
+       (mostly) consecutive integer indices.
+
+
+       Memory pool management reworked to handle NODE and BUCKET.
+
+       * awk.h (struct block_item, BLOCK, block_id): New definitions.
+       (getblock, freeblock): New macros.
+       (getbucket, freebucket): New macros to allocate and deallocate
+       a BUCKET.
+       (getnode, freenode): Adjusted.
+       * node.c (more_nodes): Nuked.
+       (more_blocks): New routine to allocate blocks of memory.
+
 2011-08-24         Arnold D. Robbins     <address@hidden>
 
        Fix pty co-process communication on Ubuntu GNU/Linux.
diff --git a/array.c b/array.c
index 91b8757..3ffc0db 100644
--- a/array.c
+++ b/array.c
@@ -48,10 +48,11 @@ static array_ptr *atypes[MAX_ATYPE];
 static int num_atypes = 0;
 
 /*
+ * register_array_func --- add routines to handle arrays.
+ *
  *     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.
  */
  
 
@@ -69,6 +70,7 @@ register_array_func(array_ptr *afunc)
        return FALSE;
 }
 
+
 /* array_init --- register all builtin array types */
 
 void
@@ -79,6 +81,7 @@ array_init()
        (void) register_array_func(cint_array_func);
 }
 
+
 /* make_array --- create an array node */
 
 NODE *
@@ -438,7 +441,7 @@ concat_exp(int nargs, int do_subsep)
                DEREF(r);
        }
 
-       return make_str_node(str, len);
+       return make_str_node(str, len, ALREADY_MALLOCED);
 }
 
 
diff --git a/awk.h b/awk.h
index a942f8c..f65426b 100644
--- a/awk.h
+++ b/awk.h
@@ -418,13 +418,13 @@ typedef struct exp_node {
 
 /* Node_hashnode, Node_param_list */
 #define hnext  sub.nodep.r.rptr
-#define        hname   vname
-#define        hlength sub.nodep.reserved
+#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
+#define param_cnt  sub.nodep.l.ll
 /* Node_param_list */
 #define param      vname
 
@@ -437,13 +437,13 @@ typedef struct exp_node {
 #define re_flags sub.nodep.reflags
 #define re_text lnode
 #define re_exp sub.nodep.x.extra
-#define        re_cnt  flags
+#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 stfmt  sub.val.idx
 #define wstptr sub.val.wsp
 #define wstlen sub.val.wslen
 #define numbr  sub.val.fltnum
@@ -1036,7 +1036,6 @@ extern int do_flags;
 #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;
@@ -1181,8 +1180,11 @@ extern STACK_ITEM *stack_top;
 #define getbucket(b)   getblock(b, BLOCK_BUCKET, BUCKET *)
 #define freebucket(b)  freeblock(b, BLOCK_BUCKET)
 
-#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        make_string(s, l)       r_make_str_node((s), (l), 0)
+#define make_str_node(s, l, f) r_make_str_node((s), (l), (f))
+
+#define                SCAN                    1
+#define                ALREADY_MALLOCED        2
 
 #define        cant_happen()   r_fatal("internal error line %d, file: %s", \
                                __LINE__, __FILE__)
@@ -1279,6 +1281,7 @@ extern NODE *get_array(NODE *symbol, int canfatal);
 extern const char *make_aname(const NODE *symbol);
 extern const char *array_vname(const NODE *symbol);
 extern void array_init(void);
+extern int register_array_func(array_ptr *afunc);
 extern void set_SUBSEP(void);
 extern NODE *concat_exp(int nargs, int do_subsep);
 extern void assoc_clear(NODE *symbol);
@@ -1481,11 +1484,10 @@ extern AWKNUM r_force_number(NODE *n);
 extern NODE *format_val(const char *format, int index, NODE *s);
 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 NODE *r_make_str_node(const char *s, size_t len, int flags);
 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);
 #if MBS_SUPPORT
 extern NODE *str2wstr(NODE *n, size_t **ptr);
 extern NODE *wstr2str(NODE *n);
diff --git a/awkgram.c b/awkgram.c
index ba9a904..b9e3002 100644
--- a/awkgram.c
+++ b/awkgram.c
@@ -2330,7 +2330,7 @@ yyreduce:
                                        _("regexp constant `/%s/' looks like a 
C comment, but is not"), re);
                  }
 
-                 exp = make_str_node(re, len);
+                 exp = make_str_node(re, len, ALREADY_MALLOCED);
                  n = make_regnode(Node_regex, exp);
                  if (n == NULL) {
                        unref(exp);
@@ -5438,7 +5438,6 @@ yylex(void)
        int mid;
        static int did_newline = FALSE;
        char *tokkey;
-       size_t toklen;
        int inhex = FALSE;
        int intlstr = FALSE;
        AWKNUM d;
@@ -5873,16 +5872,14 @@ retry:
                        tokadd(c);
                }
                yylval = GET_INSTRUCTION(Op_token);
-               toklen = tok - tokstart;
                if (want_source) {
-                       yylval->lextok = estrdup(tokstart, toklen);
+                       yylval->lextok = estrdup(tokstart, tok - tokstart);
                        return lasttok = FILENAME;
                }
                
                yylval->opcode = Op_push_i;
-               if (esc_seen)
-                       toklen = scan_escape(tokstart, toklen);
-               yylval->memory = make_string(tokstart, toklen);
+               yylval->memory = make_str_node(tokstart,
+                                       tok - tokstart, esc_seen ? SCAN : 0);
                if (intlstr) {
                        yylval->memory->flags |= INTLSTR;
                        intlstr = FALSE;
diff --git a/awkgram.y b/awkgram.y
index e2725a9..2157d3e 100644
--- a/awkgram.y
+++ b/awkgram.y
@@ -392,7 +392,7 @@ regexp
                                        _("regexp constant `/%s/' looks like a 
C comment, but is not"), re);
                  }
 
-                 exp = make_str_node(re, len);
+                 exp = make_str_node(re, len, ALREADY_MALLOCED);
                  n = make_regnode(Node_regex, exp);
                  if (n == NULL) {
                        unref(exp);
@@ -2741,7 +2741,6 @@ yylex(void)
        int mid;
        static int did_newline = FALSE;
        char *tokkey;
-       size_t toklen;
        int inhex = FALSE;
        int intlstr = FALSE;
        AWKNUM d;
@@ -3176,16 +3175,14 @@ retry:
                        tokadd(c);
                }
                yylval = GET_INSTRUCTION(Op_token);
-               toklen = tok - tokstart;
                if (want_source) {
-                       yylval->lextok = estrdup(tokstart, toklen);
+                       yylval->lextok = estrdup(tokstart, tok - tokstart);
                        return lasttok = FILENAME;
                }
                
                yylval->opcode = Op_push_i;
-               if (esc_seen)
-                       toklen = scan_escape(tokstart, toklen);
-               yylval->memory = make_string(tokstart, toklen);
+               yylval->memory = make_str_node(tokstart,
+                                       tok - tokstart, esc_seen ? SCAN : 0);
                if (intlstr) {
                        yylval->memory->flags |= INTLSTR;
                        intlstr = FALSE;
diff --git a/builtin.c b/builtin.c
index f5aa503..bf68858 100644
--- a/builtin.c
+++ b/builtin.c
@@ -1348,7 +1348,7 @@ out2:
                        _("too many arguments supplied for format string"));
        }
        bchunk(s0, s1 - s0);
-       r = make_str_node(obuf, obufout - obuf);
+       r = make_str_node(obuf, obufout - obuf, ALREADY_MALLOCED);
        obuf = NULL;
 out:
        {
@@ -1612,7 +1612,7 @@ do_substr(int nargs)
                        wp++;
                }
                *cp = '\0';
-               r = make_str_node(substr, cp - substr);
+               r = make_str_node(substr, cp - substr, ALREADY_MALLOCED);
        }
 #else
        r = make_string(t1->stptr + indx, length);
@@ -2724,7 +2724,7 @@ done:
                if (matches > 0) {
                        /* return the result string */
                        DEREF(t);
-                       return make_str_node(buf, textlen);     
+                       return make_str_node(buf, textlen, ALREADY_MALLOCED);   
                }
 
                /* return the original string */
@@ -2736,7 +2736,7 @@ done:
                DEREF(t);
        else if (matches > 0) {
                unref(*lhs);
-               *lhs = make_str_node(buf, textlen);     
+               *lhs = make_str_node(buf, textlen, ALREADY_MALLOCED);   
        }
 
        return make_number((AWKNUM) matches);
diff --git a/cint_array.c b/cint_array.c
index e7eb09f..72cd737 100644
--- a/cint_array.c
+++ b/cint_array.c
@@ -464,17 +464,19 @@ cint_dump(NODE *symbol, NODE *ndump)
        NODE *tn, *xn = NULL;
        int indent_level;
        size_t i;
-       long cint_size = 0, int_size = 0;
+       long cint_size = 0, xsize = 0;
        AWKNUM kb = 0;
        extern AWKNUM int_kilobytes(NODE *symbol);
+       extern AWKNUM str_kilobytes(NODE *symbol);
+       extern array_ptr int_array_func[];
 
        indent_level = ndump->alevel;
 
        if (symbol->xarray != NULL) {
                xn = symbol->xarray;
-               int_size = xn->table_size;      /* FIXME -- can be int_array or 
str_array */
+               xsize = xn->table_size;
        }
-       cint_size = symbol->table_size - int_size;
+       cint_size = symbol->table_size - xsize;
        
        if ((symbol->flags & XARRAY) == 0)
                fprintf(output_fp, "%s `%s'\n",
@@ -493,7 +495,7 @@ cint_dump(NODE *symbol, NODE *ndump)
        fprintf(output_fp, "THRESHOLD: %ld\n", THRESHOLD);
        indent(indent_level);
        fprintf(output_fp, "table_size: %ld (total), %ld (cint), %ld (int + 
str)\n",
-                               symbol->table_size, cint_size, int_size);
+                               symbol->table_size, cint_size, xsize);
        indent(indent_level);
        fprintf(output_fp, "array_capacity: %lu\n", (unsigned long) 
symbol->array_capacity);
        indent(indent_level);
@@ -508,8 +510,13 @@ cint_dump(NODE *symbol, NODE *ndump)
        }
        kb += (INT32_BIT * sizeof(NODE *)) / 1024.0;    /* symbol->nodes */     
        kb += (symbol->array_capacity * sizeof(NODE *)) / 1024.0;       /* 
value nodes in Node_array_leaf(s) */
-       if (xn != NULL)
-               kb += int_kilobytes(xn);        /* FIXME: can be str_array or 
int_array ? */
+       if (xn != NULL) {
+               if (xn->array_funcs == int_array_func)
+                       kb += int_kilobytes(xn);
+               else
+                       kb += str_kilobytes(xn);
+       }
+
        indent(indent_level);
        fprintf(output_fp, "memory: %.2g kB (total)\n", kb);
 
diff --git a/command.c b/command.c
index b705d5e..c3fea2b 100644
--- a/command.c
+++ b/command.c
@@ -3177,6 +3177,7 @@ again:
 
        if (c == '"') {
                char *str, *p;
+               int flags = ALREADY_MALLOCED;
                int esc_seen = FALSE;
 
                toklen = lexend - lexptr;
@@ -3209,12 +3210,10 @@ err:
                        append_cmdarg(yylval);
                        return D_STRING;
                } else {        /* awk string */
-                       size_t len;
-                       len = p - str;
                        if (esc_seen)
-                               len = scan_escape(str, len);
+                               flags |= SCAN;
                        yylval = mk_cmdarg(D_node);
-                       yylval->a_node = make_str_node(str, len);
+                       yylval->a_node = make_str_node(str, p - str, flags);
                        append_cmdarg(yylval);
                        return D_NODE;
                }
@@ -3364,7 +3363,7 @@ concat_args(CMDARG *arg, int count)
        }
        str[len] = '\0';
        efree(tmp);
-       return make_str_node(str, len);
+       return make_str_node(str, len, ALREADY_MALLOCED);
 }
 
 /* find_command --- find the index in 'cmdtab' using exact,
diff --git a/command.y b/command.y
index d2a61a0..18ef061 100644
--- a/command.y
+++ b/command.y
@@ -1163,6 +1163,7 @@ again:
 
        if (c == '"') {
                char *str, *p;
+               int flags = ALREADY_MALLOCED;
                int esc_seen = FALSE;
 
                toklen = lexend - lexptr;
@@ -1195,12 +1196,10 @@ err:
                        append_cmdarg(yylval);
                        return D_STRING;
                } else {        /* awk string */
-                       size_t len;
-                       len = p - str;
                        if (esc_seen)
-                               len = scan_escape(str, len);
+                               flags |= SCAN;
                        yylval = mk_cmdarg(D_node);
-                       yylval->a_node = make_str_node(str, len);
+                       yylval->a_node = make_str_node(str, p - str, flags);
                        append_cmdarg(yylval);
                        return D_NODE;
                }
@@ -1350,7 +1349,7 @@ concat_args(CMDARG *arg, int count)
        }
        str[len] = '\0';
        efree(tmp);
-       return make_str_node(str, len);
+       return make_str_node(str, len, ALREADY_MALLOCED);
 }
 
 /* find_command --- find the index in 'cmdtab' using exact,
diff --git a/doc/ChangeLog b/doc/ChangeLog
index 53ab79a..aa365d7 100644
--- a/doc/ChangeLog
+++ b/doc/ChangeLog
@@ -4,6 +4,10 @@
        Jeroen Schot <address@hidden>.
        * gawk.texi: Some minor fixes.
 
+2011-08-31         John Haque     <address@hidden>
+
+       * gawk.texi: Updated gawk dynamic extension doc.
+
 2011-07-28         Arnold D. Robbins     <address@hidden>
 
        * gawk.texi (Gory Details): Restore text on historical behavior
diff --git a/doc/gawk.info b/doc/gawk.info
index 1324568..619faff 100644
--- a/doc/gawk.info
+++ b/doc/gawk.info
@@ -1,4 +1,4 @@
-This is gawk.info, produced by makeinfo version 4.13 from gawk.texi.
+This is gawk.info, produced by makeinfo version 4.8 from gawk.texi.
 
 INFO-DIR-SECTION Text creation and manipulation
 START-INFO-DIR-ENTRY
@@ -781,7 +781,7 @@ A Rose by Any Other Name
 ========================
 
 The `awk' language has evolved over the years. Full details are
-provided in *note Language History::.  The language described in this
+provided in *Note Language History::.  The language described in this
 Info file is often referred to as "new `awk'" (`nawk').
 
    Because of this, there are systems with multiple versions of `awk'.
@@ -842,78 +842,78 @@ illustrates the concept currently being described.
    While this Info file is aimed principally at people who have not been
 exposed to `awk', there is a lot of information here that even the `awk'
 expert should find useful.  In particular, the description of POSIX
-`awk' and the example programs in *note Library Functions::, and in
-*note Sample Programs::, should be of interest.
+`awk' and the example programs in *Note Library Functions::, and in
+*Note Sample Programs::, should be of interest.
 
-   *note Getting Started::, provides the essentials you need to know to
+   *Note Getting Started::, provides the essentials you need to know to
 begin using `awk'.
 
-   *note Invoking Gawk::, describes how to run `gawk', the meaning of
+   *Note Invoking Gawk::, describes how to run `gawk', the meaning of
 its command-line options, and how it finds `awk' program source files.
 
-   *note Regexp::, introduces regular expressions in general, and in
+   *Note Regexp::, introduces regular expressions in general, and in
 particular the flavors supported by POSIX `awk' and `gawk'.
 
-   *note Reading Files::, describes how `awk' reads your data.  It
+   *Note Reading Files::, describes how `awk' reads your data.  It
 introduces the concepts of records and fields, as well as the `getline'
 command.  I/O redirection is first described here.  Network I/O is also
 briefly introduced here.
 
-   *note Printing::, describes how `awk' programs can produce output
+   *Note Printing::, describes how `awk' programs can produce output
 with `print' and `printf'.
 
-   *note Expressions::, describes expressions, which are the basic
+   *Note Expressions::, describes expressions, which are the basic
 building blocks for getting most things done in a program.
 
-   *note Patterns and Actions::, describes how to write patterns for
+   *Note Patterns and Actions::, describes how to write patterns for
 matching records, actions for doing something when a record is matched,
 and the built-in variables `awk' and `gawk' use.
 
-   *note Arrays::, covers `awk''s one-and-only data structure:
+   *Note Arrays::, covers `awk''s one-and-only data structure:
 associative arrays.  Deleting array elements and whole arrays is also
 described, as well as sorting arrays in `gawk'.  It also describes how
 `gawk' provides arrays of arrays.
 
-   *note Functions::, describes the built-in functions `awk' and `gawk'
+   *Note Functions::, describes the built-in functions `awk' and `gawk'
 provide, as well as how to define your own functions.
 
-   *note Internationalization::, describes special features in `gawk'
+   *Note Internationalization::, describes special features in `gawk'
 for translating program messages into different languages at runtime.
 
-   *note Advanced Features::, describes a number of `gawk'-specific
+   *Note Advanced Features::, describes a number of `gawk'-specific
 advanced features.  Of particular note are the abilities to have
 two-way communications with another process, perform TCP/IP networking,
 and profile your `awk' programs.
 
-   *note Library Functions::, and *note Sample Programs::, provide many
+   *Note Library Functions::, and *Note Sample Programs::, provide many
 sample `awk' programs.  Reading them allows you to see `awk' solving
 real problems.
 
-   *note Debugger::, describes the `awk' debugger, `dgawk'.
+   *Note Debugger::, describes the `awk' debugger, `dgawk'.
 
-   *note Language History::, describes how the `awk' language has
+   *Note Language History::, describes how the `awk' language has
 evolved since its first release to present.  It also describes how
 `gawk' has acquired features over time.
 
-   *note Installation::, describes how to get `gawk', how to compile it
+   *Note Installation::, describes how to get `gawk', how to compile it
 on POSIX-compatible systems, and how to compile and use it on different
 non-POSIX systems.  It also describes how to report bugs in `gawk' and
 where to get other freely available `awk' implementations.
 
-   *note Notes::, describes how to disable `gawk''s extensions, as well
+   *Note Notes::, describes how to disable `gawk''s extensions, as well
 as how to contribute new code to `gawk', how to write extension
 libraries, and some possible future directions for `gawk' development.
 
-   *note Basic Concepts::, provides some very cursory background
+   *Note Basic Concepts::, provides some very cursory background
 material for those who are completely unfamiliar with computer
 programming.  Also centralized there is a discussion of some of the
 issues surrounding floating-point numbers.
 
-   The *note Glossary::, defines most, if not all, the significant
+   The *Note Glossary::, defines most, if not all, the significant
 terms used throughout the book.  If you find terms that you aren't
 familiar with, try looking them up here.
 
-   *note Copying::, and *note GNU Free Documentation License::, present
+   *Note Copying::, and *Note GNU Free Documentation License::, present
 the licenses that cover the `gawk' source code and this Info file,
 respectively.
 
@@ -1029,7 +1029,7 @@ Guide'.
    This edition maintains the basic structure of the previous editions.
 For Edition 4.0, the content has been thoroughly reviewed and updated.
 All references to versions prior to 4.0 have been removed.  Of
-significant note for this edition is *note Debugger::.
+significant note for this edition is *Note Debugger::.
 
    `GAWK: Effective AWK Programming' will undoubtedly continue to
 evolve.  An electronic version comes with the `gawk' distribution from
@@ -1041,7 +1041,7 @@ electronically.
 
    (1) GNU stands for "GNU's not Unix."
 
-   (2) The terminology "GNU/Linux" is explained in the *note Glossary::.
+   (2) The terminology "GNU/Linux" is explained in the *Note Glossary::.
 
 
 File: gawk.info,  Node: How To Contribute,  Next: Acknowledgments,  Prev: 
Manual History,  Up: Preface
@@ -1143,7 +1143,7 @@ this team of fine people.
 byte-code interpreter, including the debugger. Stephen Davies
 contributed to the effort to bring the byte-code changes into the
 mainstream code base.  Efraim Yawitz contributed the initial text of
-*note Debugger::.
+*Note Debugger::.
 
    I would like to thank Brian Kernighan for invaluable assistance
 during the testing and debugging of `gawk', and for ongoing help and
@@ -1277,7 +1277,7 @@ programs from shell scripts, because it avoids the need 
for a separate
 file for the `awk' program.  A self-contained shell script is more
 reliable because there are no other files to misplace.
 
-   *note Very Simple::, presents several short, self-contained programs.
+   *Note Very Simple::, presents several short, self-contained programs.
 
 
 File: gawk.info,  Node: Read Terminal,  Next: Long,  Prev: One-shot,  Up: 
Running gawk
@@ -1462,7 +1462,7 @@ programs, but this usually isn't very useful; the purpose 
of a comment
 is to help you or another person understand the program when reading it
 at a later time.
 
-     CAUTION: As mentioned in *note One-shot::, you can enclose small
+     CAUTION: As mentioned in *Note One-shot::, you can enclose small
      to medium programs in single quotes, in order to keep your shell
      scripts self-contained.  When doing so, _don't_ put an apostrophe
      (i.e., a single quote) into a comment (or anywhere else in your
@@ -1524,7 +1524,7 @@ Shell).  If you use the C shell, you're on your own.
      quotes.  The shell does no interpretation of the quoted text,
      passing it on verbatim to the command.  It is _impossible_ to
      embed a single quote inside single-quoted text.  Refer back to
-     *note Comments::, for an example of what happens if you try.
+     *Note Comments::, for an example of what happens if you try.
 
    * Double quotes protect most things between the opening and closing
      quotes.  The shell does at least variable and command substitution
@@ -1536,7 +1536,7 @@ Shell).  If you use the C shell, you're on your own.
      the characters `$', ``', `\', and `"', all of which must be
      preceded by a backslash within double-quoted text if they are to
      be passed on literally to the program.  (The leading backslash is
-     stripped first.)  Thus, the example seen in *note Read Terminal::,
+     stripped first.)  Thus, the example seen in *Note Read Terminal::,
      is applicable:
 
           $ awk "BEGIN { print \"Don't Panic!\" }"
@@ -1691,7 +1691,7 @@ Miscellaneous File Operations: (emacs)Misc File Ops, for 
more
 information).  Using this information, create your own `BBS-list' and
 `inventory-shipped' files and practice what you learn in this Info file.
 
-   If you are using the stand-alone version of Info, see *note Extract
+   If you are using the stand-alone version of Info, see *Note Extract
 Program::, for an `awk' program that extracts these data files from
 `gawk.texi', the Texinfo source file for this Info file.
 
@@ -2033,7 +2033,7 @@ minor node could also be written this way:
    ---------- Footnotes ----------
 
    (1) The `?' and `:' referred to here is the three-operand
-conditional expression described in *note Conditional Exp::.  Splitting
+conditional expression described in *Note Conditional Exp::.  Splitting
 lines after `?' and `:' is a minor `gawk' extension; if `--posix' is
 specified (*note Options::), then this extension is disabled.
 
@@ -2056,7 +2056,7 @@ determining the type of a variable, and array sorting.
 
    As we develop our presentation of the `awk' language, we introduce
 most of the variables and many of the functions. They are described
-systematically in *note Built-in Variables::, and *note Built-in::.
+systematically in *Note Built-in Variables::, and *Note Built-in::.
 
 
 File: gawk.info,  Node: When,  Prev: Other Features,  Up: Getting Started
@@ -2214,7 +2214,7 @@ The following list describes options mandated by the 
POSIX standard:
      This is useful if you have file names that start with `-', or in
      shell scripts, if you have file names that will be specified by
      the user that could start with `-'.  It is also useful for passing
-     options on to the `awk' program; see *note Getopt Function::.
+     options on to the `awk' program; see *Note Getopt Function::.
 
    The following list describes `gawk'-specific options:
 
@@ -2233,7 +2233,7 @@ The following list describes options mandated by the 
POSIX standard:
      Specify "compatibility mode", in which the GNU extensions to the
      `awk' language are disabled, so that `gawk' behaves just like
      Brian Kernighan's version `awk'.  *Note POSIX/GNU::, which
-     summarizes the extensions.  Also see *note Compatibility Mode::.
+     summarizes the extensions.  Also see *Note Compatibility Mode::.
 
 `-C'
 `--copyright'
@@ -2421,7 +2421,7 @@ if they had been concatenated together into one big file. 
 This is
 useful for creating libraries of `awk' functions.  These functions can
 be written once and then retrieved from a standard place, instead of
 having to be included into each individual program.  (As mentioned in
-*note Definition Syntax::, function names must be unique.)
+*Note Definition Syntax::, function names must be unique.)
 
    With standard `awk', library functions can still be used, even if
 the program is entered at the terminal, by specifying `-f /dev/tty'.
@@ -2479,7 +2479,7 @@ File: gawk.info,  Node: Other Arguments,  Next: Naming 
Standard Input,  Prev: Op
 Any additional arguments on the command line are normally treated as
 input files to be processed in the order specified.   However, an
 argument that has the form `VAR=VALUE', assigns the value VALUE to the
-variable VAR--it does not specify a file at all.  (See *note Assignment
+variable VAR--it does not specify a file at all.  (See *Note Assignment
 Options::.)
 
    All these arguments are made available to your `awk' program in the
@@ -2795,7 +2795,7 @@ reducing the need for writing complex and tedious command 
lines.  In
 particular, address@hidden' is very useful for writing CGI scripts to be run
 from web pages.
 
-   As mentioned in *note AWKPATH Variable::, the current directory is
+   As mentioned in *Note AWKPATH Variable::, the current directory is
 always searched first for source files, before searching in `AWKPATH',
 and this also applies to files named with address@hidden'.
 
@@ -2813,7 +2813,7 @@ they will _not_ be in the next release).
    The process-related special files `/dev/pid', `/dev/ppid',
 `/dev/pgrpid', and `/dev/user' were deprecated in `gawk' 3.1, but still
 worked.  As of version 4.0, they are no longer interpreted specially by
-`gawk'.  (Use `PROCINFO' instead; see *note Auto-set::.)
+`gawk'.  (Use `PROCINFO' instead; see *Note Auto-set::.)
 
 
 File: gawk.info,  Node: Undocumented,  Prev: Obsolete,  Up: Invoking Gawk
@@ -3006,7 +3006,7 @@ with a backslash have special meaning in regexps.  *Note 
GNU Regexp
 Operators::.
 
    In a regexp, a backslash before any character that is not in the
-previous list and not listed in *note GNU Regexp Operators::, means
+previous list and not listed in *Note GNU Regexp Operators::, means
 that the next character should be taken literally, even if it would
 normally be a regexp operator.  For example, `/a\+b/' matches the three
 characters `a+b'.
@@ -3021,7 +3021,7 @@ character not shown in the previous list.
      early, as soon as `awk' reads your program.
 
    * `gawk' processes both regexp constants and dynamic regexps (*note
-     Computed Regexps::), for the special operators listed in *note GNU
+     Computed Regexps::), for the special operators listed in *Note GNU
      Regexp Operators::.
 
    * A backslash before any other character means to treat that
@@ -3050,7 +3050,7 @@ Advanced Notes: Escape Sequences for Metacharacters
 ---------------------------------------------------
 
 Suppose you use an octal or hexadecimal escape to represent a regexp
-metacharacter.  (See *note Regexp Operators::.)  Does `awk' treat the
+metacharacter.  (See *Note Regexp Operators::.)  Does `awk' treat the
 character as a literal character or as a regexp operator?
 
    Historically, such characters were taken literally.  (d.c.)
@@ -3070,7 +3070,7 @@ You can combine regular expressions with special 
characters, called
 "regular expression operators" or "metacharacters", to increase the
 power and versatility of regular expressions.
 
-   The escape sequences described in *note Escape Sequences::, are
+   The escape sequences described in *Note Escape Sequences::, are
 valid inside a regexp.  They are introduced by a `\' and are recognized
 and converted into corresponding real characters as the very first step
 in processing regexps.
@@ -3120,7 +3120,7 @@ sequences and that are not listed in the table stand for 
themselves:
      the characters that are enclosed in the square brackets.  For
      example, `[MVX]' matches any one of the characters `M', `V', or
      `X' in a string.  A full discussion of what can be inside the
-     square brackets of a bracket expression is given in *note Bracket
+     square brackets of a bracket expression is given in *Note Bracket
      Expressions::.
 
 `[^ ...]'
@@ -3247,7 +3247,7 @@ those listed between the opening and closing square 
brackets.
 characters separated by a hyphen.  It matches any single character that
 sorts between the two characters, based upon the system's native
 character set.  For example, `[0-9]' is equivalent to `[0123456789]'.
-(See *note Ranges and Locales::, for an explanation of how the POSIX
+(See *Note Ranges and Locales::, for an explanation of how the POSIX
 standard and `gawk' have changed over time.  This is mainly of
 historical interest.)
 
@@ -3273,7 +3273,7 @@ differs between the United States and France.
 
    A character class is only valid in a regexp _inside_ the brackets of
 a bracket expression.  Character classes consist of `[:', a keyword
-denoting the class, and `:]'.  *note table-char-classes:: lists the
+denoting the class, and `:]'.  *Note table-char-classes:: lists the
 character classes defined by the POSIX standard.
 
 Class       Meaning
@@ -3404,7 +3404,7 @@ GNU `\b' appears to be the lesser of two evils.
 
 No options
      In the default case, `gawk' provides all the facilities of POSIX
-     regexps and the GNU regexp operators described in *note Regexp
+     regexps and the GNU regexp operators described in *Note Regexp
      Operators::.
 
 `--posix'
@@ -3955,7 +3955,7 @@ that the multiplication is done before the `$' operation; 
they are
 necessary whenever there is a binary operator in the field-number
 expression.  This example, then, prints the hours of operation (the
 fourth field) for every line of the file `BBS-list'.  (All of the `awk'
-operators are listed, in order of decreasing precedence, in *note
+operators are listed, in order of decreasing precedence, in *Note
 Precedence::.)
 
    If the field number you compute is zero, you get the entire record.
@@ -3965,7 +3965,7 @@ not allowed; trying to reference one usually terminates 
the program.
 negative field number.  `gawk' notices this and terminates your
 program.  Other `awk' implementations may behave differently.)
 
-   As mentioned in *note Fields::, `awk' stores the current record's
+   As mentioned in *Note Fields::, `awk' stores the current record's
 number of fields in the built-in variable `NF' (also *note Built-in
 Variables::).  The expression `$NF' is not a special feature--it is the
 direct consequence of evaluating `NF' and using its value as a field
@@ -5226,7 +5226,7 @@ in mind:
      probably by accident, and you should reconsider what it is you're
      trying to accomplish.
 
-   * *note Getline Summary::, presents a table summarizing the
+   * *Note Getline Summary::, presents a table summarizing the
      `getline' variants and which variables they can affect.  It is
      worth noting that those variants which do not use redirection can
      cause `FILENAME' to be updated if they cause `awk' to start
@@ -5238,7 +5238,7 @@ File: gawk.info,  Node: Getline Summary,  Prev: Getline 
Notes,  Up: Getline
 4.9.10 Summary of `getline' Variants
 ------------------------------------
 
-*note table-getline-variants:: summarizes the eight variants of
+*Note table-getline-variants:: summarizes the eight variants of
 `getline', listing which built-in variables are set by each one, and
 whether the variant is standard or a `gawk' extension.
 
@@ -5286,7 +5286,7 @@ and the `printf' statement for fancier formatting.  The 
`print'
 statement is not limited when computing _which_ values to print.
 However, with two exceptions, you cannot specify _how_ to print
 them--how many columns, whether to use exponential notation or not, and
-so on.  (For the exceptions, *note Output Separators::, and *note
+so on.  (For the exceptions, *note Output Separators::, and *Note
 OFMT::.)  For printing with specifications, you need the `printf'
 statement (*note Printf::).
 
@@ -5473,7 +5473,7 @@ that string.  `awk' uses the `sprintf()' function to do 
this conversion
 `sprintf()' function accepts a "format specification" that tells it how
 to format numbers (or strings), and that there are a number of
 different ways in which numbers can be formatted.  The different format
-specifications are discussed more fully in *note Control Letters::.
+specifications are discussed more fully in *Note Control Letters::.
 
    The built-in variable `OFMT' contains the default format
 specification that `print' uses with `sprintf()' when it wants to
@@ -5523,8 +5523,8 @@ A simple `printf' statement looks like this:
      printf FORMAT, ITEM1, ITEM2, ...
 
 The entire list of arguments may optionally be enclosed in parentheses.
-The parentheses are necessary if any of the item expressions use the `>'
-relational operator; otherwise, it can be confused with an output
+The parentheses are necessary if any of the item expressions use the
+`>' relational operator; otherwise, it can be confused with an output
 redirection (*note Redirection::).
 
    The difference between `printf' and `print' is the FORMAT argument.
@@ -5730,12 +5730,12 @@ which they may appear:
           -| 1,234,567                 Results in US English UTF locale
 
      For more information about locales and internationalization issues,
-     see *note Locales::.
+     see *Note Locales::.
 
           NOTE: The `'' flag is a nice feature, but its use complicates
           things: it becomes difficult to use it in command-line
           programs.  For information on appropriate quoting tricks, see
-          *note Quoting::.
+          *Note Quoting::.
 
 `WIDTH'
      This is a number specifying the desired minimum width of a field.
@@ -5976,7 +5976,7 @@ work identically for `printf':
      The message is built using string concatenation and saved in the
      variable `m'.  It's then sent down the pipeline to the `mail'
      program.  (The parentheses group the items to concatenate--see
-     *note Concatenation::.)
+     *Note Concatenation::.)
 
      The `close()' function is called here because it's a good idea to
      close the pipe as soon as all the intended output has been sent to
@@ -6161,7 +6161,7 @@ essential pieces of information for making a networking 
connection.
 These file names are used with the `|&' operator for communicating with
 a coprocess (*note Two-way I/O::).  This is an advanced feature,
 mentioned here only for completeness.  Full discussion is delayed until
-*note TCP/IP Networking::.
+*Note TCP/IP Networking::.
 
 
 File: gawk.info,  Node: Special Caveats,  Prev: Special Network,  Up: Special 
Files
@@ -6308,7 +6308,7 @@ to `close()'.  As in any other call to `close()', the 
first argument is
 the name of the command or special file used to start the coprocess.
 The second argument should be a string, with either of the values
 `"to"' or `"from"'.  Case does not matter.  As this is an advanced
-feature, a more complete discussion is delayed until *note Two-way
+feature, a more complete discussion is delayed until *Note Two-way
 I/O::, which discusses it in more detail and gives an example.
 
 Advanced Notes: Using `close()''s Return Value
@@ -6497,7 +6497,7 @@ option; *note Nondecimal Data::.)  If you have octal or 
hexadecimal
 data, you can use the `strtonum()' function (*note String Functions::)
 to convert the data into a number.  Most of the time, you will want to
 use octal or hexadecimal constants when working with the built-in bit
-manipulation functions; see *note Bitwise Functions::, for more
+manipulation functions; see *Note Bitwise Functions::, for more
 information.
 
    Unlike some early C implementations, `8' and `9' are not valid in
@@ -6780,7 +6780,7 @@ your programs, just port `gawk' itself.  *Note Print::, 
for more
 information on the `print' statement.
 
    And, once again, where you are can matter when it comes to converting
-between numbers and strings.  In *note Locales::, we mentioned that the
+between numbers and strings.  In *Note Locales::, we mentioned that the
 local character set and language (the locale) can affect how `gawk'
 matches characters.  The locale also affects numeric formats.  In
 particular, for `awk' programs, it affects the decimal point character.
@@ -6821,7 +6821,7 @@ character.  (`gawk' also uses the locale's decimal point 
character when
 in POSIX mode, either via `--posix', or the `POSIXLY_CORRECT'
 environment variable.)
 
-   *note table-locale-affects:: describes the cases in which the
+   *Note table-locale-affects:: describes the cases in which the
 locale's decimal point character is used and when a period is used.
 Some of these features have not been described yet.
 
@@ -6837,7 +6837,7 @@ Table 6.1: Locale Decimal Point versus A Period
    Finally, modern day formal standards and IEEE standard floating point
 representation can have an unusual but important effect on the way
 `gawk' converts some special string values to numbers.  The details are
-presented in *note POSIX Floating Point Problems::.
+presented in *Note POSIX Floating Point Problems::.
 
    ---------- Footnotes ----------
 
@@ -7148,7 +7148,7 @@ righthand expression.  For example:
 The indices of `bar' are practically guaranteed to be different, because
 `rand()' returns different values each time it is called.  (Arrays and
 the `rand()' function haven't been covered yet.  *Note Arrays::, and
-see *note Numeric Functions::, for more information).  This example
+see *Note Numeric Functions::, for more information).  This example
 illustrates an important fact about assignment operators: the lefthand
 expression is only evaluated _once_.  It is up to the implementation as
 to which expression is evaluated first, the lefthand or the righthand.
@@ -7159,7 +7159,7 @@ Consider this example:
 
 The value of `a[3]' could be either two or four.
 
-   *note table-assign-ops:: lists the arithmetic assignment operators.
+   *Note table-assign-ops:: lists the arithmetic assignment operators.
 In each case, the righthand operand is an expression whose value is
 converted to a number.
 
@@ -7197,7 +7197,7 @@ A workaround is:
      awk '/[=]=/' /dev/null
 
    `gawk' does not have this problem, nor do the other freely available
-versions described in *note Other Versions::.
+versions described in *Note Other Versions::.
 
 
 File: gawk.info,  Node: Increment Ops,  Prev: Assignment Ops,  Up: All 
Operators
@@ -7462,7 +7462,7 @@ File: gawk.info,  Node: Comparison Operators,  Next: 
POSIX String Comparison,  P
 
 "Comparison expressions" compare strings or numbers for relationships
 such as equality.  They are written using "relational operators", which
-are a superset of those in C.  *note table-relational-ops:: describes
+are a superset of those in C.  *Note table-relational-ops:: describes
 them.
 
 Expression         Result
@@ -7638,8 +7638,8 @@ Boolean operators are:
           if ($0 ~ /2400/ || $0 ~ /foo/) print
 
      The subexpression BOOLEAN2 is evaluated only if BOOLEAN1 is false.
-     This can make a difference when BOOLEAN2 contains expressions that
-     have side effects.
+     This can make a difference when BOOLEAN2 contains expressions
+     that have side effects.
 
 `! BOOLEAN'
      True if BOOLEAN is false.  For example, the following program
@@ -7649,7 +7649,7 @@ Boolean operators are:
           BEGIN { if (! ("HOME" in ENVIRON))
                          print "no home!" }
 
-     (The `in' operator is described in *note Reference to Elements::.)
+     (The `in' operator is described in *Note Reference to Elements::.)
 
    The `&&' and `||' operators are called "short-circuit" operators
 because of the way they work.  Evaluation of the full expression is
@@ -7679,7 +7679,7 @@ using `!'. The next rule prints lines as long as 
`interested' is true.
 When a line is seen whose first field is `END', `interested' is toggled
 back to false.(1)
 
-     NOTE: The `next' statement is discussed in *note Next Statement::.
+     NOTE: The `next' statement is discussed in *Note Next Statement::.
      `next' tells `awk' to skip the rest of the rules, get the next
      record, and start processing the rules over again at the top.  The
      reason it's there is to avoid printing the bracketing `START' and
@@ -7782,7 +7782,7 @@ User-defined::).
    As an advanced feature, `gawk' provides indirect function calls,
 which is a way to choose the function to call at runtime, instead of
 when you write the source code to your program. We defer discussion of
-this feature until later; see *note Indirect Calls::.
+this feature until later; see *Note Indirect Calls::.
 
    Like every other expression, the function call has a value, which is
 computed by the function based on the arguments you give it.  In this
@@ -7942,12 +7942,12 @@ make several function calls, _per input character_, to 
find the record
 terminator.
 
    According to POSIX, string comparison is also affected by locales
-(similar to regular expressions).  The details are presented in *note
+(similar to regular expressions).  The details are presented in *Note
 POSIX String Comparison::.
 
    Finally, the locale affects the value of the decimal point character
 used when `gawk' parses input data.  This is discussed in detail in
-*note Conversion::.
+*Note Conversion::.
 
 
 File: gawk.info,  Node: Patterns and Actions,  Next: Arrays,  Prev: 
Expressions,  Up: Top
@@ -8048,7 +8048,7 @@ otherwise, it depends on only what has happened so far in 
the execution
 of the `awk' program.
 
    Comparison expressions, using the comparison operators described in
-*note Typing and Comparison::, are a very common kind of pattern.
+*Note Typing and Comparison::, are a very common kind of pattern.
 Regexp matching and nonmatching are also very common expressions.  The
 left operand of the `~' and `!~' operators is a string.  The right
 operand is either a constant regular expression enclosed in slashes
@@ -8114,7 +8114,7 @@ inside Boolean patterns.  Likewise, the special patterns 
`BEGIN', `END',
 expressions and cannot appear inside Boolean patterns.
 
    The precedence of the different operators which can appear in
-patterns is described in *note Precedence::.
+patterns is described in *Note Precedence::.
 
 
 File: gawk.info,  Node: Ranges,  Next: BEGIN/END,  Prev: Expression Patterns,  
Up: Pattern Overview
@@ -8300,7 +8300,7 @@ explicitly.
 `BEGIN' rule, because the implicit
 read-a-record-and-match-against-the-rules loop has not started yet.
 Similarly, those statements are not valid in an `END' rule, since all
-the input has been read.  (*Note Next Statement::, and see *note
+the input has been read.  (*Note Next Statement::, and see *Note
 Nextfile Statement::.)
 
 
@@ -8839,7 +8839,7 @@ Statement::.)
      }
 
    The `break' statement is also used to break out of the `switch'
-statement.  This is discussed in *note Switch Statement::.
+statement.  This is discussed in *Note Switch Statement::.
 
    The `break' statement has no meaning when used outside the body of a
 loop or `switch'.  However, although it was never documented,
@@ -8936,7 +8936,7 @@ beginning, in the following manner:
 Because of the `next' statement, the program's subsequent rules won't
 see the bad record.  The error message is redirected to the standard
 error output stream, as error messages should be.  For more detail see
-*note Special Files::.
+*Note Special Files::.
 
    If the `next' statement causes the end of the input to be reached,
 then the code in any `END' rules is executed.  *Note BEGIN/END::.
@@ -9107,7 +9107,7 @@ specific to `gawk' are marked with a pound sign (`#').
      string value of `"rw"' or `"wr"' indicates that all files should
      use binary I/O.  Any other string value is treated the same as
      `"rw"', but causes `gawk' to generate a warning message.
-     `BINMODE' is described in more detail in *note PC Using::.
+     `BINMODE' is described in more detail in *Note PC Using::.
 
      This variable is a `gawk' extension.  In other `awk'
      implementations (except `mawk', *note Other Versions::), or if
@@ -9411,7 +9411,7 @@ with a pound sign (`#').
           If this element exists in `PROCINFO', its value controls the
           order in which array indices will be processed by `for (index
           in array) ...' loops.  Since this is an advanced feature, we
-          defer the full description until later; see *note Scanning an
+          defer the full description until later; see *Note Scanning an
           Array::.
 
     `PROCINFO["strftime"]'
@@ -9432,7 +9432,7 @@ with a pound sign (`#').
 
      The `PROCINFO' array is also used to cause coprocesses to
      communicate over pseudo-ttys instead of through two-way pipes;
-     this is discussed further in *note Two-way I/O::.
+     this is discussed further in *Note Two-way I/O::.
 
      This array is a `gawk' extension.  In other `awk' implementations,
      or if `gawk' is in compatibility mode (*note Options::), it is not
@@ -9494,7 +9494,7 @@ File: gawk.info,  Node: ARGC and ARGV,  Prev: Auto-set,  
Up: Built-in Variables
 7.5.3 Using `ARGC' and `ARGV'
 -----------------------------
 
-*note Auto-set::, presented the following program describing the
+*Note Auto-set::, presented the following program describing the
 information contained in `ARGC' and `ARGV':
 
      $ awk 'BEGIN {
@@ -9550,7 +9550,7 @@ elements from `ARGV' (*note Delete::).
 
    All of these actions are typically done in the `BEGIN' rule, before
 actual processing of the input begins.  *Note Split Program::, and see
-*note Tee Program::, for examples of each way of removing elements from
+*Note Tee Program::, for examples of each way of removing elements from
 `ARGV'.  The following fragment processes `ARGV' in order to examine,
 and then remove, command-line options:
 
@@ -9730,7 +9730,7 @@ from English to French:
 Here we decided to translate the number one in both spelled-out and
 numeric form--thus illustrating that a single array can have both
 numbers and strings as indices.  In fact, array subscripts are always
-strings; this is discussed in more detail in *note Numeric Array
+strings; this is discussed in more detail in *Note Numeric Array
 Subscripts::.  Here, the number `1' isn't double-quoted, since `awk'
 automatically converts it to a string.
 
@@ -9931,11 +9931,11 @@ produce strange results.  It is best to avoid such 
things.
    As an extension, `gawk' makes it possible for you to loop over the
 elements of an array in order, based on the value of
 `PROCINFO["sorted_in"]' (*note Auto-set::).  This is an advanced
-feature, so discussion of it is delayed until *note Controlling Array
+feature, so discussion of it is delayed until *Note Controlling Array
 Traversal::.
 
    In addition, `gawk' provides built-in functions for sorting arrays;
-see *note Array Sorting Functions::.
+see *Note Array Sorting Functions::.
 
 
 File: gawk.info,  Node: Delete,  Next: Numeric Array Subscripts,  Prev: Array 
Basics,  Up: Arrays
@@ -10636,7 +10636,7 @@ pound sign (`#'):
 
           asort(a, a, "descending")
 
-     The `asort()' function is described in more detail in *note Array
+     The `asort()' function is described in more detail in *Note Array
      Sorting Functions::.  `asort()' is a `gawk' extension; it is not
      available in compatibility mode (*note Options::).
 
@@ -10645,7 +10645,7 @@ pound sign (`#'):
      similarly to `asort()', however, the _indices_ are sorted, instead
      of the values. (Here too, `IGNORECASE' affects the sorting.)
 
-     The `asorti()' function is described in more detail in *note Array
+     The `asorti()' function is described in more detail in *Note Array
      Sorting Functions::.  `asorti()' is a `gawk' extension; it is not
      available in compatibility mode (*note Options::).
 
@@ -11128,7 +11128,7 @@ replacement string to determine what to generate.
 
    At both levels, `awk' looks for a defined set of characters that can
 come after a backslash.  At the lexical level, it looks for the escape
-sequences listed in *note Escape Sequences::.  Thus, for every `\' that
+sequences listed in *Note Escape Sequences::.  Thus, for every `\' that
 `awk' processes at the runtime level, you must type two backslashes at
 the lexical level.  When a character that is not valid for an escape
 sequence follows the `\', Brian Kernighan's `awk' and `gawk' both
@@ -11141,7 +11141,7 @@ Historically, the `sub()' and `gsub()' functions 
treated the two
 character sequence `\&' specially; this sequence was replaced in the
 generated text with a single `&'.  Any other `\' within the REPLACEMENT
 string that did not precede an `&' was passed through unchanged.  This
-is illustrated in *note table-sub-escapes::.
+is illustrated in *Note table-sub-escapes::.
 
       You type         `sub()' sees          `sub()' generates
       -------         ---------          --------------
@@ -11153,8 +11153,7 @@ is illustrated in *note table-sub-escapes::.
      `\\\\\\&'           `\\\&'            a literal `\\&'
          `\\q'             `\q'            a literal `\q'
 
-Table 9.1: Historical Escape Sequence Processing for `sub()' and
-`gsub()'
+Table 9.1: Historical Escape Sequence Processing for `sub()' and `gsub()'
 
 This table shows both the lexical-level processing, where an odd number
 of backslashes becomes an even number at the runtime level, as well as
@@ -11169,7 +11168,7 @@ get a literal `\' followed by the matched text.
 says that `sub()' and `gsub()' look for either a `\' or an `&' after
 the `\'. If either one follows a `\', that character is output
 literally.  The interpretation of `\' and `&' then becomes as shown in
-*note table-sub-posix-92::.
+*Note table-sub-posix-92::.
 
       You type         `sub()' sees          `sub()' generates
       -------         ---------          --------------
@@ -11196,7 +11195,7 @@ problems:
 submitted proposed text for a revised standard that reverts to rules
 that correspond more closely to the original existing practice. The
 proposed rules have special cases that make it possible to produce a
-`\' preceding the matched text. This is shown in *note
+`\' preceding the matched text. This is shown in *Note
 table-sub-proposed::.
 
       You type         `sub()' sees         `sub()' generates
@@ -11224,7 +11223,7 @@ except for one case.
    The POSIX rules state that `\&' in the replacement string produces a
 literal `&', `\\' produces a literal `\', and `\' followed by anything
 else is not special; the `\' is placed straight into the output.  These
-rules are presented in *note table-posix-sub::.
+rules are presented in *Note table-posix-sub::.
 
       You type         `sub()' sees         `sub()' generates
       -------         ---------         --------------
@@ -11255,7 +11254,7 @@ level, whenever `gawk' sees a `\', if the following 
character is a
 digit, then the text that matched the corresponding parenthesized
 subexpression is placed in the generated output.  Otherwise, no matter
 what character follows the `\', it appears in the generated text and
-the `\' does not, as shown in *note table-gensub-escapes::.
+the `\' does not, as shown in *Note table-gensub-escapes::.
 
        You type          `gensub()' sees         `gensub()' generates
        -------          ------------         -----------------
@@ -11784,7 +11783,7 @@ supports all of the conversions listed here.
 
    (5) If you don't understand any of this, don't worry about it; these
 facilities are meant to make it easier to "internationalize" programs.
-Other internationalization features are described in *note
+Other internationalization features are described in *Note
 Internationalization::.
 
    (6) This is because ISO C leaves the behavior of the C version of
@@ -11804,7 +11803,7 @@ File: gawk.info,  Node: Bitwise Functions,  Next: Type 
Functions,  Prev: Time Fu
    Many languages provide the ability to perform "bitwise" operations
 on two integer numbers.  In other words, the operation is performed on
 each successive pair of bits in the operands.  Three common operations
-are bitwise AND, OR, and XOR.  The operations are described in *note
+are bitwise AND, OR, and XOR.  The operations are described in *Note
 table-bitwise-ops::.
 
                      Bit Operator
@@ -12072,7 +12071,7 @@ act of a function calling itself is called "recursion".
 
    All the built-in functions return a value to their caller.
 User-defined functions can do also, using the `return' statement, which
-is described in detail in *note Return Statement::.  Many of the
+is described in detail in *Note Return Statement::.  Many of the
 subsequent examples in this minor node use the `return' statement.
 
    In many `awk' implementations, including `gawk', the keyword
@@ -13005,7 +13004,7 @@ internationalization:
      `"LC_MESSAGES"'.
 
      If you supply a value for CATEGORY, it must be a string equal to
-     one of the known locale categories described in *note Explaining
+     one of the known locale categories described in *Note Explaining
      gettext::.  You must also supply a text domain.  Use `TEXTDOMAIN'
      if you want to use the current domain.
 
@@ -13037,7 +13036,7 @@ internationalization:
      current binding for the given DOMAIN.
 
    To use these facilities in your `awk' program, follow the steps
-outlined in *note Explaining gettext::, like so:
+outlined in *Note Explaining gettext::, like so:
 
   1. Set the variable `TEXTDOMAIN' to the text domain of your program.
      This is best done in a `BEGIN' rule (*note BEGIN/END::), or it can
@@ -13400,7 +13399,7 @@ full detail, along with the basics of TCP/IP 
networking.  Finally,
 `gawk' can "profile" an `awk' program, making it possible to tune it
 for performance.
 
-   *note Dynamic Extensions::, discusses the ability to dynamically add
+   *Note Dynamic Extensions::, discusses the ability to dynamically add
 new built-in functions to `gawk'.  As this feature is still immature
 and likely to change, its description is relegated to an appendix.
 
@@ -13718,7 +13717,7 @@ File: gawk.info,  Node: Controlling Scanning,  Prev: 
Controlling Scanning With A
 11.2.1.2 Controlling Array Scanning Order
 .........................................
 
-As described in *note Controlling Scanning With A Function::, you can
+As described in *Note Controlling Scanning With A Function::, you can
 provide the name of a function as the value of `PROCINFO["sorted_in"]'
 to specify custom sorting criteria.
 
@@ -14351,14 +14350,14 @@ File: gawk.info,  Node: Library Functions,  Next: 
Sample Programs,  Prev: Advanc
 12 A Library of `awk' Functions
 *******************************
 
-*note User-defined::, describes how to write your own `awk' functions.
+*Note User-defined::, describes how to write your own `awk' functions.
 Writing functions is important, because it allows you to encapsulate
 algorithms and program tasks in a single place.  It simplifies
 programming, making program development more manageable, and making
 programs more readable.
 
    One valuable way to learn a new programming language is to _read_
-programs in that language.  To that end, this major node and *note
+programs in that language.  To that end, this major node and *Note
 Sample Programs::, provide a good-sized body of code for you to read,
 and hopefully, to learn from.
 
@@ -14367,16 +14366,16 @@ of the sample programs presented later in this Info 
file use these
 functions.  The functions are presented here in a progression from
 simple to complex.
 
-   *note Extract Program::, presents a program that you can use to
+   *Note Extract Program::, presents a program that you can use to
 extract the source code for these example library functions and
 programs from the Texinfo source for this Info file.  (This has already
 been done as part of the `gawk' distribution.)
 
    If you have written one or more useful, general-purpose `awk'
 functions and would like to contribute them to the `awk' user
-community, see *note How To Contribute::, for more information.
+community, see *Note How To Contribute::, for more information.
 
-   The programs in this major node and in *note Sample Programs::,
+   The programs in this major node and in *Note Sample Programs::,
 freely use features that are `gawk'-specific.  Rewriting these programs
 for different implementations of `awk' is pretty straightforward.
 
@@ -14478,7 +14477,7 @@ program, leading to bugs that are very difficult to 
track down:
 single associative array to hold the values needed by the library
 function(s), or "package."  This significantly decreases the number of
 actual global names in use.  For example, the functions described in
-*note Passwd Functions::, might have used array elements
+*Note Passwd Functions::, might have used array elements
 `PW_data["inited"]', `PW_data["total"]', `PW_data["count"]', and
 `PW_data["awklib"]', instead of `_pw_inited', `_pw_awklib', `_pw_total',
 and `_pw_count'.
@@ -14916,7 +14915,7 @@ File: gawk.info,  Node: Gettimeofday Function,  Prev: 
Join Function,  Up: Genera
 12.2.7 Managing the Time of Day
 -------------------------------
 
-The `systime()' and `strftime()' functions described in *note Time
+The `systime()' and `strftime()' functions described in *Note Time
 Functions::, provide the minimum functionality necessary for dealing
 with the time of day in human readable form.  While `strftime()' is
 extensive, the control formats are not necessarily easy to remember or
@@ -14988,7 +14987,7 @@ current time formatted in the same way as the `date' 
utility:
 
    The string indices are easier to use and read than the various
 formats required by `strftime()'.  The `alarm' program presented in
-*note Alarm Program::, uses this function.  A more general design for
+*Note Alarm Program::, uses this function.  A more general design for
 the `gettimeofday()' function would have allowed the user to supply an
 optional timestamp value to use instead of the current time.
 
@@ -15089,7 +15088,7 @@ solves the problem:
 
      END  { endfile(_filename_) }
 
-   *note Wc Program::, shows how this library function can be used and
+   *Note Wc Program::, shows how this library function can be used and
 how it simplifies writing the main program.
 
 Advanced Notes: So Why Does `gawk' have `BEGINFILE' and `ENDFILE'?
@@ -15143,7 +15142,7 @@ over with it from the top.  For lack of a better name, 
we'll call it
 
    This code relies on the `ARGIND' variable (*note Auto-set::), which
 is specific to `gawk'.  If you are not using `gawk', you can use ideas
-presented in *note Filetrans Function::, to either update `ARGIND' on
+presented in *Note Filetrans Function::, to either update `ARGIND' on
 your own or modify this code as appropriate.
 
    The `rewind()' function also relies on the `nextfile' keyword (*note
@@ -15176,7 +15175,7 @@ program to your `awk' program:
 
    This works, because the `getline' won't be fatal.  Removing the
 element from `ARGV' with `delete' skips the file (since it's no longer
-in the list).  See also *note ARGC and ARGV::.
+in the list).  See also *Note ARGC and ARGV::.
 
 
 File: gawk.info,  Node: Empty Files,  Next: Ignoring Assigns,  Prev: File 
Checking,  Up: Data File Management
@@ -15194,7 +15193,7 @@ program code.
 
    Using `gawk''s `ARGIND' variable (*note Built-in Variables::), it is
 possible to detect when an empty data file has been skipped.  Similar
-to the library file presented in *note Filetrans Function::, the
+to the library file presented in *Note Filetrans Function::, the
 following library file calls a function named `zerofile()' that the
 user must provide.  The arguments passed are the file name and the
 position in `ARGV' where it was found:
@@ -15562,7 +15561,7 @@ that it does not try to interpret the `-a', etc., as 
its own options.
      `Optind', so that `awk' does not try to process the command-line
      options as file names.
 
-   Several of the sample programs presented in *note Sample Programs::,
+   Several of the sample programs presented in *Note Sample Programs::,
 use `getopt()' to process their arguments.
 
    ---------- Footnotes ----------
@@ -15807,7 +15806,7 @@ once.  If you are worried about squeezing every last 
cycle out of your
 this is not necessary, since most `awk' programs are I/O-bound, and
 such a change would clutter up the code.
 
-   The `id' program in *note Id Program::, uses these functions.
+   The `id' program in *Note Id Program::, uses these functions.
 
    ---------- Footnotes ----------
 
@@ -15820,7 +15819,7 @@ File: gawk.info,  Node: Group Functions,  Next: Walking 
Arrays,  Prev: Passwd Fu
 12.6 Reading the Group Database
 ===============================
 
-Much of the discussion presented in *note Passwd Functions::, applies
+Much of the discussion presented in *Note Passwd Functions::, applies
 to the group database as well.  Although there has traditionally been a
 well-known file (`/etc/group') in a well-known format, the POSIX
 standard only provides a set of C library routines (`<grp.h>' and
@@ -16046,7 +16045,7 @@ body of `_gr_init()' into a `BEGIN' rule).
 associative arrays.  The functions that the user calls are themselves
 very simple, relying on `awk''s associative arrays to do work.
 
-   The `id' program in *note Id Program::, uses these functions.
+   The `id' program in *Note Id Program::, uses these functions.
 
 
 File: gawk.info,  Node: Walking Arrays,  Prev: Group Functions,  Up: Library 
Functions
@@ -16054,7 +16053,7 @@ File: gawk.info,  Node: Walking Arrays,  Prev: Group 
Functions,  Up: Library Fun
 12.7 Traversing Arrays of Arrays
 ================================
 
-*note Arrays of Arrays::, described how `gawk' provides arrays of
+*Note Arrays of Arrays::, described how `gawk' provides arrays of
 arrays.  In particular, any element of an array may be either a scalar,
 or another array. The `isarray()' function (*note Type Functions::)
 lets you distinguish an array from a scalar.  The following function,
@@ -16105,12 +16104,12 @@ File: gawk.info,  Node: Sample Programs,  Next: 
Debugger,  Prev: Library Functio
 13 Practical `awk' Programs
 ***************************
 
-*note Library Functions::, presents the idea that reading programs in a
+*Note Library Functions::, presents the idea that reading programs in a
 language contributes to learning that language.  This major node
 continues that theme, presenting a potpourri of `awk' programs for your
 reading enjoyment.
 
-   Many of these programs use library functions presented in *note
+   Many of these programs use library functions presented in *Note
 Library Functions::.
 
 * Menu:
@@ -16285,7 +16284,7 @@ by characters, the output field separator is set to the 
null string:
 Using a single space (`" "') for the value of `FS' is incorrect--`awk'
 would separate fields with runs of spaces, TABs, and/or newlines, and
 we want them to be separated with individual spaces.  Also remember
-that after `getopt()' is through (as described in *note Getopt
+that after `getopt()' is through (as described in *Note Getopt
 Function::), we have to clear out all the elements of `ARGV' from 1 to
 `Optind', so that `awk' does not try to process the command-line options
 as file names.
@@ -16790,7 +16789,7 @@ to something like `myfileaa', `myfileab', and so on, 
supply an
 additional argument that specifies the file name prefix.
 
    Here is a version of `split' in `awk'. It uses the `ord()' and
-`chr()' functions presented in *note Ordinal Functions::.
+`chr()' functions presented in *Note Ordinal Functions::.
 
    The program first sets its defaults, and then tests to make sure
 there are not too many arguments.  It then looks at each argument in
@@ -17324,7 +17323,7 @@ in its length.  Next, `lines' is incremented for each 
line read, and
    ---------- Footnotes ----------
 
    (1) `wc' can't just use the value of `FNR' in `endfile()'. If you
-examine the code in *note Filetrans Function::, you will see that `FNR'
+examine the code in *Note Filetrans Function::, you will see that `FNR'
 has already been reset by the time `endfile()' is called.
 
    (2) Since `gawk' understands multibyte locales, this code counts
@@ -17420,7 +17419,7 @@ prints the message on the standard output. In addition, 
you can give it
 the number of times to repeat the message as well as a delay between
 repetitions.
 
-   This program uses the `gettimeofday()' function from *note
+   This program uses the `gettimeofday()' function from *Note
 Gettimeofday Function::.
 
    All the work is done in the `BEGIN' rule.  The first part is argument
@@ -17928,7 +17927,7 @@ File: gawk.info,  Node: Extract Program,  Next: Simple 
Sed,  Prev: History Sorti
 13.3.7 Extracting Programs from Texinfo Source Files
 ----------------------------------------------------
 
-The nodes *note Library Functions::, and *note Sample Programs::, are
+The nodes *Note Library Functions::, and *Note Sample Programs::, are
 the top level nodes for a large number of `awk' programs.  If you want
 to experiment with these programs, it is tedious to have to type them
 in by hand.  Here we present a program that can extract parts of a
@@ -18209,7 +18208,7 @@ File: gawk.info,  Node: Igawk Program,  Next: Anagram 
Program,  Prev: Simple Sed
 13.3.9 An Easy Way to Use Library Functions
 -------------------------------------------
 
-In *note Include Files::, we saw how `gawk' provides a built-in
+In *Note Include Files::, we saw how `gawk' provides a built-in
 file-inclusion capability.  However, this is a `gawk' extension.  This
 minor node provides the motivation for making file inclusion available
 for standard `awk', and shows how to do it using a combination of shell
@@ -19324,7 +19323,7 @@ execution of the program than we saw in our earlier 
example:
 `si' [COUNT]
      Execute one (or COUNT) instruction(s), stepping inside function
      calls.  (For illustration of what is meant by an "instruction" in
-     `gawk', see the output shown under `dump' in *note Miscellaneous
+     `gawk', see the output shown under `dump' in *Note Miscellaneous
      Dgawk Commands::.)
 
 `until' [[FILENAME`:']N | FUNCTION]
@@ -19730,7 +19729,7 @@ limitations.  A few which are worth being aware of are:
      Rather, it just responds `syntax error'.  When you do figure out
      what your mistake was, though, you'll feel like a real guru.
 
-   * If you perused the dump of opcodes in *note Miscellaneous Dgawk
+   * If you perused the dump of opcodes in *Note Miscellaneous Dgawk
      Commands::, (or if you are already familiar with `gawk' internals),
      you will realize that much of the internal manipulation of data in
      `gawk', as in many interpreters, is done on a stack.  `Op_push',
@@ -19750,7 +19749,7 @@ limitations.  A few which are worth being aware of are:
      you are expected to know what `/[^[:alnum:][:blank:]]/' means.
 
    * `dgawk' is designed to be used by running a program (with all its
-     parameters) on the command line, as described in *note dgawk
+     parameters) on the command line, as described in *Note dgawk
      invocation::.  There is no way (as of now) to attach or "break in"
      to a running program.  This seems reasonable for a language which
      is used mainly for quickly executing, short programs.
@@ -19940,7 +19939,7 @@ Other Versions::).
    This minor node describes common extensions that originally appeared
 in his version of `awk'.
 
-   * The `**' and `**=' operators (*note Arithmetic Ops:: and *note
+   * The `**' and `**=' operators (*note Arithmetic Ops:: and *Note
      Assignment Ops::).
 
    * The use of `func' as an abbreviation for `function' (*note
@@ -20333,7 +20332,7 @@ Info file, in approximate chronological order:
    * John Haque reworked the `gawk' internals to use a byte-code engine,
      providing the `dgawk' debugger for `awk' programs.
 
-   * Efraim Yawitz contributed the original text for *note Debugger::.
+   * Efraim Yawitz contributed the original text for *Note Debugger::.
 
    * Arnold Robbins has been working on `gawk' since 1988, at first
      helping David Trueman, and as the primary maintainer since around
@@ -20537,7 +20536,7 @@ Various `.c', `.y', and `.h' files
 
 `doc/igawk.1'
      The `troff' source for a manual page describing the `igawk'
-     program presented in *note Igawk Program::.
+     program presented in *Note Igawk Program::.
 
 `doc/Makefile.in'
      The input file used during the configuration process to generate
@@ -20557,7 +20556,7 @@ Various `.c', `.y', and `.h' files
 `missing_d/*'
 `m4/*'
      These files and subdirectories are used when configuring `gawk'
-     for various Unix systems.  They are explained in *note Unix
+     for various Unix systems.  They are explained in *Note Unix
      Installation::.
 
 `po/*'
@@ -20572,8 +20571,8 @@ Various `.c', `.y', and `.h' files
      programs from the Texinfo source file for this Info file. It also
      contains a `Makefile.in' file, which `configure' uses to generate
      a `Makefile'.  `Makefile.am' is used by GNU Automake to create
-     `Makefile.in'.  The library functions from *note Library
-     Functions::, and the `igawk' program from *note Igawk Program::,
+     `Makefile.in'.  The library functions from *Note Library
+     Functions::, and the `igawk' program from *Note Igawk Program::,
      are included as ready-to-use files in the `gawk' distribution.
      They are installed as part of the installation process.  The rest
      of the programs in this Info file are available in appropriate
@@ -20938,7 +20937,7 @@ MS-DOS or MS-Windows.  EMX (OS/2 only) does support at 
least the `|&'
 operator.
 
    The MS-DOS and MS-Windows versions of `gawk' search for program
-files as described in *note AWKPATH Variable::.  However, semicolons
+files as described in *Note AWKPATH Variable::.  However, semicolons
 (rather than colons) separate elements in the `AWKPATH' variable.  If
 `AWKPATH' is not set or is empty, then the default search path for
 MS-Windows and MS-DOS versions is `".;c:/lib/awk;c:/gnu/lib/awk"'.
@@ -21472,7 +21471,7 @@ File: gawk.info,  Node: Accessing The Source,  Next: 
Adding Code,  Up: Additions
 C.2.1 Accessing The `gawk' Git Repository
 -----------------------------------------
 
-As `gawk' is Free Software, the source code is always available.  *note
+As `gawk' is Free Software, the source code is always available.  *Note
 Gawk Distribution::, describes how to get and build the formal,
 released versions of `gawk'.
 
@@ -21492,7 +21491,7 @@ access the repository using:
      git clone http://git.savannah.gnu.org/r/gawk.git
 
    Once you have made changes, you can use `git diff' to produce a
-patch, and send that to the `gawk' maintainer; see *note Bugs:: for how
+patch, and send that to the `gawk' maintainer; see *Note Bugs:: for how
 to do that.
 
    Finally, if you cannot install Git (e.g., if it hasn't been ported
@@ -21641,7 +21640,7 @@ C.2.3 Porting `gawk' to a New Operating System
 If you want to port `gawk' to a new operating system, there are several
 steps:
 
-  1. Follow the guidelines in *note Adding Code::, concerning coding
+  1. Follow the guidelines in *Note Adding Code::, concerning coding
      style, submission of diffs, and so on.
 
   2. Be prepared to sign the appropriate paperwork.  In order for the
@@ -21791,16 +21790,9 @@ when writing extensions.  The next minor node shows 
how they are used:
      is current.  It may end up calling an internal `gawk' function.
      It also guarantees that the wide string is zero-terminated.
 
-`size_t get_curfunc_arg_count(void)'
-     This function returns the actual number of parameters passed to
-     the current function.  Inside the code of an extension this can be
-     used to determine the maximum index which is safe to use with
-     `get_actual_argument'.  If this value is greater than `nargs', the
-     function was called incorrectly from the `awk' program.
-
 `nargs'
-     Inside an extension function, this is the maximum number of
-     expected parameters, as set by the `make_builtin()' function.
+     Inside an extension function, this is the actual number of
+     parameters passed to the current function.
 
 `n->stptr'
 `n->stlen'
@@ -21828,12 +21820,10 @@ when writing extensions.  The next minor node shows 
how they are used:
      Clears the associative array pointed to by `n'.  Make sure that
      `n->type == Node_var_array' first.
 
-`NODE **assoc_lookup(NODE *symbol, NODE *subs, int reference)'
+`NODE **assoc_lookup(NODE *symbol, NODE *subs)'
      Finds, and installs if necessary, array elements.  `symbol' is the
      array, `subs' is the subscript.  This is usually a value created
-     with `make_string()' (see below).  `reference' should be `TRUE' if
-     it is an error to use the value before it is created. Typically,
-     `FALSE' is the correct value to use from extension functions.
+     with `make_string()' (see below).
 
 `NODE *make_string(char *s, size_t len)'
      Take a C string and turn it into a pointer to a `NODE' that can be
@@ -22135,7 +22125,7 @@ other POSIX-compliant systems:(1)
          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);
@@ -22192,7 +22182,7 @@ declarations and argument checking:
          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");
 
    Then comes the actual work. First, the function gets the arguments.
@@ -22219,15 +22209,15 @@ link.  If there's an error, it sets `ERRNO' and 
returns:
 calls are shown here, since they all follow the same pattern:
 
          /* 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("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("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);
@@ -22558,7 +22548,7 @@ larger range of values.  The disadvantage is that there 
are numbers
 that they cannot represent exactly.  `awk' uses "double precision"
 floating-point numbers, which can hold more digits than "single
 precision" floating-point numbers.  Floating-point issues are discussed
-more fully in *note Floating Point Issues::.
+more fully in *Note Floating Point Issues::.
 
    At the very lowest level, computers store values as groups of binary
 digits, or "bits".  Modern computers group bits into groups of eight,
@@ -22581,7 +22571,7 @@ or "binary", base 8 or "octal", and base 16 or 
"hexadecimal".  In
 binary, each column represents two times the value in the column to its
 right. Each column may contain either a 0 or a 1.  Thus, binary 1010
 represents 1 times 8, plus 0 times 4, plus 1 times 2, plus 0 times 1,
-or decimal 10.  Octal and hexadecimal are discussed more in *note
+or decimal 10.  Octal and hexadecimal are discussed more in *Note
 Nondecimal-numbers::.
 
    Programs are written in programming languages.  Hundreds, if not
@@ -22898,7 +22888,7 @@ Bit
      floating-point numbers, character data, addresses of other memory
      objects, or other data.  `awk' lets you work with floating-point
      numbers and strings.  `gawk' lets you manipulate bit values with
-     the built-in functions described in *note Bitwise Functions::.
+     the built-in functions described in *Note Bitwise Functions::.
 
      Computers are often defined by how many bits they use to represent
      integer values.  Typical systems are 32-bit systems, but 64-bit
@@ -23081,7 +23071,7 @@ Field
      built-in variable `FIELDWIDTHS' to describe their lengths.  If you
      wish to specify the contents of fields instead of the field
      separator, you can use the built-in variable `FPAT' to do so.
-     (*Note Field Separators::, *note Constant Size::, and *note
+     (*Note Field Separators::, *Note Constant Size::, and *Note
      Splitting By Content::.)
 
 Flag
@@ -23316,7 +23306,7 @@ Redirection
      `|', and `|&' operators.  You can redirect the output of the
      `print' and `printf' statements to a file or a system command,
      using the `>', `>>', `|', and `|&' operators.  (*Note Getline::,
-     and *note Redirection::.)
+     and *Note Redirection::.)
 
 Regexp
      See "Regular Expression."
@@ -24709,7 +24699,7 @@ Index
 * * (asterisk), * operator, as regexp operator: Regexp Operators.
                                                               (line  87)
 * * (asterisk), * operator, null strings, matching: Gory Details.
-                                                              (line 164)
+                                                              (line 163)
 * * (asterisk), ** operator <1>:         Precedence.          (line  49)
 * * (asterisk), ** operator:             Arithmetic Ops.      (line  81)
 * * (asterisk), **= operator <1>:        Precedence.          (line  95)
@@ -24949,7 +24939,7 @@ Index
                                                               (line  23)
 * advanced features, network connections, See Also networks, connections: 
Advanced Features.
                                                               (line   6)
-* advanced features, null strings, matching: Gory Details.    (line 164)
+* advanced features, null strings, matching: Gory Details.    (line 163)
 * advanced features, operators, precedence: Increment Ops.    (line  61)
 * advanced features, piping into sh:     Redirection.         (line 143)
 * advanced features, regexp constants:   Assignment Ops.      (line 148)
@@ -24988,18 +24978,18 @@ Index
 * arguments, command-line, invoking awk: Command Line.        (line   6)
 * arguments, in function calls:          Function Calls.      (line  16)
 * arguments, processing:                 Getopt Function.     (line   6)
-* arguments, retrieving:                 Internals.           (line 120)
+* arguments, retrieving:                 Internals.           (line 111)
 * arithmetic operators:                  Arithmetic Ops.      (line   6)
 * arrays:                                Arrays.              (line   6)
 * arrays, as parameters to functions:    Pass By Value/Reference.
                                                               (line  47)
 * arrays, associative:                   Array Intro.         (line  50)
-* arrays, associative, clearing:         Internals.           (line  75)
+* arrays, associative, clearing:         Internals.           (line  68)
 * arrays, associative, library functions and: Library Names.  (line  57)
 * arrays, deleting entire contents:      Delete.              (line  39)
 * arrays, elements, assigning:           Assigning Elements.  (line   6)
 * arrays, elements, deleting:            Delete.              (line   6)
-* arrays, elements, installing:          Internals.           (line  79)
+* arrays, elements, installing:          Internals.           (line  72)
 * arrays, elements, order of:            Scanning an Array.   (line  48)
 * arrays, elements, referencing:         Reference to Elements.
                                                               (line   6)
@@ -25038,15 +25028,15 @@ Index
 * assignment operators, evaluation order: Assignment Ops.     (line 111)
 * assignment operators, lvalues/rvalues: Assignment Ops.      (line  32)
 * assignments as filenames:              Ignoring Assigns.    (line   6)
-* assoc_clear() internal function:       Internals.           (line  75)
-* assoc_lookup() internal function:      Internals.           (line  79)
+* assoc_clear() internal function:       Internals.           (line  68)
+* assoc_lookup() internal function:      Internals.           (line  72)
 * associative arrays:                    Array Intro.         (line  50)
 * asterisk (*), * operator, as multiplication operator: Precedence.
                                                               (line  55)
 * asterisk (*), * operator, as regexp operator: Regexp Operators.
                                                               (line  87)
 * asterisk (*), * operator, null strings, matching: Gory Details.
-                                                              (line 164)
+                                                              (line 163)
 * asterisk (*), ** operator <1>:         Precedence.          (line  49)
 * asterisk (*), ** operator:             Arithmetic Ops.      (line  81)
 * asterisk (*), **= operator <1>:        Precedence.          (line  95)
@@ -25310,7 +25300,7 @@ Index
 * close() function, two-way pipes and:   Two-way I/O.         (line  77)
 * Close, Diane <1>:                      Contributors.        (line  21)
 * Close, Diane:                          Manual History.      (line  41)
-* close_func() input method:             Internals.           (line 160)
+* close_func() input method:             Internals.           (line 151)
 * collating elements:                    Bracket Expressions. (line  69)
 * collating symbols:                     Bracket Expressions. (line  76)
 * Colombo, Antonio:                      Acknowledgments.     (line  60)
@@ -25683,7 +25673,7 @@ Index
 * DuBois, John:                          Acknowledgments.     (line  60)
 * dump debugger command:                 Miscellaneous Dgawk Commands.
                                                               (line   9)
-* dupnode() internal function:           Internals.           (line  96)
+* dupnode() internal function:           Internals.           (line  87)
 * dupword.awk program:                   Dupword Program.     (line  31)
 * e debugger command (alias for enable): Breakpoint Control.  (line  72)
 * EBCDIC:                                Ordinal Functions.   (line  45)
@@ -25724,7 +25714,7 @@ Index
 * endgrent() user-defined function:      Group Functions.     (line 218)
 * endpwent() function (C library):       Passwd Functions.    (line 210)
 * endpwent() user-defined function:      Passwd Functions.    (line 213)
-* ENVIRON array <1>:                     Internals.           (line 149)
+* ENVIRON array <1>:                     Internals.           (line 140)
 * ENVIRON array:                         Auto-set.            (line  60)
 * environment variables:                 Auto-set.            (line  60)
 * epoch, definition of:                  Glossary.            (line 239)
@@ -25733,7 +25723,7 @@ Index
 * equals sign (=), == operator:          Comparison Operators.
                                                               (line  11)
 * EREs (Extended Regular Expressions):   Bracket Expressions. (line  24)
-* ERRNO variable <1>:                    Internals.           (line 139)
+* ERRNO variable <1>:                    Internals.           (line 130)
 * ERRNO variable <2>:                    TCP/IP Networking.   (line  54)
 * ERRNO variable <3>:                    Auto-set.            (line  72)
 * ERRNO variable <4>:                    BEGINFILE/ENDFILE.   (line  26)
@@ -25782,7 +25772,7 @@ Index
                                                               (line   9)
 * expressions, selecting:                Conditional Exp.     (line   6)
 * Extended Regular Expressions (EREs):   Bracket Expressions. (line  24)
-* eXtensible Markup Language (XML):      Internals.           (line 160)
+* eXtensible Markup Language (XML):      Internals.           (line 151)
 * extension() function (gawk):           Using Internal File Ops.
                                                               (line  15)
 * extensions, Brian Kernighan's awk <1>: Other Versions.      (line  13)
@@ -26004,7 +25994,7 @@ Index
 * functions, names of <1>:               Definition Syntax.   (line  20)
 * functions, names of:                   Arrays.              (line  18)
 * functions, recursive:                  Definition Syntax.   (line  73)
-* functions, return values, setting:     Internals.           (line 139)
+* functions, return values, setting:     Internals.           (line 130)
 * functions, string-translation:         I18N Functions.      (line   6)
 * functions, undefined:                  Pass By Value/Reference.
                                                               (line  71)
@@ -26118,12 +26108,11 @@ Index
 * gensub() function (gawk):              Using Constant Regexps.
                                                               (line  43)
 * gensub() function (gawk), escape processing: Gory Details.  (line   6)
-* get_actual_argument() internal function: Internals.         (line 125)
-* get_argument() internal function:      Internals.           (line 120)
-* get_array_argument() internal macro:   Internals.           (line 136)
-* get_curfunc_arg_count() internal function: Internals.       (line  42)
-* get_record() input method:             Internals.           (line 160)
-* get_scalar_argument() internal macro:  Internals.           (line 133)
+* get_actual_argument() internal function: Internals.         (line 116)
+* get_argument() internal function:      Internals.           (line 111)
+* get_array_argument() internal macro:   Internals.           (line 127)
+* get_record() input method:             Internals.           (line 151)
+* get_scalar_argument() internal macro:  Internals.           (line 124)
 * getaddrinfo() function (C library):    TCP/IP Networking.   (line  38)
 * getgrent() function (C library):       Group Functions.     (line   6)
 * getgrent() user-defined function:      Group Functions.     (line   6)
@@ -26276,37 +26265,36 @@ Index
 * integers:                              Basic Data Typing.   (line  21)
 * integers, unsigned:                    Basic Data Typing.   (line  30)
 * interacting with other programs:       I/O Functions.       (line  63)
-* internal constant, INVALID_HANDLE:     Internals.           (line 160)
-* internal function, assoc_clear():      Internals.           (line  75)
-* internal function, assoc_lookup():     Internals.           (line  79)
-* internal function, dupnode():          Internals.           (line  96)
+* internal constant, INVALID_HANDLE:     Internals.           (line 151)
+* internal function, assoc_clear():      Internals.           (line  68)
+* internal function, assoc_lookup():     Internals.           (line  72)
+* internal function, dupnode():          Internals.           (line  87)
 * internal function, force_number():     Internals.           (line  27)
 * internal function, force_string():     Internals.           (line  32)
 * internal function, force_wstring():    Internals.           (line  37)
-* internal function, get_actual_argument(): Internals.        (line 125)
-* internal function, get_argument():     Internals.           (line 120)
-* internal function, get_curfunc_arg_count(): Internals.      (line  42)
-* internal function, iop_alloc():        Internals.           (line 160)
-* internal function, make_builtin():     Internals.           (line 106)
-* internal function, make_number():      Internals.           (line  91)
-* internal function, make_string():      Internals.           (line  86)
-* internal function, register_deferred_variable(): Internals. (line 149)
-* internal function, register_open_hook(): Internals.         (line 160)
-* internal function, unref():            Internals.           (line 101)
-* internal function, update_ERRNO():     Internals.           (line 139)
-* internal function, update_ERRNO_saved(): Internals.         (line 144)
-* internal macro, get_array_argument():  Internals.           (line 136)
-* internal macro, get_scalar_argument(): Internals.           (line 133)
-* internal structure, IOBUF:             Internals.           (line 160)
+* internal function, get_actual_argument(): Internals.        (line 116)
+* internal function, get_argument():     Internals.           (line 111)
+* internal function, iop_alloc():        Internals.           (line 151)
+* internal function, make_builtin():     Internals.           (line  97)
+* internal function, make_number():      Internals.           (line  82)
+* internal function, make_string():      Internals.           (line  77)
+* internal function, register_deferred_variable(): Internals. (line 140)
+* internal function, register_open_hook(): Internals.         (line 151)
+* internal function, unref():            Internals.           (line  92)
+* internal function, update_ERRNO():     Internals.           (line 130)
+* internal function, update_ERRNO_saved(): Internals.         (line 135)
+* internal macro, get_array_argument():  Internals.           (line 127)
+* internal macro, get_scalar_argument(): Internals.           (line 124)
+* internal structure, IOBUF:             Internals.           (line 151)
 * internal type, AWKNUM:                 Internals.           (line  19)
 * internal type, NODE:                   Internals.           (line  23)
-* internal variable, nargs:              Internals.           (line  49)
-* internal variable, stlen:              Internals.           (line  53)
-* internal variable, stptr:              Internals.           (line  53)
-* internal variable, type:               Internals.           (line  66)
-* internal variable, vname:              Internals.           (line  71)
-* internal variable, wstlen:             Internals.           (line  61)
-* internal variable, wstptr:             Internals.           (line  61)
+* internal variable, nargs:              Internals.           (line  42)
+* internal variable, stlen:              Internals.           (line  46)
+* internal variable, stptr:              Internals.           (line  46)
+* internal variable, type:               Internals.           (line  59)
+* internal variable, vname:              Internals.           (line  64)
+* internal variable, wstlen:             Internals.           (line  54)
+* internal variable, wstptr:             Internals.           (line  54)
 * internationalization <1>:              I18N and L10N.       (line   6)
 * internationalization:                  I18N Functions.      (line   6)
 * internationalization, localization <1>: Internationalization.
@@ -26326,10 +26314,10 @@ Index
 * interpreted programs <1>:              Glossary.            (line 361)
 * interpreted programs:                  Basic High Level.    (line  14)
 * interval expressions:                  Regexp Operators.    (line 116)
-* INVALID_HANDLE internal constant:      Internals.           (line 160)
+* INVALID_HANDLE internal constant:      Internals.           (line 151)
 * inventory-shipped file:                Sample Data Files.   (line  32)
-* IOBUF internal structure:              Internals.           (line 160)
-* iop_alloc() internal function:         Internals.           (line 160)
+* IOBUF internal structure:              Internals.           (line 151)
+* iop_alloc() internal function:         Internals.           (line 151)
 * isarray() function (gawk):             Type Functions.      (line  11)
 * ISO:                                   Glossary.            (line 372)
 * ISO 8859-1:                            Glossary.            (line 141)
@@ -26456,9 +26444,9 @@ Index
 * lvalues/rvalues:                       Assignment Ops.      (line  32)
 * mailing labels, printing:              Labels Program.      (line   6)
 * mailing list, GNITS:                   Acknowledgments.     (line  52)
-* make_builtin() internal function:      Internals.           (line 106)
-* make_number() internal function:       Internals.           (line  91)
-* make_string() internal function:       Internals.           (line  86)
+* make_builtin() internal function:      Internals.           (line  97)
+* make_number() internal function:       Internals.           (line  82)
+* make_string() internal function:       Internals.           (line  77)
 * mark parity:                           Ordinal Functions.   (line  45)
 * marked string extraction (internationalization): String Extraction.
                                                               (line   6)
@@ -26470,10 +26458,10 @@ Index
 * matching, expressions, See comparison expressions: Typing and Comparison.
                                                               (line   9)
 * matching, leftmost longest:            Multiple Line.       (line  26)
-* matching, null strings:                Gory Details.        (line 164)
+* matching, null strings:                Gory Details.        (line 163)
 * mawk program:                          Other Versions.      (line  35)
 * McPhee, Patrick:                       Contributors.        (line 100)
-* memory, releasing:                     Internals.           (line 101)
+* memory, releasing:                     Internals.           (line  92)
 * message object files:                  Explaining gettext.  (line  41)
 * message object files, converting from portable object files: I18N Example.
                                                               (line  62)
@@ -26495,7 +26483,7 @@ Index
 * namespace issues <1>:                  Library Names.       (line   6)
 * namespace issues:                      Arrays.              (line  18)
 * namespace issues, functions:           Definition Syntax.   (line  20)
-* nargs internal variable:               Internals.           (line  49)
+* nargs internal variable:               Internals.           (line  42)
 * nawk utility:                          Names.               (line  17)
 * negative zero:                         Unexpected Results.  (line  28)
 * NetBSD:                                Glossary.            (line 611)
@@ -26537,7 +26525,7 @@ Index
                                                               (line  49)
 * noassign.awk program:                  Ignoring Assigns.    (line  15)
 * NODE internal type:                    Internals.           (line  23)
-* nodes, duplicating:                    Internals.           (line  96)
+* nodes, duplicating:                    Internals.           (line  87)
 * not Boolean-logic operator:            Boolean Ops.         (line   6)
 * NR variable <1>:                       Auto-set.            (line 118)
 * NR variable:                           Records.             (line   6)
@@ -26551,14 +26539,14 @@ Index
 * null strings, as array subscripts:     Uninitialized Subscripts.
                                                               (line  43)
 * null strings, converting numbers to strings: Conversion.    (line  21)
-* null strings, matching:                Gory Details.        (line 164)
+* null strings, matching:                Gory Details.        (line 163)
 * null strings, quoting and:             Quoting.             (line  62)
 * number sign (#), #! (executable scripts): Executable Scripts.
                                                               (line   6)
 * number sign (#), #! (executable scripts), portability issues with: 
Executable Scripts.
                                                               (line   6)
 * number sign (#), commenting:           Comments.            (line   6)
-* numbers:                               Internals.           (line  91)
+* numbers:                               Internals.           (line  82)
 * numbers, as array subscripts:          Numeric Array Subscripts.
                                                               (line   6)
 * numbers, as values of characters:      Ordinal Functions.   (line   6)
@@ -26661,7 +26649,7 @@ Index
                                                               (line  36)
 * P1003.1 POSIX standard:                Glossary.            (line 454)
 * P1003.2 POSIX standard:                Glossary.            (line 454)
-* parameters, number of:                 Internals.           (line  49)
+* parameters, number of:                 Internals.           (line  42)
 * parentheses ():                        Regexp Operators.    (line  79)
 * parentheses (), pgawk program:         Profiling.           (line 141)
 * password file:                         Passwd Functions.    (line  16)
@@ -26767,7 +26755,7 @@ Index
 * POSIX awk, field separators and:       Fields.              (line   6)
 * POSIX awk, FS variable and:            User-modified.       (line  66)
 * POSIX awk, function keyword in:        Definition Syntax.   (line  83)
-* POSIX awk, functions and, gsub()/sub(): Gory Details.       (line  54)
+* POSIX awk, functions and, gsub()/sub(): Gory Details.       (line  53)
 * POSIX awk, functions and, length():    String Functions.    (line 175)
 * POSIX awk, GNU long options and:       Options.             (line  15)
 * POSIX awk, interval expressions in:    Regexp Operators.    (line 135)
@@ -26825,7 +26813,7 @@ Index
 * private variables:                     Library Names.       (line  11)
 * processes, two-way communications with: Two-way I/O.        (line  23)
 * processing data:                       Basic High Level.    (line   6)
-* PROCINFO array <1>:                    Internals.           (line 149)
+* PROCINFO array <1>:                    Internals.           (line 140)
 * PROCINFO array <2>:                    Id Program.          (line  15)
 * PROCINFO array <3>:                    Group Functions.     (line   6)
 * PROCINFO array <4>:                    Passwd Functions.    (line   6)
@@ -26921,8 +26909,8 @@ Index
 * regexp constants, slashes vs. quotes:  Computed Regexps.    (line  28)
 * regexp constants, vs. string constants: Computed Regexps.   (line  38)
 * regexp, See regular expressions:       Regexp.              (line   6)
-* register_deferred_variable() internal function: Internals.  (line 149)
-* register_open_hook() internal function: Internals.          (line 160)
+* register_deferred_variable() internal function: Internals.  (line 140)
+* register_open_hook() internal function: Internals.          (line 151)
 * regular expressions:                   Regexp.              (line   6)
 * regular expressions as field separators: Field Separators.  (line  50)
 * regular expressions, anchors in:       Regexp Operators.    (line  22)
@@ -27148,8 +27136,8 @@ Index
                                                               (line  68)
 * stepi debugger command:                Dgawk Execution Control.
                                                               (line  76)
-* stlen internal variable:               Internals.           (line  53)
-* stptr internal variable:               Internals.           (line  53)
+* stlen internal variable:               Internals.           (line  46)
+* stptr internal variable:               Internals.           (line  46)
 * stream editors <1>:                    Simple Sed.          (line   6)
 * stream editors:                        Field Splitting Summary.
                                                               (line  47)
@@ -27160,7 +27148,7 @@ Index
                                                               (line   6)
 * string operators:                      Concatenation.       (line   9)
 * string-matching operators:             Regexp Usage.        (line  19)
-* strings:                               Internals.           (line  86)
+* strings:                               Internals.           (line  77)
 * strings, converting <1>:               Bitwise Functions.   (line 107)
 * strings, converting:                   Conversion.          (line   6)
 * strings, converting, numbers to:       User-modified.       (line  28)
@@ -27290,7 +27278,7 @@ Index
 * trunc-mod operation:                   Arithmetic Ops.      (line  66)
 * truth values:                          Truth Values.        (line   6)
 * type conversion:                       Conversion.          (line  21)
-* type internal variable:                Internals.           (line  66)
+* type internal variable:                Internals.           (line  59)
 * u debugger command (alias for until):  Dgawk Execution Control.
                                                               (line  83)
 * undefined functions:                   Pass By Value/Reference.
@@ -27316,15 +27304,15 @@ Index
                                                               (line  72)
 * Unix, awk scripts and:                 Executable Scripts.  (line   6)
 * UNIXROOT variable, on OS/2 systems:    PC Using.            (line  17)
-* unref() internal function:             Internals.           (line 101)
+* unref() internal function:             Internals.           (line  92)
 * unsigned integers:                     Basic Data Typing.   (line  30)
 * until debugger command:                Dgawk Execution Control.
                                                               (line  83)
 * unwatch debugger command:              Viewing And Changing Data.
                                                               (line  84)
 * up debugger command:                   Dgawk Stack.         (line  33)
-* update_ERRNO() internal function:      Internals.           (line 139)
-* update_ERRNO_saved() internal function: Internals.          (line 144)
+* update_ERRNO() internal function:      Internals.           (line 130)
+* update_ERRNO_saved() internal function: Internals.          (line 135)
 * user database, reading:                Passwd Functions.    (line   6)
 * user-defined, functions:               User-defined.        (line   6)
 * user-defined, functions, counts:       Profiling.           (line 132)
@@ -27375,7 +27363,7 @@ Index
 * vertical bar (|), || operator <1>:     Precedence.          (line  89)
 * vertical bar (|), || operator:         Boolean Ops.         (line  57)
 * Vinschen, Corinna:                     Acknowledgments.     (line  60)
-* vname internal variable:               Internals.           (line  71)
+* vname internal variable:               Internals.           (line  64)
 * w debugger command (alias for watch):  Viewing And Changing Data.
                                                               (line  67)
 * w utility:                             Constant Size.       (line  22)
@@ -27409,11 +27397,11 @@ Index
 * words, counting:                       Wc Program.          (line   6)
 * words, duplicate, searching for:       Dupword Program.     (line   6)
 * words, usage counts, generating:       Word Sorting.        (line   6)
-* wstlen internal variable:              Internals.           (line  61)
-* wstptr internal variable:              Internals.           (line  61)
+* wstlen internal variable:              Internals.           (line  54)
+* wstptr internal variable:              Internals.           (line  54)
 * xgawk:                                 Other Versions.      (line 119)
 * xgettext utility:                      String Extraction.   (line  13)
-* XML (eXtensible Markup Language):      Internals.           (line 160)
+* XML (eXtensible Markup Language):      Internals.           (line 151)
 * XOR bitwise operation:                 Bitwise Functions.   (line   6)
 * xor() function (gawk):                 Bitwise Functions.   (line  54)
 * Yawitz, Efraim:                        Contributors.        (line 106)
@@ -27450,418 +27438,418 @@ Index
 
 
 Tag Table:
-Node: Top1346
-Node: Foreword33440
-Node: Preface37785
-Ref: Preface-Footnote-140838
-Ref: Preface-Footnote-240944
-Node: History41176
-Node: Names43567
-Ref: Names-Footnote-145044
-Node: This Manual45116
-Ref: This Manual-Footnote-150063
-Node: Conventions50163
-Node: Manual History52297
-Ref: Manual History-Footnote-155567
-Ref: Manual History-Footnote-255608
-Node: How To Contribute55682
-Node: Acknowledgments56826
-Node: Getting Started61157
-Node: Running gawk63536
-Node: One-shot64722
-Node: Read Terminal65947
-Ref: Read Terminal-Footnote-167597
-Ref: Read Terminal-Footnote-267873
-Node: Long68044
-Node: Executable Scripts69420
-Ref: Executable Scripts-Footnote-171289
-Ref: Executable Scripts-Footnote-271391
-Node: Comments71842
-Node: Quoting74309
-Node: DOS Quoting78932
-Node: Sample Data Files79607
-Node: Very Simple82639
-Node: Two Rules87238
-Node: More Complex89385
-Ref: More Complex-Footnote-192315
-Node: Statements/Lines92400
-Ref: Statements/Lines-Footnote-196862
-Node: Other Features97127
-Node: When98055
-Node: Invoking Gawk100202
-Node: Command Line101587
-Node: Options102370
-Ref: Options-Footnote-1115807
-Node: Other Arguments115832
-Node: Naming Standard Input118490
-Node: Environment Variables119584
-Node: AWKPATH Variable120028
-Ref: AWKPATH Variable-Footnote-1122625
-Node: Other Environment Variables122885
-Node: Exit Status125225
-Node: Include Files125900
-Node: Obsolete129385
-Node: Undocumented130071
-Node: Regexp130312
-Node: Regexp Usage131701
-Node: Escape Sequences133727
-Node: Regexp Operators139490
-Ref: Regexp Operators-Footnote-1146687
-Ref: Regexp Operators-Footnote-2146834
-Node: Bracket Expressions146932
-Ref: table-char-classes148822
-Node: GNU Regexp Operators151345
-Node: Case-sensitivity155068
-Ref: Case-sensitivity-Footnote-1158036
-Ref: Case-sensitivity-Footnote-2158271
-Node: Leftmost Longest158379
-Node: Computed Regexps159580
-Node: Reading Files162990
-Node: Records164931
-Ref: Records-Footnote-1173605
-Node: Fields173642
-Ref: Fields-Footnote-1176675
-Node: Nonconstant Fields176761
-Node: Changing Fields178963
-Node: Field Separators184941
-Node: Default Field Splitting187570
-Node: Regexp Field Splitting188687
-Node: Single Character Fields192029
-Node: Command Line Field Separator193088
-Node: Field Splitting Summary196529
-Ref: Field Splitting Summary-Footnote-1199721
-Node: Constant Size199822
-Node: Splitting By Content204406
-Ref: Splitting By Content-Footnote-1208132
-Node: Multiple Line208172
-Ref: Multiple Line-Footnote-1214019
-Node: Getline214198
-Node: Plain Getline216426
-Node: Getline/Variable218515
-Node: Getline/File219656
-Node: Getline/Variable/File220978
-Ref: Getline/Variable/File-Footnote-1222577
-Node: Getline/Pipe222664
-Node: Getline/Variable/Pipe225224
-Node: Getline/Coprocess226331
-Node: Getline/Variable/Coprocess227574
-Node: Getline Notes228288
-Node: Getline Summary230230
-Ref: table-getline-variants230573
-Node: Command line directories231429
-Node: Printing232054
-Node: Print233685
-Node: Print Examples235022
-Node: Output Separators237806
-Node: OFMT239566
-Node: Printf240924
-Node: Basic Printf241830
-Node: Control Letters243369
-Node: Format Modifiers247181
-Node: Printf Examples253190
-Node: Redirection255905
-Node: Special Files262889
-Node: Special FD263422
-Ref: Special FD-Footnote-1267047
-Node: Special Network267121
-Node: Special Caveats267971
-Node: Close Files And Pipes268767
-Ref: Close Files And Pipes-Footnote-1275790
-Ref: Close Files And Pipes-Footnote-2275938
-Node: Expressions276088
-Node: Values277220
-Node: Constants277896
-Node: Scalar Constants278576
-Ref: Scalar Constants-Footnote-1279435
-Node: Nondecimal-numbers279617
-Node: Regexp Constants282676
-Node: Using Constant Regexps283151
-Node: Variables286206
-Node: Using Variables286861
-Node: Assignment Options288585
-Node: Conversion290457
-Ref: table-locale-affects295833
-Ref: Conversion-Footnote-1296457
-Node: All Operators296566
-Node: Arithmetic Ops297196
-Node: Concatenation299701
-Ref: Concatenation-Footnote-1302494
-Node: Assignment Ops302614
-Ref: table-assign-ops307602
-Node: Increment Ops309010
-Node: Truth Values and Conditions312480
-Node: Truth Values313563
-Node: Typing and Comparison314612
-Node: Variable Typing315401
-Ref: Variable Typing-Footnote-1319298
-Node: Comparison Operators319420
-Ref: table-relational-ops319830
-Node: POSIX String Comparison323379
-Ref: POSIX String Comparison-Footnote-1324335
-Node: Boolean Ops324473
-Ref: Boolean Ops-Footnote-1328551
-Node: Conditional Exp328642
-Node: Function Calls330374
-Node: Precedence333968
-Node: Locales337637
-Node: Patterns and Actions338726
-Node: Pattern Overview339780
-Node: Regexp Patterns341446
-Node: Expression Patterns341989
-Node: Ranges345674
-Node: BEGIN/END348640
-Node: Using BEGIN/END349402
-Ref: Using BEGIN/END-Footnote-1352133
-Node: I/O And BEGIN/END352239
-Node: BEGINFILE/ENDFILE354521
-Node: Empty357414
-Node: Using Shell Variables357730
-Node: Action Overview360015
-Node: Statements362372
-Node: If Statement364226
-Node: While Statement365725
-Node: Do Statement367769
-Node: For Statement368925
-Node: Switch Statement372077
-Node: Break Statement374174
-Node: Continue Statement376164
-Node: Next Statement377951
-Node: Nextfile Statement380341
-Node: Exit Statement382886
-Node: Built-in Variables385302
-Node: User-modified386397
-Ref: User-modified-Footnote-1394423
-Node: Auto-set394485
-Ref: Auto-set-Footnote-1403776
-Node: ARGC and ARGV403981
-Node: Arrays407832
-Node: Array Basics409337
-Node: Array Intro410048
-Node: Reference to Elements414366
-Node: Assigning Elements416636
-Node: Array Example417127
-Node: Scanning an Array418859
-Node: Delete421525
-Ref: Delete-Footnote-1423960
-Node: Numeric Array Subscripts424017
-Node: Uninitialized Subscripts426200
-Node: Multi-dimensional427828
-Node: Multi-scanning430922
-Node: Arrays of Arrays432506
-Node: Functions437083
-Node: Built-in437905
-Node: Calling Built-in438983
-Node: Numeric Functions440971
-Ref: Numeric Functions-Footnote-1444736
-Ref: Numeric Functions-Footnote-2445093
-Ref: Numeric Functions-Footnote-3445141
-Node: String Functions445410
-Ref: String Functions-Footnote-1468907
-Ref: String Functions-Footnote-2469036
-Ref: String Functions-Footnote-3469284
-Node: Gory Details469371
-Ref: table-sub-escapes471050
-Ref: table-sub-posix-92472404
-Ref: table-sub-proposed473747
-Ref: table-posix-sub475097
-Ref: table-gensub-escapes476643
-Ref: Gory Details-Footnote-1477850
-Ref: Gory Details-Footnote-2477901
-Node: I/O Functions478052
-Ref: I/O Functions-Footnote-1484707
-Node: Time Functions484854
-Ref: Time Functions-Footnote-1495746
-Ref: Time Functions-Footnote-2495814
-Ref: Time Functions-Footnote-3495972
-Ref: Time Functions-Footnote-4496083
-Ref: Time Functions-Footnote-5496195
-Ref: Time Functions-Footnote-6496422
-Node: Bitwise Functions496688
-Ref: table-bitwise-ops497246
-Ref: Bitwise Functions-Footnote-1501406
-Node: Type Functions501590
-Node: I18N Functions502060
-Node: User-defined503687
-Node: Definition Syntax504491
-Ref: Definition Syntax-Footnote-1509401
-Node: Function Example509470
-Node: Function Caveats512064
-Node: Calling A Function512485
-Node: Variable Scope513600
-Node: Pass By Value/Reference515575
-Node: Return Statement519015
-Node: Dynamic Typing521996
-Node: Indirect Calls522731
-Node: Internationalization532416
-Node: I18N and L10N533842
-Node: Explaining gettext534528
-Ref: Explaining gettext-Footnote-1539594
-Ref: Explaining gettext-Footnote-2539778
-Node: Programmer i18n539943
-Node: Translator i18n544143
-Node: String Extraction544936
-Ref: String Extraction-Footnote-1545897
-Node: Printf Ordering545983
-Ref: Printf Ordering-Footnote-1548767
-Node: I18N Portability548831
-Ref: I18N Portability-Footnote-1551280
-Node: I18N Example551343
-Ref: I18N Example-Footnote-1553978
-Node: Gawk I18N554050
-Node: Advanced Features554667
-Node: Nondecimal Data556180
-Node: Array Sorting557763
-Node: Controlling Array Traversal558463
-Node: Controlling Scanning With A Function559210
-Node: Controlling Scanning566913
-Ref: Controlling Scanning-Footnote-1570714
-Node: Array Sorting Functions571030
-Ref: Array Sorting Functions-Footnote-1574546
-Ref: Array Sorting Functions-Footnote-2574639
-Node: Two-way I/O574833
-Ref: Two-way I/O-Footnote-1580265
-Node: TCP/IP Networking580335
-Node: Profiling583179
-Node: Library Functions590653
-Ref: Library Functions-Footnote-1593660
-Node: Library Names593831
-Ref: Library Names-Footnote-1597302
-Ref: Library Names-Footnote-2597522
-Node: General Functions597608
-Node: Strtonum Function598561
-Node: Assert Function601491
-Node: Round Function604817
-Node: Cliff Random Function606360
-Node: Ordinal Functions607376
-Ref: Ordinal Functions-Footnote-1610446
-Ref: Ordinal Functions-Footnote-2610698
-Node: Join Function610907
-Ref: Join Function-Footnote-1612678
-Node: Gettimeofday Function612878
-Node: Data File Management616593
-Node: Filetrans Function617225
-Node: Rewind Function621364
-Node: File Checking622751
-Node: Empty Files623845
-Node: Ignoring Assigns626075
-Node: Getopt Function627628
-Ref: Getopt Function-Footnote-1638932
-Node: Passwd Functions639135
-Ref: Passwd Functions-Footnote-1648110
-Node: Group Functions648198
-Node: Walking Arrays656282
-Node: Sample Programs657851
-Node: Running Examples658516
-Node: Clones659244
-Node: Cut Program660468
-Node: Egrep Program670313
-Ref: Egrep Program-Footnote-1678086
-Node: Id Program678196
-Node: Split Program681812
-Ref: Split Program-Footnote-1685331
-Node: Tee Program685459
-Node: Uniq Program688262
-Node: Wc Program695691
-Ref: Wc Program-Footnote-1699957
-Ref: Wc Program-Footnote-2700157
-Node: Miscellaneous Programs700249
-Node: Dupword Program701437
-Node: Alarm Program703468
-Node: Translate Program708217
-Ref: Translate Program-Footnote-1712604
-Ref: Translate Program-Footnote-2712832
-Node: Labels Program712966
-Ref: Labels Program-Footnote-1716337
-Node: Word Sorting716421
-Node: History Sorting720305
-Node: Extract Program722144
-Ref: Extract Program-Footnote-1729627
-Node: Simple Sed729755
-Node: Igawk Program732817
-Ref: Igawk Program-Footnote-1747974
-Ref: Igawk Program-Footnote-2748175
-Node: Anagram Program748313
-Node: Signature Program751381
-Node: Debugger752481
-Node: Debugging753392
-Node: Debugging Concepts753805
-Node: Debugging Terms755661
-Node: Awk Debugging758284
-Node: Sample dgawk session759176
-Node: dgawk invocation759668
-Node: Finding The Bug760850
-Node: List of Debugger Commands767336
-Node: Breakpoint Control768647
-Node: Dgawk Execution Control772283
-Node: Viewing And Changing Data775634
-Node: Dgawk Stack778971
-Node: Dgawk Info780431
-Node: Miscellaneous Dgawk Commands784379
-Node: Readline Support789807
-Node: Dgawk Limitations790645
-Node: Language History792834
-Node: V7/SVR3.1794346
-Node: SVR4796667
-Node: POSIX798109
-Node: BTL799117
-Node: POSIX/GNU799851
-Node: Common Extensions805002
-Node: Ranges and Locales806109
-Ref: Ranges and Locales-Footnote-1810716
-Node: Contributors810937
-Node: Installation815199
-Node: Gawk Distribution816093
-Node: Getting816577
-Node: Extracting817403
-Node: Distribution contents819095
-Node: Unix Installation824317
-Node: Quick Installation824934
-Node: Additional Configuration Options826896
-Node: Configuration Philosophy828373
-Node: Non-Unix Installation830715
-Node: PC Installation831173
-Node: PC Binary Installation832472
-Node: PC Compiling834320
-Node: PC Testing837264
-Node: PC Using838440
-Node: Cygwin842625
-Node: MSYS843625
-Node: VMS Installation844139
-Node: VMS Compilation844742
-Ref: VMS Compilation-Footnote-1845749
-Node: VMS Installation Details845807
-Node: VMS Running847442
-Node: VMS Old Gawk849049
-Node: Bugs849523
-Node: Other Versions853376
-Node: Notes858657
-Node: Compatibility Mode859349
-Node: Additions860132
-Node: Accessing The Source860944
-Node: Adding Code862369
-Node: New Ports868336
-Node: Dynamic Extensions872449
-Node: Internals873825
-Node: Plugin License882928
-Node: Sample Library883562
-Node: Internal File Description884248
-Node: Internal File Ops887963
-Ref: Internal File Ops-Footnote-1892744
-Node: Using Internal File Ops892884
-Node: Future Extensions895261
-Node: Basic Concepts897765
-Node: Basic High Level898522
-Ref: Basic High Level-Footnote-1902557
-Node: Basic Data Typing902742
-Node: Floating Point Issues907267
-Node: String Conversion Precision908350
-Ref: String Conversion Precision-Footnote-1910050
-Node: Unexpected Results910159
-Node: POSIX Floating Point Problems911985
-Ref: POSIX Floating Point Problems-Footnote-1915690
-Node: Glossary915728
-Node: Copying940704
-Node: GNU Free Documentation License978261
-Node: Index1003398
+Node: Top1345
+Node: Foreword33439
+Node: Preface37784
+Ref: Preface-Footnote-140837
+Ref: Preface-Footnote-240943
+Node: History41175
+Node: Names43566
+Ref: Names-Footnote-145043
+Node: This Manual45115
+Ref: This Manual-Footnote-150062
+Node: Conventions50162
+Node: Manual History52296
+Ref: Manual History-Footnote-155566
+Ref: Manual History-Footnote-255607
+Node: How To Contribute55681
+Node: Acknowledgments56825
+Node: Getting Started61156
+Node: Running gawk63535
+Node: One-shot64721
+Node: Read Terminal65946
+Ref: Read Terminal-Footnote-167596
+Ref: Read Terminal-Footnote-267872
+Node: Long68043
+Node: Executable Scripts69419
+Ref: Executable Scripts-Footnote-171288
+Ref: Executable Scripts-Footnote-271390
+Node: Comments71841
+Node: Quoting74308
+Node: DOS Quoting78931
+Node: Sample Data Files79606
+Node: Very Simple82638
+Node: Two Rules87237
+Node: More Complex89384
+Ref: More Complex-Footnote-192314
+Node: Statements/Lines92399
+Ref: Statements/Lines-Footnote-196861
+Node: Other Features97126
+Node: When98054
+Node: Invoking Gawk100201
+Node: Command Line101586
+Node: Options102369
+Ref: Options-Footnote-1115806
+Node: Other Arguments115831
+Node: Naming Standard Input118489
+Node: Environment Variables119583
+Node: AWKPATH Variable120027
+Ref: AWKPATH Variable-Footnote-1122624
+Node: Other Environment Variables122884
+Node: Exit Status125224
+Node: Include Files125899
+Node: Obsolete129384
+Node: Undocumented130070
+Node: Regexp130311
+Node: Regexp Usage131700
+Node: Escape Sequences133726
+Node: Regexp Operators139489
+Ref: Regexp Operators-Footnote-1146686
+Ref: Regexp Operators-Footnote-2146833
+Node: Bracket Expressions146931
+Ref: table-char-classes148821
+Node: GNU Regexp Operators151344
+Node: Case-sensitivity155067
+Ref: Case-sensitivity-Footnote-1158035
+Ref: Case-sensitivity-Footnote-2158270
+Node: Leftmost Longest158378
+Node: Computed Regexps159579
+Node: Reading Files162989
+Node: Records164930
+Ref: Records-Footnote-1173604
+Node: Fields173641
+Ref: Fields-Footnote-1176674
+Node: Nonconstant Fields176760
+Node: Changing Fields178962
+Node: Field Separators184940
+Node: Default Field Splitting187569
+Node: Regexp Field Splitting188686
+Node: Single Character Fields192028
+Node: Command Line Field Separator193087
+Node: Field Splitting Summary196528
+Ref: Field Splitting Summary-Footnote-1199720
+Node: Constant Size199821
+Node: Splitting By Content204405
+Ref: Splitting By Content-Footnote-1208131
+Node: Multiple Line208171
+Ref: Multiple Line-Footnote-1214018
+Node: Getline214197
+Node: Plain Getline216425
+Node: Getline/Variable218514
+Node: Getline/File219655
+Node: Getline/Variable/File220977
+Ref: Getline/Variable/File-Footnote-1222576
+Node: Getline/Pipe222663
+Node: Getline/Variable/Pipe225223
+Node: Getline/Coprocess226330
+Node: Getline/Variable/Coprocess227573
+Node: Getline Notes228287
+Node: Getline Summary230229
+Ref: table-getline-variants230572
+Node: Command line directories231428
+Node: Printing232053
+Node: Print233684
+Node: Print Examples235021
+Node: Output Separators237805
+Node: OFMT239565
+Node: Printf240923
+Node: Basic Printf241829
+Node: Control Letters243368
+Node: Format Modifiers247180
+Node: Printf Examples253189
+Node: Redirection255904
+Node: Special Files262888
+Node: Special FD263421
+Ref: Special FD-Footnote-1267046
+Node: Special Network267120
+Node: Special Caveats267970
+Node: Close Files And Pipes268766
+Ref: Close Files And Pipes-Footnote-1275789
+Ref: Close Files And Pipes-Footnote-2275937
+Node: Expressions276087
+Node: Values277219
+Node: Constants277895
+Node: Scalar Constants278575
+Ref: Scalar Constants-Footnote-1279434
+Node: Nondecimal-numbers279616
+Node: Regexp Constants282675
+Node: Using Constant Regexps283150
+Node: Variables286205
+Node: Using Variables286860
+Node: Assignment Options288584
+Node: Conversion290456
+Ref: table-locale-affects295832
+Ref: Conversion-Footnote-1296456
+Node: All Operators296565
+Node: Arithmetic Ops297195
+Node: Concatenation299700
+Ref: Concatenation-Footnote-1302493
+Node: Assignment Ops302613
+Ref: table-assign-ops307601
+Node: Increment Ops309009
+Node: Truth Values and Conditions312479
+Node: Truth Values313562
+Node: Typing and Comparison314611
+Node: Variable Typing315400
+Ref: Variable Typing-Footnote-1319297
+Node: Comparison Operators319419
+Ref: table-relational-ops319829
+Node: POSIX String Comparison323378
+Ref: POSIX String Comparison-Footnote-1324334
+Node: Boolean Ops324472
+Ref: Boolean Ops-Footnote-1328550
+Node: Conditional Exp328641
+Node: Function Calls330373
+Node: Precedence333967
+Node: Locales337636
+Node: Patterns and Actions338725
+Node: Pattern Overview339779
+Node: Regexp Patterns341445
+Node: Expression Patterns341988
+Node: Ranges345673
+Node: BEGIN/END348639
+Node: Using BEGIN/END349401
+Ref: Using BEGIN/END-Footnote-1352132
+Node: I/O And BEGIN/END352238
+Node: BEGINFILE/ENDFILE354520
+Node: Empty357413
+Node: Using Shell Variables357729
+Node: Action Overview360014
+Node: Statements362371
+Node: If Statement364225
+Node: While Statement365724
+Node: Do Statement367768
+Node: For Statement368924
+Node: Switch Statement372076
+Node: Break Statement374173
+Node: Continue Statement376163
+Node: Next Statement377950
+Node: Nextfile Statement380340
+Node: Exit Statement382885
+Node: Built-in Variables385301
+Node: User-modified386396
+Ref: User-modified-Footnote-1394422
+Node: Auto-set394484
+Ref: Auto-set-Footnote-1403775
+Node: ARGC and ARGV403980
+Node: Arrays407831
+Node: Array Basics409336
+Node: Array Intro410047
+Node: Reference to Elements414365
+Node: Assigning Elements416635
+Node: Array Example417126
+Node: Scanning an Array418858
+Node: Delete421524
+Ref: Delete-Footnote-1423959
+Node: Numeric Array Subscripts424016
+Node: Uninitialized Subscripts426199
+Node: Multi-dimensional427827
+Node: Multi-scanning430921
+Node: Arrays of Arrays432505
+Node: Functions437082
+Node: Built-in437904
+Node: Calling Built-in438982
+Node: Numeric Functions440970
+Ref: Numeric Functions-Footnote-1444735
+Ref: Numeric Functions-Footnote-2445092
+Ref: Numeric Functions-Footnote-3445140
+Node: String Functions445409
+Ref: String Functions-Footnote-1468906
+Ref: String Functions-Footnote-2469035
+Ref: String Functions-Footnote-3469283
+Node: Gory Details469370
+Ref: table-sub-escapes471049
+Ref: table-sub-posix-92472403
+Ref: table-sub-proposed473746
+Ref: table-posix-sub475096
+Ref: table-gensub-escapes476642
+Ref: Gory Details-Footnote-1477849
+Ref: Gory Details-Footnote-2477900
+Node: I/O Functions478051
+Ref: I/O Functions-Footnote-1484706
+Node: Time Functions484853
+Ref: Time Functions-Footnote-1495745
+Ref: Time Functions-Footnote-2495813
+Ref: Time Functions-Footnote-3495971
+Ref: Time Functions-Footnote-4496082
+Ref: Time Functions-Footnote-5496194
+Ref: Time Functions-Footnote-6496421
+Node: Bitwise Functions496687
+Ref: table-bitwise-ops497245
+Ref: Bitwise Functions-Footnote-1501405
+Node: Type Functions501589
+Node: I18N Functions502059
+Node: User-defined503686
+Node: Definition Syntax504490
+Ref: Definition Syntax-Footnote-1509400
+Node: Function Example509469
+Node: Function Caveats512063
+Node: Calling A Function512484
+Node: Variable Scope513599
+Node: Pass By Value/Reference515574
+Node: Return Statement519014
+Node: Dynamic Typing521995
+Node: Indirect Calls522730
+Node: Internationalization532415
+Node: I18N and L10N533841
+Node: Explaining gettext534527
+Ref: Explaining gettext-Footnote-1539593
+Ref: Explaining gettext-Footnote-2539777
+Node: Programmer i18n539942
+Node: Translator i18n544142
+Node: String Extraction544935
+Ref: String Extraction-Footnote-1545896
+Node: Printf Ordering545982
+Ref: Printf Ordering-Footnote-1548766
+Node: I18N Portability548830
+Ref: I18N Portability-Footnote-1551279
+Node: I18N Example551342
+Ref: I18N Example-Footnote-1553977
+Node: Gawk I18N554049
+Node: Advanced Features554666
+Node: Nondecimal Data556179
+Node: Array Sorting557762
+Node: Controlling Array Traversal558462
+Node: Controlling Scanning With A Function559209
+Node: Controlling Scanning566912
+Ref: Controlling Scanning-Footnote-1570713
+Node: Array Sorting Functions571029
+Ref: Array Sorting Functions-Footnote-1574545
+Ref: Array Sorting Functions-Footnote-2574638
+Node: Two-way I/O574832
+Ref: Two-way I/O-Footnote-1580264
+Node: TCP/IP Networking580334
+Node: Profiling583178
+Node: Library Functions590652
+Ref: Library Functions-Footnote-1593659
+Node: Library Names593830
+Ref: Library Names-Footnote-1597301
+Ref: Library Names-Footnote-2597521
+Node: General Functions597607
+Node: Strtonum Function598560
+Node: Assert Function601490
+Node: Round Function604816
+Node: Cliff Random Function606359
+Node: Ordinal Functions607375
+Ref: Ordinal Functions-Footnote-1610445
+Ref: Ordinal Functions-Footnote-2610697
+Node: Join Function610906
+Ref: Join Function-Footnote-1612677
+Node: Gettimeofday Function612877
+Node: Data File Management616592
+Node: Filetrans Function617224
+Node: Rewind Function621363
+Node: File Checking622750
+Node: Empty Files623844
+Node: Ignoring Assigns626074
+Node: Getopt Function627627
+Ref: Getopt Function-Footnote-1638931
+Node: Passwd Functions639134
+Ref: Passwd Functions-Footnote-1648109
+Node: Group Functions648197
+Node: Walking Arrays656281
+Node: Sample Programs657850
+Node: Running Examples658515
+Node: Clones659243
+Node: Cut Program660467
+Node: Egrep Program670312
+Ref: Egrep Program-Footnote-1678085
+Node: Id Program678195
+Node: Split Program681811
+Ref: Split Program-Footnote-1685330
+Node: Tee Program685458
+Node: Uniq Program688261
+Node: Wc Program695690
+Ref: Wc Program-Footnote-1699956
+Ref: Wc Program-Footnote-2700156
+Node: Miscellaneous Programs700248
+Node: Dupword Program701436
+Node: Alarm Program703467
+Node: Translate Program708216
+Ref: Translate Program-Footnote-1712603
+Ref: Translate Program-Footnote-2712831
+Node: Labels Program712965
+Ref: Labels Program-Footnote-1716336
+Node: Word Sorting716420
+Node: History Sorting720304
+Node: Extract Program722143
+Ref: Extract Program-Footnote-1729626
+Node: Simple Sed729754
+Node: Igawk Program732816
+Ref: Igawk Program-Footnote-1747973
+Ref: Igawk Program-Footnote-2748174
+Node: Anagram Program748312
+Node: Signature Program751380
+Node: Debugger752480
+Node: Debugging753391
+Node: Debugging Concepts753804
+Node: Debugging Terms755660
+Node: Awk Debugging758283
+Node: Sample dgawk session759175
+Node: dgawk invocation759667
+Node: Finding The Bug760849
+Node: List of Debugger Commands767335
+Node: Breakpoint Control768646
+Node: Dgawk Execution Control772282
+Node: Viewing And Changing Data775633
+Node: Dgawk Stack778970
+Node: Dgawk Info780430
+Node: Miscellaneous Dgawk Commands784378
+Node: Readline Support789806
+Node: Dgawk Limitations790644
+Node: Language History792833
+Node: V7/SVR3.1794345
+Node: SVR4796666
+Node: POSIX798108
+Node: BTL799116
+Node: POSIX/GNU799850
+Node: Common Extensions805001
+Node: Ranges and Locales806108
+Ref: Ranges and Locales-Footnote-1810715
+Node: Contributors810936
+Node: Installation815198
+Node: Gawk Distribution816092
+Node: Getting816576
+Node: Extracting817402
+Node: Distribution contents819094
+Node: Unix Installation824316
+Node: Quick Installation824933
+Node: Additional Configuration Options826895
+Node: Configuration Philosophy828372
+Node: Non-Unix Installation830714
+Node: PC Installation831172
+Node: PC Binary Installation832471
+Node: PC Compiling834319
+Node: PC Testing837263
+Node: PC Using838439
+Node: Cygwin842624
+Node: MSYS843624
+Node: VMS Installation844138
+Node: VMS Compilation844741
+Ref: VMS Compilation-Footnote-1845748
+Node: VMS Installation Details845806
+Node: VMS Running847441
+Node: VMS Old Gawk849048
+Node: Bugs849522
+Node: Other Versions853375
+Node: Notes858656
+Node: Compatibility Mode859348
+Node: Additions860131
+Node: Accessing The Source860943
+Node: Adding Code862368
+Node: New Ports868335
+Node: Dynamic Extensions872448
+Node: Internals873824
+Node: Plugin License882343
+Node: Sample Library882977
+Node: Internal File Description883663
+Node: Internal File Ops887378
+Ref: Internal File Ops-Footnote-1892102
+Node: Using Internal File Ops892242
+Node: Future Extensions894619
+Node: Basic Concepts897123
+Node: Basic High Level897880
+Ref: Basic High Level-Footnote-1901915
+Node: Basic Data Typing902100
+Node: Floating Point Issues906625
+Node: String Conversion Precision907708
+Ref: String Conversion Precision-Footnote-1909408
+Node: Unexpected Results909517
+Node: POSIX Floating Point Problems911343
+Ref: POSIX Floating Point Problems-Footnote-1915048
+Node: Glossary915086
+Node: Copying940062
+Node: GNU Free Documentation License977619
+Node: Index1002756
 
 End Tag Table
diff --git a/doc/gawk.texi b/doc/gawk.texi
index 930f934..1770350 100644
--- a/doc/gawk.texi
+++ b/doc/gawk.texi
@@ -29140,22 +29140,12 @@ macro guarantees that a @code{NODE}'s wide-string 
value is current.
 It may end up calling an internal @command{gawk} function.
 It also guarantees that the wide string is zero-terminated.
 
address@hidden @code{get_curfunc_arg_count()} internal function
address@hidden internal function, @code{get_curfunc_arg_count()}
address@hidden size_t get_curfunc_arg_count(void)
-This function returns the actual number of parameters passed
-to the current function.  Inside the code of an extension
-this can be used to determine the maximum index which is
-safe to use with @code{get_actual_argument}.  If this value is
-greater than @code{nargs}, the function was
-called incorrectly from the @command{awk} program.
-
 @cindex address@hidden number of
 @cindex @code{nargs} internal variable
 @cindex internal variable, @code{nargs}
 @item nargs
-Inside an extension function, this is the maximum number of
-expected parameters, as set by the @code{make_builtin()} function.
+Inside an extension function, this is the actual number of
+parameters passed to the current function.
 
 @cindex @code{stptr} internal variable
 @cindex internal variable, @code{stptr}
@@ -29201,13 +29191,10 @@ Make sure that @samp{n->type == Node_var_array} first.
 @cindex arrays, elements, installing
 @cindex @code{assoc_lookup()} internal function
 @cindex internal function, @code{assoc_lookup()}
address@hidden NODE **assoc_lookup(NODE *symbol, NODE *subs, int reference)
address@hidden NODE **assoc_lookup(NODE *symbol, NODE *subs)
 Finds, and installs if necessary, array elements.
 @code{symbol} is the array, @code{subs} is the subscript.
 This is usually a value created with @code{make_string()} (see below).
address@hidden should be @code{TRUE} if it is an error to use the
-value before it is created. Typically, @code{FALSE} is the
-correct value to use from extension functions.
 
 @cindex strings
 @cindex @code{make_string()} internal function
@@ -29591,7 +29578,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);
@@ -29664,7 +29651,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");
 @end example
 
@@ -29698,15 +29685,15 @@ calls are shown here, since they all follow the same 
pattern:
 
 @example
     /* 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("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("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);
diff --git a/eval.c b/eval.c
index e5e0738..47b6ca1 100644
--- a/eval.c
+++ b/eval.c
@@ -1999,32 +1999,32 @@ top:
                        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;
 
@@ -2226,7 +2226,7 @@ mod:
                                memcpy(p, t1->stptr, t1->stlen);
                                memcpy(p + t1->stlen, t2->stptr, t2->stlen);
                                unref(*lhs);
-                               t1 = *lhs = make_str_node(p, nlen); 
+                               t1 = *lhs = make_str_node(p, nlen, 
ALREADY_MALLOCED); 
                        }
                        DEREF(t2);
                        break;
@@ -2332,11 +2332,6 @@ mod:
                        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;
diff --git a/extension/ChangeLog b/extension/ChangeLog
index 8aaeb41..dff4cf6 100644
--- a/extension/ChangeLog
+++ b/extension/ChangeLog
@@ -1,3 +1,7 @@
+2011-08-31         John Haque     <address@hidden>
+        * arrayparm.c, filefuncs.c, fork.c, ordchr.c, readfile.c,
+        rwarray.c, testarg.c: Updated.
+
 2011-06-23         Arnold D. Robbins     <address@hidden>
 
        * ChangeLog.0: Rotated ChangeLog into this file.
diff --git a/field.c b/field.c
index af987fa..91789d2 100644
--- a/field.c
+++ b/field.c
@@ -185,7 +185,7 @@ rebuild_record()
                        }
                }
        }
-       tmp = make_str_node(ops, tlen);
+       tmp = make_str_node(ops, tlen, ALREADY_MALLOCED);
 
        /*
         * Since we are about to unref fields_arr[0], we want to find
diff --git a/int_array.c b/int_array.c
index 913e154..7bbfb58 100644
--- a/int_array.c
+++ b/int_array.c
@@ -663,35 +663,28 @@ static uint32_t
 int_hash(uint32_t k, uint32_t hsize)
 {
 
-/*
- * Bob Jenkins
- * http://burtleburtle.net/bob/hash/integer.html
+/* Code snippet copied from:
+ *     Hash functions (http://www.azillionmonkeys.com/qed/hash.html).
+ *     Copyright 2004-2008 by Paul Hsieh. Licenced under LGPL 2.1.
  */
 
-#if 0
-       /* 6-shifts vs 7-shifts below */
-       k = (k+0x7ed55d16) + (k<<12);
-       k = (k^0xc761c23c) ^ (k>>19);
-       k = (k+0x165667b1) + (k<<5);
-       k = (k+0xd3a2646c) ^ (k<<9);
-       k = (k+0xfd7046c5) + (k<<3);
-       k = (k^0xb55a4f09) ^ (k>>16);
-#endif
-
-       k -= (k << 6);
-       k ^= (k >> 17);
-       k -= (k << 9);
-       k ^= (k << 4);
-       k -= (k << 3);
-       k ^= (k << 10);
-       k ^= (k >> 15);
+       /* This is the final mixing function used by Paul Hsieh
+        * in SuperFastHash.
+        */
+ 
+       k ^= k << 3;
+       k += k >> 5;
+       k ^= k << 4;
+       k += k >> 17;
+       k ^= k << 25;
+       k += k >> 6;
 
        if (k >= hsize)
                k %= hsize;
        return k;
 }
 
-/* assoc_find --- locate symbol[subs] */
+/* int_find --- locate symbol[subs] */
 
 static inline NODE **
 int_find(NODE *symbol, long k, uint32_t hash1)
diff --git a/main.c b/main.c
index 71699fd..6b24a80 100644
--- a/main.c
+++ b/main.c
@@ -827,7 +827,6 @@ static void
 cmdline_fs(char *str)
 {
        NODE **tmp;
-       size_t len;
 
        tmp = &FS_node->var_value;
        unref(*tmp);
@@ -845,8 +844,7 @@ cmdline_fs(char *str)
                        str[0] = '\t';
        }
 
-       len = scan_escape(str, strlen(str)); /* do process escapes */
-       *tmp = make_string(str, len);
+       *tmp = make_str_node(str, strlen(str), SCAN); /* do process escapes */
        set_FS();
 }
 
@@ -1137,7 +1135,6 @@ int
 arg_assign(char *arg, int initing)
 {
        char *cp, *cp2;
-       size_t cplen;
        int badvar;
        NODE *var;
        NODE *it;
@@ -1199,8 +1196,7 @@ arg_assign(char *arg, int initing)
                 * BWK awk expands escapes inside assignments.
                 * This makes sense, so we do it too.
                 */
-               cplen = scan_escape(cp, strlen(cp));
-               it = make_string(cp, cplen);
+               it = make_str_node(cp, strlen(cp), SCAN);
                it->flags |= MAYBE_NUM;
 #ifdef LC_NUMERIC
                /*
diff --git a/node.c b/node.c
index a16c9e0..73d3ec4 100644
--- a/node.c
+++ b/node.c
@@ -340,29 +340,77 @@ make_number(AWKNUM x)
 /* r_make_str_node --- make a string node */
 
 NODE *
-r_make_str_node(const char *s, size_t len, int already_malloced)
+r_make_str_node(const char *s, size_t len, int flags)
 {
        NODE *r;
-
        getnode(r);
        r->type = Node_val;
+       r->numbr = 0;
        r->flags = (MALLOC|STRING|STRCUR);
        r->valref = 1;
-       r->numbr = 0;
        r->stfmt = -1;
-       r->stlen = len;
+
 #if MBS_SUPPORT
        r->wstptr = NULL;
        r->wstlen = 0;
 #endif /* MBS_SUPPORT */
 
-       if (already_malloced)
+       if (flags & ALREADY_MALLOCED)
                r->stptr = (char *) s;
        else {
-               emalloc(r->stptr, char *, len + 2, "make_string");
+               emalloc(r->stptr, char *, len + 2, "r_make_str_node");
                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;
+#if 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;) {
+#if 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, "r_make_str_node");
+               r->stptr[len] = '\0';
+       }
+       r->stlen = len;
 
        return r;
 }
@@ -529,61 +577,6 @@ 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;
-#if MBS_SUPPORT
-       mbstate_t cur_state;
-
-       memset(& cur_state, 0, sizeof(cur_state));
-#endif
-
-       end = & s[len];
-       for (pf = ptm = s; pf < end;) {
-#if 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
diff --git a/symbol.h b/symbol.h
deleted file mode 100644
index d5c2d85..0000000
--- a/symbol.h
+++ /dev/null
@@ -1,6 +0,0 @@
-extern NODE *install_symbol(char *name, NODETYPE type);
-extern NODE *lookup(const char *name);
-extern void install_params(NODE *paramtab, int pcount);
-extern void remove_params(NODE *paramtab, int pcount);
-extern NODE *remove_symbol(char *name);
-extern void destroy_symbol(char *name);
diff --git a/test/fnarray2.in b/test/fnarray2.in
new file mode 100644
index 0000000..587be6b
--- /dev/null
+++ b/test/fnarray2.in
@@ -0,0 +1 @@
+x

http://git.sv.gnu.org/cgit/gawk.git/commit/?id=1fea520248b42ca995c8797698c60301ea42ffe9

commit 1fea520248b42ca995c8797698c60301ea42ffe9
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 13ba6bd..946d730 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -82,6 +82,7 @@ base_sources = \
        awk.h \
        awkgram.y \
        builtin.c \
+       cint_array.c \
        custom.h \
        dfa.c \
        dfa.h \
@@ -95,6 +96,7 @@ base_sources = \
        getopt1.c \
        getopt_int.h \
        gettext.h \
+       int_array.c \
        io.c \
        mbsupport.h \
        main.c \
@@ -107,6 +109,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 958b4a1..de8769b 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)
@@ -357,6 +359,7 @@ base_sources = \
        awk.h \
        awkgram.y \
        builtin.c \
+       cint_array.c \
        custom.h \
        dfa.c \
        dfa.h \
@@ -370,6 +373,7 @@ base_sources = \
        getopt1.c \
        getopt_int.h \
        gettext.h \
+       int_array.c \
        io.c \
        mbsupport.h \
        main.c \
@@ -382,6 +386,8 @@ base_sources = \
        regex.c \
        regex.h \
        replace.c \
+       str_array.c \
+       symbol.c \
        version.c \
        xalloc.h
 
@@ -514,6 +520,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@
@@ -526,6 +533,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@
@@ -536,6 +544,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 82e99a4..91b8757 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 0c95472..a942f8c 100644
--- a/awk.h
+++ b/awk.h
@@ -256,10 +256,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[];
 
@@ -278,10 +277,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,
@@ -291,9 +293,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.
@@ -305,13 +342,15 @@ typedef struct exp_node {
                                struct exp_node *lptr;
                                struct exp_instruction *li;
                                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 *ri;
+                               struct exp_instruction *iptr;
                        } r;
                        union {
                                struct exp_node *extra;
@@ -320,16 +359,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;
@@ -339,76 +381,79 @@ 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
-#define code_ptr    sub.nodep.r.ri
+/* 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
@@ -416,20 +461,41 @@ typedef struct exp_node {
 #define reti         sub.nodep.l.li
 
 /* Node_var: */
-#define var_value lnode
+#define var_value    lnode
 #define var_update   sub.nodep.r.uptr
 #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,
@@ -527,6 +593,7 @@ typedef enum opcodeval {
 
        Op_builtin,
        Op_sub_builtin,         /* sub, gsub and gensub */
+       Op_ext_builtin,
        Op_in_array,            /* boolean test of membership in array */
 
        /* function call instruction */
@@ -559,7 +626,6 @@ typedef enum opcodeval {
        Op_after_beginfile,
        Op_after_endfile,
 
-       Op_ext_func,
        Op_func,
 
        Op_exec_count,
@@ -660,6 +726,8 @@ typedef struct exp_instruction {
 
 /* Op_token */
 #define lextok          d.name
+#define param_count     x.xl
+
 
 /* Op_rule */
 #define in_rule         x.xl
@@ -668,11 +736,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
@@ -732,9 +800,9 @@ typedef struct exp_instruction {
 #define assign_ctxt    d.dl    
 
 /* 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
@@ -764,6 +832,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 */
@@ -856,7 +928,7 @@ typedef struct context {
        SRCFILE srcfiles;
        int sourceline;
        char *source;
-       void (*install_func)(char *);
+       void (*install_func)(NODE *);
        struct context *prev;
 } AWK_CONTEXT;
 
@@ -866,6 +938,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
@@ -906,21 +992,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;
@@ -929,8 +1047,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
 #if MBS_SUPPORT
 extern int gawk_mb_cur_max;
@@ -967,7 +1085,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;
@@ -975,84 +1093,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)
@@ -1060,24 +1169,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__)
@@ -1094,19 +1199,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 */
 
@@ -1127,57 +1247,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);
@@ -1227,7 +1356,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);
@@ -1259,7 +1388,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)
@@ -1323,6 +1451,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);
@@ -1350,13 +1479,13 @@ 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);
 #if MBS_SUPPORT
 extern NODE *str2wstr(NODE *n, size_t **ptr);
 extern NODE *wstr2str(NODE *n);
@@ -1386,6 +1515,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 7a06667..ba9a904 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,   781,   788,   795,   805,
-     814,   823,   832,   847,   863,   862,   874,   886,   886,   982,
-     982,  1007,  1030,  1036,  1037,  1043,  1044,  1051,  1056,  1068,
-    1082,  1084,  1090,  1095,  1097,  1105,  1107,  1116,  1117,  1125,
-    1130,  1130,  1141,  1145,  1153,  1154,  1157,  1159,  1164,  1165,
-    1172,  1174,  1178,  1184,  1191,  1193,  1195,  1202,  1203,  1209,
-    1210,  1215,  1217,  1222,  1224,  1226,  1228,  1234,  1241,  1243,
-    1245,  1261,  1271,  1278,  1280,  1285,  1287,  1289,  1297,  1299,
-    1304,  1306,  1311,  1313,  1315,  1368,  1370,  1372,  1374,  1376,
-    1378,  1380,  1382,  1405,  1410,  1415,  1440,  1446,  1448,  1450,
-    1452,  1454,  1456,  1461,  1465,  1496,  1498,  1504,  1510,  1523,
-    1524,  1525,  1530,  1535,  1539,  1543,  1555,  1568,  1573,  1609,
-    1627,  1628,  1634,  1635,  1640,  1642,  1649,  1666,  1683,  1685,
-    1692,  1697,  1705,  1719,  1731,  1740,  1744,  1748,  1752,  1756,
-    1760,  1763,  1765,  1769,  1773,  1777
+       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,   737,   744,   751,   761,   770,
+     779,   788,   803,   819,   818,   830,   842,   842,   936,   936,
+     961,   984,   990,   991,   997,   998,  1005,  1010,  1022,  1036,
+    1038,  1044,  1049,  1051,  1059,  1061,  1070,  1071,  1079,  1084,
+    1084,  1095,  1099,  1107,  1108,  1111,  1113,  1118,  1119,  1128,
+    1129,  1134,  1139,  1145,  1147,  1149,  1156,  1157,  1163,  1164,
+    1169,  1171,  1176,  1178,  1180,  1182,  1188,  1195,  1197,  1199,
+    1215,  1225,  1232,  1234,  1239,  1241,  1243,  1251,  1253,  1258,
+    1260,  1265,  1267,  1269,  1319,  1321,  1323,  1325,  1327,  1329,
+    1331,  1333,  1356,  1361,  1366,  1391,  1397,  1399,  1401,  1403,
+    1405,  1407,  1412,  1416,  1447,  1449,  1455,  1461,  1474,  1475,
+    1476,  1481,  1486,  1490,  1494,  1507,  1520,  1525,  1561,  1579,
+    1580,  1586,  1587,  1592,  1594,  1601,  1618,  1635,  1637,  1644,
+    1649,  1657,  1667,  1679,  1688,  1692,  1696,  1700,  1704,  1708,
+    1711,  1713,  1717,  1721,  1725
 };
 #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;
@@ -2763,10 +2714,10 @@ regular_loop:
          }
     break;
 
-  case 46:
+  case 45:
 
-/* Line 1806 of yacc.c  */
-#line 782 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 738 "awkgram.y"
     {
                (yyval) = mk_for_loop((yyvsp[(1) - (12)]), (yyvsp[(3) - (12)]), 
(yyvsp[(6) - (12)]), (yyvsp[(9) - (12)]), (yyvsp[(12) - (12)]));
 
@@ -2775,10 +2726,10 @@ regular_loop:
          }
     break;
 
-  case 47:
+  case 46:
 
-/* Line 1806 of yacc.c  */
-#line 789 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 745 "awkgram.y"
     {
                (yyval) = mk_for_loop((yyvsp[(1) - (11)]), (yyvsp[(3) - (11)]), 
(INSTRUCTION *) NULL, (yyvsp[(8) - (11)]), (yyvsp[(11) - (11)]));
 
@@ -2787,10 +2738,10 @@ regular_loop:
          }
     break;
 
-  case 48:
+  case 47:
 
-/* Line 1806 of yacc.c  */
-#line 796 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 752 "awkgram.y"
     {
                if (do_profiling)
                        (yyval) = list_prepend((yyvsp[(1) - (1)]), 
instruction(Op_exec_count));
@@ -2799,10 +2750,10 @@ regular_loop:
          }
     break;
 
-  case 49:
+  case 48:
 
-/* Line 1806 of yacc.c  */
-#line 806 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 762 "awkgram.y"
     { 
                if (! break_allowed)
                        error_ln((yyvsp[(1) - (2)])->source_line,
@@ -2813,10 +2764,10 @@ regular_loop:
          }
     break;
 
-  case 50:
+  case 49:
 
-/* Line 1806 of yacc.c  */
-#line 815 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 771 "awkgram.y"
     {
                if (! continue_allowed)
                        error_ln((yyvsp[(1) - (2)])->source_line,
@@ -2827,10 +2778,10 @@ regular_loop:
          }
     break;
 
-  case 51:
+  case 50:
 
-/* Line 1806 of yacc.c  */
-#line 824 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 780 "awkgram.y"
     {
                /* if inside function (rule = 0), resolve context at run-time */
                if (rule && rule != Rule)
@@ -2841,10 +2792,10 @@ regular_loop:
          }
     break;
 
-  case 52:
+  case 51:
 
-/* Line 1806 of yacc.c  */
-#line 833 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 789 "awkgram.y"
     {
                if (do_traditional)
                        error_ln((yyvsp[(1) - (2)])->source_line,
@@ -2861,10 +2812,10 @@ regular_loop:
          }
     break;
 
-  case 53:
+  case 52:
 
-/* Line 1806 of yacc.c  */
-#line 848 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 804 "awkgram.y"
     {
                /* Initialize the two possible jump targets, the actual target
                 * is resolved at run-time. 
@@ -2875,47 +2826,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 863 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 819 "awkgram.y"
     {
                if (! can_return)
                        yyerror(_("`return' used outside function context"));
          }
     break;
 
-  case 55:
+  case 54:
 
-/* Line 1806 of yacc.c  */
-#line 866 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 822 "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 886 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 842 "awkgram.y"
     { in_print = TRUE; in_parens = 0; }
     break;
 
-  case 58:
+  case 57:
 
-/* Line 1806 of yacc.c  */
-#line 887 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 843 "awkgram.y"
     {
                /*
                 * Optimization: plain `print' has no expression list, so $3 is 
null.
@@ -2924,13 +2875,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;
                        /*   -----------------
@@ -2944,8 +2895,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 */
@@ -3012,22 +2961,22 @@ regular_loop:
          }
     break;
 
-  case 59:
+  case 58:
 
-/* Line 1806 of yacc.c  */
-#line 982 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 936 "awkgram.y"
     { sub_counter = 0; }
     break;
 
-  case 60:
+  case 59:
 
-/* Line 1806 of yacc.c  */
-#line 983 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 937 "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;
@@ -3049,10 +2998,10 @@ regular_loop:
          }
     break;
 
-  case 61:
+  case 60:
 
-/* Line 1806 of yacc.c  */
-#line 1012 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 966 "awkgram.y"
     {
                static short warned = FALSE;
                char *arr = (yyvsp[(3) - (4)])->lextok;
@@ -3066,45 +3015,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 1031 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 985 "awkgram.y"
     {  (yyval) = optimize_assignment((yyvsp[(1) - (1)])); }
     break;
 
-  case 63:
+  case 62:
 
-/* Line 1806 of yacc.c  */
-#line 1036 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 990 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
-  case 64:
+  case 63:
 
-/* Line 1806 of yacc.c  */
-#line 1038 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 992 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
-  case 65:
+  case 64:
 
-/* Line 1806 of yacc.c  */
-#line 1043 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 997 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
-  case 66:
+  case 65:
 
-/* Line 1806 of yacc.c  */
-#line 1045 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 999 "awkgram.y"
     {
                if ((yyvsp[(1) - (2)]) == NULL)
                        (yyval) = list_create((yyvsp[(2) - (2)]));
@@ -3113,17 +3062,17 @@ regular_loop:
          }
     break;
 
-  case 67:
+  case 66:
 
-/* Line 1806 of yacc.c  */
-#line 1052 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1006 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
-  case 68:
+  case 67:
 
-/* Line 1806 of yacc.c  */
-#line 1057 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1011 "awkgram.y"
     {
                INSTRUCTION *casestmt = (yyvsp[(5) - (5)]);
                if ((yyvsp[(5) - (5)]) == NULL)
@@ -3137,10 +3086,10 @@ regular_loop:
          }
     break;
 
-  case 69:
+  case 68:
 
-/* Line 1806 of yacc.c  */
-#line 1069 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1023 "awkgram.y"
     {
                INSTRUCTION *casestmt = (yyvsp[(4) - (4)]);
                if ((yyvsp[(4) - (4)]) == NULL)
@@ -3153,17 +3102,17 @@ regular_loop:
          }
     break;
 
-  case 70:
+  case 69:
 
-/* Line 1806 of yacc.c  */
-#line 1083 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1037 "awkgram.y"
     {  (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
-  case 71:
+  case 70:
 
-/* Line 1806 of yacc.c  */
-#line 1085 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1039 "awkgram.y"
     { 
                (yyvsp[(2) - (2)])->memory->numbr = -(force_number((yyvsp[(2) - 
(2)])->memory));
                bcfree((yyvsp[(1) - (2)]));
@@ -3171,60 +3120,60 @@ regular_loop:
          }
     break;
 
-  case 72:
+  case 71:
 
-/* Line 1806 of yacc.c  */
-#line 1091 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1045 "awkgram.y"
     {
                bcfree((yyvsp[(1) - (2)]));
                (yyval) = (yyvsp[(2) - (2)]);
          }
     break;
 
-  case 73:
+  case 72:
 
-/* Line 1806 of yacc.c  */
-#line 1096 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1050 "awkgram.y"
     {  (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
-  case 74:
+  case 73:
 
-/* Line 1806 of yacc.c  */
-#line 1098 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1052 "awkgram.y"
     {
                (yyvsp[(1) - (1)])->opcode = Op_push_re;
                (yyval) = (yyvsp[(1) - (1)]);
          }
     break;
 
-  case 75:
+  case 74:
 
-/* Line 1806 of yacc.c  */
-#line 1106 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1060 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
-  case 76:
+  case 75:
 
-/* Line 1806 of yacc.c  */
-#line 1108 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1062 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
-  case 78:
+  case 77:
 
-/* Line 1806 of yacc.c  */
-#line 1118 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1072 "awkgram.y"
     {
                (yyval) = (yyvsp[(2) - (3)]);
          }
     break;
 
-  case 79:
+  case 78:
 
-/* Line 1806 of yacc.c  */
-#line 1125 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1079 "awkgram.y"
     {
                in_print = FALSE;
                in_parens = 0;
@@ -3232,17 +3181,17 @@ regular_loop:
          }
     break;
 
-  case 80:
+  case 79:
 
-/* Line 1806 of yacc.c  */
-#line 1130 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1084 "awkgram.y"
     { in_print = FALSE; in_parens = 0; }
     break;
 
-  case 81:
+  case 80:
 
-/* Line 1806 of yacc.c  */
-#line 1131 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1085 "awkgram.y"
     {
                if ((yyvsp[(1) - (3)])->redir_type == redirect_twoway
                        && (yyvsp[(3) - (3)])->lasti->opcode == 
Op_K_getline_redir
@@ -3252,162 +3201,174 @@ regular_loop:
          }
     break;
 
-  case 82:
+  case 81:
 
-/* Line 1806 of yacc.c  */
-#line 1142 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1096 "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 1147 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1101 "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 1164 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1118 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
-  case 89:
+  case 88:
 
-/* Line 1806 of yacc.c  */
-#line 1166 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1120 "awkgram.y"
     {
                bcfree((yyvsp[(1) - (2)]));
                (yyval) = (yyvsp[(2) - (2)]);
          }
     break;
 
-  case 92:
+  case 89:
 
-/* Line 1806 of yacc.c  */
-#line 1179 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1128 "awkgram.y"
+    { (yyval) = NULL; }
+    break;
+
+  case 90:
+
+/* Line 1821 of yacc.c  */
+#line 1130 "awkgram.y"
+    { (yyval) = (yyvsp[(1) - (1)]) ; }
+    break;
+
+  case 91:
+
+/* Line 1821 of yacc.c  */
+#line 1135 "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 1185 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1140 "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 1192 "awkgram.y"
-    { /* func_params = NULL; */ }
+/* Line 1821 of yacc.c  */
+#line 1146 "awkgram.y"
+    { (yyval) = NULL; }
     break;
 
-  case 95:
+  case 94:
 
-/* Line 1806 of yacc.c  */
-#line 1194 "awkgram.y"
-    { /* func_params = NULL; */ }
+/* Line 1821 of yacc.c  */
+#line 1148 "awkgram.y"
+    { (yyval) = (yyvsp[(1) - (2)]); }
     break;
 
-  case 96:
+  case 95:
 
-/* Line 1806 of yacc.c  */
-#line 1196 "awkgram.y"
-    { /* func_params = NULL; */ }
+/* Line 1821 of yacc.c  */
+#line 1150 "awkgram.y"
+    { (yyval) = (yyvsp[(1) - (3)]); }
     break;
 
-  case 97:
+  case 96:
 
-/* Line 1806 of yacc.c  */
-#line 1202 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1156 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
-  case 98:
+  case 97:
 
-/* Line 1806 of yacc.c  */
-#line 1204 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1158 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
-  case 99:
+  case 98:
 
-/* Line 1806 of yacc.c  */
-#line 1209 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1163 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
-  case 100:
+  case 99:
 
-/* Line 1806 of yacc.c  */
-#line 1211 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1165 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
-  case 101:
+  case 100:
 
-/* Line 1806 of yacc.c  */
-#line 1216 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1170 "awkgram.y"
     {  (yyval) = mk_expression_list(NULL, (yyvsp[(1) - (1)])); }
     break;
 
-  case 102:
+  case 101:
 
-/* Line 1806 of yacc.c  */
-#line 1218 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1172 "awkgram.y"
     {
                (yyval) = mk_expression_list((yyvsp[(1) - (3)]), (yyvsp[(3) - 
(3)]));
                yyerrok;
          }
     break;
 
-  case 103:
+  case 102:
 
-/* Line 1806 of yacc.c  */
-#line 1223 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1177 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
-  case 104:
+  case 103:
 
-/* Line 1806 of yacc.c  */
-#line 1225 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1179 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
-  case 105:
+  case 104:
 
-/* Line 1806 of yacc.c  */
-#line 1227 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1181 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
-  case 106:
+  case 105:
 
-/* Line 1806 of yacc.c  */
-#line 1229 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1183 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
-  case 107:
+  case 106:
 
-/* Line 1806 of yacc.c  */
-#line 1235 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1189 "awkgram.y"
     {
                if (do_lint && (yyvsp[(3) - (3)])->lasti->opcode == 
Op_match_rec)
                        lintwarn_ln((yyvsp[(2) - (3)])->source_line,
@@ -3416,24 +3377,24 @@ regular_loop:
          }
     break;
 
-  case 108:
+  case 107:
 
-/* Line 1806 of yacc.c  */
-#line 1242 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1196 "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 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 110:
+  case 109:
 
-/* Line 1806 of yacc.c  */
-#line 1246 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1200 "awkgram.y"
     {
                if ((yyvsp[(1) - (3)])->lasti->opcode == Op_match_rec)
                        warning_ln((yyvsp[(2) - (3)])->source_line,
@@ -3451,13 +3412,13 @@ regular_loop:
          }
     break;
 
-  case 111:
+  case 110:
 
-/* Line 1806 of yacc.c  */
-#line 1262 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1216 "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;
@@ -3466,10 +3427,10 @@ regular_loop:
          }
     break;
 
-  case 112:
+  case 111:
 
-/* Line 1806 of yacc.c  */
-#line 1272 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1226 "awkgram.y"
     {
                if (do_lint && (yyvsp[(3) - (3)])->lasti->opcode == 
Op_match_rec)
                        lintwarn_ln((yyvsp[(2) - (3)])->source_line,
@@ -3478,90 +3439,90 @@ regular_loop:
          }
     break;
 
-  case 113:
+  case 112:
 
-/* Line 1806 of yacc.c  */
-#line 1279 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1233 "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 1281 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1235 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
-  case 115:
+  case 114:
 
-/* Line 1806 of yacc.c  */
-#line 1286 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1240 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
-  case 116:
+  case 115:
 
-/* Line 1806 of yacc.c  */
-#line 1288 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1242 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
-  case 117:
+  case 116:
 
-/* Line 1806 of yacc.c  */
-#line 1290 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1244 "awkgram.y"
     {  
                (yyvsp[(2) - (2)])->opcode = Op_assign_quotient;
                (yyval) = (yyvsp[(2) - (2)]);
          }
     break;
 
+  case 117:
+
+/* Line 1821 of yacc.c  */
+#line 1252 "awkgram.y"
+    { (yyval) = (yyvsp[(1) - (1)]); }
+    break;
+
   case 118:
 
-/* Line 1806 of yacc.c  */
-#line 1298 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1254 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 119:
 
-/* Line 1806 of yacc.c  */
-#line 1300 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1259 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 120:
 
-/* Line 1806 of yacc.c  */
-#line 1305 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1261 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 121:
 
-/* Line 1806 of yacc.c  */
-#line 1307 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1266 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 122:
 
-/* Line 1806 of yacc.c  */
-#line 1312 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1268 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 123:
 
-/* Line 1806 of yacc.c  */
-#line 1314 "awkgram.y"
-    { (yyval) = (yyvsp[(1) - (1)]); }
-    break;
-
-  case 124:
-
-/* Line 1806 of yacc.c  */
-#line 1316 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1270 "awkgram.y"
     {
                int count = 2;
                int is_simple_var = FALSE;
@@ -3573,32 +3534,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)]));
@@ -3613,52 +3571,52 @@ regular_loop:
          }
     break;
 
+  case 125:
+
+/* Line 1821 of yacc.c  */
+#line 1322 "awkgram.y"
+    { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - 
(3)])); }
+    break;
+
   case 126:
 
-/* Line 1806 of yacc.c  */
-#line 1371 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1324 "awkgram.y"
     { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - 
(3)])); }
     break;
 
   case 127:
 
-/* 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 128:
 
-/* 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 129:
 
-/* 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 130:
 
-/* 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 131:
 
-/* Line 1806 of yacc.c  */
-#line 1381 "awkgram.y"
-    { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - 
(3)])); }
-    break;
-
-  case 132:
-
-/* Line 1806 of yacc.c  */
-#line 1383 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1334 "awkgram.y"
     {
                /*
                 * In BEGINFILE/ENDFILE, allow `getline var < file'
@@ -3683,30 +3641,30 @@ regular_loop:
          }
     break;
 
-  case 133:
+  case 132:
 
-/* Line 1806 of yacc.c  */
-#line 1406 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1357 "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 1411 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1362 "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 1416 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1367 "awkgram.y"
     {
                if (do_lint_old) {
                    warning_ln((yyvsp[(4) - (5)])->source_line,
@@ -3728,81 +3686,81 @@ regular_loop:
          }
     break;
 
-  case 136:
+  case 135:
 
-/* Line 1806 of yacc.c  */
-#line 1441 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1392 "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 1398 "awkgram.y"
+    { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - 
(3)])); }
+    break;
+
   case 137:
 
-/* Line 1806 of yacc.c  */
-#line 1447 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1400 "awkgram.y"
     { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - 
(3)])); }
     break;
 
   case 138:
 
-/* 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 139:
 
-/* 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 140:
 
-/* 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 141:
 
-/* 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 142:
 
-/* Line 1806 of yacc.c  */
-#line 1457 "awkgram.y"
-    { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - 
(3)])); }
-    break;
-
-  case 143:
-
-/* Line 1806 of yacc.c  */
-#line 1462 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1413 "awkgram.y"
     {
                (yyval) = list_create((yyvsp[(1) - (1)]));
          }
     break;
 
-  case 144:
+  case 143:
 
-/* Line 1806 of yacc.c  */
-#line 1466 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1417 "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) {
@@ -3825,17 +3783,17 @@ regular_loop:
           }
     break;
 
-  case 145:
+  case 144:
 
-/* Line 1806 of yacc.c  */
-#line 1497 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1448 "awkgram.y"
     { (yyval) = (yyvsp[(2) - (3)]); }
     break;
 
-  case 146:
+  case 145:
 
-/* Line 1806 of yacc.c  */
-#line 1499 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1450 "awkgram.y"
     {
                (yyval) = snode((yyvsp[(3) - (4)]), (yyvsp[(1) - (4)]));
                if ((yyval) == NULL)
@@ -3843,10 +3801,10 @@ regular_loop:
          }
     break;
 
-  case 147:
+  case 146:
 
-/* Line 1806 of yacc.c  */
-#line 1505 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1456 "awkgram.y"
     {
                (yyval) = snode((yyvsp[(3) - (4)]), (yyvsp[(1) - (4)]));
                if ((yyval) == NULL)
@@ -3854,10 +3812,10 @@ regular_loop:
          }
     break;
 
-  case 148:
+  case 147:
 
-/* Line 1806 of yacc.c  */
-#line 1511 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1462 "awkgram.y"
     {
                static short warned1 = FALSE;
 
@@ -3872,51 +3830,52 @@ regular_loop:
          }
     break;
 
-  case 151:
+  case 150:
 
-/* Line 1806 of yacc.c  */
-#line 1526 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1477 "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 1531 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1482 "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 1536 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1487 "awkgram.y"
     {
                (yyval) = list_create((yyvsp[(1) - (1)]));
          }
     break;
 
-  case 154:
+  case 153:
 
-/* Line 1806 of yacc.c  */
-#line 1540 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1491 "awkgram.y"
     {
                (yyval) = list_create((yyvsp[(1) - (1)]));
          }
     break;
 
-  case 155:
+  case 154:
 
-/* Line 1806 of yacc.c  */
-#line 1544 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1495 "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)]));
@@ -3927,35 +3886,35 @@ regular_loop:
          }
     break;
 
-  case 156:
+  case 155:
 
-/* Line 1806 of yacc.c  */
-#line 1556 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1508 "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 1569 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1521 "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 1574 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1526 "awkgram.y"
     {
                /* indirect function call */
                INSTRUCTION *f, *t;
@@ -3976,7 +3935,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;
 
@@ -3990,10 +3949,10 @@ regular_loop:
          }
     break;
 
-  case 159:
+  case 158:
 
-/* Line 1806 of yacc.c  */
-#line 1610 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1562 "awkgram.y"
     {
                param_sanity((yyvsp[(3) - (4)]));
                (yyvsp[(1) - (4)])->opcode = Op_func_call;
@@ -4009,54 +3968,54 @@ regular_loop:
          }
     break;
 
-  case 160:
+  case 159:
 
-/* Line 1806 of yacc.c  */
-#line 1627 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1579 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
-  case 161:
+  case 160:
 
-/* Line 1806 of yacc.c  */
-#line 1629 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1581 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
-  case 162:
+  case 161:
 
-/* Line 1806 of yacc.c  */
-#line 1634 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1586 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
-  case 163:
+  case 162:
 
-/* Line 1806 of yacc.c  */
-#line 1636 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1588 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (2)]); }
     break;
 
-  case 164:
+  case 163:
 
-/* Line 1806 of yacc.c  */
-#line 1641 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1593 "awkgram.y"
     {  (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
-  case 165:
+  case 164:
 
-/* Line 1806 of yacc.c  */
-#line 1643 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1595 "awkgram.y"
     {
                (yyval) = list_merge((yyvsp[(1) - (2)]), (yyvsp[(2) - (2)]));
          }
     break;
 
-  case 166:
+  case 165:
 
-/* Line 1806 of yacc.c  */
-#line 1650 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1602 "awkgram.y"
     {
                INSTRUCTION *ip = (yyvsp[(1) - (1)])->lasti; 
                int count = ip->sub_count;      /* # of SUBSEP-seperated 
expressions */
@@ -4072,10 +4031,10 @@ regular_loop:
          }
     break;
 
-  case 167:
+  case 166:
 
-/* Line 1806 of yacc.c  */
-#line 1667 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1619 "awkgram.y"
     {
                INSTRUCTION *t = (yyvsp[(2) - (3)]);
                if ((yyvsp[(2) - (3)]) == NULL) {
@@ -4083,7 +4042,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);
@@ -4091,67 +4050,63 @@ regular_loop:
          }
     break;
 
-  case 168:
+  case 167:
 
-/* Line 1806 of yacc.c  */
-#line 1684 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1636 "awkgram.y"
     {  (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
-  case 169:
+  case 168:
 
-/* Line 1806 of yacc.c  */
-#line 1686 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1638 "awkgram.y"
     {
                (yyval) = list_merge((yyvsp[(1) - (2)]), (yyvsp[(2) - (2)]));
          }
     break;
 
-  case 170:
+  case 169:
 
-/* Line 1806 of yacc.c  */
-#line 1693 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1645 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (2)]); }
     break;
 
-  case 171:
+  case 170:
 
-/* Line 1806 of yacc.c  */
-#line 1698 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1650 "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 1706 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1658 "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 1720 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1668 "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->update_var = ip->memory->var_update;
@@ -4160,81 +4115,81 @@ regular_loop:
          }
     break;
 
-  case 174:
+  case 173:
 
-/* Line 1806 of yacc.c  */
-#line 1732 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1680 "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 1741 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1689 "awkgram.y"
     {
                (yyvsp[(1) - (1)])->opcode = Op_postincrement;
          }
     break;
 
-  case 176:
+  case 175:
 
-/* Line 1806 of yacc.c  */
-#line 1745 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1693 "awkgram.y"
     {
                (yyvsp[(1) - (1)])->opcode = Op_postdecrement;
          }
     break;
 
-  case 177:
+  case 176:
 
-/* Line 1806 of yacc.c  */
-#line 1748 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1696 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
-  case 179:
+  case 178:
 
-/* Line 1806 of yacc.c  */
-#line 1756 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1704 "awkgram.y"
     { yyerrok; }
     break;
 
-  case 180:
+  case 179:
 
-/* Line 1806 of yacc.c  */
-#line 1760 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1708 "awkgram.y"
     { yyerrok; }
     break;
 
-  case 183:
+  case 182:
 
-/* Line 1806 of yacc.c  */
-#line 1769 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1717 "awkgram.y"
     { yyerrok; }
     break;
 
-  case 184:
+  case 183:
 
-/* Line 1806 of yacc.c  */
-#line 1773 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1721 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); yyerrok; }
     break;
 
-  case 185:
+  case 184:
 
-/* Line 1806 of yacc.c  */
-#line 1777 "awkgram.y"
+/* Line 1821 of yacc.c  */
+#line 1725 "awkgram.y"
     { yyerrok; }
     break;
 
 
 
-/* Line 1806 of yacc.c  */
-#line 4250 "awkgram.c"
+/* Line 1821 of yacc.c  */
+#line 4205 "awkgram.c"
       default: break;
     }
   /* User semantic actions sometimes alter yychar, and that requires
@@ -4465,7 +4420,7 @@ yyreturn:
 
 
 /* Line 2067 of yacc.c  */
-#line 1779 "awkgram.y"
+#line 1727 "awkgram.y"
 
 
 struct token {
@@ -4513,9 +4468,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},
@@ -4568,9 +4526,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_sub_builtin,  LEX_BUILTIN,   NOT_OLD|A(2)|A(3), 0},
@@ -5094,6 +5049,7 @@ next_sourcefile()
         *
         * assert(lexeof == TRUE);
         */
+
        lexeof = FALSE;
        eof_warned = FALSE;
        sourcefile->srclines = sourceline;      /* total no of lines in current 
file */
@@ -5482,8 +5438,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)
 
@@ -5915,16 +5873,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;
@@ -6066,10 +6024,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 '&':
@@ -6246,23 +6206,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. */
 
@@ -6314,7 +6257,7 @@ snode(INSTRUCTION *subn, INSTRUCTION *r)
                                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)));
                        }
@@ -6358,7 +6301,7 @@ snode(INSTRUCTION *subn, INSTRUCTION *r)
                        r->sub_flags |= GENSUB;
                        if (nexp == 3) {
                                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)));
                        }
@@ -6381,7 +6324,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;
@@ -6509,7 +6452,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);
@@ -6520,75 +6463,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 */
 
@@ -6597,18 +6471,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;
@@ -6620,10 +6495,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;
                }
        }
@@ -6633,79 +6508,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");
@@ -6723,52 +6529,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 */
 
@@ -6776,6 +6536,7 @@ void
 dump_vars(const char *fname)
 {
        FILE *fp;
+       NODE **vars;
 
        if (fname == NULL)
                fp = stderr;
@@ -6785,48 +6546,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
@@ -6834,175 +6572,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;
+       NODE *thisfunc;
 
-       /* 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_use(thisfunc->vname, FUNC_DEFINE);
 
-       func_count++;   /* used in profiler / pretty printer */
-
-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");
+
+       for (i = 0, p = list->nexti; p != NULL; i++, p = np) {
+               np = p->nexti;
+               name = p->lextok;
+               p->lextok = NULL;
 
-       getnode(r);
-       r->type = Node_param_list;
-       r->rnode = NULL;
-       r->param_cnt = param_counter++;
-       return (install_symbol(name, r));
+               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;
@@ -7110,69 +6825,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. */
 
 /*
@@ -7207,17 +6859,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;
@@ -7227,11 +6876,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)();
@@ -7338,9 +6983,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:
@@ -7355,14 +6997,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
@@ -7412,27 +7046,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 *
@@ -7493,11 +7106,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);
@@ -7828,9 +7437,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;
@@ -7951,13 +7558,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;
@@ -8259,320 +7879,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 69f74ca..e2725a9 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;
@@ -855,7 +811,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);
          }
@@ -867,7 +823,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);
          }
@@ -892,13 +848,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;
                        /*   -----------------
@@ -912,8 +868,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 */
@@ -984,7 +938,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;
@@ -1022,7 +976,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);
@@ -1171,29 +1125,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 */
@@ -1261,7 +1215,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;
@@ -1324,32 +1278,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);
@@ -1467,12 +1418,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) {
@@ -1543,7 +1494,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);
@@ -1559,7 +1511,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);
          }
        ;
@@ -1591,7 +1543,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;
 
@@ -1671,7 +1623,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);
@@ -1699,17 +1651,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);
          }
@@ -1720,8 +1668,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->update_var = ip->memory->var_update;
@@ -1732,7 +1680,7 @@ variable
          {
                $$ = list_append($2, $1);
                if ($3 != NULL)
-                 mk_assignment($2, NULL, $3);
+                       mk_assignment($2, NULL, $3);
          }
        ;
 
@@ -1823,9 +1771,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},
@@ -1878,9 +1829,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_sub_builtin,  LEX_BUILTIN,   NOT_OLD|A(2)|A(3), 0},
@@ -2404,6 +2352,7 @@ next_sourcefile()
         *
         * assert(lexeof == TRUE);
         */
+
        lexeof = FALSE;
        eof_warned = FALSE;
        sourcefile->srclines = sourceline;      /* total no of lines in current 
file */
@@ -2792,8 +2741,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)
 
@@ -3225,16 +3176,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;
@@ -3376,10 +3327,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 '&':
@@ -3556,23 +3509,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. */
 
@@ -3624,7 +3560,7 @@ snode(INSTRUCTION *subn, INSTRUCTION *r)
                                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)));
                        }
@@ -3668,7 +3604,7 @@ snode(INSTRUCTION *subn, INSTRUCTION *r)
                        r->sub_flags |= GENSUB;
                        if (nexp == 3) {
                                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)));
                        }
@@ -3691,7 +3627,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;
@@ -3819,7 +3755,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);
@@ -3830,75 +3766,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 */
 
@@ -3907,18 +3774,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;
@@ -3930,10 +3798,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;
                }
        }
@@ -3943,79 +3811,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");
@@ -4033,52 +3832,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 */
 
@@ -4086,6 +3839,7 @@ void
 dump_vars(const char *fname)
 {
        FILE *fp;
+       NODE **vars;
 
        if (fname == NULL)
                fp = stderr;
@@ -4095,48 +3849,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
@@ -4144,175 +3875,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;
@@ -4420,69 +4128,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. */
 
 /*
@@ -4517,17 +4162,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;
@@ -4537,11 +4179,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)();
@@ -4648,9 +4286,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:
@@ -4665,14 +4300,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
@@ -4722,27 +4349,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 *
@@ -4803,11 +4409,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);
@@ -5138,9 +4740,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;
@@ -5261,13 +4861,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;
@@ -5569,320 +5182,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 53800fc..f5aa503 100644
--- a/builtin.c
+++ b/builtin.c
@@ -76,8 +76,10 @@ extern FILE *output_fp;
 #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)
 
 
 /*
@@ -330,8 +332,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;
@@ -498,7 +502,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);
 
 #if MBS_SUPPORT
        if (gawk_mb_cur_max > 1) {
@@ -1344,7 +1348,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:
        {
@@ -1381,7 +1385,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]);
@@ -1494,12 +1498,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)
@@ -1550,10 +1554,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 */
@@ -1570,7 +1574,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)
@@ -1608,7 +1612,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);
@@ -1667,7 +1671,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)
@@ -1679,6 +1683,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;
@@ -1761,13 +1766,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);
@@ -1828,11 +1833,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;
@@ -1840,7 +1843,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);
 
@@ -1861,12 +1864,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);
                }
@@ -2258,7 +2259,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);
@@ -2281,7 +2282,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);
@@ -2294,7 +2295,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);
@@ -2723,7 +2724,7 @@ done:
                if (matches > 0) {
                        /* return the result string */
                        DEREF(t);
-                       return make_str_node(buf, textlen, ALREADY_MALLOCED);   
+                       return make_str_node(buf, textlen);     
                }
 
                /* return the original string */
@@ -2735,7 +2736,7 @@ done:
                DEREF(t);
        else if (matches > 0) {
                unref(*lhs);
-               *lhs = make_str_node(buf, textlen, ALREADY_MALLOCED);   
+               *lhs = make_str_node(buf, textlen);     
        }
 
        return make_number((AWKNUM) matches);
diff --git a/cint_array.c b/cint_array.c
new file mode 100644
index 0000000..e7eb09f
--- /dev/null
+++ b/cint_array.c
@@ -0,0 +1,1225 @@
+/*
+ * cint_array.c - routines for arrays of (mostly) consecutive positive integer 
indices.
+ */
+
+/* 
+ * Copyright (C) 1986, 1988, 1989, 1991-2011 the Free Software Foundation, Inc.
+ * 
+ * This file is part of GAWK, the GNU implementation of the
+ * AWK Programming Language.
+ * 
+ * GAWK is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * GAWK is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
USA
+ */
+
+#include "awk.h"
+
+extern FILE *output_fp;
+extern void indent(int indent_level);
+extern NODE **is_integer(NODE *symbol, NODE *subs);
+
+/*
+ * NHAT         ---  maximum size of a leaf array (2^NHAT).
+ * THRESHOLD    ---  Maximum capacity waste; THRESHOLD >= 2^(NHAT + 1).
+ */
+
+static int NHAT = 10; 
+static long THRESHOLD;
+
+/* What is the optimium NHAT ? timing results suggest that 10 is a good choice,
+ * although differences aren't that significant for > 10.
+ */
+
+
+static NODE **cint_array_init(NODE *symbol, NODE *subs);
+static NODE **is_uinteger(NODE *symbol, NODE *subs);
+static NODE **cint_lookup(NODE *symbol, NODE *subs);
+static NODE **cint_exists(NODE *symbol, NODE *subs);
+static NODE **cint_clear(NODE *symbol, NODE *subs);
+static NODE **cint_remove(NODE *symbol, NODE *subs);
+static NODE **cint_list(NODE *symbol, NODE *t);
+static NODE **cint_copy(NODE *symbol, NODE *newsymb);
+static NODE **cint_dump(NODE *symbol, NODE *ndump);
+#ifdef ARRAYDEBUG
+static NODE **cint_option(NODE *opt, NODE *val);
+static void cint_print(NODE *symbol);
+#endif
+
+array_ptr cint_array_func[] = {
+       cint_array_init,
+       is_uinteger,
+       cint_lookup,
+       cint_exists,
+       cint_clear,
+       cint_remove,
+       cint_list,
+       cint_copy,
+       cint_dump,
+#ifdef ARRAYDEBUG
+       cint_option,
+#endif
+};
+
+static inline int cint_hash(long k);
+static inline NODE **cint_find(NODE *symbol, long k, int h1);
+
+static inline NODE *make_node(NODETYPE type);
+
+static NODE **tree_lookup(NODE *symbol, NODE *tree, long k, int m, long base);
+static NODE **tree_exists(NODE *tree, long k);
+static void tree_clear(NODE *tree);
+static int tree_remove(NODE *symbol, NODE *tree, long k);
+static void tree_copy(NODE *newsymb, NODE *tree, NODE *newtree);
+static long tree_list(NODE *tree, NODE **list, unsigned int flags);
+static inline NODE **tree_find(NODE *tree, long k, int i);
+static void tree_info(NODE *tree, NODE *ndump, const char *aname);
+static size_t tree_kilobytes(NODE *tree);
+#ifdef ARRAYDEBUG
+static void tree_print(NODE *tree, size_t bi, int indent_level);
+#endif
+
+static inline NODE **leaf_lookup(NODE *symbol, NODE *array, long k, long size, 
long base);
+static inline NODE **leaf_exists(NODE *array, long k);
+static void leaf_clear(NODE *array);
+static int leaf_remove(NODE *symbol, NODE *array, long k);
+static void leaf_copy(NODE *newsymb, NODE *array, NODE *newarray);
+static long leaf_list(NODE *array, NODE **list, unsigned int flags);
+static void leaf_info(NODE *array, NODE *ndump, const char *aname);
+#ifdef ARRAYDEBUG
+static void leaf_print(NODE *array, size_t bi, int indent_level);
+#endif
+
+/* powers of 2 table upto 2^30 */ 
+static const long power_two_table[] = {
+       1, 2, 4, 8, 16, 32, 64,
+       128, 256, 512, 1024, 2048, 4096,
+       8192, 16384, 32768, 65536, 131072, 262144,
+       524288, 1048576, 2097152, 4194304, 8388608, 16777216,
+       33554432, 67108864, 134217728, 268435456, 536870912, 1073741824
+};
+
+
+#define ISUINT(a, s)   ((((s)->flags & NUMINT) != 0 || is_integer(a, s) != 
NULL) \
+                                    && (s)->numbr >= 0)
+
+/*
+ * To store 2^n integers, allocate top-level array of size n, elements
+ * of which are 1-Dimensional (leaf-array) of geometrically increasing
+ * size (power of 2).   
+ *
+ *  [0]   -->  [ 0 ]
+ *  [1]   -->  [ 1 ]
+ *  |2|   -->  [ 2 | 3 ]
+ *  |3|   -->  [ 4 | 5 | 6 | 7 ]
+ *  |.|
+ *  |k|   -->  [ 2^(k - 1)| ...  | 2^k - 1 ]
+ *  ...
+ *
+ * For a given integer n (> 0), the leaf-array is at 1 + floor(log2(n)). 
+ *
+ * The idea for the geometrically increasing array sizes is from:
+ *     Fast Functional Lists, Hash-Lists, Deques and Variable Length Arrays.
+ *     Bagwell, Phil (2002).
+ *     http://infoscience.epfl.ch/record/64410/files/techlists.pdf
+ *
+ * Disadvantage:
+ * Worst case memory waste > 99% and will happen when each of the
+ * leaf arrays contains only a single element. Even with consecutive
+ * integers, memory waste can be as high as 50%.
+ *
+ * Solution: Hashed Array Trees (HATs).
+ *
+ */
+
+/* cint_array_init ---  check relevant environment variables */
+
+static NODE **
+cint_array_init(NODE *symbol ATTRIBUTE_UNUSED, NODE *subs ATTRIBUTE_UNUSED)
+{
+       long newval;
+
+       if ((newval = getenv_long("NHAT")) > 1 && newval < INT32_BIT)
+               NHAT = newval;
+       THRESHOLD = power_two_table[NHAT + 1];
+       return (NODE **) ! NULL;
+}
+
+
+/* is_uinteger --- test if the subscript is an integer >= 0 */
+
+NODE **
+is_uinteger(NODE *symbol, NODE *subs)
+{
+       if (is_integer(symbol, subs) != NULL && subs->numbr >= 0)
+               return (NODE **) ! NULL;
+       return NULL;
+}
+
+
+/* cint_lookup --- Find the subscript in the array; Install it if it isn't 
there. */
+
+static NODE **
+cint_lookup(NODE *symbol, NODE *subs)
+{
+       NODE **lhs;
+       long k;
+       int h1 = -1, m, li;
+       NODE *tn, *xn;
+       long cint_size, capacity;
+
+       k = -1;
+       if (ISUINT(symbol, subs)) {
+               k = subs->numbr;        /* k >= 0 */
+               h1 = cint_hash(k);      /* h1 >= NHAT */
+               if ((lhs = cint_find(symbol, k, h1)) != NULL)
+                       return lhs;
+       }
+       xn = symbol->xarray;
+       if (xn != NULL && (lhs = xn->aexists(xn, subs)) != NULL)
+               return lhs;
+
+       /* It's not there, install it */
+
+       if (k < 0)
+               goto xinstall;
+
+       m = h1 - 1;     /* m >= (NHAT- 1) */
+
+       /* Estimate capacity upper bound.
+        * capacity upper bound = current capacity + leaf array size.
+        */
+       li = m > NHAT ? m : NHAT;
+       while (li >= NHAT) {
+               /* leaf-array of a HAT */
+               li = (li + 1) / 2;
+       }
+       capacity = symbol->array_capacity + power_two_table[li];
+
+       cint_size = (xn == NULL) ? symbol->table_size
+                               : (symbol->table_size - xn->table_size);
+       assert(cint_size >= 0);
+       if ((capacity - cint_size) > THRESHOLD)
+               goto xinstall;
+
+       if (symbol->nodes == NULL) {
+               symbol->array_capacity = 0;
+               assert(symbol->table_size == 0);
+
+               /* nodes[0] .. nodes[NHAT- 1] not used */
+               emalloc(symbol->nodes, NODE **, INT32_BIT * sizeof(NODE *), 
"cint_lookup");
+               memset(symbol->nodes, '\0', INT32_BIT * sizeof(NODE *));
+       }
+
+       symbol->table_size++;   /* one more element in array */
+
+       tn = symbol->nodes[h1];
+       if (tn == NULL) {
+               tn = make_node(Node_array_tree);
+               symbol->nodes[h1] = tn;
+       }
+
+       if (m < NHAT)
+               return tree_lookup(symbol, tn, k, NHAT, 0);
+       return tree_lookup(symbol, tn, k, m, power_two_table[m]);
+
+xinstall:
+
+       symbol->table_size++;
+       if (xn == NULL) {
+               extern array_ptr int_array_func[];
+               extern array_ptr str_array_func[];
+
+               xn = symbol->xarray = make_array();
+               xn->vname = symbol->vname;      /* shallow copy */
+
+               /* Avoid using assoc_lookup(xn, subs) which may lead
+                * to infinite recursion.
+                */
+
+               if (is_integer(xn, subs))
+                       xn->array_funcs = int_array_func;
+               else
+                       xn->array_funcs = str_array_func;
+               xn->flags |= XARRAY;
+       }
+       return xn->alookup(xn, subs);
+}
+
+
+/* cint_exists --- test whether an index is in the array or not. */
+
+static NODE **
+cint_exists(NODE *symbol, NODE *subs)
+{
+       NODE *xn;
+
+       if (ISUINT(symbol, subs)) {
+               long k = subs->numbr;
+               NODE **lhs;
+               if ((lhs = cint_find(symbol, k, cint_hash(k))) != NULL)
+                       return lhs;
+       }
+       if ((xn = symbol->xarray) == NULL)
+               return NULL;
+       return xn->aexists(xn, subs);
+}
+
+
+/* cint_clear --- flush all the values in symbol[] */
+
+static NODE **
+cint_clear(NODE *symbol, NODE *subs ATTRIBUTE_UNUSED)
+{
+       size_t i;
+       NODE *tn;
+
+       assert(symbol->nodes != NULL);
+
+       if (symbol->xarray != NULL) {
+               NODE *xn = symbol->xarray;
+               assoc_clear(xn);
+               freenode(xn);
+               symbol->xarray = NULL;
+       }
+
+       for (i = NHAT; i < INT32_BIT; i++) {
+               tn = symbol->nodes[i];
+               if (tn != NULL) {
+                       tree_clear(tn);
+                       freenode(tn);
+               }
+       }
+
+       efree(symbol->nodes);
+       init_array(symbol);     /* re-initialize symbol */
+       return NULL;
+}
+
+
+/* cint_remove --- remove an index from the array */
+
+static NODE **
+cint_remove(NODE *symbol, NODE *subs)
+{
+       long k;
+       int h1;
+       NODE *tn, *xn = symbol->xarray;
+
+       assert(symbol->nodes != NULL);
+       if (! ISUINT(symbol, subs))
+               goto xremove;
+
+       k = subs->numbr;
+       h1 = cint_hash(k);
+       tn = symbol->nodes[h1];
+       if (tn == NULL || ! tree_remove(symbol, tn, k))
+               goto xremove;
+
+       if (tn->table_size == 0) {
+               freenode(tn);
+               symbol->nodes[h1] = NULL;
+       }
+
+       symbol->table_size--;
+
+       if (xn == NULL && symbol->table_size == 0) {
+               efree(symbol->nodes);
+               init_array(symbol);     /* re-initialize array 'symbol' */
+       } else if(xn != NULL && symbol->table_size == xn->table_size) {
+               /* promote xn to symbol */
+               xn->flags &= ~XARRAY;
+               xn->parent_array = symbol->parent_array;
+               efree(symbol->nodes);
+               *symbol = *xn;
+               freenode(xn);
+       }
+
+       return (NODE **) ! NULL;
+
+xremove:
+       xn = symbol->xarray;
+       if (xn == NULL || xn->aremove(xn, subs) == NULL)
+               return NULL;
+       if (xn->table_size == 0) {
+               freenode(xn);
+               symbol->xarray = NULL;
+       }
+       symbol->table_size--;
+       assert(symbol->table_size > 0);
+
+       return (NODE **) ! NULL;
+}
+
+
+/* cint_copy --- duplicate input array "symbol" */
+
+static NODE **
+cint_copy(NODE *symbol, NODE *newsymb)
+{
+       NODE **old, **new;
+       size_t i;
+
+       assert(symbol->nodes != NULL);
+
+       /* allocate new table */
+       emalloc(new, NODE **, INT32_BIT * sizeof(NODE *), "cint_copy");
+       memset(new, '\0', INT32_BIT * sizeof(NODE *));
+
+       old = symbol->nodes;
+       for (i = NHAT; i < INT32_BIT; i++) {
+               if (old[i] == NULL)
+                       continue;
+               new[i] = make_node(Node_array_tree); 
+               tree_copy(newsymb, old[i], new[i]);
+       }
+
+       if (symbol->xarray != NULL) {
+               NODE *xn, *n;
+               xn = symbol->xarray;
+               n = make_array();
+               n->vname = newsymb->vname;
+               (void) xn->acopy(xn, n);
+               newsymb->xarray = n;
+       } else
+               newsymb->xarray = NULL;
+
+       newsymb->nodes = new;
+       newsymb->table_size = symbol->table_size;
+       newsymb->array_capacity = symbol->array_capacity;
+       newsymb->flags = symbol->flags;
+
+       return NULL;
+}
+
+
+/* cint_list --- return a list of items */
+
+static NODE**
+cint_list(NODE *symbol, NODE *t)
+{
+       NODE **list = NULL;
+       NODE *tn, *xn;
+       unsigned long k = 0, num_elems, list_size;
+       size_t j, ja, jd;
+       int elem_size = 1;
+
+       num_elems = symbol->table_size;
+       if (num_elems == 0)
+               return NULL;
+
+       if ((t->flags & (AINDEX|AVALUE|ADELETE)) == (AINDEX|ADELETE))
+               num_elems = 1;
+
+       if ((t->flags & (AINDEX|AVALUE)) == (AINDEX|AVALUE))
+               elem_size = 2;
+       list_size = num_elems * elem_size;
+
+       if (symbol->xarray != NULL) {
+               xn = symbol->xarray;
+               list = xn->alist(xn, t);
+               assert(list != NULL);
+               t->flags &= ~(AASC|ADESC);
+               if (num_elems == 1 || num_elems == xn->table_size)
+                       return list;
+               erealloc(list, NODE **, list_size * sizeof(NODE *), 
"cint_list");
+               k = elem_size * xn->table_size;
+       } else
+               emalloc(list, NODE **, list_size * sizeof(NODE *), "cint_list");
+
+
+       if ((t->flags & AINUM) == 0)    /* not sorting by "index num" */
+               t->flags &= ~(AASC|ADESC);
+
+       /* populate it with index in ascending or descending order */
+
+       for (ja = NHAT, jd = INT32_BIT - 1; ja < INT32_BIT && jd >= NHAT; ) {
+               j = (t->flags & ADESC) ? jd-- : ja++;
+               tn = symbol->nodes[j];
+               if (tn == NULL)
+                       continue;
+               k += tree_list(tn, list + k, t->flags);
+               if (k >= list_size)
+                       return list;
+       }
+       return list;
+}
+
+
+/* cint_dump --- dump array info */
+
+static NODE **
+cint_dump(NODE *symbol, NODE *ndump)
+{
+       NODE *tn, *xn = NULL;
+       int indent_level;
+       size_t i;
+       long cint_size = 0, int_size = 0;
+       AWKNUM kb = 0;
+       extern AWKNUM int_kilobytes(NODE *symbol);
+
+       indent_level = ndump->alevel;
+
+       if (symbol->xarray != NULL) {
+               xn = symbol->xarray;
+               int_size = xn->table_size;      /* FIXME -- can be int_array or 
str_array */
+       }
+       cint_size = symbol->table_size - int_size;
+       
+       if ((symbol->flags & XARRAY) == 0)
+               fprintf(output_fp, "%s `%s'\n",
+                       (symbol->parent_array == NULL) ? "array" : "sub-array",
+                       array_vname(symbol));
+       indent_level++;
+       indent(indent_level);
+       fprintf(output_fp, "array_func: cint_array_func\n");
+       if (symbol->flags != 0) {
+               indent(indent_level);
+               fprintf(output_fp, "flags: %s\n", flags2str(symbol->flags));
+       }
+       indent(indent_level);
+       fprintf(output_fp, "NHAT: %d\n", NHAT);
+       indent(indent_level);
+       fprintf(output_fp, "THRESHOLD: %ld\n", THRESHOLD);
+       indent(indent_level);
+       fprintf(output_fp, "table_size: %ld (total), %ld (cint), %ld (int + 
str)\n",
+                               symbol->table_size, cint_size, int_size);
+       indent(indent_level);
+       fprintf(output_fp, "array_capacity: %lu\n", (unsigned long) 
symbol->array_capacity);
+       indent(indent_level);
+       fprintf(output_fp, "Load Factor: %.2g\n", (AWKNUM) cint_size / 
symbol->array_capacity);
+
+       for (i = NHAT; i < INT32_BIT; i++) {
+               tn = symbol->nodes[i];
+               if (tn == NULL)
+                       continue;
+               /* Node_array_tree  + HAT */
+               kb += (sizeof(NODE) + tree_kilobytes(tn)) / 1024.0;
+       }
+       kb += (INT32_BIT * sizeof(NODE *)) / 1024.0;    /* symbol->nodes */     
+       kb += (symbol->array_capacity * sizeof(NODE *)) / 1024.0;       /* 
value nodes in Node_array_leaf(s) */
+       if (xn != NULL)
+               kb += int_kilobytes(xn);        /* FIXME: can be str_array or 
int_array ? */
+       indent(indent_level);
+       fprintf(output_fp, "memory: %.2g kB (total)\n", kb);
+
+       /* dump elements */
+
+       if (ndump->adepth >= 0) {
+               const char *aname;
+
+               fprintf(output_fp, "\n");
+               aname = make_aname(symbol);
+               for (i = NHAT; i < INT32_BIT; i++) {
+                       tn = symbol->nodes[i];
+                       if (tn != NULL)
+                               tree_info(tn, ndump, aname);
+               }
+       }
+
+       if (xn != NULL) {
+               fprintf(output_fp, "\n");
+               xn->adump(xn, ndump);
+       }
+
+#ifdef ARRAYDEBUG
+       if (ndump->adepth < -999)
+               cint_print(symbol);
+#endif
+
+       return NULL;
+}
+
+
+/* cint_hash --- locate the HAT for a given number 'k' */
+
+static inline int
+cint_hash(long k)
+{
+       uint32_t num, r, shift;
+
+       assert(k >= 0);
+       if (k == 0)
+               return NHAT;
+       num = k;
+
+       /* Find the Floor(log base 2 of 32-bit integer) */
+
+       /* Warren Jr., Henry S. (2002). Hacker's Delight.
+        * Addison Wesley. pp. pp. 215. ISBN 978-0201914658.
+        *
+        *      r = 0;
+        *      if (num >= 1<<16) { num >>= 16; r += 16; }
+        *      if (num >= 1<< 8) { num >>=  8; r +=  8; }
+        *      if (num >= 1<< 4) { num >>=  4; r +=  4; }
+        *      if (num >= 1<< 2) { num >>=  2; r +=  2; }
+        *      if (num >= 1<< 1) {             r +=  1; }
+        */
+
+
+       /* Slightly different code copied from:
+        *
+        * http://www-graphics.stanford.edu/~seander/bithacks.html
+        * Bit Twiddling Hacks
+        * By Sean Eron Anderson
+        * address@hidden
+        * Individually, the code snippets here are in the public domain
+        * (unless otherwise noted) — feel free to use them however you 
please.
+        * The aggregate collection and descriptions are © 1997-2005
+        * Sean Eron Anderson. The code and descriptions are distributed in the
+        * hope that they will be useful, but WITHOUT ANY WARRANTY and without
+        * even the implied warranty of merchantability or fitness for a 
particular
+        * purpose.  
+        *
+        */
+
+       r = (num > 0xFFFF) << 4; num >>= r;
+       shift = (num > 0xFF) << 3; num >>= shift; r |= shift;
+       shift = (num > 0x0F) << 2; num >>= shift; r |= shift;
+       shift = (num > 0x03) << 1; num >>= shift; r |= shift;
+       r |= (num >> 1);
+
+       /* We use a single HAT for 0 <= num < 2^NHAT */
+       if (r < NHAT)
+               return NHAT;
+
+       return (1 + r);
+}
+
+
+/* cint_find --- locate the integer subscript */
+
+static inline NODE **
+cint_find(NODE *symbol, long k, int h1)
+{
+       NODE *tn;
+
+       if (symbol->nodes == NULL || (tn = symbol->nodes[h1]) == NULL)
+               return NULL;
+       return tree_exists(tn, k);
+}
+
+
+#ifdef ARRAYDEBUG
+
+static NODE **
+cint_option(NODE *opt, NODE *val)
+{
+       NODE *tmp;
+       NODE **ret = (NODE **) ! NULL;
+
+       tmp = force_string(opt);
+       (void) force_number(val);
+       if (STREQ(tmp->stptr, "NHAT"))
+               NHAT = (int) val->numbr;
+       else
+               ret = NULL;
+       return ret;
+}
+
+
+/* cint_print --- print structural info */
+
+static void
+cint_print(NODE *symbol)
+{
+       NODE *tn;
+       size_t i;
+
+       fprintf(output_fp, "I[%4lu:%-4lu]\n", (unsigned long) INT32_BIT,
+                               (unsigned long) symbol->table_size);
+       for (i = NHAT; i < INT32_BIT; i++) {
+               tn = symbol->nodes[i];
+               if (tn == NULL)
+                       continue;
+               tree_print(tn, i, 1);
+       }
+}
+
+#endif
+
+
+/*------------------------ Hashed Array Trees -----------------------------*/
+
+/*
+ * HATs: Hashed Array Trees
+ * Fast variable-length arrays
+ * Edward Sitarski
+ * http://www.drdobbs.com/architecture-and-design/184409965
+ *
+ *  HAT has a top-level array containing a power of two
+ *  number of leaf arrays. All leaf arrays are the same size as the
+ *  top-level array. A full HAT can hold n^2 elements,
+ *  where n (some power of 2) is the size of each leaf array.
+ *  [i/n][i & (n - 1)] locates the `i th' element in a HAT.
+ *
+ */
+
+/*
+ *  A half HAT is defined here as a HAT with a top-level array of size n^2/2
+ *  and holds the first n^2/2 elements.
+ * 
+ *   1. 2^8 elements can be stored in a full HAT of size 2^4.
+ *   2. 2^9 elements can be stored in a half HAT of size 2^5.     
+ *   3. When the number of elements is some power of 2, it
+ *      can be stored in a full or a half HAT.
+ *   4. When the number of elements is some power of 2, it
+ *      can be stored in a HAT (full or half) with HATs as leaf elements
+ *      (full or half),  and so on (e.g. 2^8 elements in a HAT of size 2^4 
(top-level
+ *      array dimension) with each leaf array being a HAT of size 2^2). 
+ *
+ *  IMPLEMENTATION DETAILS:
+ *    1. A HAT of 2^12 elements needs 2^6 house-keeping NODEs
+ *       of Node_array_leaf.
+ *
+ *    2. A HAT of HATS of 2^12 elements needs
+ *       2^6 * (1 Node_array_tree + 2^3 Node_array_leaf)
+ *       ~ 2^9 house-keeping NODEs.
+ *
+ *    3. When a leaf array (or leaf HAT) becomes empty, the memory
+ *       is deallocated, and when there is no leaf array (or leaf HAT) left,
+ *       the HAT is deleted.
+ *
+ *    4. A HAT stores the base (first) element, and locates the leaf array/HAT
+ *       for the `i th' element using integer division
+ *       (i - base)/n where n is the size of the top-level array.
+ *
+ */
+
+/* make_node --- initialize a NODE */
+
+static inline NODE *
+make_node(NODETYPE type)
+{
+       NODE *n;
+       getnode(n);
+       memset(n, '\0', sizeof(NODE));
+       n->type = type;
+       return n;
+}
+
+
+/* tree_lookup --- Find an integer subscript in a HAT; Install it if it isn't 
there */
+
+static NODE **
+tree_lookup(NODE *symbol, NODE *tree, long k, int m, long base)
+{
+       NODE **lhs;
+       NODE *tn;
+       int i, n;
+       size_t size;
+       long num = k;
+
+       /*
+        * HAT size (size of Top & Leaf array) = 2^n
+        * where n = Floor ((m + 1)/2). For an odd value of m,
+        * only the first half of the HAT is needed.
+        */
+
+       n = (m + 1) / 2;
+       
+       if (tree->table_size == 0) {
+               size_t actual_size;
+               NODE **table;
+
+               assert(tree->nodes == NULL);
+
+               /* initialize top-level array */
+               size = actual_size = power_two_table[n];
+               tree->array_base = base;
+               tree->array_size = size;
+               tree->table_size = 0;   /* # of elements in the array */
+               if (n > m/2) {
+                       /* only first half of the array used */
+                       actual_size /= 2;
+                       tree->flags |= HALFHAT;
+               }
+               emalloc(table, NODE **, actual_size * sizeof(NODE *), 
"tree_lookup");
+               memset(table, '\0', actual_size * sizeof(NODE *));
+               tree->nodes = table;
+       } else
+               size = tree->array_size;
+
+       num -= tree->array_base;
+       i = num / size; /* top-level array index */
+       assert(i >= 0);
+
+       if ((lhs = tree_find(tree, k, i)) != NULL)
+               return lhs;
+
+       /* It's not there, install it */
+
+       tree->table_size++;
+       base += (size * i);
+       tn = tree->nodes[i];
+       if (n > NHAT) {
+               if (tn == NULL)
+                       tn = tree->nodes[i] = make_node(Node_array_tree);
+               return tree_lookup(symbol, tn, k, n, base);
+       } else {
+               if (tn == NULL)
+                       tn = tree->nodes[i] = make_node(Node_array_leaf);
+               return leaf_lookup(symbol, tn, k, size, base);
+       }
+}
+
+
+/* tree_exists --- test whether integer subscript `k' exists or not */
+
+static NODE **
+tree_exists(NODE *tree, long k)
+{
+       int i;
+       NODE *tn;
+
+       i = (k - tree->array_base) / tree->array_size;
+       assert(i >= 0);
+       tn = tree->nodes[i];
+       if (tn == NULL)
+               return NULL;
+       if (tn->type == Node_array_tree)
+               return tree_exists(tn, k);
+       return leaf_exists(tn, k);
+}
+
+/* tree_clear --- flush all the values */
+
+static void
+tree_clear(NODE *tree)
+{
+       NODE *tn;
+       size_t  j, hsize;
+
+       hsize = tree->array_size;
+       if ((tree->flags & HALFHAT) != 0)
+               hsize /= 2;
+
+       for (j = 0; j < hsize; j++) {
+               tn = tree->nodes[j];
+               if (tn == NULL)
+                       continue;
+               if (tn->type == Node_array_tree)
+                       tree_clear(tn);
+               else
+                       leaf_clear(tn);
+               freenode(tn);
+       }
+
+       efree(tree->nodes);
+       memset(tree, '\0', sizeof(NODE));
+       tree->type = Node_array_tree;
+}
+
+
+/* tree_remove --- If the integer subscript is in the HAT, remove it */
+
+static int
+tree_remove(NODE *symbol, NODE *tree, long k)
+{
+       int i;
+       NODE *tn;
+
+       i = (k - tree->array_base) / tree->array_size;
+       assert(i >= 0);
+       tn = tree->nodes[i];
+       if (tn == NULL)
+               return FALSE;
+
+       if (tn->type == Node_array_tree
+                       && ! tree_remove(symbol, tn, k))
+               return FALSE;
+       else if (tn->type == Node_array_leaf
+                       && ! leaf_remove(symbol, tn, k))
+               return FALSE;
+
+       if (tn->table_size == 0) {
+               freenode(tn);
+               tree->nodes[i] = NULL;
+       }
+
+       /* one less item in array */
+       if (--tree->table_size == 0) {
+               efree(tree->nodes);
+               memset(tree, '\0', sizeof(NODE));
+               tree->type = Node_array_tree;
+       }
+       return TRUE;
+}
+
+
+/* tree_find --- locate an interger subscript in the HAT */
+
+static inline NODE **
+tree_find(NODE *tree, long k, int i)
+{
+       NODE *tn;
+
+       assert(tree->nodes != NULL);
+       tn = tree->nodes[i];
+       if (tn != NULL) {
+               if (tn->type == Node_array_tree)
+                       return tree_exists(tn, k);
+               return leaf_exists(tn, k);
+       }
+       return NULL;
+}
+
+
+/* tree_list --- return a list of items in the HAT */
+
+static long
+tree_list(NODE *tree, NODE **list, unsigned int flags)
+{
+       NODE *tn;
+       size_t j, cj, hsize;
+       long k = 0;
+
+       assert(list != NULL);
+
+       hsize = tree->array_size;
+       if ((tree->flags & HALFHAT) != 0)
+               hsize /= 2;
+
+       for (j = 0; j < hsize; j++) {
+               cj = (flags & ADESC) ? (hsize - 1 - j) : j;
+               tn = tree->nodes[cj];
+               if (tn == NULL)
+                       continue;
+               if (tn->type == Node_array_tree)
+                       k += tree_list(tn, list + k, flags);
+               else
+                       k += leaf_list(tn, list + k, flags);
+               if ((flags & ADELETE) != 0 && k >= 1)
+                       return k;
+       }
+       return k;
+}
+
+
+/* tree_copy --- duplicate a HAT */
+
+static void
+tree_copy(NODE *newsymb, NODE *tree, NODE *newtree)
+{ 
+       NODE **old, **new;
+       size_t j, hsize;
+
+       hsize = tree->array_size;
+       if ((tree->flags & HALFHAT) != 0)
+               hsize /= 2;
+
+       emalloc(new, NODE **, hsize * sizeof(NODE *), "tree_copy");
+       memset(new, '\0', hsize * sizeof(NODE *));
+       newtree->nodes = new;
+       newtree->array_base = tree->array_base;
+       newtree->array_size = tree->array_size;
+       newtree->table_size = tree->table_size;
+       newtree->flags = tree->flags;
+
+       old = tree->nodes;
+       for (j = 0; j < hsize; j++) {
+               if (old[j] == NULL)
+                       continue;
+               if (old[j]->type == Node_array_tree) {
+                       new[j] = make_node(Node_array_tree);
+                       tree_copy(newsymb, old[j], new[j]);
+               } else {
+                       new[j] = make_node(Node_array_leaf);
+                       leaf_copy(newsymb, old[j], new[j]);
+               }
+       }
+}
+
+
+/* tree_info --- print index, value info */
+
+static void
+tree_info(NODE *tree, NODE *ndump, const char *aname)
+{
+       NODE *tn;
+       size_t j, hsize;
+
+       hsize = tree->array_size;
+       if ((tree->flags & HALFHAT) != 0)
+               hsize /= 2;
+
+       for (j = 0; j < hsize; j++) {
+               tn = tree->nodes[j];
+               if (tn == NULL)
+                       continue;
+               if (tn->type == Node_array_tree)
+                       tree_info(tn, ndump, aname);
+               else
+                       leaf_info(tn, ndump, aname);
+       }
+}
+
+
+/* tree_kilobytes --- calculate memory consumption of a HAT */
+
+static size_t
+tree_kilobytes(NODE *tree)
+{
+       NODE *tn;
+       size_t j, hsize;
+       size_t sz = 0;
+
+       hsize = tree->array_size;
+       if ((tree->flags & HALFHAT) != 0)
+               hsize /= 2;
+       for (j = 0; j < hsize; j++) {
+               tn = tree->nodes[j];
+               if (tn == NULL)
+                       continue;
+               sz += sizeof(NODE);     /* Node_array_tree or Node_array_leaf */
+               if (tn->type == Node_array_tree)
+                       sz += tree_kilobytes(tn);
+       }
+       sz += hsize * sizeof(NODE *);   /* tree->nodes */
+       return sz;
+}
+
+#ifdef ARRAYDEBUG
+
+/* tree_print --- print the HAT structures */
+
+static void
+tree_print(NODE *tree, size_t bi, int indent_level)
+{
+       NODE *tn;
+       size_t j, hsize;
+
+       indent(indent_level);
+
+       hsize = tree->array_size;
+       if ((tree->flags & HALFHAT) != 0)
+               hsize /= 2;
+       fprintf(output_fp, "%4d:%s[%4lu:%-4lu]\n", bi,
+                       (tree->flags & HALFHAT) ? "HH" : "H",
+                       (unsigned long) hsize, (unsigned long) 
tree->table_size);
+
+       for (j = 0; j < hsize; j++) {
+               tn = tree->nodes[j];
+               if (tn == NULL)
+                       continue;
+               if (tn->type == Node_array_tree)
+                       tree_print(tn, j, indent_level + 1);
+               else
+                       leaf_print(tn, j, indent_level + 1);
+       }
+}
+#endif
+
+/*--------------------- leaf (linear 1-D) array --------------------*/
+
+/* leaf_lookup --- find an integer subscript in the array; Install it if
+       it isn't there.
+*/
+
+static inline NODE **
+leaf_lookup(NODE *symbol, NODE *array, long k, long size, long base)
+{
+       NODE **lhs;
+
+       if (array->nodes == NULL) {
+               array->table_size = 0;  /* sanity */
+               array->array_size = size;
+               array->array_base = base;
+               emalloc(array->nodes, NODE **, size * sizeof(NODE *), 
"leaf_lookup");
+               memset(array->nodes, '\0', size * sizeof(NODE *));
+               symbol->array_capacity += size;
+       }
+
+       lhs = array->nodes + (k - base); /* leaf element */
+       if (*lhs == NULL) {
+               array->table_size++;    /* one more element in leaf array */
+               *lhs = dupnode(Nnull_string);
+       }
+       return lhs;
+}
+
+
+/* leaf_exists --- check if the array contains an integer subscript */ 
+
+static inline NODE **
+leaf_exists(NODE *array, long k)
+{
+       NODE **lhs;
+       lhs = array->nodes + (k - array->array_base); 
+       return (*lhs != NULL) ? lhs : NULL;
+}
+
+
+/* leaf_clear --- flush all values in the array */
+
+static void
+leaf_clear(NODE *array)
+{
+       long i, size = array->array_size;
+       NODE *r;
+
+       for (i = 0; i < size; i++) {
+               r = array->nodes[i];
+               if (r == NULL)
+                       continue;
+               if (r->type == Node_var_array) {
+                       assoc_clear(r);         /* recursively clear all 
sub-arrays */
+                       efree(r->vname);                        
+                       freenode(r);
+               } else
+                       unref(r);
+       }
+       efree(array->nodes);
+       array->nodes = NULL;
+       array->array_size = array->table_size = 0;
+}
+
+
+/* leaf_remove --- remove an integer subscript from the array */
+
+static int
+leaf_remove(NODE *symbol, NODE *array, long k)
+{
+       NODE **lhs;
+
+       lhs = array->nodes + (k - array->array_base); 
+       if (*lhs == NULL)
+               return FALSE;
+       *lhs = NULL;
+       if (--array->table_size == 0) {
+               efree(array->nodes);
+               array->nodes = NULL;
+               symbol->array_capacity -= array->array_size;
+               array->array_size = 0;  /* sanity */
+       }
+       return TRUE;
+}
+
+
+/* leaf_copy --- duplicate a leaf array */
+
+static void
+leaf_copy(NODE *newsymb, NODE *array, NODE *newarray)
+{
+       NODE **old, **new;
+       long size, i;
+
+       size = array->array_size;
+       emalloc(new, NODE **, size * sizeof(NODE *), "leaf_copy");
+       memset(new, '\0', size * sizeof(NODE *));
+       newarray->nodes = new;
+       newarray->array_size = size;
+       newarray->array_base = array->array_base;
+       newarray->flags = array->flags;
+       newarray->table_size = array->table_size;
+
+       old = array->nodes;
+       for (i = 0; i < size; i++) {
+               if (old[i] == NULL)
+                       continue;
+               if (old[i]->type == Node_val)
+                       new[i] = dupnode(old[i]);
+               else {
+                       NODE *r;
+                       r = make_array();
+                       r->vname = estrdup(old[i]->vname, 
strlen(old[i]->vname));
+                       r->parent_array = newsymb;
+                       new[i] = assoc_copy(old[i], r);
+               }
+       }
+}
+
+
+/* leaf_list --- return a list of items */
+
+static long
+leaf_list(NODE *array, NODE **list, unsigned int flags)
+{
+       NODE *r, *subs;
+       long num, i, ci, k = 0;
+       long size = array->array_size;
+       static char buf[100];
+
+       for (i = 0; i < size; i++) {
+               ci = (flags & ADESC) ? (size - 1 - i) : i;
+               r = array->nodes[ci];
+               if (r == NULL)
+                       continue;
+
+               /* index */
+               num = array->array_base + ci;
+               if (flags & AISTR) {
+                       sprintf(buf, "%ld", num); 
+                       subs = make_string(buf, strlen(buf));
+                       subs->numbr = num;
+                       subs->flags |= (NUMCUR|NUMINT);
+               } else {
+                       subs = make_number((AWKNUM) num);
+                       subs->flags |= (INTIND|NUMINT);
+               }
+               list[k++] = subs;
+
+               /* value */
+               if (flags & AVALUE) {
+                       if (r->type == Node_val) {
+                               if ((flags & AVNUM) != 0)
+                                       (void) force_number(r);
+                               else if ((flags & AVSTR) != 0)
+                                       r = force_string(r);
+                       }
+                       list[k++] = r;
+               }
+               if ((flags & ADELETE) != 0 && k >= 1)
+                       return k;
+       }
+
+       return k;
+}
+
+
+/* leaf_info --- print index, value info */
+
+static void
+leaf_info(NODE *array, NODE *ndump, const char *aname)
+{
+       NODE *subs, *val;
+       size_t i, size;
+
+       size = array->array_size;
+
+       subs = make_number((AWKNUM) 0.0);
+       subs->flags |= (INTIND|NUMINT);
+       for (i = 0; i < size; i++) {
+               val = array->nodes[i];
+               if (val == NULL)
+                       continue;
+               subs->numbr = array->array_base + i;
+               assoc_info(subs, val, ndump, aname);
+       }
+       unref(subs);
+}
+
+#ifdef ARRAYDEBUG
+
+/* leaf_print --- print the leaf-array structure */
+
+
+static void
+leaf_print(NODE *array, size_t bi, int indent_level)
+{
+       indent(indent_level);
+       fprintf(output_fp, "%4d:L[%4lu:%-4lu]\n", bi,
+                       (unsigned long) array->array_size,
+                       (unsigned long) array->table_size);
+}
+#endif
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 4b2cf41..b4d5e89 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 5f5ba60..a1cad96 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 29ce8b1..5870a40 100644
--- a/debug.c
+++ b/debug.c
@@ -44,8 +44,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 */
@@ -267,7 +265,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 */ 
@@ -307,8 +305,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 *);
@@ -335,9 +333,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 { \
@@ -719,6 +714,8 @@ list:
 int
 do_info(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
 {
+       NODE **table;
+
        if (arg == NULL || arg->type != D_argument)
                return FALSE;
 
@@ -804,7 +801,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);
@@ -815,8 +811,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 */
@@ -836,7 +831,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)
@@ -848,25 +843,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:
@@ -977,6 +975,7 @@ find_param(const char *name, long num, char **pname)
 {
        NODE *r = NULL;
        NODE *f;
+       char *fparam;
 
        if (pname)
                *pname = NULL;
@@ -986,20 +985,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;
                        }
                }
@@ -1059,7 +1056,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;
@@ -1067,7 +1064,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;
        }
@@ -1080,12 +1077,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);
                        }
                }
@@ -1215,7 +1212,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;
@@ -1255,7 +1252,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);
@@ -1264,12 +1261,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"),
@@ -1306,7 +1301,7 @@ do_set_var(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
                break;
        }
        return FALSE;
-}              
+}
 
 /* find_item --- find an item in the watch/display list */
 
@@ -1378,14 +1373,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;
@@ -1430,7 +1429,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;
@@ -1598,7 +1597,6 @@ condition_triggered(struct condition *cndn)
 }
 
 
-
 static int
 find_subscript(struct list_item *item, NODE **ptr)
 {
@@ -1617,7 +1615,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;
 }
 
@@ -1647,8 +1646,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;
@@ -1722,7 +1720,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 */
@@ -1730,7 +1728,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;
@@ -1738,7 +1736,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);
        }
@@ -1764,7 +1762,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)) {
@@ -1781,7 +1779,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 */
        }
@@ -1873,19 +1871,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, ", ");
        }
@@ -2351,7 +2347,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;
@@ -2478,7 +2474,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 */
@@ -2673,19 +2669,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 */
@@ -2916,9 +2910,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;
 }
@@ -3118,7 +3112,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) {
@@ -3207,7 +3200,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;
@@ -3224,12 +3217,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;
 }
@@ -3298,7 +3290,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)
@@ -3328,7 +3320,7 @@ func:
                        }
                }
                fprintf(out_fp, _("Can't find specified location in function 
`%s'\n"),
-                               func->lnode->param);
+                               func->vname);
                /* fall through */
        default:
                return FALSE;
@@ -3597,7 +3589,6 @@ pre_execute(INSTRUCTION **pi)
                return TRUE;
 
        case Op_func:
-       case Op_ext_func:
        case Op_var_update:
                return TRUE;
 
@@ -3632,7 +3623,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:
@@ -3659,8 +3650,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:
@@ -3679,9 +3670,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) {
@@ -3692,25 +3682,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]);
@@ -3726,12 +3708,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; */
        }
 
                        
@@ -3757,10 +3735,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");
@@ -3835,7 +3809,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;
 
@@ -3870,13 +3844,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:
@@ -3885,7 +3859,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;
 
@@ -3928,9 +3902,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;
@@ -3951,7 +3933,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");
@@ -3989,7 +3971,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) {
@@ -4001,25 +3984,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;
 }
 
@@ -4940,7 +4925,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);
@@ -4978,7 +4963,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)
@@ -5321,35 +5306,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
@@ -5392,12 +5348,15 @@ execute_code(volatile INSTRUCTION *code)
        volatile NODE *r = NULL;
        volatile jmp_buf fatal_tag_stack;
        long save_stack_size;
+       int save_flags = do_flags;
 
        /* We use one global stack for all contexts.
         * Save # of items in stack; in case of
         * a fatal error, pop stack until it has that many items.
         */ 
+
        save_stack_size = (stack_ptr  - stack_bottom) + 1;
+       do_flags = FALSE;
 
        PUSH_BINDING(fatal_tag_stack, fatal_tag, fatal_tag_valid);
        if (setjmp(fatal_tag) == 0) {
@@ -5407,7 +5366,7 @@ execute_code(volatile INSTRUCTION *code)
                (void) unwind_stack(save_stack_size);
 
        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;
@@ -5426,9 +5385,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);
@@ -5440,7 +5399,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 */
@@ -5462,9 +5423,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;
@@ -5473,9 +5432,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)
@@ -5483,26 +5441,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;
                }
        }
 
@@ -5542,9 +5496,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
@@ -5554,7 +5506,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;
 }
 
@@ -5571,13 +5523,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 */
@@ -5593,6 +5545,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;
@@ -5616,7 +5569,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();
 
@@ -5636,8 +5591,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;
@@ -5645,7 +5600,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:
@@ -5725,7 +5680,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 df9570e..e5e0738 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",
@@ -349,6 +352,7 @@ static struct optypetab {
        { "Op_K_nextfile", "nextfile" },
        { "Op_builtin", NULL },
        { "Op_sub_builtin", NULL },
+       { "Op_ext_builtin", NULL },
        { "Op_in_array", " in " },
        { "Op_func_call", NULL },
        { "Op_indirect_func_call", NULL },
@@ -376,7 +380,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 },
@@ -446,20 +449,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 },
        };
 
@@ -484,7 +486,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) {
@@ -498,6 +500,7 @@ genflags2str(int flagval, const struct flagtab *tab)
                }
        }
 
+       *sp = '\0';
        return buffer;
 }
 
@@ -582,7 +585,6 @@ posix_compare(NODE *s1, NODE *s2)
        return ret;
 }
 
-
 /* cmp_nodes --- compare two nodes, returning negative, 0, positive */
 
 int
@@ -599,6 +601,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;
@@ -610,8 +617,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;
@@ -637,7 +644,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:
@@ -1158,7 +1166,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;
 }
 
 
@@ -1239,15 +1247,13 @@ static INSTRUCTION *
 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 */ 
@@ -1274,7 +1280,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;
                }
 
@@ -1301,8 +1307,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:
@@ -1313,7 +1320,7 @@ setup_frame(INSTRUCTION *pc)
                default:
                        cant_happen();
                }
-               r->vname = varnames[i];
+               r->vname = fp[i].param;
        }
        stack_adj(-arg_count);  /* adjust stack pointer */
 
@@ -1354,7 +1361,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--) {
@@ -1388,11 +1395,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);
@@ -1661,12 +1671,10 @@ pop_exec_state(int *rule, char **src, long *sz)
  
  /* 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 
  */
 
 
@@ -1681,11 +1689,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;
 
 
@@ -1695,7 +1700,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)
@@ -1728,7 +1733,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;
 
@@ -1762,7 +1766,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:
@@ -1773,9 +1788,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)
@@ -1796,13 +1808,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:
@@ -1843,7 +1856,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);
@@ -1855,15 +1877,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;
@@ -1871,10 +1895,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;
@@ -1884,10 +1920,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;
@@ -1960,39 +1992,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;
 
@@ -2083,27 +2115,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);
@@ -2117,10 +2152,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();
@@ -2133,7 +2170,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:
@@ -2162,12 +2205,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;
@@ -2176,9 +2226,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;
 
@@ -2239,9 +2288,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);
@@ -2252,8 +2302,10 @@ post:
                                DEREF(t1);
                        }
 
-                       if (di) {       /* match found */
-                               decr_sp();
+                       if (di) {
+                               /* match found */
+
+                               t2 = POP_SCALAR();
                                DEREF(t2);
                                JUMPTO(pc->target_jmp);
                        }
@@ -2280,6 +2332,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;
@@ -2291,7 +2348,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;
@@ -2315,18 +2372,13 @@ 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)
@@ -2336,20 +2388,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();
@@ -2359,12 +2411,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_sub_builtin:    /* sub, gsub and gensub */
@@ -2444,18 +2507,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;
@@ -2466,26 +2531,32 @@ 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:
                        ni = setup_frame(pc);
                                                
-                       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 */
-                       }
-
                        /* 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 */
@@ -2697,15 +2768,8 @@ func_call:
                        JUMPTO(pc->target_jmp); /* Op_get_record, read next 
record */
 
                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:
@@ -2734,7 +2798,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 2e7c150..af987fa 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++) {
@@ -927,7 +927,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;
@@ -988,8 +988,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);
        }
 
@@ -1027,7 +1027,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;
 }
@@ -1088,7 +1088,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;
 }
@@ -1104,6 +1104,7 @@ set_FIELDWIDTHS()
        static int fw_alloc = 4;
        static short warned = FALSE;
        int fatal_error = FALSE;
+       NODE *tmp;
 
        if (do_lint && ! warned) {
                warned = TRUE;
@@ -1120,7 +1121,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");
@@ -1331,7 +1333,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));
@@ -1348,7 +1350,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/int_array.c b/int_array.c
new file mode 100644
index 0000000..913e154
--- /dev/null
+++ b/int_array.c
@@ -0,0 +1,833 @@
+/*
+ * int_array.c - routines for arrays of integer indices.
+ */
+
+/* 
+ * Copyright (C) 1986, 1988, 1989, 1991-2011 the Free Software Foundation, Inc.
+ * 
+ * This file is part of GAWK, the GNU implementation of the
+ * AWK Programming Language.
+ * 
+ * GAWK is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * GAWK is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
USA
+ */
+
+#include "awk.h"
+
+extern FILE *output_fp;
+extern void indent(int indent_level);
+extern NODE **is_integer(NODE *symbol, NODE *subs);
+
+static size_t INT_CHAIN_MAX = 2;
+
+static NODE **int_array_init(NODE *symbol, NODE *subs);
+static NODE **int_lookup(NODE *symbol, NODE *subs);
+static NODE **int_exists(NODE *symbol, NODE *subs);
+static NODE **int_clear(NODE *symbol, NODE *subs);
+static NODE **int_remove(NODE *symbol, NODE *subs);
+static NODE **int_list(NODE *symbol, NODE *t);
+static NODE **int_copy(NODE *symbol, NODE *newsymb);
+static NODE **int_dump(NODE *symbol, NODE *ndump);
+
+#ifdef ARRAYDEBUG
+static NODE **int_option(NODE *opt, NODE *val);
+#endif
+
+static uint32_t int_hash(uint32_t k, uint32_t hsize);
+static inline NODE **int_find(NODE *symbol, long k, uint32_t hash1);
+static NODE **int_insert(NODE *symbol, long k, uint32_t hash1);
+static void grow_int_table(NODE *symbol);
+
+array_ptr int_array_func[] = {
+       int_array_init,
+       is_integer,
+       int_lookup,
+       int_exists,
+       int_clear,
+       int_remove,
+       int_list,
+       int_copy,
+       int_dump,
+#ifdef ARRAYDEBUG
+       int_option,
+#endif
+};
+
+
+/* int_array_init --- check relevant environment variables */
+
+static NODE **
+int_array_init(NODE *symbol ATTRIBUTE_UNUSED, NODE *subs ATTRIBUTE_UNUSED)
+{
+       long newval;
+
+       if ((newval = getenv_long("INT_CHAIN_MAX")) > 0)
+               INT_CHAIN_MAX = newval;
+       return (NODE **) ! NULL;
+}
+
+
+/* is_integer --- check if subscript is an integer */
+
+NODE **
+is_integer(NODE *symbol, NODE *subs)
+{
+       long l;
+       AWKNUM d;
+
+       if (subs == Nnull_string)
+               return NULL;
+
+       if ((subs->flags & NUMINT) != 0)
+               return (NODE **) ! NULL;
+
+       if ((subs->flags & NUMBER) != 0) {
+               d = subs->numbr;
+               if (d <= INT32_MAX && d >= INT32_MIN && d == (int32_t) d) {
+                       subs->flags |= NUMINT;
+                       return (NODE **) ! NULL;
+               }
+               return NULL;
+       }
+
+       /* a[3]=1; print "3" in a    -- TRUE
+        * a[3]=1; print "+3" in a   -- FALSE
+        * a[3]=1; print "03" in a   -- FALSE
+        * a[-3]=1; print "-3" in a  -- TRUE
+        */
+
+       if ((subs->flags & (STRING|STRCUR)) != 0) {
+               char *cp = subs->stptr, *cpend, *ptr;
+               char save;
+               size_t len = subs->stlen;
+
+               if (len == 0 || (! isdigit((unsigned char) *cp) && *cp != '-'))
+                       return NULL;
+               if (len > 1 && 
+                       ((*cp == '0')           /* "00", "011" .. */
+                               || (*cp == '-' && *(cp + 1) == '0')     /* 
"-0", "-011" .. */
+                       )
+               )
+                       return NULL;
+               if (len == 1 && *cp != '-') {   /* single digit */
+                       subs->numbr = (long) (*cp - '0');
+                       if ((subs->flags & MAYBE_NUM) != 0) {
+                               subs->flags &= ~MAYBE_NUM;
+                               subs->flags |= NUMBER;
+                       }
+                       subs->flags |= (NUMCUR|NUMINT);
+                       return (NODE **) ! NULL;
+               }
+
+               cpend = cp + len;
+               save = *cpend;
+               *cpend = '\0';
+
+               errno = 0;
+               l = strtol(cp, & ptr, 10);
+               *cpend = save;
+               if (errno != 0 || ptr != cpend)
+                       return NULL;
+               subs->numbr = l;
+               if ((subs->flags & MAYBE_NUM) != 0) {
+                       subs->flags &= ~MAYBE_NUM;
+                       subs->flags |= NUMBER;
+               }
+               subs->flags |= NUMCUR;
+               if (l <= INT32_MAX && l >= INT32_MIN) {
+                       subs->flags |= NUMINT;
+                       return (NODE **) ! NULL;
+               }
+       }
+       return NULL;
+}
+
+
+/* int_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.
+ */
+
+static NODE **
+int_lookup(NODE *symbol, NODE *subs)
+{
+       uint32_t hash1;
+       long k;
+       unsigned long size;
+       NODE **lhs;
+       NODE *xn;
+
+       /* N.B: symbol->table_size is the total # of non-integers 
(symbol->xarray)
+        *      and integer elements. Also, symbol->xarray must have at least 
one
+        *      item in it, and can not exist if there are no integer elements.
+        *      In that case, symbol->xarray is promoted to 'symbol' (See 
int_remove).
+        */
+
+
+       if (! is_integer(symbol, subs)) {
+               xn = symbol->xarray; 
+               if (xn == NULL) {
+                       xn = symbol->xarray = make_array();
+                       xn->vname = symbol->vname;      /* shallow copy */
+                       xn->flags |= XARRAY;
+               } else if ((lhs = xn->aexists(xn, subs)) != NULL)
+                       return lhs;
+               symbol->table_size++;
+               return assoc_lookup(xn, subs);
+       }
+
+       k = subs->numbr;
+       if (symbol->buckets == NULL)
+               grow_int_table(symbol);
+
+       hash1 = int_hash(k, symbol->array_size);
+       if ((lhs = int_find(symbol, k, hash1)) != NULL)
+               return lhs;
+       
+       /* It's not there, install it */
+       
+       symbol->table_size++;
+
+       /* first see if we would need to grow the array, before installing */
+       size = symbol->table_size;
+       if ((xn = symbol->xarray) != NULL)
+               size -= xn->table_size;
+
+       if ((symbol->flags & ARRAYMAXED) == 0
+                   && (size / symbol->array_size) > INT_CHAIN_MAX) {
+               grow_int_table(symbol);
+               /* have to recompute hash value for new size */
+               hash1 = int_hash(k, symbol->array_size);
+       }
+       
+       return int_insert(symbol, k, hash1);
+}
+
+
+/* int_exists --- test whether the array element symbol[subs] exists or not,
+ *     return pointer to value if it does.
+ */
+
+static NODE **
+int_exists(NODE *symbol, NODE *subs)
+{
+       long k;
+       uint32_t hash1;
+
+       if (! is_integer(symbol, subs)) {
+               NODE *xn = symbol->xarray;
+               if (xn == NULL)
+                       return NULL;
+               return xn->aexists(xn, subs);
+       }
+       if (symbol->buckets == NULL)
+               return NULL;
+
+       k = subs->numbr;
+       hash1 = int_hash(k, symbol->array_size);
+       return int_find(symbol, k, hash1);
+}
+
+/* int_clear --- flush all the values in symbol[] */
+
+static NODE **
+int_clear(NODE *symbol, NODE *subs ATTRIBUTE_UNUSED)
+{
+       unsigned long i;
+       int j;
+       BUCKET *b, *next;
+       NODE *r;
+
+       if (symbol->xarray != NULL) {
+               NODE *xn = symbol->xarray;
+               assoc_clear(xn);
+               freenode(xn);
+               symbol->xarray = NULL;
+       }
+
+       for (i = 0; i < symbol->array_size; i++) {
+               for (b = symbol->buckets[i]; b != NULL; b = next) {
+                       next = b->ainext;
+                       for (j = 0; j < b->aicount; j++) {
+                               r = b->aivalue[j];
+                               if (r->type == Node_var_array) {
+                                       assoc_clear(r); /* recursively clear 
all sub-arrays */
+                                       efree(r->vname);                        
+                                       freenode(r);
+                               } else
+                                       unref(r);
+                       }
+                       freebucket(b);
+               }
+               symbol->buckets[i] = NULL;
+       }
+       if (symbol->buckets != NULL)
+               efree(symbol->buckets);
+       init_array(symbol);     /* re-initialize symbol */
+       symbol->flags &= ~ARRAYMAXED;
+       return NULL;
+}
+
+
+/* int_remove --- If SUBS is already in the table, remove it. */
+
+static NODE **
+int_remove(NODE *symbol, NODE *subs)
+{
+       uint32_t hash1;
+       BUCKET *b, *prev = NULL;
+       long k;
+       int i;
+       NODE *xn = symbol->xarray;
+
+       assert(symbol->buckets != NULL);
+
+       if (! is_integer(symbol, subs)) {
+               if (xn == NULL || xn->aremove(xn, subs) == NULL)
+                       return NULL;
+               if (xn->table_size == 0) {
+                       freenode(xn);
+                       symbol->xarray = NULL;
+               }
+               symbol->table_size--;
+               assert(symbol->table_size > 0);
+               return (NODE **) ! NULL;
+       }
+
+       k = subs->numbr;
+       hash1 = int_hash(k, symbol->array_size);
+
+       for (b = symbol->buckets[hash1]; b != NULL; prev = b, b = b->ainext) {
+               for (i = 0; i < b->aicount; i++) {
+                       if (k != b->ainum[i])
+                               continue;
+
+                       /* item found */
+                       if (i == 0 && b->aicount == 2) {
+                               /* removing the 1st item; move 2nd item from 
position 1 to 0 */
+
+                               b->ainum[0] = b->ainum[1];
+                               b->aivalue[0] = b->aivalue[1];
+                       } /* else
+                               removing the only item or the 2nd item */
+
+                       goto removed;
+               }
+       }
+
+       if (b == NULL)  /* item not in array */
+               return NULL;
+
+removed:
+       b->aicount--;
+
+       if (b->aicount == 0) {
+               /* detach bucket */
+               if (prev != NULL)
+                       prev->ainext = b->ainext;
+               else
+                       symbol->buckets[hash1] = b->ainext;
+
+               /* delete bucket */
+               freebucket(b);
+       } else if (b != symbol->buckets[hash1]) {
+               BUCKET *head = symbol->buckets[hash1];
+
+               assert(b->aicount == 1);
+               /* move the last element from head
+                * to bucket to make it full.
+                */
+               i = --head->aicount;    /* head has one less element */
+               b->ainum[1] = head->ainum[i];
+               b->aivalue[1] = head->aivalue[i];
+               b->aicount++;   /* bucket has one more element */
+               if (i == 0) {
+                       /* head is now empty; delete head */
+                       symbol->buckets[hash1] = head->ainext;
+                       freebucket(head);
+               }
+       } /* else
+               do nothing */
+
+       symbol->table_size--;
+       if (xn == NULL && symbol->table_size == 0) {
+               efree(symbol->buckets);
+               init_array(symbol);     /* re-initialize array 'symbol' */
+               symbol->flags &= ~ARRAYMAXED;
+       } else if (xn != NULL && symbol->table_size == xn->table_size) {
+               /* promote xn (str_array) to symbol */
+               xn->flags &= ~XARRAY;
+               xn->parent_array = symbol->parent_array;
+               efree(symbol->buckets);
+               *symbol = *xn;
+               freenode(xn);
+       }
+
+       return (NODE **) ! NULL;        /* return success */
+}
+
+
+/* int_copy --- duplicate input array "symbol" */
+
+static NODE **
+int_copy(NODE *symbol, NODE *newsymb)
+{
+       BUCKET **old, **new, **pnew;
+       BUCKET *chain, *newchain;
+       int j;
+       unsigned long i, cursize;
+
+       assert(symbol->buckets != NULL);
+
+       /* find the current hash size */
+       cursize = symbol->array_size;
+       
+       /* allocate new table */
+       emalloc(new, BUCKET **, cursize * sizeof(BUCKET *), "int_copy");
+       memset(new, '\0', cursize * sizeof(BUCKET *));
+
+       old = symbol->buckets;
+
+       for (i = 0; i < cursize; i++) {
+               for (chain = old[i], pnew = & new[i]; chain != NULL;
+                               chain = chain->ainext
+               ) {
+                       getbucket(newchain);
+                       newchain->aicount = chain->aicount;
+                       for (j = 0; j < chain->aicount; j++) {
+                               NODE *oldval;
+
+                               /*
+                                * copy the corresponding key and
+                                * value from the original input list
+                                */
+                               newchain->ainum[j] = chain->ainum[j];
+
+                               oldval = chain->aivalue[j];
+                               if (oldval->type == Node_val)
+                                       newchain->aivalue[j] = dupnode(oldval);
+                               else {
+                                       NODE *r;
+                                       r = make_array();
+                                       r->vname = estrdup(oldval->vname, 
strlen(oldval->vname));
+                                       r->parent_array = newsymb;
+                                       newchain->aivalue[j] = 
assoc_copy(oldval, r);
+                               }
+                       }
+
+                       *pnew = newchain;
+                       pnew = & newchain->ainext;
+               }
+       }       
+
+       if (symbol->xarray != NULL) {
+               NODE *xn, *n;
+               xn = symbol->xarray;
+               n = make_array();
+               n->vname = newsymb->vname;      /* shallow copy */
+               (void) xn->acopy(xn, n);
+               newsymb->xarray = n;
+       } else
+               newsymb->xarray = NULL;
+
+       newsymb->table_size = symbol->table_size;
+       newsymb->buckets = new;
+       newsymb->array_size = cursize;
+       newsymb->flags = symbol->flags;
+
+       return NULL;
+}
+
+
+/* int_list --- return a list of array items */
+
+static NODE**
+int_list(NODE *symbol, NODE *t)
+{
+       NODE **list = NULL;
+       unsigned long num_elems, list_size, i, k = 0;
+       BUCKET *b;
+       NODE *r, *subs, *xn;
+       int j, elem_size = 1;
+       long num;
+       static char buf[100];
+
+       assert(symbol->table_size > 0);
+
+       num_elems = symbol->table_size;
+       if ((t->flags & (AINDEX|AVALUE|ADELETE)) == (AINDEX|ADELETE))
+               num_elems = 1;
+
+       if ((t->flags & (AINDEX|AVALUE)) == (AINDEX|AVALUE))
+               elem_size = 2;
+       list_size = elem_size * num_elems;
+       
+       if (symbol->xarray != NULL) {
+               xn = symbol->xarray;
+               list = xn->alist(xn, t);
+               assert(list != NULL);
+               if (num_elems == 1 || num_elems == xn->table_size)
+                       return list;
+               erealloc(list, NODE **, list_size * sizeof(NODE *), "int_list");
+               k = elem_size * xn->table_size;
+       } else
+               emalloc(list, NODE **, list_size * sizeof(NODE *), "int_list");
+
+       /* populate it */
+
+       for (i = 0; i < symbol->array_size; i++) {
+               for (b = symbol->buckets[i]; b != NULL; b = b->ainext) {
+                       for (j = 0; j < b->aicount; j++) {
+                               /* index */
+                               num = b->ainum[j];
+                               if (t->flags & AISTR) {
+                                       sprintf(buf, "%ld", num); 
+                                       subs = make_string(buf, strlen(buf));
+                                       subs->numbr = num;
+                                       subs->flags |= (NUMCUR|NUMINT);
+                               } else {
+                                       subs = make_number((AWKNUM) num);
+                                       subs->flags |= (INTIND|NUMINT);
+                               }
+                               list[k++] = subs;
+
+                               /* value */
+                               if (t->flags & AVALUE) {
+                                       r = b->aivalue[j];
+                                       if (r->type == Node_val) {
+                                               if ((t->flags & AVNUM) != 0)
+                                                       (void) force_number(r);
+                                               else if ((t->flags & AVSTR) != 
0)
+                                                       r = force_string(r);
+                                       }
+                                       list[k++] = r;
+                               }
+
+                               if (k >= list_size)
+                                       return list;
+                       }
+               }
+       }
+       return list;
+}
+
+
+/* int_kilobytes --- calculate memory consumption of the assoc array */
+
+AWKNUM
+int_kilobytes(NODE *symbol)
+{
+       unsigned long i, bucket_cnt = 0;
+       BUCKET *b;
+       AWKNUM kb;
+       extern AWKNUM str_kilobytes(NODE *symbol);
+
+       for (i = 0; i < symbol->array_size; i++) {
+               for (b = symbol->buckets[i]; b != NULL; b = b->ainext)
+                       bucket_cnt++;
+       }
+       kb = (((AWKNUM) bucket_cnt) * sizeof (BUCKET) + 
+                       ((AWKNUM) symbol->array_size) * sizeof (BUCKET *)) / 
1024.0;
+
+       if (symbol->xarray != NULL)
+               kb += str_kilobytes(symbol->xarray);
+
+       return kb;
+}
+
+
+/* int_dump --- dump array info */
+
+static NODE **
+int_dump(NODE *symbol, NODE *ndump)
+{
+#define HCNT   31
+
+       int indent_level;
+       BUCKET *b;
+       NODE *xn = NULL;
+       unsigned long str_size = 0, int_size = 0;
+       unsigned long i;
+       size_t j, bucket_cnt;
+       static size_t hash_dist[HCNT + 1];
+
+       indent_level = ndump->alevel;
+
+       if (symbol->xarray != NULL) {
+               xn = symbol->xarray;
+               str_size = xn->table_size;
+       }
+       int_size = symbol->table_size - str_size;
+
+       if ((symbol->flags & XARRAY) == 0)
+               fprintf(output_fp, "%s `%s'\n",
+                               (symbol->parent_array == NULL) ? "array" : 
"sub-array",
+                               array_vname(symbol));
+
+       indent_level++;
+       indent(indent_level);
+       fprintf(output_fp, "array_func: int_array_func\n");
+       if (symbol->flags != 0) {
+               indent(indent_level);
+               fprintf(output_fp, "flags: %s\n", flags2str(symbol->flags));
+       }
+       indent(indent_level);
+       fprintf(output_fp, "INT_CHAIN_MAX: %d\n", INT_CHAIN_MAX);
+       indent(indent_level);
+       fprintf(output_fp, "array_size: %lu (int)\n", (unsigned long) 
symbol->array_size);
+       indent(indent_level);
+       fprintf(output_fp, "table_size: %lu (total), %lu (int), %lu (str)\n",
+                       (unsigned long) symbol->table_size, int_size, str_size);
+       indent(indent_level);
+       fprintf(output_fp, "Avg # of items per chain (int): %.2g\n",
+                       ((AWKNUM) int_size) / symbol->array_size);
+
+       indent(indent_level);
+       fprintf(output_fp, "memory: %.2g kB (total)\n", int_kilobytes(symbol));
+
+       /* hash value distribution */
+
+       memset(hash_dist, '\0', (HCNT + 1) * sizeof(size_t));
+       for (i = 0; i < symbol->array_size; i++) {
+               bucket_cnt = 0;
+               for (b = symbol->buckets[i]; b != NULL; b = b->ainext)
+                       bucket_cnt += b->aicount;
+               if (bucket_cnt >= HCNT)
+                       bucket_cnt = HCNT;
+               hash_dist[bucket_cnt]++;
+       }
+
+       indent(indent_level);
+       fprintf(output_fp, "Hash distribution:\n");
+       indent_level++;
+       for (j = 0; j <= HCNT; j++) {
+               if (hash_dist[j] > 0) {
+                       indent(indent_level);
+                       if (j == HCNT)
+                               fprintf(output_fp, "[>=%lu]:%lu\n",
+                                       (unsigned long) HCNT, (unsigned long) 
hash_dist[j]);
+                       else
+                               fprintf(output_fp, "[%lu]:%lu\n",
+                                       (unsigned long) j, (unsigned long) 
hash_dist[j]);
+               }
+       }
+       indent_level--;
+
+       /* dump elements */
+
+       if (ndump->adepth >= 0) {
+               NODE *subs;
+               const char *aname;
+
+               fprintf(output_fp, "\n");
+
+               aname = make_aname(symbol);
+               subs = make_number((AWKNUM) 0);
+               subs->flags |= (INTIND|NUMINT);
+
+               for (i = 0; i < symbol->array_size; i++) {
+                       for (b = symbol->buckets[i]; b != NULL; b = b->ainext) {
+                               for (j = 0; j < b->aicount; j++) {
+                                       subs->numbr = b->ainum[j];
+                                       assoc_info(subs, b->aivalue[j], ndump, 
aname);
+                               }
+                       }
+               }
+               unref(subs);
+       }
+
+       if (xn != NULL) {
+               fprintf(output_fp, "\n");
+               xn->adump(xn, ndump);
+       }
+
+       return NULL;
+
+#undef HCNT
+}
+
+
+/* int_hash --- calculate the hash function of the integer subs */
+
+static uint32_t
+int_hash(uint32_t k, uint32_t hsize)
+{
+
+/*
+ * Bob Jenkins
+ * http://burtleburtle.net/bob/hash/integer.html
+ */
+
+#if 0
+       /* 6-shifts vs 7-shifts below */
+       k = (k+0x7ed55d16) + (k<<12);
+       k = (k^0xc761c23c) ^ (k>>19);
+       k = (k+0x165667b1) + (k<<5);
+       k = (k+0xd3a2646c) ^ (k<<9);
+       k = (k+0xfd7046c5) + (k<<3);
+       k = (k^0xb55a4f09) ^ (k>>16);
+#endif
+
+       k -= (k << 6);
+       k ^= (k >> 17);
+       k -= (k << 9);
+       k ^= (k << 4);
+       k -= (k << 3);
+       k ^= (k << 10);
+       k ^= (k >> 15);
+
+       if (k >= hsize)
+               k %= hsize;
+       return k;
+}
+
+/* assoc_find --- locate symbol[subs] */
+
+static inline NODE **
+int_find(NODE *symbol, long k, uint32_t hash1)
+{
+       BUCKET *b;
+       int i;
+
+       assert(symbol->buckets != NULL);
+       for (b = symbol->buckets[hash1]; b != NULL; b = b->ainext) {
+               for (i = 0; i < b->aicount; i++) {
+                       if (b->ainum[i] == k)
+                               return (b->aivalue + i);
+               }
+       }
+       return NULL;
+}
+
+
+/* int_insert --- install subs in the assoc array */
+
+static NODE **
+int_insert(NODE *symbol, long k, uint32_t hash1)
+{
+       BUCKET *b;
+       int i;
+
+       b = symbol->buckets[hash1];
+
+       /* Only the first bucket in the chain can be partially full,
+        * but is never empty.
+        */ 
+
+       if (b == NULL || (i = b->aicount) == 2) {
+               getbucket(b);
+               b->aicount = 0;
+               b->ainext = symbol->buckets[hash1];
+               symbol->buckets[hash1] = b;
+               i = 0;
+       }
+
+       b->ainum[i] = k;
+       b->aivalue[i] = dupnode(Nnull_string);
+       b->aicount++;
+       return & b->aivalue[i];
+}
+
+
+/* grow_int_table --- grow the hash table */
+
+static void
+grow_int_table(NODE *symbol)
+{
+       BUCKET **old, **new;
+       BUCKET *chain, *next;
+       int i, j;
+       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.  The final size is also chosen to be small
+        * enough so that MS-DOG mallocs can handle it. When things are
+        * very large (> 8K), we just double more or less, instead of
+        * just jumping from 8K to 64K.
+        */
+
+       static const unsigned 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;
+               return;
+       }
+
+       /* allocate new table */
+       emalloc(new, BUCKET **, newsize * sizeof(BUCKET *), "grow_int_table");
+       memset(new, '\0', newsize * sizeof(BUCKET *));
+
+       old = symbol->buckets;
+       symbol->buckets = new;
+       symbol->array_size = newsize;
+
+       /* brand new hash table */
+       if (old == NULL)
+               return;         /* DO NOT initialize symbol->table_size */
+
+       /* old hash table there, move stuff to new, free old */
+       /* note that symbol->table_size does not change if an old array. */
+
+       for (k = 0; k < oldsize; k++) {
+               long num;
+               for (chain = old[k]; chain != NULL; chain = next) {
+                       for (i = 0; i < chain->aicount; i++) {
+                               num = chain->ainum[i];
+                               *int_insert(symbol, num, int_hash(num, 
newsize)) = chain->aivalue[i];
+                       }
+                       next = chain->ainext;
+                       freebucket(chain);
+               }
+       }
+       efree(old);
+}
+
+
+#ifdef ARRAYDEBUG
+
+static NODE **
+int_option(NODE *opt, NODE *val)
+{
+       int newval;
+       NODE *tmp;
+       NODE **ret = (NODE **) ! NULL;
+
+       tmp = force_string(opt);
+       (void) force_number(val);
+       if (STREQ(tmp->stptr, "INT_CHAIN_MAX")) {
+               newval = (int) val->numbr;
+               if (newval > 0)         
+                       INT_CHAIN_MAX = newval;
+       } else
+               ret = NULL;
+       return ret;
+}
+#endif
diff --git a/io.c b/io.c
index e423a43..4b7976f 100644
--- a/io.c
+++ b/io.c
@@ -211,7 +211,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;
@@ -611,7 +611,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')
@@ -2531,7 +2531,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), \
@@ -3147,8 +3147,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 43a3e4a..71699fd 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 */
 
 #if MBS_SUPPORT
@@ -172,20 +160,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' },
@@ -194,17 +182,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 */
 
@@ -225,7 +209,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
@@ -371,7 +356,7 @@ main(int argc, char **argv)
                        break;
 
                case 'c':
-                       do_traditional = TRUE;
+                       do_flags |= DO_TRADITIONAL;
                        break;
 
                case 'C':
@@ -379,7 +364,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;
@@ -392,7 +377,7 @@ main(int argc, char **argv)
                        break;
 
                case 'g':
-                       do_intl = TRUE;
+                       do_flags |= DO_INTL;
                        break;
 
                case 'h':
@@ -400,19 +385,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':
@@ -421,7 +408,7 @@ main(int argc, char **argv)
 #endif
 
                case 'n':
-                       do_non_decimal_data = TRUE;
+                       do_flags |= DO_NON_DEC_DATA;
                        break;
 
                case 'N':
@@ -433,7 +420,7 @@ main(int argc, char **argv)
                        break;
 
                case 'p':
-                       do_profiling = TRUE;
+                       do_flags |= DO_PROFILING;
                        if (optarg != NULL)
                                set_prof_file(optarg);
                        else
@@ -441,15 +428,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':
@@ -528,7 +515,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'"));
@@ -539,7 +526,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.
@@ -547,7 +534,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'"));
        }
 
@@ -568,7 +555,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();
@@ -576,8 +563,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.
@@ -732,8 +718,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. */
 
@@ -840,6 +827,7 @@ static void
 cmdline_fs(char *str)
 {
        NODE **tmp;
+       size_t len;
 
        tmp = &FS_node->var_value;
        unref(*tmp);
@@ -856,7 +844,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();
 }
 
@@ -869,26 +859,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
@@ -951,13 +942,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))();
        }
@@ -981,9 +970,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[] = "";
 
@@ -994,7 +981,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));
@@ -1017,7 +1004,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));
        }
@@ -1036,8 +1023,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);
@@ -1151,6 +1137,7 @@ int
 arg_assign(char *arg, int initing)
 {
        char *cp, *cp2;
+       size_t cplen;
        int badvar;
        NODE *var;
        NODE *it;
@@ -1212,7 +1199,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
                /*
@@ -1233,7 +1221,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)
@@ -1457,3 +1445,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 204a91f..a16c9e0 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 /* 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 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,79 @@ 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);
+#if 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);
+       r->stfmt = -1;
+       r->stlen = len;
 #if MBS_SUPPORT
        r->wstptr = NULL;
        r->wstlen = 0;
 #endif /* MBS_SUPPORT */
 
-       if (flags & ALREADY_MALLOCED)
+       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;
-#if 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;) {
-#if 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;
-
        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 +529,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;
+#if MBS_SUPPORT
+       mbstate_t cur_state;
+
+       memset(& cur_state, 0, sizeof(cur_state));
+#endif
+
+       end = & s[len];
+       for (pf = ptm = s; pf < end;) {
+#if 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 +932,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 01d1e42..5c581e8 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:
@@ -522,9 +525,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, "()", ", 
");
@@ -534,10 +541,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:
@@ -756,14 +763,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);
@@ -1321,9 +1329,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) {
@@ -1331,15 +1338,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/str_array.c b/str_array.c
new file mode 100644
index 0000000..330280a
--- /dev/null
+++ b/str_array.c
@@ -0,0 +1,759 @@
+/*
+ * str_array.c - routines for associative arrays of string indices.
+ */
+
+/* 
+ * Copyright (C) 1986, 1988, 1989, 1991-2011 the Free Software Foundation, Inc.
+ * 
+ * This file is part of GAWK, the GNU implementation of the
+ * AWK Programming Language.
+ * 
+ * GAWK is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * GAWK is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
USA
+ */
+
+#include "awk.h"
+
+/*
+ * 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.
+ *
+ * 11/2002: We make the constant a variable, so that it can be tweaked
+ * via environment variable.
+ * 11/2002: Modern machines are bigger, cut this down from 10.
+ */
+
+static size_t STR_CHAIN_MAX = 2;
+
+extern FILE *output_fp;
+extern void indent(int indent_level);
+
+static NODE **str_array_init(NODE *symbol, NODE *subs);
+static NODE **str_lookup(NODE *symbol, NODE *subs);
+static NODE **str_exists(NODE *symbol, NODE *subs);
+static NODE **str_clear(NODE *symbol, NODE *subs);
+static NODE **str_remove(NODE *symbol, NODE *subs);
+static NODE **str_list(NODE *symbol, NODE *subs);
+static NODE **str_copy(NODE *symbol, NODE *newsymb);
+static NODE **str_dump(NODE *symbol, NODE *ndump);
+
+#ifdef ARRAYDEBUG
+static NODE **str_option(NODE *opt, NODE *val);
+#endif
+
+
+array_ptr str_array_func[] = {
+       str_array_init,
+       (array_ptr) 0,
+       str_lookup,
+       str_exists,
+       str_clear,
+       str_remove,
+       str_list,
+       str_copy,
+       str_dump,
+#ifdef ARRAYDEBUG
+       str_option
+#endif
+};
+
+static inline NODE **str_find(NODE *symbol, NODE *s1, size_t code1, unsigned 
long hash1);
+static void grow_table(NODE *symbol);
+
+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);
+
+unsigned long (*hash)(const char *s, size_t len, unsigned long hsize, size_t 
*code) = awk_hash;
+
+
+/* str_array_init --- check relevant environment variables */
+
+static NODE **
+str_array_init(NODE *symbol ATTRIBUTE_UNUSED, NODE *subs ATTRIBUTE_UNUSED)
+{
+       long newval;
+       const char *val;
+
+       if ((newval = getenv_long("STR_CHAIN_MAX")) > 0)
+               STR_CHAIN_MAX = newval;
+       if ((val = getenv("AWK_HASH")) != NULL && strcmp(val, "gst") == 0)
+               hash = gst_hash_string;
+       return (NODE **) ! 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. 
+ */
+
+static NODE **
+str_lookup(NODE *symbol, NODE *subs)
+{
+       unsigned long hash1;
+       NODE **lhs;
+       BUCKET *b;
+       size_t code1;
+
+       subs = force_string(subs);
+
+       if (symbol->buckets == NULL)
+               grow_table(symbol);
+       hash1 = hash(subs->stptr, subs->stlen,
+                       (unsigned long) symbol->array_size, & code1);
+       if ((lhs = str_find(symbol, subs, code1, hash1)) != NULL)
+               return lhs;
+
+       /* It's not there, install it. */
+       /* 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) > 
STR_CHAIN_MAX) {
+               grow_table(symbol);
+               /* have to recompute hash value for new size */
+               hash1 = code1 % (unsigned long) symbol->array_size;
+       }
+
+       if (subs->stfmt != -1) {
+               NODE *tmp;
+
+               /*
+                * Need to freeze this string value --- it must never
+                * change, no matter what happens to the value
+                * that created it or to CONVFMT, etc.; So, get
+                * a private copy.
+                */
+
+               tmp = make_string(subs->stptr, subs->stlen);
+
+               /*
+               * 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) {
+                       tmp->numbr = subs->numbr;
+                       tmp->flags |= NUMCUR;
+               }
+               subs = tmp;
+       } else {
+               /* string value already "frozen" */     
+
+               subs = dupnode(subs);
+       }
+
+       getbucket(b);
+       b->ahnext = symbol->buckets[hash1];
+       symbol->buckets[hash1] = b;
+       b->ahname = subs;
+       b->ahname_str = subs->stptr;
+       b->ahname_len = subs->stlen;
+       b->ahvalue = dupnode(Nnull_string);
+       b->ahcode = code1;
+       return & (b->ahvalue);
+}
+
+/* str_exists --- test whether the array element symbol[subs] exists or not,
+ *             return pointer to value if it does.
+ */
+
+static NODE **
+str_exists(NODE *symbol, NODE *subs)
+{
+       NODE **lhs;
+       unsigned long hash1;
+       size_t code1;
+
+       assert(symbol->table_size > 0);
+
+       subs = force_string(subs);
+       hash1 = hash(subs->stptr, subs->stlen, (unsigned long) 
symbol->array_size, & code1);
+       lhs = str_find(symbol, subs, code1, hash1);
+       return lhs;
+}
+
+/* str_clear --- flush all the values in symbol[] */
+
+static NODE **
+str_clear(NODE *symbol, NODE *subs ATTRIBUTE_UNUSED)
+{
+       unsigned long i;
+       BUCKET *b, *next;
+       NODE *r;
+
+       for (i = 0; i < symbol->array_size; i++) {
+               for (b = symbol->buckets[i]; b != NULL; b = next) {
+                       next = b->ahnext;
+                       r = b->ahvalue;
+                       if (r->type == Node_var_array) {
+                               assoc_clear(r); /* recursively clear all 
sub-arrays */
+                               efree(r->vname);                        
+                               freenode(r);
+                       } else
+                               unref(r);
+                       unref(b->ahname);
+                       freebucket(b);
+               }
+               symbol->buckets[i] = NULL;
+       }
+
+       if (symbol->buckets != NULL)
+               efree(symbol->buckets);
+       init_array(symbol);     /* re-initialize symbol */
+       symbol->flags &= ~ARRAYMAXED;
+       return NULL;
+}
+
+
+/* str_remove --- If SUBS is already in the table, remove it. */
+
+static NODE **
+str_remove(NODE *symbol, NODE *subs)
+{
+       unsigned long hash1;
+       BUCKET *b, *prev;
+       NODE *s2;
+       size_t s1_len;
+
+       assert(symbol->table_size > 0);
+
+       s2 = force_string(subs);
+       hash1 = hash(s2->stptr, s2->stlen, (unsigned long) symbol->array_size, 
NULL);
+
+       for (b = symbol->buckets[hash1], prev = NULL; b != NULL;
+                               prev = b, b = b->ahnext) {
+
+               /* Array indexes are strings; compare as such, always! */
+               s1_len = b->ahname_len;
+
+               if (s1_len != s2->stlen)
+                       continue;
+               if (s1_len == 0         /* "" is a valid index */
+                           || memcmp(b->ahname_str, s2->stptr, s1_len) == 0) {
+                       /* item found */
+
+                       unref(b->ahname);
+                       if (prev != NULL)
+                               prev->ahnext = b->ahnext;
+                       else
+                               symbol->buckets[hash1] = b->ahnext;
+
+                       /* delete bucket */
+                       freebucket(b);
+
+                       /* one less element in array */
+                       if (--symbol->table_size == 0) {
+                               if (symbol->buckets != NULL)
+                                       efree(symbol->buckets);
+                               init_array(symbol);     /* re-initialize symbol 
*/
+                               symbol->flags &= ~ARRAYMAXED;
+                       }
+
+                       return (NODE **) ! NULL;        /* return success */
+               }
+       }
+
+       return NULL;
+}
+
+
+/* str_copy --- duplicate input array "symbol" */
+
+static NODE **
+str_copy(NODE *symbol, NODE *newsymb)
+{
+       BUCKET **old, **new, **pnew;
+       BUCKET *chain, *newchain;
+       unsigned long cursize, i;
+       
+       assert(symbol->table_size > 0);
+
+       /* find the current hash size */
+       cursize = symbol->array_size;
+
+       /* allocate new table */
+       emalloc(new, BUCKET **, cursize * sizeof(BUCKET *), "str_copy");
+       memset(new, '\0', cursize * sizeof(BUCKET *));
+
+       old = symbol->buckets;
+
+       for (i = 0; i < cursize; i++) {
+               for (chain = old[i], pnew = & new[i]; chain != NULL;
+                               chain = chain->ahnext
+               ) {
+                       NODE *oldval, *newsubs;
+
+                       getbucket(newchain);
+
+                       /*
+                        * copy the corresponding name and
+                        * value from the original input list
+                        */
+
+                       newsubs = newchain->ahname = dupnode(chain->ahname);
+                       newchain->ahname_str = newsubs->stptr;
+                       newchain->ahname_len = newsubs->stlen;
+
+                       oldval = chain->ahvalue;
+                       if (oldval->type == Node_val)
+                               newchain->ahvalue = dupnode(oldval);
+                       else {
+                               NODE *r;
+
+                               r = make_array();
+                               r->vname = estrdup(oldval->vname, 
strlen(oldval->vname));
+                               r->parent_array = newsymb;
+                               newchain->ahvalue = assoc_copy(oldval, r);
+                       }
+                       newchain->ahcode = chain->ahcode;
+
+                       *pnew = newchain;
+                       pnew = & newchain->ahnext;
+               }
+       }       
+
+       newsymb->table_size = symbol->table_size;
+       newsymb->buckets = new;
+       newsymb->array_size = cursize;
+       newsymb->flags = symbol->flags;
+       return NULL;
+}
+
+
+/* str_list --- return a list of array items */
+
+static NODE**
+str_list(NODE *symbol, NODE *t)
+{
+       NODE **list;
+       NODE *subs, *val;
+       BUCKET *b;
+       unsigned long num_elems, list_size, i, k = 0;
+       int elem_size = 1;
+
+       assert(symbol->table_size > 0);
+
+       if ((t->flags & (AINDEX|AVALUE)) == (AINDEX|AVALUE))
+               elem_size = 2;
+
+       /* allocate space for array */
+       num_elems = symbol->table_size;
+       if ((t->flags & (AINDEX|AVALUE|ADELETE)) == (AINDEX|ADELETE))
+               num_elems = 1;
+       list_size =  elem_size * num_elems;
+       
+       emalloc(list, NODE **, list_size * sizeof(NODE *), "str_list");
+ 
+       /* populate it */
+
+       for (i = 0; i < symbol->array_size; i++) {
+               for (b = symbol->buckets[i]; b != NULL; b = b->ahnext) {
+                       /* index */
+                       subs = b->ahname;
+                       if (t->flags & AINUM)
+                               (void) force_number(subs);
+                       list[k++] = dupnode(subs);
+
+                       /* value */
+                       if (t->flags & AVALUE) {
+                               val = b->ahvalue;
+                               if (val->type == Node_val) {
+                                       if ((t->flags & AVNUM) != 0)
+                                               (void) force_number(val);
+                                       else if ((t->flags & AVSTR) != 0)
+                                               val = force_string(val);
+                               }
+                               list[k++] = val;
+                       }
+                       if (k >= list_size)
+                               return list;
+               }                       
+       }
+       return list;
+}
+
+
+/* str_kilobytes --- calculate memory consumption of the assoc array */
+
+AWKNUM
+str_kilobytes(NODE *symbol)
+{
+       unsigned long bucket_cnt;
+       AWKNUM kb;
+
+       bucket_cnt = symbol->table_size;
+
+       /* This does not include extra memory for indices with stfmt != -1 */
+       kb = (((AWKNUM) bucket_cnt) * sizeof (BUCKET) + 
+               ((AWKNUM) symbol->array_size) * sizeof (BUCKET *)) / 1024.0;
+       return kb;
+}
+
+
+/* str_dump --- dump array info */
+
+static NODE **
+str_dump(NODE *symbol, NODE *ndump)
+{
+#define HCNT   31
+
+       int indent_level;
+       unsigned long i, bucket_cnt;
+       BUCKET *b;
+       static size_t hash_dist[HCNT + 1];
+
+       indent_level = ndump->alevel;
+
+       if ((symbol->flags & XARRAY) == 0)
+               fprintf(output_fp, "%s `%s'\n",
+                               (symbol->parent_array == NULL) ? "array" : 
"sub-array",
+                               array_vname(symbol));
+       indent_level++;
+       indent(indent_level);
+       fprintf(output_fp, "array_func: str_array_func\n");
+       if (symbol->flags != 0) {
+               indent(indent_level);
+               fprintf(output_fp, "flags: %s\n", flags2str(symbol->flags));
+       }
+       indent(indent_level);
+       fprintf(output_fp, "STR_CHAIN_MAX: %d\n", STR_CHAIN_MAX);
+       indent(indent_level);
+       fprintf(output_fp, "array_size: %lu\n", (unsigned long) 
symbol->array_size);
+       indent(indent_level);
+       fprintf(output_fp, "table_size: %lu\n", (unsigned long) 
symbol->table_size);
+       indent(indent_level);
+       fprintf(output_fp, "Avg # of items per chain: %.2g\n",
+                               ((AWKNUM) symbol->table_size) / 
symbol->array_size);
+
+       indent(indent_level);
+       fprintf(output_fp, "memory: %.2g kB\n", str_kilobytes(symbol));
+
+       /* hash value distribution */
+
+       memset(hash_dist, '\0', (HCNT + 1) * sizeof(size_t));
+       for (i = 0; i < symbol->array_size; i++) {
+               bucket_cnt = 0;
+               for (b = symbol->buckets[i]; b != NULL; b = b->ahnext)
+                       bucket_cnt++;
+               if (bucket_cnt >= HCNT)
+                       bucket_cnt = HCNT;
+               hash_dist[bucket_cnt]++;
+       }
+
+       indent(indent_level);
+       fprintf(output_fp, "Hash distribution:\n");
+       indent_level++;
+       for (i = 0; i <= HCNT; i++) {
+               if (hash_dist[i] > 0) {
+                       indent(indent_level);
+                       if (i == HCNT)
+                               fprintf(output_fp, "[>=%lu]:%lu\n",
+                                       (unsigned long) HCNT, (unsigned long) 
hash_dist[i]);
+                       else
+                               fprintf(output_fp, "[%lu]:%lu\n",
+                                       (unsigned long) i, (unsigned long) 
hash_dist[i]);
+               }
+       }
+       indent_level--;
+
+       /* dump elements */
+
+       if (ndump->adepth >= 0) {
+               const char *aname;
+
+               fprintf(output_fp, "\n");
+               aname = make_aname(symbol);
+               for (i = 0; i < symbol->array_size; i++) {
+                       for (b = symbol->buckets[i]; b != NULL; b = b->ahnext)
+                               assoc_info(b->ahname, b->ahvalue, ndump, aname);
+               }
+       }
+
+       return NULL;
+
+#undef HCNT
+}      
+
+
+/* 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;
+}
+
+
+/* str_find --- locate symbol[subs] */
+
+static inline NODE **
+str_find(NODE *symbol, NODE *s1, size_t code1, unsigned long hash1)
+{
+       BUCKET *b;
+       size_t s2_len;
+
+       for (b = symbol->buckets[hash1]; b != NULL; b = b->ahnext) {
+               /*
+                * This used to use cmp_nodes() here.  That's wrong.
+                * Array indexes are strings; compare as such, always!
+                */
+               s2_len = b->ahname_len;
+
+               if (code1 == b->ahcode
+                       && s1->stlen == s2_len
+                       && (s2_len == 0         /* "" is a valid index */
+                               || memcmp(s1->stptr, b->ahname_str, s2_len) == 
0)
+               )
+                       return & (b->ahvalue);
+       }
+       return NULL;
+}
+
+
+/* grow_table --- grow a hash table */
+
+static void
+grow_table(NODE *symbol)
+{
+       BUCKET **old, **new;
+       BUCKET *chain, *next;
+       int i, j;
+       unsigned long oldsize, newsize, k;
+       unsigned long hash1;
+
+       /*
+        * 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.  The final size is also chosen to be small
+        * enough so that MS-DOG mallocs can handle it. When things are
+        * very large (> 8K), we just double more or less, instead of
+        * just jumping from 8K to 64K.
+        */
+ 
+       static const unsigned 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;
+               return;
+       }
+
+       /* allocate new table */
+       emalloc(new, BUCKET **, newsize * sizeof(BUCKET *), "grow_table");
+       memset(new, '\0', newsize * sizeof(BUCKET *));
+
+       old = symbol->buckets;
+       symbol->buckets = new;
+       symbol->array_size = newsize;
+
+       /* brand new hash table, set things up and return */
+       if (old == NULL) {
+               symbol->table_size = 0;
+               return;
+       }
+
+       /* old hash table there, move stuff to new, free old */
+
+       /*
+        * note that symbol->table_size does not change if an old array,
+        * and is explicitly set to 0 if a new one.
+        */
+
+       for (k = 0; k < oldsize; k++) {
+               for (chain = old[k]; chain != NULL; chain = next) {
+                       next = chain->ahnext;
+                       hash1 = chain->ahcode % newsize;
+
+                       /* remove from old list, add to new */
+                       chain->ahnext = new[hash1];
+                       new[hash1] = chain;
+               }
+       }
+       efree(old);
+}
+
+
+#ifdef ARRAYDEBUG
+
+static NODE **
+str_option(NODE *opt, NODE *val)
+{
+       int newval;
+       NODE *tmp;
+       NODE **ret = (NODE **) ! NULL;
+
+       tmp = force_string(opt);
+       (void) force_number(val);
+       if (STREQ(tmp->stptr, "STR_CHAIN_MAX")) {
+               newval = (int) val->numbr;
+               if (newval > 0)         
+                       STR_CHAIN_MAX = newval;
+       } else
+               ret = NULL;
+       return ret;
+}
+#endif
+
+
+/*
+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;
+}
+
+static unsigned long
+scramble(unsigned long x)
+{
+       if (sizeof(long) == 4) {
+               int y = ~x;
+
+               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);
+       }
+
+       return x;
+}
diff --git a/symbol.c b/symbol.c
new file mode 100644
index 0000000..a1c598e
--- /dev/null
+++ b/symbol.c
@@ -0,0 +1,693 @@
+#include "awk.h"
+
+extern SRCFILE *srcfiles;
+extern INSTRUCTION *rule_list;
+
+#define HASHSIZE       1021
+
+static NODE *variables[HASHSIZE];
+static int func_count; /* total number of functions */
+static int var_count;  /* total number of global variables and functions */
+
+static NODE *symbol_list;
+static void (*install_func)(NODE *) = NULL;
+static NODE *make_symbol(char *name, NODETYPE type);
+static NODE *install(char *name, NODE *hp, NODETYPE type);
+static void free_bcpool(INSTRUCTION *pl);
+
+static AWK_CONTEXT *curr_ctxt = NULL;
+static int ctxt_level;
+
+
+/*
+ * install_symbol:
+ * Install a global 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, NODETYPE type)
+{
+       return install(name, NULL, type);
+}
+
+
+/* lookup --- find the most recent global or param node for name
+ *     installed by install_symbol
+ */
+
+NODE *
+lookup(const char *name)
+{
+       NODE *hp;
+       size_t len;
+       int hash1;
+
+       len = strlen(name);
+       hash1 = hash(name, len, (unsigned long) HASHSIZE, NULL);
+       for (hp = variables[hash1]; hp != NULL; hp = hp->hnext) {
+               if (hp->hlength == len && strncmp(hp->hname, name, len) == 0)
+                       return hp->hvalue;
+       }
+       return NULL;
+}
+
+/* make_params --- allocate function parameters for the symbol table */
+
+NODE *
+make_params(char **pnames, int pcount)
+{
+       NODE *hp, *parms;
+       int i;
+       
+       if (pcount <= 0 || pnames == NULL)
+               return NULL;
+
+       emalloc(parms, NODE *, pcount * sizeof(NODE), "make_params");
+       memset(parms, '\0', pcount * sizeof(NODE));
+
+       for (i = 0, hp = parms; i < pcount; i++, hp++) {
+               hp->type = Node_param_list;
+               hp->hname = pnames[i];  /* shadows pname and vname */
+               hp->hlength = strlen(pnames[i]);
+               hp->param_cnt = i;
+               hp->hvalue = hp;        /* points to itself */
+       }
+
+       return parms;
+}
+
+/* install_params --- install function parameters into the symbol table */
+
+void
+install_params(NODE *func)
+{
+       int i, pcount;
+       NODE *parms;
+
+       if (func == NULL)
+               return;
+       assert(func->type == Node_func);
+       if ((pcount = func->param_cnt) <= 0
+                       || (parms = func->fparms) == NULL
+       )
+               return;
+       for (i = 0; i < pcount; i++)
+               (void) install(NULL, parms + i, Node_param_list);
+}
+
+
+/*
+ * remove_params --- remove function parameters out of the symbol table.
+ */
+
+void
+remove_params(NODE *func)
+{
+       NODE *parms, *p, *prev, *n;
+       int i, pcount, hash1;
+
+       if (func == NULL)
+               return;
+       assert(func->type == Node_func);
+       if ((pcount = func->param_cnt) <= 0
+                       || (parms = func->fparms) == NULL
+       )
+               return;
+
+       for (i = pcount - 1; i >= 0; i--) {
+               p = parms + i;
+               hash1 = p->hcode;
+               if (hash1 < 0 || hash1 >= HASHSIZE)
+                       continue;
+               for (prev = NULL, n = variables[hash1]; n != NULL;
+                                       prev = n, n = n->hnext) {
+                       if (n == p)
+                               break;
+               }
+               if (n == NULL)
+                       continue;
+               if (prev == NULL)
+                       variables[hash1] = n->hnext;    /* param at the head of 
the chain */
+               else
+                       prev->hnext = n->hnext;         /* param not at the 
head */ 
+       }
+}
+
+
+/* remove_symbol --- remove a symbol from the symbol table */
+
+NODE *
+remove_symbol(NODE *r)
+{
+       NODE *prev, *hp;
+       int hash1;
+       
+       hash1 = hash(r->vname, strlen(r->vname), (unsigned long) HASHSIZE, 
NULL);
+       for (prev = NULL, hp = variables[hash1]; hp != NULL;
+                               prev = hp, hp = hp->hnext) {
+               if (hp->hvalue == r)
+                       break;
+       }
+
+       if (hp == NULL)
+               return NULL;
+       assert(hp->hcode == hash1);
+
+       if (prev == NULL)
+               variables[hash1] = hp->hnext;   /* symbol at the head of chain 
*/
+       else
+               prev->hnext = hp->hnext;        /* symbol not at the head */
+
+       if (r->type == Node_param_list)
+               return r;       /* r == hp */
+       if (r->type == Node_func)
+               func_count--;
+       if (r->type != Node_ext_func)
+               var_count--;
+       freenode(hp);
+       return r;
+}
+
+
+/* destroy_symbol --- remove a symbol from symbol table
+*      and free all associated memory.
+*/
+
+void
+destroy_symbol(NODE *r)
+{
+       r = remove_symbol(r);
+       if (r == NULL)
+               return;
+
+       switch (r->type) {
+       case Node_func:
+               if (r->param_cnt > 0) {
+                       NODE *n;
+                       int i;
+                       int pcount = r->param_cnt;
+                               
+                       /* function parameters of type Node_param_list */       
                        
+                       for (i = 0; i < pcount; i++) {
+                               n = r->fparms + i;
+                               efree(n->param);
+                       }               
+                       efree(r->fparms);
+               }
+               break;
+
+       case Node_ext_func:
+               bcfree(r->code_ptr);
+               break;
+
+       case Node_var_array:
+               assoc_clear(r);
+               break;
+
+       case Node_var: 
+               unref(r->var_value);
+               break;
+
+       default:
+               /* Node_param_list -- YYABORT */
+               return;
+       }
+
+       efree(r->vname);
+       freenode(r);
+}
+
+
+/* make_symbol --- allocates a global symbol for the symbol table. */
+
+static NODE *
+make_symbol(char *name, NODETYPE type)
+{
+       NODE *hp, *r;
+
+       getnode(hp);
+       hp->type = Node_hashnode;
+       hp->hlength = strlen(name);
+       hp->hname = name;
+       getnode(r);
+       memset(r, '\0', sizeof(NODE));
+       hp->hvalue = r;
+       if (type == Node_var_array)
+               init_array(r);
+       else if (type == Node_var)
+               r->var_value = dupnode(Nnull_string);
+       r->vname = name;
+       r->type = type;
+       return hp;
+}
+
+/* install --- install a global name or function parameter in the symbol table 
*/
+
+static NODE *
+install(char *name, NODE *hp, NODETYPE type)
+{
+       int hash1;
+       NODE *r;
+
+       if (hp == NULL) {
+               /* global symbol */
+               hp = make_symbol(name, type);
+               if (type == Node_func)
+                       func_count++;
+               if (type != Node_ext_func)
+                       var_count++;    /* total, includes Node_func */
+       }
+
+       r = hp->hvalue;
+       hash1 = hash(hp->hname, hp->hlength, (unsigned long) HASHSIZE, NULL);
+       hp->hcode = hash1;
+       hp->hnext = variables[hash1];
+       variables[hash1] = hp;
+
+       if (install_func)
+               (*install_func)(r);
+
+       return r;
+}
+
+
+/* comp_symbol --- compare two (variable or function) names */
+
+static int
+comp_symbol(const void *v1, const void *v2)
+{
+       const NODE *const *npp1, *const *npp2;
+       const NODE *n1, *n2;
+
+       npp1 = (const NODE *const *) v1;
+       npp2 = (const NODE *const *) v2;
+       n1 = *npp1;
+       n2 = *npp2;
+
+       return strcmp(n1->vname, n2->vname);
+}
+
+
+typedef enum { FUNCTION = 1, VARIABLE } SYMBOL_TYPE;
+
+/* get_symbols --- return a list of optionally sorted symbols */
+ 
+static NODE **
+get_symbols(SYMBOL_TYPE what, int sort)
+{
+       int i;
+       NODE **table;
+       NODE *hp, *r;
+       long j, count = 0;
+
+       if (what == FUNCTION)
+               count = func_count;
+       else    /* if (what == VARIABLE) */
+               count = var_count;
+
+       emalloc(table, NODE **, (count + 1) * sizeof(NODE *), "symbol_list");
+       if (what == VARIABLE)
+               update_global_values();
+
+       for (i = j = 0; i < HASHSIZE; i++)
+               for (hp = variables[i]; hp != NULL; hp = hp->hnext) {
+                       if (hp->type != Node_hashnode)
+                               continue;
+                       r = hp->hvalue;
+                       if (r->type == Node_ext_func)
+                               continue;
+                       if (what == FUNCTION && r->type == Node_func)
+                               table[j++] = r;
+                       else if (what == VARIABLE)
+                               table[j++] = r;
+               }
+
+       if (sort && count > 1)
+               qsort(table, count, sizeof(NODE *), comp_symbol);       /* 
Shazzam! */
+       table[count] = NULL; /* null terminate the list */
+       return table;
+}
+
+
+/* variable_list --- list of global variables */
+
+NODE **
+variable_list()
+{
+       return get_symbols(VARIABLE, TRUE);
+}
+
+/* function_list --- list of functions */
+
+NODE **
+function_list(int sort)
+{
+       return get_symbols(FUNCTION, sort);
+}
+
+/* print_vars --- print names and values of global variables */ 
+
+void
+print_vars(NODE **table, int (*print_func)(FILE *, const char *, ...), FILE 
*fp)
+{
+       int i;
+       NODE *r;
+
+       assert(table != NULL);
+
+       for (i = 0; (r = table[i]) != NULL; i++) {
+               if (r->type == Node_func || r->type == Node_ext_func)
+                       continue;
+               print_func(fp, "%s: ", r->vname);
+               if (r->type == Node_var_array)
+                       print_func(fp, "array, %ld elements\n", r->table_size);
+               else if (r->type == Node_var_new)
+                       print_func(fp, "untyped variable\n");
+               else if (r->type == Node_var)
+                       valinfo(r->var_value, print_func, fp);
+       }
+}
+
+
+/* foreach_func --- execute given function for each awk function in table. */
+
+int
+foreach_func(NODE **table, int (*pfunc)(INSTRUCTION *, void *), void *data)
+{
+       int i;
+       NODE *r;
+       int ret = 0;
+
+       assert(table != NULL);
+
+       for (i = 0; (r = table[i]) != NULL; i++) {
+               if ((ret = pfunc(r->code_ptr, data)) != 0)
+                       break;
+       }
+       return ret;
+}
+
+/* release_all_vars --- free all variable memory */
+
+void
+release_all_vars()
+{
+       int i;
+       NODE *hp, *r, *next;
+
+       for (i = 0; i < HASHSIZE; i++)
+               for (hp = variables[i]; hp != NULL; hp = next) {
+                       next = hp->hnext;
+                       if (hp->type != Node_hashnode)
+                               continue;
+                       r = hp->hvalue;
+                       if (r->type == Node_func || r->type == Node_ext_func)
+                               continue;
+                       if (r->type == Node_var_array)
+                               assoc_clear(r);
+                       else if (r->type == Node_var)
+                               unref(r->var_value);
+                       efree(r->vname);
+                       freenode(r);
+                       freenode(hp);
+               }
+}
+
+
+/* append_symbol --- append symbol to the list of symbols
+ *     installed in the symbol table.
+ */
+
+void
+append_symbol(NODE *r)
+{
+       NODE *hp;
+
+       getnode(hp);
+       hp->lnode = r;
+       hp->rnode = symbol_list->rnode;
+       symbol_list->rnode = hp;
+}
+
+/* release_symbol --- free symbol list and optionally remove symbol from 
symbol table */
+
+void
+release_symbols(NODE *symlist, int keep_globals)
+{
+       NODE *hp, *next;
+
+       for (hp = symlist->rnode; hp != NULL; hp = next) {
+               if (! keep_globals) {
+                       /* destroys globals, function, and params
+                        * if still in symbol table
+                        */
+                       destroy_symbol(hp->lnode);
+               }
+               next = hp->rnode;
+               freenode(hp);
+       }
+       symlist->rnode = NULL;
+}
+
+#define pool_size      d.dl
+#define freei          x.xi
+static INSTRUCTION *pool_list;
+
+/* 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;
+}
+
+/* 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);
+       ctxt_level++;
+}
+
+/* pop_context --- switch to previous execution context. */ 
+
+void
+pop_context()
+{
+       AWK_CONTEXT *ctxt;
+
+       assert(curr_ctxt != NULL);
+       if (curr_ctxt->prev == NULL)
+               fatal(_("can not pop main context"));
+       ctxt = curr_ctxt->prev;
+       /* restore source and sourceline */
+       sourceline = ctxt->sourceline;
+       source = ctxt->source;
+       set_context(ctxt);
+       ctxt_level--;
+}
+
+/* in_main_context --- are we in the main context ? */
+
+int
+in_main_context()
+{
+       assert(ctxt_level > 0);
+       return (ctxt_level == 1);
+}
+
+/* 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)
+                       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_push_i:
+               m = cp->memory;
+               unref(m);
+               break;
+       case Op_store_var:
+               m = cp->initval;
+               if (m != NULL)
+                       unref(m);
+               break;
+       case Op_illegal:
+               cant_happen();
+       default:
+               break;  
+       }
+}
+
+/* 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));
+}
diff --git a/symbol.h b/symbol.h
new file mode 100644
index 0000000..d5c2d85
--- /dev/null
+++ b/symbol.h
@@ -0,0 +1,6 @@
+extern NODE *install_symbol(char *name, NODETYPE type);
+extern NODE *lookup(const char *name);
+extern void install_params(NODE *paramtab, int pcount);
+extern void remove_params(NODE *paramtab, int pcount);
+extern NODE *remove_symbol(char *name);
+extern void destroy_symbol(char *name);
diff --git a/test/Makefile.am b/test/Makefile.am
index 57d4d46..92e5d1b 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -217,6 +217,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 e5ff200..886e22c 100644
--- a/test/Makefile.in
+++ b/test/Makefile.in
@@ -402,6 +402,7 @@ EXTRA_DIST = \
        fnarray.awk \
        fnarray.ok \
        fnarray2.awk \
+       fnarray2.in \
        fnarray2.ok \
        fnarydel.awk \
        fnarydel.ok \
@@ -2026,7 +2027,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 c76769f..5c1a6b3 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]