📄 cmd.c
字号:
/* $RCSfile: cmd.c,v $$Revision: 4.0.1.5 $$Date: 92/06/08 12:00:39 $ * * 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: cmd.c,v $ * Revision 4.0.1.5 92/06/08 12:00:39 lwall * patch20: the switch optimizer didn't do anything in subroutines * patch20: removed implicit int declarations on funcions * * Revision 4.0.1.4 91/11/11 16:29:33 lwall * patch19: do {$foo ne "bar";} returned wrong value * patch19: some earlier patches weren't propagated to alternate 286 code * * Revision 4.0.1.3 91/11/05 16:07:43 lwall * patch11: random cleanup * patch11: "foo\0" eq "foo" was sometimes optimized to true * patch11: foreach on null list could spring memory leak * * Revision 4.0.1.2 91/06/07 10:26:45 lwall * patch4: new copyright notice * patch4: made some allowances for "semi-standard" C * * Revision 4.0.1.1 91/04/11 17:36:16 lwall * patch1: you may now use "die" and "caller" in a signal handler * * Revision 4.0 91/03/20 01:04:18 lwall * 4.0 baseline. * */#include "EXTERN.h"#include "perl.h"#ifdef I_VARARGS# include <varargs.h>#endifstatic STR strchop;void grow_dlevel();/* do longjmps() clobber register variables? */#if defined(cray) || defined(STANDARD_C)#define JMPCLOBBER#endif/* This is the main command loop. We try to spend as much time in this loop * as possible, so lots of optimizations do their activities in here. This * means things get a little sloppy. */intcmd_exec(cmdparm,gimme,sp)CMD *VOLATILE cmdparm;VOLATILE int gimme;VOLATILE int sp;{ register CMD *cmd = cmdparm; SPAT *VOLATILE oldspat; VOLATILE int firstsave = savestack->ary_fill; VOLATILE int oldsave; VOLATILE int aryoptsave;#ifdef DEBUGGING VOLATILE int olddlevel; VOLATILE int entdlevel;#endif register STR *retstr = &str_undef; register char *tmps; register int cmdflags; register int match; register char *go_to = goto_targ; register int newsp = -2; register STR **st = stack->ary_array; FILE *VOLATILE fp; ARRAY *VOLATILE ar; lastsize = 0;#ifdef DEBUGGING entdlevel = dlevel;#endiftail_recursion_entry:#ifdef DEBUGGING dlevel = entdlevel; if (debug & 4) deb("mortals = (%d/%d) stack, = (%d/%d)\n", tmps_max, tmps_base, savestack->ary_fill, firstsave);#endif#ifdef TAINT tainted = 0; /* Each statement is presumed innocent */#endif if (cmd == Nullcmd) { if (gimme == G_ARRAY && newsp > -2) return newsp; else { st[++sp] = retstr; return sp; } } cmdflags = cmd->c_flags; /* hopefully load register */ if (go_to) { if (cmd->c_label && strEQ(go_to,cmd->c_label)) goto_targ = go_to = Nullch; /* here at last */ else { switch (cmd->c_type) { case C_IF: oldspat = curspat; oldsave = savestack->ary_fill;#ifdef DEBUGGING olddlevel = dlevel;#endif retstr = &str_yes; newsp = -2; if (cmd->ucmd.ccmd.cc_true) {#ifdef DEBUGGING if (debug) { debname[dlevel] = 't'; debdelim[dlevel] = '_'; if (++dlevel >= dlmax) grow_dlevel(); }#endif newsp = cmd_exec(cmd->ucmd.ccmd.cc_true,gimme && (cmdflags & CF_TERM),sp); st = stack->ary_array; /* possibly reallocated */ retstr = st[newsp]; } if (!goto_targ) go_to = Nullch; curspat = oldspat; if (savestack->ary_fill > oldsave) restorelist(oldsave);#ifdef DEBUGGING dlevel = olddlevel;#endif cmd = cmd->ucmd.ccmd.cc_alt; goto tail_recursion_entry; case C_ELSE: oldspat = curspat; oldsave = savestack->ary_fill;#ifdef DEBUGGING olddlevel = dlevel;#endif retstr = &str_undef; newsp = -2; if (cmd->ucmd.ccmd.cc_true) {#ifdef DEBUGGING if (debug) { debname[dlevel] = 'e'; debdelim[dlevel] = '_'; if (++dlevel >= dlmax) grow_dlevel(); }#endif newsp = cmd_exec(cmd->ucmd.ccmd.cc_true,gimme && (cmdflags & CF_TERM),sp); st = stack->ary_array; /* possibly reallocated */ retstr = st[newsp]; } if (!goto_targ) go_to = Nullch; curspat = oldspat; if (savestack->ary_fill > oldsave) restorelist(oldsave);#ifdef DEBUGGING dlevel = olddlevel;#endif break; case C_BLOCK: case C_WHILE: if (!(cmdflags & CF_ONCE)) { cmdflags |= CF_ONCE; if (++loop_ptr >= loop_max) { loop_max += 128; Renew(loop_stack, loop_max, struct loop); } loop_stack[loop_ptr].loop_label = cmd->c_label; loop_stack[loop_ptr].loop_sp = sp;#ifdef DEBUGGING if (debug & 4) { deb("(Pushing label #%d %s)\n", loop_ptr, cmd->c_label ? cmd->c_label : ""); }#endif }#ifdef JMPCLOBBER cmdparm = cmd;#endif match = setjmp(loop_stack[loop_ptr].loop_env); if (match) { st = stack->ary_array; /* possibly reallocated */#ifdef JMPCLOBBER cmd = cmdparm; cmdflags = cmd->c_flags|CF_ONCE;#endif if (savestack->ary_fill > oldsave) restorelist(oldsave); switch (match) { default: fatal("longjmp returned bad value (%d)",match); case O_LAST: /* not done unless go_to found */ go_to = Nullch; if (lastretstr) { retstr = lastretstr; newsp = -2; } else { newsp = sp + lastsize; retstr = st[newsp]; }#ifdef DEBUGGING olddlevel = dlevel;#endif curspat = oldspat; goto next_cmd; case O_NEXT: /* not done unless go_to found */ go_to = Nullch;#ifdef JMPCLOBBER newsp = -2; retstr = &str_undef;#endif goto next_iter; case O_REDO: /* not done unless go_to found */ go_to = Nullch;#ifdef JMPCLOBBER newsp = -2; retstr = &str_undef;#endif goto doit; } } oldspat = curspat; oldsave = savestack->ary_fill;#ifdef DEBUGGING olddlevel = dlevel;#endif if (cmd->ucmd.ccmd.cc_true) {#ifdef DEBUGGING if (debug) { debname[dlevel] = 't'; debdelim[dlevel] = '_'; if (++dlevel >= dlmax) grow_dlevel(); }#endif newsp = cmd_exec(cmd->ucmd.ccmd.cc_true,gimme && (cmdflags & CF_TERM),sp); st = stack->ary_array; /* possibly reallocated */ if (newsp >= 0) retstr = st[newsp]; } if (!goto_targ) { go_to = Nullch; goto next_iter; }#ifdef DEBUGGING dlevel = olddlevel;#endif if (cmd->ucmd.ccmd.cc_alt) {#ifdef DEBUGGING if (debug) { debname[dlevel] = 'a'; debdelim[dlevel] = '_'; if (++dlevel >= dlmax) grow_dlevel(); }#endif newsp = cmd_exec(cmd->ucmd.ccmd.cc_alt,gimme && (cmdflags & CF_TERM),sp); st = stack->ary_array; /* possibly reallocated */ if (newsp >= 0) retstr = st[newsp]; } if (goto_targ) break; go_to = Nullch; goto finish_while; } cmd = cmd->c_next; if (cmd && cmd->c_head == cmd) /* reached end of while loop */ return sp; /* targ isn't in this block */ if (cmdflags & CF_ONCE) {#ifdef DEBUGGING if (debug & 4) { tmps = loop_stack[loop_ptr].loop_label; deb("(Popping label #%d %s)\n",loop_ptr, tmps ? tmps : "" ); }#endif loop_ptr--; } goto tail_recursion_entry; } }until_loop: /* Set line number so run-time errors can be located */ curcmd = cmd;#ifdef DEBUGGING if (debug) { if (debug & 2) { deb("%s (%lx) r%lx t%lx a%lx n%lx cs%lx\n", cmdname[cmd->c_type],cmd,cmd->c_expr, cmd->ucmd.ccmd.cc_true,cmd->ucmd.ccmd.cc_alt,cmd->c_next, curspat); } debname[dlevel] = cmdname[cmd->c_type][0]; debdelim[dlevel] = '!'; if (++dlevel >= dlmax) grow_dlevel(); }#endif /* Here is some common optimization */ if (cmdflags & CF_COND) { switch (cmdflags & CF_OPTIMIZE) { case CFT_FALSE: retstr = cmd->c_short; newsp = -2; match = FALSE; if (cmdflags & CF_NESURE) goto maybe; break; case CFT_TRUE: retstr = cmd->c_short; newsp = -2; match = TRUE; if (cmdflags & CF_EQSURE) goto flipmaybe; break; case CFT_REG: retstr = STAB_STR(cmd->c_stab); newsp = -2; match = str_true(retstr); /* => retstr = retstr, c2 should fix */ if (cmdflags & (match ? CF_EQSURE : CF_NESURE)) goto flipmaybe; break; case CFT_ANCHOR: /* /^pat/ optimization */ if (multiline) { if (*cmd->c_short->str_ptr && !(cmdflags & CF_EQSURE)) goto scanner; /* just unanchor it */ else break; /* must evaluate */ } match = 0; goto strop; case CFT_STROP: /* string op optimization */ match = 1; strop: retstr = STAB_STR(cmd->c_stab); newsp = -2;#ifndef I286 if (*cmd->c_short->str_ptr == *str_get(retstr) && (match ? retstr->str_cur == cmd->c_slen - 1 : retstr->str_cur >= cmd->c_slen) && bcmp(cmd->c_short->str_ptr, str_get(retstr), cmd->c_slen) == 0 ) { if (cmdflags & CF_EQSURE) { if (sawampersand && (cmdflags & CF_OPTIMIZE) != CFT_STROP) { curspat = Nullspat; if (leftstab) str_nset(stab_val(leftstab),"",0); if (amperstab) str_sset(stab_val(amperstab),cmd->c_short); if (rightstab) str_nset(stab_val(rightstab), retstr->str_ptr + cmd->c_slen, retstr->str_cur - cmd->c_slen); } if (cmd->c_spat) lastspat = cmd->c_spat; match = !(cmdflags & CF_FIRSTNEG); retstr = match ? &str_yes : &str_no; goto flipmaybe; } } else if (cmdflags & CF_NESURE) { match = cmdflags & CF_FIRSTNEG; retstr = match ? &str_yes : &str_no; goto flipmaybe; }#else { char *zap1, *zap2, zap1c, zap2c; int zaplen; int lenok; zap1 = cmd->c_short->str_ptr; zap2 = str_get(retstr); zap1c = *zap1; zap2c = *zap2; zaplen = cmd->c_slen; if (match) lenok = (retstr->str_cur == cmd->c_slen - 1); else lenok = (retstr->str_cur >= cmd->c_slen); if ((zap1c == zap2c) && lenok && (bcmp(zap1, zap2, zaplen) == 0)) { if (cmdflags & CF_EQSURE) { if (sawampersand && (cmdflags & CF_OPTIMIZE) != CFT_STROP) { curspat = Nullspat; if (leftstab) str_nset(stab_val(leftstab),"",0); if (amperstab) str_sset(stab_val(amperstab),cmd->c_short); if (rightstab) str_nset(stab_val(rightstab), retstr->str_ptr + cmd->c_slen, retstr->str_cur - cmd->c_slen); } if (cmd->c_spat) lastspat = cmd->c_spat; match = !(cmdflags & CF_FIRSTNEG); retstr = match ? &str_yes : &str_no; goto flipmaybe; } } else if (cmdflags & CF_NESURE) { match = cmdflags & CF_FIRSTNEG; retstr = match ? &str_yes : &str_no; goto flipmaybe; } }#endif break; /* must evaluate */ case CFT_SCAN: /* non-anchored search */ scanner: retstr = STAB_STR(cmd->c_stab); newsp = -2; if (retstr->str_pok & SP_STUDIED) if (screamfirst[cmd->c_short->str_rare] >= 0) tmps = screaminstr(retstr, cmd->c_short); else tmps = Nullch; else { tmps = str_get(retstr); /* make sure it's pok */#ifndef lint tmps = fbminstr((unsigned char*)tmps, (unsigned char*)tmps + retstr->str_cur, cmd->c_short);#endif } if (tmps) { if (cmdflags & CF_EQSURE) { ++cmd->c_short->str_u.str_useful; if (sawampersand) { curspat = Nullspat; if (leftstab) str_nset(stab_val(leftstab),retstr->str_ptr, tmps - retstr->str_ptr); if (amperstab) str_nset(stab_val(amperstab), tmps, cmd->c_short->str_cur); if (rightstab) str_nset(stab_val(rightstab), tmps + cmd->c_short->str_cur, retstr->str_cur - (tmps - retstr->str_ptr) - cmd->c_short->str_cur); } lastspat = cmd->c_spat; match = !(cmdflags & CF_FIRSTNEG); retstr = match ? &str_yes : &str_no; goto flipmaybe; } else hint = tmps; } else { if (cmdflags & CF_NESURE) { ++cmd->c_short->str_u.str_useful; match = cmdflags & CF_FIRSTNEG; retstr = match ? &str_yes : &str_no; goto flipmaybe; } } if (--cmd->c_short->str_u.str_useful < 0) { cmdflags &= ~CF_OPTIMIZE; cmdflags |= CFT_EVAL; /* never try this optimization again */ cmd->c_flags = (cmdflags & ~CF_ONCE); } break; /* must evaluate */ case CFT_NUMOP: /* numeric op optimization */ retstr = STAB_STR(cmd->c_stab); newsp = -2; switch (cmd->c_slen) { case O_EQ: if (dowarn) { if ((!retstr->str_nok && !looks_like_number(retstr))) warn("Possible use of == on string value"); } match = (str_gnum(retstr) == cmd->c_short->str_u.str_nval); break; case O_NE: match = (str_gnum(retstr) != cmd->c_short->str_u.str_nval); break; case O_LT: match = (str_gnum(retstr) < cmd->c_short->str_u.str_nval); break; case O_LE: match = (str_gnum(retstr) <= cmd->c_short->str_u.str_nval); break; case O_GT: match = (str_gnum(retstr) > cmd->c_short->str_u.str_nval); break; case O_GE: match = (str_gnum(retstr) >= cmd->c_short->str_u.str_nval); break; } if (match) { if (cmdflags & CF_EQSURE) { retstr = &str_yes; goto flipmaybe; } } else if (cmdflags & CF_NESURE) { retstr = &str_no; goto flipmaybe; } break; /* must evaluate */ case CFT_INDGETS: /* while (<$foo>) */ last_in_stab = stabent(str_get(STAB_STR(cmd->c_stab)),TRUE); if (!stab_io(last_in_stab)) stab_io(last_in_stab) = stio_new(); goto dogets; case CFT_GETS: /* really a while (<file>) */ last_in_stab = cmd->c_stab; dogets: fp = stab_io(last_in_stab)->ifp; retstr = stab_val(defstab); newsp = -2; keepgoing: if (fp && str_gets(retstr, fp, 0)) { if (*retstr->str_ptr == '0' && retstr->str_cur == 1) match = FALSE; else match = TRUE; stab_io(last_in_stab)->lines++; } else if (stab_io(last_in_stab)->flags & IOF_ARGV) { if (!fp) goto doeval; /* first time through */ fp = nextargv(last_in_stab); if (fp) goto keepgoing; (void)do_close(last_in_stab,FALSE); stab_io(last_in_stab)->flags |= IOF_START; retstr = &str_undef; match = FALSE; } else { retstr = &str_undef; match = FALSE; } goto flipmaybe; case CFT_EVAL: break; case CFT_UNFLIP: while (tmps_max > tmps_base) { /* clean up after last eval */ str_free(tmps_list[tmps_max]); tmps_list[tmps_max--] = Nullstr; } newsp = eval(cmd->c_expr,gimme && (cmdflags & CF_TERM),sp); st = stack->ary_array; /* possibly reallocated */ retstr = st[newsp]; match = str_true(retstr); if (cmd->c_expr->arg_type == O_FLIP) /* undid itself? */ cmdflags = copyopt(cmd,cmd->c_expr[3].arg_ptr.arg_cmd); goto maybe; case CFT_CHOP: retstr = stab_val(cmd->c_stab); newsp = -2; match = (retstr->str_cur != 0); tmps = str_get(retstr); tmps += retstr->str_cur - match; str_nset(&strchop,tmps,match); *tmps = '\0'; retstr->str_nok = 0; retstr->str_cur = tmps - retstr->str_ptr; STABSET(retstr); retstr = &strchop; goto flipmaybe; case CFT_ARRAY: match = cmd->c_short->str_u.str_useful; /* just to get register */ if (match < 0) { /* first time through here? */ ar = stab_array(cmd->c_expr[1].arg_ptr.arg_stab); aryoptsave = savestack->ary_fill; savesptr(&stab_val(cmd->c_stab)); savelong(&cmd->c_short->str_u.str_useful); } else { ar = stab_xarray(cmd->c_expr[1].arg_ptr.arg_stab); if (cmd->c_type != C_WHILE && savestack->ary_fill > firstsave) restorelist(firstsave); } if (match >= ar->ary_fill) { /* we're in LAST, probably */ if (match < 0 && /* er, probably not... */ savestack->ary_fill > aryoptsave) restorelist(aryoptsave); retstr = &str_undef; cmd->c_short->str_u.str_useful = -1; /* actually redundant */ match = FALSE; } else { match++; if (!(retstr = ar->ary_array[match])) retstr = afetch(ar,match,TRUE); stab_val(cmd->c_stab) = retstr; cmd->c_short->str_u.str_useful = match; match = TRUE; } newsp = -2; goto maybe; case CFT_D1: break; case CFT_D0: if (DBsingle->str_u.str_nval != 0) break; if (DBsignal->str_u.str_nval != 0)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -