aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog22
-rw-r--r--FUTURES17
-rw-r--r--awkgram.c426
-rw-r--r--awkgram.y44
-rw-r--r--doc/ChangeLog4
-rw-r--r--doc/api.texi612
-rw-r--r--doc/gawk.info549
-rw-r--r--doc/gawk.texi25
-rw-r--r--interpret.h1
-rw-r--r--main.c12
-rw-r--r--symbol.c2
-rw-r--r--test/ChangeLog6
-rw-r--r--test/lintwarn.ok1
-rw-r--r--test/symtab1.awk3
14 files changed, 1266 insertions, 458 deletions
diff --git a/ChangeLog b/ChangeLog
index e147607e..896472b6 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,25 @@
+2012-10-19 Arnold D. Robbins <arnold@skeeve.com>
+
+ 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 <arnold@skeeve.com>
* gawkapi.h (IOBUF_PUBLIC): Renamed awk_input_buf_t.
diff --git a/FUTURES b/FUTURES
index ba1f1b26..a6a6f3ef 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 a3759980..703cf631 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 22b0b767..91e791ab 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 e0f8c2f9..7613e26d 100644
--- a/doc/ChangeLog
+++ b/doc/ChangeLog
@@ -1,3 +1,7 @@
+2012-10-19 Arnold D. Robbins <arnold@skeeve.com>
+
+ * gawk.texi: More doc on SYMTAB.
+
2012-10-05 Arnold D. Robbins <arnold@skeeve.com>
* Makefile.am (LN, install-data-hook, uninstall-hook): Removed. No
diff --git a/doc/api.texi b/doc/api.texi
index 9e3c288d..ab4ea632 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}).
+@quotation NOTE
+When @option{--sandbox} is specified, extensions are disabled
+(@pxref{Options}.
+@end quotation
+
@menu
+* Plugin License:: A note about licensing.
@end menu
+@node Plugin License
+@section Extension Licensing
+
+Every dynamic extension should define the global symbol
+@code{plugin_is_GPL_compatible} 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:
+
+@example
+int plugin_is_GPL_compatible;
+@end 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
-@section Sample Extensions
+@section 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
+@code{stat()} (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
+@node Internal File Description
+@subsection 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:
+
+@example
+@@load "filefuncs"
+@dots{}
+newdir = "/home/arnold/funstuff"
+ret = chdir(newdir)
+if (ret < 0) @{
+ printf("could not change to %s: %s\n",
+ newdir, ERRNO) > "/dev/stderr"
+ exit 1
+@}
+@dots{}
+@end example
+
+The return value is negative if the @code{chdir()} failed, and
+@code{ERRNO} (@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:
+
+@c broke printf for page breaking
+@example
+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
+@}
+printf("size of %s is %d bytes\n", file, fdata["size"])
+@end example
+
+The @code{stat()} function always clears the data array, even if
+the @code{stat()} fails. It fills in the following elements:
+
+@table @code
+@item "name"
+The name of the file that was @code{stat()}'ed.
+
+@item "dev"
+@itemx "ino"
+The file's device and inode numbers, respectively.
+
+@item "mode"
+The file's mode, as a numeric value. This includes both the file's
+type and its permissions.
+
+@item "nlink"
+The number of hard links (directory entries) the file has.
+
+@item "uid"
+@itemx "gid"
+The numeric user and group ID numbers of the file's owner.
+
+@item "size"
+The size in bytes of the file.
+
+@item "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.
+
+@item "atime"
+@itemx "mtime"
+@itemx "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}).
+
+@item "pmode"
+The file's ``printable mode.'' This is a string representation of
+the file's type and permissions, such as what is produced by
+@samp{ls -l}---for example, @code{"drwxr-xr-x"}.
+
+@item "type"
+A printable string representation of the file's type. The value
+is one of the following:
+
+@table @code
+@item "blockdev"
+@itemx "chardev"
+The file is a block or character device (``special file'').
+
+@ignore
+@item "door"
+The file is a Solaris ``door'' (special file used for
+interprocess communications).
+@end ignore
+
+@item "directory"
+The file is a directory.
+
+@item "fifo"
+The file is a named-pipe (also known as a FIFO).
+
+@item "file"
+The file is just a regular file.
+
+@item "socket"
+The file is an @code{AF_UNIX} (``Unix domain'') socket in the
+filesystem.
+
+@item "symlink"
+The file is a symbolic link.
+@end table
+@end 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}):
+
+@table @code
+@item "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.
+
+@item "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).
+
+@item "rdev"
+@itemx "major"
+@itemx "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.
+@end table
+
+@node Internal File Ops
+@subsection C Code for @code{chdir()} and @code{stat()}
+
+Here is the C code for these extensions.@footnote{This version is
+edited slightly for presentation. See @file{extension/filefuncs.c}
+in the @command{gawk} distribution for the complete version.}
+
+@c break line for page breaking
+@example
+#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)
+@{
+ 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"));
+@end example
+
+The file includes
+a number of standard header files, and then includes the
+@code{"gawkapi.h"} header file which provides the API definitions.
+
+@cindex 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
+@samp{int} 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
+@code{result}.
+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
+@code{chdir()} system call. If the @code{chdir()} fails, @code{ERRNO}
+is updated.
+
+@example
+ if (get_argument(0, AWK_STRING, & newdir)) @{
+ ret = chdir(newdir.str_value.str);
+ if (ret < 0)
+ update_ERRNO_int(errno);
+ @}
+@end example
+
+Finally, the function returns the return value to the @command{awk} level:
+
+@example
+ return make_number(ret, result);
+@}
+@end 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:
+
+@c break line for page breaking
+@example
+/* format_mode --- turn a stat mode field into something readable */
+
+static char *
+format_mode(unsigned long fmode)
+@{
+ @dots{}
+@}
+@end example
+
+Next comes a function for reading symbolic links, which is also
+omitted here for brevity:
+
+@example
+/* read_symlink -- read a symbolic link into an allocated buffer.
+ @dots{} */
+
+static char *
+read_symlink(const char *fname, size_t bufsize, ssize_t *linksize)
+@{
+ @dots{}
+@}
+@end example
+
+Two helper functions simplify entering values in the
+array that will contain the result of the @code{stat()}:
+
+@example
+/* array_set --- set an array element */
+
+static void
+array_set(awk_array_t array, const char *sub, awk_value_t *value)
+@{
+ awk_value_t index;
+
+ set_array_element(array,
+ make_const_string(sub, strlen(sub), & index),
+ value);
+
+@}
+
+/* array_set_numeric --- set an array element with a number */
+
+static void
+array_set_numeric(awk_array_t array, const char *sub, double num)
+@{
+ awk_value_t tmp;
+
+ array_set(array, sub, make_number(num, & tmp));
+@}
+@end 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.)
+
+@example
+/* 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)
+@{
+ 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;
+@}
+@end example
+
+Finall, here is the @code{do_stat()} function. It starts with
+variable declarations and argument checking:
+
+@ignore
+Changed message for page breaking. Used to be:
+ "stat: called with incorrect number of arguments (%d), should be 2",
+@end ignore
+@example
+/* do_stat --- provide a stat() function for gawk */
+
+static awk_value_t *
+do_stat(int nargs, awk_value_t *result)
+@{
+ 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);
+ @}
+@end 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:
+
+@example
+ /* 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);
+ @}
+@end example
+
+The tedious work is done by @code{fill_stat_array()}, shown
+earlier.
+When done, return the result from @code{fill_stat_array()}:
+
+@example
+ ret = fill_stat_array(name, array, & sbuf);
+
+ return make_number(ret, result);
+@}
+@end example
+
+@cindex 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:
+
+@example
+/* init_filefuncs --- initialization routine */
+
+static awk_bool_t
+init_filefuncs(void)
+@{
+ @dots{}
+@}
+@end example
+
+Almost done. We need an array of @code{awk_ext_func_t}
+structures for loading each function into @command{gawk}:
+
+@example
+static awk_ext_func_t func_table[] = @{
+ @{ "chdir", do_chdir, 1 @},
+ @{ "stat", do_stat, 2 @},
+ @{ "fts", do_fts, 3 @},
+@};
+@end 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
+@code{dl_load_func} macro in @code{gawkapi.h}:
+
+@example
+/* define the dl_load function using the boilerplate macro */
+
+dl_load_func(func_table, filefuncs, "")
+@end example
+
+And that's it! As an exercise, consider adding functions to
+implement system calls such as @code{chown()}, @code{chmod()},
+and @code{umask()}.
+
+@node Using Internal File Ops
+@subsection Integrating the Extensions
+
+@cindex @command{gawk}, interpreter@comma{} 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:
+
+@example
+$ @kbd{gcc -fPIC -shared -DHAVE_CONFIG_H -c -O -g -I@var{idir} filefuncs.c}
+$ @kbd{ld -o filefuncs.so -shared filefuncs.o}
+@end example
+
+@cindex @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:
+
+@example
+# 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"])
+@}
+@end example
+
+Here are the results of running the program:
+
+@example
+$ @kbd{gawk -f testff.awk}
+@print{} Info for testff.awk
+@print{} ret = 0
+@print{} data["size"] = 607
+@print{} data["ino"] = 14945891
+@print{} data["name"] = testff.awk
+@print{} data["pmode"] = -rw-rw-r--
+@print{} data["nlink"] = 1
+@print{} data["atime"] = 1293993369
+@print{} data["mtime"] = 1288520752
+@print{} data["mode"] = 33204
+@print{} data["blksize"] = 4096
+@print{} data["dev"] = 2054
+@print{} data["type"] = file
+@print{} data["gid"] = 500
+@print{} data["uid"] = 500
+@print{} data["blocks"] = 8
+@print{} data["ctime"] = 1290113572
+@print{} testff.awk modified: 10 31 10 12:25:52
+@print{}
+@print{} Info for JUNK
+@print{} ret = -1
+@print{} JUNK modified: 01 01 70 02:00:00
+@end example
+
@node Extension Sample File Functions
@subsection File Related Functions
diff --git a/doc/gawk.info b/doc/gawk.info
index 08fbc297..b97acf46 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 f0378b30..bc41fb24 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:
+
+@example
+SYMTAB["xxx"] = 5
+print SYMTAB["xxx"]
+@end example
+
+@noindent
+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
+@code{SYMTAB["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:
+
+@example
+# Indirect multiply of any variable by amount, return result
+
+function multiply(variable, amount)
+@{
+ return SYMTAB[variable] *= amount
+@}
+@end example
+
@quotation NOTE
In order to avoid severe time-travel paradoxes@footnote{Not to mention difficult
implementation issues.}, neither @code{FUNCTAB} nor @code{SYMTAB}
diff --git a/interpret.h b/interpret.h
index ab6c9b33..0a306848 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 e1cdd3d3..5e84a3c7 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 3776f905..5a34f296 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 f545a57b..7a6a6de4 100644
--- a/test/ChangeLog
+++ b/test/ChangeLog
@@ -1,3 +1,9 @@
+2012-10-19 Arnold D. Robbins <arnold@skeeve.com>
+
+ * 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 <arnold@skeeve.com>
* Makefile.am (EXTRA_DIST): Add jarebug.sh.
diff --git a/test/lintwarn.ok b/test/lintwarn.ok
index 312d40d4..ec87612f 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 6ca7d632..eeb01437 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])