source: trunk/third/perl/cons.c @ 9009

Revision 9009, 35.5 KB checked in by ghudson, 28 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r9008, which included commits to RCS files with non-trunk default branches.
Line 
1/* $RCSfile: cons.c,v $$Revision: 1.1.1.1 $$Date: 1996-10-02 06:39:56 $
2 *
3 *    Copyright (c) 1991, Larry Wall
4 *
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.
7 *
8 * $Log: not supported by cvs2svn $
9 * Revision 4.0.1.4  1993/02/05  19:30:15  lwall
10 * patch36: fixed various little coredump bugs
11 *
12 * Revision 4.0.1.3  92/06/08  12:18:35  lwall
13 * patch20: removed implicit int declarations on funcions
14 * patch20: deleted some minor memory leaks
15 * patch20: fixed double debug break in foreach with implicit array assignment
16 * patch20: fixed confusion between a *var's real name and its effective name
17 * patch20: Perl now distinguishes overlapped copies from non-overlapped
18 * patch20: debugger sometimes displayed wrong source line
19 * patch20: various error messages have been clarified
20 * patch20: an eval block containing a null block or statement could dump core
21 *
22 * Revision 4.0.1.2  91/11/05  16:15:13  lwall
23 * patch11: debugger got confused over nested subroutine definitions
24 * patch11: prepared for ctype implementations that don't define isascii()
25 *
26 * Revision 4.0.1.1  91/06/07  10:31:15  lwall
27 * patch4: new copyright notice
28 * patch4: added global modifier for pattern matches
29 *
30 * Revision 4.0  91/03/20  01:05:51  lwall
31 * 4.0 baseline.
32 *
33 */
34
35#include "EXTERN.h"
36#include "perl.h"
37#include "perly.h"
38
39extern char *tokename[];
40extern int yychar;
41
42static int cmd_tosave();
43static int arg_tosave();
44static int spat_tosave();
45static void make_cswitch();
46static void make_nswitch();
47
48static bool saw_return;
49
50SUBR *
51make_sub(name,cmd)
52char *name;
53CMD *cmd;
54{
55    register SUBR *sub;
56    STAB *stab = stabent(name,TRUE);
57
58    if (sub = stab_sub(stab)) {
59        if (dowarn) {
60            CMD *oldcurcmd = curcmd;
61
62            if (cmd)
63                curcmd = cmd;
64            warn("Subroutine %s redefined",name);
65            curcmd = oldcurcmd;
66        }
67        if (!sub->usersub && sub->cmd) {
68            cmd_free(sub->cmd);
69            sub->cmd = Nullcmd;
70            afree(sub->tosave);
71        }
72        Safefree(sub);
73    }
74    Newz(101,sub,1,SUBR);
75    stab_sub(stab) = sub;
76    sub->filestab = curcmd->c_filestab;
77    saw_return = FALSE;
78    tosave = anew(Nullstab);
79    tosave->ary_fill = 0;       /* make 1 based */
80    (void)cmd_tosave(cmd,FALSE);        /* this builds the tosave array */
81    sub->tosave = tosave;
82    if (saw_return) {
83        struct compcmd mycompblock;
84
85        mycompblock.comp_true = cmd;
86        mycompblock.comp_alt = Nullcmd;
87        cmd = add_label(savestr("_SUB_"),make_ccmd(C_BLOCK,0,
88            Nullarg,mycompblock));
89        saw_return = FALSE;
90        cmd->c_flags |= CF_TERM;
91        cmd->c_head = cmd;
92    }
93    sub->cmd = cmd;
94    if (perldb) {
95        STR *str;
96        STR *tmpstr = str_mortal(&str_undef);
97
98        sprintf(buf,"%s:%ld",stab_val(curcmd->c_filestab)->str_ptr, subline);
99        str = str_make(buf,0);
100        str_cat(str,"-");
101        sprintf(buf,"%ld",(long)curcmd->c_line);
102        str_cat(str,buf);
103        stab_efullname(tmpstr,stab);
104        hstore(stab_xhash(DBsub), tmpstr->str_ptr, tmpstr->str_cur, str, 0);
105    }
106    Safefree(name);
107    return sub;
108}
109
110SUBR *
111make_usub(name, ix, subaddr, filename)
112char *name;
113int ix;
114int (*subaddr)();
115char *filename;
116{
117    register SUBR *sub;
118    STAB *stab = stabent(name,allstabs);
119
120    if (!stab)                          /* unused function */
121        return Null(SUBR*);
122    if (sub = stab_sub(stab)) {
123        if (dowarn)
124            warn("Subroutine %s redefined",name);
125        if (!sub->usersub && sub->cmd) {
126            cmd_free(sub->cmd);
127            sub->cmd = Nullcmd;
128            afree(sub->tosave);
129        }
130        Safefree(sub);
131    }
132    Newz(101,sub,1,SUBR);
133    stab_sub(stab) = sub;
134    sub->filestab = fstab(filename);
135    sub->usersub = subaddr;
136    sub->userindex = ix;
137    return sub;
138}
139
140void
141make_form(stab,fcmd)
142STAB *stab;
143FCMD *fcmd;
144{
145    if (stab_form(stab)) {
146        FCMD *tmpfcmd;
147        FCMD *nextfcmd;
148
149        for (tmpfcmd = stab_form(stab); tmpfcmd; tmpfcmd = nextfcmd) {
150            nextfcmd = tmpfcmd->f_next;
151            if (tmpfcmd->f_expr)
152                arg_free(tmpfcmd->f_expr);
153            if (tmpfcmd->f_unparsed)
154                str_free(tmpfcmd->f_unparsed);
155            if (tmpfcmd->f_pre)
156                Safefree(tmpfcmd->f_pre);
157            Safefree(tmpfcmd);
158        }
159    }
160    stab_form(stab) = fcmd;
161}
162
163CMD *
164block_head(tail)
165register CMD *tail;
166{
167    CMD *head;
168    register int opt;
169    register int last_opt = 0;
170    register STAB *last_stab = Nullstab;
171    register int count = 0;
172    register CMD *switchbeg = Nullcmd;
173
174    if (tail == Nullcmd) {
175        return tail;
176    }
177    head = tail->c_head;
178
179    for (tail = head; tail; tail = tail->c_next) {
180
181        /* save one measly dereference at runtime */
182        if (tail->c_type == C_IF) {
183            if (!(tail->ucmd.ccmd.cc_alt = tail->ucmd.ccmd.cc_alt->c_next))
184                tail->c_flags |= CF_TERM;
185        }
186        else if (tail->c_type == C_EXPR) {
187            ARG *arg;
188
189            if (tail->ucmd.acmd.ac_expr)
190                arg = tail->ucmd.acmd.ac_expr;
191            else
192                arg = tail->c_expr;
193            if (arg) {
194                if (arg->arg_type == O_RETURN)
195                    tail->c_flags |= CF_TERM;
196                else if (arg->arg_type == O_ITEM && arg[1].arg_type == A_CMD)
197                    tail->c_flags |= CF_TERM;
198            }
199        }
200        if (!tail->c_next)
201            tail->c_flags |= CF_TERM;
202
203        if (tail->c_expr && (tail->c_flags & CF_OPTIMIZE) == CFT_FALSE)
204            opt_arg(tail,1, tail->c_type == C_EXPR);
205
206        /* now do a little optimization on case-ish structures */
207        switch(tail->c_flags & (CF_OPTIMIZE|CF_FIRSTNEG|CF_INVERT)) {
208        case CFT_ANCHOR:
209        case CFT_STROP:
210            opt = (tail->c_flags & CF_NESURE) ? CFT_STROP : 0;
211            break;
212        case CFT_CCLASS:
213            opt = CFT_STROP;
214            break;
215        case CFT_NUMOP:
216            opt = (tail->c_slen == O_NE ? 0 : CFT_NUMOP);
217            if ((tail->c_flags&(CF_NESURE|CF_EQSURE)) != (CF_NESURE|CF_EQSURE))
218                opt = 0;
219            break;
220        default:
221            opt = 0;
222        }
223        if (opt && opt == last_opt && tail->c_stab == last_stab)
224            count++;
225        else {
226            if (count >= 3) {           /* is this the breakeven point? */
227                if (last_opt == CFT_NUMOP)
228                    make_nswitch(switchbeg,count);
229                else
230                    make_cswitch(switchbeg,count);
231            }
232            if (opt) {
233                count = 1;
234                switchbeg = tail;
235            }
236            else
237                count = 0;
238        }
239        last_opt = opt;
240        last_stab = tail->c_stab;
241    }
242    if (count >= 3) {           /* is this the breakeven point? */
243        if (last_opt == CFT_NUMOP)
244            make_nswitch(switchbeg,count);
245        else
246            make_cswitch(switchbeg,count);
247    }
248    return head;
249}
250
251/* We've spotted a sequence of CMDs that all test the value of the same
252 * spat.  Thus we can insert a SWITCH in front and jump directly
253 * to the correct one.
254 */
255static void
256make_cswitch(head,count)
257register CMD *head;
258int count;
259{
260    register CMD *cur;
261    register CMD **loc;
262    register int i;
263    register int min = 255;
264    register int max = 0;
265
266    /* make a new head in the exact same spot */
267    New(102,cur, 1, CMD);
268    StructCopy(head,cur,CMD);
269    Zero(head,1,CMD);
270    head->c_head = cur->c_head;
271    head->c_type = C_CSWITCH;
272    head->c_next = cur;         /* insert new cmd at front of list */
273    head->c_stab = cur->c_stab;
274
275    Newz(103,loc,258,CMD*);
276    loc++;                              /* lie a little */
277    while (count--) {
278        if ((cur->c_flags & CF_OPTIMIZE) == CFT_CCLASS) {
279            for (i = 0; i <= 255; i++) {
280                if (!loc[i] && cur->c_short->str_ptr[i>>3] & (1 << (i&7))) {
281                    loc[i] = cur;
282                    if (i < min)
283                        min = i;
284                    if (i > max)
285                        max = i;
286                }
287            }
288        }
289        else {
290            i = *cur->c_short->str_ptr & 255;
291            if (!loc[i]) {
292                loc[i] = cur;
293                if (i < min)
294                    min = i;
295                if (i > max)
296                    max = i;
297            }
298        }
299        cur = cur->c_next;
300    }
301    max++;
302    if (min > 0)
303        Move(&loc[min],&loc[0], max - min, CMD*);
304    loc--;
305    min--;
306    max -= min;
307    for (i = 0; i <= max; i++)
308        if (!loc[i])
309            loc[i] = cur;
310    Renew(loc,max+1,CMD*);      /* chop it down to size */
311    head->ucmd.scmd.sc_offset = min;
312    head->ucmd.scmd.sc_max = max;
313    head->ucmd.scmd.sc_next = loc;
314}
315
316static void
317make_nswitch(head,count)
318register CMD *head;
319int count;
320{
321    register CMD *cur = head;
322    register CMD **loc;
323    register int i;
324    register int min = 32767;
325    register int max = -32768;
326    int origcount = count;
327    double value;               /* or your money back! */
328    short changed;              /* so triple your money back! */
329
330    while (count--) {
331        i = (int)str_gnum(cur->c_short);
332        value = (double)i;
333        if (value != cur->c_short->str_u.str_nval)
334            return;             /* fractional values--just forget it */
335        changed = i;
336        if (changed != i)
337            return;             /* too big for a short */
338        if (cur->c_slen == O_LE)
339            i++;
340        else if (cur->c_slen == O_GE)   /* we only do < or > here */
341            i--;
342        if (i < min)
343            min = i;
344        if (i > max)
345            max = i;
346        cur = cur->c_next;
347    }
348    count = origcount;
349    if (max - min > count * 2 + 10)             /* too sparse? */
350        return;
351
352    /* now make a new head in the exact same spot */
353    New(104,cur, 1, CMD);
354    StructCopy(head,cur,CMD);
355    Zero(head,1,CMD);
356    head->c_head = cur->c_head;
357    head->c_type = C_NSWITCH;
358    head->c_next = cur;         /* insert new cmd at front of list */
359    head->c_stab = cur->c_stab;
360
361    Newz(105,loc, max - min + 3, CMD*);
362    loc++;
363    max -= min;
364    max++;
365    while (count--) {
366        i = (int)str_gnum(cur->c_short);
367        i -= min;
368        switch(cur->c_slen) {
369        case O_LE:
370            i++;
371        case O_LT:
372            for (i--; i >= -1; i--)
373                if (!loc[i])
374                    loc[i] = cur;
375            break;
376        case O_GE:
377            i--;
378        case O_GT:
379            for (i++; i <= max; i++)
380                if (!loc[i])
381                    loc[i] = cur;
382            break;
383        case O_EQ:
384            if (!loc[i])
385                loc[i] = cur;
386            break;
387        }
388        cur = cur->c_next;
389    }
390    loc--;
391    min--;
392    max++;
393    for (i = 0; i <= max; i++)
394        if (!loc[i])
395            loc[i] = cur;
396    head->ucmd.scmd.sc_offset = min;
397    head->ucmd.scmd.sc_max = max;
398    head->ucmd.scmd.sc_next = loc;
399}
400
401CMD *
402append_line(head,tail)
403register CMD *head;
404register CMD *tail;
405{
406    if (tail == Nullcmd)
407        return head;
408    if (!tail->c_head)                  /* make sure tail is well formed */
409        tail->c_head = tail;
410    if (head != Nullcmd) {
411        tail = tail->c_head;            /* get to start of tail list */
412        if (!head->c_head)
413            head->c_head = head;        /* start a new head list */
414        while (head->c_next) {
415            head->c_next->c_head = head->c_head;
416            head = head->c_next;        /* get to end of head list */
417        }
418        head->c_next = tail;            /* link to end of old list */
419        tail->c_head = head->c_head;    /* propagate head pointer */
420    }
421    while (tail->c_next) {
422        tail->c_next->c_head = tail->c_head;
423        tail = tail->c_next;
424    }
425    return tail;
426}
427
428CMD *
429dodb(cur)
430CMD *cur;
431{
432    register CMD *cmd;
433    register CMD *head = cur->c_head;
434    STR *str;
435
436    if (!head)
437        head = cur;
438    if (!head->c_line)
439        return cur;
440    str = afetch(stab_xarray(curcmd->c_filestab),(int)head->c_line,FALSE);
441    if (str == &str_undef || str->str_nok)
442        return cur;
443    str->str_u.str_nval = (double)head->c_line;
444    str->str_nok = 1;
445    Newz(106,cmd,1,CMD);
446    str_magic(str, curcmd->c_filestab, 0, Nullch, 0);
447    str->str_magic->str_u.str_cmd = cmd;
448    cmd->c_type = C_EXPR;
449    cmd->ucmd.acmd.ac_stab = Nullstab;
450    cmd->ucmd.acmd.ac_expr = Nullarg;
451    cmd->c_expr = make_op(O_SUBR, 2,
452        stab2arg(A_WORD,DBstab),
453        Nullarg,
454        Nullarg);
455    /*SUPPRESS 53*/
456    cmd->c_flags |= CF_COND|CF_DBSUB|CFT_D0;
457    cmd->c_line = head->c_line;
458    cmd->c_label = head->c_label;
459    cmd->c_filestab = curcmd->c_filestab;
460    cmd->c_stash = curstash;
461    return append_line(cmd, cur);
462}
463
464CMD *
465make_acmd(type,stab,cond,arg)
466int type;
467STAB *stab;
468ARG *cond;
469ARG *arg;
470{
471    register CMD *cmd;
472
473    Newz(107,cmd,1,CMD);
474    cmd->c_type = type;
475    cmd->ucmd.acmd.ac_stab = stab;
476    cmd->ucmd.acmd.ac_expr = arg;
477    cmd->c_expr = cond;
478    if (cond)
479        cmd->c_flags |= CF_COND;
480    if (cmdline == NOLINE)
481        cmd->c_line = curcmd->c_line;
482    else {
483        cmd->c_line = cmdline;
484        cmdline = NOLINE;
485    }
486    cmd->c_filestab = curcmd->c_filestab;
487    cmd->c_stash = curstash;
488    if (perldb)
489        cmd = dodb(cmd);
490    return cmd;
491}
492
493CMD *
494make_ccmd(type,debuggable,arg,cblock)
495int type;
496int debuggable;
497ARG *arg;
498struct compcmd cblock;
499{
500    register CMD *cmd;
501
502    Newz(108,cmd, 1, CMD);
503    cmd->c_type = type;
504    cmd->c_expr = arg;
505    cmd->ucmd.ccmd.cc_true = cblock.comp_true;
506    cmd->ucmd.ccmd.cc_alt = cblock.comp_alt;
507    if (arg)
508        cmd->c_flags |= CF_COND;
509    if (cmdline == NOLINE)
510        cmd->c_line = curcmd->c_line;
511    else {
512        cmd->c_line = cmdline;
513        cmdline = NOLINE;
514    }
515    cmd->c_filestab = curcmd->c_filestab;
516    cmd->c_stash = curstash;
517    if (perldb && debuggable)
518        cmd = dodb(cmd);
519    return cmd;
520}
521
522CMD *
523make_icmd(type,arg,cblock)
524int type;
525ARG *arg;
526struct compcmd cblock;
527{
528    register CMD *cmd;
529    register CMD *alt;
530    register CMD *cur;
531    register CMD *head;
532    struct compcmd ncblock;
533
534    Newz(109,cmd, 1, CMD);
535    head = cmd;
536    cmd->c_type = type;
537    cmd->c_expr = arg;
538    cmd->ucmd.ccmd.cc_true = cblock.comp_true;
539    cmd->ucmd.ccmd.cc_alt = cblock.comp_alt;
540    if (arg)
541        cmd->c_flags |= CF_COND;
542    if (cmdline == NOLINE)
543        cmd->c_line = curcmd->c_line;
544    else {
545        cmd->c_line = cmdline;
546        cmdline = NOLINE;
547    }
548    cmd->c_filestab = curcmd->c_filestab;
549    cmd->c_stash = curstash;
550    cur = cmd;
551    alt = cblock.comp_alt;
552    while (alt && alt->c_type == C_ELSIF) {
553        cur = alt;
554        alt = alt->ucmd.ccmd.cc_alt;
555    }
556    if (alt) {                  /* a real life ELSE at the end? */
557        ncblock.comp_true = alt;
558        ncblock.comp_alt = Nullcmd;
559        alt = append_line(cur,make_ccmd(C_ELSE,1,Nullarg,ncblock));
560        cur->ucmd.ccmd.cc_alt = alt;
561    }
562    else
563        alt = cur;              /* no ELSE, so cur is proxy ELSE */
564
565    cur = cmd;
566    while (cmd) {               /* now point everyone at the ELSE */
567        cur = cmd;
568        cmd = cur->ucmd.ccmd.cc_alt;
569        cur->c_head = head;
570        if (cur->c_type == C_ELSIF)
571            cur->c_type = C_IF;
572        if (cur->c_type == C_IF)
573            cur->ucmd.ccmd.cc_alt = alt;
574        if (cur == alt)
575            break;
576        cur->c_next = cmd;
577    }
578    if (perldb)
579        cur = dodb(cur);
580    return cur;
581}
582
583void
584opt_arg(cmd,fliporflop,acmd)
585register CMD *cmd;
586int fliporflop;
587int acmd;
588{
589    register ARG *arg;
590    int opt = CFT_EVAL;
591    int sure = 0;
592    ARG *arg2;
593    int context = 0;    /* 0 = normal, 1 = before &&, 2 = before || */
594    int flp = fliporflop;
595
596    if (!cmd)
597        return;
598    if (!(arg = cmd->c_expr)) {
599        cmd->c_flags &= ~CF_COND;
600        return;
601    }
602
603    /* Can we turn && and || into if and unless? */
604
605    if (acmd && !cmd->ucmd.acmd.ac_expr && !(cmd->c_flags & CF_TERM) &&
606      (arg->arg_type == O_AND || arg->arg_type == O_OR) ) {
607        dehoist(arg,1);
608        arg[2].arg_type &= A_MASK;      /* don't suppress eval */
609        dehoist(arg,2);
610        cmd->ucmd.acmd.ac_expr = arg[2].arg_ptr.arg_arg;
611        cmd->c_expr = arg[1].arg_ptr.arg_arg;
612        if (arg->arg_type == O_OR)
613            cmd->c_flags ^= CF_INVERT;          /* || is like unless */
614        arg->arg_len = 0;
615        free_arg(arg);
616        arg = cmd->c_expr;
617    }
618
619    /* Turn "if (!expr)" into "unless (expr)" */
620
621    if (!(cmd->c_flags & CF_TERM)) {            /* unless return value wanted */
622        while (arg->arg_type == O_NOT) {
623            dehoist(arg,1);
624            cmd->c_flags ^= CF_INVERT;          /* flip sense of cmd */
625            cmd->c_expr = arg[1].arg_ptr.arg_arg; /* hoist the rest of expr */
626            free_arg(arg);
627            arg = cmd->c_expr;                  /* here we go again */
628        }
629    }
630
631    if (!arg->arg_len) {                /* sanity check */
632        cmd->c_flags |= opt;
633        return;
634    }
635
636    /* for "cond .. cond" we set up for the initial check */
637
638    if (arg->arg_type == O_FLIP)
639        context |= 4;
640
641    /* for "cond && expr" and "cond || expr" we can ignore expr, sort of */
642
643  morecontext:
644    if (arg->arg_type == O_AND)
645        context |= 1;
646    else if (arg->arg_type == O_OR)
647        context |= 2;
648    if (context && (arg[flp].arg_type & A_MASK) == A_EXPR) {
649        arg = arg[flp].arg_ptr.arg_arg;
650        flp = 1;
651        if (arg->arg_type == O_AND || arg->arg_type == O_OR)
652            goto morecontext;
653    }
654    if ((context & 3) == 3)
655        return;
656
657    if (arg[flp].arg_flags & (AF_PRE|AF_POST)) {
658        cmd->c_flags |= opt;
659        if (acmd && !cmd->ucmd.acmd.ac_expr && !(cmd->c_flags & CF_TERM)
660          && cmd->c_expr->arg_type == O_ITEM) {
661            arg[flp].arg_flags &= ~AF_POST;     /* prefer ++$foo to $foo++ */
662            arg[flp].arg_flags |= AF_PRE;       /*  if value not wanted */
663        }
664        return;                         /* side effect, can't optimize */
665    }
666
667    if (arg->arg_type == O_ITEM || arg->arg_type == O_FLIP ||
668      arg->arg_type == O_AND || arg->arg_type == O_OR) {
669        if ((arg[flp].arg_type & A_MASK) == A_SINGLE) {
670            opt = (str_true(arg[flp].arg_ptr.arg_str) ? CFT_TRUE : CFT_FALSE);
671            cmd->c_short = str_smake(arg[flp].arg_ptr.arg_str);
672            goto literal;
673        }
674        else if ((arg[flp].arg_type & A_MASK) == A_STAB ||
675          (arg[flp].arg_type & A_MASK) == A_LVAL) {
676            cmd->c_stab  = arg[flp].arg_ptr.arg_stab;
677            if (!context)
678                arg[flp].arg_ptr.arg_stab = Nullstab;
679            opt = CFT_REG;
680          literal:
681            if (!context) {     /* no && or ||? */
682                arg_free(arg);
683                cmd->c_expr = Nullarg;
684            }
685            if (!(context & 1))
686                cmd->c_flags |= CF_EQSURE;
687            if (!(context & 2))
688                cmd->c_flags |= CF_NESURE;
689        }
690    }
691    else if (arg->arg_type == O_MATCH || arg->arg_type == O_SUBST ||
692             arg->arg_type == O_NMATCH || arg->arg_type == O_NSUBST) {
693        if ((arg[1].arg_type == A_STAB || arg[1].arg_type == A_LVAL) &&
694                (arg[2].arg_type & A_MASK) == A_SPAT &&
695                arg[2].arg_ptr.arg_spat->spat_short &&
696                (arg->arg_type == O_SUBST || arg->arg_type == O_NSUBST ||
697                 (arg[2].arg_ptr.arg_spat->spat_flags & SPAT_GLOBAL) == 0 )) {
698            cmd->c_stab  = arg[1].arg_ptr.arg_stab;
699            cmd->c_short = str_smake(arg[2].arg_ptr.arg_spat->spat_short);
700            cmd->c_slen  = arg[2].arg_ptr.arg_spat->spat_slen;
701            if (arg[2].arg_ptr.arg_spat->spat_flags & SPAT_ALL &&
702                !(arg[2].arg_ptr.arg_spat->spat_flags & SPAT_ONCE) &&
703                (arg->arg_type == O_MATCH || arg->arg_type == O_NMATCH) )
704                sure |= CF_EQSURE;              /* (SUBST must be forced even */
705                                                /* if we know it will work.) */
706            if (arg->arg_type != O_SUBST) {
707                str_free(arg[2].arg_ptr.arg_spat->spat_short);
708                arg[2].arg_ptr.arg_spat->spat_short = Nullstr;
709                arg[2].arg_ptr.arg_spat->spat_slen = 0; /* only one chk */
710            }
711            sure |= CF_NESURE;          /* normally only sure if it fails */
712            if (arg->arg_type == O_NMATCH || arg->arg_type == O_NSUBST)
713                cmd->c_flags |= CF_FIRSTNEG;
714            if (context & 1) {          /* only sure if thing is false */
715                if (cmd->c_flags & CF_FIRSTNEG)
716                    sure &= ~CF_NESURE;
717                else
718                    sure &= ~CF_EQSURE;
719            }
720            else if (context & 2) {     /* only sure if thing is true */
721                if (cmd->c_flags & CF_FIRSTNEG)
722                    sure &= ~CF_EQSURE;
723                else
724                    sure &= ~CF_NESURE;
725            }
726            if (sure & (CF_EQSURE|CF_NESURE)) { /* if we know anything*/
727                if (arg[2].arg_ptr.arg_spat->spat_flags & SPAT_SCANFIRST)
728                    opt = CFT_SCAN;
729                else
730                    opt = CFT_ANCHOR;
731                if (sure == (CF_EQSURE|CF_NESURE)       /* really sure? */
732                    && arg->arg_type == O_MATCH
733                    && context & 4
734                    && fliporflop == 1) {
735                    spat_free(arg[2].arg_ptr.arg_spat);
736                    arg[2].arg_ptr.arg_spat = Nullspat; /* don't do twice */
737                }
738                else
739                    cmd->c_spat = arg[2].arg_ptr.arg_spat;
740                cmd->c_flags |= sure;
741            }
742        }
743    }
744    else if (arg->arg_type == O_SEQ || arg->arg_type == O_SNE ||
745             arg->arg_type == O_SLT || arg->arg_type == O_SGT) {
746        if (arg[1].arg_type == A_STAB || arg[1].arg_type == A_LVAL) {
747            if (arg[2].arg_type == A_SINGLE) {
748                /*SUPPRESS 594*/
749                char *junk = str_get(arg[2].arg_ptr.arg_str);
750
751                cmd->c_stab  = arg[1].arg_ptr.arg_stab;
752                cmd->c_short = str_smake(arg[2].arg_ptr.arg_str);
753                cmd->c_slen  = cmd->c_short->str_cur+1;
754                switch (arg->arg_type) {
755                case O_SLT: case O_SGT:
756                    sure |= CF_EQSURE;
757                    cmd->c_flags |= CF_FIRSTNEG;
758                    break;
759                case O_SNE:
760                    cmd->c_flags |= CF_FIRSTNEG;
761                    /* FALL THROUGH */
762                case O_SEQ:
763                    sure |= CF_NESURE|CF_EQSURE;
764                    break;
765                }
766                if (context & 1) {      /* only sure if thing is false */
767                    if (cmd->c_flags & CF_FIRSTNEG)
768                        sure &= ~CF_NESURE;
769                    else
770                        sure &= ~CF_EQSURE;
771                }
772                else if (context & 2) { /* only sure if thing is true */
773                    if (cmd->c_flags & CF_FIRSTNEG)
774                        sure &= ~CF_EQSURE;
775                    else
776                        sure &= ~CF_NESURE;
777                }
778                if (sure & (CF_EQSURE|CF_NESURE)) {
779                    opt = CFT_STROP;
780                    cmd->c_flags |= sure;
781                }
782            }
783        }
784    }
785    else if (arg->arg_type == O_EQ || arg->arg_type == O_NE ||
786             arg->arg_type == O_LE || arg->arg_type == O_GE ||
787             arg->arg_type == O_LT || arg->arg_type == O_GT) {
788        if (arg[1].arg_type == A_STAB || arg[1].arg_type == A_LVAL) {
789            if (arg[2].arg_type == A_SINGLE) {
790                cmd->c_stab  = arg[1].arg_ptr.arg_stab;
791                if (dowarn) {
792                    STR *str = arg[2].arg_ptr.arg_str;
793
794                    if ((!str->str_nok && !looks_like_number(str)))
795                        warn("Possible use of == on string value");
796                }
797                cmd->c_short = str_nmake(str_gnum(arg[2].arg_ptr.arg_str));
798                cmd->c_slen = arg->arg_type;
799                sure |= CF_NESURE|CF_EQSURE;
800                if (context & 1) {      /* only sure if thing is false */
801                    sure &= ~CF_EQSURE;
802                }
803                else if (context & 2) { /* only sure if thing is true */
804                    sure &= ~CF_NESURE;
805                }
806                if (sure & (CF_EQSURE|CF_NESURE)) {
807                    opt = CFT_NUMOP;
808                    cmd->c_flags |= sure;
809                }
810            }
811        }
812    }
813    else if (arg->arg_type == O_ASSIGN &&
814             (arg[1].arg_type == A_STAB || arg[1].arg_type == A_LVAL) &&
815             arg[1].arg_ptr.arg_stab == defstab &&
816             arg[2].arg_type == A_EXPR ) {
817        arg2 = arg[2].arg_ptr.arg_arg;
818        if (arg2->arg_type == O_ITEM && arg2[1].arg_type == A_READ) {
819            opt = CFT_GETS;
820            cmd->c_stab = arg2[1].arg_ptr.arg_stab;
821            if (!(stab_io(arg2[1].arg_ptr.arg_stab)->flags & IOF_ARGV)) {
822                free_arg(arg2);
823                arg[2].arg_ptr.arg_arg = Nullarg;
824                free_arg(arg);
825                cmd->c_expr = Nullarg;
826            }
827        }
828    }
829    else if (arg->arg_type == O_CHOP &&
830             (arg[1].arg_type == A_STAB || arg[1].arg_type == A_LVAL) ) {
831        opt = CFT_CHOP;
832        cmd->c_stab = arg[1].arg_ptr.arg_stab;
833        free_arg(arg);
834        cmd->c_expr = Nullarg;
835    }
836    if (context & 4)
837        opt |= CF_FLIP;
838    cmd->c_flags |= opt;
839
840    if (cmd->c_flags & CF_FLIP) {
841        if (fliporflop == 1) {
842            arg = cmd->c_expr;  /* get back to O_FLIP arg */
843            New(110,arg[3].arg_ptr.arg_cmd, 1, CMD);
844            Copy(cmd, arg[3].arg_ptr.arg_cmd, 1, CMD);
845            New(111,arg[4].arg_ptr.arg_cmd,1,CMD);
846            Copy(cmd, arg[4].arg_ptr.arg_cmd, 1, CMD);
847            opt_arg(arg[4].arg_ptr.arg_cmd,2,acmd);
848            arg->arg_len = 2;           /* this is a lie */
849        }
850        else {
851            if ((opt & CF_OPTIMIZE) == CFT_EVAL)
852                cmd->c_flags = (cmd->c_flags & ~CF_OPTIMIZE) | CFT_UNFLIP;
853        }
854    }
855}
856
857CMD *
858add_label(lbl,cmd)
859char *lbl;
860register CMD *cmd;
861{
862    if (cmd)
863        cmd->c_label = lbl;
864    return cmd;
865}
866
867CMD *
868addcond(cmd, arg)
869register CMD *cmd;
870register ARG *arg;
871{
872    cmd->c_expr = arg;
873    cmd->c_flags |= CF_COND;
874    return cmd;
875}
876
877CMD *
878addloop(cmd, arg)
879register CMD *cmd;
880register ARG *arg;
881{
882    void while_io();
883
884    cmd->c_expr = arg;
885    cmd->c_flags |= CF_COND|CF_LOOP;
886
887    if (!(cmd->c_flags & CF_INVERT))
888        while_io(cmd);          /* add $_ =, if necessary */
889
890    if (cmd->c_type == C_BLOCK)
891        cmd->c_flags &= ~CF_COND;
892    else {
893        arg = cmd->ucmd.acmd.ac_expr;
894        if (arg && arg->arg_type == O_ITEM && arg[1].arg_type == A_CMD)
895            cmd->c_flags &= ~CF_COND;  /* "do {} while" happens at least once */
896        if (arg && (arg->arg_flags & AF_DEPR) &&
897          (arg->arg_type == O_SUBR || arg->arg_type == O_DBSUBR) )
898            cmd->c_flags &= ~CF_COND;  /* likewise for "do subr() while" */
899    }
900    return cmd;
901}
902
903CMD *
904invert(cmd)
905CMD *cmd;
906{
907    register CMD *targ = cmd;
908    if (targ->c_head)
909        targ = targ->c_head;
910    if (targ->c_flags & CF_DBSUB)
911        targ = targ->c_next;
912    targ->c_flags ^= CF_INVERT;
913    return cmd;
914}
915
916void
917cpy7bit(d,s,l)
918register char *d;
919register char *s;
920register int l;
921{
922    while (l--)
923        *d++ = *s++ & 127;
924    *d = '\0';
925}
926
927int
928yyerror(s)
929char *s;
930{
931    char tmpbuf[258];
932    char tmp2buf[258];
933    char *tname = tmpbuf;
934
935    if (bufptr > oldoldbufptr && bufptr - oldoldbufptr < 200 &&
936      oldoldbufptr != oldbufptr && oldbufptr != bufptr) {
937        while (isSPACE(*oldoldbufptr))
938            oldoldbufptr++;
939        cpy7bit(tmp2buf, oldoldbufptr, bufptr - oldoldbufptr);
940        sprintf(tname,"next 2 tokens \"%s\"",tmp2buf);
941    }
942    else if (bufptr > oldbufptr && bufptr - oldbufptr < 200 &&
943      oldbufptr != bufptr) {
944        while (isSPACE(*oldbufptr))
945            oldbufptr++;
946        cpy7bit(tmp2buf, oldbufptr, bufptr - oldbufptr);
947        sprintf(tname,"next token \"%s\"",tmp2buf);
948    }
949    else if (yychar > 256)
950        tname = "next token ???";
951    else if (!yychar)
952        (void)strcpy(tname,"at EOF");
953    else if (yychar < 32)
954        (void)sprintf(tname,"next char ^%c",yychar+64);
955    else if (yychar == 127)
956        (void)strcpy(tname,"at EOF");
957    else
958        (void)sprintf(tname,"next char %c",yychar);
959    (void)sprintf(buf, "%s in file %s at line %d, %s\n",
960      s,stab_val(curcmd->c_filestab)->str_ptr,curcmd->c_line,tname);
961    if (curcmd->c_line == multi_end && multi_start < multi_end)
962        sprintf(buf+strlen(buf),
963          "  (Might be a runaway multi-line %c%c string starting on line %d)\n",
964          multi_open,multi_close,multi_start);
965    if (in_eval)
966        str_cat(stab_val(stabent("@",TRUE)),buf);
967    else
968        fputs(buf,stderr);
969    if (++error_count >= 10)
970        fatal("%s has too many errors.\n",
971        stab_val(curcmd->c_filestab)->str_ptr);
972}
973
974void
975while_io(cmd)
976register CMD *cmd;
977{
978    register ARG *arg = cmd->c_expr;
979    STAB *asgnstab;
980
981    /* hoist "while (<channel>)" up into command block */
982
983    if (arg && arg->arg_type == O_ITEM && arg[1].arg_type == A_READ) {
984        cmd->c_flags &= ~CF_OPTIMIZE;   /* clear optimization type */
985        cmd->c_flags |= CFT_GETS;       /* and set it to do the input */
986        cmd->c_stab = arg[1].arg_ptr.arg_stab;
987        if (stab_io(arg[1].arg_ptr.arg_stab)->flags & IOF_ARGV) {
988            cmd->c_expr = l(make_op(O_ASSIGN, 2,        /* fake up "$_ =" */
989               stab2arg(A_LVAL,defstab), arg, Nullarg));
990        }
991        else {
992            free_arg(arg);
993            cmd->c_expr = Nullarg;
994        }
995    }
996    else if (arg && arg->arg_type == O_ITEM && arg[1].arg_type == A_INDREAD) {
997        cmd->c_flags &= ~CF_OPTIMIZE;   /* clear optimization type */
998        cmd->c_flags |= CFT_INDGETS;    /* and set it to do the input */
999        cmd->c_stab = arg[1].arg_ptr.arg_stab;
1000        free_arg(arg);
1001        cmd->c_expr = Nullarg;
1002    }
1003    else if (arg && arg->arg_type == O_ITEM && arg[1].arg_type == A_GLOB) {
1004        if ((cmd->c_flags & CF_OPTIMIZE) == CFT_ARRAY)
1005            asgnstab = cmd->c_stab;
1006        else
1007            asgnstab = defstab;
1008        cmd->c_expr = l(make_op(O_ASSIGN, 2,    /* fake up "$foo =" */
1009           stab2arg(A_LVAL,asgnstab), arg, Nullarg));
1010        cmd->c_flags &= ~CF_OPTIMIZE;   /* clear optimization type */
1011    }
1012}
1013
1014CMD *
1015wopt(cmd)
1016register CMD *cmd;
1017{
1018    register CMD *tail;
1019    CMD *newtail;
1020    register int i;
1021
1022    if (cmd->c_expr && (cmd->c_flags & CF_OPTIMIZE) == CFT_FALSE)
1023        opt_arg(cmd,1, cmd->c_type == C_EXPR);
1024
1025    while_io(cmd);              /* add $_ =, if necessary */
1026
1027    /* First find the end of the true list */
1028
1029    tail = cmd->ucmd.ccmd.cc_true;
1030    if (tail == Nullcmd)
1031        return cmd;
1032    New(112,newtail, 1, CMD);   /* guaranteed continue */
1033    for (;;) {
1034        /* optimize "next" to point directly to continue block */
1035        if (tail->c_type == C_EXPR &&
1036            tail->ucmd.acmd.ac_expr &&
1037            tail->ucmd.acmd.ac_expr->arg_type == O_NEXT &&
1038            (tail->ucmd.acmd.ac_expr->arg_len == 0 ||
1039             (cmd->c_label &&
1040              strEQ(cmd->c_label,
1041                    tail->ucmd.acmd.ac_expr[1].arg_ptr.arg_str->str_ptr) )))
1042        {
1043            arg_free(tail->ucmd.acmd.ac_expr);
1044            tail->ucmd.acmd.ac_expr = Nullarg;
1045            tail->c_type = C_NEXT;
1046            if (cmd->ucmd.ccmd.cc_alt != Nullcmd)
1047                tail->ucmd.ccmd.cc_alt = cmd->ucmd.ccmd.cc_alt;
1048            else
1049                tail->ucmd.ccmd.cc_alt = newtail;
1050            tail->ucmd.ccmd.cc_true = Nullcmd;
1051        }
1052        else if (tail->c_type == C_IF && !tail->ucmd.ccmd.cc_alt) {
1053            if (cmd->ucmd.ccmd.cc_alt != Nullcmd)
1054                tail->ucmd.ccmd.cc_alt = cmd->ucmd.ccmd.cc_alt;
1055            else
1056                tail->ucmd.ccmd.cc_alt = newtail;
1057        }
1058        else if (tail->c_type == C_CSWITCH || tail->c_type == C_NSWITCH) {
1059            if (cmd->ucmd.ccmd.cc_alt != Nullcmd) {
1060                for (i = tail->ucmd.scmd.sc_max; i >= 0; i--)
1061                    if (!tail->ucmd.scmd.sc_next[i])
1062                        tail->ucmd.scmd.sc_next[i] = cmd->ucmd.ccmd.cc_alt;
1063            }
1064            else {
1065                for (i = tail->ucmd.scmd.sc_max; i >= 0; i--)
1066                    if (!tail->ucmd.scmd.sc_next[i])
1067                        tail->ucmd.scmd.sc_next[i] = newtail;
1068            }
1069        }
1070
1071        if (!tail->c_next)
1072            break;
1073        tail = tail->c_next;
1074    }
1075
1076    /* if there's a continue block, link it to true block and find end */
1077
1078    if (cmd->ucmd.ccmd.cc_alt != Nullcmd) {
1079        tail->c_next = cmd->ucmd.ccmd.cc_alt;
1080        tail = tail->c_next;
1081        for (;;) {
1082            /* optimize "next" to point directly to continue block */
1083            if (tail->c_type == C_EXPR &&
1084                tail->ucmd.acmd.ac_expr &&
1085                tail->ucmd.acmd.ac_expr->arg_type == O_NEXT &&
1086                (tail->ucmd.acmd.ac_expr->arg_len == 0 ||
1087                 (cmd->c_label &&
1088                  strEQ(cmd->c_label,
1089                        tail->ucmd.acmd.ac_expr[1].arg_ptr.arg_str->str_ptr) )))
1090            {
1091                arg_free(tail->ucmd.acmd.ac_expr);
1092                tail->ucmd.acmd.ac_expr = Nullarg;
1093                tail->c_type = C_NEXT;
1094                tail->ucmd.ccmd.cc_alt = newtail;
1095                tail->ucmd.ccmd.cc_true = Nullcmd;
1096            }
1097            else if (tail->c_type == C_IF && !tail->ucmd.ccmd.cc_alt) {
1098                tail->ucmd.ccmd.cc_alt = newtail;
1099            }
1100            else if (tail->c_type == C_CSWITCH || tail->c_type == C_NSWITCH) {
1101                for (i = tail->ucmd.scmd.sc_max; i >= 0; i--)
1102                    if (!tail->ucmd.scmd.sc_next[i])
1103                        tail->ucmd.scmd.sc_next[i] = newtail;
1104            }
1105
1106            if (!tail->c_next)
1107                break;
1108            tail = tail->c_next;
1109        }
1110        /*SUPPRESS 530*/
1111        for ( ; tail->c_next; tail = tail->c_next) ;
1112    }
1113
1114    /* Here's the real trick: link the end of the list back to the beginning,
1115     * inserting a "last" block to break out of the loop.  This saves one or
1116     * two procedure calls every time through the loop, because of how cmd_exec
1117     * does tail recursion.
1118     */
1119
1120    tail->c_next = newtail;
1121    tail = newtail;
1122    if (!cmd->ucmd.ccmd.cc_alt)
1123        cmd->ucmd.ccmd.cc_alt = tail;   /* every loop has a continue now */
1124
1125#ifndef lint
1126    Copy((char *)cmd, (char *)tail, 1, CMD);
1127#endif
1128    tail->c_type = C_EXPR;
1129    tail->c_flags ^= CF_INVERT;         /* turn into "last unless" */
1130    tail->c_next = tail->ucmd.ccmd.cc_true;     /* loop directly back to top */
1131    tail->ucmd.acmd.ac_expr = make_op(O_LAST,0,Nullarg,Nullarg,Nullarg);
1132    tail->ucmd.acmd.ac_stab = Nullstab;
1133    return cmd;
1134}
1135
1136CMD *
1137over(eachstab,cmd)
1138STAB *eachstab;
1139register CMD *cmd;
1140{
1141    /* hoist "for $foo (@bar)" up into command block */
1142
1143    cmd->c_flags &= ~CF_OPTIMIZE;       /* clear optimization type */
1144    cmd->c_flags |= CFT_ARRAY;          /* and set it to do the iteration */
1145    cmd->c_stab = eachstab;
1146    cmd->c_short = Str_new(23,0);       /* just to save a field in struct cmd */
1147    cmd->c_short->str_u.str_useful = -1;
1148
1149    return cmd;
1150}
1151
1152void
1153cmd_free(cmd)
1154register CMD *cmd;
1155{
1156    register CMD *tofree;
1157    register CMD *head = cmd;
1158
1159    if (!cmd)
1160        return;
1161    if (cmd->c_head != cmd)
1162        warn("Malformed cmd links\n");
1163    while (cmd) {
1164        if (cmd->c_type != C_WHILE) {   /* WHILE block is duplicated */
1165            if (cmd->c_label) {
1166                Safefree(cmd->c_label);
1167                cmd->c_label = Nullch;
1168            }
1169            if (cmd->c_short) {
1170                str_free(cmd->c_short);
1171                cmd->c_short = Nullstr;
1172            }
1173            if (cmd->c_expr) {
1174                arg_free(cmd->c_expr);
1175                cmd->c_expr = Nullarg;
1176            }
1177        }
1178        switch (cmd->c_type) {
1179        case C_WHILE:
1180        case C_BLOCK:
1181        case C_ELSE:
1182        case C_IF:
1183            if (cmd->ucmd.ccmd.cc_true) {
1184                cmd_free(cmd->ucmd.ccmd.cc_true);
1185                cmd->ucmd.ccmd.cc_true = Nullcmd;
1186            }
1187            break;
1188        case C_EXPR:
1189            if (cmd->ucmd.acmd.ac_expr) {
1190                arg_free(cmd->ucmd.acmd.ac_expr);
1191                cmd->ucmd.acmd.ac_expr = Nullarg;
1192            }
1193            break;
1194        }
1195        tofree = cmd;
1196        cmd = cmd->c_next;
1197        if (tofree != head)             /* to get Saber to shut up */
1198            Safefree(tofree);
1199        if (cmd && cmd == head)         /* reached end of while loop */
1200            break;
1201    }
1202    Safefree(head);
1203}
1204
1205void
1206arg_free(arg)
1207register ARG *arg;
1208{
1209    register int i;
1210
1211    if (!arg)
1212        return;
1213    for (i = 1; i <= arg->arg_len; i++) {
1214        switch (arg[i].arg_type & A_MASK) {
1215        case A_NULL:
1216            if (arg->arg_type == O_TRANS) {
1217                Safefree(arg[i].arg_ptr.arg_cval);
1218                arg[i].arg_ptr.arg_cval = Nullch;
1219            }
1220            break;
1221        case A_LEXPR:
1222            if (arg->arg_type == O_AASSIGN &&
1223              arg[i].arg_ptr.arg_arg->arg_type == O_LARRAY) {
1224                char *name =
1225                  stab_name(arg[i].arg_ptr.arg_arg[1].arg_ptr.arg_stab);
1226
1227                if (strnEQ("_GEN_",name, 5))    /* array for foreach */
1228                    hdelete(defstash,name,strlen(name));
1229            }
1230            /* FALL THROUGH */
1231        case A_EXPR:
1232            arg_free(arg[i].arg_ptr.arg_arg);
1233            arg[i].arg_ptr.arg_arg = Nullarg;
1234            break;
1235        case A_CMD:
1236            cmd_free(arg[i].arg_ptr.arg_cmd);
1237            arg[i].arg_ptr.arg_cmd = Nullcmd;
1238            break;
1239        case A_WORD:
1240        case A_STAB:
1241        case A_LVAL:
1242        case A_READ:
1243        case A_GLOB:
1244        case A_ARYLEN:
1245        case A_LARYLEN:
1246        case A_ARYSTAB:
1247        case A_LARYSTAB:
1248            break;
1249        case A_SINGLE:
1250        case A_DOUBLE:
1251        case A_BACKTICK:
1252            str_free(arg[i].arg_ptr.arg_str);
1253            arg[i].arg_ptr.arg_str = Nullstr;
1254            break;
1255        case A_SPAT:
1256            spat_free(arg[i].arg_ptr.arg_spat);
1257            arg[i].arg_ptr.arg_spat = Nullspat;
1258            break;
1259        }
1260    }
1261    free_arg(arg);
1262}
1263
1264void
1265spat_free(spat)
1266register SPAT *spat;
1267{
1268    register SPAT *sp;
1269    HENT *entry;
1270
1271    if (!spat)
1272        return;
1273    if (spat->spat_runtime) {
1274        arg_free(spat->spat_runtime);
1275        spat->spat_runtime = Nullarg;
1276    }
1277    if (spat->spat_repl) {
1278        arg_free(spat->spat_repl);
1279        spat->spat_repl = Nullarg;
1280    }
1281    if (spat->spat_short) {
1282        str_free(spat->spat_short);
1283        spat->spat_short = Nullstr;
1284    }
1285    if (spat->spat_regexp) {
1286        regfree(spat->spat_regexp);
1287        spat->spat_regexp = Null(REGEXP*);
1288    }
1289
1290    /* now unlink from spat list */
1291
1292    for (entry = defstash->tbl_array['_']; entry; entry = entry->hent_next) {
1293        register HASH *stash;
1294        STAB *stab = (STAB*)entry->hent_val;
1295
1296        if (!stab)
1297            continue;
1298        stash = stab_hash(stab);
1299        if (!stash || stash->tbl_spatroot == Null(SPAT*))
1300            continue;
1301        if (stash->tbl_spatroot == spat)
1302            stash->tbl_spatroot = spat->spat_next;
1303        else {
1304            for (sp = stash->tbl_spatroot;
1305              sp && sp->spat_next != spat;
1306              sp = sp->spat_next)
1307                /*SUPPRESS 530*/
1308                ;
1309            if (sp)
1310                sp->spat_next = spat->spat_next;
1311        }
1312    }
1313    Safefree(spat);
1314}
1315
1316/* Recursively descend a command sequence and push the address of any string
1317 * that needs saving on recursion onto the tosave array.
1318 */
1319
1320static int
1321cmd_tosave(cmd,willsave)
1322register CMD *cmd;
1323int willsave;                           /* willsave passes down the tree */
1324{
1325    register CMD *head = cmd;
1326    int shouldsave = FALSE;             /* shouldsave passes up the tree */
1327    int tmpsave;
1328    register CMD *lastcmd = Nullcmd;
1329
1330    while (cmd) {
1331        if (cmd->c_expr)
1332            shouldsave |= arg_tosave(cmd->c_expr,willsave);
1333        switch (cmd->c_type) {
1334        case C_WHILE:
1335            if (cmd->ucmd.ccmd.cc_true) {
1336                tmpsave = cmd_tosave(cmd->ucmd.ccmd.cc_true,willsave);
1337
1338                /* Here we check to see if the temporary array generated for
1339                 * a foreach needs to be localized because of recursion.
1340                 */
1341                if (tmpsave && (cmd->c_flags & CF_OPTIMIZE) == CFT_ARRAY) {
1342                    if (lastcmd &&
1343                      lastcmd->c_type == C_EXPR &&
1344                      lastcmd->c_expr) {
1345                        ARG *arg = lastcmd->c_expr;
1346
1347                        if (arg->arg_type == O_ASSIGN &&
1348                            arg[1].arg_type == A_LEXPR &&
1349                            arg[1].arg_ptr.arg_arg->arg_type == O_LARRAY &&
1350                            strnEQ("_GEN_",
1351                              stab_name(
1352                                arg[1].arg_ptr.arg_arg[1].arg_ptr.arg_stab),
1353                              5)) {     /* array generated for foreach */
1354                            (void)localize(arg);
1355                        }
1356                    }
1357
1358                    /* in any event, save the iterator */
1359
1360                    if (cmd->c_short)  /* Better safe than sorry */
1361                        (void)apush(tosave,cmd->c_short);
1362                }
1363                shouldsave |= tmpsave;
1364            }
1365            break;
1366        case C_BLOCK:
1367        case C_ELSE:
1368        case C_IF:
1369            if (cmd->ucmd.ccmd.cc_true)
1370                shouldsave |= cmd_tosave(cmd->ucmd.ccmd.cc_true,willsave);
1371            break;
1372        case C_EXPR:
1373            if (cmd->ucmd.acmd.ac_expr)
1374                shouldsave |= arg_tosave(cmd->ucmd.acmd.ac_expr,willsave);
1375            break;
1376        }
1377        lastcmd = cmd;
1378        cmd = cmd->c_next;
1379        if (cmd && cmd == head)         /* reached end of while loop */
1380            break;
1381    }
1382    return shouldsave;
1383}
1384
1385static int
1386arg_tosave(arg,willsave)
1387register ARG *arg;
1388int willsave;
1389{
1390    register int i;
1391    int shouldsave = FALSE;
1392
1393    for (i = arg->arg_len; i >= 1; i--) {
1394        switch (arg[i].arg_type & A_MASK) {
1395        case A_NULL:
1396            break;
1397        case A_LEXPR:
1398        case A_EXPR:
1399            shouldsave |= arg_tosave(arg[i].arg_ptr.arg_arg,shouldsave);
1400            break;
1401        case A_CMD:
1402            shouldsave |= cmd_tosave(arg[i].arg_ptr.arg_cmd,shouldsave);
1403            break;
1404        case A_WORD:
1405        case A_STAB:
1406        case A_LVAL:
1407        case A_READ:
1408        case A_GLOB:
1409        case A_ARYLEN:
1410        case A_SINGLE:
1411        case A_DOUBLE:
1412        case A_BACKTICK:
1413            break;
1414        case A_SPAT:
1415            shouldsave |= spat_tosave(arg[i].arg_ptr.arg_spat);
1416            break;
1417        }
1418    }
1419    switch (arg->arg_type) {
1420    case O_RETURN:
1421        saw_return = TRUE;
1422        break;
1423    case O_EVAL:
1424    case O_SUBR:
1425        shouldsave = TRUE;
1426        break;
1427    }
1428    if (willsave && arg->arg_ptr.arg_str)
1429        (void)apush(tosave,arg->arg_ptr.arg_str);
1430    return shouldsave;
1431}
1432
1433static int
1434spat_tosave(spat)
1435register SPAT *spat;
1436{
1437    int shouldsave = FALSE;
1438
1439    if (spat->spat_runtime)
1440        shouldsave |= arg_tosave(spat->spat_runtime,FALSE);
1441    if (spat->spat_repl) {
1442        shouldsave |= arg_tosave(spat->spat_repl,FALSE);
1443    }
1444
1445    return shouldsave;
1446}
1447
Note: See TracBrowser for help on using the repository browser.