diff options
-rw-r--r-- | ChangeLog | 22 | ||||
-rw-r--r-- | FUTURES | 17 | ||||
-rw-r--r-- | awkgram.c | 426 | ||||
-rw-r--r-- | awkgram.y | 44 | ||||
-rw-r--r-- | doc/ChangeLog | 4 | ||||
-rw-r--r-- | doc/api.texi | 612 | ||||
-rw-r--r-- | doc/gawk.info | 549 | ||||
-rw-r--r-- | doc/gawk.texi | 25 | ||||
-rw-r--r-- | interpret.h | 1 | ||||
-rw-r--r-- | main.c | 12 | ||||
-rw-r--r-- | symbol.c | 2 | ||||
-rw-r--r-- | test/ChangeLog | 6 | ||||
-rw-r--r-- | test/lintwarn.ok | 1 | ||||
-rw-r--r-- | test/symtab1.awk | 3 |
14 files changed, 1266 insertions, 458 deletions
@@ -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. @@ -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. @@ -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 * @@ -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: @@ -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); @@ -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]) |