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