1 /* $Header: cons.c,v 3.0.1.6 90/03/27 15:35:21 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.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
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
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
21 * Revision 3.0.1.3 89/12/21 19:20:25 lwall
22 * patch7: made nested or recursive foreach work right
24 * Revision 3.0.1.2 89/11/17 15:08:53 lwall
25 * patch5: nested foreach on same array didn't work
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
31 * Revision 3.0 89/10/18 15:10:23 lwall
40 extern char *tokename[];
43 static int cmd_tosave();
44 static int arg_tosave();
45 static int spat_tosave();
47 static bool saw_return;
55 STAB *stab = stabent(name,TRUE);
60 line_t oldline = line;
64 warn("Subroutine %s redefined",name);
67 cmd_free(stab_sub(stab)->cmd);
68 afree(stab_sub(stab)->tosave);
69 Safefree(stab_sub(stab));
71 sub->filename = filename;
73 tosave = anew(Nullstab);
74 tosave->ary_fill = 0; /* make 1 based */
75 (void)cmd_tosave(cmd,FALSE); /* this builds the tosave array */
78 struct compcmd mycompblock;
80 mycompblock.comp_true = cmd;
81 mycompblock.comp_alt = Nullcmd;
82 cmd = add_label(savestr("_SUB_"),make_ccmd(C_BLOCK,Nullarg,mycompblock));
84 cmd->c_flags |= CF_TERM;
89 STR *str = str_nmake((double)subline);
92 sprintf(buf,"%ld",(long)line);
94 name = str_get(subname);
95 hstore(stab_xhash(DBsub),name,strlen(name),str,0);
96 str_set(subname,"main");
106 if (stab_form(stab)) {
110 for (tmpfcmd = stab_form(stab); tmpfcmd; tmpfcmd = nextfcmd) {
111 nextfcmd = tmpfcmd->f_next;
113 arg_free(tmpfcmd->f_expr);
114 if (tmpfcmd->f_unparsed)
115 str_free(tmpfcmd->f_unparsed);
117 Safefree(tmpfcmd->f_pre);
121 stab_form(stab) = fcmd;
130 register int last_opt = 0;
131 register STAB *last_stab = Nullstab;
132 register int count = 0;
133 register CMD *switchbeg = Nullcmd;
135 if (tail == Nullcmd) {
140 for (tail = head; tail; tail = tail->c_next) {
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;
147 else if (tail->c_type == C_EXPR) {
150 if (tail->ucmd.acmd.ac_expr)
151 arg = tail->ucmd.acmd.ac_expr;
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;
162 tail->c_flags |= CF_TERM;
164 if (tail->c_expr && (tail->c_flags & CF_OPTIMIZE) == CFT_FALSE)
165 opt_arg(tail,1, tail->c_type == C_EXPR);
167 /* now do a little optimization on case-ish structures */
168 switch(tail->c_flags & (CF_OPTIMIZE|CF_FIRSTNEG|CF_INVERT)) {
170 if (stabent("*",FALSE)) { /* bad assumption here!!! */
176 opt = (tail->c_flags & CF_NESURE) ? CFT_STROP : 0;
182 opt = (tail->c_slen == O_NE ? 0 : CFT_NUMOP);
183 if ((tail->c_flags&(CF_NESURE|CF_EQSURE)) != (CF_NESURE|CF_EQSURE))
189 if (opt && opt == last_opt && tail->c_stab == last_stab)
192 if (count >= 3) { /* is this the breakeven point? */
193 if (last_opt == CFT_NUMOP)
194 make_nswitch(switchbeg,count);
196 make_cswitch(switchbeg,count);
206 last_stab = tail->c_stab;
208 if (count >= 3) { /* is this the breakeven point? */
209 if (last_opt == CFT_NUMOP)
210 make_nswitch(switchbeg,count);
212 make_cswitch(switchbeg,count);
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.
221 make_cswitch(head,count)
228 register int min = 255;
229 register int max = 0;
231 /* make a new head in the exact same spot */
232 New(102,cur, 1, CMD);
236 Copy(head,cur,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;
243 Newz(103,loc,258,CMD*);
244 loc++; /* lie a little */
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))) {
258 i = *cur->c_short->str_ptr & 255;
271 Copy(&loc[min],&loc[0], max - min, CMD*);
275 for (i = 0; i <= max; i++)
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;
284 make_nswitch(head,count)
288 register CMD *cur = head;
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! */
298 i = (int)str_gnum(cur->c_short);
300 if (value != cur->c_short->str_u.str_nval)
301 return; /* fractional values--just forget it */
304 return; /* too big for a short */
305 if (cur->c_slen == O_LE)
307 else if (cur->c_slen == O_GE) /* we only do < or > here */
316 if (max - min > count * 2 + 10) /* too sparse? */
319 /* now make a new head in the exact same spot */
320 New(104,cur, 1, CMD);
324 Copy(head,cur,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;
331 Newz(105,loc, max - min + 3, CMD*);
336 i = (int)str_gnum(cur->c_short);
338 switch(cur->c_slen) {
342 for (i--; i >= -1; i--)
349 for (i++; i <= max; i++)
363 for (i = 0; i <= max; i++)
366 head->ucmd.scmd.sc_offset = min;
367 head->ucmd.scmd.sc_max = max;
368 head->ucmd.scmd.sc_next = loc;
372 append_line(head,tail)
378 if (!tail->c_head) /* make sure tail is well formed */
380 if (head != Nullcmd) {
381 tail = tail->c_head; /* get to start of tail list */
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 */
388 head->c_next = tail; /* link to end of old list */
389 tail->c_head = head->c_head; /* propagate head pointer */
391 while (tail->c_next) {
392 tail->c_next->c_head = tail->c_head;
403 register CMD *head = cur->c_head;
411 str = afetch(lineary,(int)head->c_line,FALSE);
412 if (!str || str->str_nok)
414 str->str_u.str_nval = (double)head->c_line;
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),
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);
435 make_acmd(type,stab,cond,arg)
445 cmd->ucmd.acmd.ac_stab = stab;
446 cmd->ucmd.acmd.ac_expr = arg;
449 cmd->c_flags |= CF_COND;
450 if (cmdline == NOLINE)
453 cmd->c_line = cmdline;
456 cmd->c_file = filename;
463 make_ccmd(type,arg,cblock)
466 struct compcmd cblock;
470 Newz(108,cmd, 1, CMD);
473 cmd->ucmd.ccmd.cc_true = cblock.comp_true;
474 cmd->ucmd.ccmd.cc_alt = cblock.comp_alt;
476 cmd->c_flags |= CF_COND;
477 if (cmdline == NOLINE)
480 cmd->c_line = cmdline;
489 make_icmd(type,arg,cblock)
492 struct compcmd cblock;
498 struct compcmd ncblock;
500 Newz(109,cmd, 1, CMD);
504 cmd->ucmd.ccmd.cc_true = cblock.comp_true;
505 cmd->ucmd.ccmd.cc_alt = cblock.comp_alt;
507 cmd->c_flags |= CF_COND;
508 if (cmdline == NOLINE)
511 cmd->c_line = cmdline;
515 alt = cblock.comp_alt;
516 while (alt && alt->c_type == C_ELSIF) {
518 alt = alt->ucmd.ccmd.cc_alt;
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;
527 alt = cur; /* no ELSE, so cur is proxy ELSE */
530 while (cmd) { /* now point everyone at the ELSE */
532 cmd = cur->ucmd.ccmd.cc_alt;
534 if (cur->c_type == C_ELSIF)
536 if (cur->c_type == C_IF)
537 cur->ucmd.ccmd.cc_alt = alt;
548 opt_arg(cmd,fliporflop,acmd)
557 int context = 0; /* 0 = normal, 1 = before &&, 2 = before || */
558 int flp = fliporflop;
562 if (!(arg = cmd->c_expr)) {
563 cmd->c_flags &= ~CF_COND;
567 /* Can we turn && and || into if and unless? */
569 if (acmd && !cmd->ucmd.acmd.ac_expr && !(cmd->c_flags & CF_TERM) &&
570 (arg->arg_type == O_AND || arg->arg_type == O_OR) ) {
572 arg[2].arg_type &= A_MASK; /* don't suppress eval */
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 */
583 /* Turn "if (!expr)" into "unless (expr)" */
585 if (!(cmd->c_flags & CF_TERM)) { /* unless return value wanted */
586 while (arg->arg_type == O_NOT) {
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 */
591 arg = cmd->c_expr; /* here we go again */
595 if (!arg->arg_len) { /* sanity check */
600 /* for "cond .. cond" we set up for the initial check */
602 if (arg->arg_type == O_FLIP)
605 /* for "cond && expr" and "cond || expr" we can ignore expr, sort of */
608 if (arg->arg_type == O_AND)
610 else if (arg->arg_type == O_OR)
612 if (context && (arg[flp].arg_type & A_MASK) == A_EXPR) {
613 arg = arg[flp].arg_ptr.arg_arg;
615 if (arg->arg_type == O_AND || arg->arg_type == O_OR)
618 if ((context & 3) == 3)
621 if (arg[flp].arg_flags & (AF_PRE|AF_POST)) {
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 */
627 return; /* side effect, can't optimize */
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);
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;
642 if (!context) { /* no && or ||? */
644 cmd->c_expr = Nullarg;
647 cmd->c_flags |= CF_EQSURE;
649 cmd->c_flags |= CF_NESURE;
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 */
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)
678 else if (context & 2) { /* only sure if thing is true */
679 if (cmd->c_flags & CF_FIRSTNEG)
684 if (sure & (CF_EQSURE|CF_NESURE)) { /* if we know anything*/
685 if (arg[2].arg_ptr.arg_spat->spat_flags & SPAT_SCANFIRST)
689 if (sure == (CF_EQSURE|CF_NESURE) /* really sure? */
690 && arg->arg_type == O_MATCH
692 && fliporflop == 1) {
693 spat_free(arg[2].arg_ptr.arg_spat);
694 arg[2].arg_ptr.arg_spat = Nullspat; /* don't do twice */
696 cmd->c_flags |= sure;
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:
710 cmd->c_flags |= CF_FIRSTNEG;
713 cmd->c_flags |= CF_FIRSTNEG;
716 sure |= CF_NESURE|CF_EQSURE;
719 if (context & 1) { /* only sure if thing is false */
720 if (cmd->c_flags & CF_FIRSTNEG)
725 else if (context & 2) { /* only sure if thing is true */
726 if (cmd->c_flags & CF_FIRSTNEG)
731 if (sure & (CF_EQSURE|CF_NESURE)) {
733 cmd->c_flags |= sure;
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;
745 STR *str = arg[2].arg_ptr.arg_str;
747 if ((!str->str_nok && !looks_like_number(str)))
748 warn("Possible use of == on string value");
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 */
756 else if (context & 2) { /* only sure if thing is true */
759 if (sure & (CF_EQSURE|CF_NESURE)) {
761 cmd->c_flags |= sure;
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) {
773 cmd->c_stab = arg2[1].arg_ptr.arg_stab;
774 if (!(stab_io(arg2[1].arg_ptr.arg_stab)->flags & IOF_ARGV)) {
777 cmd->c_expr = Nullarg;
781 else if (arg->arg_type == O_CHOP &&
782 (arg[1].arg_type == A_STAB || arg[1].arg_type == A_LVAL) ) {
784 cmd->c_stab = arg[1].arg_ptr.arg_stab;
786 cmd->c_expr = Nullarg;
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 */
803 if ((opt & CF_OPTIMIZE) == CFT_EVAL)
804 cmd->c_flags = (cmd->c_flags & ~CF_OPTIMIZE) | CFT_UNFLIP;
825 cmd->c_flags |= CF_COND;
837 cmd->c_flags |= CF_COND|CF_LOOP;
839 if (!(cmd->c_flags & CF_INVERT))
840 while_io(cmd); /* add $_ =, if necessary */
842 if (cmd->c_type == C_BLOCK)
843 cmd->c_flags &= ~CF_COND;
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" */
858 register CMD *targ = cmd;
861 if (targ->c_flags & CF_DBSUB)
863 targ->c_flags ^= CF_INVERT;
872 char *tname = tmpbuf;
874 if (bufptr > oldoldbufptr && bufptr - oldoldbufptr < 200 &&
875 oldoldbufptr != oldbufptr && oldbufptr != bufptr) {
876 while (isspace(*oldoldbufptr))
878 strncpy(tmp2buf, oldoldbufptr, bufptr - oldoldbufptr);
879 tmp2buf[bufptr - oldoldbufptr] = '\0';
880 sprintf(tname,"next 2 tokens \"%s\"",tmp2buf);
882 else if (bufptr > oldbufptr && bufptr - oldbufptr < 200 &&
883 oldbufptr != bufptr) {
884 while (isspace(*oldbufptr))
886 strncpy(tmp2buf, oldbufptr, bufptr - oldbufptr);
887 tmp2buf[bufptr - oldbufptr] = '\0';
888 sprintf(tname,"next token \"%s\"",tmp2buf);
890 else if (yychar > 256)
891 tname = "next token ???";
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");
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);
907 str_cat(stab_val(stabent("@",TRUE)),buf);
910 if (++error_count >= 10)
911 fatal("Too many errors\n");
918 register ARG *arg = cmd->c_expr;
921 /* hoist "while (<channel>)" up into command block */
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));
933 cmd->c_expr = Nullarg;
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;
941 cmd->c_expr = Nullarg;
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;
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 */
962 if (cmd->c_expr && (cmd->c_flags & CF_OPTIMIZE) == CFT_FALSE)
963 opt_arg(cmd,1, cmd->c_type == C_EXPR);
965 while_io(cmd); /* add $_ =, if necessary */
967 /* First find the end of the true list */
969 tail = cmd->ucmd.ccmd.cc_true;
972 New(112,newtail, 1, CMD); /* guaranteed continue */
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 ||
981 tail->ucmd.acmd.ac_expr[1].arg_ptr.arg_str->str_ptr) )))
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;
988 tail->ucmd.ccmd.cc_alt = newtail;
989 tail->ucmd.ccmd.cc_true = Nullcmd;
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;
995 tail->ucmd.ccmd.cc_alt = newtail;
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;
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;
1012 tail = tail->c_next;
1015 /* if there's a continue block, link it to true block and find end */
1017 if (cmd->ucmd.ccmd.cc_alt != Nullcmd) {
1018 tail->c_next = cmd->ucmd.ccmd.cc_alt;
1019 tail = tail->c_next;
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 ||
1028 tail->ucmd.acmd.ac_expr[1].arg_ptr.arg_str->str_ptr) )))
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;
1035 else if (tail->c_type == C_IF && !tail->ucmd.ccmd.cc_alt) {
1036 tail->ucmd.ccmd.cc_alt = newtail;
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;
1046 tail = tail->c_next;
1048 for ( ; tail->c_next; tail = tail->c_next) ;
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.
1057 tail->c_next = newtail;
1059 if (!cmd->ucmd.ccmd.cc_alt)
1060 cmd->ucmd.ccmd.cc_alt = tail; /* every loop has a continue now */
1063 (void)bcopy((char *)cmd, (char *)tail, sizeof(CMD));
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;
1078 /* hoist "for $foo (@bar)" up into command block */
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;
1092 register CMD *tofree;
1093 register CMD *head = cmd;
1096 if (cmd->c_type != C_WHILE) { /* WHILE block is duplicated */
1098 Safefree(cmd->c_label);
1100 str_free(cmd->c_short);
1102 spat_free(cmd->c_spat);
1104 arg_free(cmd->c_expr);
1106 switch (cmd->c_type) {
1111 if (cmd->ucmd.ccmd.cc_true)
1112 cmd_free(cmd->ucmd.ccmd.cc_true);
1115 if (cmd->ucmd.acmd.ac_expr)
1116 arg_free(cmd->ucmd.acmd.ac_expr);
1122 if (cmd && cmd == head) /* reached end of while loop */
1132 for (i = 1; i <= arg->arg_len; i++) {
1133 switch (arg[i].arg_type & A_MASK) {
1137 if (arg->arg_type == O_AASSIGN &&
1138 arg[i].arg_ptr.arg_arg->arg_type == O_LARRAY) {
1140 stab_name(arg[i].arg_ptr.arg_arg[1].arg_ptr.arg_stab);
1142 if (strnEQ("_GEN_",name, 5)) /* array for foreach */
1143 hdelete(defstash,name,strlen(name));
1147 arg_free(arg[i].arg_ptr.arg_arg);
1150 cmd_free(arg[i].arg_ptr.arg_cmd);
1165 str_free(arg[i].arg_ptr.arg_str);
1168 spat_free(arg[i].arg_ptr.arg_spat);
1176 register SPAT *spat;
1181 if (spat->spat_runtime)
1182 arg_free(spat->spat_runtime);
1183 if (spat->spat_repl) {
1184 arg_free(spat->spat_repl);
1186 if (spat->spat_short) {
1187 str_free(spat->spat_short);
1189 if (spat->spat_regexp) {
1190 regfree(spat->spat_regexp);
1193 /* now unlink from spat list */
1195 for (entry = defstash->tbl_array['_']; entry; entry = entry->hent_next) {
1196 register HASH *stash;
1197 STAB *stab = (STAB*)entry->hent_val;
1201 stash = stab_hash(stab);
1202 if (!stash || stash->tbl_spatroot == Null(SPAT*))
1204 if (stash->tbl_spatroot == spat)
1205 stash->tbl_spatroot = spat->spat_next;
1207 for (sp = stash->tbl_spatroot;
1208 sp && sp->spat_next != spat;
1212 sp->spat_next = spat->spat_next;
1218 /* Recursively descend a command sequence and push the address of any string
1219 * that needs saving on recursion onto the tosave array.
1223 cmd_tosave(cmd,willsave)
1225 int willsave; /* willsave passes down the tree */
1227 register CMD *head = cmd;
1228 int shouldsave = FALSE; /* shouldsave passes up the tree */
1230 register CMD *lastcmd = Nullcmd;
1234 shouldsave |= spat_tosave(cmd->c_spat);
1236 shouldsave |= arg_tosave(cmd->c_expr,willsave);
1237 switch (cmd->c_type) {
1239 if (cmd->ucmd.ccmd.cc_true) {
1240 tmpsave = cmd_tosave(cmd->ucmd.ccmd.cc_true,willsave);
1242 /* Here we check to see if the temporary array generated for
1243 * a foreach needs to be localized because of recursion.
1245 if (tmpsave && (cmd->c_flags & CF_OPTIMIZE) == CFT_ARRAY) {
1247 lastcmd->c_type == C_EXPR &&
1248 lastcmd->ucmd.acmd.ac_expr) {
1249 ARG *arg = lastcmd->ucmd.acmd.ac_expr;
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 &&
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);
1262 /* in any event, save the iterator */
1264 (void)apush(tosave,cmd->c_short);
1266 shouldsave |= tmpsave;
1272 if (cmd->ucmd.ccmd.cc_true)
1273 shouldsave |= cmd_tosave(cmd->ucmd.ccmd.cc_true,willsave);
1276 if (cmd->ucmd.acmd.ac_expr)
1277 shouldsave |= arg_tosave(cmd->ucmd.acmd.ac_expr,willsave);
1282 if (cmd && cmd == head) /* reached end of while loop */
1289 arg_tosave(arg,willsave)
1294 int shouldsave = FALSE;
1296 for (i = arg->arg_len; i >= 1; i--) {
1297 switch (arg[i].arg_type & A_MASK) {
1302 shouldsave |= arg_tosave(arg[i].arg_ptr.arg_arg,shouldsave);
1305 shouldsave |= cmd_tosave(arg[i].arg_ptr.arg_cmd,shouldsave);
1318 shouldsave |= spat_tosave(arg[i].arg_ptr.arg_spat);
1322 switch (arg->arg_type) {
1332 (void)apush(tosave,arg->arg_ptr.arg_str);
1338 register SPAT *spat;
1340 int shouldsave = FALSE;
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);