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