1 /* $Header: cons.c,v 4.0 91/03/20 01:05:51 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 4.0 91/03/20 01:05:51 lwall
18 extern char *tokename[];
21 static int cmd_tosave();
22 static int arg_tosave();
23 static int spat_tosave();
25 static bool saw_return;
33 STAB *stab = stabent(name,TRUE);
38 CMD *oldcurcmd = curcmd;
42 warn("Subroutine %s redefined",name);
45 if (stab_sub(stab)->cmd) {
46 cmd_free(stab_sub(stab)->cmd);
47 stab_sub(stab)->cmd = Nullcmd;
48 afree(stab_sub(stab)->tosave);
50 Safefree(stab_sub(stab));
53 sub->filestab = curcmd->c_filestab;
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));
66 cmd->c_flags |= CF_TERM;
71 STR *tmpstr = str_mortal(&str_undef);
73 sprintf(buf,"%s:%ld",stab_val(curcmd->c_filestab)->str_ptr,
75 str = str_make(buf,0);
77 sprintf(buf,"%ld",(long)curcmd->c_line);
79 name = str_get(subname);
80 stab_fullname(tmpstr,stab);
81 hstore(stab_xhash(DBsub), tmpstr->str_ptr, tmpstr->str_cur, str, 0);
82 str_set(subname,"main");
89 make_usub(name, ix, subaddr, filename)
96 STAB *stab = stabent(name,allstabs);
98 if (!stab) /* unused function */
100 Newz(101,sub,1,SUBR);
101 if (stab_sub(stab)) {
103 warn("Subroutine %s redefined",name);
104 if (stab_sub(stab)->cmd) {
105 cmd_free(stab_sub(stab)->cmd);
106 stab_sub(stab)->cmd = Nullcmd;
107 afree(stab_sub(stab)->tosave);
109 Safefree(stab_sub(stab));
111 stab_sub(stab) = sub;
112 sub->filestab = fstab(filename);
113 sub->usersub = subaddr;
122 if (stab_form(stab)) {
126 for (tmpfcmd = stab_form(stab); tmpfcmd; tmpfcmd = nextfcmd) {
127 nextfcmd = tmpfcmd->f_next;
129 arg_free(tmpfcmd->f_expr);
130 if (tmpfcmd->f_unparsed)
131 str_free(tmpfcmd->f_unparsed);
133 Safefree(tmpfcmd->f_pre);
137 stab_form(stab) = fcmd;
146 register int last_opt = 0;
147 register STAB *last_stab = Nullstab;
148 register int count = 0;
149 register CMD *switchbeg = Nullcmd;
151 if (tail == Nullcmd) {
156 for (tail = head; tail; tail = tail->c_next) {
158 /* save one measly dereference at runtime */
159 if (tail->c_type == C_IF) {
160 if (!(tail->ucmd.ccmd.cc_alt = tail->ucmd.ccmd.cc_alt->c_next))
161 tail->c_flags |= CF_TERM;
163 else if (tail->c_type == C_EXPR) {
166 if (tail->ucmd.acmd.ac_expr)
167 arg = tail->ucmd.acmd.ac_expr;
171 if (arg->arg_type == O_RETURN)
172 tail->c_flags |= CF_TERM;
173 else if (arg->arg_type == O_ITEM && arg[1].arg_type == A_CMD)
174 tail->c_flags |= CF_TERM;
178 tail->c_flags |= CF_TERM;
180 if (tail->c_expr && (tail->c_flags & CF_OPTIMIZE) == CFT_FALSE)
181 opt_arg(tail,1, tail->c_type == C_EXPR);
183 /* now do a little optimization on case-ish structures */
184 switch(tail->c_flags & (CF_OPTIMIZE|CF_FIRSTNEG|CF_INVERT)) {
186 if (stabent("*",FALSE)) { /* bad assumption here!!! */
192 opt = (tail->c_flags & CF_NESURE) ? CFT_STROP : 0;
198 opt = (tail->c_slen == O_NE ? 0 : CFT_NUMOP);
199 if ((tail->c_flags&(CF_NESURE|CF_EQSURE)) != (CF_NESURE|CF_EQSURE))
205 if (opt && opt == last_opt && tail->c_stab == last_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);
222 last_stab = tail->c_stab;
224 if (count >= 3) { /* is this the breakeven point? */
225 if (last_opt == CFT_NUMOP)
226 make_nswitch(switchbeg,count);
228 make_cswitch(switchbeg,count);
233 /* We've spotted a sequence of CMDs that all test the value of the same
234 * spat. Thus we can insert a SWITCH in front and jump directly
235 * to the correct one.
237 make_cswitch(head,count)
244 register int min = 255;
245 register int max = 0;
247 /* make a new head in the exact same spot */
248 New(102,cur, 1, CMD);
252 Copy(head,cur,1,CMD);
255 head->c_type = C_CSWITCH;
256 head->c_next = cur; /* insert new cmd at front of list */
257 head->c_stab = cur->c_stab;
259 Newz(103,loc,258,CMD*);
260 loc++; /* lie a little */
262 if ((cur->c_flags & CF_OPTIMIZE) == CFT_CCLASS) {
263 for (i = 0; i <= 255; i++) {
264 if (!loc[i] && cur->c_short->str_ptr[i>>3] & (1 << (i&7))) {
274 i = *cur->c_short->str_ptr & 255;
287 Copy(&loc[min],&loc[0], max - min, CMD*);
291 for (i = 0; i <= max; i++)
294 Renew(loc,max+1,CMD*); /* chop it down to size */
295 head->ucmd.scmd.sc_offset = min;
296 head->ucmd.scmd.sc_max = max;
297 head->ucmd.scmd.sc_next = loc;
300 make_nswitch(head,count)
304 register CMD *cur = head;
307 register int min = 32767;
308 register int max = -32768;
309 int origcount = count;
310 double value; /* or your money back! */
311 short changed; /* so triple your money back! */
314 i = (int)str_gnum(cur->c_short);
316 if (value != cur->c_short->str_u.str_nval)
317 return; /* fractional values--just forget it */
320 return; /* too big for a short */
321 if (cur->c_slen == O_LE)
323 else if (cur->c_slen == O_GE) /* we only do < or > here */
332 if (max - min > count * 2 + 10) /* too sparse? */
335 /* now make a new head in the exact same spot */
336 New(104,cur, 1, CMD);
340 Copy(head,cur,1,CMD);
343 head->c_type = C_NSWITCH;
344 head->c_next = cur; /* insert new cmd at front of list */
345 head->c_stab = cur->c_stab;
347 Newz(105,loc, max - min + 3, CMD*);
352 i = (int)str_gnum(cur->c_short);
354 switch(cur->c_slen) {
358 for (i--; i >= -1; i--)
365 for (i++; i <= max; i++)
379 for (i = 0; i <= max; i++)
382 head->ucmd.scmd.sc_offset = min;
383 head->ucmd.scmd.sc_max = max;
384 head->ucmd.scmd.sc_next = loc;
388 append_line(head,tail)
394 if (!tail->c_head) /* make sure tail is well formed */
396 if (head != Nullcmd) {
397 tail = tail->c_head; /* get to start of tail list */
399 head->c_head = head; /* start a new head list */
400 while (head->c_next) {
401 head->c_next->c_head = head->c_head;
402 head = head->c_next; /* get to end of head list */
404 head->c_next = tail; /* link to end of old list */
405 tail->c_head = head->c_head; /* propagate head pointer */
407 while (tail->c_next) {
408 tail->c_next->c_head = tail->c_head;
419 register CMD *head = cur->c_head;
426 str = afetch(stab_xarray(curcmd->c_filestab),(int)head->c_line,FALSE);
427 if (str == &str_undef || str->str_nok)
429 str->str_u.str_nval = (double)head->c_line;
432 str_magic(str, curcmd->c_filestab, 0, Nullch, 0);
433 str->str_magic->str_u.str_cmd = cmd;
434 cmd->c_type = C_EXPR;
435 cmd->ucmd.acmd.ac_stab = Nullstab;
436 cmd->ucmd.acmd.ac_expr = Nullarg;
437 cmd->c_expr = make_op(O_SUBR, 2,
438 stab2arg(A_WORD,DBstab),
441 cmd->c_flags |= CF_COND|CF_DBSUB|CFT_D0;
442 cmd->c_line = head->c_line;
443 cmd->c_label = head->c_label;
444 cmd->c_filestab = curcmd->c_filestab;
445 cmd->c_stash = curstash;
446 return append_line(cmd, cur);
450 make_acmd(type,stab,cond,arg)
460 cmd->ucmd.acmd.ac_stab = stab;
461 cmd->ucmd.acmd.ac_expr = arg;
464 cmd->c_flags |= CF_COND;
465 if (cmdline == NOLINE)
466 cmd->c_line = curcmd->c_line;
468 cmd->c_line = cmdline;
471 cmd->c_filestab = curcmd->c_filestab;
472 cmd->c_stash = curstash;
479 make_ccmd(type,arg,cblock)
482 struct compcmd cblock;
486 Newz(108,cmd, 1, CMD);
489 cmd->ucmd.ccmd.cc_true = cblock.comp_true;
490 cmd->ucmd.ccmd.cc_alt = cblock.comp_alt;
492 cmd->c_flags |= CF_COND;
493 if (cmdline == NOLINE)
494 cmd->c_line = curcmd->c_line;
496 cmd->c_line = cmdline;
499 cmd->c_filestab = curcmd->c_filestab;
500 cmd->c_stash = curstash;
507 make_icmd(type,arg,cblock)
510 struct compcmd cblock;
516 struct compcmd ncblock;
518 Newz(109,cmd, 1, CMD);
522 cmd->ucmd.ccmd.cc_true = cblock.comp_true;
523 cmd->ucmd.ccmd.cc_alt = cblock.comp_alt;
525 cmd->c_flags |= CF_COND;
526 if (cmdline == NOLINE)
527 cmd->c_line = curcmd->c_line;
529 cmd->c_line = cmdline;
532 cmd->c_filestab = curcmd->c_filestab;
533 cmd->c_stash = curstash;
535 alt = cblock.comp_alt;
536 while (alt && alt->c_type == C_ELSIF) {
538 alt = alt->ucmd.ccmd.cc_alt;
540 if (alt) { /* a real life ELSE at the end? */
541 ncblock.comp_true = alt;
542 ncblock.comp_alt = Nullcmd;
543 alt = append_line(cur,make_ccmd(C_ELSE,Nullarg,ncblock));
544 cur->ucmd.ccmd.cc_alt = alt;
547 alt = cur; /* no ELSE, so cur is proxy ELSE */
550 while (cmd) { /* now point everyone at the ELSE */
552 cmd = cur->ucmd.ccmd.cc_alt;
554 if (cur->c_type == C_ELSIF)
556 if (cur->c_type == C_IF)
557 cur->ucmd.ccmd.cc_alt = alt;
568 opt_arg(cmd,fliporflop,acmd)
577 int context = 0; /* 0 = normal, 1 = before &&, 2 = before || */
578 int flp = fliporflop;
582 if (!(arg = cmd->c_expr)) {
583 cmd->c_flags &= ~CF_COND;
587 /* Can we turn && and || into if and unless? */
589 if (acmd && !cmd->ucmd.acmd.ac_expr && !(cmd->c_flags & CF_TERM) &&
590 (arg->arg_type == O_AND || arg->arg_type == O_OR) ) {
592 arg[2].arg_type &= A_MASK; /* don't suppress eval */
594 cmd->ucmd.acmd.ac_expr = arg[2].arg_ptr.arg_arg;
595 cmd->c_expr = arg[1].arg_ptr.arg_arg;
596 if (arg->arg_type == O_OR)
597 cmd->c_flags ^= CF_INVERT; /* || is like unless */
603 /* Turn "if (!expr)" into "unless (expr)" */
605 if (!(cmd->c_flags & CF_TERM)) { /* unless return value wanted */
606 while (arg->arg_type == O_NOT) {
608 cmd->c_flags ^= CF_INVERT; /* flip sense of cmd */
609 cmd->c_expr = arg[1].arg_ptr.arg_arg; /* hoist the rest of expr */
611 arg = cmd->c_expr; /* here we go again */
615 if (!arg->arg_len) { /* sanity check */
620 /* for "cond .. cond" we set up for the initial check */
622 if (arg->arg_type == O_FLIP)
625 /* for "cond && expr" and "cond || expr" we can ignore expr, sort of */
628 if (arg->arg_type == O_AND)
630 else if (arg->arg_type == O_OR)
632 if (context && (arg[flp].arg_type & A_MASK) == A_EXPR) {
633 arg = arg[flp].arg_ptr.arg_arg;
635 if (arg->arg_type == O_AND || arg->arg_type == O_OR)
638 if ((context & 3) == 3)
641 if (arg[flp].arg_flags & (AF_PRE|AF_POST)) {
643 if (acmd && !cmd->ucmd.acmd.ac_expr && !(cmd->c_flags & CF_TERM)
644 && cmd->c_expr->arg_type == O_ITEM) {
645 arg[flp].arg_flags &= ~AF_POST; /* prefer ++$foo to $foo++ */
646 arg[flp].arg_flags |= AF_PRE; /* if value not wanted */
648 return; /* side effect, can't optimize */
651 if (arg->arg_type == O_ITEM || arg->arg_type == O_FLIP ||
652 arg->arg_type == O_AND || arg->arg_type == O_OR) {
653 if ((arg[flp].arg_type & A_MASK) == A_SINGLE) {
654 opt = (str_true(arg[flp].arg_ptr.arg_str) ? CFT_TRUE : CFT_FALSE);
655 cmd->c_short = str_smake(arg[flp].arg_ptr.arg_str);
658 else if ((arg[flp].arg_type & A_MASK) == A_STAB ||
659 (arg[flp].arg_type & A_MASK) == A_LVAL) {
660 cmd->c_stab = arg[flp].arg_ptr.arg_stab;
662 arg[flp].arg_ptr.arg_stab = Nullstab;
665 if (!context) { /* no && or ||? */
667 cmd->c_expr = Nullarg;
670 cmd->c_flags |= CF_EQSURE;
672 cmd->c_flags |= CF_NESURE;
675 else if (arg->arg_type == O_MATCH || arg->arg_type == O_SUBST ||
676 arg->arg_type == O_NMATCH || arg->arg_type == O_NSUBST) {
677 if ((arg[1].arg_type == A_STAB || arg[1].arg_type == A_LVAL) &&
678 (arg[2].arg_type & A_MASK) == A_SPAT &&
679 arg[2].arg_ptr.arg_spat->spat_short ) {
680 cmd->c_stab = arg[1].arg_ptr.arg_stab;
681 cmd->c_short = str_smake(arg[2].arg_ptr.arg_spat->spat_short);
682 cmd->c_slen = arg[2].arg_ptr.arg_spat->spat_slen;
683 if (arg[2].arg_ptr.arg_spat->spat_flags & SPAT_ALL &&
684 !(arg[2].arg_ptr.arg_spat->spat_flags & SPAT_ONCE) &&
685 (arg->arg_type == O_MATCH || arg->arg_type == O_NMATCH) )
686 sure |= CF_EQSURE; /* (SUBST must be forced even */
687 /* if we know it will work.) */
688 if (arg->arg_type != O_SUBST) {
689 arg[2].arg_ptr.arg_spat->spat_short = Nullstr;
690 arg[2].arg_ptr.arg_spat->spat_slen = 0; /* only one chk */
692 sure |= CF_NESURE; /* normally only sure if it fails */
693 if (arg->arg_type == O_NMATCH || arg->arg_type == O_NSUBST)
694 cmd->c_flags |= CF_FIRSTNEG;
695 if (context & 1) { /* only sure if thing is false */
696 if (cmd->c_flags & CF_FIRSTNEG)
701 else if (context & 2) { /* only sure if thing is true */
702 if (cmd->c_flags & CF_FIRSTNEG)
707 if (sure & (CF_EQSURE|CF_NESURE)) { /* if we know anything*/
708 if (arg[2].arg_ptr.arg_spat->spat_flags & SPAT_SCANFIRST)
712 if (sure == (CF_EQSURE|CF_NESURE) /* really sure? */
713 && arg->arg_type == O_MATCH
715 && fliporflop == 1) {
716 spat_free(arg[2].arg_ptr.arg_spat);
717 arg[2].arg_ptr.arg_spat = Nullspat; /* don't do twice */
720 cmd->c_spat = arg[2].arg_ptr.arg_spat;
721 cmd->c_flags |= sure;
725 else if (arg->arg_type == O_SEQ || arg->arg_type == O_SNE ||
726 arg->arg_type == O_SLT || arg->arg_type == O_SGT) {
727 if (arg[1].arg_type == A_STAB || arg[1].arg_type == A_LVAL) {
728 if (arg[2].arg_type == A_SINGLE) {
729 char *junk = str_get(arg[2].arg_ptr.arg_str);
731 cmd->c_stab = arg[1].arg_ptr.arg_stab;
732 cmd->c_short = str_smake(arg[2].arg_ptr.arg_str);
733 cmd->c_slen = cmd->c_short->str_cur+1;
734 switch (arg->arg_type) {
735 case O_SLT: case O_SGT:
737 cmd->c_flags |= CF_FIRSTNEG;
740 cmd->c_flags |= CF_FIRSTNEG;
743 sure |= CF_NESURE|CF_EQSURE;
746 if (context & 1) { /* only sure if thing is false */
747 if (cmd->c_flags & CF_FIRSTNEG)
752 else if (context & 2) { /* only sure if thing is true */
753 if (cmd->c_flags & CF_FIRSTNEG)
758 if (sure & (CF_EQSURE|CF_NESURE)) {
760 cmd->c_flags |= sure;
765 else if (arg->arg_type == O_EQ || arg->arg_type == O_NE ||
766 arg->arg_type == O_LE || arg->arg_type == O_GE ||
767 arg->arg_type == O_LT || arg->arg_type == O_GT) {
768 if (arg[1].arg_type == A_STAB || arg[1].arg_type == A_LVAL) {
769 if (arg[2].arg_type == A_SINGLE) {
770 cmd->c_stab = arg[1].arg_ptr.arg_stab;
772 STR *str = arg[2].arg_ptr.arg_str;
774 if ((!str->str_nok && !looks_like_number(str)))
775 warn("Possible use of == on string value");
777 cmd->c_short = str_nmake(str_gnum(arg[2].arg_ptr.arg_str));
778 cmd->c_slen = arg->arg_type;
779 sure |= CF_NESURE|CF_EQSURE;
780 if (context & 1) { /* only sure if thing is false */
783 else if (context & 2) { /* only sure if thing is true */
786 if (sure & (CF_EQSURE|CF_NESURE)) {
788 cmd->c_flags |= sure;
793 else if (arg->arg_type == O_ASSIGN &&
794 (arg[1].arg_type == A_STAB || arg[1].arg_type == A_LVAL) &&
795 arg[1].arg_ptr.arg_stab == defstab &&
796 arg[2].arg_type == A_EXPR ) {
797 arg2 = arg[2].arg_ptr.arg_arg;
798 if (arg2->arg_type == O_ITEM && arg2[1].arg_type == A_READ) {
800 cmd->c_stab = arg2[1].arg_ptr.arg_stab;
801 if (!(stab_io(arg2[1].arg_ptr.arg_stab)->flags & IOF_ARGV)) {
803 arg[2].arg_ptr.arg_arg = Nullarg;
805 cmd->c_expr = Nullarg;
809 else if (arg->arg_type == O_CHOP &&
810 (arg[1].arg_type == A_STAB || arg[1].arg_type == A_LVAL) ) {
812 cmd->c_stab = arg[1].arg_ptr.arg_stab;
814 cmd->c_expr = Nullarg;
820 if (cmd->c_flags & CF_FLIP) {
821 if (fliporflop == 1) {
822 arg = cmd->c_expr; /* get back to O_FLIP arg */
823 New(110,arg[3].arg_ptr.arg_cmd, 1, CMD);
824 Copy(cmd, arg[3].arg_ptr.arg_cmd, 1, CMD);
825 New(111,arg[4].arg_ptr.arg_cmd,1,CMD);
826 Copy(cmd, arg[4].arg_ptr.arg_cmd, 1, CMD);
827 opt_arg(arg[4].arg_ptr.arg_cmd,2,acmd);
828 arg->arg_len = 2; /* this is a lie */
831 if ((opt & CF_OPTIMIZE) == CFT_EVAL)
832 cmd->c_flags = (cmd->c_flags & ~CF_OPTIMIZE) | CFT_UNFLIP;
853 cmd->c_flags |= CF_COND;
865 cmd->c_flags |= CF_COND|CF_LOOP;
867 if (!(cmd->c_flags & CF_INVERT))
868 while_io(cmd); /* add $_ =, if necessary */
870 if (cmd->c_type == C_BLOCK)
871 cmd->c_flags &= ~CF_COND;
873 arg = cmd->ucmd.acmd.ac_expr;
874 if (arg && arg->arg_type == O_ITEM && arg[1].arg_type == A_CMD)
875 cmd->c_flags &= ~CF_COND; /* "do {} while" happens at least once */
876 if (arg && (arg->arg_flags & AF_DEPR) &&
877 (arg->arg_type == O_SUBR || arg->arg_type == O_DBSUBR) )
878 cmd->c_flags &= ~CF_COND; /* likewise for "do subr() while" */
887 register CMD *targ = cmd;
890 if (targ->c_flags & CF_DBSUB)
892 targ->c_flags ^= CF_INVERT;
901 char *tname = tmpbuf;
903 if (bufptr > oldoldbufptr && bufptr - oldoldbufptr < 200 &&
904 oldoldbufptr != oldbufptr && oldbufptr != bufptr) {
905 while (isspace(*oldoldbufptr))
907 strncpy(tmp2buf, oldoldbufptr, bufptr - oldoldbufptr);
908 tmp2buf[bufptr - oldoldbufptr] = '\0';
909 sprintf(tname,"next 2 tokens \"%s\"",tmp2buf);
911 else if (bufptr > oldbufptr && bufptr - oldbufptr < 200 &&
912 oldbufptr != bufptr) {
913 while (isspace(*oldbufptr))
915 strncpy(tmp2buf, oldbufptr, bufptr - oldbufptr);
916 tmp2buf[bufptr - oldbufptr] = '\0';
917 sprintf(tname,"next token \"%s\"",tmp2buf);
919 else if (yychar > 256)
920 tname = "next token ???";
922 (void)strcpy(tname,"at EOF");
923 else if (yychar < 32)
924 (void)sprintf(tname,"next char ^%c",yychar+64);
925 else if (yychar == 127)
926 (void)strcpy(tname,"at EOF");
928 (void)sprintf(tname,"next char %c",yychar);
929 (void)sprintf(buf, "%s in file %s at line %d, %s\n",
930 s,stab_val(curcmd->c_filestab)->str_ptr,curcmd->c_line,tname);
931 if (curcmd->c_line == multi_end && multi_start < multi_end)
932 sprintf(buf+strlen(buf),
933 " (Might be a runaway multi-line %c%c string starting on line %d)\n",
934 multi_open,multi_close,multi_start);
936 str_cat(stab_val(stabent("@",TRUE)),buf);
939 if (++error_count >= 10)
940 fatal("%s has too many errors.\n",
941 stab_val(curcmd->c_filestab)->str_ptr);
948 register ARG *arg = cmd->c_expr;
951 /* hoist "while (<channel>)" up into command block */
953 if (arg && arg->arg_type == O_ITEM && arg[1].arg_type == A_READ) {
954 cmd->c_flags &= ~CF_OPTIMIZE; /* clear optimization type */
955 cmd->c_flags |= CFT_GETS; /* and set it to do the input */
956 cmd->c_stab = arg[1].arg_ptr.arg_stab;
957 if (stab_io(arg[1].arg_ptr.arg_stab)->flags & IOF_ARGV) {
958 cmd->c_expr = l(make_op(O_ASSIGN, 2, /* fake up "$_ =" */
959 stab2arg(A_LVAL,defstab), arg, Nullarg));
963 cmd->c_expr = Nullarg;
966 else if (arg && arg->arg_type == O_ITEM && arg[1].arg_type == A_INDREAD) {
967 cmd->c_flags &= ~CF_OPTIMIZE; /* clear optimization type */
968 cmd->c_flags |= CFT_INDGETS; /* and set it to do the input */
969 cmd->c_stab = arg[1].arg_ptr.arg_stab;
971 cmd->c_expr = Nullarg;
973 else if (arg && arg->arg_type == O_ITEM && arg[1].arg_type == A_GLOB) {
974 if ((cmd->c_flags & CF_OPTIMIZE) == CFT_ARRAY)
975 asgnstab = cmd->c_stab;
978 cmd->c_expr = l(make_op(O_ASSIGN, 2, /* fake up "$foo =" */
979 stab2arg(A_LVAL,asgnstab), arg, Nullarg));
980 cmd->c_flags &= ~CF_OPTIMIZE; /* clear optimization type */
992 if (cmd->c_expr && (cmd->c_flags & CF_OPTIMIZE) == CFT_FALSE)
993 opt_arg(cmd,1, cmd->c_type == C_EXPR);
995 while_io(cmd); /* add $_ =, if necessary */
997 /* First find the end of the true list */
999 tail = cmd->ucmd.ccmd.cc_true;
1000 if (tail == Nullcmd)
1002 New(112,newtail, 1, CMD); /* guaranteed continue */
1004 /* optimize "next" to point directly to continue block */
1005 if (tail->c_type == C_EXPR &&
1006 tail->ucmd.acmd.ac_expr &&
1007 tail->ucmd.acmd.ac_expr->arg_type == O_NEXT &&
1008 (tail->ucmd.acmd.ac_expr->arg_len == 0 ||
1011 tail->ucmd.acmd.ac_expr[1].arg_ptr.arg_str->str_ptr) )))
1013 arg_free(tail->ucmd.acmd.ac_expr);
1014 tail->ucmd.acmd.ac_expr = Nullarg;
1015 tail->c_type = C_NEXT;
1016 if (cmd->ucmd.ccmd.cc_alt != Nullcmd)
1017 tail->ucmd.ccmd.cc_alt = cmd->ucmd.ccmd.cc_alt;
1019 tail->ucmd.ccmd.cc_alt = newtail;
1020 tail->ucmd.ccmd.cc_true = Nullcmd;
1022 else if (tail->c_type == C_IF && !tail->ucmd.ccmd.cc_alt) {
1023 if (cmd->ucmd.ccmd.cc_alt != Nullcmd)
1024 tail->ucmd.ccmd.cc_alt = cmd->ucmd.ccmd.cc_alt;
1026 tail->ucmd.ccmd.cc_alt = newtail;
1028 else if (tail->c_type == C_CSWITCH || tail->c_type == C_NSWITCH) {
1029 if (cmd->ucmd.ccmd.cc_alt != Nullcmd) {
1030 for (i = tail->ucmd.scmd.sc_max; i >= 0; i--)
1031 if (!tail->ucmd.scmd.sc_next[i])
1032 tail->ucmd.scmd.sc_next[i] = cmd->ucmd.ccmd.cc_alt;
1035 for (i = tail->ucmd.scmd.sc_max; i >= 0; i--)
1036 if (!tail->ucmd.scmd.sc_next[i])
1037 tail->ucmd.scmd.sc_next[i] = newtail;
1043 tail = tail->c_next;
1046 /* if there's a continue block, link it to true block and find end */
1048 if (cmd->ucmd.ccmd.cc_alt != Nullcmd) {
1049 tail->c_next = cmd->ucmd.ccmd.cc_alt;
1050 tail = tail->c_next;
1052 /* optimize "next" to point directly to continue block */
1053 if (tail->c_type == C_EXPR &&
1054 tail->ucmd.acmd.ac_expr &&
1055 tail->ucmd.acmd.ac_expr->arg_type == O_NEXT &&
1056 (tail->ucmd.acmd.ac_expr->arg_len == 0 ||
1059 tail->ucmd.acmd.ac_expr[1].arg_ptr.arg_str->str_ptr) )))
1061 arg_free(tail->ucmd.acmd.ac_expr);
1062 tail->ucmd.acmd.ac_expr = Nullarg;
1063 tail->c_type = C_NEXT;
1064 tail->ucmd.ccmd.cc_alt = newtail;
1065 tail->ucmd.ccmd.cc_true = Nullcmd;
1067 else if (tail->c_type == C_IF && !tail->ucmd.ccmd.cc_alt) {
1068 tail->ucmd.ccmd.cc_alt = newtail;
1070 else if (tail->c_type == C_CSWITCH || tail->c_type == C_NSWITCH) {
1071 for (i = tail->ucmd.scmd.sc_max; i >= 0; i--)
1072 if (!tail->ucmd.scmd.sc_next[i])
1073 tail->ucmd.scmd.sc_next[i] = newtail;
1078 tail = tail->c_next;
1080 for ( ; tail->c_next; tail = tail->c_next) ;
1083 /* Here's the real trick: link the end of the list back to the beginning,
1084 * inserting a "last" block to break out of the loop. This saves one or
1085 * two procedure calls every time through the loop, because of how cmd_exec
1086 * does tail recursion.
1089 tail->c_next = newtail;
1091 if (!cmd->ucmd.ccmd.cc_alt)
1092 cmd->ucmd.ccmd.cc_alt = tail; /* every loop has a continue now */
1095 (void)bcopy((char *)cmd, (char *)tail, sizeof(CMD));
1097 tail->c_type = C_EXPR;
1098 tail->c_flags ^= CF_INVERT; /* turn into "last unless" */
1099 tail->c_next = tail->ucmd.ccmd.cc_true; /* loop directly back to top */
1100 tail->ucmd.acmd.ac_expr = make_op(O_LAST,0,Nullarg,Nullarg,Nullarg);
1101 tail->ucmd.acmd.ac_stab = Nullstab;
1110 /* hoist "for $foo (@bar)" up into command block */
1112 cmd->c_flags &= ~CF_OPTIMIZE; /* clear optimization type */
1113 cmd->c_flags |= CFT_ARRAY; /* and set it to do the iteration */
1114 cmd->c_stab = eachstab;
1115 cmd->c_short = str_new(0); /* just to save a field in struct cmd */
1116 cmd->c_short->str_u.str_useful = -1;
1124 register CMD *tofree;
1125 register CMD *head = cmd;
1128 if (cmd->c_type != C_WHILE) { /* WHILE block is duplicated */
1130 Safefree(cmd->c_label);
1131 cmd->c_label = Nullch;
1134 str_free(cmd->c_short);
1135 cmd->c_short = Nullstr;
1138 arg_free(cmd->c_expr);
1139 cmd->c_expr = Nullarg;
1142 switch (cmd->c_type) {
1147 if (cmd->ucmd.ccmd.cc_true) {
1148 cmd_free(cmd->ucmd.ccmd.cc_true);
1149 cmd->ucmd.ccmd.cc_true = Nullcmd;
1153 if (cmd->ucmd.acmd.ac_expr) {
1154 arg_free(cmd->ucmd.acmd.ac_expr);
1155 cmd->ucmd.acmd.ac_expr = Nullarg;
1161 if (tofree != head) /* to get Saber to shut up */
1163 if (cmd && cmd == head) /* reached end of while loop */
1174 for (i = 1; i <= arg->arg_len; i++) {
1175 switch (arg[i].arg_type & A_MASK) {
1177 if (arg->arg_type == O_TRANS) {
1178 Safefree(arg[i].arg_ptr.arg_cval);
1179 arg[i].arg_ptr.arg_cval = Nullch;
1183 if (arg->arg_type == O_AASSIGN &&
1184 arg[i].arg_ptr.arg_arg->arg_type == O_LARRAY) {
1186 stab_name(arg[i].arg_ptr.arg_arg[1].arg_ptr.arg_stab);
1188 if (strnEQ("_GEN_",name, 5)) /* array for foreach */
1189 hdelete(defstash,name,strlen(name));
1193 arg_free(arg[i].arg_ptr.arg_arg);
1194 arg[i].arg_ptr.arg_arg = Nullarg;
1197 cmd_free(arg[i].arg_ptr.arg_cmd);
1198 arg[i].arg_ptr.arg_cmd = Nullcmd;
1213 str_free(arg[i].arg_ptr.arg_str);
1214 arg[i].arg_ptr.arg_str = Nullstr;
1217 spat_free(arg[i].arg_ptr.arg_spat);
1218 arg[i].arg_ptr.arg_spat = Nullspat;
1226 register SPAT *spat;
1231 if (spat->spat_runtime) {
1232 arg_free(spat->spat_runtime);
1233 spat->spat_runtime = Nullarg;
1235 if (spat->spat_repl) {
1236 arg_free(spat->spat_repl);
1237 spat->spat_repl = Nullarg;
1239 if (spat->spat_short) {
1240 str_free(spat->spat_short);
1241 spat->spat_short = Nullstr;
1243 if (spat->spat_regexp) {
1244 regfree(spat->spat_regexp);
1245 spat->spat_regexp = Null(REGEXP*);
1248 /* now unlink from spat list */
1250 for (entry = defstash->tbl_array['_']; entry; entry = entry->hent_next) {
1251 register HASH *stash;
1252 STAB *stab = (STAB*)entry->hent_val;
1256 stash = stab_hash(stab);
1257 if (!stash || stash->tbl_spatroot == Null(SPAT*))
1259 if (stash->tbl_spatroot == spat)
1260 stash->tbl_spatroot = spat->spat_next;
1262 for (sp = stash->tbl_spatroot;
1263 sp && sp->spat_next != spat;
1267 sp->spat_next = spat->spat_next;
1273 /* Recursively descend a command sequence and push the address of any string
1274 * that needs saving on recursion onto the tosave array.
1278 cmd_tosave(cmd,willsave)
1280 int willsave; /* willsave passes down the tree */
1282 register CMD *head = cmd;
1283 int shouldsave = FALSE; /* shouldsave passes up the tree */
1285 register CMD *lastcmd = Nullcmd;
1289 shouldsave |= arg_tosave(cmd->c_expr,willsave);
1290 switch (cmd->c_type) {
1292 if (cmd->ucmd.ccmd.cc_true) {
1293 tmpsave = cmd_tosave(cmd->ucmd.ccmd.cc_true,willsave);
1295 /* Here we check to see if the temporary array generated for
1296 * a foreach needs to be localized because of recursion.
1298 if (tmpsave && (cmd->c_flags & CF_OPTIMIZE) == CFT_ARRAY) {
1300 lastcmd->c_type == C_EXPR &&
1302 ARG *arg = lastcmd->c_expr;
1304 if (arg->arg_type == O_ASSIGN &&
1305 arg[1].arg_type == A_LEXPR &&
1306 arg[1].arg_ptr.arg_arg->arg_type == O_LARRAY &&
1309 arg[1].arg_ptr.arg_arg[1].arg_ptr.arg_stab),
1310 5)) { /* array generated for foreach */
1311 (void)localize(arg);
1315 /* in any event, save the iterator */
1317 (void)apush(tosave,cmd->c_short);
1319 shouldsave |= tmpsave;
1325 if (cmd->ucmd.ccmd.cc_true)
1326 shouldsave |= cmd_tosave(cmd->ucmd.ccmd.cc_true,willsave);
1329 if (cmd->ucmd.acmd.ac_expr)
1330 shouldsave |= arg_tosave(cmd->ucmd.acmd.ac_expr,willsave);
1335 if (cmd && cmd == head) /* reached end of while loop */
1342 arg_tosave(arg,willsave)
1347 int shouldsave = FALSE;
1349 for (i = arg->arg_len; i >= 1; i--) {
1350 switch (arg[i].arg_type & A_MASK) {
1355 shouldsave |= arg_tosave(arg[i].arg_ptr.arg_arg,shouldsave);
1358 shouldsave |= cmd_tosave(arg[i].arg_ptr.arg_cmd,shouldsave);
1371 shouldsave |= spat_tosave(arg[i].arg_ptr.arg_spat);
1375 switch (arg->arg_type) {
1385 (void)apush(tosave,arg->arg_ptr.arg_str);
1391 register SPAT *spat;
1393 int shouldsave = FALSE;
1395 if (spat->spat_runtime)
1396 shouldsave |= arg_tosave(spat->spat_runtime,FALSE);
1397 if (spat->spat_repl) {
1398 shouldsave |= arg_tosave(spat->spat_repl,FALSE);