1 /* $Header: cons.c,v 3.0.1.3 89/12/21 19:20:25 lwall Locked $
3 * Copyright (c) 1989, Larry Wall
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.
9 * Revision 3.0.1.3 89/12/21 19:20:25 lwall
10 * patch7: made nested or recursive foreach work right
12 * Revision 3.0.1.2 89/11/17 15:08:53 lwall
13 * patch5: nested foreach on same array didn't work
15 * Revision 3.0.1.1 89/10/26 23:09:01 lwall
16 * patch1: numeric switch optimization was broken
17 * patch1: unless was broken when run under the debugger
19 * Revision 3.0 89/10/18 15:10:23 lwall
28 extern char *tokename[];
31 static int cmd_tosave();
32 static int arg_tosave();
33 static int spat_tosave();
35 static bool saw_return;
43 STAB *stab = stabent(name,TRUE);
48 line_t oldline = line;
52 warn("Subroutine %s redefined",name);
55 cmd_free(stab_sub(stab)->cmd);
56 afree(stab_sub(stab)->tosave);
57 Safefree(stab_sub(stab));
59 sub->filename = filename;
61 tosave = anew(Nullstab);
62 tosave->ary_fill = 0; /* make 1 based */
63 (void)cmd_tosave(cmd,FALSE); /* this builds the tosave array */
66 struct compcmd mycompblock;
68 mycompblock.comp_true = cmd;
69 mycompblock.comp_alt = Nullcmd;
70 cmd = add_label(savestr("SUB"),make_ccmd(C_BLOCK,Nullarg,mycompblock));
76 STR *str = str_nmake((double)subline);
79 sprintf(buf,"%ld",(long)line);
81 name = str_get(subname);
82 hstore(stab_xhash(DBsub),name,strlen(name),str,0);
83 str_set(subname,"main");
95 register int last_opt = 0;
96 register STAB *last_stab = Nullstab;
97 register int count = 0;
98 register CMD *switchbeg = Nullcmd;
100 if (tail == Nullcmd) {
105 for (tail = head; tail; tail = tail->c_next) {
107 /* save one measly dereference at runtime */
108 if (tail->c_type == C_IF) {
109 if (!(tail->ucmd.ccmd.cc_alt = tail->ucmd.ccmd.cc_alt->c_next))
110 tail->c_flags |= CF_TERM;
112 else if (tail->c_type == C_EXPR) {
115 if (tail->ucmd.acmd.ac_expr)
116 arg = tail->ucmd.acmd.ac_expr;
120 if (arg->arg_type == O_RETURN)
121 tail->c_flags |= CF_TERM;
122 else if (arg->arg_type == O_ITEM && arg[1].arg_type == A_CMD)
123 tail->c_flags |= CF_TERM;
127 tail->c_flags |= CF_TERM;
129 if (tail->c_expr && (tail->c_flags & CF_OPTIMIZE) == CFT_FALSE)
130 opt_arg(tail,1, tail->c_type == C_EXPR);
132 /* now do a little optimization on case-ish structures */
133 switch(tail->c_flags & (CF_OPTIMIZE|CF_FIRSTNEG|CF_INVERT)) {
135 if (stabent("*",FALSE)) { /* bad assumption here!!! */
141 opt = (tail->c_flags & CF_NESURE) ? CFT_STROP : 0;
147 opt = (tail->c_slen == O_NE ? 0 : CFT_NUMOP);
148 if ((tail->c_flags&(CF_NESURE|CF_EQSURE)) != (CF_NESURE|CF_EQSURE))
154 if (opt && opt == last_opt && tail->c_stab == last_stab)
157 if (count >= 3) { /* is this the breakeven point? */
158 if (last_opt == CFT_NUMOP)
159 make_nswitch(switchbeg,count);
161 make_cswitch(switchbeg,count);
171 last_stab = tail->c_stab;
173 if (count >= 3) { /* is this the breakeven point? */
174 if (last_opt == CFT_NUMOP)
175 make_nswitch(switchbeg,count);
177 make_cswitch(switchbeg,count);
182 /* We've spotted a sequence of CMDs that all test the value of the same
183 * spat. Thus we can insert a SWITCH in front and jump directly
184 * to the correct one.
186 make_cswitch(head,count)
193 register int min = 255;
194 register int max = 0;
196 /* make a new head in the exact same spot */
197 New(102,cur, 1, CMD);
201 Copy(head,cur,1,CMD);
204 head->c_type = C_CSWITCH;
205 head->c_next = cur; /* insert new cmd at front of list */
206 head->c_stab = cur->c_stab;
208 Newz(103,loc,258,CMD*);
209 loc++; /* lie a little */
211 if ((cur->c_flags & CF_OPTIMIZE) == CFT_CCLASS) {
212 for (i = 0; i <= 255; i++) {
213 if (!loc[i] && cur->c_short->str_ptr[i>>3] & (1 << (i&7))) {
223 i = *cur->c_short->str_ptr & 255;
236 Copy(&loc[min],&loc[0], max - min, CMD*);
240 for (i = 0; i <= max; i++)
243 Renew(loc,max+1,CMD*); /* chop it down to size */
244 head->ucmd.scmd.sc_offset = min;
245 head->ucmd.scmd.sc_max = max;
246 head->ucmd.scmd.sc_next = loc;
249 make_nswitch(head,count)
253 register CMD *cur = head;
256 register int min = 32767;
257 register int max = -32768;
258 int origcount = count;
259 double value; /* or your money back! */
260 short changed; /* so triple your money back! */
263 i = (int)str_gnum(cur->c_short);
265 if (value != cur->c_short->str_u.str_nval)
266 return; /* fractional values--just forget it */
269 return; /* too big for a short */
270 if (cur->c_slen == O_LE)
272 else if (cur->c_slen == O_GE) /* we only do < or > here */
281 if (max - min > count * 2 + 10) /* too sparse? */
284 /* now make a new head in the exact same spot */
285 New(104,cur, 1, CMD);
289 Copy(head,cur,1,CMD);
292 head->c_type = C_NSWITCH;
293 head->c_next = cur; /* insert new cmd at front of list */
294 head->c_stab = cur->c_stab;
296 Newz(105,loc, max - min + 3, CMD*);
301 i = (int)str_gnum(cur->c_short);
303 switch(cur->c_slen) {
307 for (i--; i >= -1; i--)
314 for (i++; i <= max; i++)
328 for (i = 0; i <= max; i++)
331 head->ucmd.scmd.sc_offset = min;
332 head->ucmd.scmd.sc_max = max;
333 head->ucmd.scmd.sc_next = loc;
337 append_line(head,tail)
343 if (!tail->c_head) /* make sure tail is well formed */
345 if (head != Nullcmd) {
346 tail = tail->c_head; /* get to start of tail list */
348 head->c_head = head; /* start a new head list */
349 while (head->c_next) {
350 head->c_next->c_head = head->c_head;
351 head = head->c_next; /* get to end of head list */
353 head->c_next = tail; /* link to end of old list */
354 tail->c_head = head->c_head; /* propagate head pointer */
356 while (tail->c_next) {
357 tail->c_next->c_head = tail->c_head;
368 register CMD *head = cur->c_head;
376 str = afetch(lineary,(int)head->c_line,FALSE);
377 if (!str || str->str_nok)
379 str->str_u.str_nval = (double)head->c_line;
382 cmd->c_type = C_EXPR;
383 cmd->ucmd.acmd.ac_stab = Nullstab;
384 cmd->ucmd.acmd.ac_expr = Nullarg;
385 arg = make_op(O_ITEM,1,Nullarg,Nullarg,Nullarg);
386 arg[1].arg_type = A_SINGLE;
387 arg[1].arg_ptr.arg_str = str_nmake((double)head->c_line);
388 cmd->c_expr = make_op(O_SUBR, 2,
389 stab2arg(A_WORD,DBstab),
392 cmd->c_flags |= CF_COND|CF_DBSUB;
393 cmd->c_line = head->c_line;
394 cmd->c_label = head->c_label;
395 cmd->c_file = filename;
396 return append_line(cmd, cur);
400 make_acmd(type,stab,cond,arg)
410 cmd->ucmd.acmd.ac_stab = stab;
411 cmd->ucmd.acmd.ac_expr = arg;
414 cmd->c_flags |= CF_COND;
415 if (cmdline != NOLINE) {
416 cmd->c_line = cmdline;
419 cmd->c_file = filename;
426 make_ccmd(type,arg,cblock)
429 struct compcmd cblock;
433 Newz(108,cmd, 1, CMD);
436 cmd->ucmd.ccmd.cc_true = cblock.comp_true;
437 cmd->ucmd.ccmd.cc_alt = cblock.comp_alt;
439 cmd->c_flags |= CF_COND;
440 if (cmdline != NOLINE) {
441 cmd->c_line = cmdline;
450 make_icmd(type,arg,cblock)
453 struct compcmd cblock;
459 struct compcmd ncblock;
461 Newz(109,cmd, 1, CMD);
465 cmd->ucmd.ccmd.cc_true = cblock.comp_true;
466 cmd->ucmd.ccmd.cc_alt = cblock.comp_alt;
468 cmd->c_flags |= CF_COND;
469 if (cmdline != NOLINE) {
470 cmd->c_line = cmdline;
474 alt = cblock.comp_alt;
475 while (alt && alt->c_type == C_ELSIF) {
477 alt = alt->ucmd.ccmd.cc_alt;
479 if (alt) { /* a real life ELSE at the end? */
480 ncblock.comp_true = alt;
481 ncblock.comp_alt = Nullcmd;
482 alt = append_line(cur,make_ccmd(C_ELSE,Nullarg,ncblock));
483 cur->ucmd.ccmd.cc_alt = alt;
486 alt = cur; /* no ELSE, so cur is proxy ELSE */
489 while (cmd) { /* now point everyone at the ELSE */
491 cmd = cur->ucmd.ccmd.cc_alt;
493 if (cur->c_type == C_ELSIF)
495 if (cur->c_type == C_IF)
496 cur->ucmd.ccmd.cc_alt = alt;
507 opt_arg(cmd,fliporflop,acmd)
516 int context = 0; /* 0 = normal, 1 = before &&, 2 = before || */
517 int flp = fliporflop;
521 if (!(arg = cmd->c_expr)) {
522 cmd->c_flags &= ~CF_COND;
526 /* Can we turn && and || into if and unless? */
528 if (acmd && !cmd->ucmd.acmd.ac_expr && !(cmd->c_flags & CF_TERM) &&
529 (arg->arg_type == O_AND || arg->arg_type == O_OR) ) {
531 arg[2].arg_type &= A_MASK; /* don't suppress eval */
533 cmd->ucmd.acmd.ac_expr = arg[2].arg_ptr.arg_arg;
534 cmd->c_expr = arg[1].arg_ptr.arg_arg;
535 if (arg->arg_type == O_OR)
536 cmd->c_flags ^= CF_INVERT; /* || is like unless */
542 /* Turn "if (!expr)" into "unless (expr)" */
544 if (!(cmd->c_flags & CF_TERM)) { /* unless return value wanted */
545 while (arg->arg_type == O_NOT) {
547 cmd->c_flags ^= CF_INVERT; /* flip sense of cmd */
548 cmd->c_expr = arg[1].arg_ptr.arg_arg; /* hoist the rest of expr */
550 arg = cmd->c_expr; /* here we go again */
554 if (!arg->arg_len) { /* sanity check */
559 /* for "cond .. cond" we set up for the initial check */
561 if (arg->arg_type == O_FLIP)
564 /* for "cond && expr" and "cond || expr" we can ignore expr, sort of */
567 if (arg->arg_type == O_AND)
569 else if (arg->arg_type == O_OR)
571 if (context && (arg[flp].arg_type & A_MASK) == A_EXPR) {
572 arg = arg[flp].arg_ptr.arg_arg;
574 if (arg->arg_type == O_AND || arg->arg_type == O_OR)
577 if ((context & 3) == 3)
580 if (arg[flp].arg_flags & (AF_PRE|AF_POST)) {
582 return; /* side effect, can't optimize */
585 if (arg->arg_type == O_ITEM || arg->arg_type == O_FLIP ||
586 arg->arg_type == O_AND || arg->arg_type == O_OR) {
587 if ((arg[flp].arg_type & A_MASK) == A_SINGLE) {
588 opt = (str_true(arg[flp].arg_ptr.arg_str) ? CFT_TRUE : CFT_FALSE);
589 cmd->c_short = str_smake(arg[flp].arg_ptr.arg_str);
592 else if ((arg[flp].arg_type & A_MASK) == A_STAB ||
593 (arg[flp].arg_type & A_MASK) == A_LVAL) {
594 cmd->c_stab = arg[flp].arg_ptr.arg_stab;
597 if (!context) { /* no && or ||? */
599 cmd->c_expr = Nullarg;
602 cmd->c_flags |= CF_EQSURE;
604 cmd->c_flags |= CF_NESURE;
607 else if (arg->arg_type == O_MATCH || arg->arg_type == O_SUBST ||
608 arg->arg_type == O_NMATCH || arg->arg_type == O_NSUBST) {
609 if ((arg[1].arg_type == A_STAB || arg[1].arg_type == A_LVAL) &&
610 (arg[2].arg_type & A_MASK) == A_SPAT &&
611 arg[2].arg_ptr.arg_spat->spat_short ) {
612 cmd->c_stab = arg[1].arg_ptr.arg_stab;
613 cmd->c_short = str_smake(arg[2].arg_ptr.arg_spat->spat_short);
614 cmd->c_slen = arg[2].arg_ptr.arg_spat->spat_slen;
615 if (arg[2].arg_ptr.arg_spat->spat_flags & SPAT_ALL &&
616 !(arg[2].arg_ptr.arg_spat->spat_flags & SPAT_ONCE) &&
617 (arg->arg_type == O_MATCH || arg->arg_type == O_NMATCH) )
618 sure |= CF_EQSURE; /* (SUBST must be forced even */
619 /* if we know it will work.) */
620 if (arg->arg_type != O_SUBST) {
621 arg[2].arg_ptr.arg_spat->spat_short = Nullstr;
622 arg[2].arg_ptr.arg_spat->spat_slen = 0; /* only one chk */
624 sure |= CF_NESURE; /* normally only sure if it fails */
625 if (arg->arg_type == O_NMATCH || arg->arg_type == O_NSUBST)
626 cmd->c_flags |= CF_FIRSTNEG;
627 if (context & 1) { /* only sure if thing is false */
628 if (cmd->c_flags & CF_FIRSTNEG)
633 else if (context & 2) { /* only sure if thing is true */
634 if (cmd->c_flags & CF_FIRSTNEG)
639 if (sure & (CF_EQSURE|CF_NESURE)) { /* if we know anything*/
640 if (arg[2].arg_ptr.arg_spat->spat_flags & SPAT_SCANFIRST)
644 if (sure == (CF_EQSURE|CF_NESURE) /* really sure? */
645 && arg->arg_type == O_MATCH
647 && fliporflop == 1) {
648 spat_free(arg[2].arg_ptr.arg_spat);
649 arg[2].arg_ptr.arg_spat = Nullspat; /* don't do twice */
651 cmd->c_flags |= sure;
655 else if (arg->arg_type == O_SEQ || arg->arg_type == O_SNE ||
656 arg->arg_type == O_SLT || arg->arg_type == O_SGT) {
657 if (arg[1].arg_type == A_STAB || arg[1].arg_type == A_LVAL) {
658 if (arg[2].arg_type == A_SINGLE) {
659 cmd->c_stab = arg[1].arg_ptr.arg_stab;
660 cmd->c_short = str_smake(arg[2].arg_ptr.arg_str);
661 cmd->c_slen = cmd->c_short->str_cur+1;
662 switch (arg->arg_type) {
663 case O_SLT: case O_SGT:
665 cmd->c_flags |= CF_FIRSTNEG;
668 cmd->c_flags |= CF_FIRSTNEG;
671 sure |= CF_NESURE|CF_EQSURE;
674 if (context & 1) { /* only sure if thing is false */
675 if (cmd->c_flags & CF_FIRSTNEG)
680 else if (context & 2) { /* only sure if thing is true */
681 if (cmd->c_flags & CF_FIRSTNEG)
686 if (sure & (CF_EQSURE|CF_NESURE)) {
688 cmd->c_flags |= sure;
693 else if (arg->arg_type == O_EQ || arg->arg_type == O_NE ||
694 arg->arg_type == O_LE || arg->arg_type == O_GE ||
695 arg->arg_type == O_LT || arg->arg_type == O_GT) {
696 if (arg[1].arg_type == A_STAB || arg[1].arg_type == A_LVAL) {
697 if (arg[2].arg_type == A_SINGLE) {
698 cmd->c_stab = arg[1].arg_ptr.arg_stab;
700 STR *str = arg[2].arg_ptr.arg_str;
702 if ((!str->str_nok && !looks_like_number(str)))
703 warn("Possible use of == on string value");
705 cmd->c_short = str_nmake(str_gnum(arg[2].arg_ptr.arg_str));
706 cmd->c_slen = arg->arg_type;
707 sure |= CF_NESURE|CF_EQSURE;
708 if (context & 1) { /* only sure if thing is false */
711 else if (context & 2) { /* only sure if thing is true */
714 if (sure & (CF_EQSURE|CF_NESURE)) {
716 cmd->c_flags |= sure;
721 else if (arg->arg_type == O_ASSIGN &&
722 (arg[1].arg_type == A_STAB || arg[1].arg_type == A_LVAL) &&
723 arg[1].arg_ptr.arg_stab == defstab &&
724 arg[2].arg_type == A_EXPR ) {
725 arg2 = arg[2].arg_ptr.arg_arg;
726 if (arg2->arg_type == O_ITEM && arg2[1].arg_type == A_READ) {
728 cmd->c_stab = arg2[1].arg_ptr.arg_stab;
729 if (!(stab_io(arg2[1].arg_ptr.arg_stab)->flags & IOF_ARGV)) {
732 cmd->c_expr = Nullarg;
736 else if (arg->arg_type == O_CHOP &&
737 (arg[1].arg_type == A_STAB || arg[1].arg_type == A_LVAL) ) {
739 cmd->c_stab = arg[1].arg_ptr.arg_stab;
741 cmd->c_expr = Nullarg;
747 if (cmd->c_flags & CF_FLIP) {
748 if (fliporflop == 1) {
749 arg = cmd->c_expr; /* get back to O_FLIP arg */
750 New(110,arg[3].arg_ptr.arg_cmd, 1, CMD);
751 Copy(cmd, arg[3].arg_ptr.arg_cmd, 1, CMD);
752 New(111,arg[4].arg_ptr.arg_cmd,1,CMD);
753 Copy(cmd, arg[4].arg_ptr.arg_cmd, 1, CMD);
754 opt_arg(arg[4].arg_ptr.arg_cmd,2,acmd);
755 arg->arg_len = 2; /* this is a lie */
758 if ((opt & CF_OPTIMIZE) == CFT_EVAL)
759 cmd->c_flags = (cmd->c_flags & ~CF_OPTIMIZE) | CFT_UNFLIP;
780 cmd->c_flags |= CF_COND;
792 cmd->c_flags |= CF_COND|CF_LOOP;
794 if (!(cmd->c_flags & CF_INVERT))
795 while_io(cmd); /* add $_ =, if necessary */
797 if (cmd->c_type == C_BLOCK)
798 cmd->c_flags &= ~CF_COND;
800 arg = cmd->ucmd.acmd.ac_expr;
801 if (arg && arg->arg_type == O_ITEM && arg[1].arg_type == A_CMD)
802 cmd->c_flags &= ~CF_COND; /* "do {} while" happens at least once */
803 if (arg && arg->arg_type == O_SUBR)
804 cmd->c_flags &= ~CF_COND; /* likewise for "do subr() while" */
813 register CMD *targ = cmd;
816 if (targ->c_flags & CF_DBSUB)
818 targ->c_flags ^= CF_INVERT;
827 char *tname = tmpbuf;
829 if (bufptr > oldoldbufptr && bufptr - oldoldbufptr < 200 &&
830 oldoldbufptr != oldbufptr && oldbufptr != bufptr) {
831 while (isspace(*oldoldbufptr))
833 strncpy(tmp2buf, oldoldbufptr, bufptr - oldoldbufptr);
834 tmp2buf[bufptr - oldoldbufptr] = '\0';
835 sprintf(tname,"next 2 tokens \"%s\"",tmp2buf);
837 else if (bufptr > oldbufptr && bufptr - oldbufptr < 200 &&
838 oldbufptr != bufptr) {
839 while (isspace(*oldbufptr))
841 strncpy(tmp2buf, oldbufptr, bufptr - oldbufptr);
842 tmp2buf[bufptr - oldbufptr] = '\0';
843 sprintf(tname,"next token \"%s\"",tmp2buf);
845 else if (yychar > 256)
846 tname = "next token ???";
848 (void)strcpy(tname,"at EOF");
849 else if (yychar < 32)
850 (void)sprintf(tname,"next char ^%c",yychar+64);
851 else if (yychar == 127)
852 (void)strcpy(tname,"at EOF");
854 (void)sprintf(tname,"next char %c",yychar);
855 (void)sprintf(buf, "%s in file %s at line %d, %s\n",
856 s,filename,line,tname);
857 if (line == multi_end && multi_start < multi_end)
858 sprintf(buf+strlen(buf),
859 " (Might be a runaway multi-line %c%c string starting on line %d)\n",
860 multi_open,multi_close,multi_start);
862 str_cat(stab_val(stabent("@",TRUE)),buf);
865 if (++error_count >= 10)
866 fatal("Too many errors\n");
873 register ARG *arg = cmd->c_expr;
876 /* hoist "while (<channel>)" up into command block */
878 if (arg && arg->arg_type == O_ITEM && arg[1].arg_type == A_READ) {
879 cmd->c_flags &= ~CF_OPTIMIZE; /* clear optimization type */
880 cmd->c_flags |= CFT_GETS; /* and set it to do the input */
881 cmd->c_stab = arg[1].arg_ptr.arg_stab;
882 if (stab_io(arg[1].arg_ptr.arg_stab)->flags & IOF_ARGV) {
883 cmd->c_expr = l(make_op(O_ASSIGN, 2, /* fake up "$_ =" */
884 stab2arg(A_LVAL,defstab), arg, Nullarg));
888 cmd->c_expr = Nullarg;
891 else if (arg && arg->arg_type == O_ITEM && arg[1].arg_type == A_INDREAD) {
892 cmd->c_flags &= ~CF_OPTIMIZE; /* clear optimization type */
893 cmd->c_flags |= CFT_INDGETS; /* and set it to do the input */
894 cmd->c_stab = arg[1].arg_ptr.arg_stab;
896 cmd->c_expr = Nullarg;
898 else if (arg && arg->arg_type == O_ITEM && arg[1].arg_type == A_GLOB) {
899 if ((cmd->c_flags & CF_OPTIMIZE) == CFT_ARRAY)
900 asgnstab = cmd->c_stab;
903 cmd->c_expr = l(make_op(O_ASSIGN, 2, /* fake up "$foo =" */
904 stab2arg(A_LVAL,asgnstab), arg, Nullarg));
905 cmd->c_flags &= ~CF_OPTIMIZE; /* clear optimization type */
917 if (cmd->c_expr && (cmd->c_flags & CF_OPTIMIZE) == CFT_FALSE)
918 opt_arg(cmd,1, cmd->c_type == C_EXPR);
920 while_io(cmd); /* add $_ =, if necessary */
922 /* First find the end of the true list */
924 tail = cmd->ucmd.ccmd.cc_true;
927 New(112,newtail, 1, CMD); /* guaranteed continue */
929 /* optimize "next" to point directly to continue block */
930 if (tail->c_type == C_EXPR &&
931 tail->ucmd.acmd.ac_expr &&
932 tail->ucmd.acmd.ac_expr->arg_type == O_NEXT &&
933 (tail->ucmd.acmd.ac_expr->arg_len == 0 ||
936 tail->ucmd.acmd.ac_expr[1].arg_ptr.arg_str->str_ptr) )))
938 arg_free(tail->ucmd.acmd.ac_expr);
939 tail->c_type = C_NEXT;
940 if (cmd->ucmd.ccmd.cc_alt != Nullcmd)
941 tail->ucmd.ccmd.cc_alt = cmd->ucmd.ccmd.cc_alt;
943 tail->ucmd.ccmd.cc_alt = newtail;
944 tail->ucmd.ccmd.cc_true = Nullcmd;
946 else if (tail->c_type == C_IF && !tail->ucmd.ccmd.cc_alt) {
947 if (cmd->ucmd.ccmd.cc_alt != Nullcmd)
948 tail->ucmd.ccmd.cc_alt = cmd->ucmd.ccmd.cc_alt;
950 tail->ucmd.ccmd.cc_alt = newtail;
952 else if (tail->c_type == C_CSWITCH || tail->c_type == C_NSWITCH) {
953 if (cmd->ucmd.ccmd.cc_alt != Nullcmd) {
954 for (i = tail->ucmd.scmd.sc_max; i >= 0; i--)
955 if (!tail->ucmd.scmd.sc_next[i])
956 tail->ucmd.scmd.sc_next[i] = cmd->ucmd.ccmd.cc_alt;
959 for (i = tail->ucmd.scmd.sc_max; i >= 0; i--)
960 if (!tail->ucmd.scmd.sc_next[i])
961 tail->ucmd.scmd.sc_next[i] = newtail;
970 /* if there's a continue block, link it to true block and find end */
972 if (cmd->ucmd.ccmd.cc_alt != Nullcmd) {
973 tail->c_next = cmd->ucmd.ccmd.cc_alt;
976 /* optimize "next" to point directly to continue block */
977 if (tail->c_type == C_EXPR &&
978 tail->ucmd.acmd.ac_expr &&
979 tail->ucmd.acmd.ac_expr->arg_type == O_NEXT &&
980 (tail->ucmd.acmd.ac_expr->arg_len == 0 ||
983 tail->ucmd.acmd.ac_expr[1].arg_ptr.arg_str->str_ptr) )))
985 arg_free(tail->ucmd.acmd.ac_expr);
986 tail->c_type = C_NEXT;
987 tail->ucmd.ccmd.cc_alt = newtail;
988 tail->ucmd.ccmd.cc_true = Nullcmd;
990 else if (tail->c_type == C_IF && !tail->ucmd.ccmd.cc_alt) {
991 tail->ucmd.ccmd.cc_alt = newtail;
993 else if (tail->c_type == C_CSWITCH || tail->c_type == C_NSWITCH) {
994 for (i = tail->ucmd.scmd.sc_max; i >= 0; i--)
995 if (!tail->ucmd.scmd.sc_next[i])
996 tail->ucmd.scmd.sc_next[i] = newtail;
1001 tail = tail->c_next;
1003 for ( ; tail->c_next; tail = tail->c_next) ;
1006 /* Here's the real trick: link the end of the list back to the beginning,
1007 * inserting a "last" block to break out of the loop. This saves one or
1008 * two procedure calls every time through the loop, because of how cmd_exec
1009 * does tail recursion.
1012 tail->c_next = newtail;
1014 if (!cmd->ucmd.ccmd.cc_alt)
1015 cmd->ucmd.ccmd.cc_alt = tail; /* every loop has a continue now */
1018 (void)bcopy((char *)cmd, (char *)tail, sizeof(CMD));
1020 tail->c_type = C_EXPR;
1021 tail->c_flags ^= CF_INVERT; /* turn into "last unless" */
1022 tail->c_next = tail->ucmd.ccmd.cc_true; /* loop directly back to top */
1023 tail->ucmd.acmd.ac_expr = make_op(O_LAST,0,Nullarg,Nullarg,Nullarg);
1024 tail->ucmd.acmd.ac_stab = Nullstab;
1033 /* hoist "for $foo (@bar)" up into command block */
1035 cmd->c_flags &= ~CF_OPTIMIZE; /* clear optimization type */
1036 cmd->c_flags |= CFT_ARRAY; /* and set it to do the iteration */
1037 cmd->c_stab = eachstab;
1038 cmd->c_short = str_new(0); /* just to save a field in struct cmd */
1039 cmd->c_short->str_u.str_useful = -1;
1047 register CMD *tofree;
1048 register CMD *head = cmd;
1051 if (cmd->c_type != C_WHILE) { /* WHILE block is duplicated */
1053 Safefree(cmd->c_label);
1055 str_free(cmd->c_short);
1057 spat_free(cmd->c_spat);
1059 arg_free(cmd->c_expr);
1061 switch (cmd->c_type) {
1066 if (cmd->ucmd.ccmd.cc_true)
1067 cmd_free(cmd->ucmd.ccmd.cc_true);
1070 if (cmd->ucmd.acmd.ac_expr)
1071 arg_free(cmd->ucmd.acmd.ac_expr);
1077 if (cmd && cmd == head) /* reached end of while loop */
1087 for (i = 1; i <= arg->arg_len; i++) {
1088 switch (arg[i].arg_type & A_MASK) {
1092 if (arg->arg_type == O_AASSIGN &&
1093 arg[i].arg_ptr.arg_arg->arg_type == O_LARRAY) {
1095 stab_name(arg[i].arg_ptr.arg_arg[1].arg_ptr.arg_stab);
1097 if (strnEQ("_GEN_",name, 5)) /* array for foreach */
1098 hdelete(defstash,name,strlen(name));
1102 arg_free(arg[i].arg_ptr.arg_arg);
1105 cmd_free(arg[i].arg_ptr.arg_cmd);
1120 str_free(arg[i].arg_ptr.arg_str);
1123 spat_free(arg[i].arg_ptr.arg_spat);
1131 register SPAT *spat;
1136 if (spat->spat_runtime)
1137 arg_free(spat->spat_runtime);
1138 if (spat->spat_repl) {
1139 arg_free(spat->spat_repl);
1141 if (spat->spat_short) {
1142 str_free(spat->spat_short);
1144 if (spat->spat_regexp) {
1145 regfree(spat->spat_regexp);
1148 /* now unlink from spat list */
1150 for (entry = defstash->tbl_array['_']; entry; entry = entry->hent_next) {
1151 register HASH *stash;
1152 STAB *stab = (STAB*)entry->hent_val;
1156 stash = stab_hash(stab);
1157 if (!stash || stash->tbl_spatroot == Null(SPAT*))
1159 if (stash->tbl_spatroot == spat)
1160 stash->tbl_spatroot = spat->spat_next;
1162 for (sp = stash->tbl_spatroot;
1163 sp && sp->spat_next != spat;
1167 sp->spat_next = spat->spat_next;
1173 /* Recursively descend a command sequence and push the address of any string
1174 * that needs saving on recursion onto the tosave array.
1178 cmd_tosave(cmd,willsave)
1180 int willsave; /* willsave passes down the tree */
1182 register CMD *head = cmd;
1183 int shouldsave = FALSE; /* shouldsave passes up the tree */
1185 register CMD *lastcmd = Nullcmd;
1189 shouldsave |= spat_tosave(cmd->c_spat);
1191 shouldsave |= arg_tosave(cmd->c_expr,willsave);
1192 switch (cmd->c_type) {
1194 if (cmd->ucmd.ccmd.cc_true) {
1195 tmpsave = cmd_tosave(cmd->ucmd.ccmd.cc_true,willsave);
1197 /* Here we check to see if the temporary array generated for
1198 * a foreach needs to be localized because of recursion.
1200 if (tmpsave && (cmd->c_flags & CF_OPTIMIZE) == CFT_ARRAY) {
1202 lastcmd->c_type == C_EXPR &&
1203 lastcmd->ucmd.acmd.ac_expr) {
1204 ARG *arg = lastcmd->ucmd.acmd.ac_expr;
1206 if (arg->arg_type == O_ASSIGN &&
1207 arg[1].arg_type == A_LEXPR &&
1208 arg[1].arg_ptr.arg_arg->arg_type == O_LARRAY &&
1211 arg[1].arg_ptr.arg_arg[1].arg_ptr.arg_stab),
1212 5)) { /* array generated for foreach */
1213 (void)localize(arg[1].arg_ptr.arg_arg);
1217 /* in any event, save the iterator */
1219 (void)apush(tosave,cmd->c_short);
1221 shouldsave |= tmpsave;
1227 if (cmd->ucmd.ccmd.cc_true)
1228 shouldsave |= cmd_tosave(cmd->ucmd.ccmd.cc_true,willsave);
1231 if (cmd->ucmd.acmd.ac_expr)
1232 shouldsave |= arg_tosave(cmd->ucmd.acmd.ac_expr,willsave);
1237 if (cmd && cmd == head) /* reached end of while loop */
1244 arg_tosave(arg,willsave)
1249 int shouldsave = FALSE;
1251 for (i = arg->arg_len; i >= 1; i--) {
1252 switch (arg[i].arg_type & A_MASK) {
1257 shouldsave |= arg_tosave(arg[i].arg_ptr.arg_arg,shouldsave);
1260 shouldsave |= cmd_tosave(arg[i].arg_ptr.arg_cmd,shouldsave);
1273 shouldsave |= spat_tosave(arg[i].arg_ptr.arg_spat);
1277 switch (arg->arg_type) {
1287 (void)apush(tosave,arg->arg_ptr.arg_str);
1293 register SPAT *spat;
1295 int shouldsave = FALSE;
1297 if (spat->spat_runtime)
1298 shouldsave |= arg_tosave(spat->spat_runtime,FALSE);
1299 if (spat->spat_repl) {
1300 shouldsave |= arg_tosave(spat->spat_repl,FALSE);