1 /* $RCSfile: cons.c,v $$Revision: 4.0.1.2 $$Date: 91/11/05 16:15:13 $
3 * Copyright (c) 1991, Larry Wall
5 * You may distribute under the terms of either the GNU General Public
6 * License or the Artistic License, as specified in the README file.
9 * Revision 4.0.1.2 91/11/05 16:15:13 lwall
10 * patch11: debugger got confused over nested subroutine definitions
11 * patch11: prepared for ctype implementations that don't define isascii()
13 * Revision 4.0.1.1 91/06/07 10:31:15 lwall
14 * patch4: new copyright notice
15 * patch4: added global modifier for pattern matches
17 * Revision 4.0 91/03/20 01:05:51 lwall
26 extern char *tokename[];
29 static int cmd_tosave();
30 static int arg_tosave();
31 static int spat_tosave();
33 static bool saw_return;
41 STAB *stab = stabent(name,TRUE);
46 CMD *oldcurcmd = curcmd;
50 warn("Subroutine %s redefined",name);
53 if (stab_sub(stab)->cmd) {
54 cmd_free(stab_sub(stab)->cmd);
55 stab_sub(stab)->cmd = Nullcmd;
56 afree(stab_sub(stab)->tosave);
58 Safefree(stab_sub(stab));
61 sub->filestab = curcmd->c_filestab;
63 tosave = anew(Nullstab);
64 tosave->ary_fill = 0; /* make 1 based */
65 (void)cmd_tosave(cmd,FALSE); /* this builds the tosave array */
68 struct compcmd mycompblock;
70 mycompblock.comp_true = cmd;
71 mycompblock.comp_alt = Nullcmd;
72 cmd = add_label(savestr("_SUB_"),make_ccmd(C_BLOCK,Nullarg,mycompblock));
74 cmd->c_flags |= CF_TERM;
79 STR *tmpstr = str_mortal(&str_undef);
81 sprintf(buf,"%s:%ld",stab_val(curcmd->c_filestab)->str_ptr, subline);
82 str = str_make(buf,0);
84 sprintf(buf,"%ld",(long)curcmd->c_line);
86 name = str_get(subname);
87 stab_fullname(tmpstr,stab);
88 hstore(stab_xhash(DBsub), tmpstr->str_ptr, tmpstr->str_cur, str, 0);
94 make_usub(name, ix, subaddr, filename)
101 STAB *stab = stabent(name,allstabs);
103 if (!stab) /* unused function */
105 Newz(101,sub,1,SUBR);
106 if (stab_sub(stab)) {
108 warn("Subroutine %s redefined",name);
109 if (stab_sub(stab)->cmd) {
110 cmd_free(stab_sub(stab)->cmd);
111 stab_sub(stab)->cmd = Nullcmd;
112 afree(stab_sub(stab)->tosave);
114 Safefree(stab_sub(stab));
116 stab_sub(stab) = sub;
117 sub->filestab = fstab(filename);
118 sub->usersub = subaddr;
127 if (stab_form(stab)) {
131 for (tmpfcmd = stab_form(stab); tmpfcmd; tmpfcmd = nextfcmd) {
132 nextfcmd = tmpfcmd->f_next;
134 arg_free(tmpfcmd->f_expr);
135 if (tmpfcmd->f_unparsed)
136 str_free(tmpfcmd->f_unparsed);
138 Safefree(tmpfcmd->f_pre);
142 stab_form(stab) = fcmd;
151 register int last_opt = 0;
152 register STAB *last_stab = Nullstab;
153 register int count = 0;
154 register CMD *switchbeg = Nullcmd;
156 if (tail == Nullcmd) {
161 for (tail = head; tail; tail = tail->c_next) {
163 /* save one measly dereference at runtime */
164 if (tail->c_type == C_IF) {
165 if (!(tail->ucmd.ccmd.cc_alt = tail->ucmd.ccmd.cc_alt->c_next))
166 tail->c_flags |= CF_TERM;
168 else if (tail->c_type == C_EXPR) {
171 if (tail->ucmd.acmd.ac_expr)
172 arg = tail->ucmd.acmd.ac_expr;
176 if (arg->arg_type == O_RETURN)
177 tail->c_flags |= CF_TERM;
178 else if (arg->arg_type == O_ITEM && arg[1].arg_type == A_CMD)
179 tail->c_flags |= CF_TERM;
183 tail->c_flags |= CF_TERM;
185 if (tail->c_expr && (tail->c_flags & CF_OPTIMIZE) == CFT_FALSE)
186 opt_arg(tail,1, tail->c_type == C_EXPR);
188 /* now do a little optimization on case-ish structures */
189 switch(tail->c_flags & (CF_OPTIMIZE|CF_FIRSTNEG|CF_INVERT)) {
191 if (stabent("*",FALSE)) { /* bad assumption here!!! */
197 opt = (tail->c_flags & CF_NESURE) ? CFT_STROP : 0;
203 opt = (tail->c_slen == O_NE ? 0 : CFT_NUMOP);
204 if ((tail->c_flags&(CF_NESURE|CF_EQSURE)) != (CF_NESURE|CF_EQSURE))
210 if (opt && opt == last_opt && tail->c_stab == last_stab)
213 if (count >= 3) { /* is this the breakeven point? */
214 if (last_opt == CFT_NUMOP)
215 make_nswitch(switchbeg,count);
217 make_cswitch(switchbeg,count);
227 last_stab = tail->c_stab;
229 if (count >= 3) { /* is this the breakeven point? */
230 if (last_opt == CFT_NUMOP)
231 make_nswitch(switchbeg,count);
233 make_cswitch(switchbeg,count);
238 /* We've spotted a sequence of CMDs that all test the value of the same
239 * spat. Thus we can insert a SWITCH in front and jump directly
240 * to the correct one.
242 make_cswitch(head,count)
249 register int min = 255;
250 register int max = 0;
252 /* make a new head in the exact same spot */
253 New(102,cur, 1, CMD);
257 Copy(head,cur,1,CMD);
260 head->c_type = C_CSWITCH;
261 head->c_next = cur; /* insert new cmd at front of list */
262 head->c_stab = cur->c_stab;
264 Newz(103,loc,258,CMD*);
265 loc++; /* lie a little */
267 if ((cur->c_flags & CF_OPTIMIZE) == CFT_CCLASS) {
268 for (i = 0; i <= 255; i++) {
269 if (!loc[i] && cur->c_short->str_ptr[i>>3] & (1 << (i&7))) {
279 i = *cur->c_short->str_ptr & 255;
292 Copy(&loc[min],&loc[0], max - min, CMD*);
296 for (i = 0; i <= max; i++)
299 Renew(loc,max+1,CMD*); /* chop it down to size */
300 head->ucmd.scmd.sc_offset = min;
301 head->ucmd.scmd.sc_max = max;
302 head->ucmd.scmd.sc_next = loc;
305 make_nswitch(head,count)
309 register CMD *cur = head;
312 register int min = 32767;
313 register int max = -32768;
314 int origcount = count;
315 double value; /* or your money back! */
316 short changed; /* so triple your money back! */
319 i = (int)str_gnum(cur->c_short);
321 if (value != cur->c_short->str_u.str_nval)
322 return; /* fractional values--just forget it */
325 return; /* too big for a short */
326 if (cur->c_slen == O_LE)
328 else if (cur->c_slen == O_GE) /* we only do < or > here */
337 if (max - min > count * 2 + 10) /* too sparse? */
340 /* now make a new head in the exact same spot */
341 New(104,cur, 1, CMD);
345 Copy(head,cur,1,CMD);
348 head->c_type = C_NSWITCH;
349 head->c_next = cur; /* insert new cmd at front of list */
350 head->c_stab = cur->c_stab;
352 Newz(105,loc, max - min + 3, CMD*);
357 i = (int)str_gnum(cur->c_short);
359 switch(cur->c_slen) {
363 for (i--; i >= -1; i--)
370 for (i++; i <= max; i++)
384 for (i = 0; i <= max; i++)
387 head->ucmd.scmd.sc_offset = min;
388 head->ucmd.scmd.sc_max = max;
389 head->ucmd.scmd.sc_next = loc;
393 append_line(head,tail)
399 if (!tail->c_head) /* make sure tail is well formed */
401 if (head != Nullcmd) {
402 tail = tail->c_head; /* get to start of tail list */
404 head->c_head = head; /* start a new head list */
405 while (head->c_next) {
406 head->c_next->c_head = head->c_head;
407 head = head->c_next; /* get to end of head list */
409 head->c_next = tail; /* link to end of old list */
410 tail->c_head = head->c_head; /* propagate head pointer */
412 while (tail->c_next) {
413 tail->c_next->c_head = tail->c_head;
424 register CMD *head = cur->c_head;
431 str = afetch(stab_xarray(curcmd->c_filestab),(int)head->c_line,FALSE);
432 if (str == &str_undef || str->str_nok)
434 str->str_u.str_nval = (double)head->c_line;
437 str_magic(str, curcmd->c_filestab, 0, Nullch, 0);
438 str->str_magic->str_u.str_cmd = cmd;
439 cmd->c_type = C_EXPR;
440 cmd->ucmd.acmd.ac_stab = Nullstab;
441 cmd->ucmd.acmd.ac_expr = Nullarg;
442 cmd->c_expr = make_op(O_SUBR, 2,
443 stab2arg(A_WORD,DBstab),
446 cmd->c_flags |= CF_COND|CF_DBSUB|CFT_D0;
447 cmd->c_line = head->c_line;
448 cmd->c_label = head->c_label;
449 cmd->c_filestab = curcmd->c_filestab;
450 cmd->c_stash = curstash;
451 return append_line(cmd, cur);
455 make_acmd(type,stab,cond,arg)
465 cmd->ucmd.acmd.ac_stab = stab;
466 cmd->ucmd.acmd.ac_expr = arg;
469 cmd->c_flags |= CF_COND;
470 if (cmdline == NOLINE)
471 cmd->c_line = curcmd->c_line;
473 cmd->c_line = cmdline;
476 cmd->c_filestab = curcmd->c_filestab;
477 cmd->c_stash = curstash;
484 make_ccmd(type,arg,cblock)
487 struct compcmd cblock;
491 Newz(108,cmd, 1, CMD);
494 cmd->ucmd.ccmd.cc_true = cblock.comp_true;
495 cmd->ucmd.ccmd.cc_alt = cblock.comp_alt;
497 cmd->c_flags |= CF_COND;
498 if (cmdline == NOLINE)
499 cmd->c_line = curcmd->c_line;
501 cmd->c_line = cmdline;
504 cmd->c_filestab = curcmd->c_filestab;
505 cmd->c_stash = curstash;
512 make_icmd(type,arg,cblock)
515 struct compcmd cblock;
521 struct compcmd ncblock;
523 Newz(109,cmd, 1, CMD);
527 cmd->ucmd.ccmd.cc_true = cblock.comp_true;
528 cmd->ucmd.ccmd.cc_alt = cblock.comp_alt;
530 cmd->c_flags |= CF_COND;
531 if (cmdline == NOLINE)
532 cmd->c_line = curcmd->c_line;
534 cmd->c_line = cmdline;
537 cmd->c_filestab = curcmd->c_filestab;
538 cmd->c_stash = curstash;
540 alt = cblock.comp_alt;
541 while (alt && alt->c_type == C_ELSIF) {
543 alt = alt->ucmd.ccmd.cc_alt;
545 if (alt) { /* a real life ELSE at the end? */
546 ncblock.comp_true = alt;
547 ncblock.comp_alt = Nullcmd;
548 alt = append_line(cur,make_ccmd(C_ELSE,Nullarg,ncblock));
549 cur->ucmd.ccmd.cc_alt = alt;
552 alt = cur; /* no ELSE, so cur is proxy ELSE */
555 while (cmd) { /* now point everyone at the ELSE */
557 cmd = cur->ucmd.ccmd.cc_alt;
559 if (cur->c_type == C_ELSIF)
561 if (cur->c_type == C_IF)
562 cur->ucmd.ccmd.cc_alt = alt;
573 opt_arg(cmd,fliporflop,acmd)
582 int context = 0; /* 0 = normal, 1 = before &&, 2 = before || */
583 int flp = fliporflop;
587 if (!(arg = cmd->c_expr)) {
588 cmd->c_flags &= ~CF_COND;
592 /* Can we turn && and || into if and unless? */
594 if (acmd && !cmd->ucmd.acmd.ac_expr && !(cmd->c_flags & CF_TERM) &&
595 (arg->arg_type == O_AND || arg->arg_type == O_OR) ) {
597 arg[2].arg_type &= A_MASK; /* don't suppress eval */
599 cmd->ucmd.acmd.ac_expr = arg[2].arg_ptr.arg_arg;
600 cmd->c_expr = arg[1].arg_ptr.arg_arg;
601 if (arg->arg_type == O_OR)
602 cmd->c_flags ^= CF_INVERT; /* || is like unless */
608 /* Turn "if (!expr)" into "unless (expr)" */
610 if (!(cmd->c_flags & CF_TERM)) { /* unless return value wanted */
611 while (arg->arg_type == O_NOT) {
613 cmd->c_flags ^= CF_INVERT; /* flip sense of cmd */
614 cmd->c_expr = arg[1].arg_ptr.arg_arg; /* hoist the rest of expr */
616 arg = cmd->c_expr; /* here we go again */
620 if (!arg->arg_len) { /* sanity check */
625 /* for "cond .. cond" we set up for the initial check */
627 if (arg->arg_type == O_FLIP)
630 /* for "cond && expr" and "cond || expr" we can ignore expr, sort of */
633 if (arg->arg_type == O_AND)
635 else if (arg->arg_type == O_OR)
637 if (context && (arg[flp].arg_type & A_MASK) == A_EXPR) {
638 arg = arg[flp].arg_ptr.arg_arg;
640 if (arg->arg_type == O_AND || arg->arg_type == O_OR)
643 if ((context & 3) == 3)
646 if (arg[flp].arg_flags & (AF_PRE|AF_POST)) {
648 if (acmd && !cmd->ucmd.acmd.ac_expr && !(cmd->c_flags & CF_TERM)
649 && cmd->c_expr->arg_type == O_ITEM) {
650 arg[flp].arg_flags &= ~AF_POST; /* prefer ++$foo to $foo++ */
651 arg[flp].arg_flags |= AF_PRE; /* if value not wanted */
653 return; /* side effect, can't optimize */
656 if (arg->arg_type == O_ITEM || arg->arg_type == O_FLIP ||
657 arg->arg_type == O_AND || arg->arg_type == O_OR) {
658 if ((arg[flp].arg_type & A_MASK) == A_SINGLE) {
659 opt = (str_true(arg[flp].arg_ptr.arg_str) ? CFT_TRUE : CFT_FALSE);
660 cmd->c_short = str_smake(arg[flp].arg_ptr.arg_str);
663 else if ((arg[flp].arg_type & A_MASK) == A_STAB ||
664 (arg[flp].arg_type & A_MASK) == A_LVAL) {
665 cmd->c_stab = arg[flp].arg_ptr.arg_stab;
667 arg[flp].arg_ptr.arg_stab = Nullstab;
670 if (!context) { /* no && or ||? */
672 cmd->c_expr = Nullarg;
675 cmd->c_flags |= CF_EQSURE;
677 cmd->c_flags |= CF_NESURE;
680 else if (arg->arg_type == O_MATCH || arg->arg_type == O_SUBST ||
681 arg->arg_type == O_NMATCH || arg->arg_type == O_NSUBST) {
682 if ((arg[1].arg_type == A_STAB || arg[1].arg_type == A_LVAL) &&
683 (arg[2].arg_type & A_MASK) == A_SPAT &&
684 arg[2].arg_ptr.arg_spat->spat_short &&
685 (arg->arg_type == O_SUBST || arg->arg_type == O_NSUBST ||
686 (arg[2].arg_ptr.arg_spat->spat_flags & SPAT_GLOBAL) == 0 )) {
687 cmd->c_stab = arg[1].arg_ptr.arg_stab;
688 cmd->c_short = str_smake(arg[2].arg_ptr.arg_spat->spat_short);
689 cmd->c_slen = arg[2].arg_ptr.arg_spat->spat_slen;
690 if (arg[2].arg_ptr.arg_spat->spat_flags & SPAT_ALL &&
691 !(arg[2].arg_ptr.arg_spat->spat_flags & SPAT_ONCE) &&
692 (arg->arg_type == O_MATCH || arg->arg_type == O_NMATCH) )
693 sure |= CF_EQSURE; /* (SUBST must be forced even */
694 /* if we know it will work.) */
695 if (arg->arg_type != O_SUBST) {
696 arg[2].arg_ptr.arg_spat->spat_short = Nullstr;
697 arg[2].arg_ptr.arg_spat->spat_slen = 0; /* only one chk */
699 sure |= CF_NESURE; /* normally only sure if it fails */
700 if (arg->arg_type == O_NMATCH || arg->arg_type == O_NSUBST)
701 cmd->c_flags |= CF_FIRSTNEG;
702 if (context & 1) { /* only sure if thing is false */
703 if (cmd->c_flags & CF_FIRSTNEG)
708 else if (context & 2) { /* only sure if thing is true */
709 if (cmd->c_flags & CF_FIRSTNEG)
714 if (sure & (CF_EQSURE|CF_NESURE)) { /* if we know anything*/
715 if (arg[2].arg_ptr.arg_spat->spat_flags & SPAT_SCANFIRST)
719 if (sure == (CF_EQSURE|CF_NESURE) /* really sure? */
720 && arg->arg_type == O_MATCH
722 && fliporflop == 1) {
723 spat_free(arg[2].arg_ptr.arg_spat);
724 arg[2].arg_ptr.arg_spat = Nullspat; /* don't do twice */
727 cmd->c_spat = arg[2].arg_ptr.arg_spat;
728 cmd->c_flags |= sure;
732 else if (arg->arg_type == O_SEQ || arg->arg_type == O_SNE ||
733 arg->arg_type == O_SLT || arg->arg_type == O_SGT) {
734 if (arg[1].arg_type == A_STAB || arg[1].arg_type == A_LVAL) {
735 if (arg[2].arg_type == A_SINGLE) {
737 char *junk = str_get(arg[2].arg_ptr.arg_str);
739 cmd->c_stab = arg[1].arg_ptr.arg_stab;
740 cmd->c_short = str_smake(arg[2].arg_ptr.arg_str);
741 cmd->c_slen = cmd->c_short->str_cur+1;
742 switch (arg->arg_type) {
743 case O_SLT: case O_SGT:
745 cmd->c_flags |= CF_FIRSTNEG;
748 cmd->c_flags |= CF_FIRSTNEG;
751 sure |= CF_NESURE|CF_EQSURE;
754 if (context & 1) { /* only sure if thing is false */
755 if (cmd->c_flags & CF_FIRSTNEG)
760 else if (context & 2) { /* only sure if thing is true */
761 if (cmd->c_flags & CF_FIRSTNEG)
766 if (sure & (CF_EQSURE|CF_NESURE)) {
768 cmd->c_flags |= sure;
773 else if (arg->arg_type == O_EQ || arg->arg_type == O_NE ||
774 arg->arg_type == O_LE || arg->arg_type == O_GE ||
775 arg->arg_type == O_LT || arg->arg_type == O_GT) {
776 if (arg[1].arg_type == A_STAB || arg[1].arg_type == A_LVAL) {
777 if (arg[2].arg_type == A_SINGLE) {
778 cmd->c_stab = arg[1].arg_ptr.arg_stab;
780 STR *str = arg[2].arg_ptr.arg_str;
782 if ((!str->str_nok && !looks_like_number(str)))
783 warn("Possible use of == on string value");
785 cmd->c_short = str_nmake(str_gnum(arg[2].arg_ptr.arg_str));
786 cmd->c_slen = arg->arg_type;
787 sure |= CF_NESURE|CF_EQSURE;
788 if (context & 1) { /* only sure if thing is false */
791 else if (context & 2) { /* only sure if thing is true */
794 if (sure & (CF_EQSURE|CF_NESURE)) {
796 cmd->c_flags |= sure;
801 else if (arg->arg_type == O_ASSIGN &&
802 (arg[1].arg_type == A_STAB || arg[1].arg_type == A_LVAL) &&
803 arg[1].arg_ptr.arg_stab == defstab &&
804 arg[2].arg_type == A_EXPR ) {
805 arg2 = arg[2].arg_ptr.arg_arg;
806 if (arg2->arg_type == O_ITEM && arg2[1].arg_type == A_READ) {
808 cmd->c_stab = arg2[1].arg_ptr.arg_stab;
809 if (!(stab_io(arg2[1].arg_ptr.arg_stab)->flags & IOF_ARGV)) {
811 arg[2].arg_ptr.arg_arg = Nullarg;
813 cmd->c_expr = Nullarg;
817 else if (arg->arg_type == O_CHOP &&
818 (arg[1].arg_type == A_STAB || arg[1].arg_type == A_LVAL) ) {
820 cmd->c_stab = arg[1].arg_ptr.arg_stab;
822 cmd->c_expr = Nullarg;
828 if (cmd->c_flags & CF_FLIP) {
829 if (fliporflop == 1) {
830 arg = cmd->c_expr; /* get back to O_FLIP arg */
831 New(110,arg[3].arg_ptr.arg_cmd, 1, CMD);
832 Copy(cmd, arg[3].arg_ptr.arg_cmd, 1, CMD);
833 New(111,arg[4].arg_ptr.arg_cmd,1,CMD);
834 Copy(cmd, arg[4].arg_ptr.arg_cmd, 1, CMD);
835 opt_arg(arg[4].arg_ptr.arg_cmd,2,acmd);
836 arg->arg_len = 2; /* this is a lie */
839 if ((opt & CF_OPTIMIZE) == CFT_EVAL)
840 cmd->c_flags = (cmd->c_flags & ~CF_OPTIMIZE) | CFT_UNFLIP;
861 cmd->c_flags |= CF_COND;
873 cmd->c_flags |= CF_COND|CF_LOOP;
875 if (!(cmd->c_flags & CF_INVERT))
876 while_io(cmd); /* add $_ =, if necessary */
878 if (cmd->c_type == C_BLOCK)
879 cmd->c_flags &= ~CF_COND;
881 arg = cmd->ucmd.acmd.ac_expr;
882 if (arg && arg->arg_type == O_ITEM && arg[1].arg_type == A_CMD)
883 cmd->c_flags &= ~CF_COND; /* "do {} while" happens at least once */
884 if (arg && (arg->arg_flags & AF_DEPR) &&
885 (arg->arg_type == O_SUBR || arg->arg_type == O_DBSUBR) )
886 cmd->c_flags &= ~CF_COND; /* likewise for "do subr() while" */
895 register CMD *targ = cmd;
898 if (targ->c_flags & CF_DBSUB)
900 targ->c_flags ^= CF_INVERT;
909 char *tname = tmpbuf;
911 if (bufptr > oldoldbufptr && bufptr - oldoldbufptr < 200 &&
912 oldoldbufptr != oldbufptr && oldbufptr != bufptr) {
913 while (isSPACE(*oldoldbufptr))
915 strncpy(tmp2buf, oldoldbufptr, bufptr - oldoldbufptr);
916 tmp2buf[bufptr - oldoldbufptr] = '\0';
917 sprintf(tname,"next 2 tokens \"%s\"",tmp2buf);
919 else if (bufptr > oldbufptr && bufptr - oldbufptr < 200 &&
920 oldbufptr != bufptr) {
921 while (isSPACE(*oldbufptr))
923 strncpy(tmp2buf, oldbufptr, bufptr - oldbufptr);
924 tmp2buf[bufptr - oldbufptr] = '\0';
925 sprintf(tname,"next token \"%s\"",tmp2buf);
927 else if (yychar > 256)
928 tname = "next token ???";
930 (void)strcpy(tname,"at EOF");
931 else if (yychar < 32)
932 (void)sprintf(tname,"next char ^%c",yychar+64);
933 else if (yychar == 127)
934 (void)strcpy(tname,"at EOF");
936 (void)sprintf(tname,"next char %c",yychar);
937 (void)sprintf(buf, "%s in file %s at line %d, %s\n",
938 s,stab_val(curcmd->c_filestab)->str_ptr,curcmd->c_line,tname);
939 if (curcmd->c_line == multi_end && multi_start < multi_end)
940 sprintf(buf+strlen(buf),
941 " (Might be a runaway multi-line %c%c string starting on line %d)\n",
942 multi_open,multi_close,multi_start);
944 str_cat(stab_val(stabent("@",TRUE)),buf);
947 if (++error_count >= 10)
948 fatal("%s has too many errors.\n",
949 stab_val(curcmd->c_filestab)->str_ptr);
956 register ARG *arg = cmd->c_expr;
959 /* hoist "while (<channel>)" up into command block */
961 if (arg && arg->arg_type == O_ITEM && arg[1].arg_type == A_READ) {
962 cmd->c_flags &= ~CF_OPTIMIZE; /* clear optimization type */
963 cmd->c_flags |= CFT_GETS; /* and set it to do the input */
964 cmd->c_stab = arg[1].arg_ptr.arg_stab;
965 if (stab_io(arg[1].arg_ptr.arg_stab)->flags & IOF_ARGV) {
966 cmd->c_expr = l(make_op(O_ASSIGN, 2, /* fake up "$_ =" */
967 stab2arg(A_LVAL,defstab), arg, Nullarg));
971 cmd->c_expr = Nullarg;
974 else if (arg && arg->arg_type == O_ITEM && arg[1].arg_type == A_INDREAD) {
975 cmd->c_flags &= ~CF_OPTIMIZE; /* clear optimization type */
976 cmd->c_flags |= CFT_INDGETS; /* and set it to do the input */
977 cmd->c_stab = arg[1].arg_ptr.arg_stab;
979 cmd->c_expr = Nullarg;
981 else if (arg && arg->arg_type == O_ITEM && arg[1].arg_type == A_GLOB) {
982 if ((cmd->c_flags & CF_OPTIMIZE) == CFT_ARRAY)
983 asgnstab = cmd->c_stab;
986 cmd->c_expr = l(make_op(O_ASSIGN, 2, /* fake up "$foo =" */
987 stab2arg(A_LVAL,asgnstab), arg, Nullarg));
988 cmd->c_flags &= ~CF_OPTIMIZE; /* clear optimization type */
1000 if (cmd->c_expr && (cmd->c_flags & CF_OPTIMIZE) == CFT_FALSE)
1001 opt_arg(cmd,1, cmd->c_type == C_EXPR);
1003 while_io(cmd); /* add $_ =, if necessary */
1005 /* First find the end of the true list */
1007 tail = cmd->ucmd.ccmd.cc_true;
1008 if (tail == Nullcmd)
1010 New(112,newtail, 1, CMD); /* guaranteed continue */
1012 /* optimize "next" to point directly to continue block */
1013 if (tail->c_type == C_EXPR &&
1014 tail->ucmd.acmd.ac_expr &&
1015 tail->ucmd.acmd.ac_expr->arg_type == O_NEXT &&
1016 (tail->ucmd.acmd.ac_expr->arg_len == 0 ||
1019 tail->ucmd.acmd.ac_expr[1].arg_ptr.arg_str->str_ptr) )))
1021 arg_free(tail->ucmd.acmd.ac_expr);
1022 tail->ucmd.acmd.ac_expr = Nullarg;
1023 tail->c_type = C_NEXT;
1024 if (cmd->ucmd.ccmd.cc_alt != Nullcmd)
1025 tail->ucmd.ccmd.cc_alt = cmd->ucmd.ccmd.cc_alt;
1027 tail->ucmd.ccmd.cc_alt = newtail;
1028 tail->ucmd.ccmd.cc_true = Nullcmd;
1030 else if (tail->c_type == C_IF && !tail->ucmd.ccmd.cc_alt) {
1031 if (cmd->ucmd.ccmd.cc_alt != Nullcmd)
1032 tail->ucmd.ccmd.cc_alt = cmd->ucmd.ccmd.cc_alt;
1034 tail->ucmd.ccmd.cc_alt = newtail;
1036 else if (tail->c_type == C_CSWITCH || tail->c_type == C_NSWITCH) {
1037 if (cmd->ucmd.ccmd.cc_alt != Nullcmd) {
1038 for (i = tail->ucmd.scmd.sc_max; i >= 0; i--)
1039 if (!tail->ucmd.scmd.sc_next[i])
1040 tail->ucmd.scmd.sc_next[i] = cmd->ucmd.ccmd.cc_alt;
1043 for (i = tail->ucmd.scmd.sc_max; i >= 0; i--)
1044 if (!tail->ucmd.scmd.sc_next[i])
1045 tail->ucmd.scmd.sc_next[i] = newtail;
1051 tail = tail->c_next;
1054 /* if there's a continue block, link it to true block and find end */
1056 if (cmd->ucmd.ccmd.cc_alt != Nullcmd) {
1057 tail->c_next = cmd->ucmd.ccmd.cc_alt;
1058 tail = tail->c_next;
1060 /* optimize "next" to point directly to continue block */
1061 if (tail->c_type == C_EXPR &&
1062 tail->ucmd.acmd.ac_expr &&
1063 tail->ucmd.acmd.ac_expr->arg_type == O_NEXT &&
1064 (tail->ucmd.acmd.ac_expr->arg_len == 0 ||
1067 tail->ucmd.acmd.ac_expr[1].arg_ptr.arg_str->str_ptr) )))
1069 arg_free(tail->ucmd.acmd.ac_expr);
1070 tail->ucmd.acmd.ac_expr = Nullarg;
1071 tail->c_type = C_NEXT;
1072 tail->ucmd.ccmd.cc_alt = newtail;
1073 tail->ucmd.ccmd.cc_true = Nullcmd;
1075 else if (tail->c_type == C_IF && !tail->ucmd.ccmd.cc_alt) {
1076 tail->ucmd.ccmd.cc_alt = newtail;
1078 else if (tail->c_type == C_CSWITCH || tail->c_type == C_NSWITCH) {
1079 for (i = tail->ucmd.scmd.sc_max; i >= 0; i--)
1080 if (!tail->ucmd.scmd.sc_next[i])
1081 tail->ucmd.scmd.sc_next[i] = newtail;
1086 tail = tail->c_next;
1089 for ( ; tail->c_next; tail = tail->c_next) ;
1092 /* Here's the real trick: link the end of the list back to the beginning,
1093 * inserting a "last" block to break out of the loop. This saves one or
1094 * two procedure calls every time through the loop, because of how cmd_exec
1095 * does tail recursion.
1098 tail->c_next = newtail;
1100 if (!cmd->ucmd.ccmd.cc_alt)
1101 cmd->ucmd.ccmd.cc_alt = tail; /* every loop has a continue now */
1104 (void)bcopy((char *)cmd, (char *)tail, sizeof(CMD));
1106 tail->c_type = C_EXPR;
1107 tail->c_flags ^= CF_INVERT; /* turn into "last unless" */
1108 tail->c_next = tail->ucmd.ccmd.cc_true; /* loop directly back to top */
1109 tail->ucmd.acmd.ac_expr = make_op(O_LAST,0,Nullarg,Nullarg,Nullarg);
1110 tail->ucmd.acmd.ac_stab = Nullstab;
1119 /* hoist "for $foo (@bar)" up into command block */
1121 cmd->c_flags &= ~CF_OPTIMIZE; /* clear optimization type */
1122 cmd->c_flags |= CFT_ARRAY; /* and set it to do the iteration */
1123 cmd->c_stab = eachstab;
1124 cmd->c_short = Str_new(23,0); /* just to save a field in struct cmd */
1125 cmd->c_short->str_u.str_useful = -1;
1133 register CMD *tofree;
1134 register CMD *head = cmd;
1137 if (cmd->c_type != C_WHILE) { /* WHILE block is duplicated */
1139 Safefree(cmd->c_label);
1140 cmd->c_label = Nullch;
1143 str_free(cmd->c_short);
1144 cmd->c_short = Nullstr;
1147 arg_free(cmd->c_expr);
1148 cmd->c_expr = Nullarg;
1151 switch (cmd->c_type) {
1156 if (cmd->ucmd.ccmd.cc_true) {
1157 cmd_free(cmd->ucmd.ccmd.cc_true);
1158 cmd->ucmd.ccmd.cc_true = Nullcmd;
1162 if (cmd->ucmd.acmd.ac_expr) {
1163 arg_free(cmd->ucmd.acmd.ac_expr);
1164 cmd->ucmd.acmd.ac_expr = Nullarg;
1170 if (tofree != head) /* to get Saber to shut up */
1172 if (cmd && cmd == head) /* reached end of while loop */
1183 for (i = 1; i <= arg->arg_len; i++) {
1184 switch (arg[i].arg_type & A_MASK) {
1186 if (arg->arg_type == O_TRANS) {
1187 Safefree(arg[i].arg_ptr.arg_cval);
1188 arg[i].arg_ptr.arg_cval = Nullch;
1192 if (arg->arg_type == O_AASSIGN &&
1193 arg[i].arg_ptr.arg_arg->arg_type == O_LARRAY) {
1195 stab_name(arg[i].arg_ptr.arg_arg[1].arg_ptr.arg_stab);
1197 if (strnEQ("_GEN_",name, 5)) /* array for foreach */
1198 hdelete(defstash,name,strlen(name));
1202 arg_free(arg[i].arg_ptr.arg_arg);
1203 arg[i].arg_ptr.arg_arg = Nullarg;
1206 cmd_free(arg[i].arg_ptr.arg_cmd);
1207 arg[i].arg_ptr.arg_cmd = Nullcmd;
1222 str_free(arg[i].arg_ptr.arg_str);
1223 arg[i].arg_ptr.arg_str = Nullstr;
1226 spat_free(arg[i].arg_ptr.arg_spat);
1227 arg[i].arg_ptr.arg_spat = Nullspat;
1235 register SPAT *spat;
1240 if (spat->spat_runtime) {
1241 arg_free(spat->spat_runtime);
1242 spat->spat_runtime = Nullarg;
1244 if (spat->spat_repl) {
1245 arg_free(spat->spat_repl);
1246 spat->spat_repl = Nullarg;
1248 if (spat->spat_short) {
1249 str_free(spat->spat_short);
1250 spat->spat_short = Nullstr;
1252 if (spat->spat_regexp) {
1253 regfree(spat->spat_regexp);
1254 spat->spat_regexp = Null(REGEXP*);
1257 /* now unlink from spat list */
1259 for (entry = defstash->tbl_array['_']; entry; entry = entry->hent_next) {
1260 register HASH *stash;
1261 STAB *stab = (STAB*)entry->hent_val;
1265 stash = stab_hash(stab);
1266 if (!stash || stash->tbl_spatroot == Null(SPAT*))
1268 if (stash->tbl_spatroot == spat)
1269 stash->tbl_spatroot = spat->spat_next;
1271 for (sp = stash->tbl_spatroot;
1272 sp && sp->spat_next != spat;
1277 sp->spat_next = spat->spat_next;
1283 /* Recursively descend a command sequence and push the address of any string
1284 * that needs saving on recursion onto the tosave array.
1288 cmd_tosave(cmd,willsave)
1290 int willsave; /* willsave passes down the tree */
1292 register CMD *head = cmd;
1293 int shouldsave = FALSE; /* shouldsave passes up the tree */
1295 register CMD *lastcmd = Nullcmd;
1299 shouldsave |= arg_tosave(cmd->c_expr,willsave);
1300 switch (cmd->c_type) {
1302 if (cmd->ucmd.ccmd.cc_true) {
1303 tmpsave = cmd_tosave(cmd->ucmd.ccmd.cc_true,willsave);
1305 /* Here we check to see if the temporary array generated for
1306 * a foreach needs to be localized because of recursion.
1308 if (tmpsave && (cmd->c_flags & CF_OPTIMIZE) == CFT_ARRAY) {
1310 lastcmd->c_type == C_EXPR &&
1312 ARG *arg = lastcmd->c_expr;
1314 if (arg->arg_type == O_ASSIGN &&
1315 arg[1].arg_type == A_LEXPR &&
1316 arg[1].arg_ptr.arg_arg->arg_type == O_LARRAY &&
1319 arg[1].arg_ptr.arg_arg[1].arg_ptr.arg_stab),
1320 5)) { /* array generated for foreach */
1321 (void)localize(arg);
1325 /* in any event, save the iterator */
1327 (void)apush(tosave,cmd->c_short);
1329 shouldsave |= tmpsave;
1335 if (cmd->ucmd.ccmd.cc_true)
1336 shouldsave |= cmd_tosave(cmd->ucmd.ccmd.cc_true,willsave);
1339 if (cmd->ucmd.acmd.ac_expr)
1340 shouldsave |= arg_tosave(cmd->ucmd.acmd.ac_expr,willsave);
1345 if (cmd && cmd == head) /* reached end of while loop */
1352 arg_tosave(arg,willsave)
1357 int shouldsave = FALSE;
1359 for (i = arg->arg_len; i >= 1; i--) {
1360 switch (arg[i].arg_type & A_MASK) {
1365 shouldsave |= arg_tosave(arg[i].arg_ptr.arg_arg,shouldsave);
1368 shouldsave |= cmd_tosave(arg[i].arg_ptr.arg_cmd,shouldsave);
1381 shouldsave |= spat_tosave(arg[i].arg_ptr.arg_spat);
1385 switch (arg->arg_type) {
1395 (void)apush(tosave,arg->arg_ptr.arg_str);
1401 register SPAT *spat;
1403 int shouldsave = FALSE;
1405 if (spat->spat_runtime)
1406 shouldsave |= arg_tosave(spat->spat_runtime,FALSE);
1407 if (spat->spat_repl) {
1408 shouldsave |= arg_tosave(spat->spat_repl,FALSE);