1 diff --git a/ChangeLog b/ChangeLog
2 index bf0f749..913b4a3 100644
6 +2011-07-05 John Haque <address@hidden>
8 + * awk.h (Op_sub_builtin): New opcode.
9 + (GSUB, GENSUB, AFTER_ASSIGN, LITERAL): New flags for
11 + * awkgram.y (struct tokentab): Change opcode to Op_sub_builtin
12 + for sub, gsub and gensub.
13 + (snode): Update processing of sub, gsub and gensub.
14 + * builtin.c (do_sub, do_gsub, do_gensub): Nuke.
15 + (sub_common): Renamed to do_sub. Relocate gensub argument
16 + handling code from do_gensub to here; Simplify the code a
18 + * eval.c (r_interpret): Handle Op_sub_builtin. Avoid field
19 + re-splitting or $0 rebuilding if (g)sub target string is
20 + a field and no substitutions were done.
21 + * pprint (profile.c): Add case for the new opcode.
22 + * print_instruction (debug.c): Ditto.
24 2011-06-24 Arnold D. Robbins <arnold@skeeve.com>
26 * Makefile.am (EXTRA_DIST): Add ChangeLog.0.
27 diff --git a/awk.h b/awk.h
28 index 25abf41..e224061 100644
31 @@ -521,6 +521,7 @@ typedef enum opcodeval {
35 + Op_sub_builtin, /* sub, gsub and gensub */
36 Op_in_array, /* boolean test of membership in array */
38 /* function call instruction */
39 @@ -626,6 +627,16 @@ typedef struct exp_instruction {
40 #define target_jmp d.di
41 #define target_break x.xi
44 +#define sub_flags d.dl
45 +#define GSUB 0x01 /* builtin is gsub */
46 +#define GENSUB 0x02 /* builtin is gensub */
47 +#define AFTER_ASSIGN 0x04 /* (g)sub target is a field or a special var with
50 +#define LITERAL 0x08 /* target is a literal string */
54 #define target_end d.di
55 #define target_atexit x.xi
56 @@ -1181,9 +1192,7 @@ extern NODE *do_cos(int nargs);
57 extern NODE *do_rand(int nargs);
58 extern NODE *do_srand(int nargs);
59 extern NODE *do_match(int nargs);
60 -extern NODE *do_gsub(int nargs);
61 -extern NODE *do_sub(int nargs);
62 -extern NODE *do_gensub(int nargs);
63 +extern NODE *do_sub(int nargs, unsigned int flags, int *num_matches);
64 extern NODE *format_tree(const char *, size_t, NODE **, long);
65 extern NODE *do_lshift(int nargs);
66 extern NODE *do_rshift(int nargs);
67 diff --git a/awkgram.c b/awkgram.c
68 index 4edec57..ac4ceaa 100644
71 @@ -2065,7 +2065,7 @@ yyreduce:
75 -/* Line 1806 of yacc.c */
76 +/* Line 1821 of yacc.c */
80 @@ -2075,7 +2075,7 @@ yyreduce:
84 -/* Line 1806 of yacc.c */
85 +/* Line 1821 of yacc.c */
89 @@ -2084,7 +2084,7 @@ yyreduce:
93 -/* Line 1806 of yacc.c */
94 +/* Line 1821 of yacc.c */
98 @@ -2098,7 +2098,7 @@ yyreduce:
102 -/* Line 1806 of yacc.c */
103 +/* Line 1821 of yacc.c */
104 #line 243 "awkgram.y"
106 (void) append_rule((yyvsp[(1) - (2)]), (yyvsp[(2) - (2)]));
107 @@ -2107,7 +2107,7 @@ yyreduce:
111 -/* Line 1806 of yacc.c */
112 +/* Line 1821 of yacc.c */
113 #line 247 "awkgram.y"
116 @@ -2123,7 +2123,7 @@ yyreduce:
120 -/* Line 1806 of yacc.c */
121 +/* Line 1821 of yacc.c */
122 #line 258 "awkgram.y"
125 @@ -2136,7 +2136,7 @@ yyreduce:
129 -/* Line 1806 of yacc.c */
130 +/* Line 1821 of yacc.c */
131 #line 266 "awkgram.y"
134 @@ -2146,7 +2146,7 @@ yyreduce:
138 -/* Line 1806 of yacc.c */
139 +/* Line 1821 of yacc.c */
140 #line 274 "awkgram.y"
142 if (include_source((yyvsp[(1) - (1)])) < 0)
143 @@ -2159,35 +2159,35 @@ yyreduce:
147 -/* Line 1806 of yacc.c */
148 +/* Line 1821 of yacc.c */
149 #line 282 "awkgram.y"
155 -/* Line 1806 of yacc.c */
156 +/* Line 1821 of yacc.c */
157 #line 284 "awkgram.y"
163 -/* Line 1806 of yacc.c */
164 +/* Line 1821 of yacc.c */
165 #line 289 "awkgram.y"
166 { (yyval) = NULL; rule = Rule; }
171 -/* Line 1806 of yacc.c */
172 +/* Line 1821 of yacc.c */
173 #line 291 "awkgram.y"
174 { (yyval) = (yyvsp[(1) - (1)]); rule = Rule; }
179 -/* Line 1806 of yacc.c */
180 +/* Line 1821 of yacc.c */
181 #line 293 "awkgram.y"
184 @@ -2218,7 +2218,7 @@ yyreduce:
188 -/* Line 1806 of yacc.c */
189 +/* Line 1821 of yacc.c */
190 #line 319 "awkgram.y"
192 static int begin_seen = 0;
193 @@ -2234,7 +2234,7 @@ yyreduce:
197 -/* Line 1806 of yacc.c */
198 +/* Line 1821 of yacc.c */
199 #line 330 "awkgram.y"
201 static int end_seen = 0;
202 @@ -2250,7 +2250,7 @@ yyreduce:
206 -/* Line 1806 of yacc.c */
207 +/* Line 1821 of yacc.c */
208 #line 341 "awkgram.y"
210 (yyvsp[(1) - (1)])->in_rule = rule = BEGINFILE;
211 @@ -2261,7 +2261,7 @@ yyreduce:
215 -/* Line 1806 of yacc.c */
216 +/* Line 1821 of yacc.c */
217 #line 347 "awkgram.y"
219 (yyvsp[(1) - (1)])->in_rule = rule = ENDFILE;
220 @@ -2272,7 +2272,7 @@ yyreduce:
224 -/* Line 1806 of yacc.c */
225 +/* Line 1821 of yacc.c */
226 #line 356 "awkgram.y"
228 if ((yyvsp[(2) - (5)]) == NULL)
229 @@ -2284,21 +2284,21 @@ yyreduce:
233 -/* Line 1806 of yacc.c */
234 +/* Line 1821 of yacc.c */
235 #line 366 "awkgram.y"
236 { (yyval) = (yyvsp[(1) - (1)]); }
241 -/* Line 1806 of yacc.c */
242 +/* Line 1821 of yacc.c */
243 #line 368 "awkgram.y"
244 { (yyval) = (yyvsp[(1) - (1)]); }
249 -/* Line 1806 of yacc.c */
250 +/* Line 1821 of yacc.c */
251 #line 370 "awkgram.y"
253 yyerror(_("`%s' is a built-in function, it cannot be redefined"),
254 @@ -2314,14 +2314,14 @@ yyreduce:
258 -/* Line 1806 of yacc.c */
259 +/* Line 1821 of yacc.c */
260 #line 381 "awkgram.y"
261 { (yyval) = (yyvsp[(2) - (2)]); }
266 -/* Line 1806 of yacc.c */
267 +/* Line 1821 of yacc.c */
268 #line 391 "awkgram.y"
271 @@ -2331,7 +2331,7 @@ yyreduce:
275 -/* Line 1806 of yacc.c */
276 +/* Line 1821 of yacc.c */
277 #line 396 "awkgram.y"
280 @@ -2353,14 +2353,14 @@ yyreduce:
284 -/* Line 1806 of yacc.c */
285 +/* Line 1821 of yacc.c */
286 #line 420 "awkgram.y"
292 -/* Line 1806 of yacc.c */
293 +/* Line 1821 of yacc.c */
294 #line 422 "awkgram.y"
297 @@ -2393,21 +2393,21 @@ yyreduce:
301 -/* Line 1806 of yacc.c */
302 +/* Line 1821 of yacc.c */
303 #line 453 "awkgram.y"
304 { bcfree((yyvsp[(1) - (1)])); }
309 -/* Line 1806 of yacc.c */
310 +/* Line 1821 of yacc.c */
311 #line 459 "awkgram.y"
317 -/* Line 1806 of yacc.c */
318 +/* Line 1821 of yacc.c */
319 #line 461 "awkgram.y"
321 if ((yyvsp[(2) - (2)]) == NULL)
322 @@ -2425,28 +2425,28 @@ yyreduce:
326 -/* Line 1806 of yacc.c */
327 +/* Line 1821 of yacc.c */
328 #line 474 "awkgram.y"
334 -/* Line 1806 of yacc.c */
335 +/* Line 1821 of yacc.c */
336 #line 484 "awkgram.y"
342 -/* Line 1806 of yacc.c */
343 +/* Line 1821 of yacc.c */
344 #line 486 "awkgram.y"
345 { (yyval) = (yyvsp[(2) - (3)]); }
350 -/* Line 1806 of yacc.c */
351 +/* Line 1821 of yacc.c */
352 #line 488 "awkgram.y"
355 @@ -2458,7 +2458,7 @@ yyreduce:
359 -/* Line 1806 of yacc.c */
360 +/* Line 1821 of yacc.c */
361 #line 495 "awkgram.y"
363 INSTRUCTION *dflt, *curr = NULL, *cexp, *cstmt;
364 @@ -2553,7 +2553,7 @@ yyreduce:
368 -/* Line 1806 of yacc.c */
369 +/* Line 1821 of yacc.c */
370 #line 585 "awkgram.y"
373 @@ -2600,7 +2600,7 @@ yyreduce:
377 -/* Line 1806 of yacc.c */
378 +/* Line 1821 of yacc.c */
379 #line 627 "awkgram.y"
382 @@ -2647,7 +2647,7 @@ yyreduce:
386 -/* Line 1806 of yacc.c */
387 +/* Line 1821 of yacc.c */
388 #line 669 "awkgram.y"
391 @@ -2767,7 +2767,7 @@ regular_loop:
395 -/* Line 1806 of yacc.c */
396 +/* Line 1821 of yacc.c */
397 #line 784 "awkgram.y"
399 (yyval) = mk_for_loop((yyvsp[(1) - (12)]), (yyvsp[(3) - (12)]), (yyvsp[(6) - (12)]), (yyvsp[(9) - (12)]), (yyvsp[(12) - (12)]));
400 @@ -2779,7 +2779,7 @@ regular_loop:
404 -/* Line 1806 of yacc.c */
405 +/* Line 1821 of yacc.c */
406 #line 791 "awkgram.y"
408 (yyval) = mk_for_loop((yyvsp[(1) - (11)]), (yyvsp[(3) - (11)]), (INSTRUCTION *) NULL, (yyvsp[(8) - (11)]), (yyvsp[(11) - (11)]));
409 @@ -2791,7 +2791,7 @@ regular_loop:
413 -/* Line 1806 of yacc.c */
414 +/* Line 1821 of yacc.c */
415 #line 798 "awkgram.y"
418 @@ -2803,7 +2803,7 @@ regular_loop:
422 -/* Line 1806 of yacc.c */
423 +/* Line 1821 of yacc.c */
424 #line 808 "awkgram.y"
427 @@ -2817,7 +2817,7 @@ regular_loop:
431 -/* Line 1806 of yacc.c */
432 +/* Line 1821 of yacc.c */
433 #line 817 "awkgram.y"
435 if (! continue_allowed)
436 @@ -2831,7 +2831,7 @@ regular_loop:
440 -/* Line 1806 of yacc.c */
441 +/* Line 1821 of yacc.c */
442 #line 826 "awkgram.y"
444 /* if inside function (rule = 0), resolve context at run-time */
445 @@ -2845,7 +2845,7 @@ regular_loop:
449 -/* Line 1806 of yacc.c */
450 +/* Line 1821 of yacc.c */
451 #line 835 "awkgram.y"
454 @@ -2865,7 +2865,7 @@ regular_loop:
458 -/* Line 1806 of yacc.c */
459 +/* Line 1821 of yacc.c */
460 #line 850 "awkgram.y"
462 /* Initialize the two possible jump targets, the actual target
463 @@ -2885,7 +2885,7 @@ regular_loop:
467 -/* Line 1806 of yacc.c */
468 +/* Line 1821 of yacc.c */
469 #line 865 "awkgram.y"
472 @@ -2895,7 +2895,7 @@ regular_loop:
476 -/* Line 1806 of yacc.c */
477 +/* Line 1821 of yacc.c */
478 #line 868 "awkgram.y"
480 if ((yyvsp[(3) - (4)]) == NULL) {
481 @@ -2909,14 +2909,14 @@ regular_loop:
485 -/* Line 1806 of yacc.c */
486 +/* Line 1821 of yacc.c */
487 #line 888 "awkgram.y"
488 { in_print = TRUE; in_parens = 0; }
493 -/* Line 1806 of yacc.c */
494 +/* Line 1821 of yacc.c */
495 #line 889 "awkgram.y"
498 @@ -3016,14 +3016,14 @@ regular_loop:
502 -/* Line 1806 of yacc.c */
503 +/* Line 1821 of yacc.c */
504 #line 984 "awkgram.y"
510 -/* Line 1806 of yacc.c */
511 +/* Line 1821 of yacc.c */
512 #line 985 "awkgram.y"
514 char *arr = (yyvsp[(2) - (4)])->lextok;
515 @@ -3053,7 +3053,7 @@ regular_loop:
519 -/* Line 1806 of yacc.c */
520 +/* Line 1821 of yacc.c */
521 #line 1014 "awkgram.y"
523 static short warned = FALSE;
524 @@ -3077,35 +3077,35 @@ regular_loop:
528 -/* Line 1806 of yacc.c */
529 +/* Line 1821 of yacc.c */
530 #line 1033 "awkgram.y"
531 { (yyval) = optimize_assignment((yyvsp[(1) - (1)])); }
536 -/* Line 1806 of yacc.c */
537 +/* Line 1821 of yacc.c */
538 #line 1038 "awkgram.y"
544 -/* Line 1806 of yacc.c */
545 +/* Line 1821 of yacc.c */
546 #line 1040 "awkgram.y"
547 { (yyval) = (yyvsp[(1) - (1)]); }
552 -/* Line 1806 of yacc.c */
553 +/* Line 1821 of yacc.c */
554 #line 1045 "awkgram.y"
560 -/* Line 1806 of yacc.c */
561 +/* Line 1821 of yacc.c */
562 #line 1047 "awkgram.y"
564 if ((yyvsp[(1) - (2)]) == NULL)
565 @@ -3117,14 +3117,14 @@ regular_loop:
569 -/* Line 1806 of yacc.c */
570 +/* Line 1821 of yacc.c */
571 #line 1054 "awkgram.y"
577 -/* Line 1806 of yacc.c */
578 +/* Line 1821 of yacc.c */
579 #line 1059 "awkgram.y"
581 INSTRUCTION *casestmt = (yyvsp[(5) - (5)]);
582 @@ -3141,7 +3141,7 @@ regular_loop:
586 -/* Line 1806 of yacc.c */
587 +/* Line 1821 of yacc.c */
588 #line 1071 "awkgram.y"
590 INSTRUCTION *casestmt = (yyvsp[(4) - (4)]);
591 @@ -3157,14 +3157,14 @@ regular_loop:
595 -/* Line 1806 of yacc.c */
596 +/* Line 1821 of yacc.c */
597 #line 1085 "awkgram.y"
598 { (yyval) = (yyvsp[(1) - (1)]); }
603 -/* Line 1806 of yacc.c */
604 +/* Line 1821 of yacc.c */
605 #line 1087 "awkgram.y"
607 (yyvsp[(2) - (2)])->memory->numbr = -(force_number((yyvsp[(2) - (2)])->memory));
608 @@ -3175,7 +3175,7 @@ regular_loop:
612 -/* Line 1806 of yacc.c */
613 +/* Line 1821 of yacc.c */
614 #line 1093 "awkgram.y"
616 bcfree((yyvsp[(1) - (2)]));
617 @@ -3185,14 +3185,14 @@ regular_loop:
621 -/* Line 1806 of yacc.c */
622 +/* Line 1821 of yacc.c */
623 #line 1098 "awkgram.y"
624 { (yyval) = (yyvsp[(1) - (1)]); }
629 -/* Line 1806 of yacc.c */
630 +/* Line 1821 of yacc.c */
631 #line 1100 "awkgram.y"
633 (yyvsp[(1) - (1)])->opcode = Op_push_re;
634 @@ -3202,21 +3202,21 @@ regular_loop:
638 -/* Line 1806 of yacc.c */
639 +/* Line 1821 of yacc.c */
640 #line 1108 "awkgram.y"
641 { (yyval) = (yyvsp[(1) - (1)]); }
646 -/* Line 1806 of yacc.c */
647 +/* Line 1821 of yacc.c */
648 #line 1110 "awkgram.y"
649 { (yyval) = (yyvsp[(1) - (1)]); }
654 -/* Line 1806 of yacc.c */
655 +/* Line 1821 of yacc.c */
656 #line 1120 "awkgram.y"
658 (yyval) = (yyvsp[(2) - (3)]);
659 @@ -3225,7 +3225,7 @@ regular_loop:
663 -/* Line 1806 of yacc.c */
664 +/* Line 1821 of yacc.c */
665 #line 1127 "awkgram.y"
668 @@ -3236,14 +3236,14 @@ regular_loop:
672 -/* Line 1806 of yacc.c */
673 +/* Line 1821 of yacc.c */
674 #line 1132 "awkgram.y"
675 { in_print = FALSE; in_parens = 0; }
680 -/* Line 1806 of yacc.c */
681 +/* Line 1821 of yacc.c */
682 #line 1133 "awkgram.y"
684 if ((yyvsp[(1) - (3)])->redir_type == redirect_twoway
685 @@ -3256,7 +3256,7 @@ regular_loop:
689 -/* Line 1806 of yacc.c */
690 +/* Line 1821 of yacc.c */
691 #line 1144 "awkgram.y"
693 (yyval) = mk_condition((yyvsp[(3) - (6)]), (yyvsp[(1) - (6)]), (yyvsp[(6) - (6)]), NULL, NULL);
694 @@ -3265,7 +3265,7 @@ regular_loop:
698 -/* Line 1806 of yacc.c */
699 +/* Line 1821 of yacc.c */
700 #line 1149 "awkgram.y"
702 (yyval) = mk_condition((yyvsp[(3) - (9)]), (yyvsp[(1) - (9)]), (yyvsp[(6) - (9)]), (yyvsp[(7) - (9)]), (yyvsp[(9) - (9)]));
703 @@ -3274,14 +3274,14 @@ regular_loop:
707 -/* Line 1806 of yacc.c */
708 +/* Line 1821 of yacc.c */
709 #line 1166 "awkgram.y"
715 -/* Line 1806 of yacc.c */
716 +/* Line 1821 of yacc.c */
717 #line 1168 "awkgram.y"
719 bcfree((yyvsp[(1) - (2)]));
720 @@ -3291,7 +3291,7 @@ regular_loop:
724 -/* Line 1806 of yacc.c */
725 +/* Line 1821 of yacc.c */
726 #line 1181 "awkgram.y"
728 append_param((yyvsp[(1) - (1)])->lextok);
729 @@ -3302,7 +3302,7 @@ regular_loop:
733 -/* Line 1806 of yacc.c */
734 +/* Line 1821 of yacc.c */
735 #line 1187 "awkgram.y"
737 append_param((yyvsp[(3) - (3)])->lextok);
738 @@ -3314,63 +3314,63 @@ regular_loop:
742 -/* Line 1806 of yacc.c */
743 +/* Line 1821 of yacc.c */
744 #line 1194 "awkgram.y"
745 { /* func_params = NULL; */ }
750 -/* Line 1806 of yacc.c */
751 +/* Line 1821 of yacc.c */
752 #line 1196 "awkgram.y"
753 { /* func_params = NULL; */ }
758 -/* Line 1806 of yacc.c */
759 +/* Line 1821 of yacc.c */
760 #line 1198 "awkgram.y"
761 { /* func_params = NULL; */ }
766 -/* Line 1806 of yacc.c */
767 +/* Line 1821 of yacc.c */
768 #line 1204 "awkgram.y"
774 -/* Line 1806 of yacc.c */
775 +/* Line 1821 of yacc.c */
776 #line 1206 "awkgram.y"
777 { (yyval) = (yyvsp[(1) - (1)]); }
782 -/* Line 1806 of yacc.c */
783 +/* Line 1821 of yacc.c */
784 #line 1211 "awkgram.y"
790 -/* Line 1806 of yacc.c */
791 +/* Line 1821 of yacc.c */
792 #line 1213 "awkgram.y"
793 { (yyval) = (yyvsp[(1) - (1)]); }
798 -/* Line 1806 of yacc.c */
799 +/* Line 1821 of yacc.c */
800 #line 1218 "awkgram.y"
801 { (yyval) = mk_expression_list(NULL, (yyvsp[(1) - (1)])); }
806 -/* Line 1806 of yacc.c */
807 +/* Line 1821 of yacc.c */
808 #line 1220 "awkgram.y"
810 (yyval) = mk_expression_list((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]));
811 @@ -3380,35 +3380,35 @@ regular_loop:
815 -/* Line 1806 of yacc.c */
816 +/* Line 1821 of yacc.c */
817 #line 1225 "awkgram.y"
823 -/* Line 1806 of yacc.c */
824 +/* Line 1821 of yacc.c */
825 #line 1227 "awkgram.y"
831 -/* Line 1806 of yacc.c */
832 +/* Line 1821 of yacc.c */
833 #line 1229 "awkgram.y"
839 -/* Line 1806 of yacc.c */
840 +/* Line 1821 of yacc.c */
841 #line 1231 "awkgram.y"
847 -/* Line 1806 of yacc.c */
848 +/* Line 1821 of yacc.c */
849 #line 1237 "awkgram.y"
851 if (do_lint && (yyvsp[(3) - (3)])->lasti->opcode == Op_match_rec)
852 @@ -3420,21 +3420,21 @@ regular_loop:
856 -/* Line 1806 of yacc.c */
857 +/* Line 1821 of yacc.c */
858 #line 1244 "awkgram.y"
859 { (yyval) = mk_boolean((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - (3)])); }
864 -/* Line 1806 of yacc.c */
865 +/* Line 1821 of yacc.c */
866 #line 1246 "awkgram.y"
867 { (yyval) = mk_boolean((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - (3)])); }
872 -/* Line 1806 of yacc.c */
873 +/* Line 1821 of yacc.c */
874 #line 1248 "awkgram.y"
876 if ((yyvsp[(1) - (3)])->lasti->opcode == Op_match_rec)
877 @@ -3455,7 +3455,7 @@ regular_loop:
881 -/* Line 1806 of yacc.c */
882 +/* Line 1821 of yacc.c */
883 #line 1264 "awkgram.y"
886 @@ -3470,7 +3470,7 @@ regular_loop:
890 -/* Line 1806 of yacc.c */
891 +/* Line 1821 of yacc.c */
892 #line 1274 "awkgram.y"
894 if (do_lint && (yyvsp[(3) - (3)])->lasti->opcode == Op_match_rec)
895 @@ -3482,35 +3482,35 @@ regular_loop:
899 -/* Line 1806 of yacc.c */
900 +/* Line 1821 of yacc.c */
901 #line 1281 "awkgram.y"
902 { (yyval) = mk_condition((yyvsp[(1) - (5)]), (yyvsp[(2) - (5)]), (yyvsp[(3) - (5)]), (yyvsp[(4) - (5)]), (yyvsp[(5) - (5)])); }
907 -/* Line 1806 of yacc.c */
908 +/* Line 1821 of yacc.c */
909 #line 1283 "awkgram.y"
910 { (yyval) = (yyvsp[(1) - (1)]); }
915 -/* Line 1806 of yacc.c */
916 +/* Line 1821 of yacc.c */
917 #line 1288 "awkgram.y"
918 { (yyval) = (yyvsp[(1) - (1)]); }
923 -/* Line 1806 of yacc.c */
924 +/* Line 1821 of yacc.c */
925 #line 1290 "awkgram.y"
926 { (yyval) = (yyvsp[(1) - (1)]); }
931 -/* Line 1806 of yacc.c */
932 +/* Line 1821 of yacc.c */
933 #line 1292 "awkgram.y"
935 (yyvsp[(2) - (2)])->opcode = Op_assign_quotient;
936 @@ -3520,49 +3520,49 @@ regular_loop:
940 -/* Line 1806 of yacc.c */
941 +/* Line 1821 of yacc.c */
942 #line 1300 "awkgram.y"
943 { (yyval) = (yyvsp[(1) - (1)]); }
948 -/* Line 1806 of yacc.c */
949 +/* Line 1821 of yacc.c */
950 #line 1302 "awkgram.y"
951 { (yyval) = (yyvsp[(1) - (1)]); }
956 -/* Line 1806 of yacc.c */
957 +/* Line 1821 of yacc.c */
958 #line 1307 "awkgram.y"
959 { (yyval) = (yyvsp[(1) - (1)]); }
964 -/* Line 1806 of yacc.c */
965 +/* Line 1821 of yacc.c */
966 #line 1309 "awkgram.y"
967 { (yyval) = (yyvsp[(1) - (1)]); }
972 -/* Line 1806 of yacc.c */
973 +/* Line 1821 of yacc.c */
974 #line 1314 "awkgram.y"
975 { (yyval) = (yyvsp[(1) - (1)]); }
980 -/* Line 1806 of yacc.c */
981 +/* Line 1821 of yacc.c */
982 #line 1316 "awkgram.y"
983 { (yyval) = (yyvsp[(1) - (1)]); }
988 -/* Line 1806 of yacc.c */
989 +/* Line 1821 of yacc.c */
990 #line 1318 "awkgram.y"
993 @@ -3617,49 +3617,49 @@ regular_loop:
997 -/* Line 1806 of yacc.c */
998 +/* Line 1821 of yacc.c */
999 #line 1373 "awkgram.y"
1000 { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - (3)])); }
1005 -/* Line 1806 of yacc.c */
1006 +/* Line 1821 of yacc.c */
1007 #line 1375 "awkgram.y"
1008 { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - (3)])); }
1013 -/* Line 1806 of yacc.c */
1014 +/* Line 1821 of yacc.c */
1015 #line 1377 "awkgram.y"
1016 { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - (3)])); }
1021 -/* Line 1806 of yacc.c */
1022 +/* Line 1821 of yacc.c */
1023 #line 1379 "awkgram.y"
1024 { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - (3)])); }
1029 -/* Line 1806 of yacc.c */
1030 +/* Line 1821 of yacc.c */
1031 #line 1381 "awkgram.y"
1032 { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - (3)])); }
1037 -/* Line 1806 of yacc.c */
1038 +/* Line 1821 of yacc.c */
1039 #line 1383 "awkgram.y"
1040 { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - (3)])); }
1045 -/* Line 1806 of yacc.c */
1046 +/* Line 1821 of yacc.c */
1047 #line 1385 "awkgram.y"
1050 @@ -3687,7 +3687,7 @@ regular_loop:
1054 -/* Line 1806 of yacc.c */
1055 +/* Line 1821 of yacc.c */
1056 #line 1408 "awkgram.y"
1058 (yyvsp[(2) - (2)])->opcode = Op_postincrement;
1059 @@ -3697,7 +3697,7 @@ regular_loop:
1063 -/* Line 1806 of yacc.c */
1064 +/* Line 1821 of yacc.c */
1065 #line 1413 "awkgram.y"
1067 (yyvsp[(2) - (2)])->opcode = Op_postdecrement;
1068 @@ -3707,7 +3707,7 @@ regular_loop:
1072 -/* Line 1806 of yacc.c */
1073 +/* Line 1821 of yacc.c */
1074 #line 1418 "awkgram.y"
1077 @@ -3732,7 +3732,7 @@ regular_loop:
1081 -/* Line 1806 of yacc.c */
1082 +/* Line 1821 of yacc.c */
1083 #line 1443 "awkgram.y"
1085 (yyval) = mk_getline((yyvsp[(3) - (4)]), (yyvsp[(4) - (4)]), (yyvsp[(1) - (4)]), (yyvsp[(2) - (4)])->redir_type);
1086 @@ -3742,49 +3742,49 @@ regular_loop:
1090 -/* Line 1806 of yacc.c */
1091 +/* Line 1821 of yacc.c */
1092 #line 1449 "awkgram.y"
1093 { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - (3)])); }
1098 -/* Line 1806 of yacc.c */
1099 +/* Line 1821 of yacc.c */
1100 #line 1451 "awkgram.y"
1101 { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - (3)])); }
1106 -/* Line 1806 of yacc.c */
1107 +/* Line 1821 of yacc.c */
1108 #line 1453 "awkgram.y"
1109 { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - (3)])); }
1114 -/* Line 1806 of yacc.c */
1115 +/* Line 1821 of yacc.c */
1116 #line 1455 "awkgram.y"
1117 { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - (3)])); }
1122 -/* Line 1806 of yacc.c */
1123 +/* Line 1821 of yacc.c */
1124 #line 1457 "awkgram.y"
1125 { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - (3)])); }
1130 -/* Line 1806 of yacc.c */
1131 +/* Line 1821 of yacc.c */
1132 #line 1459 "awkgram.y"
1133 { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - (3)])); }
1138 -/* Line 1806 of yacc.c */
1139 +/* Line 1821 of yacc.c */
1140 #line 1464 "awkgram.y"
1142 (yyval) = list_create((yyvsp[(1) - (1)]));
1143 @@ -3793,7 +3793,7 @@ regular_loop:
1147 -/* Line 1806 of yacc.c */
1148 +/* Line 1821 of yacc.c */
1149 #line 1468 "awkgram.y"
1151 if ((yyvsp[(2) - (2)])->opcode == Op_match_rec) {
1152 @@ -3829,14 +3829,14 @@ regular_loop:
1156 -/* Line 1806 of yacc.c */
1157 +/* Line 1821 of yacc.c */
1158 #line 1499 "awkgram.y"
1159 { (yyval) = (yyvsp[(2) - (3)]); }
1164 -/* Line 1806 of yacc.c */
1165 +/* Line 1821 of yacc.c */
1166 #line 1501 "awkgram.y"
1168 (yyval) = snode((yyvsp[(3) - (4)]), (yyvsp[(1) - (4)]));
1169 @@ -3847,7 +3847,7 @@ regular_loop:
1173 -/* Line 1806 of yacc.c */
1174 +/* Line 1821 of yacc.c */
1175 #line 1507 "awkgram.y"
1177 (yyval) = snode((yyvsp[(3) - (4)]), (yyvsp[(1) - (4)]));
1178 @@ -3858,7 +3858,7 @@ regular_loop:
1182 -/* Line 1806 of yacc.c */
1183 +/* Line 1821 of yacc.c */
1184 #line 1513 "awkgram.y"
1186 static short warned1 = FALSE;
1187 @@ -3876,7 +3876,7 @@ regular_loop:
1191 -/* Line 1806 of yacc.c */
1192 +/* Line 1821 of yacc.c */
1193 #line 1528 "awkgram.y"
1195 (yyvsp[(1) - (2)])->opcode = Op_preincrement;
1196 @@ -3886,7 +3886,7 @@ regular_loop:
1200 -/* Line 1806 of yacc.c */
1201 +/* Line 1821 of yacc.c */
1202 #line 1533 "awkgram.y"
1204 (yyvsp[(1) - (2)])->opcode = Op_predecrement;
1205 @@ -3896,7 +3896,7 @@ regular_loop:
1209 -/* Line 1806 of yacc.c */
1210 +/* Line 1821 of yacc.c */
1211 #line 1538 "awkgram.y"
1213 (yyval) = list_create((yyvsp[(1) - (1)]));
1214 @@ -3905,7 +3905,7 @@ regular_loop:
1218 -/* Line 1806 of yacc.c */
1219 +/* Line 1821 of yacc.c */
1220 #line 1542 "awkgram.y"
1222 (yyval) = list_create((yyvsp[(1) - (1)]));
1223 @@ -3914,7 +3914,7 @@ regular_loop:
1227 -/* Line 1806 of yacc.c */
1228 +/* Line 1821 of yacc.c */
1229 #line 1546 "awkgram.y"
1231 if ((yyvsp[(2) - (2)])->lasti->opcode == Op_push_i
1232 @@ -3931,7 +3931,7 @@ regular_loop:
1236 -/* Line 1806 of yacc.c */
1237 +/* Line 1821 of yacc.c */
1238 #line 1558 "awkgram.y"
1241 @@ -3946,7 +3946,7 @@ regular_loop:
1245 -/* Line 1806 of yacc.c */
1246 +/* Line 1821 of yacc.c */
1247 #line 1571 "awkgram.y"
1249 func_use((yyvsp[(1) - (1)])->lasti->func_name, FUNC_USE);
1250 @@ -3956,7 +3956,7 @@ regular_loop:
1254 -/* Line 1806 of yacc.c */
1255 +/* Line 1821 of yacc.c */
1256 #line 1576 "awkgram.y"
1258 /* indirect function call */
1259 @@ -3994,7 +3994,7 @@ regular_loop:
1263 -/* Line 1806 of yacc.c */
1264 +/* Line 1821 of yacc.c */
1265 #line 1612 "awkgram.y"
1267 param_sanity((yyvsp[(3) - (4)]));
1268 @@ -4013,42 +4013,42 @@ regular_loop:
1272 -/* Line 1806 of yacc.c */
1273 +/* Line 1821 of yacc.c */
1274 #line 1629 "awkgram.y"
1280 -/* Line 1806 of yacc.c */
1281 +/* Line 1821 of yacc.c */
1282 #line 1631 "awkgram.y"
1283 { (yyval) = (yyvsp[(1) - (1)]); }
1288 -/* Line 1806 of yacc.c */
1289 +/* Line 1821 of yacc.c */
1290 #line 1636 "awkgram.y"
1296 -/* Line 1806 of yacc.c */
1297 +/* Line 1821 of yacc.c */
1298 #line 1638 "awkgram.y"
1299 { (yyval) = (yyvsp[(1) - (2)]); }
1304 -/* Line 1806 of yacc.c */
1305 +/* Line 1821 of yacc.c */
1306 #line 1643 "awkgram.y"
1307 { (yyval) = (yyvsp[(1) - (1)]); }
1312 -/* Line 1806 of yacc.c */
1313 +/* Line 1821 of yacc.c */
1314 #line 1645 "awkgram.y"
1316 (yyval) = list_merge((yyvsp[(1) - (2)]), (yyvsp[(2) - (2)]));
1317 @@ -4057,7 +4057,7 @@ regular_loop:
1321 -/* Line 1806 of yacc.c */
1322 +/* Line 1821 of yacc.c */
1323 #line 1652 "awkgram.y"
1325 INSTRUCTION *ip = (yyvsp[(1) - (1)])->lasti;
1326 @@ -4076,7 +4076,7 @@ regular_loop:
1330 -/* Line 1806 of yacc.c */
1331 +/* Line 1821 of yacc.c */
1332 #line 1669 "awkgram.y"
1334 INSTRUCTION *t = (yyvsp[(2) - (3)]);
1335 @@ -4095,14 +4095,14 @@ regular_loop:
1339 -/* Line 1806 of yacc.c */
1340 +/* Line 1821 of yacc.c */
1341 #line 1686 "awkgram.y"
1342 { (yyval) = (yyvsp[(1) - (1)]); }
1347 -/* Line 1806 of yacc.c */
1348 +/* Line 1821 of yacc.c */
1349 #line 1688 "awkgram.y"
1351 (yyval) = list_merge((yyvsp[(1) - (2)]), (yyvsp[(2) - (2)]));
1352 @@ -4111,14 +4111,14 @@ regular_loop:
1356 -/* Line 1806 of yacc.c */
1357 +/* Line 1821 of yacc.c */
1358 #line 1695 "awkgram.y"
1359 { (yyval) = (yyvsp[(1) - (2)]); }
1364 -/* Line 1806 of yacc.c */
1365 +/* Line 1821 of yacc.c */
1366 #line 1700 "awkgram.y"
1368 char *var_name = (yyvsp[(1) - (1)])->lextok;
1369 @@ -4131,7 +4131,7 @@ regular_loop:
1373 -/* Line 1806 of yacc.c */
1374 +/* Line 1821 of yacc.c */
1375 #line 1708 "awkgram.y"
1378 @@ -4147,7 +4147,7 @@ regular_loop:
1382 -/* Line 1806 of yacc.c */
1383 +/* Line 1821 of yacc.c */
1384 #line 1722 "awkgram.y"
1386 INSTRUCTION *ip = (yyvsp[(1) - (1)])->nexti;
1387 @@ -4165,7 +4165,7 @@ regular_loop:
1391 -/* Line 1806 of yacc.c */
1392 +/* Line 1821 of yacc.c */
1393 #line 1735 "awkgram.y"
1395 (yyval) = list_append((yyvsp[(2) - (3)]), (yyvsp[(1) - (3)]));
1396 @@ -4176,7 +4176,7 @@ regular_loop:
1400 -/* Line 1806 of yacc.c */
1401 +/* Line 1821 of yacc.c */
1402 #line 1744 "awkgram.y"
1404 (yyvsp[(1) - (1)])->opcode = Op_postincrement;
1405 @@ -4185,7 +4185,7 @@ regular_loop:
1409 -/* Line 1806 of yacc.c */
1410 +/* Line 1821 of yacc.c */
1411 #line 1748 "awkgram.y"
1413 (yyvsp[(1) - (1)])->opcode = Op_postdecrement;
1414 @@ -4194,49 +4194,49 @@ regular_loop:
1418 -/* Line 1806 of yacc.c */
1419 +/* Line 1821 of yacc.c */
1420 #line 1751 "awkgram.y"
1426 -/* Line 1806 of yacc.c */
1427 +/* Line 1821 of yacc.c */
1428 #line 1759 "awkgram.y"
1434 -/* Line 1806 of yacc.c */
1435 +/* Line 1821 of yacc.c */
1436 #line 1763 "awkgram.y"
1442 -/* Line 1806 of yacc.c */
1443 +/* Line 1821 of yacc.c */
1444 #line 1772 "awkgram.y"
1450 -/* Line 1806 of yacc.c */
1451 +/* Line 1821 of yacc.c */
1452 #line 1776 "awkgram.y"
1453 { (yyval) = (yyvsp[(1) - (1)]); yyerrok; }
1458 -/* Line 1806 of yacc.c */
1459 +/* Line 1821 of yacc.c */
1460 #line 1780 "awkgram.y"
1466 -/* Line 1806 of yacc.c */
1467 +/* Line 1821 of yacc.c */
1468 #line 4253 "awkgram.c"
1471 @@ -4485,6 +4485,7 @@ struct token {
1472 # define RESX 0x0800 /* Bell Labs Research extension */
1473 # define BREAK 0x1000 /* break allowed inside */
1474 # define CONTINUE 0x2000 /* continue allowed inside */
1476 NODE *(*ptr)(int); /* function that implements this keyword */
1479 @@ -4542,9 +4543,9 @@ static const struct token tokentab[] = {
1480 {"for", Op_K_for, LEX_FOR, BREAK|CONTINUE, 0},
1481 {"func", Op_func, LEX_FUNCTION, NOT_POSIX|NOT_OLD, 0},
1482 {"function",Op_func, LEX_FUNCTION, NOT_OLD, 0},
1483 -{"gensub", Op_builtin, LEX_BUILTIN, GAWKX|A(3)|A(4), do_gensub},
1484 +{"gensub", Op_sub_builtin, LEX_BUILTIN, GAWKX|A(3)|A(4), 0},
1485 {"getline", Op_K_getline_redir, LEX_GETLINE, NOT_OLD, 0},
1486 -{"gsub", Op_builtin, LEX_BUILTIN, NOT_OLD|A(2)|A(3), do_gsub},
1487 +{"gsub", Op_sub_builtin, LEX_BUILTIN, NOT_OLD|A(2)|A(3), 0},
1488 {"if", Op_K_if, LEX_IF, 0, 0},
1489 {"in", Op_symbol, LEX_IN, 0, 0},
1490 {"include", Op_symbol, LEX_INCLUDE, GAWKX, 0},
1491 @@ -4575,7 +4576,7 @@ static const struct token tokentab[] = {
1493 {"strftime", Op_builtin, LEX_BUILTIN, GAWKX|A(0)|A(1)|A(2)|A(3), do_strftime},
1494 {"strtonum", Op_builtin, LEX_BUILTIN, GAWKX|A(1), do_strtonum},
1495 -{"sub", Op_builtin, LEX_BUILTIN, NOT_OLD|A(2)|A(3), do_sub},
1496 +{"sub", Op_sub_builtin, LEX_BUILTIN, NOT_OLD|A(2)|A(3), 0},
1497 {"substr", Op_builtin, LEX_BUILTIN, A(2)|A(3), do_substr},
1498 {"switch", Op_K_switch, LEX_SWITCH, GAWKX|BREAK, 0},
1499 {"system", Op_builtin, LEX_BUILTIN, NOT_OLD|A(1), do_system},
1500 @@ -6286,8 +6287,6 @@ snode(INSTRUCTION *subn, INSTRUCTION *r)
1504 - r->builtin = tokentab[idx].ptr;
1506 /* check against how many args. are allowed for this builtin */
1507 args_allowed = tokentab[idx].flags & ARGS;
1508 if (args_allowed && (args_allowed & A(nexp)) == 0) {
1509 @@ -6296,7 +6295,85 @@ snode(INSTRUCTION *subn, INSTRUCTION *r)
1513 + /* special processing for sub, gsub and gensub */
1515 + if (tokentab[idx].value == Op_sub_builtin) {
1516 + const char *operator = tokentab[idx].operator;
1520 + arg = subn->nexti; /* first arg list */
1521 + (void) mk_rexp(arg);
1523 + if (strcmp(operator, "gensub") != 0) {
1524 + /* sun and gsub */
1526 + if (strcmp(operator, "gsub") == 0)
1527 + r->sub_flags |= GSUB;
1529 + arg = arg->lasti->nexti; /* 2nd arg list */
1531 + INSTRUCTION *expr;
1532 + expr = list_create(instruction(Op_push_i));
1533 + expr->nexti->memory = mk_number((AWKNUM) 0.0, (PERM|NUMCUR|NUMBER));
1534 + (void) mk_expression_list(subn,
1535 + list_append(expr, instruction(Op_field_spec)));
1538 + arg = arg->lasti->nexti; /* third arg list */
1540 + if (ip->opcode == Op_push_i) {
1542 + lintwarn(_("%s: string literal as last arg of substitute has no effect"),
1544 + r->sub_flags |= LITERAL;
1546 + if (make_assignable(ip) == NULL)
1547 + yyerror(_("%s third parameter is not a changeable object"),
1550 + ip->do_reference = TRUE;
1553 + r->expr_count = count_expressions(&subn, FALSE);
1556 + (void) list_append(subn, r);
1558 + /* add after_assign code */
1559 + if (ip->opcode == Op_push_lhs && ip->memory->type == Node_var && ip->memory->var_assign) {
1560 + (void) list_append(subn, instruction(Op_var_assign));
1561 + subn->lasti->memory = ip->memory;
1562 + subn->lasti->assign_var = ip->memory->var_assign;
1563 + r->sub_flags |= AFTER_ASSIGN;
1564 + } else if (ip->opcode == Op_field_spec_lhs) {
1565 + (void) list_append(subn, instruction(Op_field_assign));
1566 + subn->lasti->field_assign = (Func_ptr) 0;
1567 + ip->target_assign = subn->lasti;
1568 + r->sub_flags |= AFTER_ASSIGN;
1575 + r->sub_flags |= GENSUB;
1577 + ip = instruction(Op_push_i);
1578 + ip->memory = mk_number((AWKNUM) 0.0, (PERM|NUMCUR|NUMBER));
1579 + (void) mk_expression_list(subn,
1580 + list_append(list_create(ip), instruction(Op_field_spec)));
1583 + r->expr_count = count_expressions(&subn, FALSE);
1584 + return list_append(subn, r);
1588 + r->builtin = tokentab[idx].ptr;
1590 /* special case processing for a few builtins */
1592 if (r->builtin == do_length) {
1594 /* no args. Use $0 */
1595 @@ -6338,71 +6415,6 @@ snode(INSTRUCTION *subn, INSTRUCTION *r)
1596 if (/*ip == arg->nexti && */ ip->opcode == Op_push)
1597 ip->opcode = Op_push_array;
1599 - } else if (r->builtin == do_sub || r->builtin == do_gsub) {
1600 - int literal = FALSE;
1602 - arg = subn->nexti; /* first arg list */
1603 - (void) mk_rexp(arg);
1605 - arg = arg->lasti->nexti; /* 2nd arg list */
1607 - INSTRUCTION *expr;
1608 - expr = list_create(instruction(Op_push_i));
1609 - expr->nexti->memory = mk_number((AWKNUM) 0.0, (PERM|NUMCUR|NUMBER));
1610 - (void) mk_expression_list(subn,
1611 - list_append(expr, instruction(Op_field_spec)));
1614 - arg = arg->lasti->nexti; /* third arg list */
1616 - if (ip->opcode == Op_push_i) {
1618 - lintwarn(_("%s: string literal as last arg of substitute has no effect"),
1619 - (r->builtin == do_sub) ? "sub" : "gsub");
1622 - if (make_assignable(ip) == NULL)
1623 - yyerror(_("%s third parameter is not a changeable object"),
1624 - (r->builtin == do_sub) ? "sub" : "gsub");
1626 - ip->do_reference = TRUE;
1629 - /* kludge: This is one of the few cases
1630 - * when we need to know the type of item on stack.
1631 - * In case of string literal as the last argument,
1632 - * pass 4 as # of args (See sub_common code in builtin.c).
1633 - * Other cases like length(array or scalar) seem
1637 - r->expr_count = count_expressions(&subn, FALSE) + !!literal;
1640 - (void) list_append(subn, r);
1642 - /* add after_assign bytecode(s) */
1643 - if (ip->opcode == Op_push_lhs && ip->memory->type == Node_var && ip->memory->var_assign) {
1644 - (void) list_append(subn, instruction(Op_var_assign));
1645 - subn->lasti->memory = ip->memory;
1646 - subn->lasti->assign_var = ip->memory->var_assign;
1647 - } else if (ip->opcode == Op_field_spec_lhs) {
1648 - (void) list_append(subn, instruction(Op_field_assign));
1649 - subn->lasti->field_assign = (Func_ptr) 0;
1650 - ip->target_assign = subn->lasti;
1653 - } else if (r->builtin == do_gensub) {
1655 - arg = subn->nexti->lasti->nexti->lasti->nexti; /* 3rd arg list */
1656 - ip = instruction(Op_push_i);
1657 - ip->memory = mk_number((AWKNUM) 0.0, (PERM|NUMCUR|NUMBER));
1658 - (void) mk_expression_list(subn,
1659 - list_append(list_create(ip),
1660 - instruction(Op_field_spec)));
1662 - arg = subn->nexti; /* first arg list */
1663 - (void) mk_rexp(arg);
1664 } else if (r->builtin == do_split) {
1665 arg = subn->nexti->lasti->nexti; /* 2nd arg list */
1667 diff --git a/awkgram.y b/awkgram.y
1668 index 6b28b52..4553d09 100644
1671 @@ -1795,6 +1795,7 @@ struct token {
1672 # define RESX 0x0800 /* Bell Labs Research extension */
1673 # define BREAK 0x1000 /* break allowed inside */
1674 # define CONTINUE 0x2000 /* continue allowed inside */
1676 NODE *(*ptr)(int); /* function that implements this keyword */
1679 @@ -1852,9 +1853,9 @@ static const struct token tokentab[] = {
1680 {"for", Op_K_for, LEX_FOR, BREAK|CONTINUE, 0},
1681 {"func", Op_func, LEX_FUNCTION, NOT_POSIX|NOT_OLD, 0},
1682 {"function",Op_func, LEX_FUNCTION, NOT_OLD, 0},
1683 -{"gensub", Op_builtin, LEX_BUILTIN, GAWKX|A(3)|A(4), do_gensub},
1684 +{"gensub", Op_sub_builtin, LEX_BUILTIN, GAWKX|A(3)|A(4), 0},
1685 {"getline", Op_K_getline_redir, LEX_GETLINE, NOT_OLD, 0},
1686 -{"gsub", Op_builtin, LEX_BUILTIN, NOT_OLD|A(2)|A(3), do_gsub},
1687 +{"gsub", Op_sub_builtin, LEX_BUILTIN, NOT_OLD|A(2)|A(3), 0},
1688 {"if", Op_K_if, LEX_IF, 0, 0},
1689 {"in", Op_symbol, LEX_IN, 0, 0},
1690 {"include", Op_symbol, LEX_INCLUDE, GAWKX, 0},
1691 @@ -1885,7 +1886,7 @@ static const struct token tokentab[] = {
1693 {"strftime", Op_builtin, LEX_BUILTIN, GAWKX|A(0)|A(1)|A(2)|A(3), do_strftime},
1694 {"strtonum", Op_builtin, LEX_BUILTIN, GAWKX|A(1), do_strtonum},
1695 -{"sub", Op_builtin, LEX_BUILTIN, NOT_OLD|A(2)|A(3), do_sub},
1696 +{"sub", Op_sub_builtin, LEX_BUILTIN, NOT_OLD|A(2)|A(3), 0},
1697 {"substr", Op_builtin, LEX_BUILTIN, A(2)|A(3), do_substr},
1698 {"switch", Op_K_switch, LEX_SWITCH, GAWKX|BREAK, 0},
1699 {"system", Op_builtin, LEX_BUILTIN, NOT_OLD|A(1), do_system},
1700 @@ -3596,8 +3597,6 @@ snode(INSTRUCTION *subn, INSTRUCTION *r)
1704 - r->builtin = tokentab[idx].ptr;
1706 /* check against how many args. are allowed for this builtin */
1707 args_allowed = tokentab[idx].flags & ARGS;
1708 if (args_allowed && (args_allowed & A(nexp)) == 0) {
1709 @@ -3606,7 +3605,85 @@ snode(INSTRUCTION *subn, INSTRUCTION *r)
1713 + /* special processing for sub, gsub and gensub */
1715 + if (tokentab[idx].value == Op_sub_builtin) {
1716 + const char *operator = tokentab[idx].operator;
1720 + arg = subn->nexti; /* first arg list */
1721 + (void) mk_rexp(arg);
1723 + if (strcmp(operator, "gensub") != 0) {
1724 + /* sun and gsub */
1726 + if (strcmp(operator, "gsub") == 0)
1727 + r->sub_flags |= GSUB;
1729 + arg = arg->lasti->nexti; /* 2nd arg list */
1731 + INSTRUCTION *expr;
1732 + expr = list_create(instruction(Op_push_i));
1733 + expr->nexti->memory = mk_number((AWKNUM) 0.0, (PERM|NUMCUR|NUMBER));
1734 + (void) mk_expression_list(subn,
1735 + list_append(expr, instruction(Op_field_spec)));
1738 + arg = arg->lasti->nexti; /* third arg list */
1740 + if (ip->opcode == Op_push_i) {
1742 + lintwarn(_("%s: string literal as last arg of substitute has no effect"),
1744 + r->sub_flags |= LITERAL;
1746 + if (make_assignable(ip) == NULL)
1747 + yyerror(_("%s third parameter is not a changeable object"),
1750 + ip->do_reference = TRUE;
1753 + r->expr_count = count_expressions(&subn, FALSE);
1756 + (void) list_append(subn, r);
1758 + /* add after_assign code */
1759 + if (ip->opcode == Op_push_lhs && ip->memory->type == Node_var && ip->memory->var_assign) {
1760 + (void) list_append(subn, instruction(Op_var_assign));
1761 + subn->lasti->memory = ip->memory;
1762 + subn->lasti->assign_var = ip->memory->var_assign;
1763 + r->sub_flags |= AFTER_ASSIGN;
1764 + } else if (ip->opcode == Op_field_spec_lhs) {
1765 + (void) list_append(subn, instruction(Op_field_assign));
1766 + subn->lasti->field_assign = (Func_ptr) 0;
1767 + ip->target_assign = subn->lasti;
1768 + r->sub_flags |= AFTER_ASSIGN;
1775 + r->sub_flags |= GENSUB;
1777 + ip = instruction(Op_push_i);
1778 + ip->memory = mk_number((AWKNUM) 0.0, (PERM|NUMCUR|NUMBER));
1779 + (void) mk_expression_list(subn,
1780 + list_append(list_create(ip), instruction(Op_field_spec)));
1783 + r->expr_count = count_expressions(&subn, FALSE);
1784 + return list_append(subn, r);
1788 + r->builtin = tokentab[idx].ptr;
1790 /* special case processing for a few builtins */
1792 if (r->builtin == do_length) {
1794 /* no args. Use $0 */
1795 @@ -3648,71 +3725,6 @@ snode(INSTRUCTION *subn, INSTRUCTION *r)
1796 if (/*ip == arg->nexti && */ ip->opcode == Op_push)
1797 ip->opcode = Op_push_array;
1799 - } else if (r->builtin == do_sub || r->builtin == do_gsub) {
1800 - int literal = FALSE;
1802 - arg = subn->nexti; /* first arg list */
1803 - (void) mk_rexp(arg);
1805 - arg = arg->lasti->nexti; /* 2nd arg list */
1807 - INSTRUCTION *expr;
1808 - expr = list_create(instruction(Op_push_i));
1809 - expr->nexti->memory = mk_number((AWKNUM) 0.0, (PERM|NUMCUR|NUMBER));
1810 - (void) mk_expression_list(subn,
1811 - list_append(expr, instruction(Op_field_spec)));
1814 - arg = arg->lasti->nexti; /* third arg list */
1816 - if (ip->opcode == Op_push_i) {
1818 - lintwarn(_("%s: string literal as last arg of substitute has no effect"),
1819 - (r->builtin == do_sub) ? "sub" : "gsub");
1822 - if (make_assignable(ip) == NULL)
1823 - yyerror(_("%s third parameter is not a changeable object"),
1824 - (r->builtin == do_sub) ? "sub" : "gsub");
1826 - ip->do_reference = TRUE;
1829 - /* kludge: This is one of the few cases
1830 - * when we need to know the type of item on stack.
1831 - * In case of string literal as the last argument,
1832 - * pass 4 as # of args (See sub_common code in builtin.c).
1833 - * Other cases like length(array or scalar) seem
1837 - r->expr_count = count_expressions(&subn, FALSE) + !!literal;
1840 - (void) list_append(subn, r);
1842 - /* add after_assign bytecode(s) */
1843 - if (ip->opcode == Op_push_lhs && ip->memory->type == Node_var && ip->memory->var_assign) {
1844 - (void) list_append(subn, instruction(Op_var_assign));
1845 - subn->lasti->memory = ip->memory;
1846 - subn->lasti->assign_var = ip->memory->var_assign;
1847 - } else if (ip->opcode == Op_field_spec_lhs) {
1848 - (void) list_append(subn, instruction(Op_field_assign));
1849 - subn->lasti->field_assign = (Func_ptr) 0;
1850 - ip->target_assign = subn->lasti;
1853 - } else if (r->builtin == do_gensub) {
1855 - arg = subn->nexti->lasti->nexti->lasti->nexti; /* 3rd arg list */
1856 - ip = instruction(Op_push_i);
1857 - ip->memory = mk_number((AWKNUM) 0.0, (PERM|NUMCUR|NUMBER));
1858 - (void) mk_expression_list(subn,
1859 - list_append(list_create(ip),
1860 - instruction(Op_field_spec)));
1862 - arg = subn->nexti; /* first arg list */
1863 - (void) mk_rexp(arg);
1864 } else if (r->builtin == do_split) {
1865 arg = subn->nexti->lasti->nexti; /* 2nd arg list */
1867 diff --git a/builtin.c b/builtin.c
1868 index 724ea6d..d554930 100644
1871 @@ -72,7 +72,6 @@ extern NODE **fields_arr;
1872 extern int output_is_tty;
1873 extern FILE *output_fp;
1875 -static NODE *sub_common(int nargs, long how_many, int backdigs);
1877 #define POP_TWO_SCALARS(s1, s2) \
1878 s2 = POP_SCALAR(); \
1879 @@ -2319,7 +2318,7 @@ do_match(int nargs)
1880 return make_number((AWKNUM) rstart);
1883 -/* sub_common --- the common code (does the work) for sub, gsub, and gensub */
1884 +/* do_sub --- do the work for sub, gsub, and gensub */
1887 * Gsub can be tricksy; particularly when handling the case of null strings.
1888 @@ -2412,12 +2411,12 @@ do_match(int nargs)
1889 * NB: `howmany' conflicts with a SunOS 4.x macro in <sys/param.h>.
1893 -sub_common(int nargs, long how_many, int backdigs)
1895 +do_sub(int nargs, unsigned int flags, int *num_matches)
1904 @@ -2434,38 +2433,77 @@ sub_common(int nargs, long how_many, int backdigs)
1905 NODE *s; /* subst. pattern */
1906 NODE *t; /* string to make sub. in; $0 if none given */
1909 - int global = (how_many == -1);
1910 + NODE **lhs = NULL;
1911 + long how_many = 1; /* one substitution for sub, also gensub default */
1914 int lastmatchnonzero;
1915 char *mb_indices = NULL;
1917 - tmp = PEEK(2); /* take care of regexp early, in case re_update is fatal */
1918 - rp = re_update(tmp);
1920 - /* original string */
1921 - if (nargs == 4) { /* kludge: no of items on stack is really 3,
1922 - * See snode(..) in awkgram.y
1926 + if ((flags & GENSUB) != 0) {
1931 + rp = re_update(tmp);
1933 + t = POP_STRING(); /* original string */
1935 + t1 = POP_SCALAR(); /* value of global flag */
1936 + if ((t1->flags & (STRCUR|STRING)) != 0) {
1937 + if (t1->stlen > 0 && (t1->stptr[0] == 'g' || t1->stptr[0] == 'G'))
1940 + d = force_number(t1);
1942 + if ((t1->flags & NUMCUR) != 0)
1943 + goto set_how_many;
1948 + d = force_number(t1);
1952 + else if (d < LONG_MAX)
1955 + how_many = LONG_MAX;
1957 + warning(_("gensub: third argument of 0 treated as 1"));
1962 - lhs = POP_ADDRESS();
1963 - t = force_string(*lhs);
1965 + /* take care of regexp early, in case re_update is fatal */
1968 + rp = re_update(tmp);
1970 + if ((flags & GSUB) != 0)
1973 + /* original string */
1975 + if ((flags & LITERAL) != 0)
1978 + lhs = POP_ADDRESS();
1979 + t = force_string(*lhs);
1983 + global = (how_many == -1);
1985 - s = POP_STRING(); /* replacement text */
1986 + s = POP_STRING(); /* replacement text */
1987 decr_sp(); /* regexp, already updated above */
1989 /* do the search early to avoid work on non-match */
1990 if (research(rp, t->stptr, 0, t->stlen, RE_NEED_START) == -1 ||
1991 - RESTART(rp, t->stptr) > t->stlen) {
1995 - return make_number((AWKNUM) 0.0);
1997 + RESTART(rp, t->stptr) > t->stlen)
2002 @@ -2476,7 +2514,7 @@ sub_common(int nargs, long how_many, int backdigs)
2004 replend = repl + s->stlen;
2005 repllen = replend - repl;
2006 - emalloc(buf, char *, buflen + 2, "sub_common");
2007 + emalloc(buf, char *, buflen + 2, "do_sub");
2009 buf[buflen + 1] = '\0';
2011 @@ -2490,7 +2528,7 @@ sub_common(int nargs, long how_many, int backdigs)
2014 if (gawk_mb_cur_max > 1 && repllen > 0) {
2015 - emalloc(mb_indices, char *, repllen * sizeof(char), "sub_common");
2016 + emalloc(mb_indices, char *, repllen * sizeof(char), "do_sub");
2017 index_multibyte_buffer(repl, mb_indices, repllen);
2020 @@ -2500,7 +2538,7 @@ sub_common(int nargs, long how_many, int backdigs)
2023 } else if (*scan == '\\') {
2024 - if (backdigs) { /* gensub, behave sanely */
2025 + if (flags & GENSUB) { /* gensub, behave sanely */
2026 if (isdigit((unsigned char) scan[1])) {
2029 @@ -2575,7 +2613,7 @@ sub_common(int nargs, long how_many, int backdigs)
2030 && (gawk_mb_cur_max == 1
2031 || (repllen > 0 && mb_indices[scan - repl] == 1))
2033 - if (backdigs) { /* gensub, behave sanely */
2034 + if (flags & GENSUB) { /* gensub, behave sanely */
2035 if (isdigit((unsigned char) scan[1])) {
2036 int dig = scan[1] - '0';
2037 if (dig < NUMSUBPATS(rp, t->stptr) && SUBPATSTART(rp, tp->stptr, dig) != -1) {
2038 @@ -2619,7 +2657,7 @@ sub_common(int nargs, long how_many, int backdigs)
2039 textlen = text + textlen - matchend;
2042 - if ((current >= how_many && !global)
2043 + if ((current >= how_many && ! global)
2044 || ((long) textlen <= 0 && matchstart == matchend)
2045 || research(rp, t->stptr, text - t->stptr, textlen, RE_NEED_START) == -1)
2047 @@ -2628,7 +2666,7 @@ sub_common(int nargs, long how_many, int backdigs)
2049 if (buflen - sofar - textlen - 1) {
2050 buflen = sofar + textlen + 2;
2051 - erealloc(buf, char *, buflen, "sub_common");
2052 + erealloc(buf, char *, buflen, "do_sub");
2055 for (scan = matchend; scan < text + textlen; scan++)
2056 @@ -2636,102 +2674,39 @@ sub_common(int nargs, long how_many, int backdigs)
2062 - if (lhs != NULL) {
2063 - if (matches > 0) {
2065 - *lhs = make_str_node(buf, textlen, ALREADY_MALLOCED);
2073 if (mb_indices != NULL)
2076 - return make_number((AWKNUM) matches);
2079 -/* do_gsub --- global substitution */
2084 - return sub_common(nargs, -1, FALSE);
2087 -/* do_sub --- single substitution */
2092 - return sub_common(nargs, 1, FALSE);
2095 -/* do_gensub --- fix up the tree for sub_common for the gensub function */
2098 -do_gensub(int nargs)
2100 - NODE *t, *tmp, *target, *ret;
2101 - long how_many = 1; /* default is one substitution */
2104 - tmp = POP_STRING(); /* target */
2105 - t = POP_SCALAR(); /* value of global flag */
2108 - * We make copy of the original target string, and pass that
2109 - * in to sub_common() as the target to make the substitution in.
2110 - * We will then return the result string as the return value of
2114 - target = make_string(tmp->stptr, tmp->stlen);
2116 - PUSH_ADDRESS(& target);
2118 - if ((t->flags & (STRCUR|STRING)) != 0) {
2119 - if (t->stlen > 0 && (t->stptr[0] == 'g' || t->stptr[0] == 'G'))
2122 - d = force_number(t);
2126 - if ((t->flags & NUMCUR) != 0)
2127 - goto set_how_many;
2128 + *num_matches = matches;
2129 + if ((matches == 0 || (flags & LITERAL) != 0) && buf != NULL)
2133 + if (flags & GENSUB) {
2134 + if (matches > 0) {
2135 + /* return the result string */
2137 + return make_str_node(buf, textlen, ALREADY_MALLOCED);
2140 - d = force_number(t);
2144 - else if (d < LONG_MAX)
2147 - how_many = LONG_MAX;
2149 - warning(_("gensub: third argument of 0 treated as 1"));
2154 - ret = sub_common(3, how_many, TRUE);
2156 + /* return the original string */
2161 - * Note that we don't care what sub_common() returns, since the
2162 - * easiest thing for the programmer is to return the string, even
2163 - * if no substitutions were done.
2165 + /* For a string literal, must not change the original string. */
2166 + if (flags & LITERAL)
2168 + else if (matches > 0) {
2170 + *lhs = make_str_node(buf, textlen, ALREADY_MALLOCED);
2174 + return make_number((AWKNUM) matches);
2178 /* make_integer - Convert an integer to a number node. */
2181 diff --git a/debug.c b/debug.c
2182 index 9b9db34..404042c 100644
2185 @@ -3740,7 +3740,16 @@ print_instruction(INSTRUCTION *pc, Func_print print_func, FILE *fp, int in_dump)
2189 - print_func(fp, "[set_%s]\n", pc->memory->vname);
2190 + if (pc->assign_var)
2191 + print_func(fp, "[set_%s()]", pc->memory->vname);
2192 + print_func(fp, "\n");
2195 + case Op_field_assign:
2196 + if (pc->field_assign)
2197 + print_func(fp, "[%s]", pc->field_assign == reset_record ?
2198 + "reset_record()" : "invalidate_field0()");
2199 + print_func(fp, "\n");
2202 case Op_field_spec_lhs:
2203 @@ -3830,6 +3839,27 @@ print_instruction(INSTRUCTION *pc, Func_print print_func, FILE *fp, int in_dump)
2204 pc->line_range, pc->target_jmp);
2207 + case Op_sub_builtin:
2209 + const char *fname = "sub";
2210 + static const struct flagtab values[] = {
2212 + { GENSUB, "GENSUB" },
2213 + { AFTER_ASSIGN, "AFTER_ASSIGN" },
2214 + { LITERAL, "LITERAL" },
2218 + if (pc->sub_flags & GSUB)
2220 + else if (pc->sub_flags & GENSUB)
2222 + print_func(fp, "%s [arg_count = %ld] [sub_flags = %s]\n",
2223 + fname, pc->expr_count,
2224 + genflags2str(pc->sub_flags, values));
2230 const char *fname = getfname(pc->builtin);
2231 diff --git a/eval.c b/eval.c
2232 index 4132474..bdbd04b 100644
2235 @@ -348,6 +348,7 @@ static struct optypetab {
2236 { "Op_K_getline", "getline" },
2237 { "Op_K_nextfile", "nextfile" },
2238 { "Op_builtin", NULL },
2239 + { "Op_sub_builtin", NULL },
2240 { "Op_in_array", " in " },
2241 { "Op_func_call", NULL },
2242 { "Op_indirect_func_call", NULL },
2243 @@ -2114,11 +2115,13 @@ post:
2248 + if (pc->assign_var)
2252 case Op_field_assign:
2253 - pc->field_assign();
2254 + if (pc->field_assign)
2255 + pc->field_assign();
2259 @@ -2256,7 +2259,34 @@ arrayfor:
2265 + case Op_sub_builtin:
2267 + /* sub, gsub and gensub */
2271 + r = do_sub(pc->expr_count, pc->sub_flags, & matches);
2274 + if (matches == 0 && (pc->sub_flags & AFTER_ASSIGN) != 0) {
2276 + /* For sub and gsub, must not execute after_assign code;
2277 + * If the target is a FIELD, this means no field re-splitting or
2278 + * $0 reconstruction. For a special variable as target,
2279 + * set_XX routine is not called.
2283 + assert(ni->opcode == Op_field_assign || ni->opcode == Op_var_assign);
2284 + if (ni->opcode == Op_field_assign)
2285 + ni->field_assign = (Func_ptr) 0;
2287 + ni->assign_var = (Func_ptr) 0;
2293 do_print(pc->expr_count, pc->redir_type);
2295 diff --git a/profile.c b/profile.c
2296 index cba8be9..01d1e42 100644
2299 @@ -507,6 +507,20 @@ cleanup:
2300 case Op_after_endfile:
2303 + case Op_sub_builtin:
2305 + const char *fname = "sub";
2306 + if (pc->sub_flags & GSUB)
2308 + else if (pc->sub_flags & GENSUB)
2310 + tmp = pp_list(pc->expr_count, "()", ", ");
2311 + str = pp_concat(fname, tmp, "");
2313 + pp_push(Op_sub_builtin, str, CAN_FREE);
2319 static char *ext_func = "extension_function()";