diff options
Diffstat (limited to 'cons.c.orig')
-rw-r--r-- | cons.c.orig | 1442 |
1 files changed, 1442 insertions, 0 deletions
diff --git a/cons.c.orig b/cons.c.orig new file mode 100644 index 0000000000..54fa14d880 --- /dev/null +++ b/cons.c.orig @@ -0,0 +1,1442 @@ +/* $RCSfile: cons.c,v $$Revision: 4.0.1.3 $$Date: 92/06/08 12:18:35 $ + * + * Copyright (c) 1991, Larry Wall + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + * $Log: cons.c,v $ + * Revision 4.0.1.3 92/06/08 12:18:35 lwall + * patch20: removed implicit int declarations on funcions + * patch20: deleted some minor memory leaks + * patch20: fixed double debug break in foreach with implicit array assignment + * patch20: fixed confusion between a *var's real name and its effective name + * patch20: Perl now distinguishes overlapped copies from non-overlapped + * patch20: debugger sometimes displayed wrong source line + * patch20: various error messages have been clarified + * patch20: an eval block containing a null block or statement could dump core + * + * Revision 4.0.1.2 91/11/05 16:15:13 lwall + * patch11: debugger got confused over nested subroutine definitions + * patch11: prepared for ctype implementations that don't define isascii() + * + * Revision 4.0.1.1 91/06/07 10:31:15 lwall + * patch4: new copyright notice + * patch4: added global modifier for pattern matches + * + * Revision 4.0 91/03/20 01:05:51 lwall + * 4.0 baseline. + * + */ + +#include "EXTERN.h" +#include "perl.h" +#include "perly.h" + +extern char *tokename[]; +extern int yychar; + +static int cmd_tosave(); +static int arg_tosave(); +static int spat_tosave(); +static void make_cswitch(); +static void make_nswitch(); + +static bool saw_return; + +SUBR * +make_sub(name,cmd) +char *name; +CMD *cmd; +{ + register SUBR *sub; + STAB *stab = stabent(name,TRUE); + + if (sub = stab_sub(stab)) { + if (dowarn) { + CMD *oldcurcmd = curcmd; + + if (cmd) + curcmd = cmd; + warn("Subroutine %s redefined",name); + curcmd = oldcurcmd; + } + if (!sub->usersub && sub->cmd) { + cmd_free(sub->cmd); + sub->cmd = Nullcmd; + afree(sub->tosave); + } + Safefree(sub); + } + Newz(101,sub,1,SUBR); + stab_sub(stab) = sub; + sub->filestab = curcmd->c_filestab; + saw_return = FALSE; + tosave = anew(Nullstab); + tosave->ary_fill = 0; /* make 1 based */ + (void)cmd_tosave(cmd,FALSE); /* this builds the tosave array */ + sub->tosave = tosave; + if (saw_return) { + struct compcmd mycompblock; + + mycompblock.comp_true = cmd; + mycompblock.comp_alt = Nullcmd; + cmd = add_label(savestr("_SUB_"),make_ccmd(C_BLOCK,0, + Nullarg,mycompblock)); + saw_return = FALSE; + cmd->c_flags |= CF_TERM; + } + sub->cmd = cmd; + if (perldb) { + STR *str; + STR *tmpstr = str_mortal(&str_undef); + + sprintf(buf,"%s:%ld",stab_val(curcmd->c_filestab)->str_ptr, subline); + str = str_make(buf,0); + str_cat(str,"-"); + sprintf(buf,"%ld",(long)curcmd->c_line); + str_cat(str,buf); + stab_efullname(tmpstr,stab); + hstore(stab_xhash(DBsub), tmpstr->str_ptr, tmpstr->str_cur, str, 0); + } + Safefree(name); + return sub; +} + +SUBR * +make_usub(name, ix, subaddr, filename) +char *name; +int ix; +int (*subaddr)(); +char *filename; +{ + register SUBR *sub; + STAB *stab = stabent(name,allstabs); + + if (!stab) /* unused function */ + return Null(SUBR*); + if (sub = stab_sub(stab)) { + if (dowarn) + warn("Subroutine %s redefined",name); + if (!sub->usersub && sub->cmd) { + cmd_free(sub->cmd); + sub->cmd = Nullcmd; + afree(sub->tosave); + } + Safefree(sub); + } + Newz(101,sub,1,SUBR); + stab_sub(stab) = sub; + sub->filestab = fstab(filename); + sub->usersub = subaddr; + sub->userindex = ix; + return sub; +} + +void +make_form(stab,fcmd) +STAB *stab; +FCMD *fcmd; +{ + if (stab_form(stab)) { + FCMD *tmpfcmd; + FCMD *nextfcmd; + + for (tmpfcmd = stab_form(stab); tmpfcmd; tmpfcmd = nextfcmd) { + nextfcmd = tmpfcmd->f_next; + if (tmpfcmd->f_expr) + arg_free(tmpfcmd->f_expr); + if (tmpfcmd->f_unparsed) + str_free(tmpfcmd->f_unparsed); + if (tmpfcmd->f_pre) + Safefree(tmpfcmd->f_pre); + Safefree(tmpfcmd); + } + } + stab_form(stab) = fcmd; +} + +CMD * +block_head(tail) +register CMD *tail; +{ + CMD *head; + register int opt; + register int last_opt = 0; + register STAB *last_stab = Nullstab; + register int count = 0; + register CMD *switchbeg = Nullcmd; + + if (tail == Nullcmd) { + return tail; + } + head = tail->c_head; + + for (tail = head; tail; tail = tail->c_next) { + + /* save one measly dereference at runtime */ + if (tail->c_type == C_IF) { + if (!(tail->ucmd.ccmd.cc_alt = tail->ucmd.ccmd.cc_alt->c_next)) + tail->c_flags |= CF_TERM; + } + else if (tail->c_type == C_EXPR) { + ARG *arg; + + if (tail->ucmd.acmd.ac_expr) + arg = tail->ucmd.acmd.ac_expr; + else + arg = tail->c_expr; + if (arg) { + if (arg->arg_type == O_RETURN) + tail->c_flags |= CF_TERM; + else if (arg->arg_type == O_ITEM && arg[1].arg_type == A_CMD) + tail->c_flags |= CF_TERM; + } + } + if (!tail->c_next) + tail->c_flags |= CF_TERM; + + if (tail->c_expr && (tail->c_flags & CF_OPTIMIZE) == CFT_FALSE) + opt_arg(tail,1, tail->c_type == C_EXPR); + + /* now do a little optimization on case-ish structures */ + switch(tail->c_flags & (CF_OPTIMIZE|CF_FIRSTNEG|CF_INVERT)) { + case CFT_ANCHOR: + case CFT_STROP: + opt = (tail->c_flags & CF_NESURE) ? CFT_STROP : 0; + break; + case CFT_CCLASS: + opt = CFT_STROP; + break; + case CFT_NUMOP: + opt = (tail->c_slen == O_NE ? 0 : CFT_NUMOP); + if ((tail->c_flags&(CF_NESURE|CF_EQSURE)) != (CF_NESURE|CF_EQSURE)) + opt = 0; + break; + default: + opt = 0; + } + if (opt && opt == last_opt && tail->c_stab == last_stab) + count++; + else { + if (count >= 3) { /* is this the breakeven point? */ + if (last_opt == CFT_NUMOP) + make_nswitch(switchbeg,count); + else + make_cswitch(switchbeg,count); + } + if (opt) { + count = 1; + switchbeg = tail; + } + else + count = 0; + } + last_opt = opt; + last_stab = tail->c_stab; + } + if (count >= 3) { /* is this the breakeven point? */ + if (last_opt == CFT_NUMOP) + make_nswitch(switchbeg,count); + else + make_cswitch(switchbeg,count); + } + return head; +} + +/* We've spotted a sequence of CMDs that all test the value of the same + * spat. Thus we can insert a SWITCH in front and jump directly + * to the correct one. + */ +static void +make_cswitch(head,count) +register CMD *head; +int count; +{ + register CMD *cur; + register CMD **loc; + register int i; + register int min = 255; + register int max = 0; + + /* make a new head in the exact same spot */ + New(102,cur, 1, CMD); + StructCopy(head,cur,CMD); + Zero(head,1,CMD); + head->c_head = cur->c_head; + head->c_type = C_CSWITCH; + head->c_next = cur; /* insert new cmd at front of list */ + head->c_stab = cur->c_stab; + + Newz(103,loc,258,CMD*); + loc++; /* lie a little */ + while (count--) { + if ((cur->c_flags & CF_OPTIMIZE) == CFT_CCLASS) { + for (i = 0; i <= 255; i++) { + if (!loc[i] && cur->c_short->str_ptr[i>>3] & (1 << (i&7))) { + loc[i] = cur; + if (i < min) + min = i; + if (i > max) + max = i; + } + } + } + else { + i = *cur->c_short->str_ptr & 255; + if (!loc[i]) { + loc[i] = cur; + if (i < min) + min = i; + if (i > max) + max = i; + } + } + cur = cur->c_next; + } + max++; + if (min > 0) + Move(&loc[min],&loc[0], max - min, CMD*); + loc--; + min--; + max -= min; + for (i = 0; i <= max; i++) + if (!loc[i]) + loc[i] = cur; + Renew(loc,max+1,CMD*); /* chop it down to size */ + head->ucmd.scmd.sc_offset = min; + head->ucmd.scmd.sc_max = max; + head->ucmd.scmd.sc_next = loc; +} + +static void +make_nswitch(head,count) +register CMD *head; +int count; +{ + register CMD *cur = head; + register CMD **loc; + register int i; + register int min = 32767; + register int max = -32768; + int origcount = count; + double value; /* or your money back! */ + short changed; /* so triple your money back! */ + + while (count--) { + i = (int)str_gnum(cur->c_short); + value = (double)i; + if (value != cur->c_short->str_u.str_nval) + return; /* fractional values--just forget it */ + changed = i; + if (changed != i) + return; /* too big for a short */ + if (cur->c_slen == O_LE) + i++; + else if (cur->c_slen == O_GE) /* we only do < or > here */ + i--; + if (i < min) + min = i; + if (i > max) + max = i; + cur = cur->c_next; + } + count = origcount; + if (max - min > count * 2 + 10) /* too sparse? */ + return; + + /* now make a new head in the exact same spot */ + New(104,cur, 1, CMD); + StructCopy(head,cur,CMD); + Zero(head,1,CMD); + head->c_head = cur->c_head; + head->c_type = C_NSWITCH; + head->c_next = cur; /* insert new cmd at front of list */ + head->c_stab = cur->c_stab; + + Newz(105,loc, max - min + 3, CMD*); + loc++; + max -= min; + max++; + while (count--) { + i = (int)str_gnum(cur->c_short); + i -= min; + switch(cur->c_slen) { + case O_LE: + i++; + case O_LT: + for (i--; i >= -1; i--) + if (!loc[i]) + loc[i] = cur; + break; + case O_GE: + i--; + case O_GT: + for (i++; i <= max; i++) + if (!loc[i]) + loc[i] = cur; + break; + case O_EQ: + if (!loc[i]) + loc[i] = cur; + break; + } + cur = cur->c_next; + } + loc--; + min--; + max++; + for (i = 0; i <= max; i++) + if (!loc[i]) + loc[i] = cur; + head->ucmd.scmd.sc_offset = min; + head->ucmd.scmd.sc_max = max; + head->ucmd.scmd.sc_next = loc; +} + +CMD * +append_line(head,tail) +register CMD *head; +register CMD *tail; +{ + if (tail == Nullcmd) + return head; + if (!tail->c_head) /* make sure tail is well formed */ + tail->c_head = tail; + if (head != Nullcmd) { + tail = tail->c_head; /* get to start of tail list */ + if (!head->c_head) + head->c_head = head; /* start a new head list */ + while (head->c_next) { + head->c_next->c_head = head->c_head; + head = head->c_next; /* get to end of head list */ + } + head->c_next = tail; /* link to end of old list */ + tail->c_head = head->c_head; /* propagate head pointer */ + } + while (tail->c_next) { + tail->c_next->c_head = tail->c_head; + tail = tail->c_next; + } + return tail; +} + +CMD * +dodb(cur) +CMD *cur; +{ + register CMD *cmd; + register CMD *head = cur->c_head; + STR *str; + + if (!head) + head = cur; + if (!head->c_line) + return cur; + str = afetch(stab_xarray(curcmd->c_filestab),(int)head->c_line,FALSE); + if (str == &str_undef || str->str_nok) + return cur; + str->str_u.str_nval = (double)head->c_line; + str->str_nok = 1; + Newz(106,cmd,1,CMD); + str_magic(str, curcmd->c_filestab, 0, Nullch, 0); + str->str_magic->str_u.str_cmd = cmd; + cmd->c_type = C_EXPR; + cmd->ucmd.acmd.ac_stab = Nullstab; + cmd->ucmd.acmd.ac_expr = Nullarg; + cmd->c_expr = make_op(O_SUBR, 2, + stab2arg(A_WORD,DBstab), + Nullarg, + Nullarg); + /*SUPPRESS 53*/ + cmd->c_flags |= CF_COND|CF_DBSUB|CFT_D0; + cmd->c_line = head->c_line; + cmd->c_label = head->c_label; + cmd->c_filestab = curcmd->c_filestab; + cmd->c_stash = curstash; + return append_line(cmd, cur); +} + +CMD * +make_acmd(type,stab,cond,arg) +int type; +STAB *stab; +ARG *cond; +ARG *arg; +{ + register CMD *cmd; + + Newz(107,cmd,1,CMD); + cmd->c_type = type; + cmd->ucmd.acmd.ac_stab = stab; + cmd->ucmd.acmd.ac_expr = arg; + cmd->c_expr = cond; + if (cond) + cmd->c_flags |= CF_COND; + if (cmdline == NOLINE) + cmd->c_line = curcmd->c_line; + else { + cmd->c_line = cmdline; + cmdline = NOLINE; + } + cmd->c_filestab = curcmd->c_filestab; + cmd->c_stash = curstash; + if (perldb) + cmd = dodb(cmd); + return cmd; +} + +CMD * +make_ccmd(type,debuggable,arg,cblock) +int type; +int debuggable; +ARG *arg; +struct compcmd cblock; +{ + register CMD *cmd; + + Newz(108,cmd, 1, CMD); + cmd->c_type = type; + cmd->c_expr = arg; + cmd->ucmd.ccmd.cc_true = cblock.comp_true; + cmd->ucmd.ccmd.cc_alt = cblock.comp_alt; + if (arg) + cmd->c_flags |= CF_COND; + if (cmdline == NOLINE) + cmd->c_line = curcmd->c_line; + else { + cmd->c_line = cmdline; + cmdline = NOLINE; + } + cmd->c_filestab = curcmd->c_filestab; + cmd->c_stash = curstash; + if (perldb && debuggable) + cmd = dodb(cmd); + return cmd; +} + +CMD * +make_icmd(type,arg,cblock) +int type; +ARG *arg; +struct compcmd cblock; +{ + register CMD *cmd; + register CMD *alt; + register CMD *cur; + register CMD *head; + struct compcmd ncblock; + + Newz(109,cmd, 1, CMD); + head = cmd; + cmd->c_type = type; + cmd->c_expr = arg; + cmd->ucmd.ccmd.cc_true = cblock.comp_true; + cmd->ucmd.ccmd.cc_alt = cblock.comp_alt; + if (arg) + cmd->c_flags |= CF_COND; + if (cmdline == NOLINE) + cmd->c_line = curcmd->c_line; + else { + cmd->c_line = cmdline; + cmdline = NOLINE; + } + cmd->c_filestab = curcmd->c_filestab; + cmd->c_stash = curstash; + cur = cmd; + alt = cblock.comp_alt; + while (alt && alt->c_type == C_ELSIF) { + cur = alt; + alt = alt->ucmd.ccmd.cc_alt; + } + if (alt) { /* a real life ELSE at the end? */ + ncblock.comp_true = alt; + ncblock.comp_alt = Nullcmd; + alt = append_line(cur,make_ccmd(C_ELSE,1,Nullarg,ncblock)); + cur->ucmd.ccmd.cc_alt = alt; + } + else + alt = cur; /* no ELSE, so cur is proxy ELSE */ + + cur = cmd; + while (cmd) { /* now point everyone at the ELSE */ + cur = cmd; + cmd = cur->ucmd.ccmd.cc_alt; + cur->c_head = head; + if (cur->c_type == C_ELSIF) + cur->c_type = C_IF; + if (cur->c_type == C_IF) + cur->ucmd.ccmd.cc_alt = alt; + if (cur == alt) + break; + cur->c_next = cmd; + } + if (perldb) + cur = dodb(cur); + return cur; +} + +void +opt_arg(cmd,fliporflop,acmd) +register CMD *cmd; +int fliporflop; +int acmd; +{ + register ARG *arg; + int opt = CFT_EVAL; + int sure = 0; + ARG *arg2; + int context = 0; /* 0 = normal, 1 = before &&, 2 = before || */ + int flp = fliporflop; + + if (!cmd) + return; + if (!(arg = cmd->c_expr)) { + cmd->c_flags &= ~CF_COND; + return; + } + + /* Can we turn && and || into if and unless? */ + + if (acmd && !cmd->ucmd.acmd.ac_expr && !(cmd->c_flags & CF_TERM) && + (arg->arg_type == O_AND || arg->arg_type == O_OR) ) { + dehoist(arg,1); + arg[2].arg_type &= A_MASK; /* don't suppress eval */ + dehoist(arg,2); + cmd->ucmd.acmd.ac_expr = arg[2].arg_ptr.arg_arg; + cmd->c_expr = arg[1].arg_ptr.arg_arg; + if (arg->arg_type == O_OR) + cmd->c_flags ^= CF_INVERT; /* || is like unless */ + arg->arg_len = 0; + free_arg(arg); + arg = cmd->c_expr; + } + + /* Turn "if (!expr)" into "unless (expr)" */ + + if (!(cmd->c_flags & CF_TERM)) { /* unless return value wanted */ + while (arg->arg_type == O_NOT) { + dehoist(arg,1); + cmd->c_flags ^= CF_INVERT; /* flip sense of cmd */ + cmd->c_expr = arg[1].arg_ptr.arg_arg; /* hoist the rest of expr */ + free_arg(arg); + arg = cmd->c_expr; /* here we go again */ + } + } + + if (!arg->arg_len) { /* sanity check */ + cmd->c_flags |= opt; + return; + } + + /* for "cond .. cond" we set up for the initial check */ + + if (arg->arg_type == O_FLIP) + context |= 4; + + /* for "cond && expr" and "cond || expr" we can ignore expr, sort of */ + + morecontext: + if (arg->arg_type == O_AND) + context |= 1; + else if (arg->arg_type == O_OR) + context |= 2; + if (context && (arg[flp].arg_type & A_MASK) == A_EXPR) { + arg = arg[flp].arg_ptr.arg_arg; + flp = 1; + if (arg->arg_type == O_AND || arg->arg_type == O_OR) + goto morecontext; + } + if ((context & 3) == 3) + return; + + if (arg[flp].arg_flags & (AF_PRE|AF_POST)) { + cmd->c_flags |= opt; + if (acmd && !cmd->ucmd.acmd.ac_expr && !(cmd->c_flags & CF_TERM) + && cmd->c_expr->arg_type == O_ITEM) { + arg[flp].arg_flags &= ~AF_POST; /* prefer ++$foo to $foo++ */ + arg[flp].arg_flags |= AF_PRE; /* if value not wanted */ + } + return; /* side effect, can't optimize */ + } + + if (arg->arg_type == O_ITEM || arg->arg_type == O_FLIP || + arg->arg_type == O_AND || arg->arg_type == O_OR) { + if ((arg[flp].arg_type & A_MASK) == A_SINGLE) { + opt = (str_true(arg[flp].arg_ptr.arg_str) ? CFT_TRUE : CFT_FALSE); + cmd->c_short = str_smake(arg[flp].arg_ptr.arg_str); + goto literal; + } + else if ((arg[flp].arg_type & A_MASK) == A_STAB || + (arg[flp].arg_type & A_MASK) == A_LVAL) { + cmd->c_stab = arg[flp].arg_ptr.arg_stab; + if (!context) + arg[flp].arg_ptr.arg_stab = Nullstab; + opt = CFT_REG; + literal: + if (!context) { /* no && or ||? */ + arg_free(arg); + cmd->c_expr = Nullarg; + } + if (!(context & 1)) + cmd->c_flags |= CF_EQSURE; + if (!(context & 2)) + cmd->c_flags |= CF_NESURE; + } + } + else if (arg->arg_type == O_MATCH || arg->arg_type == O_SUBST || + arg->arg_type == O_NMATCH || arg->arg_type == O_NSUBST) { + if ((arg[1].arg_type == A_STAB || arg[1].arg_type == A_LVAL) && + (arg[2].arg_type & A_MASK) == A_SPAT && + arg[2].arg_ptr.arg_spat->spat_short && + (arg->arg_type == O_SUBST || arg->arg_type == O_NSUBST || + (arg[2].arg_ptr.arg_spat->spat_flags & SPAT_GLOBAL) == 0 )) { + cmd->c_stab = arg[1].arg_ptr.arg_stab; + cmd->c_short = str_smake(arg[2].arg_ptr.arg_spat->spat_short); + cmd->c_slen = arg[2].arg_ptr.arg_spat->spat_slen; + if (arg[2].arg_ptr.arg_spat->spat_flags & SPAT_ALL && + !(arg[2].arg_ptr.arg_spat->spat_flags & SPAT_ONCE) && + (arg->arg_type == O_MATCH || arg->arg_type == O_NMATCH) ) + sure |= CF_EQSURE; /* (SUBST must be forced even */ + /* if we know it will work.) */ + if (arg->arg_type != O_SUBST) { + str_free(arg[2].arg_ptr.arg_spat->spat_short); + arg[2].arg_ptr.arg_spat->spat_short = Nullstr; + arg[2].arg_ptr.arg_spat->spat_slen = 0; /* only one chk */ + } + sure |= CF_NESURE; /* normally only sure if it fails */ + if (arg->arg_type == O_NMATCH || arg->arg_type == O_NSUBST) + cmd->c_flags |= CF_FIRSTNEG; + if (context & 1) { /* only sure if thing is false */ + if (cmd->c_flags & CF_FIRSTNEG) + sure &= ~CF_NESURE; + else + sure &= ~CF_EQSURE; + } + else if (context & 2) { /* only sure if thing is true */ + if (cmd->c_flags & CF_FIRSTNEG) + sure &= ~CF_EQSURE; + else + sure &= ~CF_NESURE; + } + if (sure & (CF_EQSURE|CF_NESURE)) { /* if we know anything*/ + if (arg[2].arg_ptr.arg_spat->spat_flags & SPAT_SCANFIRST) + opt = CFT_SCAN; + else + opt = CFT_ANCHOR; + if (sure == (CF_EQSURE|CF_NESURE) /* really sure? */ + && arg->arg_type == O_MATCH + && context & 4 + && fliporflop == 1) { + spat_free(arg[2].arg_ptr.arg_spat); + arg[2].arg_ptr.arg_spat = Nullspat; /* don't do twice */ + } + else + cmd->c_spat = arg[2].arg_ptr.arg_spat; + cmd->c_flags |= sure; + } + } + } + else if (arg->arg_type == O_SEQ || arg->arg_type == O_SNE || + arg->arg_type == O_SLT || arg->arg_type == O_SGT) { + if (arg[1].arg_type == A_STAB || arg[1].arg_type == A_LVAL) { + if (arg[2].arg_type == A_SINGLE) { + /*SUPPRESS 594*/ + char *junk = str_get(arg[2].arg_ptr.arg_str); + + cmd->c_stab = arg[1].arg_ptr.arg_stab; + cmd->c_short = str_smake(arg[2].arg_ptr.arg_str); + cmd->c_slen = cmd->c_short->str_cur+1; + switch (arg->arg_type) { + case O_SLT: case O_SGT: + sure |= CF_EQSURE; + cmd->c_flags |= CF_FIRSTNEG; + break; + case O_SNE: + cmd->c_flags |= CF_FIRSTNEG; + /* FALL THROUGH */ + case O_SEQ: + sure |= CF_NESURE|CF_EQSURE; + break; + } + if (context & 1) { /* only sure if thing is false */ + if (cmd->c_flags & CF_FIRSTNEG) + sure &= ~CF_NESURE; + else + sure &= ~CF_EQSURE; + } + else if (context & 2) { /* only sure if thing is true */ + if (cmd->c_flags & CF_FIRSTNEG) + sure &= ~CF_EQSURE; + else + sure &= ~CF_NESURE; + } + if (sure & (CF_EQSURE|CF_NESURE)) { + opt = CFT_STROP; + cmd->c_flags |= sure; + } + } + } + } + else if (arg->arg_type == O_EQ || arg->arg_type == O_NE || + arg->arg_type == O_LE || arg->arg_type == O_GE || + arg->arg_type == O_LT || arg->arg_type == O_GT) { + if (arg[1].arg_type == A_STAB || arg[1].arg_type == A_LVAL) { + if (arg[2].arg_type == A_SINGLE) { + cmd->c_stab = arg[1].arg_ptr.arg_stab; + if (dowarn) { + STR *str = arg[2].arg_ptr.arg_str; + + if ((!str->str_nok && !looks_like_number(str))) + warn("Possible use of == on string value"); + } + cmd->c_short = str_nmake(str_gnum(arg[2].arg_ptr.arg_str)); + cmd->c_slen = arg->arg_type; + sure |= CF_NESURE|CF_EQSURE; + if (context & 1) { /* only sure if thing is false */ + sure &= ~CF_EQSURE; + } + else if (context & 2) { /* only sure if thing is true */ + sure &= ~CF_NESURE; + } + if (sure & (CF_EQSURE|CF_NESURE)) { + opt = CFT_NUMOP; + cmd->c_flags |= sure; + } + } + } + } + else if (arg->arg_type == O_ASSIGN && + (arg[1].arg_type == A_STAB || arg[1].arg_type == A_LVAL) && + arg[1].arg_ptr.arg_stab == defstab && + arg[2].arg_type == A_EXPR ) { + arg2 = arg[2].arg_ptr.arg_arg; + if (arg2->arg_type == O_ITEM && arg2[1].arg_type == A_READ) { + opt = CFT_GETS; + cmd->c_stab = arg2[1].arg_ptr.arg_stab; + if (!(stab_io(arg2[1].arg_ptr.arg_stab)->flags & IOF_ARGV)) { + free_arg(arg2); + arg[2].arg_ptr.arg_arg = Nullarg; + free_arg(arg); + cmd->c_expr = Nullarg; + } + } + } + else if (arg->arg_type == O_CHOP && + (arg[1].arg_type == A_STAB || arg[1].arg_type == A_LVAL) ) { + opt = CFT_CHOP; + cmd->c_stab = arg[1].arg_ptr.arg_stab; + free_arg(arg); + cmd->c_expr = Nullarg; + } + if (context & 4) + opt |= CF_FLIP; + cmd->c_flags |= opt; + + if (cmd->c_flags & CF_FLIP) { + if (fliporflop == 1) { + arg = cmd->c_expr; /* get back to O_FLIP arg */ + New(110,arg[3].arg_ptr.arg_cmd, 1, CMD); + Copy(cmd, arg[3].arg_ptr.arg_cmd, 1, CMD); + New(111,arg[4].arg_ptr.arg_cmd,1,CMD); + Copy(cmd, arg[4].arg_ptr.arg_cmd, 1, CMD); + opt_arg(arg[4].arg_ptr.arg_cmd,2,acmd); + arg->arg_len = 2; /* this is a lie */ + } + else { + if ((opt & CF_OPTIMIZE) == CFT_EVAL) + cmd->c_flags = (cmd->c_flags & ~CF_OPTIMIZE) | CFT_UNFLIP; + } + } +} + +CMD * +add_label(lbl,cmd) +char *lbl; +register CMD *cmd; +{ + if (cmd) + cmd->c_label = lbl; + return cmd; +} + +CMD * +addcond(cmd, arg) +register CMD *cmd; +register ARG *arg; +{ + cmd->c_expr = arg; + cmd->c_flags |= CF_COND; + return cmd; +} + +CMD * +addloop(cmd, arg) +register CMD *cmd; +register ARG *arg; +{ + void while_io(); + + cmd->c_expr = arg; + cmd->c_flags |= CF_COND|CF_LOOP; + + if (!(cmd->c_flags & CF_INVERT)) + while_io(cmd); /* add $_ =, if necessary */ + + if (cmd->c_type == C_BLOCK) + cmd->c_flags &= ~CF_COND; + else { + arg = cmd->ucmd.acmd.ac_expr; + if (arg && arg->arg_type == O_ITEM && arg[1].arg_type == A_CMD) + cmd->c_flags &= ~CF_COND; /* "do {} while" happens at least once */ + if (arg && (arg->arg_flags & AF_DEPR) && + (arg->arg_type == O_SUBR || arg->arg_type == O_DBSUBR) ) + cmd->c_flags &= ~CF_COND; /* likewise for "do subr() while" */ + } + return cmd; +} + +CMD * +invert(cmd) +CMD *cmd; +{ + register CMD *targ = cmd; + if (targ->c_head) + targ = targ->c_head; + if (targ->c_flags & CF_DBSUB) + targ = targ->c_next; + targ->c_flags ^= CF_INVERT; + return cmd; +} + +void +cpy7bit(d,s,l) +register char *d; +register char *s; +register int l; +{ + while (l--) + *d++ = *s++ & 127; + *d = '\0'; +} + +int +yyerror(s) +char *s; +{ + char tmpbuf[258]; + char tmp2buf[258]; + char *tname = tmpbuf; + + if (bufptr > oldoldbufptr && bufptr - oldoldbufptr < 200 && + oldoldbufptr != oldbufptr && oldbufptr != bufptr) { + while (isSPACE(*oldoldbufptr)) + oldoldbufptr++; + cpy7bit(tmp2buf, oldoldbufptr, bufptr - oldoldbufptr); + sprintf(tname,"next 2 tokens \"%s\"",tmp2buf); + } + else if (bufptr > oldbufptr && bufptr - oldbufptr < 200 && + oldbufptr != bufptr) { + while (isSPACE(*oldbufptr)) + oldbufptr++; + cpy7bit(tmp2buf, oldbufptr, bufptr - oldbufptr); + sprintf(tname,"next token \"%s\"",tmp2buf); + } + else if (yychar > 256) + tname = "next token ???"; + else if (!yychar) + (void)strcpy(tname,"at EOF"); + else if (yychar < 32) + (void)sprintf(tname,"next char ^%c",yychar+64); + else if (yychar == 127) + (void)strcpy(tname,"at EOF"); + else + (void)sprintf(tname,"next char %c",yychar); + (void)sprintf(buf, "%s in file %s at line %d, %s\n", + s,stab_val(curcmd->c_filestab)->str_ptr,curcmd->c_line,tname); + if (curcmd->c_line == multi_end && multi_start < multi_end) + sprintf(buf+strlen(buf), + " (Might be a runaway multi-line %c%c string starting on line %d)\n", + multi_open,multi_close,multi_start); + if (in_eval) + str_cat(stab_val(stabent("@",TRUE)),buf); + else + fputs(buf,stderr); + if (++error_count >= 10) + fatal("%s has too many errors.\n", + stab_val(curcmd->c_filestab)->str_ptr); +} + +void +while_io(cmd) +register CMD *cmd; +{ + register ARG *arg = cmd->c_expr; + STAB *asgnstab; + + /* hoist "while (<channel>)" up into command block */ + + if (arg && arg->arg_type == O_ITEM && arg[1].arg_type == A_READ) { + cmd->c_flags &= ~CF_OPTIMIZE; /* clear optimization type */ + cmd->c_flags |= CFT_GETS; /* and set it to do the input */ + cmd->c_stab = arg[1].arg_ptr.arg_stab; + if (stab_io(arg[1].arg_ptr.arg_stab)->flags & IOF_ARGV) { + cmd->c_expr = l(make_op(O_ASSIGN, 2, /* fake up "$_ =" */ + stab2arg(A_LVAL,defstab), arg, Nullarg)); + } + else { + free_arg(arg); + cmd->c_expr = Nullarg; + } + } + else if (arg && arg->arg_type == O_ITEM && arg[1].arg_type == A_INDREAD) { + cmd->c_flags &= ~CF_OPTIMIZE; /* clear optimization type */ + cmd->c_flags |= CFT_INDGETS; /* and set it to do the input */ + cmd->c_stab = arg[1].arg_ptr.arg_stab; + free_arg(arg); + cmd->c_expr = Nullarg; + } + else if (arg && arg->arg_type == O_ITEM && arg[1].arg_type == A_GLOB) { + if ((cmd->c_flags & CF_OPTIMIZE) == CFT_ARRAY) + asgnstab = cmd->c_stab; + else + asgnstab = defstab; + cmd->c_expr = l(make_op(O_ASSIGN, 2, /* fake up "$foo =" */ + stab2arg(A_LVAL,asgnstab), arg, Nullarg)); + cmd->c_flags &= ~CF_OPTIMIZE; /* clear optimization type */ + } +} + +CMD * +wopt(cmd) +register CMD *cmd; +{ + register CMD *tail; + CMD *newtail; + register int i; + + if (cmd->c_expr && (cmd->c_flags & CF_OPTIMIZE) == CFT_FALSE) + opt_arg(cmd,1, cmd->c_type == C_EXPR); + + while_io(cmd); /* add $_ =, if necessary */ + + /* First find the end of the true list */ + + tail = cmd->ucmd.ccmd.cc_true; + if (tail == Nullcmd) + return cmd; + New(112,newtail, 1, CMD); /* guaranteed continue */ + for (;;) { + /* optimize "next" to point directly to continue block */ + if (tail->c_type == C_EXPR && + tail->ucmd.acmd.ac_expr && + tail->ucmd.acmd.ac_expr->arg_type == O_NEXT && + (tail->ucmd.acmd.ac_expr->arg_len == 0 || + (cmd->c_label && + strEQ(cmd->c_label, + tail->ucmd.acmd.ac_expr[1].arg_ptr.arg_str->str_ptr) ))) + { + arg_free(tail->ucmd.acmd.ac_expr); + tail->ucmd.acmd.ac_expr = Nullarg; + tail->c_type = C_NEXT; + if (cmd->ucmd.ccmd.cc_alt != Nullcmd) + tail->ucmd.ccmd.cc_alt = cmd->ucmd.ccmd.cc_alt; + else + tail->ucmd.ccmd.cc_alt = newtail; + tail->ucmd.ccmd.cc_true = Nullcmd; + } + else if (tail->c_type == C_IF && !tail->ucmd.ccmd.cc_alt) { + if (cmd->ucmd.ccmd.cc_alt != Nullcmd) + tail->ucmd.ccmd.cc_alt = cmd->ucmd.ccmd.cc_alt; + else + tail->ucmd.ccmd.cc_alt = newtail; + } + else if (tail->c_type == C_CSWITCH || tail->c_type == C_NSWITCH) { + if (cmd->ucmd.ccmd.cc_alt != Nullcmd) { + for (i = tail->ucmd.scmd.sc_max; i >= 0; i--) + if (!tail->ucmd.scmd.sc_next[i]) + tail->ucmd.scmd.sc_next[i] = cmd->ucmd.ccmd.cc_alt; + } + else { + for (i = tail->ucmd.scmd.sc_max; i >= 0; i--) + if (!tail->ucmd.scmd.sc_next[i]) + tail->ucmd.scmd.sc_next[i] = newtail; + } + } + + if (!tail->c_next) + break; + tail = tail->c_next; + } + + /* if there's a continue block, link it to true block and find end */ + + if (cmd->ucmd.ccmd.cc_alt != Nullcmd) { + tail->c_next = cmd->ucmd.ccmd.cc_alt; + tail = tail->c_next; + for (;;) { + /* optimize "next" to point directly to continue block */ + if (tail->c_type == C_EXPR && + tail->ucmd.acmd.ac_expr && + tail->ucmd.acmd.ac_expr->arg_type == O_NEXT && + (tail->ucmd.acmd.ac_expr->arg_len == 0 || + (cmd->c_label && + strEQ(cmd->c_label, + tail->ucmd.acmd.ac_expr[1].arg_ptr.arg_str->str_ptr) ))) + { + arg_free(tail->ucmd.acmd.ac_expr); + tail->ucmd.acmd.ac_expr = Nullarg; + tail->c_type = C_NEXT; + tail->ucmd.ccmd.cc_alt = newtail; + tail->ucmd.ccmd.cc_true = Nullcmd; + } + else if (tail->c_type == C_IF && !tail->ucmd.ccmd.cc_alt) { + tail->ucmd.ccmd.cc_alt = newtail; + } + else if (tail->c_type == C_CSWITCH || tail->c_type == C_NSWITCH) { + for (i = tail->ucmd.scmd.sc_max; i >= 0; i--) + if (!tail->ucmd.scmd.sc_next[i]) + tail->ucmd.scmd.sc_next[i] = newtail; + } + + if (!tail->c_next) + break; + tail = tail->c_next; + } + /*SUPPRESS 530*/ + for ( ; tail->c_next; tail = tail->c_next) ; + } + + /* Here's the real trick: link the end of the list back to the beginning, + * inserting a "last" block to break out of the loop. This saves one or + * two procedure calls every time through the loop, because of how cmd_exec + * does tail recursion. + */ + + tail->c_next = newtail; + tail = newtail; + if (!cmd->ucmd.ccmd.cc_alt) + cmd->ucmd.ccmd.cc_alt = tail; /* every loop has a continue now */ + +#ifndef lint + Copy((char *)cmd, (char *)tail, 1, CMD); +#endif + tail->c_type = C_EXPR; + tail->c_flags ^= CF_INVERT; /* turn into "last unless" */ + tail->c_next = tail->ucmd.ccmd.cc_true; /* loop directly back to top */ + tail->ucmd.acmd.ac_expr = make_op(O_LAST,0,Nullarg,Nullarg,Nullarg); + tail->ucmd.acmd.ac_stab = Nullstab; + return cmd; +} + +CMD * +over(eachstab,cmd) +STAB *eachstab; +register CMD *cmd; +{ + /* hoist "for $foo (@bar)" up into command block */ + + cmd->c_flags &= ~CF_OPTIMIZE; /* clear optimization type */ + cmd->c_flags |= CFT_ARRAY; /* and set it to do the iteration */ + cmd->c_stab = eachstab; + cmd->c_short = Str_new(23,0); /* just to save a field in struct cmd */ + cmd->c_short->str_u.str_useful = -1; + + return cmd; +} + +void +cmd_free(cmd) +register CMD *cmd; +{ + register CMD *tofree; + register CMD *head = cmd; + + if (!cmd) + return; + if (cmd->c_head != cmd) + warn("Malformed cmd links\n"); + while (cmd) { + if (cmd->c_type != C_WHILE) { /* WHILE block is duplicated */ + if (cmd->c_label) { + Safefree(cmd->c_label); + cmd->c_label = Nullch; + } + if (cmd->c_short) { + str_free(cmd->c_short); + cmd->c_short = Nullstr; + } + if (cmd->c_expr) { + arg_free(cmd->c_expr); + cmd->c_expr = Nullarg; + } + } + switch (cmd->c_type) { + case C_WHILE: + case C_BLOCK: + case C_ELSE: + case C_IF: + if (cmd->ucmd.ccmd.cc_true) { + cmd_free(cmd->ucmd.ccmd.cc_true); + cmd->ucmd.ccmd.cc_true = Nullcmd; + } + break; + case C_EXPR: + if (cmd->ucmd.acmd.ac_expr) { + arg_free(cmd->ucmd.acmd.ac_expr); + cmd->ucmd.acmd.ac_expr = Nullarg; + } + break; + } + tofree = cmd; + cmd = cmd->c_next; + if (tofree != head) /* to get Saber to shut up */ + Safefree(tofree); + if (cmd && cmd == head) /* reached end of while loop */ + break; + } + Safefree(head); +} + +void +arg_free(arg) +register ARG *arg; +{ + register int i; + + if (!arg) + return; + for (i = 1; i <= arg->arg_len; i++) { + switch (arg[i].arg_type & A_MASK) { + case A_NULL: + if (arg->arg_type == O_TRANS) { + Safefree(arg[i].arg_ptr.arg_cval); + arg[i].arg_ptr.arg_cval = Nullch; + } + break; + case A_LEXPR: + if (arg->arg_type == O_AASSIGN && + arg[i].arg_ptr.arg_arg->arg_type == O_LARRAY) { + char *name = + stab_name(arg[i].arg_ptr.arg_arg[1].arg_ptr.arg_stab); + + if (strnEQ("_GEN_",name, 5)) /* array for foreach */ + hdelete(defstash,name,strlen(name)); + } + /* FALL THROUGH */ + case A_EXPR: + arg_free(arg[i].arg_ptr.arg_arg); + arg[i].arg_ptr.arg_arg = Nullarg; + break; + case A_CMD: + cmd_free(arg[i].arg_ptr.arg_cmd); + arg[i].arg_ptr.arg_cmd = Nullcmd; + break; + case A_WORD: + case A_STAB: + case A_LVAL: + case A_READ: + case A_GLOB: + case A_ARYLEN: + case A_LARYLEN: + case A_ARYSTAB: + case A_LARYSTAB: + break; + case A_SINGLE: + case A_DOUBLE: + case A_BACKTICK: + str_free(arg[i].arg_ptr.arg_str); + arg[i].arg_ptr.arg_str = Nullstr; + break; + case A_SPAT: + spat_free(arg[i].arg_ptr.arg_spat); + arg[i].arg_ptr.arg_spat = Nullspat; + break; + } + } + free_arg(arg); +} + +void +spat_free(spat) +register SPAT *spat; +{ + register SPAT *sp; + HENT *entry; + + if (!spat) + return; + if (spat->spat_runtime) { + arg_free(spat->spat_runtime); + spat->spat_runtime = Nullarg; + } + if (spat->spat_repl) { + arg_free(spat->spat_repl); + spat->spat_repl = Nullarg; + } + if (spat->spat_short) { + str_free(spat->spat_short); + spat->spat_short = Nullstr; + } + if (spat->spat_regexp) { + regfree(spat->spat_regexp); + spat->spat_regexp = Null(REGEXP*); + } + + /* now unlink from spat list */ + + for (entry = defstash->tbl_array['_']; entry; entry = entry->hent_next) { + register HASH *stash; + STAB *stab = (STAB*)entry->hent_val; + + if (!stab) + continue; + stash = stab_hash(stab); + if (!stash || stash->tbl_spatroot == Null(SPAT*)) + continue; + if (stash->tbl_spatroot == spat) + stash->tbl_spatroot = spat->spat_next; + else { + for (sp = stash->tbl_spatroot; + sp && sp->spat_next != spat; + sp = sp->spat_next) + /*SUPPRESS 530*/ + ; + if (sp) + sp->spat_next = spat->spat_next; + } + } + Safefree(spat); +} + +/* Recursively descend a command sequence and push the address of any string + * that needs saving on recursion onto the tosave array. + */ + +static int +cmd_tosave(cmd,willsave) +register CMD *cmd; +int willsave; /* willsave passes down the tree */ +{ + register CMD *head = cmd; + int shouldsave = FALSE; /* shouldsave passes up the tree */ + int tmpsave; + register CMD *lastcmd = Nullcmd; + + while (cmd) { + if (cmd->c_expr) + shouldsave |= arg_tosave(cmd->c_expr,willsave); + switch (cmd->c_type) { + case C_WHILE: + if (cmd->ucmd.ccmd.cc_true) { + tmpsave = cmd_tosave(cmd->ucmd.ccmd.cc_true,willsave); + + /* Here we check to see if the temporary array generated for + * a foreach needs to be localized because of recursion. + */ + if (tmpsave && (cmd->c_flags & CF_OPTIMIZE) == CFT_ARRAY) { + if (lastcmd && + lastcmd->c_type == C_EXPR && + lastcmd->c_expr) { + ARG *arg = lastcmd->c_expr; + + if (arg->arg_type == O_ASSIGN && + arg[1].arg_type == A_LEXPR && + arg[1].arg_ptr.arg_arg->arg_type == O_LARRAY && + strnEQ("_GEN_", + stab_name( + arg[1].arg_ptr.arg_arg[1].arg_ptr.arg_stab), + 5)) { /* array generated for foreach */ + (void)localize(arg); + } + } + + /* in any event, save the iterator */ + + (void)apush(tosave,cmd->c_short); + } + shouldsave |= tmpsave; + } + break; + case C_BLOCK: + case C_ELSE: + case C_IF: + if (cmd->ucmd.ccmd.cc_true) + shouldsave |= cmd_tosave(cmd->ucmd.ccmd.cc_true,willsave); + break; + case C_EXPR: + if (cmd->ucmd.acmd.ac_expr) + shouldsave |= arg_tosave(cmd->ucmd.acmd.ac_expr,willsave); + break; + } + lastcmd = cmd; + cmd = cmd->c_next; + if (cmd && cmd == head) /* reached end of while loop */ + break; + } + return shouldsave; +} + +static int +arg_tosave(arg,willsave) +register ARG *arg; +int willsave; +{ + register int i; + int shouldsave = FALSE; + + for (i = arg->arg_len; i >= 1; i--) { + switch (arg[i].arg_type & A_MASK) { + case A_NULL: + break; + case A_LEXPR: + case A_EXPR: + shouldsave |= arg_tosave(arg[i].arg_ptr.arg_arg,shouldsave); + break; + case A_CMD: + shouldsave |= cmd_tosave(arg[i].arg_ptr.arg_cmd,shouldsave); + break; + case A_WORD: + case A_STAB: + case A_LVAL: + case A_READ: + case A_GLOB: + case A_ARYLEN: + case A_SINGLE: + case A_DOUBLE: + case A_BACKTICK: + break; + case A_SPAT: + shouldsave |= spat_tosave(arg[i].arg_ptr.arg_spat); + break; + } + } + switch (arg->arg_type) { + case O_RETURN: + saw_return = TRUE; + break; + case O_EVAL: + case O_SUBR: + shouldsave = TRUE; + break; + } + if (willsave) + (void)apush(tosave,arg->arg_ptr.arg_str); + return shouldsave; +} + +static int +spat_tosave(spat) +register SPAT *spat; +{ + int shouldsave = FALSE; + + if (spat->spat_runtime) + shouldsave |= arg_tosave(spat->spat_runtime,FALSE); + if (spat->spat_repl) { + shouldsave |= arg_tosave(spat->spat_repl,FALSE); + } + + return shouldsave; +} + |