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