gawk-diffs
[Top][All Lists]
Advanced

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

[gawk-diffs] [SCM] gawk branch, master, updated. 0a1746da98ef24b887074ba


From: Arnold Robbins
Subject: [gawk-diffs] [SCM] gawk branch, master, updated. 0a1746da98ef24b887074bad1c390523f6c4b190
Date: Fri, 19 Oct 2012 11:37:32 +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, master has been updated
       via  0a1746da98ef24b887074bad1c390523f6c4b190 (commit)
      from  a892293556960b0813098ede7da7a34774da7d3c (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

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

commit 0a1746da98ef24b887074bad1c390523f6c4b190
Author: Arnold D. Robbins <address@hidden>
Date:   Fri Oct 19 13:36:49 2012 +0200

    SYMTAB enhancements, bug fix. Doc additions.

diff --git a/ChangeLog b/ChangeLog
index e147607..896472b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,25 @@
+2012-10-19         Arnold D. Robbins     <address@hidden>
+
+       If SYMTAB is used, make sure ENVIRON and PROCINFO get loaded too.
+
+       * awkgram.y (process_deferred): New function. Call it when program
+       is completely parsed.
+       (symtab_used): New variable.
+       (variable): Set it to true if SYMTAB is looked up.
+       * main.c (load_environ, load_procinfo): Make sure the routines are
+       only called once.
+
+       Unrelated fixes:
+
+       * awkgram.y (yylex): Check continue_allowed and break_allowed as
+       soon as they are seen in the scanner; the rules that check them
+       can not be reduced until after a token that allows them is seen,
+       leading to errors at execution time.
+       * interpret.h (Op_K_break, Op_K_continue, Op_jmp): Add asssertion
+       that pc->target_jmp is not NULL.
+
+       * symbol.c (lookup): Correct a comment.
+
 2012-10-14         Arnold D. Robbins     <address@hidden>
 
        * gawkapi.h (IOBUF_PUBLIC): Renamed awk_input_buf_t.
diff --git a/FUTURES b/FUTURES
index ba1f1b2..a6a6f3e 100644
--- a/FUTURES
+++ b/FUTURES
@@ -28,12 +28,29 @@ For 4.1
        global variables are defined.
 
        Continue code reviews / code cleanup
+               - Nuking overly deep macros...
+
+       Consider making shadowed variables a warning and not
+       a fatal warning when -lint=fatal
 
        Consider making gawk output +nan for NaN values so that it
        will accept its own output as input.
 
 For 4.2
 =======
+       Think about how to generalize indirect access. Manuel Collado
+       suggests things like
+
+               foo = 5
+               @"foo" += 4
+
+       Also needed:
+
+               indirect calls of built-ins
+               indirect calls of extension functions
+               indirect through array elements, not just scalar variables
+
+       Consider relaxing the strictness of --posix.
 
        Consider removing use of and/or need for the protos.h file.
 
diff --git a/awkgram.c b/awkgram.c
index a375998..703cf63 100644
--- a/awkgram.c
+++ b/awkgram.c
@@ -117,6 +117,8 @@ static int count_expressions(INSTRUCTION **list, bool 
isarg);
 static INSTRUCTION *optimize_assignment(INSTRUCTION *exp);
 static void add_lint(INSTRUCTION *list, LINTTYPE linttype);
 
+static void process_deferred();
+
 enum defref { FUNC_DEFINE, FUNC_USE, FUNC_EXT };
 static void func_use(const char *name, enum defref how);
 static void check_funcs(void);
@@ -127,6 +129,7 @@ static int one_line_close(int fd);
 static bool want_source = false;
 static bool want_regexp;               /* lexical scanning kludge */
 static char *in_function;              /* parsing kludge */
+static bool symtab_used = false;       /* program used SYMTAB */
 static int rule = 0;
 
 const char *const ruletab[] = {
@@ -191,7 +194,7 @@ extern double fmod(double x, double y);
 #define YYSTYPE INSTRUCTION *
 
 /* Line 336 of yacc.c  */
-#line 195 "awkgram.c"
+#line 198 "awkgram.c"
 
 # ifndef YY_NULL
 #  if defined __cplusplus && 201103L <= __cplusplus
@@ -363,7 +366,7 @@ int yyparse ();
 /* Copy the second part of user declarations.  */
 
 /* Line 353 of yacc.c  */
-#line 367 "awkgram.c"
+#line 370 "awkgram.c"
 
 #ifdef short
 # undef short
@@ -727,25 +730,25 @@ static const yytype_int16 yyrhs[] =
 /* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
 static const yytype_uint16 yyrline[] =
 {
-       0,   192,   192,   194,   199,   200,   204,   216,   220,   231,
-     237,   242,   250,   258,   260,   265,   273,   275,   281,   282,
-     284,   310,   321,   332,   338,   347,   357,   359,   361,   367,
-     372,   373,   377,   396,   395,   429,   431,   436,   437,   450,
-     455,   456,   460,   462,   464,   471,   561,   603,   645,   758,
-     765,   772,   782,   791,   800,   809,   820,   836,   835,   859,
-     871,   871,   969,   969,  1002,  1032,  1038,  1039,  1045,  1046,
-    1053,  1058,  1070,  1084,  1086,  1094,  1099,  1101,  1109,  1111,
-    1120,  1121,  1129,  1134,  1134,  1145,  1149,  1157,  1158,  1161,
-    1163,  1168,  1169,  1178,  1179,  1184,  1189,  1195,  1197,  1199,
-    1206,  1207,  1213,  1214,  1219,  1221,  1226,  1228,  1230,  1232,
-    1238,  1245,  1247,  1249,  1265,  1275,  1282,  1284,  1289,  1291,
-    1293,  1301,  1303,  1308,  1310,  1315,  1317,  1319,  1369,  1371,
-    1373,  1375,  1377,  1379,  1381,  1383,  1406,  1411,  1416,  1441,
-    1447,  1449,  1451,  1453,  1455,  1457,  1462,  1466,  1498,  1500,
-    1506,  1512,  1525,  1526,  1527,  1532,  1537,  1541,  1545,  1560,
-    1573,  1578,  1614,  1632,  1633,  1639,  1640,  1645,  1647,  1654,
-    1671,  1688,  1690,  1697,  1702,  1710,  1720,  1732,  1741,  1745,
-    1749,  1753,  1757,  1761,  1764,  1766,  1770,  1774,  1778
+       0,   195,   195,   197,   202,   203,   209,   221,   225,   236,
+     242,   247,   255,   263,   265,   270,   278,   280,   286,   287,
+     289,   315,   326,   337,   343,   352,   362,   364,   366,   372,
+     377,   378,   382,   401,   400,   434,   436,   441,   442,   455,
+     460,   461,   465,   467,   469,   476,   566,   608,   650,   763,
+     770,   777,   787,   796,   805,   814,   825,   841,   840,   864,
+     876,   876,   974,   974,  1007,  1037,  1043,  1044,  1050,  1051,
+    1058,  1063,  1075,  1089,  1091,  1099,  1104,  1106,  1114,  1116,
+    1125,  1126,  1134,  1139,  1139,  1150,  1154,  1162,  1163,  1166,
+    1168,  1173,  1174,  1183,  1184,  1189,  1194,  1200,  1202,  1204,
+    1211,  1212,  1218,  1219,  1224,  1226,  1231,  1233,  1235,  1237,
+    1243,  1250,  1252,  1254,  1270,  1280,  1287,  1289,  1294,  1296,
+    1298,  1306,  1308,  1313,  1315,  1320,  1322,  1324,  1374,  1376,
+    1378,  1380,  1382,  1384,  1386,  1388,  1411,  1416,  1421,  1446,
+    1452,  1454,  1456,  1458,  1460,  1462,  1467,  1471,  1503,  1505,
+    1511,  1517,  1530,  1531,  1532,  1537,  1542,  1546,  1550,  1565,
+    1578,  1583,  1619,  1637,  1638,  1644,  1645,  1650,  1652,  1659,
+    1676,  1693,  1695,  1702,  1707,  1715,  1725,  1737,  1746,  1750,
+    1754,  1758,  1762,  1766,  1769,  1771,  1775,  1779,  1783
 };
 #endif
 
@@ -2055,7 +2058,7 @@ yyreduce:
     {
         case 3:
 /* Line 1787 of yacc.c  */
-#line 195 "awkgram.y"
+#line 198 "awkgram.y"
     {
                rule = 0;
                yyerrok;
@@ -2064,15 +2067,17 @@ yyreduce:
 
   case 5:
 /* Line 1787 of yacc.c  */
-#line 201 "awkgram.y"
+#line 204 "awkgram.y"
     {
                next_sourcefile();
+               if (sourcefile == srcfiles)
+                       process_deferred();
          }
     break;
 
   case 6:
 /* Line 1787 of yacc.c  */
-#line 205 "awkgram.y"
+#line 210 "awkgram.y"
     {
                rule = 0;
                /*
@@ -2085,7 +2090,7 @@ yyreduce:
 
   case 7:
 /* Line 1787 of yacc.c  */
-#line 217 "awkgram.y"
+#line 222 "awkgram.y"
     {
                (void) append_rule((yyvsp[(1) - (2)]), (yyvsp[(2) - (2)]));
          }
@@ -2093,7 +2098,7 @@ yyreduce:
 
   case 8:
 /* Line 1787 of yacc.c  */
-#line 221 "awkgram.y"
+#line 226 "awkgram.y"
     {
                if (rule != Rule) {
                        msg(_("%s blocks must have an action part"), 
ruletab[rule]);
@@ -2108,7 +2113,7 @@ yyreduce:
 
   case 9:
 /* Line 1787 of yacc.c  */
-#line 232 "awkgram.y"
+#line 237 "awkgram.y"
     {
                in_function = NULL;
                (void) mk_function((yyvsp[(1) - (2)]), (yyvsp[(2) - (2)]));
@@ -2118,7 +2123,7 @@ yyreduce:
 
   case 10:
 /* Line 1787 of yacc.c  */
-#line 238 "awkgram.y"
+#line 243 "awkgram.y"
     {
                want_source = false;
                yyerrok;
@@ -2127,7 +2132,7 @@ yyreduce:
 
   case 11:
 /* Line 1787 of yacc.c  */
-#line 243 "awkgram.y"
+#line 248 "awkgram.y"
     {
                want_source = false;
                yyerrok;
@@ -2136,7 +2141,7 @@ yyreduce:
 
   case 12:
 /* Line 1787 of yacc.c  */
-#line 251 "awkgram.y"
+#line 256 "awkgram.y"
     {
                if (include_source((yyvsp[(1) - (1)])) < 0)
                        YYABORT;
@@ -2148,19 +2153,19 @@ yyreduce:
 
   case 13:
 /* Line 1787 of yacc.c  */
-#line 259 "awkgram.y"
+#line 264 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 14:
 /* Line 1787 of yacc.c  */
-#line 261 "awkgram.y"
+#line 266 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 15:
 /* Line 1787 of yacc.c  */
-#line 266 "awkgram.y"
+#line 271 "awkgram.y"
     {
                if (load_library((yyvsp[(1) - (1)])) < 0)
                        YYABORT;
@@ -2172,31 +2177,31 @@ yyreduce:
 
   case 16:
 /* Line 1787 of yacc.c  */
-#line 274 "awkgram.y"
+#line 279 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 17:
 /* Line 1787 of yacc.c  */
-#line 276 "awkgram.y"
+#line 281 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 18:
 /* Line 1787 of yacc.c  */
-#line 281 "awkgram.y"
+#line 286 "awkgram.y"
     {  (yyval) = NULL; rule = Rule; }
     break;
 
   case 19:
 /* Line 1787 of yacc.c  */
-#line 283 "awkgram.y"
+#line 288 "awkgram.y"
     {  (yyval) = (yyvsp[(1) - (1)]); rule = Rule; }
     break;
 
   case 20:
 /* Line 1787 of yacc.c  */
-#line 285 "awkgram.y"
+#line 290 "awkgram.y"
     {
                INSTRUCTION *tp;
 
@@ -2226,7 +2231,7 @@ yyreduce:
 
   case 21:
 /* Line 1787 of yacc.c  */
-#line 311 "awkgram.y"
+#line 316 "awkgram.y"
     {
                static int begin_seen = 0;
                if (do_lint_old && ++begin_seen == 2)
@@ -2241,7 +2246,7 @@ yyreduce:
 
   case 22:
 /* Line 1787 of yacc.c  */
-#line 322 "awkgram.y"
+#line 327 "awkgram.y"
     {
                static int end_seen = 0;
                if (do_lint_old && ++end_seen == 2)
@@ -2256,7 +2261,7 @@ yyreduce:
 
   case 23:
 /* Line 1787 of yacc.c  */
-#line 333 "awkgram.y"
+#line 338 "awkgram.y"
     {
                (yyvsp[(1) - (1)])->in_rule = rule = BEGINFILE;
                (yyvsp[(1) - (1)])->source_file = source;
@@ -2266,7 +2271,7 @@ yyreduce:
 
   case 24:
 /* Line 1787 of yacc.c  */
-#line 339 "awkgram.y"
+#line 344 "awkgram.y"
     {
                (yyvsp[(1) - (1)])->in_rule = rule = ENDFILE;
                (yyvsp[(1) - (1)])->source_file = source;
@@ -2276,7 +2281,7 @@ yyreduce:
 
   case 25:
 /* Line 1787 of yacc.c  */
-#line 348 "awkgram.y"
+#line 353 "awkgram.y"
     {
                if ((yyvsp[(2) - (5)]) == NULL)
                        (yyval) = list_create(instruction(Op_no_op));
@@ -2287,19 +2292,19 @@ yyreduce:
 
   case 26:
 /* Line 1787 of yacc.c  */
-#line 358 "awkgram.y"
+#line 363 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 27:
 /* Line 1787 of yacc.c  */
-#line 360 "awkgram.y"
+#line 365 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 28:
 /* Line 1787 of yacc.c  */
-#line 362 "awkgram.y"
+#line 367 "awkgram.y"
     {
                yyerror(_("`%s' is a built-in function, it cannot be 
redefined"),
                                        tokstart);
@@ -2309,13 +2314,13 @@ yyreduce:
 
   case 29:
 /* Line 1787 of yacc.c  */
-#line 368 "awkgram.y"
+#line 373 "awkgram.y"
     { (yyval) = (yyvsp[(2) - (2)]); }
     break;
 
   case 32:
 /* Line 1787 of yacc.c  */
-#line 378 "awkgram.y"
+#line 383 "awkgram.y"
     {
                (yyvsp[(1) - (6)])->source_file = source;
                if (install_function((yyvsp[(2) - (6)])->lextok, (yyvsp[(1) - 
(6)]), (yyvsp[(4) - (6)])) < 0)
@@ -2330,13 +2335,13 @@ yyreduce:
 
   case 33:
 /* Line 1787 of yacc.c  */
-#line 396 "awkgram.y"
+#line 401 "awkgram.y"
     { ++want_regexp; }
     break;
 
   case 34:
 /* Line 1787 of yacc.c  */
-#line 398 "awkgram.y"
+#line 403 "awkgram.y"
     {
                  NODE *n, *exp;
                  char *re;
@@ -2369,19 +2374,19 @@ yyreduce:
 
   case 35:
 /* Line 1787 of yacc.c  */
-#line 430 "awkgram.y"
+#line 435 "awkgram.y"
     { bcfree((yyvsp[(1) - (1)])); }
     break;
 
   case 37:
 /* Line 1787 of yacc.c  */
-#line 436 "awkgram.y"
+#line 441 "awkgram.y"
     {  (yyval) = NULL; }
     break;
 
   case 38:
 /* Line 1787 of yacc.c  */
-#line 438 "awkgram.y"
+#line 443 "awkgram.y"
     {
                if ((yyvsp[(2) - (2)]) == NULL)
                        (yyval) = (yyvsp[(1) - (2)]);
@@ -2398,25 +2403,25 @@ yyreduce:
 
   case 39:
 /* Line 1787 of yacc.c  */
-#line 451 "awkgram.y"
+#line 456 "awkgram.y"
     {  (yyval) = NULL; }
     break;
 
   case 42:
 /* Line 1787 of yacc.c  */
-#line 461 "awkgram.y"
+#line 466 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 43:
 /* Line 1787 of yacc.c  */
-#line 463 "awkgram.y"
+#line 468 "awkgram.y"
     { (yyval) = (yyvsp[(2) - (3)]); }
     break;
 
   case 44:
 /* Line 1787 of yacc.c  */
-#line 465 "awkgram.y"
+#line 470 "awkgram.y"
     {
                if (do_pretty_print)
                        (yyval) = list_prepend((yyvsp[(1) - (1)]), 
instruction(Op_exec_count));
@@ -2427,7 +2432,7 @@ yyreduce:
 
   case 45:
 /* Line 1787 of yacc.c  */
-#line 472 "awkgram.y"
+#line 477 "awkgram.y"
     {
                INSTRUCTION *dflt, *curr = NULL, *cexp, *cstmt;
                INSTRUCTION *ip, *nextc, *tbreak;
@@ -2521,7 +2526,7 @@ yyreduce:
 
   case 46:
 /* Line 1787 of yacc.c  */
-#line 562 "awkgram.y"
+#line 567 "awkgram.y"
     { 
                /*
                 *    -----------------
@@ -2567,7 +2572,7 @@ yyreduce:
 
   case 47:
 /* Line 1787 of yacc.c  */
-#line 604 "awkgram.y"
+#line 609 "awkgram.y"
     {
                /*
                 *    -----------------
@@ -2613,7 +2618,7 @@ yyreduce:
 
   case 48:
 /* Line 1787 of yacc.c  */
-#line 646 "awkgram.y"
+#line 651 "awkgram.y"
     {
                INSTRUCTION *ip;
                char *var_name = (yyvsp[(3) - (8)])->lextok;
@@ -2730,7 +2735,7 @@ regular_loop:
 
   case 49:
 /* Line 1787 of yacc.c  */
-#line 759 "awkgram.y"
+#line 764 "awkgram.y"
     {
                (yyval) = mk_for_loop((yyvsp[(1) - (12)]), (yyvsp[(3) - (12)]), 
(yyvsp[(6) - (12)]), (yyvsp[(9) - (12)]), (yyvsp[(12) - (12)]));
 
@@ -2741,7 +2746,7 @@ regular_loop:
 
   case 50:
 /* Line 1787 of yacc.c  */
-#line 766 "awkgram.y"
+#line 771 "awkgram.y"
     {
                (yyval) = mk_for_loop((yyvsp[(1) - (11)]), (yyvsp[(3) - (11)]), 
(INSTRUCTION *) NULL, (yyvsp[(8) - (11)]), (yyvsp[(11) - (11)]));
 
@@ -2752,7 +2757,7 @@ regular_loop:
 
   case 51:
 /* Line 1787 of yacc.c  */
-#line 773 "awkgram.y"
+#line 778 "awkgram.y"
     {
                if (do_pretty_print)
                        (yyval) = list_prepend((yyvsp[(1) - (1)]), 
instruction(Op_exec_count));
@@ -2763,7 +2768,7 @@ regular_loop:
 
   case 52:
 /* Line 1787 of yacc.c  */
-#line 783 "awkgram.y"
+#line 788 "awkgram.y"
     { 
                if (! break_allowed)
                        error_ln((yyvsp[(1) - (2)])->source_line,
@@ -2776,7 +2781,7 @@ regular_loop:
 
   case 53:
 /* Line 1787 of yacc.c  */
-#line 792 "awkgram.y"
+#line 797 "awkgram.y"
     {
                if (! continue_allowed)
                        error_ln((yyvsp[(1) - (2)])->source_line,
@@ -2789,7 +2794,7 @@ regular_loop:
 
   case 54:
 /* Line 1787 of yacc.c  */
-#line 801 "awkgram.y"
+#line 806 "awkgram.y"
     {
                /* if inside function (rule = 0), resolve context at run-time */
                if (rule && rule != Rule)
@@ -2802,7 +2807,7 @@ regular_loop:
 
   case 55:
 /* Line 1787 of yacc.c  */
-#line 810 "awkgram.y"
+#line 815 "awkgram.y"
     {
                /* if inside function (rule = 0), resolve context at run-time */
                if (rule == BEGIN || rule == END || rule == ENDFILE)
@@ -2817,7 +2822,7 @@ regular_loop:
 
   case 56:
 /* Line 1787 of yacc.c  */
-#line 821 "awkgram.y"
+#line 826 "awkgram.y"
     {
                /* Initialize the two possible jump targets, the actual target
                 * is resolved at run-time. 
@@ -2836,7 +2841,7 @@ regular_loop:
 
   case 57:
 /* Line 1787 of yacc.c  */
-#line 836 "awkgram.y"
+#line 841 "awkgram.y"
     {
                if (! in_function)
                        yyerror(_("`return' used outside function context"));
@@ -2845,7 +2850,7 @@ regular_loop:
 
   case 58:
 /* Line 1787 of yacc.c  */
-#line 839 "awkgram.y"
+#line 844 "awkgram.y"
     {
                if ((yyvsp[(3) - (4)]) == NULL) {
                        (yyval) = list_create((yyvsp[(1) - (4)]));
@@ -2870,13 +2875,13 @@ regular_loop:
 
   case 60:
 /* Line 1787 of yacc.c  */
-#line 871 "awkgram.y"
+#line 876 "awkgram.y"
     { in_print = true; in_parens = 0; }
     break;
 
   case 61:
 /* Line 1787 of yacc.c  */
-#line 872 "awkgram.y"
+#line 877 "awkgram.y"
     {
                /*
                 * Optimization: plain `print' has no expression list, so $3 is 
null.
@@ -2977,13 +2982,13 @@ regular_print:
 
   case 62:
 /* Line 1787 of yacc.c  */
-#line 969 "awkgram.y"
+#line 974 "awkgram.y"
     { sub_counter = 0; }
     break;
 
   case 63:
 /* Line 1787 of yacc.c  */
-#line 970 "awkgram.y"
+#line 975 "awkgram.y"
     {
                char *arr = (yyvsp[(2) - (4)])->lextok;
 
@@ -3020,7 +3025,7 @@ regular_print:
 
   case 64:
 /* Line 1787 of yacc.c  */
-#line 1007 "awkgram.y"
+#line 1012 "awkgram.y"
     {
                static bool warned = false;
                char *arr = (yyvsp[(3) - (4)])->lextok;
@@ -3050,31 +3055,31 @@ regular_print:
 
   case 65:
 /* Line 1787 of yacc.c  */
-#line 1033 "awkgram.y"
+#line 1038 "awkgram.y"
     {  (yyval) = optimize_assignment((yyvsp[(1) - (1)])); }
     break;
 
   case 66:
 /* Line 1787 of yacc.c  */
-#line 1038 "awkgram.y"
+#line 1043 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 67:
 /* Line 1787 of yacc.c  */
-#line 1040 "awkgram.y"
+#line 1045 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 68:
 /* Line 1787 of yacc.c  */
-#line 1045 "awkgram.y"
+#line 1050 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 69:
 /* Line 1787 of yacc.c  */
-#line 1047 "awkgram.y"
+#line 1052 "awkgram.y"
     {
                if ((yyvsp[(1) - (2)]) == NULL)
                        (yyval) = list_create((yyvsp[(2) - (2)]));
@@ -3085,13 +3090,13 @@ regular_print:
 
   case 70:
 /* Line 1787 of yacc.c  */
-#line 1054 "awkgram.y"
+#line 1059 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 71:
 /* Line 1787 of yacc.c  */
-#line 1059 "awkgram.y"
+#line 1064 "awkgram.y"
     {
                INSTRUCTION *casestmt = (yyvsp[(5) - (5)]);
                if ((yyvsp[(5) - (5)]) == NULL)
@@ -3107,7 +3112,7 @@ regular_print:
 
   case 72:
 /* Line 1787 of yacc.c  */
-#line 1071 "awkgram.y"
+#line 1076 "awkgram.y"
     {
                INSTRUCTION *casestmt = (yyvsp[(4) - (4)]);
                if ((yyvsp[(4) - (4)]) == NULL)
@@ -3122,13 +3127,13 @@ regular_print:
 
   case 73:
 /* Line 1787 of yacc.c  */
-#line 1085 "awkgram.y"
+#line 1090 "awkgram.y"
     {  (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 74:
 /* Line 1787 of yacc.c  */
-#line 1087 "awkgram.y"
+#line 1092 "awkgram.y"
     { 
                NODE *n = (yyvsp[(2) - (2)])->memory;
                (void) force_number(n);
@@ -3140,7 +3145,7 @@ regular_print:
 
   case 75:
 /* Line 1787 of yacc.c  */
-#line 1095 "awkgram.y"
+#line 1100 "awkgram.y"
     {
                bcfree((yyvsp[(1) - (2)]));
                (yyval) = (yyvsp[(2) - (2)]);
@@ -3149,13 +3154,13 @@ regular_print:
 
   case 76:
 /* Line 1787 of yacc.c  */
-#line 1100 "awkgram.y"
+#line 1105 "awkgram.y"
     {  (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 77:
 /* Line 1787 of yacc.c  */
-#line 1102 "awkgram.y"
+#line 1107 "awkgram.y"
     {
                (yyvsp[(1) - (1)])->opcode = Op_push_re;
                (yyval) = (yyvsp[(1) - (1)]);
@@ -3164,19 +3169,19 @@ regular_print:
 
   case 78:
 /* Line 1787 of yacc.c  */
-#line 1110 "awkgram.y"
+#line 1115 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 79:
 /* Line 1787 of yacc.c  */
-#line 1112 "awkgram.y"
+#line 1117 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 81:
 /* Line 1787 of yacc.c  */
-#line 1122 "awkgram.y"
+#line 1127 "awkgram.y"
     {
                (yyval) = (yyvsp[(2) - (3)]);
          }
@@ -3184,7 +3189,7 @@ regular_print:
 
   case 82:
 /* Line 1787 of yacc.c  */
-#line 1129 "awkgram.y"
+#line 1134 "awkgram.y"
     {
                in_print = false;
                in_parens = 0;
@@ -3194,13 +3199,13 @@ regular_print:
 
   case 83:
 /* Line 1787 of yacc.c  */
-#line 1134 "awkgram.y"
+#line 1139 "awkgram.y"
     { in_print = false; in_parens = 0; }
     break;
 
   case 84:
 /* Line 1787 of yacc.c  */
-#line 1135 "awkgram.y"
+#line 1140 "awkgram.y"
     {
                if ((yyvsp[(1) - (3)])->redir_type == redirect_twoway
                        && (yyvsp[(3) - (3)])->lasti->opcode == 
Op_K_getline_redir
@@ -3212,7 +3217,7 @@ regular_print:
 
   case 85:
 /* Line 1787 of yacc.c  */
-#line 1146 "awkgram.y"
+#line 1151 "awkgram.y"
     {
                (yyval) = mk_condition((yyvsp[(3) - (6)]), (yyvsp[(1) - (6)]), 
(yyvsp[(6) - (6)]), NULL, NULL);
          }
@@ -3220,7 +3225,7 @@ regular_print:
 
   case 86:
 /* Line 1787 of yacc.c  */
-#line 1151 "awkgram.y"
+#line 1156 "awkgram.y"
     {
                (yyval) = mk_condition((yyvsp[(3) - (9)]), (yyvsp[(1) - (9)]), 
(yyvsp[(6) - (9)]), (yyvsp[(7) - (9)]), (yyvsp[(9) - (9)]));
          }
@@ -3228,13 +3233,13 @@ regular_print:
 
   case 91:
 /* Line 1787 of yacc.c  */
-#line 1168 "awkgram.y"
+#line 1173 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 92:
 /* Line 1787 of yacc.c  */
-#line 1170 "awkgram.y"
+#line 1175 "awkgram.y"
     {
                bcfree((yyvsp[(1) - (2)]));
                (yyval) = (yyvsp[(2) - (2)]);
@@ -3243,19 +3248,19 @@ regular_print:
 
   case 93:
 /* Line 1787 of yacc.c  */
-#line 1178 "awkgram.y"
+#line 1183 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 94:
 /* Line 1787 of yacc.c  */
-#line 1180 "awkgram.y"
+#line 1185 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]) ; }
     break;
 
   case 95:
 /* Line 1787 of yacc.c  */
-#line 1185 "awkgram.y"
+#line 1190 "awkgram.y"
     {
                (yyvsp[(1) - (1)])->param_count = 0;
                (yyval) = list_create((yyvsp[(1) - (1)]));
@@ -3264,7 +3269,7 @@ regular_print:
 
   case 96:
 /* Line 1787 of yacc.c  */
-#line 1190 "awkgram.y"
+#line 1195 "awkgram.y"
     {
                (yyvsp[(3) - (3)])->param_count =  (yyvsp[(1) - 
(3)])->lasti->param_count + 1;
                (yyval) = list_append((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]));
@@ -3274,55 +3279,55 @@ regular_print:
 
   case 97:
 /* Line 1787 of yacc.c  */
-#line 1196 "awkgram.y"
+#line 1201 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 98:
 /* Line 1787 of yacc.c  */
-#line 1198 "awkgram.y"
+#line 1203 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (2)]); }
     break;
 
   case 99:
 /* Line 1787 of yacc.c  */
-#line 1200 "awkgram.y"
+#line 1205 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (3)]); }
     break;
 
   case 100:
 /* Line 1787 of yacc.c  */
-#line 1206 "awkgram.y"
+#line 1211 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 101:
 /* Line 1787 of yacc.c  */
-#line 1208 "awkgram.y"
+#line 1213 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 102:
 /* Line 1787 of yacc.c  */
-#line 1213 "awkgram.y"
+#line 1218 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 103:
 /* Line 1787 of yacc.c  */
-#line 1215 "awkgram.y"
+#line 1220 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 104:
 /* Line 1787 of yacc.c  */
-#line 1220 "awkgram.y"
+#line 1225 "awkgram.y"
     {  (yyval) = mk_expression_list(NULL, (yyvsp[(1) - (1)])); }
     break;
 
   case 105:
 /* Line 1787 of yacc.c  */
-#line 1222 "awkgram.y"
+#line 1227 "awkgram.y"
     {
                (yyval) = mk_expression_list((yyvsp[(1) - (3)]), (yyvsp[(3) - 
(3)]));
                yyerrok;
@@ -3331,31 +3336,31 @@ regular_print:
 
   case 106:
 /* Line 1787 of yacc.c  */
-#line 1227 "awkgram.y"
+#line 1232 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 107:
 /* Line 1787 of yacc.c  */
-#line 1229 "awkgram.y"
+#line 1234 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 108:
 /* Line 1787 of yacc.c  */
-#line 1231 "awkgram.y"
+#line 1236 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 109:
 /* Line 1787 of yacc.c  */
-#line 1233 "awkgram.y"
+#line 1238 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 110:
 /* Line 1787 of yacc.c  */
-#line 1239 "awkgram.y"
+#line 1244 "awkgram.y"
     {
                if (do_lint && (yyvsp[(3) - (3)])->lasti->opcode == 
Op_match_rec)
                        lintwarn_ln((yyvsp[(2) - (3)])->source_line,
@@ -3366,19 +3371,19 @@ regular_print:
 
   case 111:
 /* Line 1787 of yacc.c  */
-#line 1246 "awkgram.y"
+#line 1251 "awkgram.y"
     {  (yyval) = mk_boolean((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) 
- (3)])); }
     break;
 
   case 112:
 /* Line 1787 of yacc.c  */
-#line 1248 "awkgram.y"
+#line 1253 "awkgram.y"
     {  (yyval) = mk_boolean((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) 
- (3)])); }
     break;
 
   case 113:
 /* Line 1787 of yacc.c  */
-#line 1250 "awkgram.y"
+#line 1255 "awkgram.y"
     {
                if ((yyvsp[(1) - (3)])->lasti->opcode == Op_match_rec)
                        warning_ln((yyvsp[(2) - (3)])->source_line,
@@ -3398,7 +3403,7 @@ regular_print:
 
   case 114:
 /* Line 1787 of yacc.c  */
-#line 1266 "awkgram.y"
+#line 1271 "awkgram.y"
     {
                if (do_lint_old)
                        warning_ln((yyvsp[(2) - (3)])->source_line,
@@ -3412,7 +3417,7 @@ regular_print:
 
   case 115:
 /* Line 1787 of yacc.c  */
-#line 1276 "awkgram.y"
+#line 1281 "awkgram.y"
     {
                if (do_lint && (yyvsp[(3) - (3)])->lasti->opcode == 
Op_match_rec)
                        lintwarn_ln((yyvsp[(2) - (3)])->source_line,
@@ -3423,31 +3428,31 @@ regular_print:
 
   case 116:
 /* Line 1787 of yacc.c  */
-#line 1283 "awkgram.y"
+#line 1288 "awkgram.y"
     { (yyval) = mk_condition((yyvsp[(1) - (5)]), (yyvsp[(2) - (5)]), 
(yyvsp[(3) - (5)]), (yyvsp[(4) - (5)]), (yyvsp[(5) - (5)])); }
     break;
 
   case 117:
 /* Line 1787 of yacc.c  */
-#line 1285 "awkgram.y"
+#line 1290 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 118:
 /* Line 1787 of yacc.c  */
-#line 1290 "awkgram.y"
+#line 1295 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 119:
 /* Line 1787 of yacc.c  */
-#line 1292 "awkgram.y"
+#line 1297 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 120:
 /* Line 1787 of yacc.c  */
-#line 1294 "awkgram.y"
+#line 1299 "awkgram.y"
     {  
                (yyvsp[(2) - (2)])->opcode = Op_assign_quotient;
                (yyval) = (yyvsp[(2) - (2)]);
@@ -3456,43 +3461,43 @@ regular_print:
 
   case 121:
 /* Line 1787 of yacc.c  */
-#line 1302 "awkgram.y"
+#line 1307 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 122:
 /* Line 1787 of yacc.c  */
-#line 1304 "awkgram.y"
+#line 1309 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 123:
 /* Line 1787 of yacc.c  */
-#line 1309 "awkgram.y"
+#line 1314 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 124:
 /* Line 1787 of yacc.c  */
-#line 1311 "awkgram.y"
+#line 1316 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 125:
 /* Line 1787 of yacc.c  */
-#line 1316 "awkgram.y"
+#line 1321 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 126:
 /* Line 1787 of yacc.c  */
-#line 1318 "awkgram.y"
+#line 1323 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 127:
 /* Line 1787 of yacc.c  */
-#line 1320 "awkgram.y"
+#line 1325 "awkgram.y"
     {
                int count = 2;
                bool is_simple_var = false;
@@ -3543,43 +3548,43 @@ regular_print:
 
   case 129:
 /* Line 1787 of yacc.c  */
-#line 1372 "awkgram.y"
+#line 1377 "awkgram.y"
     { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - 
(3)])); }
     break;
 
   case 130:
 /* Line 1787 of yacc.c  */
-#line 1374 "awkgram.y"
+#line 1379 "awkgram.y"
     { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - 
(3)])); }
     break;
 
   case 131:
 /* Line 1787 of yacc.c  */
-#line 1376 "awkgram.y"
+#line 1381 "awkgram.y"
     { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - 
(3)])); }
     break;
 
   case 132:
 /* Line 1787 of yacc.c  */
-#line 1378 "awkgram.y"
+#line 1383 "awkgram.y"
     { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - 
(3)])); }
     break;
 
   case 133:
 /* Line 1787 of yacc.c  */
-#line 1380 "awkgram.y"
+#line 1385 "awkgram.y"
     { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - 
(3)])); }
     break;
 
   case 134:
 /* Line 1787 of yacc.c  */
-#line 1382 "awkgram.y"
+#line 1387 "awkgram.y"
     { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - 
(3)])); }
     break;
 
   case 135:
 /* Line 1787 of yacc.c  */
-#line 1384 "awkgram.y"
+#line 1389 "awkgram.y"
     {
                /*
                 * In BEGINFILE/ENDFILE, allow `getline var < file'
@@ -3606,7 +3611,7 @@ regular_print:
 
   case 136:
 /* Line 1787 of yacc.c  */
-#line 1407 "awkgram.y"
+#line 1412 "awkgram.y"
     {
                (yyvsp[(2) - (2)])->opcode = Op_postincrement;
                (yyval) = mk_assignment((yyvsp[(1) - (2)]), NULL, (yyvsp[(2) - 
(2)]));
@@ -3615,7 +3620,7 @@ regular_print:
 
   case 137:
 /* Line 1787 of yacc.c  */
-#line 1412 "awkgram.y"
+#line 1417 "awkgram.y"
     {
                (yyvsp[(2) - (2)])->opcode = Op_postdecrement;
                (yyval) = mk_assignment((yyvsp[(1) - (2)]), NULL, (yyvsp[(2) - 
(2)]));
@@ -3624,7 +3629,7 @@ regular_print:
 
   case 138:
 /* Line 1787 of yacc.c  */
-#line 1417 "awkgram.y"
+#line 1422 "awkgram.y"
     {
                if (do_lint_old) {
                    warning_ln((yyvsp[(4) - (5)])->source_line,
@@ -3648,7 +3653,7 @@ regular_print:
 
   case 139:
 /* Line 1787 of yacc.c  */
-#line 1442 "awkgram.y"
+#line 1447 "awkgram.y"
     {
                  (yyval) = mk_getline((yyvsp[(3) - (4)]), (yyvsp[(4) - (4)]), 
(yyvsp[(1) - (4)]), (yyvsp[(2) - (4)])->redir_type);
                  bcfree((yyvsp[(2) - (4)]));
@@ -3657,43 +3662,43 @@ regular_print:
 
   case 140:
 /* Line 1787 of yacc.c  */
-#line 1448 "awkgram.y"
+#line 1453 "awkgram.y"
     { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - 
(3)])); }
     break;
 
   case 141:
 /* Line 1787 of yacc.c  */
-#line 1450 "awkgram.y"
+#line 1455 "awkgram.y"
     { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - 
(3)])); }
     break;
 
   case 142:
 /* Line 1787 of yacc.c  */
-#line 1452 "awkgram.y"
+#line 1457 "awkgram.y"
     { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - 
(3)])); }
     break;
 
   case 143:
 /* Line 1787 of yacc.c  */
-#line 1454 "awkgram.y"
+#line 1459 "awkgram.y"
     { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - 
(3)])); }
     break;
 
   case 144:
 /* Line 1787 of yacc.c  */
-#line 1456 "awkgram.y"
+#line 1461 "awkgram.y"
     { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - 
(3)])); }
     break;
 
   case 145:
 /* Line 1787 of yacc.c  */
-#line 1458 "awkgram.y"
+#line 1463 "awkgram.y"
     { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - 
(3)])); }
     break;
 
   case 146:
 /* Line 1787 of yacc.c  */
-#line 1463 "awkgram.y"
+#line 1468 "awkgram.y"
     {
                (yyval) = list_create((yyvsp[(1) - (1)]));
          }
@@ -3701,7 +3706,7 @@ regular_print:
 
   case 147:
 /* Line 1787 of yacc.c  */
-#line 1467 "awkgram.y"
+#line 1472 "awkgram.y"
     {
                if ((yyvsp[(2) - (2)])->opcode == Op_match_rec) {
                        (yyvsp[(2) - (2)])->opcode = Op_nomatch;
@@ -3737,13 +3742,13 @@ regular_print:
 
   case 148:
 /* Line 1787 of yacc.c  */
-#line 1499 "awkgram.y"
+#line 1504 "awkgram.y"
     { (yyval) = (yyvsp[(2) - (3)]); }
     break;
 
   case 149:
 /* Line 1787 of yacc.c  */
-#line 1501 "awkgram.y"
+#line 1506 "awkgram.y"
     {
                (yyval) = snode((yyvsp[(3) - (4)]), (yyvsp[(1) - (4)]));
                if ((yyval) == NULL)
@@ -3753,7 +3758,7 @@ regular_print:
 
   case 150:
 /* Line 1787 of yacc.c  */
-#line 1507 "awkgram.y"
+#line 1512 "awkgram.y"
     {
                (yyval) = snode((yyvsp[(3) - (4)]), (yyvsp[(1) - (4)]));
                if ((yyval) == NULL)
@@ -3763,7 +3768,7 @@ regular_print:
 
   case 151:
 /* Line 1787 of yacc.c  */
-#line 1513 "awkgram.y"
+#line 1518 "awkgram.y"
     {
                static bool warned = false;
 
@@ -3780,7 +3785,7 @@ regular_print:
 
   case 154:
 /* Line 1787 of yacc.c  */
-#line 1528 "awkgram.y"
+#line 1533 "awkgram.y"
     {
                (yyvsp[(1) - (2)])->opcode = Op_preincrement;
                (yyval) = mk_assignment((yyvsp[(2) - (2)]), NULL, (yyvsp[(1) - 
(2)]));
@@ -3789,7 +3794,7 @@ regular_print:
 
   case 155:
 /* Line 1787 of yacc.c  */
-#line 1533 "awkgram.y"
+#line 1538 "awkgram.y"
     {
                (yyvsp[(1) - (2)])->opcode = Op_predecrement;
                (yyval) = mk_assignment((yyvsp[(2) - (2)]), NULL, (yyvsp[(1) - 
(2)]));
@@ -3798,7 +3803,7 @@ regular_print:
 
   case 156:
 /* Line 1787 of yacc.c  */
-#line 1538 "awkgram.y"
+#line 1543 "awkgram.y"
     {
                (yyval) = list_create((yyvsp[(1) - (1)]));
          }
@@ -3806,7 +3811,7 @@ regular_print:
 
   case 157:
 /* Line 1787 of yacc.c  */
-#line 1542 "awkgram.y"
+#line 1547 "awkgram.y"
     {
                (yyval) = list_create((yyvsp[(1) - (1)]));
          }
@@ -3814,7 +3819,7 @@ regular_print:
 
   case 158:
 /* Line 1787 of yacc.c  */
-#line 1546 "awkgram.y"
+#line 1551 "awkgram.y"
     {
                if ((yyvsp[(2) - (2)])->lasti->opcode == Op_push_i
                        && ((yyvsp[(2) - (2)])->lasti->memory->flags & 
(STRCUR|STRING)) == 0
@@ -3833,7 +3838,7 @@ regular_print:
 
   case 159:
 /* Line 1787 of yacc.c  */
-#line 1561 "awkgram.y"
+#line 1566 "awkgram.y"
     {
            /*
             * was: $$ = $2
@@ -3847,7 +3852,7 @@ regular_print:
 
   case 160:
 /* Line 1787 of yacc.c  */
-#line 1574 "awkgram.y"
+#line 1579 "awkgram.y"
     {
                func_use((yyvsp[(1) - (1)])->lasti->func_name, FUNC_USE);
                (yyval) = (yyvsp[(1) - (1)]);
@@ -3856,7 +3861,7 @@ regular_print:
 
   case 161:
 /* Line 1787 of yacc.c  */
-#line 1579 "awkgram.y"
+#line 1584 "awkgram.y"
     {
                /* indirect function call */
                INSTRUCTION *f, *t;
@@ -3893,7 +3898,7 @@ regular_print:
 
   case 162:
 /* Line 1787 of yacc.c  */
-#line 1615 "awkgram.y"
+#line 1620 "awkgram.y"
     {
                param_sanity((yyvsp[(3) - (4)]));
                (yyvsp[(1) - (4)])->opcode = Op_func_call;
@@ -3911,37 +3916,37 @@ regular_print:
 
   case 163:
 /* Line 1787 of yacc.c  */
-#line 1632 "awkgram.y"
+#line 1637 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 164:
 /* Line 1787 of yacc.c  */
-#line 1634 "awkgram.y"
+#line 1639 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 165:
 /* Line 1787 of yacc.c  */
-#line 1639 "awkgram.y"
+#line 1644 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 166:
 /* Line 1787 of yacc.c  */
-#line 1641 "awkgram.y"
+#line 1646 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (2)]); }
     break;
 
   case 167:
 /* Line 1787 of yacc.c  */
-#line 1646 "awkgram.y"
+#line 1651 "awkgram.y"
     {  (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 168:
 /* Line 1787 of yacc.c  */
-#line 1648 "awkgram.y"
+#line 1653 "awkgram.y"
     {
                (yyval) = list_merge((yyvsp[(1) - (2)]), (yyvsp[(2) - (2)]));
          }
@@ -3949,7 +3954,7 @@ regular_print:
 
   case 169:
 /* Line 1787 of yacc.c  */
-#line 1655 "awkgram.y"
+#line 1660 "awkgram.y"
     {
                INSTRUCTION *ip = (yyvsp[(1) - (1)])->lasti; 
                int count = ip->sub_count;      /* # of SUBSEP-seperated 
expressions */
@@ -3967,7 +3972,7 @@ regular_print:
 
   case 170:
 /* Line 1787 of yacc.c  */
-#line 1672 "awkgram.y"
+#line 1677 "awkgram.y"
     {
                INSTRUCTION *t = (yyvsp[(2) - (3)]);
                if ((yyvsp[(2) - (3)]) == NULL) {
@@ -3985,13 +3990,13 @@ regular_print:
 
   case 171:
 /* Line 1787 of yacc.c  */
-#line 1689 "awkgram.y"
+#line 1694 "awkgram.y"
     {  (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 172:
 /* Line 1787 of yacc.c  */
-#line 1691 "awkgram.y"
+#line 1696 "awkgram.y"
     {
                (yyval) = list_merge((yyvsp[(1) - (2)]), (yyvsp[(2) - (2)]));
          }
@@ -3999,13 +4004,13 @@ regular_print:
 
   case 173:
 /* Line 1787 of yacc.c  */
-#line 1698 "awkgram.y"
+#line 1703 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (2)]); }
     break;
 
   case 174:
 /* Line 1787 of yacc.c  */
-#line 1703 "awkgram.y"
+#line 1708 "awkgram.y"
     {
                char *var_name = (yyvsp[(1) - (1)])->lextok;
 
@@ -4017,7 +4022,7 @@ regular_print:
 
   case 175:
 /* Line 1787 of yacc.c  */
-#line 1711 "awkgram.y"
+#line 1716 "awkgram.y"
     {
                char *arr = (yyvsp[(1) - (2)])->lextok;
                (yyvsp[(1) - (2)])->memory = variable((yyvsp[(1) - 
(2)])->source_line, arr, Node_var_new);
@@ -4028,7 +4033,7 @@ regular_print:
 
   case 176:
 /* Line 1787 of yacc.c  */
-#line 1721 "awkgram.y"
+#line 1726 "awkgram.y"
     {
                INSTRUCTION *ip = (yyvsp[(1) - (1)])->nexti;
                if (ip->opcode == Op_push
@@ -4044,7 +4049,7 @@ regular_print:
 
   case 177:
 /* Line 1787 of yacc.c  */
-#line 1733 "awkgram.y"
+#line 1738 "awkgram.y"
     {
                (yyval) = list_append((yyvsp[(2) - (3)]), (yyvsp[(1) - (3)]));
                if ((yyvsp[(3) - (3)]) != NULL)
@@ -4054,7 +4059,7 @@ regular_print:
 
   case 178:
 /* Line 1787 of yacc.c  */
-#line 1742 "awkgram.y"
+#line 1747 "awkgram.y"
     {
                (yyvsp[(1) - (1)])->opcode = Op_postincrement;
          }
@@ -4062,7 +4067,7 @@ regular_print:
 
   case 179:
 /* Line 1787 of yacc.c  */
-#line 1746 "awkgram.y"
+#line 1751 "awkgram.y"
     {
                (yyvsp[(1) - (1)])->opcode = Op_postdecrement;
          }
@@ -4070,43 +4075,43 @@ regular_print:
 
   case 180:
 /* Line 1787 of yacc.c  */
-#line 1749 "awkgram.y"
+#line 1754 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 182:
 /* Line 1787 of yacc.c  */
-#line 1757 "awkgram.y"
+#line 1762 "awkgram.y"
     { yyerrok; }
     break;
 
   case 183:
 /* Line 1787 of yacc.c  */
-#line 1761 "awkgram.y"
+#line 1766 "awkgram.y"
     { yyerrok; }
     break;
 
   case 186:
 /* Line 1787 of yacc.c  */
-#line 1770 "awkgram.y"
+#line 1775 "awkgram.y"
     { yyerrok; }
     break;
 
   case 187:
 /* Line 1787 of yacc.c  */
-#line 1774 "awkgram.y"
+#line 1779 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); yyerrok; }
     break;
 
   case 188:
 /* Line 1787 of yacc.c  */
-#line 1778 "awkgram.y"
+#line 1783 "awkgram.y"
     { yyerrok; }
     break;
 
 
 /* Line 1787 of yacc.c  */
-#line 4122 "awkgram.c"
+#line 4127 "awkgram.c"
       default: break;
     }
   /* User semantic actions sometimes alter yychar, and that requires
@@ -4336,7 +4341,7 @@ yyreturn:
 
 
 /* Line 2048 of yacc.c  */
-#line 1780 "awkgram.y"
+#line 1785 "awkgram.y"
 
 
 struct token {
@@ -6221,7 +6226,29 @@ retry:
                        yylval = bcalloc(tokentab[mid].value, 2, sourceline);
                        break;
 
+               /*
+                * These must be checked here, due to the LALR nature of the 
parser,
+                * the rules for continue and break may not be reduced until 
after
+                * a token that increments the xxx_allowed varibles is seen. 
Bleah.
+                */
+               case LEX_CONTINUE:
+                       if (! continue_allowed) {
+                               error_ln(sourceline,
+                                       _("`continue' is not allowed outside a 
loop"));
+                               errcount++;
+                       }
+                       goto make_instruction;
+
+               case LEX_BREAK:
+                       if (! break_allowed) {
+                               error_ln(sourceline,
+                                       _("`break' is not allowed outside a 
loop or switch"));
+                               errcount++;
+                       }
+                       goto make_instruction;
+
                default:
+make_instruction:
                        yylval = GET_INSTRUCTION(tokentab[mid].value);
                        if (class == LEX_BUILTIN || class == LEX_LENGTH)
                                yylval->builtin_idx = mid;
@@ -6961,6 +6988,8 @@ variable(int location, char *name, NODETYPE type)
                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);
+               if (r == symbol_table)
+                       symtab_used = true;
        } else {
                /* not found */
                struct deferred_variable *dv;
@@ -6982,6 +7011,21 @@ variable(int location, char *name, NODETYPE type)
        return r;
 }
 
+/* process_deferred --- if the program uses SYMTAB, load deferred variables */
+
+static void
+process_deferred()
+{
+       struct deferred_variable *dv;
+
+       if (! symtab_used)
+               return;
+
+       for (dv = deferred_variables; dv != NULL; dv = dv->next) {
+               (void) dv->load_func();
+       }
+}
+
 /* make_regnode --- make a regular expression node */
 
 static NODE *
diff --git a/awkgram.y b/awkgram.y
index 22b0b76..91e791a 100644
--- a/awkgram.y
+++ b/awkgram.y
@@ -76,6 +76,8 @@ static int count_expressions(INSTRUCTION **list, bool isarg);
 static INSTRUCTION *optimize_assignment(INSTRUCTION *exp);
 static void add_lint(INSTRUCTION *list, LINTTYPE linttype);
 
+static void process_deferred();
+
 enum defref { FUNC_DEFINE, FUNC_USE, FUNC_EXT };
 static void func_use(const char *name, enum defref how);
 static void check_funcs(void);
@@ -86,6 +88,7 @@ static int one_line_close(int fd);
 static bool want_source = false;
 static bool want_regexp;               /* lexical scanning kludge */
 static char *in_function;              /* parsing kludge */
+static bool symtab_used = false;       /* program used SYMTAB */
 static int rule = 0;
 
 const char *const ruletab[] = {
@@ -200,6 +203,8 @@ program
        | program LEX_EOF
          {
                next_sourcefile();
+               if (sourcefile == srcfiles)
+                       process_deferred();
          }
        | program error
          {
@@ -3661,7 +3666,29 @@ retry:
                        yylval = bcalloc(tokentab[mid].value, 2, sourceline);
                        break;
 
+               /*
+                * These must be checked here, due to the LALR nature of the 
parser,
+                * the rules for continue and break may not be reduced until 
after
+                * a token that increments the xxx_allowed varibles is seen. 
Bleah.
+                */
+               case LEX_CONTINUE:
+                       if (! continue_allowed) {
+                               error_ln(sourceline,
+                                       _("`continue' is not allowed outside a 
loop"));
+                               errcount++;
+                       }
+                       goto make_instruction;
+
+               case LEX_BREAK:
+                       if (! break_allowed) {
+                               error_ln(sourceline,
+                                       _("`break' is not allowed outside a 
loop or switch"));
+                               errcount++;
+                       }
+                       goto make_instruction;
+
                default:
+make_instruction:
                        yylval = GET_INSTRUCTION(tokentab[mid].value);
                        if (class == LEX_BUILTIN || class == LEX_LENGTH)
                                yylval->builtin_idx = mid;
@@ -4401,6 +4428,8 @@ variable(int location, char *name, NODETYPE type)
                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);
+               if (r == symbol_table)
+                       symtab_used = true;
        } else {
                /* not found */
                struct deferred_variable *dv;
@@ -4422,6 +4451,21 @@ variable(int location, char *name, NODETYPE type)
        return r;
 }
 
+/* process_deferred --- if the program uses SYMTAB, load deferred variables */
+
+static void
+process_deferred()
+{
+       struct deferred_variable *dv;
+
+       if (! symtab_used)
+               return;
+
+       for (dv = deferred_variables; dv != NULL; dv = dv->next) {
+               (void) dv->load_func();
+       }
+}
+
 /* make_regnode --- make a regular expression node */
 
 static NODE *
diff --git a/doc/ChangeLog b/doc/ChangeLog
index e0f8c2f..7613e26 100644
--- a/doc/ChangeLog
+++ b/doc/ChangeLog
@@ -1,3 +1,7 @@
+2012-10-19         Arnold D. Robbins     <address@hidden>
+
+       * gawk.texi: More doc on SYMTAB.
+
 2012-10-05         Arnold D. Robbins     <address@hidden>
 
        * Makefile.am (LN, install-data-hook, uninstall-hook): Removed. No
diff --git a/doc/api.texi b/doc/api.texi
index 9e3c288..ab4ea63 100644
--- a/doc/api.texi
+++ b/doc/api.texi
@@ -221,15 +221,41 @@ ISBN 1-882114-28-0 @*
 @node Extension API
 @chapter Writing Extensions for @command{gawk}
 
-This @value{CHAPTER} describes how to extend @command{gawk} using
+It is possible to add new built-in
+functions to @command{gawk} using dynamically loaded libraries. This
+facility is available on systems (such as GNU/Linux) that support
+the C @code{dlopen()} and @code{dlsym()} functions.
+This @value{CHAPTER} describes how to do so using
 code written in C or C++.  If you don't know anything about C
 programming, you can safely skip this @value{CHAPTER}, although you
 may wish to review the documentation on the extensions that come
 with @command{gawk} (@pxref{Extension Samples}).
 
address@hidden NOTE
+When @option{--sandbox} is specified, extensions are disabled
+(@pxref{Options}.
address@hidden quotation
+
 @menu
+* Plugin License::              A note about licensing.
 @end menu
 
address@hidden Plugin License
address@hidden Extension Licensing
+
+Every dynamic extension should define the global symbol
address@hidden to assert that it has been licensed under
+a GPL-compatible license.  If this symbol does not exist, @command{gawk}
+will emit a fatal error and exit.
+
+The declared type of the symbol should be @code{int}.  It does not need
+to be in any allocated section, though.  The code merely asserts that
+the symbol exists in the global scope.  Something like this is enough:
+
address@hidden
+int plugin_is_GPL_compatible;
address@hidden example
+
 @node Extension Intro
 @section Introduction
 
@@ -1599,11 +1625,593 @@ The others should not change during execution.
 @c It's enough to show chdir and stat, no need for fts
 
 @node Extension Samples
address@hidden Sample Extensions
address@hidden Example: Directory and File Operation Built-ins
+
+Two useful functions that are not in @command{awk} are @code{chdir()}
+(so that an @command{awk} program can change its directory) and
address@hidden()} (so that an @command{awk} program can gather information about
+a file).
+This @value{SECTION} implements these functions for @command{gawk} in an
+external extension.
 
 @menu
+* Internal File Description::   What the new functions will do.
+* Internal File Ops::           The code for internal file operations.
+* Using Internal File Ops::     How to use an external extension.
 @end menu
 
address@hidden Internal File Description
address@hidden Using @code{chdir()} and @code{stat()}
+
+This @value{SECTION} shows how to use the new functions at
+the @command{awk} level once they've been integrated into the
+running @command{gawk} interpreter.  Using @code{chdir()} is very
+straightforward. It takes one argument, the new directory to change to:
+
address@hidden
+@@load "filefuncs"
address@hidden
+newdir = "/home/arnold/funstuff"
+ret = chdir(newdir)
+if (ret < 0) @{
+    printf("could not change to %s: %s\n",
+                   newdir, ERRNO) > "/dev/stderr"
+    exit 1
address@hidden
address@hidden
address@hidden example
+
+The return value is negative if the @code{chdir()} failed, and
address@hidden (@pxref{Built-in Variables}) is set to a string indicating
+the error.
+
+Using @code{stat()} is a bit more complicated.  The C @code{stat()}
+function fills in a structure that has a fair amount of information.
+The right way to model this in @command{awk} is to fill in an associative
+array with the appropriate information:
+
address@hidden broke printf for page breaking
address@hidden
+file = "/home/arnold/.profile"
+# fdata[1] = "x"    # force `fdata' to be an array FIXME: IS THIS NEEDED
+ret = stat(file, fdata)
+if (ret < 0) @{
+    printf("could not stat %s: %s\n",
+             file, ERRNO) > "/dev/stderr"
+    exit 1
address@hidden
+printf("size of %s is %d bytes\n", file, fdata["size"])
address@hidden example
+
+The @code{stat()} function always clears the data array, even if
+the @code{stat()} fails.  It fills in the following elements:
+
address@hidden @code
address@hidden "name"
+The name of the file that was @code{stat()}'ed.
+
address@hidden "dev"
address@hidden "ino"
+The file's device and inode numbers, respectively.
+
address@hidden "mode"
+The file's mode, as a numeric value. This includes both the file's
+type and its permissions.
+
address@hidden "nlink"
+The number of hard links (directory entries) the file has.
+
address@hidden "uid"
address@hidden "gid"
+The numeric user and group ID numbers of the file's owner.
+
address@hidden "size"
+The size in bytes of the file.
+
address@hidden "blocks"
+The number of disk blocks the file actually occupies. This may not
+be a function of the file's size if the file has holes.
+
address@hidden "atime"
address@hidden "mtime"
address@hidden "ctime"
+The file's last access, modification, and inode update times,
+respectively.  These are numeric timestamps, suitable for formatting
+with @code{strftime()}
+(@pxref{Built-in}).
+
address@hidden "pmode"
+The file's ``printable mode.''  This is a string representation of
+the file's type and permissions, such as what is produced by
address@hidden -l}---for example, @code{"drwxr-xr-x"}.
+
address@hidden "type"
+A printable string representation of the file's type.  The value
+is one of the following:
+
address@hidden @code
address@hidden "blockdev"
address@hidden "chardev"
+The file is a block or character device (``special file'').
+
address@hidden
address@hidden "door"
+The file is a Solaris ``door'' (special file used for
+interprocess communications).
address@hidden ignore
+
address@hidden "directory"
+The file is a directory.
+
address@hidden "fifo"
+The file is a named-pipe (also known as a FIFO).
+
address@hidden "file"
+The file is just a regular file.
+
address@hidden "socket"
+The file is an @code{AF_UNIX} (``Unix domain'') socket in the
+filesystem.
+
address@hidden "symlink"
+The file is a symbolic link.
address@hidden table
address@hidden table
+
+Several additional elements may be present depending upon the operating
+system and the type of the file.  You can test for them in your @command{awk}
+program by using the @code{in} operator
+(@pxref{Reference to Elements}):
+
address@hidden @code
address@hidden "blksize"
+The preferred block size for I/O to the file. This field is not
+present on all POSIX-like systems in the C @code{stat} structure.
+
address@hidden "linkval"
+If the file is a symbolic link, this element is the name of the
+file the link points to (i.e., the value of the link).
+
address@hidden "rdev"
address@hidden "major"
address@hidden "minor"
+If the file is a block or character device file, then these values
+represent the numeric device number and the major and minor components
+of that number, respectively.
address@hidden table
+
address@hidden Internal File Ops
address@hidden C Code for @code{chdir()} and @code{stat()}
+
+Here is the C code for these address@hidden version is
+edited slightly for presentation.  See @file{extension/filefuncs.c}
+in the @command{gawk} distribution for the complete version.}
+
address@hidden break line for page breaking
address@hidden
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "gawkapi.h"
+
+#include "gettext.h"
+#define _(msgid)  gettext(msgid)
+#define N_(msgid) msgid
+
+#include "gawkfts.h"
+#include "stack.h"
+
+static const gawk_api_t *api;  /* for convenience macros to work */
+static awk_ext_id_t *ext_id;
+static awk_bool_t init_filefuncs(void);
+static awk_bool_t (*init_func)(void) = init_filefuncs;
+static const char *ext_version = "filefuncs extension: version 1.0";
+
+int plugin_is_GPL_compatible;
+
+/*  do_chdir --- provide dynamically loaded chdir() builtin for gawk */
+
+static awk_value_t *
+do_chdir(int nargs, awk_value_t *result)
address@hidden
+    awk_value_t newdir;
+    int ret = -1;
+
+    assert(result != NULL);
+
+    if (do_lint && nargs != 1)
+        lintwarn(ext_id, _("chdir: called with incorrect number of arguments, 
expecting 1"));
address@hidden example
+
+The file includes
+a number of standard header files, and then includes the
address@hidden"gawkapi.h"} header file which provides the API definitions.
+
address@hidden programming conventions, @command{gawk} internals
+By convention, for an @command{awk} function @code{foo()}, the function that
+implements it is called @samp{do_foo()}.  The function should have two
+arguments: the first is an
address@hidden usually called @code{nargs}, that
+represents the number of defined arguments for the function.
+The second is a pointer to an @code{awk_result_t}, usally named
address@hidden
+The @code{newdir}
+variable represents the new directory to change to, retrieved
+with @code{get_argument()}.  Note that the first argument is
+numbered zero.
+
+This code actually accomplishes the @code{chdir()}. It first forces
+the argument to be a string and passes the string value to the
address@hidden()} system call. If the @code{chdir()} fails, @code{ERRNO}
+is updated.
+
address@hidden
+    if (get_argument(0, AWK_STRING, & newdir)) @{
+        ret = chdir(newdir.str_value.str);
+        if (ret < 0)
+            update_ERRNO_int(errno);
+    @}
address@hidden example
+
+Finally, the function returns the return value to the @command{awk} level:
+
address@hidden
+    return make_number(ret, result);
address@hidden
address@hidden example
+
+The @code{stat()} built-in is more involved.  First comes a function
+that turns a numeric mode into a printable representation
+(e.g., 644 becomes @samp{-rw-r--r--}). This is omitted here for brevity:
+
address@hidden break line for page breaking
address@hidden
+/* format_mode --- turn a stat mode field into something readable */
+
+static char *
+format_mode(unsigned long fmode)
address@hidden
+    @dots{}
address@hidden
address@hidden example
+
+Next comes a function for reading symbolic links, which is also
+omitted here for brevity:
+
address@hidden
+/* read_symlink -- read a symbolic link into an allocated buffer.
+   @dots{} */
+
+static char *
+read_symlink(const char *fname, size_t bufsize, ssize_t *linksize)
address@hidden
+    @dots{}
address@hidden
address@hidden example
+
+Two helper functions simplify entering values in the
+array that will contain the result of the @code{stat()}:
+
address@hidden
+/* array_set --- set an array element */
+
+static void
+array_set(awk_array_t array, const char *sub, awk_value_t *value)
address@hidden
+    awk_value_t index;
+
+    set_array_element(array,
+                      make_const_string(sub, strlen(sub), & index),
+                      value);
+
address@hidden
+
+/* array_set_numeric --- set an array element with a number */
+
+static void
+array_set_numeric(awk_array_t array, const char *sub, double num)
address@hidden
+    awk_value_t tmp;
+
+    array_set(array, sub, make_number(num, & tmp));
address@hidden
address@hidden example
+
+The following function does most of the work to fill in
+the @code{awk_array_t} result array with values obtained
+from a valid @code{struct stat}. It is done in a separate function
+to support the @code{stat()} function for @command{gawk} and also
+to support the @code{fts()} extension which is included in
+the same file but whose code is not shown here. (FIXME: XREF to section
+with documentation.)
+
address@hidden
+/* fill_stat_array --- do the work to fill an array with stat info */
+
+static int
+fill_stat_array(const char *name, awk_array_t array, struct stat *sbuf)
address@hidden
+    char *pmode;    /* printable mode */
+    const char *type = "unknown";
+    awk_value_t tmp;
+    static struct ftype_map @{
+        unsigned int mask;
+        const char *type;
+    @} ftype_map[] = @{
+        @{ S_IFREG, "file" @},
+        @{ S_IFBLK, "blockdev" @},
+        @{ S_IFCHR, "chardev" @},
+        @{ S_IFDIR, "directory" @},
+#ifdef S_IFSOCK
+        @{ S_IFSOCK, "socket" @},
+#endif
+#ifdef S_IFIFO
+        @{ S_IFIFO, "fifo" @},
+#endif
+#ifdef S_IFLNK
+        @{ S_IFLNK, "symlink" @},
+#endif
+#ifdef S_IFDOOR /* Solaris weirdness */
+        @{ S_IFDOOR, "door" @},
+#endif /* S_IFDOOR */
+    @};
+    int j, k;
+
+    /* empty out the array */
+    clear_array(array);
+
+    /* fill in the array */
+    array_set(array, "name", make_const_string(name, strlen(name), & tmp));
+    array_set_numeric(array, "dev", sbuf->st_dev);
+    array_set_numeric(array, "ino", sbuf->st_ino);
+    array_set_numeric(array, "mode", sbuf->st_mode);
+    array_set_numeric(array, "nlink", sbuf->st_nlink);
+    array_set_numeric(array, "uid", sbuf->st_uid);
+    array_set_numeric(array, "gid", sbuf->st_gid);
+    array_set_numeric(array, "size", sbuf->st_size);
+    array_set_numeric(array, "blocks", sbuf->st_blocks);
+    array_set_numeric(array, "atime", sbuf->st_atime);
+    array_set_numeric(array, "mtime", sbuf->st_mtime);
+    array_set_numeric(array, "ctime", sbuf->st_ctime);
+
+    /* for block and character devices, add rdev, major and minor numbers */
+    if (S_ISBLK(sbuf->st_mode) || S_ISCHR(sbuf->st_mode)) @{
+        array_set_numeric(array, "rdev", sbuf->st_rdev);
+        array_set_numeric(array, "major", major(sbuf->st_rdev));
+        array_set_numeric(array, "minor", minor(sbuf->st_rdev));
+    @}
+
+#ifdef HAVE_ST_BLKSIZE
+    array_set_numeric(array, "blksize", sbuf->st_blksize);
+#endif /* HAVE_ST_BLKSIZE */
+
+    pmode = format_mode(sbuf->st_mode);
+    array_set(array, "pmode", make_const_string(pmode, strlen(pmode), & tmp));
+
+    /* for symbolic links, add a linkval field */
+    if (S_ISLNK(sbuf->st_mode)) @{
+        char *buf;
+        ssize_t linksize;
+
+        if ((buf = read_symlink(name, sbuf->st_size,
+                    & linksize)) != NULL)
+            array_set(array, "linkval", make_malloced_string(buf, linksize, & 
tmp));
+        else
+            warning(ext_id, "stat: unable to read symbolic link `%s'", name);
+    @}
+
+    /* add a type field */
+    type = "unknown";   /* shouldn't happen */
+    for (j = 0, k = sizeof(ftype_map)/sizeof(ftype_map[0]); j < k; j++) @{
+        if ((sbuf->st_mode & S_IFMT) == ftype_map[j].mask) @{
+            type = ftype_map[j].type;
+            break;
+        @}
+    @}
+
+    array_set(array, "type", make_const_string(type, strlen(type), &tmp));
+
+    return 0;
address@hidden
address@hidden example
+
+Finall, here is the @code{do_stat()} function. It starts with
+variable declarations and argument checking:
+
address@hidden
+Changed message for page breaking. Used to be:
+    "stat: called with incorrect number of arguments (%d), should be 2",
address@hidden ignore
address@hidden
+/* do_stat --- provide a stat() function for gawk */
+
+static awk_value_t *
+do_stat(int nargs, awk_value_t *result)
address@hidden
+    awk_value_t file_param, array_param;
+    char *name;
+    awk_array_t array;
+    int ret;
+    struct stat sbuf;
+
+    assert(result != NULL);
+
+    if (do_lint && nargs != 2) @{
+        lintwarn(ext_id, _("stat: called with wrong number of arguments"));
+        return make_number(-1, result);
+    @}
address@hidden example
+
+Then comes the actual work. First, the function gets the arguments.
+Next, it gets the information for the file.
+The code use @code{lstat()} (instead of @code{stat()})
+to get the file information,
+in case the file is a symbolic link.
+If there's an error, it sets @code{ERRNO} and returns:
+
address@hidden
+    /* file is first arg, array to hold results is second */
+    if (   ! get_argument(0, AWK_STRING, & file_param)
+        || ! get_argument(1, AWK_ARRAY, & array_param)) @{
+        warning(ext_id, _("stat: bad parameters"));
+        return make_number(-1, result);
+    @}
+
+    name = file_param.str_value.str;
+    array = array_param.array_cookie;
+
+    /* lstat the file, if error, set ERRNO and return */
+    ret = lstat(name, & sbuf);
+    if (ret < 0) @{
+        update_ERRNO_int(errno);
+        return make_number(ret, result);
+    @}
address@hidden example
+
+The tedious work is done by @code{fill_stat_array()}, shown
+earlier.
+When done, return the result from @code{fill_stat_array()}:
+
address@hidden
+    ret = fill_stat_array(name, array, & sbuf);
+
+    return make_number(ret, result);
address@hidden
address@hidden example
+
address@hidden programming conventions, @command{gawk} internals
+Finally, it's necessary to provide the ``glue'' that loads the
+new function(s) into @command{gawk}.
+
+The @samp{filefuncs} extension also provides an @code{fts()}
+function, which we omit here. For its sake there is an initialization
+function:
+
address@hidden
+/* init_filefuncs --- initialization routine */
+
+static awk_bool_t
+init_filefuncs(void)
address@hidden
+    @dots{}
address@hidden
address@hidden example
+
+Almost done. We need an array of @code{awk_ext_func_t}
+structures for loading each function into @command{gawk}:
+
address@hidden
+static awk_ext_func_t func_table[] = @{
+    @{ "chdir", do_chdir, 1 @},
+    @{ "stat",  do_stat, 2 @},
+    @{ "fts",   do_fts, 3 @},
address@hidden;
address@hidden example
+
+Each extension must have a routine named @code{dl_load()} to load
+everything that needs to be loaded.  The simplest way is to use the
address@hidden macro in @code{gawkapi.h}:
+
address@hidden
+/* define the dl_load function using the boilerplate macro */
+
+dl_load_func(func_table, filefuncs, "")
address@hidden example
+
+And that's it!  As an exercise, consider adding functions to
+implement system calls such as @code{chown()}, @code{chmod()},
+and @code{umask()}.
+
address@hidden Using Internal File Ops
address@hidden Integrating the Extensions
+
address@hidden @command{gawk}, address@hidden adding code to
+Now that the code is written, it must be possible to add it at
+runtime to the running @command{gawk} interpreter.  First, the
+code must be compiled.  Assuming that the functions are in
+a file named @file{filefuncs.c}, and @var{idir} is the location
+of the @command{gawk} include files,
+the following steps create
+a GNU/Linux shared library:
+
address@hidden
+$ @kbd{gcc -fPIC -shared -DHAVE_CONFIG_H -c -O -g address@hidden filefuncs.c}
+$ @kbd{ld -o filefuncs.so -shared filefuncs.o}
address@hidden example
+
address@hidden @code{extension()} function (@command{gawk})
+Once the library exists, it is loaded by calling the @code{extension()}
+built-in function.
+This function takes two arguments: the name of the
+library to load and the name of a function to call when the library
+is first loaded. This function adds the new functions to @command{gawk}.
+It returns the value returned by the initialization function
+within the shared library:
+
address@hidden
+# file testff.awk
+BEGIN @{
+    extension("./filefuncs.so", "dl_load")
+
+    chdir(".")  # no-op
+
+    data[1] = 1 # force `data' to be an array
+    print "Info for testff.awk"
+    ret = stat("testff.awk", data)
+    print "ret =", ret
+    for (i in data)
+        printf "data[\"%s\"] = %s\n", i, data[i]
+    print "testff.awk modified:",
+        strftime("%m %d %y %H:%M:%S", data["mtime"])
+
+    print "\nInfo for JUNK"
+    ret = stat("JUNK", data)
+    print "ret =", ret
+    for (i in data)
+        printf "data[\"%s\"] = %s\n", i, data[i]
+    print "JUNK modified:", strftime("%m %d %y %H:%M:%S", data["mtime"])
address@hidden
address@hidden example
+
+Here are the results of running the program:
+
address@hidden
+$ @kbd{gawk -f testff.awk}
address@hidden Info for testff.awk
address@hidden ret = 0
address@hidden data["size"] = 607
address@hidden data["ino"] = 14945891
address@hidden data["name"] = testff.awk
address@hidden data["pmode"] = -rw-rw-r--
address@hidden data["nlink"] = 1
address@hidden data["atime"] = 1293993369
address@hidden data["mtime"] = 1288520752
address@hidden data["mode"] = 33204
address@hidden data["blksize"] = 4096
address@hidden data["dev"] = 2054
address@hidden data["type"] = file
address@hidden data["gid"] = 500
address@hidden data["uid"] = 500
address@hidden data["blocks"] = 8
address@hidden data["ctime"] = 1290113572
address@hidden testff.awk modified: 10 31 10 12:25:52
address@hidden 
address@hidden Info for JUNK
address@hidden ret = -1
address@hidden JUNK modified: 01 01 70 02:00:00
address@hidden example
+
 @node Extension Sample File Functions
 @subsection File Related Functions
 
diff --git a/doc/gawk.info b/doc/gawk.info
index 08fbc29..b97acf4 100644
--- a/doc/gawk.info
+++ b/doc/gawk.info
@@ -9750,6 +9750,27 @@ with a pound sign (`#').
      test if an element in `SYMTAB' is an array.  Also, you may not use
      the `delete' statement with the `SYMTAB' array.
 
+     You may use an index for `SYMTAB' that is not a predefined
+     identifer:
+
+          SYMTAB["xxx"] = 5
+          print SYMTAB["xxx"]
+
+     This works as expected: in this case `SYMTAB' acts just like a
+     regular array.  The only difference is that you can't then delete
+     `SYMTAB["xxx"]'.
+
+     The `SYMTAB' array is more interesting than it looks. Andrew Schorr
+     points out that it effectively gives `awk' data pointers. Consider
+     his example:
+
+          # Indirect multiply of any variable by amount, return result
+
+          function multiply(variable, amount)
+          {
+              return SYMTAB[variable] *= amount
+          }
+
           NOTE: In order to avoid severe time-travel paradoxes(2),
           neither `FUNCTAB' nor `SYMTAB' are available as elements
           within the `SYMTAB' array.
@@ -26022,7 +26043,7 @@ Index
                                                               (line  67)
 * advanced features, data files as single record: Records.    (line 180)
 * advanced features, fixed-width data:   Constant Size.       (line   9)
-* advanced features, FNR/NR variables:   Auto-set.            (line 274)
+* advanced features, FNR/NR variables:   Auto-set.            (line 295)
 * advanced features, gawk:               Advanced Features.   (line   6)
 * advanced features, gawk, network programming: TCP/IP Networking.
                                                               (line   6)
@@ -26527,7 +26548,7 @@ Index
                                                               (line  47)
 * dark corner, FILENAME variable <1>:    Auto-set.            (line  93)
 * dark corner, FILENAME variable:        Getline Notes.       (line  19)
-* dark corner, FNR/NR variables:         Auto-set.            (line 274)
+* dark corner, FNR/NR variables:         Auto-set.            (line 295)
 * dark corner, format-control characters: Control Letters.    (line  18)
 * dark corner, FS as null string:        Single Character Fields.
                                                               (line  20)
@@ -27009,7 +27030,7 @@ Index
 * floating-point, numbers:               General Arithmetic.  (line   6)
 * FNR variable <1>:                      Auto-set.            (line 103)
 * FNR variable:                          Records.             (line   6)
-* FNR variable, changing:                Auto-set.            (line 274)
+* FNR variable, changing:                Auto-set.            (line 295)
 * for statement:                         For Statement.       (line   6)
 * for statement, in arrays:              Scanning an Array.   (line  20)
 * format specifiers, mixing regular with positional specifiers: Printf 
Ordering.
@@ -27594,7 +27615,7 @@ Index
 * not Boolean-logic operator:            Boolean Ops.         (line   6)
 * NR variable <1>:                       Auto-set.            (line 125)
 * NR variable:                           Records.             (line   6)
-* NR variable, changing:                 Auto-set.            (line 274)
+* NR variable, changing:                 Auto-set.            (line 295)
 * null strings <1>:                      Basic Data Typing.   (line  26)
 * null strings <2>:                      Truth Values.        (line   6)
 * null strings <3>:                      Regexp Field Splitting.
@@ -28674,265 +28695,265 @@ Node: Built-in Variables393879
 Node: User-modified394974
 Ref: User-modified-Footnote-1403329
 Node: Auto-set403391
-Ref: Auto-set-Footnote-1415085
-Ref: Auto-set-Footnote-2415290
-Node: ARGC and ARGV415346
-Node: Arrays419197
-Node: Array Basics420702
-Node: Array Intro421528
-Node: Reference to Elements425846
-Node: Assigning Elements428116
-Node: Array Example428607
-Node: Scanning an Array430339
-Node: Controlling Scanning432653
-Ref: Controlling Scanning-Footnote-1437586
-Node: Delete437902
-Ref: Delete-Footnote-1440667
-Node: Numeric Array Subscripts440724
-Node: Uninitialized Subscripts442907
-Node: Multi-dimensional444535
-Node: Multi-scanning447629
-Node: Arrays of Arrays449220
-Node: Functions453865
-Node: Built-in454687
-Node: Calling Built-in455765
-Node: Numeric Functions457753
-Ref: Numeric Functions-Footnote-1461585
-Ref: Numeric Functions-Footnote-2461942
-Ref: Numeric Functions-Footnote-3461990
-Node: String Functions462259
-Ref: String Functions-Footnote-1485756
-Ref: String Functions-Footnote-2485885
-Ref: String Functions-Footnote-3486133
-Node: Gory Details486220
-Ref: table-sub-escapes487899
-Ref: table-sub-posix-92489253
-Ref: table-sub-proposed490596
-Ref: table-posix-sub491946
-Ref: table-gensub-escapes493492
-Ref: Gory Details-Footnote-1494699
-Ref: Gory Details-Footnote-2494750
-Node: I/O Functions494901
-Ref: I/O Functions-Footnote-1501556
-Node: Time Functions501703
-Ref: Time Functions-Footnote-1512595
-Ref: Time Functions-Footnote-2512663
-Ref: Time Functions-Footnote-3512821
-Ref: Time Functions-Footnote-4512932
-Ref: Time Functions-Footnote-5513044
-Ref: Time Functions-Footnote-6513271
-Node: Bitwise Functions513537
-Ref: table-bitwise-ops514095
-Ref: Bitwise Functions-Footnote-1518316
-Node: Type Functions518500
-Node: I18N Functions518970
-Node: User-defined520597
-Node: Definition Syntax521401
-Ref: Definition Syntax-Footnote-1526311
-Node: Function Example526380
-Node: Function Caveats528974
-Node: Calling A Function529395
-Node: Variable Scope530510
-Node: Pass By Value/Reference532485
-Node: Return Statement535925
-Node: Dynamic Typing538906
-Node: Indirect Calls539641
-Node: Internationalization549326
-Node: I18N and L10N550752
-Node: Explaining gettext551438
-Ref: Explaining gettext-Footnote-1556504
-Ref: Explaining gettext-Footnote-2556688
-Node: Programmer i18n556853
-Node: Translator i18n561053
-Node: String Extraction561846
-Ref: String Extraction-Footnote-1562807
-Node: Printf Ordering562893
-Ref: Printf Ordering-Footnote-1565677
-Node: I18N Portability565741
-Ref: I18N Portability-Footnote-1568190
-Node: I18N Example568253
-Ref: I18N Example-Footnote-1570888
-Node: Gawk I18N570960
-Node: Advanced Features571577
-Node: Nondecimal Data573090
-Node: Array Sorting574673
-Node: Controlling Array Traversal575370
-Node: Array Sorting Functions583608
-Ref: Array Sorting Functions-Footnote-1587282
-Ref: Array Sorting Functions-Footnote-2587375
-Node: Two-way I/O587569
-Ref: Two-way I/O-Footnote-1593001
-Node: TCP/IP Networking593071
-Node: Profiling595915
-Node: Library Functions603369
-Ref: Library Functions-Footnote-1606376
-Node: Library Names606547
-Ref: Library Names-Footnote-1610018
-Ref: Library Names-Footnote-2610238
-Node: General Functions610324
-Node: Strtonum Function611277
-Node: Assert Function614207
-Node: Round Function617533
-Node: Cliff Random Function619076
-Node: Ordinal Functions620092
-Ref: Ordinal Functions-Footnote-1623162
-Ref: Ordinal Functions-Footnote-2623414
-Node: Join Function623623
-Ref: Join Function-Footnote-1625394
-Node: Getlocaltime Function625594
-Node: Data File Management629309
-Node: Filetrans Function629941
-Node: Rewind Function634080
-Node: File Checking635467
-Node: Empty Files636561
-Node: Ignoring Assigns638791
-Node: Getopt Function640344
-Ref: Getopt Function-Footnote-1651648
-Node: Passwd Functions651851
-Ref: Passwd Functions-Footnote-1660826
-Node: Group Functions660914
-Node: Walking Arrays668998
-Node: Sample Programs670567
-Node: Running Examples671232
-Node: Clones671960
-Node: Cut Program673184
-Node: Egrep Program683029
-Ref: Egrep Program-Footnote-1690802
-Node: Id Program690912
-Node: Split Program694528
-Ref: Split Program-Footnote-1698047
-Node: Tee Program698175
-Node: Uniq Program700978
-Node: Wc Program708407
-Ref: Wc Program-Footnote-1712673
-Ref: Wc Program-Footnote-2712873
-Node: Miscellaneous Programs712965
-Node: Dupword Program714153
-Node: Alarm Program716184
-Node: Translate Program720933
-Ref: Translate Program-Footnote-1725320
-Ref: Translate Program-Footnote-2725548
-Node: Labels Program725682
-Ref: Labels Program-Footnote-1729053
-Node: Word Sorting729137
-Node: History Sorting733021
-Node: Extract Program734860
-Ref: Extract Program-Footnote-1742343
-Node: Simple Sed742471
-Node: Igawk Program745533
-Ref: Igawk Program-Footnote-1760690
-Ref: Igawk Program-Footnote-2760891
-Node: Anagram Program761029
-Node: Signature Program764097
-Node: Debugger765197
-Node: Debugging766163
-Node: Debugging Concepts766596
-Node: Debugging Terms768452
-Node: Awk Debugging771049
-Node: Sample Debugging Session771941
-Node: Debugger Invocation772461
-Node: Finding The Bug773790
-Node: List of Debugger Commands780278
-Node: Breakpoint Control781612
-Node: Debugger Execution Control785276
-Node: Viewing And Changing Data788636
-Node: Execution Stack791992
-Node: Debugger Info793459
-Node: Miscellaneous Debugger Commands797440
-Node: Readline Support802885
-Node: Limitations803716
-Node: Arbitrary Precision Arithmetic805968
-Ref: Arbitrary Precision Arithmetic-Footnote-1807610
-Node: General Arithmetic807758
-Node: Floating Point Issues809478
-Node: String Conversion Precision810359
-Ref: String Conversion Precision-Footnote-1812065
-Node: Unexpected Results812174
-Node: POSIX Floating Point Problems814327
-Ref: POSIX Floating Point Problems-Footnote-1818152
-Node: Integer Programming818190
-Node: Floating-point Programming819943
-Ref: Floating-point Programming-Footnote-1826252
-Node: Floating-point Representation826516
-Node: Floating-point Context827681
-Ref: table-ieee-formats828523
-Node: Rounding Mode829907
-Ref: table-rounding-modes830386
-Ref: Rounding Mode-Footnote-1833390
-Node: Gawk and MPFR833571
-Node: Arbitrary Precision Floats834813
-Ref: Arbitrary Precision Floats-Footnote-1837242
-Node: Setting Precision837553
-Node: Setting Rounding Mode840286
-Ref: table-gawk-rounding-modes840690
-Node: Floating-point Constants841870
-Node: Changing Precision843294
-Ref: Changing Precision-Footnote-1844694
-Node: Exact Arithmetic844868
-Node: Arbitrary Precision Integers847976
-Ref: Arbitrary Precision Integers-Footnote-1850976
-Node: Dynamic Extensions851123
-Node: Plugin License852041
-Node: Sample Library852655
-Node: Internal File Description853339
-Node: Internal File Ops857052
-Ref: Internal File Ops-Footnote-1861615
-Node: Using Internal File Ops861755
-Node: Language History864131
-Node: V7/SVR3.1865653
-Node: SVR4867974
-Node: POSIX869416
-Node: BTL870424
-Node: POSIX/GNU871158
-Node: Common Extensions876693
-Node: Ranges and Locales877800
-Ref: Ranges and Locales-Footnote-1882418
-Ref: Ranges and Locales-Footnote-2882445
-Ref: Ranges and Locales-Footnote-3882705
-Node: Contributors882926
-Node: Installation887222
-Node: Gawk Distribution888116
-Node: Getting888600
-Node: Extracting889426
-Node: Distribution contents891118
-Node: Unix Installation896340
-Node: Quick Installation896957
-Node: Additional Configuration Options898919
-Node: Configuration Philosophy900396
-Node: Non-Unix Installation902738
-Node: PC Installation903196
-Node: PC Binary Installation904495
-Node: PC Compiling906343
-Node: PC Testing909287
-Node: PC Using910463
-Node: Cygwin914648
-Node: MSYS915648
-Node: VMS Installation916162
-Node: VMS Compilation916765
-Ref: VMS Compilation-Footnote-1917772
-Node: VMS Installation Details917830
-Node: VMS Running919465
-Node: VMS Old Gawk921072
-Node: Bugs921546
-Node: Other Versions925398
-Node: Notes930713
-Node: Compatibility Mode931300
-Node: Additions932083
-Node: Accessing The Source933010
-Node: Adding Code934436
-Node: New Ports940478
-Node: Derived Files944613
-Ref: Derived Files-Footnote-1949918
-Ref: Derived Files-Footnote-2949952
-Ref: Derived Files-Footnote-3950552
-Node: Future Extensions950650
-Node: Basic Concepts952137
-Node: Basic High Level952818
-Ref: Basic High Level-Footnote-1956853
-Node: Basic Data Typing957038
-Node: Glossary960393
-Node: Copying985568
-Node: GNU Free Documentation License1023125
-Node: Index1048262
+Ref: Auto-set-Footnote-1415742
+Ref: Auto-set-Footnote-2415947
+Node: ARGC and ARGV416003
+Node: Arrays419854
+Node: Array Basics421359
+Node: Array Intro422185
+Node: Reference to Elements426503
+Node: Assigning Elements428773
+Node: Array Example429264
+Node: Scanning an Array430996
+Node: Controlling Scanning433310
+Ref: Controlling Scanning-Footnote-1438243
+Node: Delete438559
+Ref: Delete-Footnote-1441324
+Node: Numeric Array Subscripts441381
+Node: Uninitialized Subscripts443564
+Node: Multi-dimensional445192
+Node: Multi-scanning448286
+Node: Arrays of Arrays449877
+Node: Functions454522
+Node: Built-in455344
+Node: Calling Built-in456422
+Node: Numeric Functions458410
+Ref: Numeric Functions-Footnote-1462242
+Ref: Numeric Functions-Footnote-2462599
+Ref: Numeric Functions-Footnote-3462647
+Node: String Functions462916
+Ref: String Functions-Footnote-1486413
+Ref: String Functions-Footnote-2486542
+Ref: String Functions-Footnote-3486790
+Node: Gory Details486877
+Ref: table-sub-escapes488556
+Ref: table-sub-posix-92489910
+Ref: table-sub-proposed491253
+Ref: table-posix-sub492603
+Ref: table-gensub-escapes494149
+Ref: Gory Details-Footnote-1495356
+Ref: Gory Details-Footnote-2495407
+Node: I/O Functions495558
+Ref: I/O Functions-Footnote-1502213
+Node: Time Functions502360
+Ref: Time Functions-Footnote-1513252
+Ref: Time Functions-Footnote-2513320
+Ref: Time Functions-Footnote-3513478
+Ref: Time Functions-Footnote-4513589
+Ref: Time Functions-Footnote-5513701
+Ref: Time Functions-Footnote-6513928
+Node: Bitwise Functions514194
+Ref: table-bitwise-ops514752
+Ref: Bitwise Functions-Footnote-1518973
+Node: Type Functions519157
+Node: I18N Functions519627
+Node: User-defined521254
+Node: Definition Syntax522058
+Ref: Definition Syntax-Footnote-1526968
+Node: Function Example527037
+Node: Function Caveats529631
+Node: Calling A Function530052
+Node: Variable Scope531167
+Node: Pass By Value/Reference533142
+Node: Return Statement536582
+Node: Dynamic Typing539563
+Node: Indirect Calls540298
+Node: Internationalization549983
+Node: I18N and L10N551409
+Node: Explaining gettext552095
+Ref: Explaining gettext-Footnote-1557161
+Ref: Explaining gettext-Footnote-2557345
+Node: Programmer i18n557510
+Node: Translator i18n561710
+Node: String Extraction562503
+Ref: String Extraction-Footnote-1563464
+Node: Printf Ordering563550
+Ref: Printf Ordering-Footnote-1566334
+Node: I18N Portability566398
+Ref: I18N Portability-Footnote-1568847
+Node: I18N Example568910
+Ref: I18N Example-Footnote-1571545
+Node: Gawk I18N571617
+Node: Advanced Features572234
+Node: Nondecimal Data573747
+Node: Array Sorting575330
+Node: Controlling Array Traversal576027
+Node: Array Sorting Functions584265
+Ref: Array Sorting Functions-Footnote-1587939
+Ref: Array Sorting Functions-Footnote-2588032
+Node: Two-way I/O588226
+Ref: Two-way I/O-Footnote-1593658
+Node: TCP/IP Networking593728
+Node: Profiling596572
+Node: Library Functions604026
+Ref: Library Functions-Footnote-1607033
+Node: Library Names607204
+Ref: Library Names-Footnote-1610675
+Ref: Library Names-Footnote-2610895
+Node: General Functions610981
+Node: Strtonum Function611934
+Node: Assert Function614864
+Node: Round Function618190
+Node: Cliff Random Function619733
+Node: Ordinal Functions620749
+Ref: Ordinal Functions-Footnote-1623819
+Ref: Ordinal Functions-Footnote-2624071
+Node: Join Function624280
+Ref: Join Function-Footnote-1626051
+Node: Getlocaltime Function626251
+Node: Data File Management629966
+Node: Filetrans Function630598
+Node: Rewind Function634737
+Node: File Checking636124
+Node: Empty Files637218
+Node: Ignoring Assigns639448
+Node: Getopt Function641001
+Ref: Getopt Function-Footnote-1652305
+Node: Passwd Functions652508
+Ref: Passwd Functions-Footnote-1661483
+Node: Group Functions661571
+Node: Walking Arrays669655
+Node: Sample Programs671224
+Node: Running Examples671889
+Node: Clones672617
+Node: Cut Program673841
+Node: Egrep Program683686
+Ref: Egrep Program-Footnote-1691459
+Node: Id Program691569
+Node: Split Program695185
+Ref: Split Program-Footnote-1698704
+Node: Tee Program698832
+Node: Uniq Program701635
+Node: Wc Program709064
+Ref: Wc Program-Footnote-1713330
+Ref: Wc Program-Footnote-2713530
+Node: Miscellaneous Programs713622
+Node: Dupword Program714810
+Node: Alarm Program716841
+Node: Translate Program721590
+Ref: Translate Program-Footnote-1725977
+Ref: Translate Program-Footnote-2726205
+Node: Labels Program726339
+Ref: Labels Program-Footnote-1729710
+Node: Word Sorting729794
+Node: History Sorting733678
+Node: Extract Program735517
+Ref: Extract Program-Footnote-1743000
+Node: Simple Sed743128
+Node: Igawk Program746190
+Ref: Igawk Program-Footnote-1761347
+Ref: Igawk Program-Footnote-2761548
+Node: Anagram Program761686
+Node: Signature Program764754
+Node: Debugger765854
+Node: Debugging766820
+Node: Debugging Concepts767253
+Node: Debugging Terms769109
+Node: Awk Debugging771706
+Node: Sample Debugging Session772598
+Node: Debugger Invocation773118
+Node: Finding The Bug774447
+Node: List of Debugger Commands780935
+Node: Breakpoint Control782269
+Node: Debugger Execution Control785933
+Node: Viewing And Changing Data789293
+Node: Execution Stack792649
+Node: Debugger Info794116
+Node: Miscellaneous Debugger Commands798097
+Node: Readline Support803542
+Node: Limitations804373
+Node: Arbitrary Precision Arithmetic806625
+Ref: Arbitrary Precision Arithmetic-Footnote-1808267
+Node: General Arithmetic808415
+Node: Floating Point Issues810135
+Node: String Conversion Precision811016
+Ref: String Conversion Precision-Footnote-1812722
+Node: Unexpected Results812831
+Node: POSIX Floating Point Problems814984
+Ref: POSIX Floating Point Problems-Footnote-1818809
+Node: Integer Programming818847
+Node: Floating-point Programming820600
+Ref: Floating-point Programming-Footnote-1826909
+Node: Floating-point Representation827173
+Node: Floating-point Context828338
+Ref: table-ieee-formats829180
+Node: Rounding Mode830564
+Ref: table-rounding-modes831043
+Ref: Rounding Mode-Footnote-1834047
+Node: Gawk and MPFR834228
+Node: Arbitrary Precision Floats835470
+Ref: Arbitrary Precision Floats-Footnote-1837899
+Node: Setting Precision838210
+Node: Setting Rounding Mode840943
+Ref: table-gawk-rounding-modes841347
+Node: Floating-point Constants842527
+Node: Changing Precision843951
+Ref: Changing Precision-Footnote-1845351
+Node: Exact Arithmetic845525
+Node: Arbitrary Precision Integers848633
+Ref: Arbitrary Precision Integers-Footnote-1851633
+Node: Dynamic Extensions851780
+Node: Plugin License852698
+Node: Sample Library853312
+Node: Internal File Description853996
+Node: Internal File Ops857709
+Ref: Internal File Ops-Footnote-1862272
+Node: Using Internal File Ops862412
+Node: Language History864788
+Node: V7/SVR3.1866310
+Node: SVR4868631
+Node: POSIX870073
+Node: BTL871081
+Node: POSIX/GNU871815
+Node: Common Extensions877350
+Node: Ranges and Locales878457
+Ref: Ranges and Locales-Footnote-1883075
+Ref: Ranges and Locales-Footnote-2883102
+Ref: Ranges and Locales-Footnote-3883362
+Node: Contributors883583
+Node: Installation887879
+Node: Gawk Distribution888773
+Node: Getting889257
+Node: Extracting890083
+Node: Distribution contents891775
+Node: Unix Installation896997
+Node: Quick Installation897614
+Node: Additional Configuration Options899576
+Node: Configuration Philosophy901053
+Node: Non-Unix Installation903395
+Node: PC Installation903853
+Node: PC Binary Installation905152
+Node: PC Compiling907000
+Node: PC Testing909944
+Node: PC Using911120
+Node: Cygwin915305
+Node: MSYS916305
+Node: VMS Installation916819
+Node: VMS Compilation917422
+Ref: VMS Compilation-Footnote-1918429
+Node: VMS Installation Details918487
+Node: VMS Running920122
+Node: VMS Old Gawk921729
+Node: Bugs922203
+Node: Other Versions926055
+Node: Notes931370
+Node: Compatibility Mode931957
+Node: Additions932740
+Node: Accessing The Source933667
+Node: Adding Code935093
+Node: New Ports941135
+Node: Derived Files945270
+Ref: Derived Files-Footnote-1950575
+Ref: Derived Files-Footnote-2950609
+Ref: Derived Files-Footnote-3951209
+Node: Future Extensions951307
+Node: Basic Concepts952794
+Node: Basic High Level953475
+Ref: Basic High Level-Footnote-1957510
+Node: Basic Data Typing957695
+Node: Glossary961050
+Node: Copying986225
+Node: GNU Free Documentation License1023782
+Node: Index1048919
 
 End Tag Table
diff --git a/doc/gawk.texi b/doc/gawk.texi
index f0378b3..bc41fb2 100644
--- a/doc/gawk.texi
+++ b/doc/gawk.texi
@@ -13201,6 +13201,31 @@ if an element in @code{SYMTAB} is an array.
 Also, you may not use the @code{delete} statement with the
 @code{SYMTAB} array.
 
+You may use an index for @code{SYMTAB} that is not a predefined identifer:
+
address@hidden
+SYMTAB["xxx"] = 5
+print SYMTAB["xxx"]
address@hidden example
+
address@hidden
+This works as expected: in this case @code{SYMTAB} acts just like
+a regular array.  The only difference is that you can't then delete
address@hidden"xxx"]}.
+
+The @code{SYMTAB} array is more interesting than it looks. Andrew Schorr
+points out that it effectively gives @command{awk} data pointers. Consider his
+example:
+
address@hidden
+# Indirect multiply of any variable by amount, return result
+
+function multiply(variable, amount)
address@hidden
+    return SYMTAB[variable] *= amount
address@hidden
address@hidden example
+
 @quotation NOTE
 In order to avoid severe time-travel address@hidden to mention difficult
 implementation issues.}, neither @code{FUNCTAB} nor @code{SYMTAB}
diff --git a/interpret.h b/interpret.h
index ab6c9b3..0a30684 100644
--- a/interpret.h
+++ b/interpret.h
@@ -321,6 +321,7 @@ top:
                case Op_K_break:
                case Op_K_continue:
                case Op_jmp:
+                       assert(pc->target_jmp != NULL);
                        JUMPTO(pc->target_jmp);
 
                case Op_jmp_false:
diff --git a/main.c b/main.c
index e1cdd3d..5e84a3c 100644
--- a/main.c
+++ b/main.c
@@ -1064,6 +1064,12 @@ load_environ()
        NODE **aptr;
        int i;
        NODE *tmp;
+       static bool been_here = false;
+
+       if (been_here)
+               return ENVIRON_node;
+
+       been_here = true;
 
        ENVIRON_node = install_symbol(estrdup("ENVIRON", 7), Node_var_array);
        for (i = 0; environ[i] != NULL; i++) {
@@ -1107,6 +1113,12 @@ load_procinfo()
        char name[100];
 #endif
        AWKNUM value;
+       static bool been_here = false;
+
+       if (been_here)
+               return PROCINFO_node;
+
+       been_here = true;
 
        PROCINFO_node = install_symbol(estrdup("PROCINFO", 8), Node_var_array);
 
diff --git a/symbol.c b/symbol.c
index 3776f90..5a34f29 100644
--- a/symbol.c
+++ b/symbol.c
@@ -91,7 +91,7 @@ lookup(const char *name)
 {
        NODE *n;
        NODE *tmp;
-       /* ``It's elephants, all the way down.'' */
+       /* ``It's turtles, all the way down.'' */
        NODE *tables[] = {
                param_table,    /* parameters shadow everything */
                global_table,   /* SYMTAB and FUNCTAB found first, can't be 
redefined */
diff --git a/test/ChangeLog b/test/ChangeLog
index f545a57..7a6a6de 100644
--- a/test/ChangeLog
+++ b/test/ChangeLog
@@ -1,3 +1,9 @@
+2012-10-19         Arnold D. Robbins     <address@hidden>
+
+       * symtab1.awk: Adjust to not print ENVIRON and PROCINFO which won't
+       be the same as on the author's machine.
+       * lintwarn.ok: Adjust.
+
 2012-10-13         Arnold D. Robbins     <address@hidden>
 
        * Makefile.am (EXTRA_DIST): Add jarebug.sh.
diff --git a/test/lintwarn.ok b/test/lintwarn.ok
index 312d40d..ec87612 100644
--- a/test/lintwarn.ok
+++ b/test/lintwarn.ok
@@ -16,6 +16,7 @@ gawk: lintwarn.awk:18: warning: `case' is a gawk extension
 gawk: lintwarn.awk:19: warning: `default' is a gawk extension
 gawk: lintwarn.awk:19: error: duplicate `default' detected in switch body
 gawk: lintwarn.awk:18: error: duplicate case values in switch body: 1
+gawk: lintwarn.awk:24: error: `continue' is not allowed outside a loop
 gawk: lintwarn.awk:23: error: `break' is not allowed outside a loop or switch
 gawk: lintwarn.awk:24: error: `continue' is not allowed outside a loop
 gawk: lintwarn.awk:25: error: `next' used in BEGIN action
diff --git a/test/symtab1.awk b/test/symtab1.awk
index 6ca7d63..eeb0143 100644
--- a/test/symtab1.awk
+++ b/test/symtab1.awk
@@ -1,5 +1,8 @@
 function dumparray(name, array,                i)
 {
+       if (name == "ENVIRON" || name == "PROCINFO")
+               return
+
        for (i in array)
                if (isarray(array[i]))
                        dumparray(name "[" i "]", array[i])

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

Summary of changes:
 ChangeLog        |   22 ++
 FUTURES          |   17 ++
 awkgram.c        |  426 +++++++++++++++++++++-----------------
 awkgram.y        |   44 ++++
 doc/ChangeLog    |    4 +
 doc/api.texi     |  612 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
 doc/gawk.info    |  549 +++++++++++++++++++++++++-----------------------
 doc/gawk.texi    |   25 +++
 interpret.h      |    1 +
 main.c           |   12 +
 symbol.c         |    2 +-
 test/ChangeLog   |    6 +
 test/lintwarn.ok |    1 +
 test/symtab1.awk |    3 +
 14 files changed, 1266 insertions(+), 458 deletions(-)


hooks/post-receive
-- 
gawk



reply via email to

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