1 /* $Header: cons.c,v 3.0.1.1 89/10/26 23:09:01 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.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
13 * Revision 3.0 89/10/18 15:10:23 lwall
22 extern char *tokename[];
25 static int cmd_tosave();
26 static int arg_tosave();
27 static int spat_tosave();
29 static bool saw_return;
37 STAB *stab = stabent(name,TRUE);
42 line_t oldline = line;
46 warn("Subroutine %s redefined",name);
49 cmd_free(stab_sub(stab)->cmd);
50 afree(stab_sub(stab)->tosave);
51 Safefree(stab_sub(stab));
53 sub->filename = filename;
55 tosave = anew(Nullstab);
56 tosave->ary_fill = 0; /* make 1 based */
57 (void)cmd_tosave(cmd,FALSE); /* this builds the tosave array */
60 struct compcmd mycompblock;
62 mycompblock.comp_true = cmd;
63 mycompblock.comp_alt = Nullcmd;
64 cmd = add_label(savestr("SUB"),make_ccmd(C_BLOCK,Nullarg,mycompblock));
70 STR *str = str_nmake((double)subline);
73 sprintf(buf,"%ld",(long)line);
75 name = str_get(subname);
76 hstore(stab_xhash(DBsub),name,strlen(name),str,0);
77 str_set(subname,"main");
89 register int last_opt = 0;
90 register STAB *last_stab = Nullstab;
91 register int count = 0;
92 register CMD *switchbeg = Nullcmd;
94 if (tail == Nullcmd) {
99 for (tail = head; tail; tail = tail->c_next) {
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;
106 else if (tail->c_type == C_EXPR) {
109 if (tail->ucmd.acmd.ac_expr)
110 arg = tail->ucmd.acmd.ac_expr;
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;
121 tail->c_flags |= CF_TERM;
123 if (tail->c_expr && (tail->c_flags & CF_OPTIMIZE) == CFT_FALSE)
124 opt_arg(tail,1, tail->c_type == C_EXPR);
126 /* now do a little optimization on case-ish structures */
127 switch(tail->c_flags & (CF_OPTIMIZE|CF_FIRSTNEG|CF_INVERT)) {
129 if (stabent("*",FALSE)) { /* bad assumption here!!! */
135 opt = (tail->c_flags & CF_NESURE) ? CFT_STROP : 0;
141 opt = (tail->c_slen == O_NE ? 0 : CFT_NUMOP);
142 if ((tail->c_flags&(CF_NESURE|CF_EQSURE)) != (CF_NESURE|CF_EQSURE))
148 if (opt && opt == last_opt && tail->c_stab == last_stab)
151 if (count >= 3) { /* is this the breakeven point? */
152 if (last_opt == CFT_NUMOP)
153 make_nswitch(switchbeg,count);
155 make_cswitch(switchbeg,count);
165 last_stab = tail->c_stab;
167 if (count >= 3) { /* is this the breakeven point? */
168 if (last_opt == CFT_NUMOP)
169 make_nswitch(switchbeg,count);
171 make_cswitch(switchbeg,count);
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.
180 make_cswitch(head,count)
187 register int min = 255;
188 register int max = 0;
190 /* make a new head in the exact same spot */
191 New(102,cur, 1, CMD);
195 Copy(head,cur,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;
202 Newz(103,loc,258,CMD*);
203 loc++; /* lie a little */
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))) {
217 i = *cur->c_short->str_ptr & 255;
230 Copy(&loc[min],&loc[0], max - min, CMD*);
234 for (i = 0; i <= max; i++)
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;
243 make_nswitch(head,count)
247 register CMD *cur = head;
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! */
257 i = (int)str_gnum(cur->c_short);
259 if (value != cur->c_short->str_u.str_nval)
260 return; /* fractional values--just forget it */
263 return; /* too big for a short */
264 if (cur->c_slen == O_LE)
266 else if (cur->c_slen == O_GE) /* we only do < or > here */
275 if (max - min > count * 2 + 10) /* too sparse? */
278 /* now make a new head in the exact same spot */
279 New(104,cur, 1, CMD);
283 Copy(head,cur,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;
290 Newz(105,loc, max - min + 3, CMD*);
295 i = (int)str_gnum(cur->c_short);
297 switch(cur->c_slen) {
301 for (i--; i >= -1; i--)
308 for (i++; i <= max; i++)
322 for (i = 0; i <= max; i++)
325 head->ucmd.scmd.sc_offset = min;
326 head->ucmd.scmd.sc_max = max;
327 head->ucmd.scmd.sc_next = loc;
331 append_line(head,tail)
337 if (!tail->c_head) /* make sure tail is well formed */
339 if (head != Nullcmd) {
340 tail = tail->c_head; /* get to start of tail list */
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 */
347 head->c_next = tail; /* link to end of old list */
348 tail->c_head = head->c_head; /* propagate head pointer */
350 while (tail->c_next) {
351 tail->c_next->c_head = tail->c_head;
362 register CMD *head = cur->c_head;
370 str = afetch(lineary,(int)head->c_line,FALSE);
371 if (!str || str->str_nok)
373 str->str_u.str_nval = (double)head->c_line;
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),
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);
394 make_acmd(type,stab,cond,arg)
404 cmd->ucmd.acmd.ac_stab = stab;
405 cmd->ucmd.acmd.ac_expr = arg;
408 cmd->c_flags |= CF_COND;
409 if (cmdline != NOLINE) {
410 cmd->c_line = cmdline;
413 cmd->c_file = filename;
420 make_ccmd(type,arg,cblock)
423 struct compcmd cblock;
427 Newz(108,cmd, 1, CMD);
430 cmd->ucmd.ccmd.cc_true = cblock.comp_true;
431 cmd->ucmd.ccmd.cc_alt = cblock.comp_alt;
433 cmd->c_flags |= CF_COND;
434 if (cmdline != NOLINE) {
435 cmd->c_line = cmdline;
444 make_icmd(type,arg,cblock)
447 struct compcmd cblock;
453 struct compcmd ncblock;
455 Newz(109,cmd, 1, CMD);
459 cmd->ucmd.ccmd.cc_true = cblock.comp_true;
460 cmd->ucmd.ccmd.cc_alt = cblock.comp_alt;
462 cmd->c_flags |= CF_COND;
463 if (cmdline != NOLINE) {
464 cmd->c_line = cmdline;
468 alt = cblock.comp_alt;
469 while (alt && alt->c_type == C_ELSIF) {
471 alt = alt->ucmd.ccmd.cc_alt;
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;
480 alt = cur; /* no ELSE, so cur is proxy ELSE */
483 while (cmd) { /* now point everyone at the ELSE */
485 cmd = cur->ucmd.ccmd.cc_alt;
487 if (cur->c_type == C_ELSIF)
489 if (cur->c_type == C_IF)
490 cur->ucmd.ccmd.cc_alt = alt;
501 opt_arg(cmd,fliporflop,acmd)
510 int context = 0; /* 0 = normal, 1 = before &&, 2 = before || */
511 int flp = fliporflop;
515 if (!(arg = cmd->c_expr)) {
516 cmd->c_flags &= ~CF_COND;
520 /* Can we turn && and || into if and unless? */
522 if (acmd && !cmd->ucmd.acmd.ac_expr && !(cmd->c_flags & CF_TERM) &&
523 (arg->arg_type == O_AND || arg->arg_type == O_OR) ) {
525 arg[2].arg_type &= A_MASK; /* don't suppress eval */
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 */
536 /* Turn "if (!expr)" into "unless (expr)" */
538 if (!(cmd->c_flags & CF_TERM)) { /* unless return value wanted */
539 while (arg->arg_type == O_NOT) {
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 */
544 arg = cmd->c_expr; /* here we go again */
548 if (!arg->arg_len) { /* sanity check */
553 /* for "cond .. cond" we set up for the initial check */
555 if (arg->arg_type == O_FLIP)
558 /* for "cond && expr" and "cond || expr" we can ignore expr, sort of */
561 if (arg->arg_type == O_AND)
563 else if (arg->arg_type == O_OR)
565 if (context && (arg[flp].arg_type & A_MASK) == A_EXPR) {
566 arg = arg[flp].arg_ptr.arg_arg;
568 if (arg->arg_type == O_AND || arg->arg_type == O_OR)
571 if ((context & 3) == 3)
574 if (arg[flp].arg_flags & (AF_PRE|AF_POST)) {
576 return; /* side effect, can't optimize */
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);
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;
591 if (!context) { /* no && or ||? */
593 cmd->c_expr = Nullarg;
596 cmd->c_flags |= CF_EQSURE;
598 cmd->c_flags |= CF_NESURE;
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 */
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)
627 else if (context & 2) { /* only sure if thing is true */
628 if (cmd->c_flags & CF_FIRSTNEG)
633 if (sure & (CF_EQSURE|CF_NESURE)) { /* if we know anything*/
634 if (arg[2].arg_ptr.arg_spat->spat_flags & SPAT_SCANFIRST)
638 if (sure == (CF_EQSURE|CF_NESURE) /* really sure? */
639 && arg->arg_type == O_MATCH
641 && fliporflop == 1) {
642 spat_free(arg[2].arg_ptr.arg_spat);
643 arg[2].arg_ptr.arg_spat = Nullspat; /* don't do twice */
645 cmd->c_flags |= sure;
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:
659 cmd->c_flags |= CF_FIRSTNEG;
662 cmd->c_flags |= CF_FIRSTNEG;
665 sure |= CF_NESURE|CF_EQSURE;
668 if (context & 1) { /* only sure if thing is false */
669 if (cmd->c_flags & CF_FIRSTNEG)
674 else if (context & 2) { /* only sure if thing is true */
675 if (cmd->c_flags & CF_FIRSTNEG)
680 if (sure & (CF_EQSURE|CF_NESURE)) {
682 cmd->c_flags |= sure;
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;
694 STR *str = arg[2].arg_ptr.arg_str;
696 if ((!str->str_nok && !looks_like_number(str)))
697 warn("Possible use of == on string value");
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 */
705 else if (context & 2) { /* only sure if thing is true */
708 if (sure & (CF_EQSURE|CF_NESURE)) {
710 cmd->c_flags |= sure;
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) {
722 cmd->c_stab = arg2[1].arg_ptr.arg_stab;
723 if (!(stab_io(arg2[1].arg_ptr.arg_stab)->flags & IOF_ARGV)) {
726 cmd->c_expr = Nullarg;
730 else if (arg->arg_type == O_CHOP &&
731 (arg[1].arg_type == A_STAB || arg[1].arg_type == A_LVAL) ) {
733 cmd->c_stab = arg[1].arg_ptr.arg_stab;
735 cmd->c_expr = Nullarg;
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 */
752 if ((opt & CF_OPTIMIZE) == CFT_EVAL)
753 cmd->c_flags = (cmd->c_flags & ~CF_OPTIMIZE) | CFT_UNFLIP;
774 cmd->c_flags |= CF_COND;
786 cmd->c_flags |= CF_COND|CF_LOOP;
788 if (!(cmd->c_flags & CF_INVERT))
789 while_io(cmd); /* add $_ =, if necessary */
791 if (cmd->c_type == C_BLOCK)
792 cmd->c_flags &= ~CF_COND;
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" */
807 register CMD *targ = cmd;
810 if (targ->c_flags & CF_DBSUB)
812 targ->c_flags ^= CF_INVERT;
821 char *tname = tmpbuf;
823 if (bufptr > oldoldbufptr && bufptr - oldoldbufptr < 200 &&
824 oldoldbufptr != oldbufptr && oldbufptr != bufptr) {
825 while (isspace(*oldoldbufptr))
827 strncpy(tmp2buf, oldoldbufptr, bufptr - oldoldbufptr);
828 tmp2buf[bufptr - oldoldbufptr] = '\0';
829 sprintf(tname,"next 2 tokens \"%s\"",tmp2buf);
831 else if (bufptr > oldbufptr && bufptr - oldbufptr < 200 &&
832 oldbufptr != bufptr) {
833 while (isspace(*oldbufptr))
835 strncpy(tmp2buf, oldbufptr, bufptr - oldbufptr);
836 tmp2buf[bufptr - oldbufptr] = '\0';
837 sprintf(tname,"next token \"%s\"",tmp2buf);
839 else if (yychar > 256)
840 tname = "next token ???";
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");
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);
856 str_cat(stab_val(stabent("@",TRUE)),buf);
859 if (++error_count >= 10)
860 fatal("Too many errors\n");
867 register ARG *arg = cmd->c_expr;
870 /* hoist "while (<channel>)" up into command block */
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));
882 cmd->c_expr = Nullarg;
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;
890 cmd->c_expr = Nullarg;
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;
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 */
911 if (cmd->c_expr && (cmd->c_flags & CF_OPTIMIZE) == CFT_FALSE)
912 opt_arg(cmd,1, cmd->c_type == C_EXPR);
914 while_io(cmd); /* add $_ =, if necessary */
916 /* First find the end of the true list */
918 tail = cmd->ucmd.ccmd.cc_true;
921 New(112,newtail, 1, CMD); /* guaranteed continue */
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 ||
930 tail->ucmd.acmd.ac_expr[1].arg_ptr.arg_str->str_ptr) )))
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;
937 tail->ucmd.ccmd.cc_alt = newtail;
938 tail->ucmd.ccmd.cc_true = Nullcmd;
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;
944 tail->ucmd.ccmd.cc_alt = newtail;
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;
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;
964 /* if there's a continue block, link it to true block and find end */
966 if (cmd->ucmd.ccmd.cc_alt != Nullcmd) {
967 tail->c_next = cmd->ucmd.ccmd.cc_alt;
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 ||
977 tail->ucmd.acmd.ac_expr[1].arg_ptr.arg_str->str_ptr) )))
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;
984 else if (tail->c_type == C_IF && !tail->ucmd.ccmd.cc_alt) {
985 tail->ucmd.ccmd.cc_alt = newtail;
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;
997 for ( ; tail->c_next; tail = tail->c_next) ;
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.
1006 tail->c_next = newtail;
1008 if (!cmd->ucmd.ccmd.cc_alt)
1009 cmd->ucmd.ccmd.cc_alt = tail; /* every loop has a continue now */
1012 (void)bcopy((char *)cmd, (char *)tail, sizeof(CMD));
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;
1027 /* hoist "for $foo (@bar)" up into command block */
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;
1039 register CMD *tofree;
1040 register CMD *head = cmd;
1043 if (cmd->c_type != C_WHILE) { /* WHILE block is duplicated */
1045 Safefree(cmd->c_label);
1047 str_free(cmd->c_short);
1049 spat_free(cmd->c_spat);
1051 arg_free(cmd->c_expr);
1053 switch (cmd->c_type) {
1058 if (cmd->ucmd.ccmd.cc_true)
1059 cmd_free(cmd->ucmd.ccmd.cc_true);
1062 if (cmd->ucmd.acmd.ac_expr)
1063 arg_free(cmd->ucmd.acmd.ac_expr);
1069 if (cmd && cmd == head) /* reached end of while loop */
1079 for (i = 1; i <= arg->arg_len; i++) {
1080 switch (arg[i].arg_type & A_MASK) {
1084 if (arg->arg_type == O_AASSIGN &&
1085 arg[i].arg_ptr.arg_arg->arg_type == O_LARRAY) {
1087 stab_name(arg[i].arg_ptr.arg_arg[1].arg_ptr.arg_stab);
1089 if (strnEQ("_GEN_",name, 5)) /* array for foreach */
1090 hdelete(defstash,name,strlen(name));
1094 arg_free(arg[i].arg_ptr.arg_arg);
1097 cmd_free(arg[i].arg_ptr.arg_cmd);
1112 str_free(arg[i].arg_ptr.arg_str);
1115 spat_free(arg[i].arg_ptr.arg_spat);
1123 register SPAT *spat;
1128 if (spat->spat_runtime)
1129 arg_free(spat->spat_runtime);
1130 if (spat->spat_repl) {
1131 arg_free(spat->spat_repl);
1133 if (spat->spat_short) {
1134 str_free(spat->spat_short);
1136 if (spat->spat_regexp) {
1137 regfree(spat->spat_regexp);
1140 /* now unlink from spat list */
1142 for (entry = defstash->tbl_array['_']; entry; entry = entry->hent_next) {
1143 register HASH *stash;
1144 STAB *stab = (STAB*)entry->hent_val;
1148 stash = stab_hash(stab);
1149 if (!stash || stash->tbl_spatroot == Null(SPAT*))
1151 if (stash->tbl_spatroot == spat)
1152 stash->tbl_spatroot = spat->spat_next;
1154 for (sp = stash->tbl_spatroot;
1155 sp && sp->spat_next != spat;
1159 sp->spat_next = spat->spat_next;
1165 /* Recursively descend a command sequence and push the address of any string
1166 * that needs saving on recursion onto the tosave array.
1170 cmd_tosave(cmd,willsave)
1172 int willsave; /* willsave passes down the tree */
1174 register CMD *head = cmd;
1175 int shouldsave = FALSE; /* shouldsave passes up the tree */
1177 register CMD *lastcmd = Nullcmd;
1181 shouldsave |= spat_tosave(cmd->c_spat);
1183 shouldsave |= arg_tosave(cmd->c_expr,willsave);
1184 switch (cmd->c_type) {
1186 if (cmd->ucmd.ccmd.cc_true) {
1187 tmpsave = cmd_tosave(cmd->ucmd.ccmd.cc_true,willsave);
1189 /* Here we check to see if the temporary array generated for
1190 * a foreach needs to be localized because of recursion.
1192 if (tmpsave && (cmd->c_flags & CF_OPTIMIZE) == CFT_ARRAY &&
1194 lastcmd->c_type == C_EXPR &&
1195 lastcmd->ucmd.acmd.ac_expr) {
1196 ARG *arg = lastcmd->ucmd.acmd.ac_expr;
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 &&
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);
1207 shouldsave |= tmpsave;
1213 if (cmd->ucmd.ccmd.cc_true)
1214 shouldsave |= cmd_tosave(cmd->ucmd.ccmd.cc_true,willsave);
1217 if (cmd->ucmd.acmd.ac_expr)
1218 shouldsave |= arg_tosave(cmd->ucmd.acmd.ac_expr,willsave);
1223 if (cmd && cmd == head) /* reached end of while loop */
1230 arg_tosave(arg,willsave)
1235 int shouldsave = FALSE;
1237 for (i = arg->arg_len; i >= 1; i--) {
1238 switch (arg[i].arg_type & A_MASK) {
1243 shouldsave |= arg_tosave(arg[i].arg_ptr.arg_arg,shouldsave);
1246 shouldsave |= cmd_tosave(arg[i].arg_ptr.arg_cmd,shouldsave);
1259 shouldsave |= spat_tosave(arg[i].arg_ptr.arg_spat);
1263 switch (arg->arg_type) {
1273 (void)apush(tosave,arg->arg_ptr.arg_str);
1279 register SPAT *spat;
1281 int shouldsave = FALSE;
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);