This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
perl 3.0 patch #44 patch #42, continued
[perl5.git] / cons.c
CommitLineData
7e1cf235 1/* $Header: cons.c,v 3.0.1.10 91/01/11 17:33:33 lwall Locked $
a687059c
LW
2 *
3 * Copyright (c) 1989, Larry Wall
4 *
5 * You may distribute under the terms of the GNU General Public License
6 * as specified in the README file that comes with the perl 3.0 kit.
7 *
8 * $Log: cons.c,v $
7e1cf235
LW
9 * Revision 3.0.1.10 91/01/11 17:33:33 lwall
10 * patch42: the perl debugger was dumping core frequently
11 * patch42: the postincrement to preincrement optimizer was overzealous
12 * patch42: foreach didn't localize its temp array properly
13 *
5303340c
LW
14 * Revision 3.0.1.9 90/11/10 01:10:50 lwall
15 * patch38: random cleanup
16 *
39c3038c
LW
17 * Revision 3.0.1.8 90/10/15 15:41:09 lwall
18 * patch29: added caller
19 * patch29: scripts now run at almost full speed under the debugger
20 * patch29: the debugger now understands packages and evals
21 * patch29: package behavior is now more consistent
22 *
ff8e2863
LW
23 * Revision 3.0.1.7 90/08/09 02:35:52 lwall
24 * patch19: did preliminary work toward debugging packages and evals
25 * patch19: Added support for linked-in C subroutines
26 * patch19: Numeric literals are now stored only in floating point
27 * patch19: Added -c switch to do compilation only
28 *
0f85fab0
LW
29 * Revision 3.0.1.6 90/03/27 15:35:21 lwall
30 * patch16: formats didn't work inside eval
31 * patch16: $foo++ now optimized to ++$foo where value not required
32 *
ff2452de
LW
33 * Revision 3.0.1.5 90/03/12 16:23:10 lwall
34 * patch13: perl -d coredumped on scripts with subs that did explicit return
35 *
afd9f252
LW
36 * Revision 3.0.1.4 90/02/28 16:44:00 lwall
37 * patch9: subs which return by both mechanisms can clobber local return data
38 * patch9: changed internal SUB label to _SUB_
39 * patch9: line numbers were bogus during certain portions of foreach evaluation
40 *
663a0e37
LW
41 * Revision 3.0.1.3 89/12/21 19:20:25 lwall
42 * patch7: made nested or recursive foreach work right
43 *
0d3e774c
LW
44 * Revision 3.0.1.2 89/11/17 15:08:53 lwall
45 * patch5: nested foreach on same array didn't work
46 *
03a14243
LW
47 * Revision 3.0.1.1 89/10/26 23:09:01 lwall
48 * patch1: numeric switch optimization was broken
49 * patch1: unless was broken when run under the debugger
50 *
a687059c
LW
51 * Revision 3.0 89/10/18 15:10:23 lwall
52 * 3.0 baseline
53 *
54 */
55
56#include "EXTERN.h"
57#include "perl.h"
58#include "perly.h"
59
60extern char *tokename[];
61extern int yychar;
62
63static int cmd_tosave();
64static int arg_tosave();
65static int spat_tosave();
66
67static bool saw_return;
68
69SUBR *
70make_sub(name,cmd)
71char *name;
72CMD *cmd;
73{
74 register SUBR *sub;
75 STAB *stab = stabent(name,TRUE);
76
77 Newz(101,sub,1,SUBR);
78 if (stab_sub(stab)) {
79 if (dowarn) {
ff8e2863 80 CMD *oldcurcmd = curcmd;
a687059c
LW
81
82 if (cmd)
ff8e2863 83 curcmd = cmd;
a687059c 84 warn("Subroutine %s redefined",name);
ff8e2863
LW
85 curcmd = oldcurcmd;
86 }
87 if (stab_sub(stab)->cmd) {
88 cmd_free(stab_sub(stab)->cmd);
89 afree(stab_sub(stab)->tosave);
a687059c 90 }
a687059c
LW
91 Safefree(stab_sub(stab));
92 }
39c3038c 93 sub->filestab = curcmd->c_filestab;
a687059c
LW
94 saw_return = FALSE;
95 tosave = anew(Nullstab);
96 tosave->ary_fill = 0; /* make 1 based */
97 (void)cmd_tosave(cmd,FALSE); /* this builds the tosave array */
98 sub->tosave = tosave;
99 if (saw_return) {
100 struct compcmd mycompblock;
101
102 mycompblock.comp_true = cmd;
103 mycompblock.comp_alt = Nullcmd;
afd9f252 104 cmd = add_label(savestr("_SUB_"),make_ccmd(C_BLOCK,Nullarg,mycompblock));
a687059c 105 saw_return = FALSE;
ff2452de 106 cmd->c_flags |= CF_TERM;
a687059c
LW
107 }
108 sub->cmd = cmd;
109 stab_sub(stab) = sub;
110 if (perldb) {
39c3038c
LW
111 STR *str;
112 STR *tmpstr = str_static(&str_undef);
a687059c 113
39c3038c
LW
114 sprintf(buf,"%s:%ld",stab_val(curcmd->c_filestab)->str_ptr,
115 (long)subline);
116 str = str_make(buf,0);
a687059c 117 str_cat(str,"-");
ff8e2863 118 sprintf(buf,"%ld",(long)curcmd->c_line);
a687059c
LW
119 str_cat(str,buf);
120 name = str_get(subname);
39c3038c
LW
121 stab_fullname(tmpstr,stab);
122 hstore(stab_xhash(DBsub), tmpstr->str_ptr, tmpstr->str_cur, str, 0);
a687059c
LW
123 str_set(subname,"main");
124 }
125 subline = 0;
126 return sub;
127}
128
ff8e2863
LW
129SUBR *
130make_usub(name, ix, subaddr, filename)
131char *name;
132int ix;
133int (*subaddr)();
134char *filename;
135{
136 register SUBR *sub;
137 STAB *stab = stabent(name,allstabs);
138
139 if (!stab) /* unused function */
140 return;
141 Newz(101,sub,1,SUBR);
142 if (stab_sub(stab)) {
143 if (dowarn)
144 warn("Subroutine %s redefined",name);
145 if (stab_sub(stab)->cmd) {
146 cmd_free(stab_sub(stab)->cmd);
147 afree(stab_sub(stab)->tosave);
148 }
149 Safefree(stab_sub(stab));
150 }
39c3038c 151 sub->filestab = fstab(filename);
ff8e2863
LW
152 sub->usersub = subaddr;
153 sub->userindex = ix;
154 stab_sub(stab) = sub;
155 return sub;
156}
157
0f85fab0
LW
158make_form(stab,fcmd)
159STAB *stab;
160FCMD *fcmd;
161{
162 if (stab_form(stab)) {
163 FCMD *tmpfcmd;
164 FCMD *nextfcmd;
165
166 for (tmpfcmd = stab_form(stab); tmpfcmd; tmpfcmd = nextfcmd) {
167 nextfcmd = tmpfcmd->f_next;
168 if (tmpfcmd->f_expr)
169 arg_free(tmpfcmd->f_expr);
170 if (tmpfcmd->f_unparsed)
171 str_free(tmpfcmd->f_unparsed);
172 if (tmpfcmd->f_pre)
173 Safefree(tmpfcmd->f_pre);
174 Safefree(tmpfcmd);
175 }
176 }
177 stab_form(stab) = fcmd;
178}
179
a687059c
LW
180CMD *
181block_head(tail)
182register CMD *tail;
183{
184 CMD *head;
185 register int opt;
186 register int last_opt = 0;
187 register STAB *last_stab = Nullstab;
188 register int count = 0;
189 register CMD *switchbeg = Nullcmd;
190
191 if (tail == Nullcmd) {
192 return tail;
193 }
194 head = tail->c_head;
195
196 for (tail = head; tail; tail = tail->c_next) {
197
198 /* save one measly dereference at runtime */
199 if (tail->c_type == C_IF) {
200 if (!(tail->ucmd.ccmd.cc_alt = tail->ucmd.ccmd.cc_alt->c_next))
201 tail->c_flags |= CF_TERM;
202 }
203 else if (tail->c_type == C_EXPR) {
204 ARG *arg;
205
206 if (tail->ucmd.acmd.ac_expr)
207 arg = tail->ucmd.acmd.ac_expr;
208 else
209 arg = tail->c_expr;
210 if (arg) {
211 if (arg->arg_type == O_RETURN)
212 tail->c_flags |= CF_TERM;
213 else if (arg->arg_type == O_ITEM && arg[1].arg_type == A_CMD)
214 tail->c_flags |= CF_TERM;
215 }
216 }
217 if (!tail->c_next)
218 tail->c_flags |= CF_TERM;
219
220 if (tail->c_expr && (tail->c_flags & CF_OPTIMIZE) == CFT_FALSE)
221 opt_arg(tail,1, tail->c_type == C_EXPR);
222
223 /* now do a little optimization on case-ish structures */
224 switch(tail->c_flags & (CF_OPTIMIZE|CF_FIRSTNEG|CF_INVERT)) {
225 case CFT_ANCHOR:
226 if (stabent("*",FALSE)) { /* bad assumption here!!! */
227 opt = 0;
228 break;
229 }
230 /* FALL THROUGH */
231 case CFT_STROP:
232 opt = (tail->c_flags & CF_NESURE) ? CFT_STROP : 0;
233 break;
234 case CFT_CCLASS:
235 opt = CFT_STROP;
236 break;
237 case CFT_NUMOP:
238 opt = (tail->c_slen == O_NE ? 0 : CFT_NUMOP);
239 if ((tail->c_flags&(CF_NESURE|CF_EQSURE)) != (CF_NESURE|CF_EQSURE))
240 opt = 0;
241 break;
242 default:
243 opt = 0;
244 }
245 if (opt && opt == last_opt && tail->c_stab == last_stab)
246 count++;
247 else {
248 if (count >= 3) { /* is this the breakeven point? */
249 if (last_opt == CFT_NUMOP)
250 make_nswitch(switchbeg,count);
251 else
252 make_cswitch(switchbeg,count);
253 }
254 if (opt) {
255 count = 1;
256 switchbeg = tail;
257 }
258 else
259 count = 0;
260 }
261 last_opt = opt;
262 last_stab = tail->c_stab;
263 }
264 if (count >= 3) { /* is this the breakeven point? */
265 if (last_opt == CFT_NUMOP)
266 make_nswitch(switchbeg,count);
267 else
268 make_cswitch(switchbeg,count);
269 }
270 return head;
271}
272
273/* We've spotted a sequence of CMDs that all test the value of the same
274 * spat. Thus we can insert a SWITCH in front and jump directly
275 * to the correct one.
276 */
277make_cswitch(head,count)
278register CMD *head;
279int count;
280{
281 register CMD *cur;
282 register CMD **loc;
283 register int i;
284 register int min = 255;
285 register int max = 0;
286
287 /* make a new head in the exact same spot */
288 New(102,cur, 1, CMD);
289#ifdef STRUCTCOPY
290 *cur = *head;
291#else
292 Copy(head,cur,1,CMD);
293#endif
294 Zero(head,1,CMD);
295 head->c_type = C_CSWITCH;
296 head->c_next = cur; /* insert new cmd at front of list */
297 head->c_stab = cur->c_stab;
298
299 Newz(103,loc,258,CMD*);
300 loc++; /* lie a little */
301 while (count--) {
302 if ((cur->c_flags & CF_OPTIMIZE) == CFT_CCLASS) {
303 for (i = 0; i <= 255; i++) {
304 if (!loc[i] && cur->c_short->str_ptr[i>>3] & (1 << (i&7))) {
305 loc[i] = cur;
306 if (i < min)
307 min = i;
308 if (i > max)
309 max = i;
310 }
311 }
312 }
313 else {
314 i = *cur->c_short->str_ptr & 255;
315 if (!loc[i]) {
316 loc[i] = cur;
317 if (i < min)
318 min = i;
319 if (i > max)
320 max = i;
321 }
322 }
323 cur = cur->c_next;
324 }
325 max++;
326 if (min > 0)
327 Copy(&loc[min],&loc[0], max - min, CMD*);
328 loc--;
329 min--;
330 max -= min;
331 for (i = 0; i <= max; i++)
332 if (!loc[i])
333 loc[i] = cur;
334 Renew(loc,max+1,CMD*); /* chop it down to size */
335 head->ucmd.scmd.sc_offset = min;
336 head->ucmd.scmd.sc_max = max;
337 head->ucmd.scmd.sc_next = loc;
338}
339
340make_nswitch(head,count)
341register CMD *head;
342int count;
343{
344 register CMD *cur = head;
345 register CMD **loc;
346 register int i;
347 register int min = 32767;
348 register int max = -32768;
349 int origcount = count;
350 double value; /* or your money back! */
351 short changed; /* so triple your money back! */
352
353 while (count--) {
354 i = (int)str_gnum(cur->c_short);
355 value = (double)i;
356 if (value != cur->c_short->str_u.str_nval)
357 return; /* fractional values--just forget it */
358 changed = i;
359 if (changed != i)
360 return; /* too big for a short */
361 if (cur->c_slen == O_LE)
362 i++;
363 else if (cur->c_slen == O_GE) /* we only do < or > here */
364 i--;
365 if (i < min)
366 min = i;
367 if (i > max)
368 max = i;
369 cur = cur->c_next;
370 }
371 count = origcount;
372 if (max - min > count * 2 + 10) /* too sparse? */
373 return;
374
375 /* now make a new head in the exact same spot */
376 New(104,cur, 1, CMD);
377#ifdef STRUCTCOPY
378 *cur = *head;
379#else
380 Copy(head,cur,1,CMD);
381#endif
382 Zero(head,1,CMD);
383 head->c_type = C_NSWITCH;
384 head->c_next = cur; /* insert new cmd at front of list */
385 head->c_stab = cur->c_stab;
386
387 Newz(105,loc, max - min + 3, CMD*);
388 loc++;
03a14243
LW
389 max -= min;
390 max++;
a687059c
LW
391 while (count--) {
392 i = (int)str_gnum(cur->c_short);
393 i -= min;
a687059c
LW
394 switch(cur->c_slen) {
395 case O_LE:
396 i++;
397 case O_LT:
398 for (i--; i >= -1; i--)
399 if (!loc[i])
400 loc[i] = cur;
401 break;
402 case O_GE:
403 i--;
404 case O_GT:
405 for (i++; i <= max; i++)
406 if (!loc[i])
407 loc[i] = cur;
408 break;
409 case O_EQ:
410 if (!loc[i])
411 loc[i] = cur;
412 break;
413 }
414 cur = cur->c_next;
415 }
416 loc--;
417 min--;
03a14243 418 max++;
a687059c
LW
419 for (i = 0; i <= max; i++)
420 if (!loc[i])
421 loc[i] = cur;
422 head->ucmd.scmd.sc_offset = min;
423 head->ucmd.scmd.sc_max = max;
424 head->ucmd.scmd.sc_next = loc;
425}
426
427CMD *
428append_line(head,tail)
429register CMD *head;
430register CMD *tail;
431{
432 if (tail == Nullcmd)
433 return head;
434 if (!tail->c_head) /* make sure tail is well formed */
435 tail->c_head = tail;
436 if (head != Nullcmd) {
437 tail = tail->c_head; /* get to start of tail list */
438 if (!head->c_head)
439 head->c_head = head; /* start a new head list */
440 while (head->c_next) {
441 head->c_next->c_head = head->c_head;
442 head = head->c_next; /* get to end of head list */
443 }
444 head->c_next = tail; /* link to end of old list */
445 tail->c_head = head->c_head; /* propagate head pointer */
446 }
447 while (tail->c_next) {
448 tail->c_next->c_head = tail->c_head;
449 tail = tail->c_next;
450 }
451 return tail;
452}
453
454CMD *
455dodb(cur)
456CMD *cur;
457{
458 register CMD *cmd;
459 register CMD *head = cur->c_head;
a687059c
LW
460 STR *str;
461
462 if (!head)
463 head = cur;
464 if (!head->c_line)
465 return cur;
39c3038c
LW
466 str = afetch(stab_xarray(curcmd->c_filestab),(int)head->c_line,FALSE);
467 if (str == &str_undef || str->str_nok)
a687059c
LW
468 return cur;
469 str->str_u.str_nval = (double)head->c_line;
470 str->str_nok = 1;
471 Newz(106,cmd,1,CMD);
39c3038c
LW
472 str_magic(str, curcmd->c_filestab, 0, Nullch, 0);
473 str->str_magic->str_u.str_cmd = cmd;
a687059c
LW
474 cmd->c_type = C_EXPR;
475 cmd->ucmd.acmd.ac_stab = Nullstab;
476 cmd->ucmd.acmd.ac_expr = Nullarg;
7e1cf235 477 cmd->c_expr = make_op(O_SUBR, 2,
a687059c 478 stab2arg(A_WORD,DBstab),
39c3038c 479 Nullarg,
a687059c 480 Nullarg);
39c3038c 481 cmd->c_flags |= CF_COND|CF_DBSUB|CFT_D0;
a687059c
LW
482 cmd->c_line = head->c_line;
483 cmd->c_label = head->c_label;
39c3038c
LW
484 cmd->c_filestab = curcmd->c_filestab;
485 cmd->c_stash = curstash;
a687059c
LW
486 return append_line(cmd, cur);
487}
488
489CMD *
490make_acmd(type,stab,cond,arg)
491int type;
492STAB *stab;
493ARG *cond;
494ARG *arg;
495{
496 register CMD *cmd;
497
498 Newz(107,cmd,1,CMD);
499 cmd->c_type = type;
500 cmd->ucmd.acmd.ac_stab = stab;
501 cmd->ucmd.acmd.ac_expr = arg;
502 cmd->c_expr = cond;
503 if (cond)
504 cmd->c_flags |= CF_COND;
afd9f252 505 if (cmdline == NOLINE)
ff8e2863 506 cmd->c_line = curcmd->c_line;
afd9f252 507 else {
a687059c
LW
508 cmd->c_line = cmdline;
509 cmdline = NOLINE;
510 }
39c3038c
LW
511 cmd->c_filestab = curcmd->c_filestab;
512 cmd->c_stash = curstash;
a687059c
LW
513 if (perldb)
514 cmd = dodb(cmd);
515 return cmd;
516}
517
518CMD *
519make_ccmd(type,arg,cblock)
520int type;
521ARG *arg;
522struct compcmd cblock;
523{
524 register CMD *cmd;
525
526 Newz(108,cmd, 1, CMD);
527 cmd->c_type = type;
528 cmd->c_expr = arg;
529 cmd->ucmd.ccmd.cc_true = cblock.comp_true;
530 cmd->ucmd.ccmd.cc_alt = cblock.comp_alt;
531 if (arg)
532 cmd->c_flags |= CF_COND;
afd9f252 533 if (cmdline == NOLINE)
ff8e2863 534 cmd->c_line = curcmd->c_line;
afd9f252 535 else {
a687059c
LW
536 cmd->c_line = cmdline;
537 cmdline = NOLINE;
538 }
39c3038c
LW
539 cmd->c_filestab = curcmd->c_filestab;
540 cmd->c_stash = curstash;
a687059c
LW
541 if (perldb)
542 cmd = dodb(cmd);
543 return cmd;
544}
545
546CMD *
547make_icmd(type,arg,cblock)
548int type;
549ARG *arg;
550struct compcmd cblock;
551{
552 register CMD *cmd;
553 register CMD *alt;
554 register CMD *cur;
555 register CMD *head;
556 struct compcmd ncblock;
557
558 Newz(109,cmd, 1, CMD);
559 head = cmd;
560 cmd->c_type = type;
561 cmd->c_expr = arg;
562 cmd->ucmd.ccmd.cc_true = cblock.comp_true;
563 cmd->ucmd.ccmd.cc_alt = cblock.comp_alt;
564 if (arg)
565 cmd->c_flags |= CF_COND;
afd9f252 566 if (cmdline == NOLINE)
ff8e2863 567 cmd->c_line = curcmd->c_line;
afd9f252 568 else {
a687059c
LW
569 cmd->c_line = cmdline;
570 cmdline = NOLINE;
571 }
39c3038c
LW
572 cmd->c_filestab = curcmd->c_filestab;
573 cmd->c_stash = curstash;
a687059c
LW
574 cur = cmd;
575 alt = cblock.comp_alt;
576 while (alt && alt->c_type == C_ELSIF) {
577 cur = alt;
578 alt = alt->ucmd.ccmd.cc_alt;
579 }
580 if (alt) { /* a real life ELSE at the end? */
581 ncblock.comp_true = alt;
582 ncblock.comp_alt = Nullcmd;
583 alt = append_line(cur,make_ccmd(C_ELSE,Nullarg,ncblock));
584 cur->ucmd.ccmd.cc_alt = alt;
585 }
586 else
587 alt = cur; /* no ELSE, so cur is proxy ELSE */
588
589 cur = cmd;
590 while (cmd) { /* now point everyone at the ELSE */
591 cur = cmd;
592 cmd = cur->ucmd.ccmd.cc_alt;
593 cur->c_head = head;
594 if (cur->c_type == C_ELSIF)
595 cur->c_type = C_IF;
596 if (cur->c_type == C_IF)
597 cur->ucmd.ccmd.cc_alt = alt;
598 if (cur == alt)
599 break;
600 cur->c_next = cmd;
601 }
602 if (perldb)
603 cur = dodb(cur);
604 return cur;
605}
606
607void
608opt_arg(cmd,fliporflop,acmd)
609register CMD *cmd;
610int fliporflop;
611int acmd;
612{
613 register ARG *arg;
614 int opt = CFT_EVAL;
615 int sure = 0;
616 ARG *arg2;
617 int context = 0; /* 0 = normal, 1 = before &&, 2 = before || */
618 int flp = fliporflop;
619
620 if (!cmd)
621 return;
622 if (!(arg = cmd->c_expr)) {
623 cmd->c_flags &= ~CF_COND;
624 return;
625 }
626
627 /* Can we turn && and || into if and unless? */
628
629 if (acmd && !cmd->ucmd.acmd.ac_expr && !(cmd->c_flags & CF_TERM) &&
630 (arg->arg_type == O_AND || arg->arg_type == O_OR) ) {
631 dehoist(arg,1);
632 arg[2].arg_type &= A_MASK; /* don't suppress eval */
633 dehoist(arg,2);
634 cmd->ucmd.acmd.ac_expr = arg[2].arg_ptr.arg_arg;
635 cmd->c_expr = arg[1].arg_ptr.arg_arg;
636 if (arg->arg_type == O_OR)
637 cmd->c_flags ^= CF_INVERT; /* || is like unless */
638 arg->arg_len = 0;
639 free_arg(arg);
640 arg = cmd->c_expr;
641 }
642
643 /* Turn "if (!expr)" into "unless (expr)" */
644
645 if (!(cmd->c_flags & CF_TERM)) { /* unless return value wanted */
646 while (arg->arg_type == O_NOT) {
647 dehoist(arg,1);
648 cmd->c_flags ^= CF_INVERT; /* flip sense of cmd */
649 cmd->c_expr = arg[1].arg_ptr.arg_arg; /* hoist the rest of expr */
650 free_arg(arg);
651 arg = cmd->c_expr; /* here we go again */
652 }
653 }
654
655 if (!arg->arg_len) { /* sanity check */
656 cmd->c_flags |= opt;
657 return;
658 }
659
660 /* for "cond .. cond" we set up for the initial check */
661
662 if (arg->arg_type == O_FLIP)
663 context |= 4;
664
665 /* for "cond && expr" and "cond || expr" we can ignore expr, sort of */
666
667 morecontext:
668 if (arg->arg_type == O_AND)
669 context |= 1;
670 else if (arg->arg_type == O_OR)
671 context |= 2;
672 if (context && (arg[flp].arg_type & A_MASK) == A_EXPR) {
673 arg = arg[flp].arg_ptr.arg_arg;
674 flp = 1;
675 if (arg->arg_type == O_AND || arg->arg_type == O_OR)
676 goto morecontext;
677 }
678 if ((context & 3) == 3)
679 return;
680
681 if (arg[flp].arg_flags & (AF_PRE|AF_POST)) {
682 cmd->c_flags |= opt;
7e1cf235
LW
683 if (acmd && !cmd->ucmd.acmd.ac_expr && !(cmd->c_flags & CF_TERM)
684 && cmd->c_expr->arg_type == O_ITEM) {
0f85fab0
LW
685 arg[flp].arg_flags &= ~AF_POST; /* prefer ++$foo to $foo++ */
686 arg[flp].arg_flags |= AF_PRE; /* if value not wanted */
687 }
a687059c
LW
688 return; /* side effect, can't optimize */
689 }
690
691 if (arg->arg_type == O_ITEM || arg->arg_type == O_FLIP ||
692 arg->arg_type == O_AND || arg->arg_type == O_OR) {
693 if ((arg[flp].arg_type & A_MASK) == A_SINGLE) {
694 opt = (str_true(arg[flp].arg_ptr.arg_str) ? CFT_TRUE : CFT_FALSE);
695 cmd->c_short = str_smake(arg[flp].arg_ptr.arg_str);
696 goto literal;
697 }
698 else if ((arg[flp].arg_type & A_MASK) == A_STAB ||
699 (arg[flp].arg_type & A_MASK) == A_LVAL) {
700 cmd->c_stab = arg[flp].arg_ptr.arg_stab;
701 opt = CFT_REG;
702 literal:
703 if (!context) { /* no && or ||? */
704 free_arg(arg);
705 cmd->c_expr = Nullarg;
706 }
707 if (!(context & 1))
708 cmd->c_flags |= CF_EQSURE;
709 if (!(context & 2))
710 cmd->c_flags |= CF_NESURE;
711 }
712 }
713 else if (arg->arg_type == O_MATCH || arg->arg_type == O_SUBST ||
714 arg->arg_type == O_NMATCH || arg->arg_type == O_NSUBST) {
715 if ((arg[1].arg_type == A_STAB || arg[1].arg_type == A_LVAL) &&
716 (arg[2].arg_type & A_MASK) == A_SPAT &&
717 arg[2].arg_ptr.arg_spat->spat_short ) {
718 cmd->c_stab = arg[1].arg_ptr.arg_stab;
719 cmd->c_short = str_smake(arg[2].arg_ptr.arg_spat->spat_short);
720 cmd->c_slen = arg[2].arg_ptr.arg_spat->spat_slen;
721 if (arg[2].arg_ptr.arg_spat->spat_flags & SPAT_ALL &&
722 !(arg[2].arg_ptr.arg_spat->spat_flags & SPAT_ONCE) &&
723 (arg->arg_type == O_MATCH || arg->arg_type == O_NMATCH) )
724 sure |= CF_EQSURE; /* (SUBST must be forced even */
725 /* if we know it will work.) */
726 if (arg->arg_type != O_SUBST) {
727 arg[2].arg_ptr.arg_spat->spat_short = Nullstr;
728 arg[2].arg_ptr.arg_spat->spat_slen = 0; /* only one chk */
729 }
730 sure |= CF_NESURE; /* normally only sure if it fails */
731 if (arg->arg_type == O_NMATCH || arg->arg_type == O_NSUBST)
732 cmd->c_flags |= CF_FIRSTNEG;
733 if (context & 1) { /* only sure if thing is false */
734 if (cmd->c_flags & CF_FIRSTNEG)
735 sure &= ~CF_NESURE;
736 else
737 sure &= ~CF_EQSURE;
738 }
739 else if (context & 2) { /* only sure if thing is true */
740 if (cmd->c_flags & CF_FIRSTNEG)
741 sure &= ~CF_EQSURE;
742 else
743 sure &= ~CF_NESURE;
744 }
745 if (sure & (CF_EQSURE|CF_NESURE)) { /* if we know anything*/
746 if (arg[2].arg_ptr.arg_spat->spat_flags & SPAT_SCANFIRST)
747 opt = CFT_SCAN;
748 else
749 opt = CFT_ANCHOR;
750 if (sure == (CF_EQSURE|CF_NESURE) /* really sure? */
751 && arg->arg_type == O_MATCH
752 && context & 4
753 && fliporflop == 1) {
754 spat_free(arg[2].arg_ptr.arg_spat);
755 arg[2].arg_ptr.arg_spat = Nullspat; /* don't do twice */
756 }
757 cmd->c_flags |= sure;
758 }
759 }
760 }
761 else if (arg->arg_type == O_SEQ || arg->arg_type == O_SNE ||
762 arg->arg_type == O_SLT || arg->arg_type == O_SGT) {
763 if (arg[1].arg_type == A_STAB || arg[1].arg_type == A_LVAL) {
764 if (arg[2].arg_type == A_SINGLE) {
ff8e2863
LW
765 char *junk = str_get(arg[2].arg_ptr.arg_str);
766
a687059c
LW
767 cmd->c_stab = arg[1].arg_ptr.arg_stab;
768 cmd->c_short = str_smake(arg[2].arg_ptr.arg_str);
769 cmd->c_slen = cmd->c_short->str_cur+1;
770 switch (arg->arg_type) {
771 case O_SLT: case O_SGT:
772 sure |= CF_EQSURE;
773 cmd->c_flags |= CF_FIRSTNEG;
774 break;
775 case O_SNE:
776 cmd->c_flags |= CF_FIRSTNEG;
777 /* FALL THROUGH */
778 case O_SEQ:
779 sure |= CF_NESURE|CF_EQSURE;
780 break;
781 }
782 if (context & 1) { /* only sure if thing is false */
783 if (cmd->c_flags & CF_FIRSTNEG)
784 sure &= ~CF_NESURE;
785 else
786 sure &= ~CF_EQSURE;
787 }
788 else if (context & 2) { /* only sure if thing is true */
789 if (cmd->c_flags & CF_FIRSTNEG)
790 sure &= ~CF_EQSURE;
791 else
792 sure &= ~CF_NESURE;
793 }
794 if (sure & (CF_EQSURE|CF_NESURE)) {
795 opt = CFT_STROP;
796 cmd->c_flags |= sure;
797 }
798 }
799 }
800 }
801 else if (arg->arg_type == O_EQ || arg->arg_type == O_NE ||
802 arg->arg_type == O_LE || arg->arg_type == O_GE ||
803 arg->arg_type == O_LT || arg->arg_type == O_GT) {
804 if (arg[1].arg_type == A_STAB || arg[1].arg_type == A_LVAL) {
805 if (arg[2].arg_type == A_SINGLE) {
806 cmd->c_stab = arg[1].arg_ptr.arg_stab;
807 if (dowarn) {
808 STR *str = arg[2].arg_ptr.arg_str;
809
810 if ((!str->str_nok && !looks_like_number(str)))
811 warn("Possible use of == on string value");
812 }
813 cmd->c_short = str_nmake(str_gnum(arg[2].arg_ptr.arg_str));
814 cmd->c_slen = arg->arg_type;
815 sure |= CF_NESURE|CF_EQSURE;
816 if (context & 1) { /* only sure if thing is false */
817 sure &= ~CF_EQSURE;
818 }
819 else if (context & 2) { /* only sure if thing is true */
820 sure &= ~CF_NESURE;
821 }
822 if (sure & (CF_EQSURE|CF_NESURE)) {
823 opt = CFT_NUMOP;
824 cmd->c_flags |= sure;
825 }
826 }
827 }
828 }
829 else if (arg->arg_type == O_ASSIGN &&
830 (arg[1].arg_type == A_STAB || arg[1].arg_type == A_LVAL) &&
831 arg[1].arg_ptr.arg_stab == defstab &&
832 arg[2].arg_type == A_EXPR ) {
833 arg2 = arg[2].arg_ptr.arg_arg;
834 if (arg2->arg_type == O_ITEM && arg2[1].arg_type == A_READ) {
835 opt = CFT_GETS;
836 cmd->c_stab = arg2[1].arg_ptr.arg_stab;
837 if (!(stab_io(arg2[1].arg_ptr.arg_stab)->flags & IOF_ARGV)) {
838 free_arg(arg2);
839 free_arg(arg);
840 cmd->c_expr = Nullarg;
841 }
842 }
843 }
844 else if (arg->arg_type == O_CHOP &&
845 (arg[1].arg_type == A_STAB || arg[1].arg_type == A_LVAL) ) {
846 opt = CFT_CHOP;
847 cmd->c_stab = arg[1].arg_ptr.arg_stab;
848 free_arg(arg);
849 cmd->c_expr = Nullarg;
850 }
851 if (context & 4)
852 opt |= CF_FLIP;
853 cmd->c_flags |= opt;
854
855 if (cmd->c_flags & CF_FLIP) {
856 if (fliporflop == 1) {
857 arg = cmd->c_expr; /* get back to O_FLIP arg */
858 New(110,arg[3].arg_ptr.arg_cmd, 1, CMD);
859 Copy(cmd, arg[3].arg_ptr.arg_cmd, 1, CMD);
860 New(111,arg[4].arg_ptr.arg_cmd,1,CMD);
861 Copy(cmd, arg[4].arg_ptr.arg_cmd, 1, CMD);
862 opt_arg(arg[4].arg_ptr.arg_cmd,2,acmd);
863 arg->arg_len = 2; /* this is a lie */
864 }
865 else {
866 if ((opt & CF_OPTIMIZE) == CFT_EVAL)
867 cmd->c_flags = (cmd->c_flags & ~CF_OPTIMIZE) | CFT_UNFLIP;
868 }
869 }
870}
871
872CMD *
873add_label(lbl,cmd)
874char *lbl;
875register CMD *cmd;
876{
877 if (cmd)
878 cmd->c_label = lbl;
879 return cmd;
880}
881
882CMD *
883addcond(cmd, arg)
884register CMD *cmd;
885register ARG *arg;
886{
887 cmd->c_expr = arg;
888 cmd->c_flags |= CF_COND;
889 return cmd;
890}
891
892CMD *
893addloop(cmd, arg)
894register CMD *cmd;
895register ARG *arg;
896{
897 void while_io();
898
899 cmd->c_expr = arg;
900 cmd->c_flags |= CF_COND|CF_LOOP;
901
902 if (!(cmd->c_flags & CF_INVERT))
903 while_io(cmd); /* add $_ =, if necessary */
904
905 if (cmd->c_type == C_BLOCK)
906 cmd->c_flags &= ~CF_COND;
907 else {
908 arg = cmd->ucmd.acmd.ac_expr;
909 if (arg && arg->arg_type == O_ITEM && arg[1].arg_type == A_CMD)
910 cmd->c_flags &= ~CF_COND; /* "do {} while" happens at least once */
911 if (arg && arg->arg_type == O_SUBR)
912 cmd->c_flags &= ~CF_COND; /* likewise for "do subr() while" */
913 }
914 return cmd;
915}
916
917CMD *
918invert(cmd)
03a14243 919CMD *cmd;
a687059c 920{
03a14243
LW
921 register CMD *targ = cmd;
922 if (targ->c_head)
923 targ = targ->c_head;
924 if (targ->c_flags & CF_DBSUB)
925 targ = targ->c_next;
926 targ->c_flags ^= CF_INVERT;
a687059c
LW
927 return cmd;
928}
929
930yyerror(s)
931char *s;
932{
933 char tmpbuf[258];
934 char tmp2buf[258];
935 char *tname = tmpbuf;
936
937 if (bufptr > oldoldbufptr && bufptr - oldoldbufptr < 200 &&
938 oldoldbufptr != oldbufptr && oldbufptr != bufptr) {
939 while (isspace(*oldoldbufptr))
940 oldoldbufptr++;
941 strncpy(tmp2buf, oldoldbufptr, bufptr - oldoldbufptr);
942 tmp2buf[bufptr - oldoldbufptr] = '\0';
943 sprintf(tname,"next 2 tokens \"%s\"",tmp2buf);
944 }
945 else if (bufptr > oldbufptr && bufptr - oldbufptr < 200 &&
946 oldbufptr != bufptr) {
947 while (isspace(*oldbufptr))
948 oldbufptr++;
949 strncpy(tmp2buf, oldbufptr, bufptr - oldbufptr);
950 tmp2buf[bufptr - oldbufptr] = '\0';
951 sprintf(tname,"next token \"%s\"",tmp2buf);
952 }
953 else if (yychar > 256)
954 tname = "next token ???";
955 else if (!yychar)
956 (void)strcpy(tname,"at EOF");
957 else if (yychar < 32)
958 (void)sprintf(tname,"next char ^%c",yychar+64);
959 else if (yychar == 127)
960 (void)strcpy(tname,"at EOF");
961 else
962 (void)sprintf(tname,"next char %c",yychar);
963 (void)sprintf(buf, "%s in file %s at line %d, %s\n",
39c3038c 964 s,stab_val(curcmd->c_filestab)->str_ptr,curcmd->c_line,tname);
ff8e2863 965 if (curcmd->c_line == multi_end && multi_start < multi_end)
a687059c
LW
966 sprintf(buf+strlen(buf),
967 " (Might be a runaway multi-line %c%c string starting on line %d)\n",
968 multi_open,multi_close,multi_start);
969 if (in_eval)
970 str_cat(stab_val(stabent("@",TRUE)),buf);
971 else
972 fputs(buf,stderr);
973 if (++error_count >= 10)
39c3038c
LW
974 fatal("%s has too many errors.\n",
975 stab_val(curcmd->c_filestab)->str_ptr);
a687059c
LW
976}
977
978void
979while_io(cmd)
980register CMD *cmd;
981{
982 register ARG *arg = cmd->c_expr;
983 STAB *asgnstab;
984
985 /* hoist "while (<channel>)" up into command block */
986
987 if (arg && arg->arg_type == O_ITEM && arg[1].arg_type == A_READ) {
988 cmd->c_flags &= ~CF_OPTIMIZE; /* clear optimization type */
989 cmd->c_flags |= CFT_GETS; /* and set it to do the input */
990 cmd->c_stab = arg[1].arg_ptr.arg_stab;
991 if (stab_io(arg[1].arg_ptr.arg_stab)->flags & IOF_ARGV) {
992 cmd->c_expr = l(make_op(O_ASSIGN, 2, /* fake up "$_ =" */
993 stab2arg(A_LVAL,defstab), arg, Nullarg));
994 }
995 else {
996 free_arg(arg);
997 cmd->c_expr = Nullarg;
998 }
999 }
1000 else if (arg && arg->arg_type == O_ITEM && arg[1].arg_type == A_INDREAD) {
1001 cmd->c_flags &= ~CF_OPTIMIZE; /* clear optimization type */
1002 cmd->c_flags |= CFT_INDGETS; /* and set it to do the input */
1003 cmd->c_stab = arg[1].arg_ptr.arg_stab;
1004 free_arg(arg);
1005 cmd->c_expr = Nullarg;
1006 }
1007 else if (arg && arg->arg_type == O_ITEM && arg[1].arg_type == A_GLOB) {
1008 if ((cmd->c_flags & CF_OPTIMIZE) == CFT_ARRAY)
1009 asgnstab = cmd->c_stab;
1010 else
1011 asgnstab = defstab;
1012 cmd->c_expr = l(make_op(O_ASSIGN, 2, /* fake up "$foo =" */
1013 stab2arg(A_LVAL,asgnstab), arg, Nullarg));
1014 cmd->c_flags &= ~CF_OPTIMIZE; /* clear optimization type */
1015 }
1016}
1017
1018CMD *
1019wopt(cmd)
1020register CMD *cmd;
1021{
1022 register CMD *tail;
1023 CMD *newtail;
1024 register int i;
1025
1026 if (cmd->c_expr && (cmd->c_flags & CF_OPTIMIZE) == CFT_FALSE)
1027 opt_arg(cmd,1, cmd->c_type == C_EXPR);
1028
1029 while_io(cmd); /* add $_ =, if necessary */
1030
1031 /* First find the end of the true list */
1032
1033 tail = cmd->ucmd.ccmd.cc_true;
1034 if (tail == Nullcmd)
1035 return cmd;
1036 New(112,newtail, 1, CMD); /* guaranteed continue */
1037 for (;;) {
1038 /* optimize "next" to point directly to continue block */
1039 if (tail->c_type == C_EXPR &&
1040 tail->ucmd.acmd.ac_expr &&
1041 tail->ucmd.acmd.ac_expr->arg_type == O_NEXT &&
1042 (tail->ucmd.acmd.ac_expr->arg_len == 0 ||
1043 (cmd->c_label &&
1044 strEQ(cmd->c_label,
1045 tail->ucmd.acmd.ac_expr[1].arg_ptr.arg_str->str_ptr) )))
1046 {
1047 arg_free(tail->ucmd.acmd.ac_expr);
1048 tail->c_type = C_NEXT;
1049 if (cmd->ucmd.ccmd.cc_alt != Nullcmd)
1050 tail->ucmd.ccmd.cc_alt = cmd->ucmd.ccmd.cc_alt;
1051 else
1052 tail->ucmd.ccmd.cc_alt = newtail;
1053 tail->ucmd.ccmd.cc_true = Nullcmd;
1054 }
1055 else if (tail->c_type == C_IF && !tail->ucmd.ccmd.cc_alt) {
1056 if (cmd->ucmd.ccmd.cc_alt != Nullcmd)
1057 tail->ucmd.ccmd.cc_alt = cmd->ucmd.ccmd.cc_alt;
1058 else
1059 tail->ucmd.ccmd.cc_alt = newtail;
1060 }
1061 else if (tail->c_type == C_CSWITCH || tail->c_type == C_NSWITCH) {
1062 if (cmd->ucmd.ccmd.cc_alt != Nullcmd) {
1063 for (i = tail->ucmd.scmd.sc_max; i >= 0; i--)
1064 if (!tail->ucmd.scmd.sc_next[i])
1065 tail->ucmd.scmd.sc_next[i] = cmd->ucmd.ccmd.cc_alt;
1066 }
1067 else {
1068 for (i = tail->ucmd.scmd.sc_max; i >= 0; i--)
1069 if (!tail->ucmd.scmd.sc_next[i])
1070 tail->ucmd.scmd.sc_next[i] = newtail;
1071 }
1072 }
1073
1074 if (!tail->c_next)
1075 break;
1076 tail = tail->c_next;
1077 }
1078
1079 /* if there's a continue block, link it to true block and find end */
1080
1081 if (cmd->ucmd.ccmd.cc_alt != Nullcmd) {
1082 tail->c_next = cmd->ucmd.ccmd.cc_alt;
1083 tail = tail->c_next;
1084 for (;;) {
1085 /* optimize "next" to point directly to continue block */
1086 if (tail->c_type == C_EXPR &&
1087 tail->ucmd.acmd.ac_expr &&
1088 tail->ucmd.acmd.ac_expr->arg_type == O_NEXT &&
1089 (tail->ucmd.acmd.ac_expr->arg_len == 0 ||
1090 (cmd->c_label &&
1091 strEQ(cmd->c_label,
1092 tail->ucmd.acmd.ac_expr[1].arg_ptr.arg_str->str_ptr) )))
1093 {
1094 arg_free(tail->ucmd.acmd.ac_expr);
1095 tail->c_type = C_NEXT;
1096 tail->ucmd.ccmd.cc_alt = newtail;
1097 tail->ucmd.ccmd.cc_true = Nullcmd;
1098 }
1099 else if (tail->c_type == C_IF && !tail->ucmd.ccmd.cc_alt) {
1100 tail->ucmd.ccmd.cc_alt = newtail;
1101 }
1102 else if (tail->c_type == C_CSWITCH || tail->c_type == C_NSWITCH) {
1103 for (i = tail->ucmd.scmd.sc_max; i >= 0; i--)
1104 if (!tail->ucmd.scmd.sc_next[i])
1105 tail->ucmd.scmd.sc_next[i] = newtail;
1106 }
1107
1108 if (!tail->c_next)
1109 break;
1110 tail = tail->c_next;
1111 }
1112 for ( ; tail->c_next; tail = tail->c_next) ;
1113 }
1114
1115 /* Here's the real trick: link the end of the list back to the beginning,
1116 * inserting a "last" block to break out of the loop. This saves one or
1117 * two procedure calls every time through the loop, because of how cmd_exec
1118 * does tail recursion.
1119 */
1120
1121 tail->c_next = newtail;
1122 tail = newtail;
1123 if (!cmd->ucmd.ccmd.cc_alt)
1124 cmd->ucmd.ccmd.cc_alt = tail; /* every loop has a continue now */
1125
1126#ifndef lint
1127 (void)bcopy((char *)cmd, (char *)tail, sizeof(CMD));
1128#endif
1129 tail->c_type = C_EXPR;
1130 tail->c_flags ^= CF_INVERT; /* turn into "last unless" */
1131 tail->c_next = tail->ucmd.ccmd.cc_true; /* loop directly back to top */
1132 tail->ucmd.acmd.ac_expr = make_op(O_LAST,0,Nullarg,Nullarg,Nullarg);
1133 tail->ucmd.acmd.ac_stab = Nullstab;
1134 return cmd;
1135}
1136
1137CMD *
1138over(eachstab,cmd)
1139STAB *eachstab;
1140register CMD *cmd;
1141{
1142 /* hoist "for $foo (@bar)" up into command block */
1143
1144 cmd->c_flags &= ~CF_OPTIMIZE; /* clear optimization type */
1145 cmd->c_flags |= CFT_ARRAY; /* and set it to do the iteration */
1146 cmd->c_stab = eachstab;
0d3e774c
LW
1147 cmd->c_short = str_new(0); /* just to save a field in struct cmd */
1148 cmd->c_short->str_u.str_useful = -1;
a687059c
LW
1149
1150 return cmd;
1151}
1152
1153cmd_free(cmd)
1154register CMD *cmd;
1155{
1156 register CMD *tofree;
1157 register CMD *head = cmd;
1158
1159 while (cmd) {
1160 if (cmd->c_type != C_WHILE) { /* WHILE block is duplicated */
1161 if (cmd->c_label)
1162 Safefree(cmd->c_label);
1163 if (cmd->c_short)
1164 str_free(cmd->c_short);
1165 if (cmd->c_spat)
1166 spat_free(cmd->c_spat);
1167 if (cmd->c_expr)
1168 arg_free(cmd->c_expr);
1169 }
1170 switch (cmd->c_type) {
1171 case C_WHILE:
1172 case C_BLOCK:
1173 case C_ELSE:
1174 case C_IF:
1175 if (cmd->ucmd.ccmd.cc_true)
1176 cmd_free(cmd->ucmd.ccmd.cc_true);
1177 break;
1178 case C_EXPR:
1179 if (cmd->ucmd.acmd.ac_expr)
1180 arg_free(cmd->ucmd.acmd.ac_expr);
1181 break;
1182 }
1183 tofree = cmd;
1184 cmd = cmd->c_next;
ff8e2863
LW
1185 if (tofree != head) /* to get Saber to shut up */
1186 Safefree(tofree);
a687059c
LW
1187 if (cmd && cmd == head) /* reached end of while loop */
1188 break;
1189 }
ff8e2863 1190 Safefree(head);
a687059c
LW
1191}
1192
1193arg_free(arg)
1194register ARG *arg;
1195{
1196 register int i;
1197
1198 for (i = 1; i <= arg->arg_len; i++) {
1199 switch (arg[i].arg_type & A_MASK) {
1200 case A_NULL:
1201 break;
1202 case A_LEXPR:
1203 if (arg->arg_type == O_AASSIGN &&
1204 arg[i].arg_ptr.arg_arg->arg_type == O_LARRAY) {
1205 char *name =
1206 stab_name(arg[i].arg_ptr.arg_arg[1].arg_ptr.arg_stab);
1207
1208 if (strnEQ("_GEN_",name, 5)) /* array for foreach */
1209 hdelete(defstash,name,strlen(name));
1210 }
1211 /* FALL THROUGH */
1212 case A_EXPR:
1213 arg_free(arg[i].arg_ptr.arg_arg);
1214 break;
1215 case A_CMD:
1216 cmd_free(arg[i].arg_ptr.arg_cmd);
1217 break;
1218 case A_WORD:
1219 case A_STAB:
1220 case A_LVAL:
1221 case A_READ:
1222 case A_GLOB:
1223 case A_ARYLEN:
1224 case A_LARYLEN:
1225 case A_ARYSTAB:
1226 case A_LARYSTAB:
1227 break;
1228 case A_SINGLE:
1229 case A_DOUBLE:
1230 case A_BACKTICK:
1231 str_free(arg[i].arg_ptr.arg_str);
1232 break;
1233 case A_SPAT:
1234 spat_free(arg[i].arg_ptr.arg_spat);
1235 break;
1236 }
1237 }
1238 free_arg(arg);
1239}
1240
1241spat_free(spat)
1242register SPAT *spat;
1243{
1244 register SPAT *sp;
1245 HENT *entry;
1246
1247 if (spat->spat_runtime)
1248 arg_free(spat->spat_runtime);
1249 if (spat->spat_repl) {
1250 arg_free(spat->spat_repl);
1251 }
1252 if (spat->spat_short) {
1253 str_free(spat->spat_short);
1254 }
1255 if (spat->spat_regexp) {
1256 regfree(spat->spat_regexp);
1257 }
1258
1259 /* now unlink from spat list */
1260
1261 for (entry = defstash->tbl_array['_']; entry; entry = entry->hent_next) {
1262 register HASH *stash;
1263 STAB *stab = (STAB*)entry->hent_val;
1264
1265 if (!stab)
1266 continue;
1267 stash = stab_hash(stab);
1268 if (!stash || stash->tbl_spatroot == Null(SPAT*))
1269 continue;
1270 if (stash->tbl_spatroot == spat)
1271 stash->tbl_spatroot = spat->spat_next;
1272 else {
1273 for (sp = stash->tbl_spatroot;
1274 sp && sp->spat_next != spat;
1275 sp = sp->spat_next)
1276 ;
1277 if (sp)
1278 sp->spat_next = spat->spat_next;
1279 }
1280 }
1281 Safefree(spat);
1282}
1283
1284/* Recursively descend a command sequence and push the address of any string
1285 * that needs saving on recursion onto the tosave array.
1286 */
1287
1288static int
1289cmd_tosave(cmd,willsave)
1290register CMD *cmd;
1291int willsave; /* willsave passes down the tree */
1292{
1293 register CMD *head = cmd;
1294 int shouldsave = FALSE; /* shouldsave passes up the tree */
1295 int tmpsave;
1296 register CMD *lastcmd = Nullcmd;
1297
1298 while (cmd) {
1299 if (cmd->c_spat)
1300 shouldsave |= spat_tosave(cmd->c_spat);
1301 if (cmd->c_expr)
1302 shouldsave |= arg_tosave(cmd->c_expr,willsave);
1303 switch (cmd->c_type) {
1304 case C_WHILE:
1305 if (cmd->ucmd.ccmd.cc_true) {
1306 tmpsave = cmd_tosave(cmd->ucmd.ccmd.cc_true,willsave);
1307
1308 /* Here we check to see if the temporary array generated for
1309 * a foreach needs to be localized because of recursion.
1310 */
663a0e37
LW
1311 if (tmpsave && (cmd->c_flags & CF_OPTIMIZE) == CFT_ARRAY) {
1312 if (lastcmd &&
1313 lastcmd->c_type == C_EXPR &&
7e1cf235
LW
1314 lastcmd->c_expr) {
1315 ARG *arg = lastcmd->c_expr;
663a0e37
LW
1316
1317 if (arg->arg_type == O_ASSIGN &&
1318 arg[1].arg_type == A_LEXPR &&
1319 arg[1].arg_ptr.arg_arg->arg_type == O_LARRAY &&
1320 strnEQ("_GEN_",
1321 stab_name(
1322 arg[1].arg_ptr.arg_arg[1].arg_ptr.arg_stab),
1323 5)) { /* array generated for foreach */
7e1cf235 1324 (void)localize(arg);
663a0e37 1325 }
a687059c 1326 }
663a0e37
LW
1327
1328 /* in any event, save the iterator */
1329
1330 (void)apush(tosave,cmd->c_short);
a687059c
LW
1331 }
1332 shouldsave |= tmpsave;
1333 }
1334 break;
1335 case C_BLOCK:
1336 case C_ELSE:
1337 case C_IF:
1338 if (cmd->ucmd.ccmd.cc_true)
1339 shouldsave |= cmd_tosave(cmd->ucmd.ccmd.cc_true,willsave);
1340 break;
1341 case C_EXPR:
1342 if (cmd->ucmd.acmd.ac_expr)
1343 shouldsave |= arg_tosave(cmd->ucmd.acmd.ac_expr,willsave);
1344 break;
1345 }
1346 lastcmd = cmd;
1347 cmd = cmd->c_next;
1348 if (cmd && cmd == head) /* reached end of while loop */
1349 break;
1350 }
1351 return shouldsave;
1352}
1353
1354static int
1355arg_tosave(arg,willsave)
1356register ARG *arg;
1357int willsave;
1358{
1359 register int i;
1360 int shouldsave = FALSE;
1361
1362 for (i = arg->arg_len; i >= 1; i--) {
1363 switch (arg[i].arg_type & A_MASK) {
1364 case A_NULL:
1365 break;
1366 case A_LEXPR:
1367 case A_EXPR:
1368 shouldsave |= arg_tosave(arg[i].arg_ptr.arg_arg,shouldsave);
1369 break;
1370 case A_CMD:
1371 shouldsave |= cmd_tosave(arg[i].arg_ptr.arg_cmd,shouldsave);
1372 break;
1373 case A_WORD:
1374 case A_STAB:
1375 case A_LVAL:
1376 case A_READ:
1377 case A_GLOB:
1378 case A_ARYLEN:
1379 case A_SINGLE:
1380 case A_DOUBLE:
1381 case A_BACKTICK:
1382 break;
1383 case A_SPAT:
1384 shouldsave |= spat_tosave(arg[i].arg_ptr.arg_spat);
1385 break;
1386 }
1387 }
1388 switch (arg->arg_type) {
1389 case O_RETURN:
1390 saw_return = TRUE;
1391 break;
1392 case O_EVAL:
1393 case O_SUBR:
1394 shouldsave = TRUE;
1395 break;
1396 }
1397 if (willsave)
1398 (void)apush(tosave,arg->arg_ptr.arg_str);
1399 return shouldsave;
1400}
1401
1402static int
1403spat_tosave(spat)
1404register SPAT *spat;
1405{
1406 int shouldsave = FALSE;
1407
1408 if (spat->spat_runtime)
1409 shouldsave |= arg_tosave(spat->spat_runtime,FALSE);
1410 if (spat->spat_repl) {
1411 shouldsave |= arg_tosave(spat->spat_repl,FALSE);
1412 }
1413
1414 return shouldsave;
1415}
1416